대규모 미확인 사용자 알림으로 인해 대형 큐에서 발생하는 매우 느린 Sidekiq 문제

Sidekiq와 관련하여 문제가 있습니다.

Sidekiq 웹 UI를 통해 모니터링할 때 작업 처리 속도가 놀라울 정도로 빠릅니다. 하지만 가끔씩 과부하가 걸린 것처럼 보이며 속도가 극도로 느려집니다. 평소 속도의 1~5% 수준으로만 작동하며, 서버 리소스 사용량이 정상적이거나 낮은 상태임에도 불구하고 Redis를 flush하지 않는 한 회복되지 않습니다.

큐가 특정 크기에 도달하면 시스템이 멈추고 속도가 급격히 떨어지는 것처럼 보입니다. 이로 인해 큐가 더 커지는 악순환이 발생합니다. 다만 이것은 제 추측일 뿐이며, 다른 이유로 인해 속도가 느려져 큐가 커진 것일 수도 있습니다.

아래 GIF는 제가 보고 있는 상황을 잘 설명해 줍니다.

simpsons_EDIFIL20161024_0001

서버 리소스는 충분히 여유가 있으며, 현재 CPU 사용률은 10% 미만으로 매우 낮습니다. RAM과 SSD도 여유가 있습니다. 서버 사양은 16개 CPU 코어, 32스레드입니다. 8~14개의 unicorn_sidekiq 프로세스를 실행해 보았으며, 20개로 늘려 보았지만 이는 많은 수의 5xx 에러를 유발했습니다.

Sidekiq 웹 UI의 ‘busy’ 탭에 표시되는 느린 작업의 속도를 다음과 같은 방법으로 향상시킬 수 있었습니다.
Could sidekiq queue be reason for 500 errors? - #30 by bartv (
/etc/sysctl.conf 파일에 'vm.overcommit_memory = 1’을 추가하고 재부팅) 그리고 unicorn_sidekiq 수를 12개에서 8개로 줄이는 것입니다.

하지만 여전히 속도가 느립니다. 어제 Redis 로그에서 다음 내용을 확인했습니다(위 설정 변경 외에 유일한 다른 경고는 overcommit_memory가 1로 설정되어 있지 않다는 것이었습니다):

# WARNING: /proc/sys/net/core/somaxconn is set to the lower value of 128

^ 위에서 언급한 이 경고를 수정하신 분이 계신가요?

어쨌든, 원인과/또는 해결 방법에 대한 아이디어가 있으시다면 알려주시면 감사하겠습니다.

flush하는 대신 이 문제를 근본적으로 해결하여 다시 발생하지 않도록 하는 것이 정말 중요할 것입니다.

Sidekiq 대시보드에서 확인하는 스크린샷입니다:

busy 탭의 작업 스크린샷 몇 장입니다:

또한, 이 옵션을 사용하는 것이 안전한지 아시는 분이 계신가요? Sidekiq 웹 UI에서 low priority 큐를 삭제하는 것 말입니다.

업데이트: 낮은 우선순위 큐를 문제없이 삭제했지만, 작업 처리 속도는 여전히 동일합니다.

작업이 얼마나 걸리는지에 대한 메트릭을 가지고 계신가요? PostAlert 작업에서 상당한 경합이 발생하고 있는 것으로 보이지만, 다른 작업들은 빠르게 완료되고 있습니다.

sidekiq 웹 UI에서 관찰한 바를 판단하면, 맞습니다. 다음 작업을 제외하고는 다른 작업들이 빠르게 완료되는 것으로 보입니다:

Jobs::PostAlert - 0~3분, 대부분 0~1분 범위.
Jobs::ProcessPost - 0~21초.

SMTP 서버가 느린가요?

Amazon SES를 사용하여 메일을 보내고 있으며, VERP 수신도 위해 메일 수신기 구성을 완료했습니다.

SES에서 표시되는 전송 한도는 초당 25통입니다. 이 속도가 너무 느린가요? 한도 상향을 요청할 수 있을 것 같습니다.

말씀해 주시니 생각나는데, 평소보다 많은 다이제스트 메일이 발송된 날부터 이 문제가 발생하기 시작했다는 상관관계를 발견했습니다. 과거 설정 오류로 인해 많은 다이제스트 메일이 하루에 집중되어 발송된 적이 있었기 때문입니다.

얼마나 많은 사용자에게 이메일을 보내고 있나요? 메일 발송량은 어느 정도인가요?

얼마나 많은 사용자에게 이메일이 발송되는지 정확히 알 수 없습니다. 관리자 대시보드의 최근 30일 활성 사용자 통계는 60.8k로, 이것이 지표가 될 수 있을까요? SES의 발송 통계(24시간당 10만 건 이상 제한)는 다음과 같습니다:

업데이트: 초당 SES 전송速率 제한이 25에서 50으로 증가했습니다. 이제 시간당 180,000통의 이메일을 전송할 수 있습니다(다만, 일일 허용 총량은 약 100,000통에 불과합니다). 그러나 Sidekiq 작업 처리 속도는 개선된 것으로 보이지 않습니다.

몇 해 전, 사용자가 1만 건의 읽지 않은 알림을 보유하여 알림 조회가 느려지고, 이로 인해 PostAlert 작업도 지연되는 문제가 있었습니다.

이런 일이 다시 발생하지 않도록 보호 장치를 추가했지만, 사용자의 환경에서는 다른 성능 특성이 나타날 수 있습니다.

