pitchfork의 메모리 사용량이 너무 많은가요?

혹시 이 현상을 확인하시는 분이 계신가요? 규모나 트래픽 면에서 꽤 소규모인 포럼입니다. pitchfork 워커 프로세스가 4개 있는데, 그중 하나가 수신 요청의 대부분을 처리하고 다른 프로세스보다 더 많은 메모리를 사용하고 있는 것으로 보입니다. 스왑 사용량이 많으며, pitchfork를 의도적으로 재시작하면 스왑 사용량이 상당히 줄어듭니다. 따라서 현재 pitchfork 프로세스에 상당량의 콜드 페이지가 스왑아웃되어 있다고 결론짓습니다.

이것은 4GB RAM과 4GB 스왑을 가진 머신에서 20일 동안 운영한 후의 결과입니다.

스왑이 소진되는 것은 좋지 않을 것입니다. pitchfork가 마침내 가비지 컬렉션을 수행할 때 모든 스왑이 다시 페이징 인되는 상황이 발생할 수도 있는데, 이것 역시 좋지 않을 것입니다.

혹시 유사한 현상을 목격하신 분이 계신가요? 머신 구성을 공유해 주십시오!

# ps aux | sort -n -k 4 | egrep pitchf\|MEM |tail
root     2167652  0.0  0.0   5912  1792 pts/0    S+   20:07   0:00 grep -E --color=auto pitchf|MEM
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000       15094  0.0  0.2 497544 10988 ?        Sl   Jul28   0:17 pitchfork monitor - 
1000       15704  0.0  2.5 6799124 97836 ?       Sl   Jul28   1:00 pitchfork (gen:0) service - ready
1000       15097  0.0  4.8 6791252 189724 ?      Sl   Jul28   5:26 pitchfork (gen:0) mold - ready
1000       15959  0.0  8.1 6815508 319708 ?      Sl   Jul28  12:05 pitchfork (gen:0) worker[3] - requests: 6684, waiting
1000       15900  0.0  9.2 6864596 360696 ?      Sl   Jul28  17:43 pitchfork (gen:0) worker[2] - requests: 14756, waiting
1000       15795  0.1 10.3 6884756 405420 ?      Sl   Jul28  48:36 pitchfork (gen:0) worker[1] - requests: 97007, waiting
1000       15734  2.1 12.8 11299708 500120 ?     Sl   Jul28 637:50 pitchfork (gen:0) worker[0] - requests: 2229848, waiting

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1874636       98840      678812     1931492     1160916
Swap:        4194288     1226600     2967688


# vmstat 5 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0 1226600 115820  65288 1866284    1    1    20    38    0    3  3  1 97  0  0
 0  0 1226600 113208  65296 1866296    0    0     0    14  411  478  1  1 98  0  0
 0  0 1226600 112956  65304 1866336    0    0     1    23  438  528  2  1 97  0  0
 0  0 1226600 112704  65308 1866360    0    0     1    31  518  603  5  1 94  0  0
 0  0 1226600 112704  65308 1866364    0    0     0    11  347  387  1  1 98  0  0

vmstat 출력은 현재 메모리 압박이 없음을 보여줍니다 - 페이징 활동이 없습니다. 제 우려는 현재 설치가 잘 작동하지 않고 있다는 것이 아니라, 잠재적인 위험이 있다는 것입니다.

cpu0

조금 더 진지하게 말하자면, 모든 작업을 수행하는 프로세스의 RSS가 평균보다 겨우 100MB 더 높은 것 같습니다. 제게는 정상적으로 보이는데, 제가 뭘 놓치고 있는 걸까요?

더 활발한 포럼의 통계를 보고 싶네요. 누적 요청 수가 중요한 것 같고, 제 포럼은 결코 매우 활발하지는 않으니까요.

네, RSS 차이는 상대적으로 작지만, 300M에서 500M까지의 범위는 비율로 보면 꽤 큰 차이가 있습니다.

더 눈에 띄는 것은 스왑 사용량입니다. 가축용 포크를 꺼내기 전에, 재활용 전 상태는 다음과 같습니다:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1888140       77308      679004     1939520     1147220
Swap:        4194288     1226344     2967944

그리고 재활용 후에는 다음과 같습니다:

