이 시나리오에서는 2 개의 공유 리소스 (데이터베이스 및 큐)가 있고 이들을 함께 처리하려고합니다. 메시지가 대기열로 전송 된 경우 데이터베이스를 커밋해야합니다. 성공적으로 전송되지 않으면 데이터베이스를 커밋하지 않고 그 반대도 마찬가지입니다. 이것은 단순히 2PC와 같은 글로벌 트랜잭션 메커니즘입니다. 그러나 글로벌 트랜잭션 메커니즘을 구현하는 것은 쉽지 않으며 비용도 많이 듭니다.
일관성을 제공하기 위해 소비자 측에서 생산자 측면과 멱등 원함에 대한 전략을 하나 이상 구현하는 것이 좋습니다.
생산자 측 데이터베이스에 메시지 테이블을 만들고 대기열로 보내기 전에이 테이블에 메시지를 저장해야합니다. 그런 다음 예약 된 스레드 (여기에는 처리량을 높이기 위해 여러 개의 스레드가있을 수 있지만 생성 된 순서대로 메시지를 사용해야하는 경우주의해야합니다.) 또는 큐에 보낼 수있는 다른 모든 메시지는 이미 전송 된 메시지는 다시 전송되지 않습니다. 그렇게해도 메시지가 두 번 이상 발송되는 경우가 있습니다 (예 : 메시지를 대기열로 보내고 전송 된 메시지를 표시하기 전에 애플리케이션이 다운 됨). 그러나 우리는 이미 적어도 한 번 이상 메시지를 큐에 보내길 원한다는 것을 의미하는 생산자 측 전략을 적어도 한 번 이상 구현하기를 원하기 때문에 문제가되지 않습니다.
소비자가 제작자 측에서 두 번 이상 생성 된 동일한 메시지를 소비하지 못하게하려면 멱등하지 않은 소비자를 구현해야합니다. 간단하게 소비 된 메시지의 ID를 소비자 측의 데이터베이스 테이블에 저장하고 큐에서 오는 메시지를 처리하기 전에 이미 소비되었는지 확인할 수 있습니다. 이미 소비 된 경우이를 무시하고 다음 메시지를 가져와야합니다.
물론 마이크로 서비스 환경에서 일관성을 유지하는 데있어 다른 옵션이 있습니다. 이 훌륭한 블로그 (https://www.nginx.com/blog/event-driven-data-management-microservices/)에서 다른 솔루션을 찾을 수 있습니다. 위에서 설명한 솔루션도이 블로그에 있습니다. 로컬 트랜잭션을 사용하여 이벤트 게시 섹션에서 찾을 수 있습니다.
생산자가 전송할 때 "보낸"것으로 db에 메시지를 표시하고 시작할 때 "보내지 않은"메시지를 모두 가져 오지 않습니까? 보낸 메시지에 대한 정보를 저장할 수있는 다른 방법이 없습니다. – cassandrad
@cassandrad 메시지가 MQserver로 전송 된 후 앱이 죽을 수 있지만 앱 표시 전에는 메시지가 db로 전송되었습니다. 다른 옵션 : db 트랜잭션과 동일한 메시지 (db 테이블)는 여전히 고객을 기다리고 있습니다. 커밋, 메시지 보내기, 소비자가 메시지를 가져 오면 소비자가해야 할 일은 메시지를 db로받은 것으로 표시하는 것입니다. 그러나이 방법은 고주파 메시지의 경우 느립니다. – weakleaf
"그는 메시지가 MQserver로 전송 된 후 앱이 죽을 수 있지만 앱 표시 전에는 메시지가 db로 전송되었습니다." 전혀 문제가 없습니다. 앱을 시동하면 메시지가 다시 전송됩니다. 배달 옵션이 정확히 한 번만 지정되어 있다고 지정하지 않았습니다. – cassandrad