알림 개수에 대해 무관심한 채로 카테고리를 구독(watch)하도록 설정된 사용자가 있나요?

데이터베이스에서 사용자별 최대 미확인 알림 수를 확인해 볼 수 있을까요?

그래서 우선순위 낮은 큐를 한 번 더 비우고 며칠간 그대로 두었습니다(마지막 업데이트 이후 변경 사항 없음). 바로 빨라지지는 않았고 큐에 쌓인 작업이 빠르게 증가했지만, 시간이 좀 지나자 스스로 해결된 것 같습니다. 지금은 작업 처리 속도가 매우 빠릅니다. :slight_smile: 20초 폴링 간격을 사용했는데, 지난 몇 분 동안 초당 55~140개의 작업이 처리되고 있습니다. 일일 기준으로도 정상적으로 보이며 큐가 쌓이는 현상도 없습니다.

@Falco @supermathie @Stephen, 도움 주셔서 정말 감사합니다. 정말 감사했습니다!

질문하신 사항에 대해서는 어떻게 확인해야 할지 잘 모르겠습니다. 그래도 여전히 도움이 된다면 확인해 드리겠습니다(조언이 필요합니다). 관련이 있을 수 있는 점으로, ‘사용자당 하루 최대 이메일 수’ 설정을 오랫동안 3으로 해두었습니다.

아직 이르렀을지도 모르겠다. 현재 Sidekiq 작업이 초당 약 1~3개씩 처리되고 있으며, 대기열에는 881만 개의 작업이 쌓여 있다.

:philosoraptor:

마지막으로 업데이트를 언제 하셨나요? 며칠 전 PostAlert 작업에 몇 가지 성능 개선 사항을 추가했습니다:

매우 큰 규모인 몇몇 사이트에서 많은 사용자가 "첫 게시물 보기"를 설정한 카테고리에서 성능 문제를 겪고 있었습니다. 이 커밋으로 저희 호스팅 환경에서는 해당 문제가 해결되었으므로, 여러분의 사이트에도 도움이 될 수 있습니다.

좋아요! 지금 업데이트하고 있습니다. 마지막으로 업데이트한 시점은 약 10일 전쯤이었어요 (테스트 통과). 개선 여부에 대해 모니터링한 후 결과를 보고하겠습니다. 감사합니다!

업데이트: 불행히도 업데이트 후 속도 개선이 바로 느껴지지 않습니다. 시간이 지나면 개선될지 지켜보겠습니다.

업데이트: 여전히 느리게 실행되고 있으며 큐가 쌓이고 있습니다. ‘top’ 명령을 통해 많은 수의 postmaster 프로세스를 확인할 수 있습니다. 총 CPU 사용량은 약 85%(32코어)이며, 그 대부분이 postmaster에서 발생하고 있습니다. 이는 흥미로운 부분으로, 오늘早些 CPU 사용량은 20~35%였습니다(그때도 sidekiq의 처리 속도는 여전히 느렸습니다). 관련 링크: Primary Postgres database process (postmaster) eating all CPU - #5 by pfaffman

이 redis 경고가 문제와 관련이 있을 수 있다고 생각하시나요? 앱 재빌드 중에 표시됩니다:

# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

# WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.

docker 설치 환경에서 이 오류를 해결해 보신 분 계신가요?

이미 overcommit memory 경고를 해결하기 위해 /etc/sysctl.conf에 vm.overcommit_memory = 1을 추가해 두었습니다.

그래서 루트 권한으로 echo never > /sys/kernel/mm/transparent_hugepage/enabled 명령을 실행하여 Transparent Huge Pages (THP) 경고를 해결했습니다. 아직 영구 적용을 위해 rc.local에 추가하지는 않았고, 테스트 목적으로만 실행했습니다. Discourse를 다시 빌드해 보니 성능은 이전과 비슷하거나 약간 향상된 것 같습니다.

하지만 이 경고는 어떻게 수정해야 할지 잘 모르겠습니다:
# WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

시스템 값이 더 높게 설정되어 있더라도(예: Performance tips for Redis Cache Server – Tech and Me 같은 가이드를 따를 경우) Docker는 여전히 128 값을 사용한다는 이야기를 몇몇 사용자들로부터 보고 있습니다.

UNICORN_SIDEKIQS를 일부만 저우선순위 큐에 특별히 할당하는 것이 좋은 방법일 수 있다고 생각합니다.

‘default’ 우선순위 작업, 즉 PostAlert이 상당히 느리게 처리되고 있으며, 이러한 느린 기본 우선순위 작업이 쌓이면, 훨씬 더 빠르게 완료될 수 있는 작업들이 포함된 저우선순위 큐가 거의 처리되지 않아 부풀어 오릅니다. 이 부풀어 오름이 전체 작업 처리 속도를 더 느리게 만드는 원인일 수 있다고 의심하고 있습니다. 이는 초당 작업 수의 큰 변동도 설명할 수 있을 것입니다.

app.yml 파일(또는 다른 방법)을 통해 UNICORN_SIDEKIQS를 특정 우선순위 작업에 할당할 수 있는지 아는 분이 계신가요?

데이터베이스가 병목 현상을 일으키고 있는 상태에서 Sidekiq를 추가하면 상황이 더 나빠질 뿐입니다.

위에서 말했듯이 PostgreSQL의 성능 저하 문제를 디버깅해야 합니다.