RocketMQ 실전 요약|메시지 큐 누적 문제 해결 기록 기록

1. 배경

그림

이 문제와 관련된 시스템 링크는 위의 그림과 같으며 각 시스템의 기본 책임은 다음과 같습니다.

  • 프록시: 요청 프록시 서비스를 제공합니다. 다운스트림 시스템에 전송된 다양한 요청의 통합 에이전트로 업스트림 시스템은 다운스트림 서비스 사용의 차이를 인식할 필요가 없으며 동시에 전류 제한 및 전환과 같은 정교한 서비스 기능을 제공합니다.
  • Latu SDK: 스토리지 플랫폼별 통합 이미지 다운로드 기능을 제공합니다. 일반적으로 이미지 알고리즘 모델과 함께 배열됩니다.
  • 추정 엔진: 모델 추론 서비스를 제공합니다. 다양한 머신 러닝 및 딥 러닝 알고리즘 모델의 엔지니어링 배포를 지원합니다.

2. 문제 해결

참고: 이 글에서 사용하는 메시지 큐는 내부적으로 MetaQ라고 하고, 외부 오픈 소스 버전은 RocketMQ이며, 이하에서는 "MQ"로 지칭한다.

2.1 문제 설명

어느 날 아침 Proxy 시스템의 입장 MQ가 누적되었다는 알람 알림을 받았습니다. 콘솔을 열고 500개의 프록시 시스템 중 1개 시스템이 심각하게 누적된 반면 나머지 시스템은 정상적으로 실행되고 있음을 확인합니다.

그림

2.2 문장의 근본 원인

본론으로 들어가 문제의 근본 원인에 대해 직접 이야기해 보겠습니다(자세한 문제 해결 프로세스는 다음 콘텐츠 참조).

  • 개별 기계 누적: 기계에 고정된 소비 스레드가 있지만 나머지 스레드는 정상적으로 소비하지만 MQ 메커니즘은 소비 위치가 진행되지 않는다고 결정합니다.
  • HTTP 다운로드 중단: 사용된 HttpClient 버전에 버그가 있으며 특정 상황에서 시간 초과가 적용되지 않아 스레드가 항상 중단될 수 있습니다.

2.3 문제 해결 프로세스

1. 기계의 소비 속도가 너무 느리다?

첫 번째 반응은 이 기계의 소비가 너무 느리다는 것입니다. 같은 양의 정보가 다른 기계에 의해 빠르게 소화될 수 있지만 느린 소비로 인해 계속 축적됩니다. 그러나 MQ 콘솔에서 자세히 비교한 후 이 시스템의 비즈니스 처리 시간 및 소비 TPS가 다른 시스템과 유사하고 다른 시스템의 사양도 동일하다는 것을 알 수 있습니다.

그림

둘째, Arthas가 그린 불꽃 다이어그램을 관찰하십시오.오른쪽에 있는 두 개의 가느다란 불꽃은 우리 시스템의 비즈니스 로직입니다(불꽃이 높을수록 RPC 호출 스택이 더 깊기 때문입니다). 화염 그래프에 명백한 "평면 효과"가 없고 화염의 폭이 상대적으로 좁다는 것을 그림에서 볼 수 있습니다. 비즈니스 로직 느린 비즈니스 처리로 인해 시스템이 누적되지 않았음을 증명합니다.

그림

2. 시스템 표시등이 정상입니까?

머신에 로그인하고 CPU, MEM 및 LOAD가 모두 정상이고 일반 머신과 유사하며 명백한 단서가 없는지 확인합니다.

그림

그리고 기계에는 명백한 Full GC가 없습니다.

그림

3. 전류 제한으로 인해 발생합니까?

팁: 프록시에는 요청을 프록시할 때 흐름 제한 메커니즘이 있으며 제한을 초과하는 트래픽은 차단 대기를 트리거하여 다운스트림 동기화 서비스를 보호합니다.

따라서 현재 시스템 트래픽이 매우 크고 다운스트림 서비스가 감당할 수 있는 한도를 초과하는 경우 초과 요청이 RateLimiter 흐름 제한을 트리거하고 차단합니다. 결과적으로 많은 수의 MQ 소비자 스레드가 차단되므로 프록시 시스템의 전체 메시지 소비 속도가 느려지고 최종 결과는 항목 항목의 누적입니다.

그림

그러나 로그를 보든 기계의 모니터링을 보든 전류 제한으로 인한 차단 현상은 심각하지 않으며 비교적 원활합니다.

그림

둘째, 오늘날 시스템의 대규모 수신 트래픽이 실제로 원인이라면 모든 프록시 머신(MQ 소비자)은 비슷한 수준의 누적을 가져야 합니다. 다른 499대의 기계는 정상인 반면 동일한 기계에 모두 쌓아서는 안 됩니다. 따라서 시스템 유입 유량이 너무 클 가능성을 확인하십시오.

