더 큰 규모로 확장하기 (200만+ 게시글, 월 8만+ 건)

하드웨어 스케일링을 어떻게 계속해나가야 할지, 여러분의 경험을 듣고 싶습니다.

현재의 핵심 데이터는 다음과 같습니다:

  • 현재 게시물 220만 건, 월 약 8만 건 증가
  • 사용자 3.5만 명, 월 약 1,500명 증가

현재 Hetzner VM에서 8개의 전용 코어와 32GB의 RAM을 사용 중입니다. 12월부터 제한 사항을 느끼기 시작했는데, 먼저 Nginx 워커 연결 수에서 문제가 발생하여 기본값인 768에서 1536으로 늘렸습니다. 어제 다시 그 한계에 도달하여 현재 3072로 늘렸습니다. 이러한 변경 후 시스템이 다시 원활하게 작동하고 있지만, 서버 사용률이 100%에 근접하고 있습니다.

db_work_mem은 80MB, db_shared_buffers는 8192MB로 설정되어 있습니다. 사용 가능한 메모리를 전혀 사용하지 않고 있는 것 같지만, 더 많은 메모리를 사용해도 이점을 얻을 수 있을지 확신이 서지 않습니다. 어떻게 생각하시나요?

#~> free -m

              total        used        free      shared  buff/cache   available
Mem:          31360        6105        1241        8423       24013       16412

Hetzner에서 다음으로 쉬운 스케일링 옵션은 16코어와 64GB RAM입니다. 비용 측면에서는 우리에게 문제가 없지만, 여전히 수직 스케일링이 의미 있을지 궁금합니다. 애플리케이션과 데이터베이스를 다른 서버로 분리하는 것이 훨씬 더 합리적인 선택인지, 아니면 많은 난이도를 도입하는지 고민 중입니다.

이러한 작업을 해보신 분은 누구입니까? 어떤 경험이 있으신가요?

왜 확장성을 고려하고 계신가요? API 응답 시간 지표가 악화되고 있나요?

여기서 언급하신 리소스는 무엇인가요? CPU? 디스크 공간? 메모리?

페이지 뷰는 얼마나 되고 있나요?

인터넷에서 찾을 수 있는 모든 조언은 무시하고 메모리의 40~50%로 설정하세요.

sar 출력을 공유해 주실 수 있나요?

앞으로를 대비해서 계획하고 있기 때문입니다. 지금 당장 스케일링이 필요하지는 않을 수 있지만, 과거에 관찰된 성장 추세와 자원 수요 증가를 고려할 때, 가능한 다음 단계를 생각하기 위해 미리 계획을 세우고 있는 것입니다.

주로 CPU입니다. 오늘 업데이트 이후로 피크 시간대 부하가 약 8~9에서 이제 약 6 정도로 내려온 것으로 보입니다.

월 1,200만 회입니다. 1년 전에는 월 650만 회였는데 성장한 수치입니다.

sar 출력 결과는 나중에 다시 공유하겠습니다. 그때는 실행 중이 아니었습니다.

CPU를 정확히 무엇인지 조사해 보셔야 합니다. 다음 중 하나일 수 있습니다:

  • Unicorn 웹 워커
  • PostgreSQL
  • 이미지 최적화 백그라운드 작업과 같은 Sidekiq
  • Redis
  • nginx (가능성은 낮음)

원인에 따라 해당 부하를 분산시키는 방법을 제안해 드릴 수 있습니다.

CPU 시간을 살펴보면, 주로 유니콘(unicorn) 워커들이 원인인 것 같습니다:

전용 CPU 기능을 빼고 여기 있는 이 옵션을 사용하는 건 어떨까요?

사용자 요구 사항에 더 적합한 것 같습니다.

저도 이미 그 옵션에 대해 생각하고 있었습니다. 전에 비전용 CPU를 사용했는데, 전용 CPU로 '업그레이드’해도 크게 나아지지 않았습니다.

CPU가 병목 현상의 원인인지 확신할 수 없습니다. 그 사이에 sar 출력을 공유해 주실 수 있나요?

네, 맞습니다. 다만 아직 정오 시간대는 아닙니다. 내일쯤이면 해당 시간대 데이터가 나올 겁니다.

어제 워커 연결 수를 늘린 후 CPU 사용량이 확실히 줄었습니다. 다만 얼마나 줄었는지는 정확히 모르겠네요.

12:00:01 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle

