우리 친구들은 RabbitMQ, RocketMQ, Kafka 등과 같은 메시지 미들웨어 MQ에 대해 충분히 들어봤을 것입니다. 미들웨어 도입의 이점은 높은 동시성, 피킹 및 비즈니스 분리를 방지하는 역할을 할 수 있습니다.
위에 표시된 대로:
(1) 주문 서비스는 MQ 미들웨어에 메시지를 전달합니다. (2) 물류 서비스는 소비를 위해 MQ 미들웨어 메시지를 모니터링합니다.
이 기사에서 주문 서비스를 보장하는 방법에 대해 논의하겠습니다. 메시지는 RabbitMQ를 예로 들어 MQ 미들웨어에 성공적으로 전달되었습니다.
친구들이 이것에 대해 몇 가지 질문을 할 수 있습니다. 주문 서비스가 메시지 서비스를 시작하면 반품이 성공한다는 의미가 아닙니까? 예를 들어 다음과 같은 의사 코드는 다음과 같습니다.
위 코드에서는 일반적으로 다음과 같은 메시지가 전송됩니다. 문제가 있다고 생각하시나요?
MQ 서버가 갑자기 다운되면 어떻게 될까요? 저희 주문 서비스에서 보낸 메시지가 모두 사라졌나요? 예, 일반적으로 MQ 미들웨어는 시스템 처리량을 향상시키기 위해 메시지를 메모리에 저장합니다. 다른 처리가 수행되지 않으면 MQ 서버가 다운되면 모든 메시지가 손실됩니다. 이는 비즈니스에서 허용되지 않으며 큰 영향을 미칠 것입니다.
RabbitMQ에서 메시지를 보낼 때 지속성 매개변수를 true로 설정하는 것이 한 가지 방법이라고 말할 것입니다. , 그것은 지속성입니다.
이 경우 MQ 서버가 다운되더라도 재시작 후 메시지는 디스크 파일에 저장되므로 메시지가 유실되지 않습니다. 예, 이렇게 하면 특정 확률로 메시지가 손실되지 않습니다.
하지만 메시지가 방금 MQ 메모리에 저장되었지만 디스크 파일로 업데이트되기 전에 갑자기 충돌이 발생하는 시나리오가 있습니다. (젠장, 이렇게 짧은 시간 안에 이런 일이 일어날 것이다. 확률이 너무 낮다.) 이러한 시나리오는 지속적인 대규모 메시지 전달 과정에서 매우 일반적일 것이다.
우리는 어떻게 해야 할까요? 디스크에 유지되는지 어떻게 확인할 수 있나요?
위의 문제는 지속성이 성공적인지 아무도 알려주지 않기 때문에 발생합니다. 다행히도 많은 MQ에는 콜백 알림 기능이 있고 RabbitMQ에는 지속성이 성공적인지 여부를 알려주는 확인 메커니즘이 있습니다.
확인 메커니즘의 원리:
(1) 메시지 생성자는 수신에 성공하면 메시지를 MQ로 보냅니다.
(2) 메시지 수신에 성공하면 ack 메시지가 반환됩니다. 실패하면 MQ nack 메시지가 생산자에게 반환됩니다.
위 의사코드에는 메시지를 처리하는 두 가지 방법, 즉 ack 콜백과 nack 콜백이 있습니다.
이렇게 하면 메시지가 100% 손실되지 않는다는 보장이 있나요?
확인 메커니즘을 살펴보겠습니다. 생산자가 메시지를 보낼 때마다 MQ가 디스크에 유지된 다음 ack 또는 nack 콜백을 시작해야 한다고 상상해 보세요. 이 경우 메시지가 매번 디스크에 유지되어야 하므로 MQ의 처리량이 매우 낮습니다. 디스크에 쓰는 속도가 매우 느립니다. 이는 높은 동시성 시나리오에서는 허용되지 않으며 처리량이 너무 낮습니다.
그래서 MQ 영구 디스크의 실제 구현은 비동기 호출을 통해 처리됩니다. 예를 들어 수천 개의 메시지가 있으면 한 번에 디스크로 플러시됩니다. 메시지가 올 때마다 디스크를 플러시하는 대신.
따라서 확인 메커니즘은 실제로 시스템의 높은 처리량을 보장하기 위한 비동기식 청취 메커니즘입니다. 즉, 확인 메커니즘이 추가되더라도 메시지가 손실되지 않을 것이라고 100% 보장할 수는 없습니다. , 메시지는 여전히 MQ 메모리에 있으며 디스크에 플래시하지 않고 컴퓨터가 충돌하여 여전히 처리할 수 없습니다.
너무 많이 말해도 아직 장담할 수 없으니 어떻게 해야 할까요? ? ?
사실 본질적인 이유는 지속성 여부를 판단하는 것이 불가능하기 때문이겠죠? 그렇다면 우리 스스로 메시지를 지속적으로 만들 수 있을까요? 대답은 '예'입니다. 우리의 계획은 더욱 발전할 것입니다.
위 그림의 과정:
(1) 메시지를 전달하기 전에 주문 서비스 생산자는 먼저 Redis 또는 DB에 메시지를 유지하는 것이 좋습니다. 메시지 상태는 보내는 중입니다.
(2) 메커니즘 모니터링 메시지 확인이 성공적으로 전송되었나요? 확인이 성공하면 Redis에서 이 메시지를 삭제합니다.
(3) nack이 실패할 경우 본인의 업무에 맞게 메시지를 재전송할지 여부를 선택할 수 있습니다. 비즈니스 결정에 따라 이 메시지를 삭제할 수도 있습니다.
(4) 일정 시간이 지난 후 메시지를 가져오는 예약된 작업이 여기에 추가됩니다. 메시지 상태는 아직 전송 중입니다. 이 상태는 주문 서비스가 승인 성공 메시지를 받지 못했음을 나타냅니다.
(5) 예약된 작업은 보상 메시지를 전달합니다. 이때 MQ 콜백 ack가 성공적으로 수신되면 Redis에서는 해당 메시지가 삭제됩니다.
이 메커니즘은 실제로 보상 메커니즘입니다. 내 Redis의 메시지 상태가 [보내기]인 한 MQ가 실제로 수신하는지 여부는 상관하지 않습니다. 이는 메시지가 성공적으로 전달되지 않았음을 의미합니다. 그런 다음 예약된 작업을 시작하여 보상 전달을 모니터링하고 시작합니다.
물론, 예정된 작업에 대한 보상 번호를 추가할 수도 있습니다. 3회 이상인데 여전히 ack 메시지를 받지 못한 경우에는 메시지 상태를 직접 [실패]로 설정하고 그 이유를 수동으로 확인하세요.
이 경우 메시지가 100% 손실되지 않도록 하는 솔루션이 더 완벽합니다(물론 디스크 오류는 포함되지 않으므로 마스터-슬레이브 솔루션을 사용할 수 있습니다).
그러나 이 솔루션을 사용하면 동일한 메시지를 여러 번 보낼 수 있습니다. MQ가 이미 메시지를 받았지만 ack 메시지의 콜백 중에 네트워크 오류가 발생하여 생산자가 이를 수행하지 않았을 가능성이 높습니다. 그것을 받으십시오.
그러면 소비자가 소비할 때 멱등성을 보장하도록 요구해야 합니다!
먼저 멱등성이 무엇인지 알아볼까요? 분산 응용에서는 멱등성이 매우 중요합니다. 즉, 동일한 조건에서 비즈니스를 운영하면 몇 번을 수행해도 결과는 동일할 것입니다.
멱등성이라는 시나리오가 있는 이유는 무엇인가요? 대규모 시스템에서는 모두 분산 방식으로 배포되기 때문입니다. 예를 들어 주문 비즈니스와 재고 비즈니스는 독립적으로 배포될 수 있으며 별도의 서비스입니다. 사용자가 주문을 하면 주문 서비스와 재고 서비스가 호출됩니다.
분산 배포로 인해 재고 서비스 호출 시 네트워크 및 기타 사유로 인해 주문 서비스 호출이 실패할 가능성이 매우 높습니다. 그러나 실제로는 재고 서비스가 처리되었으나 처리 중 예외가 발생했습니다. 결과가 주문 서비스로 반환되었습니다. 이때 시스템은 일반적으로 보상 계획을 수립합니다. 즉, 주문 서비스가 재고 서비스를 호출하고 재고가 1 감소합니다.
문제가 있습니다. 실제로 마지막 통화가 1개 줄었지만 주문 서비스에서 처리 결과를 받지 못했습니다. 이제 다시 불러와서 1을 빼야 합니다. 이는 업무상 맞지 않으며 추가 공제입니다.
멱등성의 개념은 동일한 조건에서 인벤토리 서비스를 몇 번 호출해도 처리 결과는 동일하다는 것입니다. 그래야만 보상 계획의 타당성이 보장될 수 있습니다.
다음과 같은 데이터베이스의 낙관적 잠금 메커니즘에서 학습합니다.
버전 버전에 따라, 즉 인벤토리를 운영하기 전에 먼저 버전 번호를 얻습니다. 현재 제품의 버전 번호를 가져와서 작동하세요. 정리하자면, 처음 재고를 운영했을 때 버전 1이 나왔고, 재고 서비스를 호출하니 버전이 2가 되었는데, 주문 서비스로 복귀할 때 문제가 발생했습니다. 버전이 1로 전달된 주문 서비스를 다시 실행하면 버전이 2로 변경되어 실행되지 않으므로 where 조건이 유지되지 않습니다. 이렇게 하면 호출 횟수에 관계없이 한 번만 처리됩니다.
업무 완료 후 기본 키 식별자를 삽입하는 것이 원칙입니다. 제품 ID와 같은 비즈니스 테이블의 유일한 기본 키입니다
지문 코드는 각 작업마다 생성되는 코드이며, 타임스탬프 + 비즈니스 번호 방식을 사용할 수 있습니다.
위 SQL문은
반환값이 0이면 업무 수행 후 t_check(고유ID+지문코드)
0보다 크면 값을 반환합니다. 연산 후 바로 반환합니다.
장점: 간단한 구현
단점: 높은 동시성에서 데이터베이스 병목 현상
해결책: 알고리즘의 ID에 따라 데이터베이스와 테이블을 분할합니다. 라우팅
Redis의 원자 연산을 사용하여 작업 완료를 표시합니다. 이 성능이 더 좋습니다. 그러나 몇 가지 문제가 있을 것입니다.
먼저: 비즈니스 결과를 데이터베이스에 저장해야 합니까? 그렇다면 해결해야 할 핵심 문제는 데이터베이스 및 Redis 작업에서 원자성을 달성하는 방법입니다.
즉, 인벤토리가 1씩 줄어든다는 뜻인데 Redis 작업이 마크 완료 시 실패하면 어떻게 해야 할까요? 즉, 데이터베이스 삭제와 Redis가 함께 성공하거나 실패하는지 확인해야 합니다.
두 번째: 데이터베이스가 삭제되지 않으면 모든 것이 캐시에 저장됩니다. 예약된 동기화 전략을 설정하는 방법은 무엇입니까?
즉, 인벤토리가 1개 줄어들고, Redis 작업을 직접 수행하여 마킹을 완료한 다음, 또 다른 동기화 서비스를 사용하여 인벤토리를 삭제하는 방식입니다. , 동기화 전략 설정 방법
위 내용은 [인터뷰] 메시지를 100% 성공적으로 전달하려면 어떻게 해야 할까요? 메시지 멱등성을 보장하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!