4. MQ 데이터 왜곡?

500개의 프록시 시스템이 수신 MQ의 메시지를 균등하게 분배할 것으로 예상됩니다. 데이터 분배에 편향이 있어 이 시스템에 대한 메시지가 너무 많고 다른 시스템에 대한 메시지가 적을 수 있습니까?

프록시의 업스트림 시스템 코드를 확인하십시오.시스템은 프록시에 메시지를 보낼 때 사용자 지정 셔플을 수행하지 않으므로 MQ의 기본 selectOneMessageQueue 전략을 사용합니다. 그리고 이 전략은 인덱스 % queue_size를 기반으로 선택된 큐에 현재 메시지를 보냅니다. 인덱스의 논리를 자세히 살펴보면 초기화할 때 임의의 숫자로 시작하고 액세스할 때마다 +1씩 증가한다는 것을 알 수 있습니다.

그림

위의 두 가지 사항을 결합하면 달성되는 효과는 다음과 같습니다. 왼쪽에서 오른쪽으로 각 큐에 메시지를 균등하게 배포하고 %를 통해 자동 순환을 실현합니다.

그림

요약하면 MQ의 기본 셔플 전략은 다음과 같습니다. 메시지를 각 대기열에 균등하게 나눕니다. 따라서 MQ에서 보낸 왜곡된 메시지 데이터로 인해 프록시 시스템이 누적될 가능성을 배제할 수 있습니다.

5、CPU 훔치기 ?

팁: CPU 스틸은 가상 머신에서 실행 중인 프로세스가 호스트 머신의 다른 프로세스/가상 머신에서 차지하는 CPU 시간의 백분율을 나타냅니다. CPU 스틸 값이 높으면 일반적으로 가상 머신의 프로세스 성능이 저하되었음을 의미합니다.

예를 들어, 기계 사양 자체에는 4C라고 나와 있지만 실제로는 도난당한 후에는 2C만 사용할 수 있습니다. 그래서 반영된 결과는 단일 요청의 RT는 크게 변하지 않지만(다른 C의 차이는 크지 않음) C의 양이 줄어들기 때문에 이 기계의 전체 처리량은 줄어들고 소비 용량은 약해지며, 결과적으로 축적됩니다.

그러나 조사 결과 st는 정상이며 이러한 가능성은 배제됩니다.

그림

6. 단서 찾기: MQ 소비 위치가 변경되지 않았습니다!

이리저리 돌아다니다 이상점을 발견하지 못했는데 문제 현상이 MQ 누적이라 미들웨어 로그를 확인하면 단서를 찾을 수 있을 것 같았습니다. 확실히, 정체된 기계의 queueId에 대한 방향 검색을 통해 이 대기열의 소비 지점이 오랫동안 진행되지 않았으며 특정 위치에 정체되어 있음을 발견했습니다.

그림

팁: MQ 풀링 메시지의 메커니즘은 풀링된 메시지가 먼저 메모리에 1000개 용량의 캐시에 저장되고 메모리의 메시지가 소비자 스레드에 의해 소비된다는 것입니다. 캐시가 가득 차면 더 이상 대기열에서 가져오지 않습니다.

그림

이것으로부터 다음과 같은 의심이 듭니다. 프록시 소비가 중지되거나 소비가 매우 느려서 로컬 캐시가 항상 가득 차서 MQ가 대기열에서 메시지 가져오기를 중지하여 오프셋이 변경되지 않았습니까?

그러나 위에서 언급했듯이 MQ 콘솔, 시스템 모니터링 표시기 및 머신 로그에 관계없이 머신은 정상이며 다른 머신과 차이가 없습니다. 그렇다면 왜 기계의 소비 지점이 움직이지 않아 축적이 점점 더 심각해집니까?

7. 근본 원인 찾기: 소비자 스레드가 중단됨

팁: 로컬 캐시에 있는 메시지의 경우 MQ는 여러 스레드(사용자가 지정한 스레드 수)를 열어 사용을 가져오고 취소합니다. 그리고 메시지가 손실되지 않도록 하기 위해 오프셋은 맨 앞 메시지만 기록합니다.

첫째, 메커니즘이 건전합니다. At Least Once 의미 체계에서는 메시지를 여러 번 사용할 수 있지만 놓칠 수는 없습니다. 이제 동시에 두 개의 메시지를 가져오는 두 개의 스레드가 있고 후자의 메시지가 먼저 실행된다고 가정합니다. 이전 메시지의 실행이 비정상적일 수 있으므로 후자의 오프셋은 오프셋을 업데이트하는 데 직접 사용할 수 없습니다. 그렇지 않으면 소비 실패 메시지가 검색되지 않습니다. 따라서 소비 지점 오프셋의 의미는 이 위치와 그 이전의 모든 메시지가 올바르게 소비되었다는 것입니다(Flink의 워터마크 메커니즘과 다소 유사함).

