• performance
  • linux
  • book

시스템 성능 엔지니어링 Ch.1~2 — 소개와 방법론

성능 분석의 목적, 지연 시간과 캐시 히트율, 튜닝의 트레이드오프, 분석을 멈출 시점, 반방법론까지 1~2장을 정리한다.

시리즈 · DevOps 서적4 / 5
  1. 서버/인프라를 지탱하는 기술 Ch.1 — 다중화와 부하분산의 기본
  2. 서버/인프라를 지탱하는 기술 Ch.2 — 리버스 프록시를 도입하는 이유
  3. 서버/인프라를 지탱하는 기술 Ch.4 — 부하 그리고 Load Average
  4. 시스템 성능 엔지니어링 Ch.1~2 — 소개와 방법론
  5. 시스템 성능 엔지니어링 Ch.4 — 관측 가능성 도구와 모니터링 S/W의 본질

『시스템 성능 엔지니어링』 1~2장을 읽고 정리한 내용이다.

Ch.1 소개

성능 분석이란

성능 분석은 단순히 도구를 사용하는 것을 넘어, 시스템의 동작 원리를 깊이 이해하고 문제의 근본 원인을 찾아내는 과정이다. 목적은 두 가지다.

  • 지연 시간을 줄여 최종 사용자 경험을 개선한다.
  • 컴퓨팅 비용을 절감한다.

성능 엔지니어링은 하드웨어를 선택하거나 소프트웨어를 작성하기 전, 목표 설정과 성능 모델 작성에서부터 시작해야 한다.

성능은 주관적이다

“평균 디스크 I/O 응답 시간은 1ms이다”라는 사실은 어떤 사용자에게는 빠르고 다른 사용자에게는 느리다. 목표를 명확하게 설정해야 객관화할 수 있다. 목표 평균 응답 시간을 정하거나, 요청의 일정 비율이 특정 지연 시간 이내에 처리되어야 한다고 정하는 식이다.

가장 적합한 지표는 지연 시간이다. 다만 지연 시간에는 구체적인 맥락(연결 지연 시간, 요청 지연 시간 등)이 필요하다.

Ch.2 방법론

페이지 폴트, 컨텍스트 스위치 같은 시스템 지표의 정의를 안다고 해서, 그것을 어떻게 활용하고 징후를 어떻게 해결책으로 옮겨야 하는지까지 아는 것은 아니다. 소프트웨어, 하드웨어, 성능 도구, 튜닝 파라미터는 모두 변해 왔지만 이론과 방법론은 변하지 않았다.

용어

용어 설명
IOPS 초당 입출력 연산 수. 디스크 I/O에서는 초당 읽기와 쓰기 횟수를 의미한다.
스루풋 (throughput) 단위 시간당 처리량. 데이터 전송 속도(초당 바이트/비트)나 연산 속도(초당 작업 수, 트랜잭션 수)를 의미한다.
응답 시간 (response time) 연산이 완료될 때까지 걸리는 시간. 대기 시간, 처리 시간, 결과 전송 시간을 포함한다.
지연 시간 (latency) 요청이 처리되기까지 기다려야 하는 시간. 단어 자체가 모호하므로 “TCP 연결 지연 시간”처럼 측정 대상을 명확히 해야 한다.
사용률 (utilization) 자원이 얼마나 바쁜지를 측정하는 기준. 예: CPU, 메모리 사용률
포화도 (saturation) 큐에 처리하지 못한 작업이 얼마나 쌓여 있는지의 정도
병목 지점 (bottleneck) 전체 시스템의 성능을 제약하는 자원
워크로드 (workload) 시스템에 가해지는 부하. 예: DB에서는 클라이언트가 보낸 쿼리
캐시 (cache) 더 느린 저장 장치와 직접 통신하지 않고도 데이터를 빠르게 처리하기 위한 저장 공간

요청 왕복 지연 시간과 처리 시간을 합친 것이 응답 시간임을 보여주는 다이어그램

지연 시간으로 변환하면 비교할 수 있다

초당 100번의 네트워크 I/O와 초당 50번의 디스크 I/O 중 어느 쪽이 성능에 더 영향을 주는지는 횟수만으로 비교하기 어렵다. 네트워크 홉 수, 패킷 드롭 비율, I/O 크기 등 고려할 요소가 너무 많다. 하지만 이를 지연 시간으로 변환해 “네트워크 I/O 전체 100ms, 디스크 I/O 전체 50ms”로 놓으면 차이를 명확하게 알 수 있다.