# free
               total        used        free      shared  buff/cache   available
Mem:         3904968     1486412     1422380      640744      996176     1587908
Swap:        4194288      309892     3884396

제 생각에는 재활용으로 약 1300M가 해제된 것 같습니다(사용량+스왑의 차이).

unicorn을 사용할 때 이렇게 많은 스왑이 필요했던 것은 본 적이 없었습니다. 그래서 제목을 그렇게 지었습니다.

말씀드린 대로, 다른 인스턴스의 수치도 보고 싶습니다.

하나의 pitchfork 프로세스가 대부분의 부하를 처리하는 것은 정상적인 현상입니다. 첫 번째 프로세스가 바쁠 때만 다른 프로세스가 선택되므로 그렇습니다. 시간이 지남에 따라 메모리가 증가하는 것도 정상입니다. 캐시나 ruby-JIT와 같은 모든 것이 워밍업을 마친 후에는 결국 안정 상태에 도달해야 합니다.

아래는 7일간의 기간 동안 우리 프로덕션 클러스터 중 하나의 그래프입니다. 이는 가장 많은 메모리를 사용하는 단일 프로세스를 추적한 것입니다. 녹색 점선은 배포(즉, pitchfork의 새로운 시작)를 나타냅니다:

보시다시피, 초기 출시 후 메모리가 증가하지만, 결국 약 1.4GB 미만에서 안정화됩니다. 이 클러스터는 수백 개의 사이트를 서비스하고 있으므로 숫자 측면에서 가장 좋은 비교 대상은 아닐 수 있습니다… 하지만 성장 추세를 시각적으로 보여주는 데는 도움이 되기를 바랍니다.

프로세스별 RSS 수치를 살펴보는 것만으로는 전체 이야기를 파악할 수 없습니다. Pitchfork는 "포킹 웹 서버"입니다. 즉, ‘모드(mold)’ 프로세스를 부팅한 다음, 모든 워커가 쓰기 시 복제(copy-on-write) 메모리 패턴을 사용하여 해당 모드에서 포크됩니다. 따라서 RSS가 worker[0]에 대해 500mb를 표시하더라도, 그 중 약 200mb는 모드 및 다른 모든 워커와 공유되고 있습니다.

가까운 장래에 Pitchfork의 “리포킹(reforking)” 기능을 활성화하는 것을 목표로 하고 있습니다. 이 기능은 워커를 주기적으로 종료하고, 이미 워밍업된 워커에서 다시 포크하여 시간이 지남에 따라 가능한 한 많은 메모리를 공유하게 합니다. 다만, 모든 코드가 이러한 패턴과 호환되도록 하는 데 일부 작업이 필요합니다 :crossed_fingers:

유용한 시각화 자료 감사합니다. 완전히 안정화되었다고 말하기는 어렵지만, 성장률이 이전보다 낮아졌습니다.

주기적인 리포킹(Re-forking)은 좋은 개선 사항으로 보입니다. 해당 기능이 적용되면 여기에서 알려주시면 감사하겠습니다.

그린 라인에 대해 말씀해 주실 수 있을까요? 피치포크(Pitchfork)가 언제(혹은) 가비지 컬렉션을 수행하는지, 그 원인이 무엇인지, 그리고 수행 중 어떤 영향을 미치는지에 대해 궁금합니다.

초록색 선은 업데이트를 배포하는 시점입니다. 기본적으로 ./launcher rebuild app 명령을 실행하는 것입니다.

Ruby(그리고 Ruby 프로세스 내에서 MiniRacer/v8을 통해 실행되는 JS)는 실행 중 지속적으로 가비지 컬렉션을 수행하며, 운영체제에서 보내는 신호에 따라 이를 처리합니다. 따라서 수동으로 무언가를 실행하는 것에서 큰 이점을 얻을 수 있다고 생각하지 않습니다.

감사합니다. 장기적으로 상황이 어떻게 전개될지 궁금합니다. 다만, 비교적 자주 업데이트되는 서버에서는 그걸 바로 확인하기 어렵습니다. 제 경우에는 20일 동안 지켜보다가, 결국 pitchfork를 이용해 재시작을 선택했습니다. 덕분에 몇 가지 정보를 얻을 수 있었지만, 동시에 타이머도 리셋되었습니다.