08:45:01 AM     all     40.22      2.21      7.44      0.27      0.00     49.86
08:55:01 AM     all     42.84      2.89      8.02      0.16      0.00     46.09
09:05:01 AM     all     38.81      0.86      7.68      0.12      0.00     52.53
09:15:01 AM     all     38.80      0.70      7.66      0.10      0.00     52.73
09:25:01 AM     all     38.71      2.14      7.88      0.12      0.00     51.16
09:35:01 AM     all     38.74      0.84      7.86      0.09      0.00     52.47
09:45:01 AM     all     40.31      1.07      7.95      0.10      0.00     50.57
09:55:01 AM     all     40.03      1.37      7.90      0.08      0.00     50.62
10:05:01 AM     all     39.00      1.29      7.90      0.09      0.00     51.72
10:15:01 AM     all     40.26      2.68      8.07      0.09      0.00     48.91
10:25:01 AM     all     41.59      0.93      8.31      0.08      0.00     49.09
10:35:01 AM     all     40.39      1.55      8.25      0.07      0.00     49.73
10:45:01 AM     all     45.44      2.37      9.08      0.08      0.00     43.03
10:55:01 AM     all     50.56      2.20      9.23      0.06      0.00     37.95
11:05:01 AM     all     41.82      1.54      8.55      0.08      0.00     48.02
11:15:01 AM     all     38.74      1.54      8.11      0.10      0.00     51.50
11:25:01 AM     all     45.41      1.59      9.27      0.19      0.00     43.55
11:35:01 AM     all     38.45      1.78      8.20      0.11      0.00     51.45
11:45:01 AM     all     41.03      1.60      8.48      0.14      0.00     48.75
11:55:01 AM     all     40.65      1.17      8.36      0.15      0.00     49.67
12:05:01 PM     all     40.03      1.29      8.40      0.13      0.00     50.15
12:15:01 PM     all     40.47      1.10      8.19      0.11      0.00     50.13

고려해 볼 만한 유용한 sar 통계 항목에는 어떤 것들이 있을까요?

Postgres에 메모리가 충분히 할당되지 않았다고 의심했는데, 이로 인해 %iowait가 높아진 것으로 보입니다.
하지만 위의 sar 출력이 시스템 과부하를 나타내지 않으므로, 새로운 통계가 나올 때까지 기다려야 합니다.

다른 사람의 성능 문제를 해결하려고 하고 있습니다. Postgres 버퍼 크기를 늘렸는데, 약간 도움이 된 것 같지만 미니 프로파일러에서는 여전히 300ms 이상으로 표시됩니다. 16개 CPU 기준 CPU 사용률은 약 30%입니다.

변화가 없을 것 같습니다. 이틀 저녁 동안 지켜봤는데 CPU 사용률이 더 높아지지 않았습니다. Postgres에 대한 가정이 맞을 수도 있겠네요.

미니 프로파일러에 관해서: 여기서 목표로 삼아야 할 수치는 얼마인가요? 현재 약 300ms입니다. 이전에는 500ms 정도였습니다.

피크 시간대 여부와 관계없이 모든 경우에서 50ms 미만을 달성할 수 있다면, 저는 이를 빠른 서버 응답 시간이라고 부를 것입니다. 모든 것이 초기 서버 응답 시간에 의존하기 때문에 사이트의 나머지 부분도 더 빨라질 것입니다.

모든 지역의 사용자로부터 50ms 미만으로 유지되고 일관성이 있다면 매우 이상적일 것입니다. 현재는 계속 요동치며 대부분 더 높은 편인데, 이것이 느리다고 느끼는 큰 문제인 것 같습니다.

지난 며칠간 전반적으로 순조롭게 진행되었지만, 오후에 약 30분 정도 예외가 있었습니다. 해당 시간에는 제가 서버에 직접 접속해 있지 않았지만, nginx 로그에서 백엔드 타임아웃이 보고되었습니다. sar 출력에서는 시스템 사용률이 약간 높은 것으로 보이지만, 전반적인 CPU 부하가 높은 것은 아닙니다. 정확히 무슨 일이 있었는지 모르겠지만, 그 시간 동안 unicorn/redis/postgres가 원활하게 작동하지 못했던 것으로 보입니다.