위의 메커니즘에 따라 이 질문으로 돌아가서 이 프록시 시스템의 많은 MQ 소비자 스레드 중 하나가 중단되면 전체 대기열의 소비 위치는 항상 중단된 메시지에 해당하는 오프셋에 유지됩니다. 이때 다른 쓰레드는 계속해서 정상적으로 소비하고 있지만 오프셋을 앞으로 전진시킬 수는 없다. 반면에 업스트림은 계속해서 큐에 메시지를 보내고 있기 때문에 메시지는 안팎으로만 보낼 수 있으며 누적량 = 가장 최근에 수신된 메시지의 오프셋 - 소비 사이트의 오프셋만 증가하므로 콘솔 누적에 반영됩니다. 더 심각합니다!

이 분석을 바탕으로 jstack을 통해 모든 MQ 소비자 스레드의 상태를 확인하고 실제로 251번 스레드가 항상 실행 가능한 상태에 있음을 확인합니다!

그림

정체된 소비자 스레드라고 의심할 만한 이유가 있습니다. 프록시 시스템의 비즈니스 시나리오에서 대부분의 시간은 딥 러닝 모델을 동기식으로 호출하는 RPC에 소비되므로(수백 밀리초 빠르고 몇 초 느림) 스레드는 동기식 호출이 반환되기를 기다려야 합니다. 대부분 대기 상태! 그러나 여기서 스레드 251은 항상 실행 가능하므로 문제가 있어야 합니다.

세부 정보를 추가로 인쇄하여 스레드가 걸린 특정 코드 위치를 찾습니다.

그림

여기서 getImageDetail 메서드는 딥러닝 모델이 예측할 수 있도록 내부적으로 HTTP를 통해 이미지를 다운로드합니다. 둘째, 비즈니스 로그를 검색해도 이 스레드의 로그를 찾을 수 없습니다. 어젯밤 10시에 중단되었기 때문에 이 스레드는 새 로그를 생성하지 않습니다. 컴퓨터 로그가 롤링되고 정리됨에 따라 이제 모든 로그에 이 스레드의 내용이 포함됩니다.

그림

지금까지 프록시 시스템의 개별 시스템에 MQ가 누적되는 심각한 문제의 근본 원인이 발견되었습니다. HTTP를 통해 사진을 다운로드할 때 이 시스템의 소비자 스레드가 멈춰 전체 대기열의 소비가 진행되지 않습니다. , 지속적인 축적 결과.

8. HTTP가 계속 멈추는 이유는 무엇입니까?

지금까지는 누적의 근본 원인을 찾아 시도한 후 애플리케이션을 다시 시작하거나 단기적으로 오프라인으로 전환하여 일시적으로 해결할 수 있습니다. 그러나 장기적으로는 항상 숨겨진 위험이 있습니다. 최근 며칠에 한 번씩 같은 문제가 나타나기 때문입니다. 이 문제를 근본적으로 해결하기 위해서는 HTTP가 멈추는 근본 원인을 철저히 조사해야 합니다.

스쿼트를 여러 번 한 후 스레드가 멈추는 원인이 되는 사진 URL을 얻었습니다. 그 중 어느 것도 내부 이미지 주소가 아니며 주소를 열 수 없고 jpg 형식으로 끝나지도 않는 것으로 나타났습니다.

https://ju1.vmhealthy.cn
https://978.vmhealthy.cn
https://xiong.bhjgkjhhb.shop

그런데 문제는 이렇게 열리지 않는 극단적인 URL을 입력해도 HttpClient에 5초 타임아웃을 설정해두었기 때문에 기껏해야 5초만 멈춰있을 것인데, 왜 타임아웃 메커니즘이 적용되지 않은 것 같고, 10시간 넘게 붙어있어??

팁: HTTP는 데이터 전송 전에 연결을 설정해야 합니다. 1. 연결 설정 단계에 대한 연결 시간 초과, 2. 데이터 전송 중 시간 초과에 대한 소켓 시간 초과.

그림

점검 결과 현재 코드에서는 소켓 타임아웃만 설정되어 있고 연결 타임아웃은 설정되어 있지 않아 위의 요청이 바로 이전 연결 단계에서 막힌 것으로 의심되며, 연결 타임아웃이 설정되어 있지 않기 때문에 요청이 막혔어? 그러나 코드를 수정하고 이러한 주소를 다시 요청하려고 시도한 후에도 여전히 멈춰 있으며 추가 조사가 필요합니다.