캐시 히트율

캐시 히트율 98%와 99%의 차이는 10%와 11%의 차이보다 성능에 훨씬 큰 영향을 미친다. 히트와 미스의 속도 차이 때문이며, 미스 시 데이터를 읽어 오는 저장 장치가 느릴수록 곡선은 더 가팔라진다.

그렇다고 히트율만 볼 수는 없다. A의 히트율이 90%, B의 히트율이 80%라도, A의 초당 미스가 200회이고 B의 초당 미스가 20회라면 B가 훨씬 빠르게 끝난다. 히트 지연 시간 1ms, 미스 지연 시간 10ms로 워크로드의 전체 실행 시간을 계산해 보면 다음과 같다.

워크로드 미스율 초당 액세스 초당 미스 전체 실행 시간
A 10% 2000회 200회 1800 × 1ms + 200 × 10ms = 3.8초
B 20% 100회 20회 80 × 1ms + 20 × 10ms = 0.28초

Trade-off

튜닝 파라미터는 대부분 트레이드오프를 가진다.

  • 파일 시스템 레코드 크기: 애플리케이션 I/O 크기와 비슷한 작은 레코드는 임의 접근 I/O 성능이 좋고 캐시 히트율이 높아진다. 큰 레코드는 파일 시스템 백업 같은 연속 전송에서 성능이 향상된다.
  • 네트워크 버퍼 크기: 작은 버퍼는 연결당 메모리 오버헤드를 줄여 더 많은 연결을 처리할 수 있다. 큰 버퍼는 네트워크 스루풋이 증가한다.

어디를 튜닝할 것인가

  • 애플리케이션 수준에서는 불필요한 DB 쿼리를 줄이는 것만으로 큰 성능 향상(2000%)을 얻을 수 있다.
  • 저장 장치 수준까지 내려가면 I/O 속도를 높이거나 I/O 자체를 없앨 수 있지만, 이미 시스템 콜 같은 상위 운영 체제 스택의 실행 비용이 발생한 뒤다. 성능 향상 폭은 상대적으로 작다(20%).

즉 애플리케이션을 튜닝하는 것이 가장 효과적이다. “가장 빠른 쿼리는 실행하지 않는 쿼리”라는 말과 같은 맥락이다.

다만 관찰의 시작점을 애플리케이션에 두는 것이 항상 효율적이지는 않다. 느린 쿼리는 CPU 사용 시간이나 파일 시스템, 디스크 I/O 같은 하위 계층의 관점에서 이해하는 편이 더 유리할 수 있다. 애플리케이션은 매주, 매일 변경되므로 운영 체제 분석을 소홀히 해서는 안 된다.

적합성의 수준과 ROI

조직이나 환경에 따라 성능 요구사항이 다르고, 성능 분석에 대한 투자 대비 효용(ROI)도 다르다. 대규모 데이터 센터나 클라우드 환경을 운영하는 기업은 성능 엔지니어 팀을 두고 커널 내부부터 CPU 성능 카운터까지 모든 것을 측정하고 분석한다.

분석을 언제 중단할 것인가

성능 분석의 큰 어려움 중 하나는 언제 멈춰야 할지 결정하는 일이다. 사용해 볼 도구도, 검토할 사항도 너무 많고, 현실의 문제는 원인이 몇 개인지조차 알 수 없는 경우가 많다. 다음 상황에서는 중단을 고려할 수 있다.

  1. 성능 문제의 주요 원인을 설명할 수 있을 때
  2. 잠재적 ROI가 분석 비용보다 적을 때: 연간 수천만 달러로 추산되는 성능 향상이라면 몇 달의 분석 시간을 충분히 정당화한다. 반면 작은 마이크로서비스의 성능 개선처럼 효과가 수백 달러 수준이라면 한 시간의 엔지니어링 시간조차 가치가 없을 수 있다.
  3. 더 큰 ROI가 기대되는 다른 문제가 있을 때

잠재적 ROI를 일상 업무에서 분석 우선순위를 정하는 기준으로 삼아야 한다.

성능 개선의 한시성