03:55:01 PM     all     34.99      1.87      6.67      0.12      0.00     56.35
04:05:01 PM     all     33.99      0.35      6.52      0.31      0.00     58.82
04:15:01 PM     all     35.24      1.17      7.14      0.13      0.00     56.31
04:25:02 PM     all     36.45      0.63      7.15      0.13      0.00     55.65
> 04:35:01 PM     all     39.09      0.71     16.78      0.11      0.00     43.32
> 04:45:01 PM     all     35.53      0.95     20.16      0.08      0.00     43.27
> 04:55:01 PM     all     41.64      4.29     15.44      0.24      0.00     38.39
05:05:01 PM     all     36.75      2.47      7.78      0.13      0.00     52.87
05:15:01 PM     all     35.96      1.29      7.81      0.10      0.00     54.85
05:25:01 PM     all     38.69      1.35      8.00      0.09      0.00     51.87
05:35:01 PM     all     37.01      4.53      7.92      0.07      0.00     50.46

위에서 >로 표시된 행들입니다.

해당 시간대에 높은 트래픽이 있었다는 것을 볼 수 없으므로, 무슨 일이었는지 전혀 감이 오지 않습니다. 하지만 실제로는 그 30분 동안에만 그런 현상이 발생했습니다.

전반적으로 CPU 시간을 살펴보면, Redis가 선두를 달리고 있으며 일반적으로 CPU의 상당 부분을 차지하고 있습니다. 이에 대해 할 수 있는 조치가 있는지 잘 모르겠습니다. 보통 20~25% 수준을 유지하다가 가끔 35%까지 치솟습니다.

1721566 uuidd      20   0 2035M 1458M  1952 S 16.1  4.6 16h22:37 /usr/bin/redis-server *:6379
1721578 www-data   20   0  108M 69100 12516 S  6.7  0.2  6h32:27 nginx: worker process
2853756 1000       20   0 1355M  444M 19356 R 63.7  1.4  2h38:10 unicorn worker[0] -E production -c config/unicorn.conf.rb
2854380 1000       20   0 1267M  409M 18768 S 41.6  1.3  2h19:45 unicorn worker[4] -E production -c config/unicorn.conf.rb
1721598 1000       20   0  592M  285M  5192 S  1.3  0.9  2h08:53 unicorn master -E production -c config/unicorn.conf.rb
    575 root       20   0 1747M 20468  5040 S  0.7  0.1  2h01:02 /usr/bin/containerd
2854731 1000       20   0 1280M  399M 17880 S 36.9  1.3  1h57:52 unicorn worker[7] -E production -c config/unicorn.conf.rb
1721841 1000       20   0  592M  285M  5192 S  0.7  0.9  1h49:49 unicorn master -E production -c config/unicorn.conf.rb
2855284 1000       20   0 1287M  425M 18396 S 18.8  1.4  1h35:02 unicorn worker[3] -E production -c config/unicorn.conf.rb
2856414 1000       20   0 1223M  391M 19268 S 13.4  1.2  1h14:50 unicorn worker[2] -E production -c config/unicorn.conf.rb
2856478 1000       20   0 1207M  401M 21120 S  5.4  1.3 58:42.50 unicorn worker[5] -E production -c config/unicorn.conf.rb
2856503 1000       20   0 1215M  389M 18980 S  4.7  1.2 47:22.95 unicorn worker[1] -E production -c config/unicorn.conf.rb
1721581 www-data   20   0 69888 28636 13368 S  0.0  0.1 44:49.50 nginx: worker process
2857467 1000       20   0 1199M  385M 18112 S  4.0  1.2 39:23.87 unicorn worker[6] -E production -c config/unicorn.conf.rb
1721594 _apt       20   0 8479M 20036 18128 S  1.3  0.1 32:55.29 postgres: 13/main: walwriter
    580 root       20   0 1747M 20468  5040 S  0.0  0.1 32:15.27 /usr/bin/containerd

장기 평균 로드는 현재 5로 안정화되었지만, 가끔 8~9까지 올라가는 것을 여전히 보고 있습니다.

미니 프로파일러에 관해서 말씀드린 것은 전체 로드 시간입니다. 서버 응답 시간(초기 요청)은 저희 쪽에서는 보통 10ms 미만입니다. 가끔 조금 더 걸리기도 하지만, 최근 확인 결과 20ms를 초과한 경우는 본 적이 없습니다. 전체 로드 시간은 때때로 800ms까지 올라가며, 매우 드물게 1000ms를 초과하기도 합니다.

해당 지역 외에는 상당한 수의 사용자가 없으므로, 하나의 지리적 지역만 보고 있습니다.

성능을 향상시킬 수 있는 부분을 파악하는 데 도움이 될 DISCOURSE_ENABLE_PERFORMANCE_HTTP_HEADERS 설정을 확인해 보시는 것을 권장합니다.