9. HTTP 정체의 근본 원인 찾기

팁: 근본 원인을 찾으십시오. 특정 버전의 HttpClient에는 SSL 연결을 기반으로 한 요청에 버그가 있습니다. 실제로 연결을 먼저 설정한 다음 제한 시간을 설정하고 순서가 반대로 됩니다. 따라서 연결이 끊어지면 시간 제한이 설정되지 않았으며 이 HTTP 요청은 항상 중단됩니다...

그림

위의 막힌 URL을 되돌아보면 모두 예외 없이 https로 시작합니다! 사건은 해결되었고 프로젝트에서 사용하는 HttpClient에 버그가 있음이 밝혀졌습니다. HttpClient 버전을 업그레이드 한 후 미리 발급된 구축 테스트 요청을 다시 발급하여 스레드가 더 이상 중단되지 않고 모두 온라인 환경으로 전송되었습니다. 다시는 발생하지 않았습니다.

지금까지 많은 우여곡절을 겪은 끝에 마침내 문제가 완전히 해결되었습니다.

2.4 종합 검토

최외곽 프록시에 개별 머신이 누적되는 모습부터 근본 원인을 찾을 때까지 내부 조사에서 많은 핵심 노드를 거쳤습니다. 현재 모든 문제가 완전히 조사되었으며 이제 하나님의 관점에서 내부에서 외부로의 완전한 인과 관계는 다음과 같습니다.

–> 프록시 시스템은 HttpClient를 기반으로 사진을 다운로드한 다음 추정을 위해 이미지 클래스 모델을 호출합니다.

–> 사용하는 HttpClient 버전에 버그가 있어 https 주소에 접근할 때 timeout이 적용되지 않음

–> Proxy 시스템에서 우연히 소수의 https 주소가 발생하여 중단되는 일이 발생(낮은 확률 이벤트)하므로 시간 초과가 적용되지 않기 때문에 항상 중단됩니다.

–> MQ의 At Least Once 메커니즘을 기반으로 소비 지점은 항상 중단된 메시지에 해당하는 오프셋에 유지됩니다(나머지 스레드는 정상적으로 소비하고 있지만).

-> 상류 시스템은 계속해서 Proxy로 메시지를 보내므로 메시지가 들어오고 나갈 수 밖에 없고 누적이 심해지고 있음

–> 누적이 일정 임계값을 초과하면 모니터링 알람이 트리거되고 사용자가 알 수 있습니다.

3. 요약

이 문제의 문제 해결 프로세스는 약간 복잡하지만 이 섹션에 요약된 많은 일반적인 방법론과 교훈을 배울 수도 있습니다.

  • ** 문제 해결 도구를 잘 사용하십시오: ** jstack, Arthas, jprofile 및 기타 날카로운 도구를 사용하는 방법을 배우고 다양한 시나리오에서 적절한 도구를 잘 사용하여 비정상 지점을 효율적으로 찾고 단서를 찾아 점진적으로 찾을 수 있습니다. 문제의 근본 원인;
  • **비정상적인 민감도:**때때로 문제를 발견할 수 있는 몇 가지 단서가 실제로 우리 앞에 일찍 나타나기도 하지만 여러 가지 이유(예: 처음에 문제에 대한 많은 의심, 배제 등) 단서를 발견하려면 더 많은 경험이 필요합니다.
  • ** 광범위한 정보 검색: ** 인트라넷에서 문서를 검색하고 상담을 위해 관련 인력을 찾는 것 외에도 외부 영어 웹 사이트에서 직접 정보를 확인하는 방법도 배워야 합니다.
  • **어려울 때 인내:** 일부 숨겨진 문제의 경우 한 번 나타난 후 즉시 문제를 찾아 해결할 수 없는 경우가 많습니다. 근본 원인을 찾기 위해 전후에 여러 차례의 조사가 필요할 수 있습니다.
  • ** 추가 기본 지식: ** 처음에 MQ의 오프셋 메커니즘을 알 수 있다면 일부 문제는 그렇게 많이 우회하지 않을 것입니다. 앞으로 다양한 미들웨어를 사용하는 과정에서 기본 원리에 대해 더 많이 배울 필요가 있습니다.
  • **형이상학적 질문 없음:** 코드와 기계는 사람을 속이지 않습니다. 모든 "형이상학적" 질문 뒤에는 일련의 엄격하고 합리적인 원인이 있습니다.

참고:

  • HttpClient 버그:https://issues.apache.org/jira/browse/HTTPCLIENT-1478
  • 연결 시간 초과 대 소켓 시간 초과:https://stackoverflow.com/questions/7360520/connectiontimeout-versus-sockettimeout

추천

출처blog.csdn.net/agonie201218/article/details/131783826