인터넷에서 찾은 튜닝 파라미터 값으로 성능을 빠르게 개선할 수도 있지만, 일부 상황에만 해당한다. 책에서는 이를 다른 사람의 약장을 뒤져 자신에게 맞지 않는 약을 아무거나 먹는 행위에 비유한다.

튜닝 파라미터를 변경할 때는 버전 관리 시스템에 변경 이력을 상세한 설명과 함께 남겨야 한다. Puppet, Salt, Chef 같은 설정 관리 도구를 쓰는 이유이기도 하다.

규모 확장성

부하가 증가할 때 선형으로 늘던 스루풋이 특정 지점부터 꺾이는 그래프

  • 자원에 대한 경쟁이 시작되면 스루풋이 더 이상 선형으로 늘지 않는다. 이 지점을 무릎점(knee point)이라고 부른다.
  • 자원 경쟁이 심화되면 컨텍스트 스위칭 같은 오버헤드 때문에 완료되는 작업이 오히려 줄어든다.
  • 메모리 부하는 빠른 성능 저하를 일으킨다(메모리 페이지를 디스크로 옮기기 시작할 때). CPU 부하는 느린 성능 저하를 일으킨다.

응답 시간을 일정하게 유지하려면, 자원이 부족할 때 큐에 작업을 계속 쌓는 대신 오류를 반환하도록 설계해야 한다. 503을 반환해서 처리 중인 요청의 응답 시간을 지키는 방식이다.

모른다는 것을 아는 것들

  • 이미 알고 있는 것: 확인해야 할 성능 지표와 그 현재 값을 안다. 예: CPU 사용률을 확인해야 하고 그 값이 평균 10%이다.
  • 모른다는 것을 아는 것: 지표나 서브시스템의 존재는 알지만 아직 살펴보지 않았다. 예: 프로파일링으로 CPU를 바쁘게 만드는 원인을 찾을 수 있다는 것은 알지만 아직 하지 않았다.
  • 모른다는 것조차 모르는 것: 장치 인터럽트가 CPU 자원을 많이 소모할 수 있다는 사실을 모른다면, 확인조차 하지 않을 것이다.

알면 알수록 모르는 것이 더 많아진다.

방법론과 반방법론

방법론은 분석을 어디서 시작할지 보여주고 따를 만한 효과적인 절차를 제시한다. 책은 먼저 피해야 할 반방법론부터 소개한다.

가로등 반방법론

특정 방법론 없이, 익숙한 도구로 시스템을 보면서 눈에 띄는 일이 없는지 살펴보거나 이미 아는 튜닝 파라미터를 임의로 바꿔 보는 것이다. 특별히 top을 써야 할 이유가 없는데도, 다른 도구의 출력을 읽을 줄 몰라 top 화면만 들여다보는 경우가 여기에 해당한다. 읽으면서 내 얘기 같았다.

어느 날 밤 한 주정뱅이가 가로등 아래에서 뭔가를 찾고 있었다. 경찰관이 묻자 열쇠를 잃어버렸다고 한다. 함께 찾아봤지만 찾을 수 없어 경찰관이 물었다. “열쇠를 이 가로등 아래에서 잃어버린 것이 확실해요?” 주정뱅이는 대답했다. “아니요. 하지만 여기가 제일 밝거든요.”

다른 사람 비난 반방법론

“네트워크 문제일지도 모릅니다. 네트워크 팀에 패킷 손실이 있었는지 확인해 주실래요?” 성능 문제를 검토하기보다 다른 사람의 문제로 만들어 버리는 것이다. 희생자가 되지 않으려면 문제를 제기하는 쪽에 어떤 도구로 그렇게 판단했는지, 실행 화면과 분석 과정을 요청하면 된다.

체크리스트 방법론

“iostat -x 1을 실행하고 r_await 칼럼을 살펴봐라. 부하가 걸린 상태에서 이 값이 일관되게 10ms 이상이라면 디스크 읽기가 느리거나 디스크가 과부하 상태일 수 있다”와 같은 항목을 모아 둔 것이다. 팀원 모두가 공통적인 문제를 어떻게 점검해야 하는지 알게 하는 효과적인 방법이지만, 목록을 지속적으로 업데이트해야 한다.

마치며

2장까지는 이론적인 소개에 가까웠다. 3장부터 운영체제를 다루니 본격적인 내용은 이제 시작이다.