저희는 간헐적으로 스토리지에서 막대한 트랜잭션 부하가 발생하는 문제를 겪고 있습니다. 이 현상의 일정이나 시간 패턴을 찾지 못했지만, 하루에 최소 한 번은 발생하며 지속 시간도 10분에서 수 시간까지 다양합니다.
이러한 부하가 발생할 때 저희 전체 설치 환경이 약간 이상하게 동작합니다. 예를 들어, 토픽 읽기가 인식되지 않아 여전히 “새로움” 또는 "읽지 않음"으로 표시되는 경우가 있습니다.
Discourse가 대량의 파일을 이동시키고 있는 것처럼 보입니다. 특히 READ 작업이 증가하고 있습니다. 외부 트래픽도 함께 증가하는지 확인해 보았지만, 그렇지 않았습니다. Discourse와 스토리지 간의 트래픽만 영향을 받고 있습니다.
이러한 동작은 Discourse 2.4.0.beta9에서 2.4.0.beta10으로 업그레이드한 후 처음 발견했지만, 이전에도 발생했는지는 확실하지 않습니다. 현재는 2.5.0.beta4 버전을 실행 중입니다.
저희 Discourse 설치 환경은 SMBv3로 연결된 Premium Storage가_attached된 Azure 환경에서 실행되고 있으며, 평소에는 상당히 원활하게 동작합니다.
무슨 일이 일어나고 있는지 설명해 주실 수 있나요? 처음에는 sidekiq 작업인 MigrateUploadScheme을 의심했지만, 이 작업이 해당 트랜잭션의 원인이라면 지금보다 훨씬 더 자주 이러한 높은 부하를 볼 수 있어야 합니다. 또한 다른 책임 있는 작업을 찾지 못했습니다.
“Burst IOPS” 덕분에 약 800k 트랜잭션/30분이라는 피크를 확인할 수 있습니다. 이 크레딧이 소진되면 약 250k 트랜잭션/30분으로 스로틀링됩니다. 따라서 이 피크는 Azure 스토리지 티어의 제한/크레딧 보너스일 뿐이므로 걱정하지 않으셔도 됩니다.
보통 30분당 5k ~ 40k 트랜잭션을 처리합니다.
WITH x AS (SELECT
u.id user_id,
SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 2 THEN 1 ELSE 0 END) likes_received,
SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 1 THEN 1 ELSE 0 END) likes_given,
COALESCE((SELECT COUNT(topic_id) FROM topic_views AS v WHERE v.user_id = u.id AND v.viewed_at > '2019-10-28 23:52:24.911261'), 0) topics_entered,
COALESCE((SELECT COUNT(id) FROM user_visits AS uv WHERE uv.user_id = u.id AND uv.visited_at > '2019-10-28 23:52:24.911261'), 0) days_visited,
COALESCE((SELECT SUM(posts_read) FROM user_visits AS uv2 WHERE uv2.user_id = u.id AND uv2.visited_at > '2019-10-28 23:52:24.911261'), 0) posts_read,
SUM(CASE WHEN t2.id IS NOT NULL AND ua.action_type = 4 THEN 1 ELSE 0 END) topic_count,
SUM(CASE WHEN p.id IS NOT NULL AND t.id IS NOT NULL AND ua.action_type = 5 THEN 1 ELSE 0 END) post_count
FROM users AS u
LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id AND COALESCE(ua.created_at, '2019-10-28 23:52:24.911261') > '2019-10-28 23:52:24.911261'
LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id AND p.deleted_at IS NULL AND p.post_type = 1 AND NOT p.hidden
LEFT OUTER JOIN topics AS t ON p.topic_id = t.id AND t.archetype = 'regular' AND t.deleted_at IS NULL AND t.visible
LEFT OUTER JOIN topics AS t2 ON t2.id = ua.target_topic_id AND t2.archetype = 'regular' AND t2.deleted_at IS NULL AND t2.visible
LEFT OUTER JOIN categories AS c ON t.category_id = c.id
WHERE u.active
AND u.silenced_till IS NULL
AND u.id > 0
GROUP BY u.id)
UPDATE directory_items di SET
likes_received = x.likes_received,
likes_given = x.likes_given,
topics_entered = x.topics_entered,
days_visited = x.days_visited,
posts_read = x.posts_read,
topic_count = x.topic_count,
post_count = x.post_count
FROM x
WHERE
x.user_id = di.user_id AND
di.period_type = 5 AND (
di.likes_received <> x.likes_received OR
di.likes_given <> x.likes_given OR
di.topics_entered <> x.topics_entered OR
di.days_visited <> x.days_visited OR
di.posts_read <> x.posts_read OR
di.topic_count <> x.topic_count OR
di.post_count <> x.post_count )
더 잘 평가할 수 있도록 몇 가지 맥락을 제공해도 될까요?
저희는 약 43만 명의 사용자, 삭제된 항목을 제외하고 160만 개의 토픽(840만 개의 게시물 포함), 241개의 카테고리, 그리고 1,200만 개의 user_actions를 보유하고 있습니다.
하지만 여전히 느린 쿼리가 스토리지(/uploads)에서 이렇게 많은 READ 작업을 유발하는 이유가 무엇인지 이해하지 못하고 있습니다. 제가 놓치고 있는 것이 있을까요?
이것은 맞지 않는 것 같습니다. Azure를 사용 중이라면 파일을 어떻게 저장하고 계신지 혼란스럽습니다. 단일 컨테이너 구성인가요? 업로드는 어떻게 설정되어 있나요?
디렉터리 업데이트가 매우 느립니다. 업데이트 비용을 감당할 수 없다면 디렉터리를 비활성화할 수 있습니다. https://meta.discourse.org/u 페이지에 대한 디렉터리를 비활성화하면 됩니다. 전체 페이지 검색에 사용자 검색을 추가하는 구체적인 계획이 있으므로, 디렉터리 없이도 충분히 작동할 수 있습니다.
먼저, 이는 단일 컨테이너 구성이 아닙니다. Redis, PostgreSQL, 스토리지에는 Azure 자체 서비스를 사용하도록 구성을 분리했습니다.
Discourse + nginx가 실행 중인 3대의 VM이 있습니다. 이 3대의 VM에는 SMBv3를 통해 별도의 Azure File Share가 마운트되어 있으며, 이 마운트 포인트가 Discourse 컨테이너에 볼륨으로 연결됩니다.
여기에 /public/uploads, /tmp/javascript-cache, /tmp/stylesheet-cache가 저장됩니다.
VM 디스크, 스토리지, 데이터베이스는 서로 분리되어 있습니다. 따라서 DB 부하가 스토리지나 VM 성능에 영향을 주지 않으며(주지 말아야 할 것은 아닙니다), 해당 서비스의 이점(예: 위에서 언급한 PostgreSQL 인스턴스의 데이터베이스 통계 및 성능 권장 사항)을 활용할 수 있습니다.
이 구성을 통해 각 서비스/부분을 독립적으로 모니터링할 수도 있으며, uploads가 위치한 Azure File Share가 매우 높은 트랜잭션 수를 받고 있음을 확인했습니다(첫 번째 게시물에서 볼 수 있듯이). 이러한 트랜잭션은 대부분 READ 작업입니다.
따라서 이 스토리지(File Share)가 Discourse 자체에서만 사용되므로, 하루에 1~2회 발생하여 수 분에서 수 시간까지 지속되는 이러한 이벤트의 원인이 되는 프로세스/잡을 파악하기 위해 노력해 왔습니다.
이러한 막대한 트랜잭션 수를 제외하면, 이 구성은 몇 가지 느리게 실행되는 쿼리(예: 소수의 사용자 활동 요약 페이지가 최대 15초까지 로드될 수 있음)로 인해 일부 경우에만 성능에 영향을 미치지만, 전반적으로 잘 작동하고 있습니다.
왜 DB 성능이 정적 파일의 트랜잭션 수에 영향을 미쳐야 하는지 궁금해했는지 설명할 수 있었기를 바랍니다.
감사합니다.
Sascha
P.S.
우리는 설정에 커스텀 도커 이미지를 사용하고 있으며, 커스텀 솔루션에 대한 지원을 제공하지 않거나 제공하지 않을 것이라는 점을 충분히 이해하고 있습니다.
우리가 알고 싶은 유일한 것은 이러한 스토리지 트랜잭션 수를 유발할 수 있는 프로세스/잡/설정이 무엇이며, 전체 설정의 속도를 부분적으로 늦추는 것을 방지하기 위해 우리가 무엇을 할 수 있는지에 대한 것입니다.
성능 측면에서 가장 좋은 방법은 업로드 저장소를 S3 또는 S3 호환 저장 엔진 + CDN으로 전환하는 것입니다. 업로드에 SMB 공유를 사용하는 것은 우리가 한 번도 테스트해 본 적이 없으며, 제 추측으로는 업로드 크기를 매일 확인하는 것인데, 로컬에서는 매우 빠르지만 SMB에서는 매우 느리다고 봅니다.
설명과 조언에 감사합니다. 실제로 파일에 대량으로 접근할 때 SMB는 매우 느릴 수 있습니다. 대부분의 경우 차이는 없는데, 이는 자주 접근되는 파일들이 nginx에 의해 캐시되기 때문입니다(우리는 discourse nginx 샘플 설정에 적용된 변경 사항을 자주 적용합니다).
하지만 이러한 순간에 성능이 저하됩니다.
우리는 다른 저장 솔루션을 찾아보고 있습니다. 외부 s3(호환) 스토리지를 사용하면 우리 보안 개념의 일부가 깨질 수 있습니다. 관련되는 모든 인스턴스/서비스(db, vm, 스토리지, …)는 비공개 네트워크에 바인딩되어 있으며 공개 인터넷에서는 접근할 수 없습니다. 모든 공개 트래픽은 Azure Application Gateway로 관리됩니다.
불행히도 Azure Blob Storage는 S3와 호환되지 않지만, 이를 활용하기 위해 시간을 투자해야 할 수도 있습니다.
현재 가능한 솔루션은 Discourse Blob Storage 플러그인 또는 컨테이너 내부에서 blobfuse를 직접 사용하는 것입니다.
어쨌든. 시간과 도움을 주셔서 감사합니다. 업로드 크기가 매일 확인되는 이유가 있으며, 이를 끄는 방법이 있나요?