1. 메시지 큐에 대한 자세한 설명
메시지 큐( Message Queue )는 분산 시스템 의 중요한 구성 요소 입니다. 일반적인 사용 시나리오는 간단히 설명할 수 있습니다: 결과를 즉시 얻을 필요는 없지만 동시성을 제어해야 하는 경우 메시지 큐가 거의 필요합니다. .언제
주로 애플리케이션 결합 , 비동기 메시징 , 트래픽 절감 및 기타 문제를 해결합니다. 고성능, 고가용성, 확장성 및 궁극적으로 일관된 아키텍처를 달성합니다. 대규모 분산 시스템에 없어서는 안될 미들웨어입니다.
현재 프로덕션 환경에서 가장 일반적으로 사용되는 메시지 대기열에는 ActiveMQ , RabbitMQ, ZeroMQ, Kafka, MetaMQ, RocketMQ 등이 있습니다.
1. 메시지 대기열의 두 가지 모델
1.1 점대점 모델
각 메시지에는 하나의 수신자( Consumer )만 있습니다. 일단 메시지가 전송되면 더 이상 메시지 대기열에 있지 않습니다.
발신자와 수신자 사이에 종속성이 없습니다. 발신자가 메시지를 보낸 후에는 실행 중인 수신자가 있는지 여부에 관계없이 여부는 다음에 영향을 미치지 않습니다. 한 번 보내십시오.
1.2 모델 게시 및 구독
각 메시지에는 여러 명의 구독자가 있을 수 있으며,
각 구독자는 해당 주제의 모든 메시지를 받을 수 있습니다.
두 모델의 차이점: 메시지를 여러 번 소비할 수 있는지
여부 구독자가 1명인 경우 두 모델은 기본적으로 동일하므로 게시-구독 모델은 기능 수준에서 대기열 모델과 호환됩니다.
2. 메시지 큐는 분산 트랜잭션을 구현합니다.
엄격한 트랜잭션 구현에는 원자성, 일관성, 격리성 및 내구성이라는 네 가지 ACID 속성이 있습니다. 원자성:
트랜잭션 작업은 분할할 수 없으며 모두 성공하거나 모두 실패하며 절반은 성공하고 절반은 실패할 수 없습니다.
일관성: 이전 시점 트랜잭션 실행이 완료되고, 읽은 데이터는 업데이트
전의 데이터여야 하며, 업데이트 후 읽은 데이터는 업데이트 후의 데이터여야 합니다. 트랜잭션 및 사용된 데이터 데이터는 진행 중인 다른 트랜잭션과 격리되며 동시에 실행되는 트랜잭션은 서로 간섭할 수 없습니다.)
내구성: 일단 트랜잭션이 제출되면 후속 작업 및 실패는 트랜잭션 결과에 영향을 미치지 않습니다.
분산 시스템에서는 데이터 일관성만으로는 달성하기가 매우 어렵기 때문에 일반적으로 궁극적인 일관성 달성만이 보장됩니다. 보다 일반적인 분산 트랜잭션 구현에는 다음이 포함됩니다.
1), 2PC ( Two-phase Commit ) 2단계 커밋
2), TCC ( Try-Confirm-Cancel )
3) 트랜잭션 메시지
3. 메시지 큐 분산 트랜잭션 구현
Kafka 와 RocketMQ 모두 트랜잭션 관련 기능을 제공하는데, 주문을 예로 들어 어떻게 구현하는지 살펴보겠습니다.
Kafka 와 RocketMQ 모두 트랜잭션 관련 기능을 제공합니다.핵심: 절반 메시지 및
절반 메시지: 이 절반 메시지는 메시지 내용이 불완전하다는 의미가 아니라 트랜잭션이 제출되기 전에 메시지가 소비자에게 보이지 않는다는 의미입니다( sendMessageInTransaction )
(1) 메시지 큐의 응용 시나리오(또는 기능)
애플리케이션 시나리오는 비동기 처리 , 애플리케이션 분리 , 트래픽 절단 , 메시지 통신 등 으로 구분되며 가장 중요한 시나리오는 비동기 처리 , 애플리케이션 분리 , 트래픽 절단 입니다.
1. 비동기 처리
시나리오: 사용자가 등록한 후 등록 이메일과 등록 정보를 보내야 합니다. 전통적인 방법에는 직렬 방법 과 병렬 방법의 두 가지가 있습니다.
기존 모델의 단점: 일부 비필수 비즈니스 로직이 동기식으로 실행되므로 시간이 많이 소요됨
미들웨어 모델의 장점: 메시지를 메시지 큐에 기록하고 비필수 비즈니스 로직이 비동기식으로 실행되어 속도가 향상됨 응답.
1.1.직렬 모드
등록 정보가 데이터베이스에 성공적으로 기록되면 등록 이메일이 전송되고 등록 SMS가 전송되며 모든 작업이 완료된 후 그림과 같이 정보가 클라이언트로 반환됩니다.
1.2 병렬 방식
등록 정보가 데이터베이스에 성공적으로 기록되면 등록 이메일과 등록 SMS가 동시에 전송됩니다. 모든 작업이 실행된 후 정보가 클라이언트에 반환됩니다. 직렬 모드와 비교하여 병렬 모드는 실행 효율성을 향상시키고 실행 시간을 줄일 수 있습니다.
세 가지 작업 모두 50ms의 실행 시간이 필요하다고 가정하면 네트워크 요인을 제외하고 최종 실행이 완료되는데, 직렬 모드는 150ms가 필요하고, 병렬 모드는
단위 시간당 CPU가 처리하는 요청 수가 동일하므로 100ms가 필요하다고 가정한다. : CPU 매 1 두 번째 처리량은 100회이면 직렬 모드에서 1초에 실행할 수 있는 요청 수는 1000/150으로 7회 미만입니다. 병렬 모드는 1000/100으로 10배입니다.
전통적인 직렬 및 병렬 방식은 시스템 성능에 따라 제한된다는 것을 알 수 있는데 , 이 문제를 어떻게 해결합니까?
필수적이지 않은 비즈니스 로직을 비동기식으로 처리하려면 메시지 큐를 도입해야 합니다. 결과 프로세스는 다음과 같습니다.
위 프로세스에 따르면 사용자의 응답 시간은 기본적으로 사용자 데이터를 데이터베이스에 쓰는 데 걸리는 시간과 동일하며, 등록 이메일을 보내고 등록 SMS 메시지를 보낸 후 실행 결과를 메시지 큐에 기록한 후 반환할 수 있습니다. 메시지 큐를 쓰는 데 걸리는 시간은 매우 짧고 빠르며 거의 무시할 수 있습니다. 또한 시스템 처리량을 직렬 모드보다 거의 3배 더 높은 20QPS( 초당 쿼리 속도 )로 늘릴 수 있습니다. 병렬 모드보다 몇 배 더 높습니다.
QPS: 초당 쿼리 속도는 특정 쿼리 서버가 지정된 기간 내에 처리하는 트래픽의 양을 측정한 것입니다.
인터넷에서 초당 쿼리 속도는 도메인 이름 시스템 서버 시스템의 성능을 측정하는 데 자주 사용되며, 이는 최대 처리량인 초당 응답 요청 수인 fetches/sec 에 해당하는 QPS 입니다. .
2. 애플리케이션 분리
시나리오: 특정 시스템 A가 다른 시스템(즉, 호출 방법)을 처리해야 하는데, 다른 시스템이 변경되거나 새로운 시스템이 추가되면 시스템 A도 변경됩니다. 이 경우 결합도가 상대적으로 높고 더 많습니다. 귀찮은.
미들웨어 패턴: 이 문제를 해결하려면 메시지 대기열을 사용하세요.
우리의 A 시스템은 생성된 데이터를 메시지 큐로 보내고 다른 시스템은 메시지 큐로 이동하여 소비하므로 다른 시스템의 축소 또는 추가는 A 시스템과 거의 관련이 없으므로 디커플링 기능을 달성합니다.
3. 트래픽 샤프닝
예를 들어, 제품 플래시 세일 비즈니스의 경우 일반적으로 트래픽이 급격히 증가하고 과도한 트래픽으로 인해 애플리케이션이 중단됩니다. 이 문제를 해결하려면 일반적으로 애플리케이션 프런트 엔드에 메시지 대기열을 추가해야 합니다.
1) 이벤트 참여 인원을 조절할 수 있습니다.
2) 높은 트래픽으로 인한 신청에 대한 큰 부담을 단시간에 완화할 수 있습니다.
처리 방법은 그림과 같습니다.
1) 서버는 사용자 요청을 받은 후 먼저 메시지 큐에 씁니다. 이때, 메시지 큐의 메시지 개수가 최대 개수를 초과하는 경우 사용자 요청이 바로 거부되거나 오류 페이지가 반환됩니다.2
) 플래시세일 사업자는 메시지 큐에 있는 요청 정보를 다음 지침에 따라 읽습니다. 플래시 세일 규칙을 적용하고 후속 처리를 수행합니다.
4. 메시지 통신
로그 처리란 Kafka 애플리케이션과 같은 로그 처리에서 메시지 큐를 사용하여 로그 전송량이 많은 문제를 해결하는 것을 의미합니다.
로그 수집 클라이언트: 로그 데이터 수집, Kafka 대기열에 대한 예약된 쓰기 및 쓰기를 담당합니다.
Kafka 메시지 대기열: 로그 데이터 수신, 저장 및 전달을 담당합니다.
로그 처리 애플리케이션: Kafka 대기열에서 로그 데이터를 구독하고 사용합니다.
(2) 메시지 큐 사용의 단점
1. 시스템 가용성이 감소합니다: 시스템 가용성이 어느 정도 감소합니다.이렇게 말하는 이유는 무엇입니까? MQ에 가입하기 전에는 메시지 손실이나 MQ 끊김 등을 걱정할 필요가 없습니다. 하지만 MQ를 도입한 후에는 생각해 볼 필요가 있습니다!
2. 시스템 복잡도 증가: MQ에 가입한 후에는 메시지가 반복적으로 소비되지 않는지 확인하고, 메시지 손실을 처리하고, 메시지 전달 순서를 확인하는 등의 문제를 해결해야 합니다!
3. 일관성 문제: 메시지 큐는 비동기화를 달성할 수 있으며, 메시지 큐에 의한 비동기화는 실제로 시스템 응답 속도를 향상시킬 수 있습니다. 하지만 메시지의 실제 소비자가 메시지를 올바르게 소비하지 않으면 어떻게 될까요? 이로 인해 데이터 불일치가 발생합니다.
(3) 공통 메시지 대기열
공통 메시지 대기열 비교 |
---|
액티브MQ | RabbitMQ | 로켓MQ | 카프카 | |
개발 언어 | 자바 | 얼랭 | 자바 | 스칼라 |
단일 머신 처리량 | 레벨 10,000 | 레벨 10,000 | 십만 레벨 | 십만 레벨 |
적시 | ms 수준 | 우리 수준 | ms 수준 | ms 수준 이내 |
유효성 | 높음(마스터-슬레이브 아키텍처) | 높음(마스터-슬레이브 아키텍처) | 매우 높음(분산 아키텍처) | 매우 높음(분산 아키텍처) |
특징 | 많은 회사에서 사용되는 성숙한 제품, 더 많은 문서가 있고 다양한 프로토콜을 잘 지원합니다. | Erlang을 기반으로 개발되었으며 강력한 동시성 기능, 매우 우수한 성능, 짧은 대기 시간 및 풍부한 관리 인터페이스를 갖추고 있습니다. | MQ는 상대적으로 완전한 기능과 우수한 확장성을 가지고 있습니다. | MQ의 주요 기능만 지원되며 일부 메시지 쿼리, 메시지 추적 및 기타 기능은 제공되지 않으며 결국 빅데이터용으로 준비되어 빅데이터 분야에서 널리 사용됩니다. |
위의 비교를 바탕으로 다음과 같은 결론을 내릴 수 있습니다.
1) 중소 소프트웨어 회사 의 경우 얼랭 언어는 본질적으로 높은 동시성이 특징 이고 관리 인터페이스가 사용하기 매우 편리하므로 RabbitMQ를 선택하는 것이 좋습니다. 속담처럼 샤오허도 성공하고 샤오허는 실패자입니다! 단점도 여기에 있습니다 .RabbitMQ 는 오픈 소스이지만 중국에서 Erlang을 사용자 정의하고 개발할 수 있는 프로그래머는 몇 명입니까 ? 다행스럽게도 RabbitMQ 커뮤니티는 매우 활발하여 개발 과정에서 발생하는 버그를 해결할 수 있습니다 . 이는 중소기업에게 매우 중요합니다. Kafka를 고려하지 않는 이유 는 중소 소프트웨어 회사가 그다지 좋지 않기 때문입니다. 인터넷 기업이고 데이터량이 그리 많지 않기 때문에 비교적 완전한 기능을 갖춘 메시지 미들웨어를 선호 해야 하므로 Kafka 는 Rocketmq 를 제외합니다 . 그리고 중견 기업에서는 일반적으로 RocketMQ 의 맞춤형 개발을 수행할 인력을 확보할 수 없으므로 권장하지 않습니다.
2) 대형 소프트웨어 회사는 특정 애플리케이션을 기반으로 RocketMQ 와 Kafka 중 하나를 선택해야 합니다
. 대형 소프트웨어 회사는 분산 환경을 구축할 수 있는 충분한 자금과 충분한 양의 데이터를 보유하고 있습니다. RocketMQ 의 경우 대규모 소프트웨어 회사에서도 RocketMQ 의 맞춤형 개발 에 인력을 투입할 수 있습니다. 결국 중국에는 JAVA 소스 코드를 수정할 수 있는 능력을 가진 사람이 여전히 꽤 많습니다 . Kafka 의 경우 비즈니스 시나리오에 따라 로그 수집 기능이 있는 경우 Kafka가 가장 먼저 선택됩니다 . 어느 것을 선택할지는 사용 시나리오에 따라 다릅니다.
(4) 메시지 큐의 고가용성
rcoketMQ 클러스터 에는 그림과 같이 다중 마스터 모드, 다중 마스터 및 다중 슬레이브 비동기 복제 모드, 다중 마스터 및 다중 슬레이브 동기 이중 쓰기 모드가 있습니다.
생산자는 NameServer 클러스터 의 노드 중 하나(임의로 선택됨) 와 긴 연결을 설정하고 정기적으로 NameServer 에서 Topic 라우팅 정보를 얻고 Topic 서비스를 제공하는 Broker Master 와 긴 연결을 설정 하고 정기적으로 Broker 에 하트비트를 보냅니다 . Producer는 Broker master 에게만 메시지를 보낼 수 있지만 Consumer는 다릅니다. Topic 서비스를 동시에 제공하는 Master 및 Slave 와 장기적인 연결을 설정합니다 . Broker Master 또는 Broker 의 메시지를 구독 할 수 있습니다. 노예 .
카프카
일반적인 Kafka 클러스터에는 여러 생산자 ( 웹 프런트 엔드 에서 생성된 페이지 보기 또는 서버 로그, 시스템 CPU , 메모리 등), 여러 브로커 ( Kafka는 수평 확장 지원)가 포함됩니다. 일반적으로 브로커 수가 많을수록 , 클러스터 처리 속도가 높아질수록 ), 여러 소비자 그룹 및 Zookeeper 클러스터. Kafka는 Zookeeper를 사용하여 클러스터 구성을 관리하고, 리더를 선택하고 , 소비자 그룹이 변경될 때 재조정합니다 . 생산자는 푸시 모드를 사용하여 브로커 에 메시지를 게시하고 , 소비자는 풀 모드를 사용하여 브로커 의 메시지를 구독하고 소비합니다 .
RabbitMQ: 일반적인 클러스터 모드와 미러 클러스터 모드도 있는데 여기서는 자세히 설명하지 않겠습니다.
(5) 메시지의 반복적인 소비
반복 소비 이유: 소비자가 메시지를 소비하면 소비가 완료된 후 확인 메시지를 메시지 대기열로 보냅니다. 메시지 대기열은 메시지가 소비되었음을 알고 메시지 대기열에서 메시지를 삭제합니다. . 단지 서로 다른 메시지 큐가 서로 다른 형태의 확인 정보를 보내는 것일 뿐입니다. 예를 들어 RabbitMQ는 ACK 확인 메시지를 보내고 RocketMQ는 CONSUME_SUCCESS 성공 플래그를 반환합니다 . Kafka 에는 실제로 오프셋 이라는 개념이 있습니다 . 간단히 말하면 모든 메시지에는 오프셋 이 있습니다 . kafka는 메시지를 소비한 후 오프셋을 제출하여 메시지 큐에 메시지 소비 사실을 알려야 합니다 . 반복적으로 소비되는 이유는 무엇입니까?네트워크 전송 및 기타 장애로 인해 확인 정보가 메시지 큐로 전송되지 않아 메시지 큐가 메시지를 소비했다는 사실을 알지 못하고 메시지를 다시 다른 소비자에게 배포하기 때문입니다. .
해결책:
1. 예를 들어, 이 메시지를 받고 데이터베이스에서 삽입 작업을 수행합니다. 그것은 쉬울 것입니다. 이 메시지에 고유한 기본 키를 제공하십시오. 그러면 소비가 반복되더라도 기본 키 충돌이 발생하여 데이터베이스의 더티 데이터를 방지할 수 있습니다. 2. 예: 이 메시지를 받고 redis를 수행
하는 경우 set 연산을 수행하면 몇 번을 설정해도 결과는 동일하므로 간단하고 해결할 필요가 없습니다. set 연산은 멱등 연산으로 간주됩니다. 3. 타사 매체를 준비
합니다 . 소비 기록. Redis를 예로 들어 메시지에 전역 ID를 할당하면 메시지가 소비되는 한 <id, message>가 KV 형식으로 Redis에 기록됩니다. 소비자가 소비를 시작하기 전에 먼저 Redis에 소비 기록이 있는지 확인할 수 있습니다.
(6) 소비의 성적 전달
각 MQ 유형은 생산자의 데이터 손실, 메시지 큐의 데이터 손실, 소비자의 데이터 손실이라는 세 가지 관점에서 분석되어야 합니다.
RabbitMQ
1. 생산자는 데이터를 잃습니다.
데이터가 손실되는 생산자의 관점에서 RabbitMQ는 생산자가 메시지를 잃지 않도록 트랜잭션 및 확인 모드를 제공합니다 .
트랜잭션 메커니즘은 메시지를 보내기 전에 트랜잭션( channel.txSelect() )을 열고 다음을 보내는 것을 의미합니다. 메시지를 보내는 경우 트랜잭션에서 예외가 발생하면 트랜잭션이 롤백됩니다( channel.txRollback() ).전송이 성공하면 트랜잭션이 제출됩니다( channel.txCommit() )
. 단점은 처리량이 감소한다는 것입니다. 따라서 확인 모드는 프로덕션 환경에서 주로 사용됩니다. 채널이 확인 모드 에 들어가면 채널 에 게시된 모든 메시지에 고유 ID가 할당됩니다 (1부터 시작). 메시지가 일치하는 모든 대기열에 전달되면 RabbitMQ 는 생산자에게 Ack 를 보냅니다. 메시지 )를 통해 생성자는 메시지가 대상 큐에 올바르게 도착했음을 알 수 있습니다. rabiitMQ가 메시지 처리에 실패하면 Nack 메시지 를 보내며 작업을 다시 시도할 수 있습니다.
2. 메시지 대기열의 데이터가 손실됩니다.
메시지 큐에서 데이터가 손실되는 상황을 처리하려면 일반적으로 영구 디스크 구성을 활성화해야 합니다. 이 지속성 구성은 확인 메커니즘 과 함께 사용할 수 있으며 , 메시지가 디스크에 지속된 후 생산자에게 확인 신호를 보낼 수 있습니다. 이런 방식으로 메시지가 디스크에 유지되기 전에 RabbitMQ가 종료되면 생산자는 Ack 신호를 받을 수 없으며 생산자는 자동으로 이를 다시 보냅니다
. 그렇다면 이를 지속하는 방법은 실제로 매우 쉽습니다. 다음 두 단계를 따르십시오. :
1. 큐 의 Durable 플래그가 **true로 설정되어 ** 내구성이 있는 큐를 나타냅니다
. 2. 메시지를 보낼 때 DeliveryMode =2로 설정합니다. 이렇게 DeliveryMode =2
로 설정한 후에 는 RabbitMQ 가 멈춰도 데이터가 다시 시작한 후에 복원할 수 있습니다.
3. 소비자의 데이터 손실
소비자는 일반적으로 자동 확인 메시지 모드를 사용하므로 데이터가 손실됩니다. 이 모드에서는 소비자가 메시지 수신을 자동으로 확인합니다. 이때 rahbitMQ는 즉시 메시지를 삭제하는데, 이 경우 소비자가 예외를 만나 메시지 처리에 실패하면 메시지가 유실되므로 해결 방법은 수동으로 메시지를 확인하면 된다
.
2. RabbitMQ 설치
1. 얼랭 설치
Erlang 공식 다운로드: 다운로드 - Erlang/OTP
[root@servers ~]# yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel
[root@servers ~]# tar xvf otp_src_24.2-rc1.tar.gz
[root@servers ~]# cd otp_src_24.2
[root@servers otp_src_24.2]# ./configure --prefix=/usr/local/erlang --with-ssl -enable-threads -enable-smmp-support -enable-kernel-poll --enable-hipe --without-javac
[root@servers otp_src_24.2]# make && make install
[root@servers otp_src_24.2]# vim /etc/profile
................ 在最后加入
........
ERLANG_HOME=/usr/local/erlang
PATH=$ERLANG_HOME/bin:$PATH
export ERLANG_HOME
export PATH
保存
root@servers ~]# source /etc/profile
[root@servers ~]# erl #验证是否安装成功
Erlang/OTP 24 [erts-12.0] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1]
Eshell V12.0 (abort with ^G)
1>
ctrl + C 退出 如果一次没有退出就多按几次
2. RadditMQ 설치
RabbitMQ 다운로드: https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.9.12
[root@servers ~]# xz -d rabbitmq-server-generic-unix-3.9.12.tar.xz
[root@servers ~]# tar xf rabbitmq-server-generic-unix-3.9.12.tar
[root@servers ~]# cp -rf rabbitmq_server-3.9.12 /usr/local/
[root@servers ~]# cd /usr/local/
[root@servers local]# mv rabbitmq_server-3.9.12 rabbitmq
[root@servers local]# cd rabbitmq/sbin/
[root@servers sbin]# ./rabbitmq-plugins enable rabbitmq_management #开启管理页面插件
Enabling plugins on node rabbit@C7--13:
rabbitmq_management
The following plugins have been configured:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
Applying plugin configuration to rabbit@C7--13...
The following plugins have been enabled:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
set 3 plugins.
Offline change; changes will take effect at broker restart.
서비스 시작 및 종료
[root@servers sbin]# ./rabbitmq-server #启动,ctrl + c 退出及关闭
[root@servers sbin]# ./rabbitmq-server -detached #在后台启动服务
[root@servers sbin]# ./rabbitmqctl stop #关闭服务
관리자 계정 추가
백그라운드에서 시작한 후 사용자 추가
添加用户格式: ./rabbitmqctl add_user 用户名 密码
[root@servers sbin]# ./rabbitmqctl add_user admin 123.com
Adding user "admin" ...
Done. Don't forget to grant the user permissions to some virtual hosts! See 'rabbitmqctl help set_permissions' to learn more.
分配用户标签格式: ./rabbitmqctl add_user_tags 用户名 管理员标签[administrator]
[root@servers sbin]# ./rabbitmqctl set_user_tags admin administrator
Setting tags for user "admin" to [administrator] ...
액세스 테스트
이전에 설정한 사용자: admin, 비밀번호: 123.com을 입력하여 로그인하세요.
3. RabbitMQ에 대한 자세한 설명
(1) AMQP 소개
RabbitMQ 는 AMQP 프로토콜 (Advanced Message Queuing Protocol)을 구현하는 오픈 소스 메시지 브로커 소프트웨어(메시지 지향 미들웨어라고도 함) 입니다. RabbitMQ 서버는 Erlang 언어 로 작성되었으며 클러스터링 및 장애 조치는 Open Telecommunications Platform 프레임워크를 기반으로 구축되었습니다. 모든 주요 프로그래밍 언어에는 프록시 인터페이스와 통신하는 클라이언트 라이브러리가 있습니다.
AMQP
프로토콜 : Advanced Message Queuing Protocol은 애플리케이션 계층 프로토콜에 대한 개방형 표준이며 메시지 지향 미들웨어용으로 설계되었습니다. 메시지 미들웨어는 주로 구성 요소 간의 분리에 사용됩니다. 메시지 발신자는 메시지 소비자의 존재를 알 필요가 없으며 그 반대도 마찬가지입니다. 프로토콜의 주요 기능은
AMQP
메시지 지향, 대기열, 라우팅(지점 포함)입니다. -point 및 게시/구독) 및 안정성. Secure
RabbitMQ 는 오픈 소스 AMQP 구현입니다. 서버는 Erlang 언어로 작성되었으며 Python , Ruby , .NET , Java , JMS , C 와 같은 다양한 클라이언트를 지원합니다., PHP , ActionScript , XMPP , STOMP 등을 지원하며 AJAX를 지원합니다 . 분산 시스템에서 메시지를 저장하고 전달하는 데 사용되며 사용 용이성, 확장성 및 고가용성 측면에서 우수한 성능을 발휘합니다.
AMQP 3계층 프로토콜 | |
---|---|
모듈 레이어 | 프로토콜의 최상위 레벨에 위치하며 주로 클라이언트가 호출할 몇 가지 명령을 정의합니다. 클라이언트는 이러한 명령을 사용하여 자체 비즈니스 로직을 구현할 수 있습니다. 예를 들어 클라이언트는 queue.declare를 통해 큐를 선언하고 소비를 사용할 수 있습니다. 대기열 에 있는 메시지 를 가져오는 명령입니다 . |
세션 계층 | 클라이언트의 명령을 서버에 보내고, 서버의 응답을 클라이언트에 반환하는 역할을 주로 담당하며, 클라이언트와 서버 간의 통신에 대한 신뢰성, 동기화 메커니즘 및 오류 처리 기능을 제공하는 역할을 주로 담당합니다. |
전송 계층 | 주로 이진 데이터 스트림을 전송하고 프레임 처리, 채널 다중화, 오류 감지 및 데이터 표현을 제공합니다. |
(2) 기능
저장 및 전달 | 여러 메시지 발신자, 단일 메시지 수신자 |
---|---|
분산 트랜잭션 | 여러 메시지 발신자, 여러 메시지 수신자 |
발행구독 | 여러 메시지 발신자, 여러 메시지 수신자 |
콘텐츠 기반 라우팅 | 여러 메시지 발신자, 여러 메시지 수신자 |
파일 전송 대기열 | 여러 메시지 발신자, 여러 메시지 수신자 |
지점 간 연결 | 단일 메시지 발신자, 단일 메시지 수신자 |
(3) 용어 설명
AMQP 모델( AMQP Model ) |
AMQP 호환 서버가 제공해야 하는 주요 엔터티 및 의미 체계로 표현되는 논리적 프레임워크입니다 . 이 사양에 정의된 의미를 구현하기 위해 클라이언트는 AMQP 서버를 제어하는 명령을 보낼 수 있습니다. |
---|---|
연결( Connection ) |
TCP/IP 소켓 연결 과 같은 네트워크 연결 |
세션( Session ) |
엔드포인트 간의 명명된 대화. 세션 컨텍스트 내에서 "정확히 한 번" 전달이 보장됩니다. |
채널( Channel ) |
다중화된 연결 내의 독립적인 양방향 데이터 흐름 채널입니다. 세션에 대한 물리적 전송 매체 제공 |
클라이언트( Client ) |
AMQP 연결 또는 세션의 개시자입니다. AMQP 는 비대칭이며 클라이언트는 메시지를 생성하고 소비하며 서버는 이러한 메시지를 저장하고 라우팅합니다. |
서버( Server ) |
클라이언트 연결을 수락하고 AMQP 메시지 대기열 및 라우팅 기능을 구현하는 프로세스입니다. "메시지 브로커"라고도 함 |
끝점( Peer ) |
AMQP 대화의 당사자 중 하나입니다. AMQP 연결은 두 개의 엔드포인트(하나는 클라이언트이고 다른 하나는 서버)로 구성됩니다. |
파트너( Partner ) |
두 끝점 간의 상호 작용을 설명할 때 "파트너"라는 용어는 "다른" 끝점을 줄여서 사용합니다. 예를 들어 엔드포인트 A와 엔드포인트 B를 정의합니다. 이들이 통신할 때 엔드포인트 B는 엔드포인트 A의 파트너이고 엔드포인트 A는 엔드포인트 B의 파트너입니다. |
조각 세트( Assembly ) |
논리적 작업 단위를 형성하는 정렬된 세그먼트 모음 |
세그먼트( Segment ) |
조각 세트의 완전한 하위 단위를 형성하는 정렬된 프레임 모음 |
프레임( Frame ) |
AMQP 전송의 원자 단위입니다. 프레임은 세그먼트의 모든 조각입니다. |
제어( Control ) |
단방향 명령어, AMQP 사양에서는 이러한 명령어의 전송이 신뢰할 수 없다고 가정합니다. |
명령( Command ) |
확인이 필요한 지침 AMQP 사양은 이러한 지침의 전송이 신뢰할 수 있다고 규정합니다. |
예외( Exception ) |
하나 이상의 명령을 실행할 때 발생할 수 있는 오류 상태 |
수업 ( Class ) |
특정 기능을 설명하는 데 사용되는 일련의 AMQP 명령 또는 컨트롤 |
메시지 헤더( Header ) |
메시지 데이터 속성을 설명하는 특수 섹션 |
메시지 본문( Body ) |
包含应用程序数据的一种特殊段。消息体段对于服务器来说完全透明——服务器不能查看或者修改消息体 |
消息内容(Content ) |
包含在消息体段中的的消息数据 |
交换器(Exchange ) |
服务器中的实体,用来接收生产者发送的消息并将这些消息路由给服务器中的队列 |
交换器类型(Exchange Type ) |
基于不同路由语义的交换器类 |
消息队列(Message Queue ) |
一个命名实体,用来保存消息直到发送给消费者 |
绑定器(Binding ) |
消息队列和交换器之间的关联 |
绑定器关键字(Binding Key ) |
绑定的名称。一些交换器类型可能使用这个名称作为定义绑定器路由行为的模式 |
路由关键字(Routing Key ) |
一个消息头,交换器可以用这个消息头决定如何路由某条消息 |
持久存储(Durable ) |
一种服务器资源,当服务器重启时,保存的消息数据不会丢失 |
临时存储(Transient ) |
一种服务器资源,当服务器重启时,保存的消息数据会丢失 |
持久化(Persistent ) |
服务器将消息保存在可靠磁盘存储中,当服务器重启时,消息不会丢失 |
非持久化(Non-Persistent ) |
服务器将消息保存在内存中,当服务器重启时,消息可能丢失 |
消费者(Consumer ) |
一个从消息队列中请求消息的客户端应用程序 |
生产者(Producer ) |
一个向交换器发布消息的客户端应用程序 |
虚拟主机(Virtual Host ) |
一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。客户端应用程序在登录到服务器之后,可以选择一个虚拟主机 |
(四)、RabbitMQ的工作流程
消息队列有三个概念: 发消息者、消息队列、收消息者。RabbitMQ 在这个基本概念之上, 多做了一层抽象, 在发消息者和队列之间, 加入了交换器 (Exchange)。这样发消息者和消息队列就没有直接联系,转而变成发消息者把消息发给交换器,交换器根据调度策略再把消息转发给消息队列
消息生产者并没有直接将消息发送给消息队列,而是通过建立与Exchange的Channel,将消息发送给Exchange。Exchange根据路由规则,将消息转发给指定的消息队列。消息队列储存消息,等待消费者取出消息。消费者通过建立与消息队列相连的Channel,从消息队列中获取消息
Producer(消息的生产者) | 向消息队列发布消息的客户端应用程序 |
---|---|
Channel(信道) | 多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,复用TCP连接的通道 |
Routing Key(路由键) | 消息头的一个属性,用于标记消息的路由规则,决定了交换机的转发路径。最大长度255 字节 |
Broker | RabbitMQ Server,服务器实体 |
Binding(绑定) | 用于建立Exchange和Queue之间的关联。一个绑定就是基于Binding Key将Exchange和Queue连接起来的路由规则,所以可以将交换器理解成一个由Binding构成的路由表 |
Exchange(交换器|路由器) | 提供Producer到Queue之间的匹配,接收生产者发送的消息并将这些消息按照路由规则转发到消息队列。交换器用于转发消息,它不会存储消息 ,如果没有 Queue绑定到 Exchange 的话,它会直接丢弃掉 Producer 发送过来的消息。交换器有四种消息调度策略,分别是fanout, direct, topic, headers |
Binding Key(绑定键) | Exchange与Queue的绑定关系,用于匹配Routing Key。最大长度255 字节 |
Queue(消息队列) | 存储消息的一种数据结构,用来保存消息,直到消息发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将消息取走。需要注意,当多个消费者订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理,每一条消息只能被一个订阅者接收 |
Consumer(消息的消费者) | 从消息队列取得消息的客户端应用程序 |
Message(消息) | 消息由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由键)、priority(消息优先权)、delivery-mode(是否持久性存储)等 |
(五)、Exchange消息调度策略
交换器的功能主要是接收消息并且转发到绑定的队列,交换器不存储消息,在启用ack模式后,交换器找不到队列会返回错误
调度策略是指Exchange在收到生产者发送的消息后依据什么规则把消息转发到一个或多个队列中保存。调度策略与三个因素相关:Exchange Type(Exchange的类型),Binding Key(Exchange和Queue的绑定关系),消息的标记信息(Routing Key和headers)
Exchange根据消息的Routing Key和Exchange绑定Queue的Binding Key分配消息。生产者在将消息发送给Exchange的时候,一般会指定一个Routing Key,来指定这个消息的路由规则,而这个Routing Key需要与Exchange Type及Binding Key联合使用才能最终生效
在Exchange Type与Binding Key固定的情况下(一般这些内容都是固定配置好的),我们的生产者就可以在发送消息给Exchange时,通过指定Routing Key来决定消息流向哪里
交换器的四种消息调度策略:fanout, direct, topic, headers
1、Fanout (订阅模式**/**广播模式)
交换器会把所有发送到该交换器的消息路由到所有与该交换器绑定的消息队列中。订阅模式
与Binding Key和Routing Key无关,交换器将接受到的消息分发给有绑定关系的所有消息队列队列(不论Binding Key和Routing Key是什么)。类似于子网广播,子网内的每台主机都获得了一份复制的消息。Fanout交换机转发消息是最快的
2、Direct(路由模式)
精确匹配:当消息的Routing Key与 Exchange和Queue 之间的Binding Key完全匹配,如果匹配成功,将消息分发到该Queue。只有当Routing Key和Binding Key完全匹配的时候,消息队列才可以获取消息。Direct是Exchange的默认模式
RabbitMQ默认提供了一个Exchange,名字是空字符串,类型是Direct,绑定到所有的Queue(每一个Queue和这个无名Exchange之间的Binding Key是Queue的名字)。所以,有时候我们感觉不需要交换器也可以发送和接收消息,但是实际上是使用了RabbitMQ默认提供的Exchange
3、Topic (通配符模式)
按照正则表达式模糊匹配:用消息的Routing Key与 Exchange和Queue 之间的Binding Key进行模糊匹配,如果匹配成功,将消息分发到该Queue
Routing Key是一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词)。Binding Key与Routing Key一样也是句点号“. ”分隔的字符串。Binding Key中可以存在两种特殊字符“ * ”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
4、Headers(键值对模式)
Headers不依赖于Routing Key与Binding Key的匹配规则来转发消息,交换器的路由规则是通过消息头的Headers属性来进行匹配转发的,类似HTTP请求的Headers
在绑定Queue与Exchange时指定一组键值对,键值对的Hash结构中要求携带一个键“x-match”,这个键的Value可以是any或all,代表消息携带的Hash是需要全部匹配(all),还是仅匹配一个键(any)
当消息发送到Exchange时,交换器会取到该消息的headers,对比其中的键值对是否完全匹配Queue与Exchange绑定时指定的键值对;如果完全匹配则消息会路由到该Queue,否则不会路由到该Queue。Headers交换机的优势是匹配的规则不被限定为字符串(String),而是Object类型
(六)、RPC(Remote Procedure Call,远程过程调用)
MQ本身是基于异步的消息处理,前面的示例中所有的生产者(P)将消息发送到RabbitMQ后不会知道消费者(C)处理成功或者失败(甚至连有没有消费者来处理这条消息都不知道)
但实际的应用场景中,我们很可能需要一些同步处理,需要同步等待服务端将我的消息处理完成后再进行下一步处理。这相当于RPC(Remote Procedure Call,远程过程调用)。在RabbitMQ中也支持RPC
RabbitMQ中实现RPC的机制是:
1、客户端发送请求(消息)时,在消息的属性(MessageProperties,在AMQP协议中定义了14个属性,这些属性会随着消息一起发送)中设置两个值replyTo(一个Queue名称,用于告诉服务器处理完成后将通知我的消息发送到这个Queue中)和correlationId(此次请求的标识号,服务器处理完成后需要将此属性返还,客户端将根据这个id了解哪条请求被成功执行了或执行失败)
2、服务器端收到消息并处理
3、服务器端处理完消息后,将生成一条应答消息到replyTo指定的Queue,同时带上correlationId属性
4、客户端之前已订阅replyTo指定的Queue,从中收到服务器的应答消息后,根据其中的correlationId属性分析哪条请求被执行了,根据执行结果进行后续业务处理
(七)、消息确认:Message acknowledgment
在实际应用中,可能会发生消费者收到Queue中的消息,但没有处理完成就宕机(或出现其他意外)的情况,这种情况下就可能会导致消息丢失。为了避免这种情况发生,我们可以要求消费者在消费完消息后发送一个回执给RabbitMQ,RabbitMQ收到消息回执(Message acknowledgment)后才将该消息从Queue中移除;如果RabbitMQ没有收到回执并检测到消费者的RabbitMQ连接断开,则RabbitMQ会将该消息发送给其他消费者(如果存在多个消费者)进行处理。这里不存在Timeout概念,一个消费者处理消息时间再长也不会导致该消息被发送给其他消费者,除非它的RabbitMQ连接断开
这里会产生另外一个问题,如果我们的开发人员在处理完业务逻辑后,忘记发送回执给RabbitMQ,这将会导致严重的问题,Queue中堆积的消息会越来越多,消费者重启后会重复消费这些消息并重复执行业务逻辑
如果我们采用no-ack的方式进行确认,也就是说,每次Consumer接到数据后,而不管是否处理完成,RabbitMQ会立即把这个Message标记为完成,然后从queue中删除了
(八)、消息持久化:Message durability
如果我们希望即使在RabbitMQ服务重启的情况下,也不会丢失消息,我们可以将Queue与Message都设置为可持久化的(durable),这样可以保证绝大部分情况下我们的RabbitMQ消息不会丢失。但依然解决不了小概率丢失事件的发生(比如RabbitMQ服务器已经接收到生产者的消息,但还没来得及持久化该消息时RabbitMQ服务器就断电了),如果我们需要对这种小概率事件也要管理起来,那么我们要用到事务
(九)、分发机制
我们在应用程序使用消息系统时,一般情况下生产者往队列里插入数据时速度是比较快的,但是消费者消费数据往往涉及到一些业务逻辑处理导致速度跟不上生产者生产数据。因此如果一个生产者对应一个消费者的话,很容易导致很多消息堆积在队列里。这时,就得使用工作队列了。一个队列有多个消费者同时消费数据
工作队列有两种分发数据的方式: 轮询分发(Round-robin)和 公平分发(Fair dispatch)
轮询分发:队列给每一个消费者发送数量一样的数据
公平分发: 消费者设置每次从队列中取一条数据,并且消费完后手动应答,继续从队列取下一个数据
1、轮询分发:Round-robin dispatching
如果工作队列中有两个消费者,两个消费者得到的数据量一样的,并不会因为两个消费者处理数据速度不一样使得两个消费者取得不一样数量的数据。但是这种分发方式存在着一些隐患,消费者虽然得到了消息,但是如果消费者没能成功处理业务逻辑,在RabbitMQ中也不存在这条消息。就会出现消息丢失并且业务逻辑没能成功处理的情况
2、公平分发:Fair dispatch
消费者设置每次从队列里取一条数据,并且关闭自动回复机制,每次取完一条数据后,手动回复并继续取下一条数据。与轮询分发不同的是,当每个消费都设置了每次只会从队列取一条数据时,并且关闭自动应答,在每次处理完数据后手动给队列发送确认收到数据。这样队列就会公平给每个消息费者发送数据,消费一条再发第二条,而且可以在管理界面中看到数据是一条条随着消费者消费完从而减少的,并不是一下子全部分发完了。采用公平分发方式就不会出现消息丢失并且业务逻辑没能成功处理的情况
(十)、事务
对事务的支持是AMQP协议的一个重要特性。假设当生产者将一个持久化消息发送给服务器时,因为consume 命令本身没有任何Response返回,所以即使服务器崩溃,没有持久化该消息,生产者也无法获知该消息已经丢失。如果此时使用事务,即通过txSelect()开启一个事务,然后发送消息给服务器,然后通过txCommit() 提交该事务,即可以保证,如果txCommit()提交了,则该消息一定会持久化,如果txCommit() 还未提交即服务器崩溃,则该消息不会服务器接收。当然Rabbit MQ 也提供了txRollback() 命令用于回滚某一个事务
(十一)、Confirm机制
使用事务固然可以保证只有提交的事务,才会被服务器执行。但是这样同时也将客户端与消息服务器同步起来,这背离了消息队列解耦的本质。Rabbit MQ提供了一个更加轻量级的机制来保证生产者可以感知服务器消息是否已被路由到正确的队列中——Confirm。如果设置channel为confirm状态,则通过该channel发送的消息都会被分配一个唯一的ID,然后一旦该消息被正确的路由到匹配的队列中后,服务器会返回给生产者一个Confirm,该Confirm包含该消息的ID,这样生产者就会知道该消息已被正确分发。对于持久化消息,只有该消息被持久化后,才会返回Confirm。Confirm机制的最大优点在于异步,生产者在发送消息以后,即可继续执行其他任务。而服务器返回Confirm后,会触发生产者的回调函数,生产者在回调函数中处理Confirm信息。如果消息服务器发生异常,导致该消息丢失,会返回给生产者一个nack,表示消息已经丢失,这样生产者就可以通过重发消息,保证消息不丢失。Confirm机制在性能上要比事务优越很多。但是Confirm机制,无法进行回滚,就是一旦服务器崩溃,生产者无法得到Confirm信息,生产者其实本身也不知道该消息是否已经被持久化,只有继续重发来保证消息不丢失,但是如果原先已经持久化的消息,并不会被回滚,这样队列中就会存在两条相同的消息,系统需要支持去重
(十二)、Alternate Exchange(代替交换器)
Alternate Exchange是Rabbitmq自己扩展的功能,不是AMQP协议定义的
创建Exchange指定该Exchange的Alternate Exchange,发送消息的时候如果Exchange没有成功把消息路由到队列中去,这就会将此消息路由到Alternate Exchange属性指定的Exchange上了。需要在创建Exchange时添加alternate-exchange属性。如果Alternate Exchange也没能成功把消息路由到队列中去,这个消息就会丢失。可以触发publish confirm机制,表示这个消息没有确认
创建交换器时需要指定如下属性
Map<String,Object> argsMap = new HashMap<>();
argsMap.put(“alternate-exchange”,“Alternate Exchange Name”);
(十三)、TTL(生存时间)
RabbitMQ允许您为消息和队列设置TTL(生存时间)。 可以使用可选的队列参数或策略完成(推荐使用后一个选项)。 可以为单个队列,一组队列或单个消息应用消息TTL
设置消息的过期时间
MessageProperties messageProperties = new MessageProperties();
messageProperties.setExpiration(“30000”);
设置队列中消息的过期时间
在声明一个队列时,可以指定队列中消息的过期时间,需要添加x-message-ttl属性
Map<String, Object> arguments = new HashMap<>();
arguments.put(“x-message-ttl”,30000);
如果同时制定了Message TTL,Queue TTL,则时间短的生效
(十四)、Queue Length Limit(队列长度限制)
可以设置队列中消息数量的限制,如果测试队列中最多只有5个消息,当第六条消息发送过来的时候,会删除最早的那条消息。队列中永远只有5条消息
使用代码声明含有x-max-length和x-max-length-bytes属性的队列
Max length(x-max-length) 用来控制队列中消息的数量
如果超出数量,则先到达的消息将会被删除掉
Max length bytes(x-max-length-bytes) 用来控制队列中消息总的大小
如果超过总大小,则最先到达的消息将会被删除,直到总大小不超过x-max-length-byte为止
Map<String, Object> arguments = new HashMap<>();
arguments.put(“x-max-length”,3); #表示队列中最多存放三条消息
Map<String, Object> arguments = new HashMap<>();
arguments.put(“x-max-length-bytes”,10); #队列中消息总的空间大小
(十五)、Dead Letter Exchange(死信交换器)
在队列上指定一个Exchange,则在该队列上发生如下情况
1、 消息被拒绝(basic.reject or basic.nack),且requeue=false
2、 消息过期而被删除(TTL)
3、 消息数量超过队列最大限制而被删除
4、 消息总大小超过队列最大限制而被删除
就会把该消息转发到指定的这个exchange
需要定义了x-dead-letter-exchange属性,同时也可以指定一个可选的x-dead-letter-routing-key,表示默认的routing-key,如果没有指定,则使用消息原来的routeing-key进行转发
当定义队列时指定了x-dead-letter-exchange(x-dead-letter-routing-key视情况而定),并且消费端执行拒绝策略的时候将消息路由到指定的Exchange中去
我们知道还有二种情况会造成消息转发到死信队列
一种是消息过期而被删除,可以使用这个方式使的rabbitmq实现延迟队列的作用。还有一种就是消息数量超过队列最大限制而被删除或者消息总大小超过队列最大限制而被删除
(十六)、priority queue(优先级队列)
声明队列时需要指定x-max-priority属性,并设置一个优先级数值
消息优先级属性
MessageProperties messageProperties = new MessageProperties();
messageProperties.setPriority(priority);
如果设置的优先级小于等于队列设置的x-max-priority属性,优先级有效
如果设置的优先级大于队列设置的x-max-priority属性,则优先级失效
创建优先级队列,需要增加x-max-priority参数,指定一个数字。表示最大的优先级,建议优先级设置为1~10之间
发送消息的时候,需要设置priority属性,最好不要超过上面指定的最大的优先级
如果生产端发送很慢,消费者消息很快,则有可能不会严格的按照优先级来进行消费
1、发送的消息的优先级属性小于设置的队列属性x-max-priority值,则按优先级的高低进行消费,数字越高则优先级越高
2、送的消息的优先级属性都大于设置的队列属性x-max-priority值,则设置的优先级失效,按照入队列的顺序进行消费
3、 费端一直进行监听,而发送端一条条的发送消息,优先级属性也会失效
RabbitMQ不能保证消息的严格的顺序消费
(十七)、延迟队列
延迟队列就是进入该队列的消息会被延迟消费的队列。而一般的队列,消息一旦入队了之后就会被消费者马上消费
延迟队列多用于需要延迟工作的场景
最常见的是以下两种场景:
1、 消费
如:用户生成订单之后,需要过一段时间校验订单的支付状态,如果订单仍未支付则需要及时地关闭订单
用户注册成功之后,需要过一段时间比如一周后校验用户的使用情况,如果发现用户活跃度较低,则发送邮件或者短信来提醒用户使用
2、延迟重试
如:消费者从队列里消费消息时失败了,但是想要延迟一段时间后自动重试
我们可以利用RabbitMQ的两个特性,一个是Time-To-Live Extensions,另一个是Dead Letter Exchanges。实现延迟队列
Time-To-Live Extensions
RabbitMQ允许我们为消息或者队列设置TTL(time to live),也就是过期时间。TTL表明了一条消息可在队列中存活的最大时间,单位为毫秒。也就是说,当某条消息被设置了TTL或者当某条消息进入了设置了TTL的队列时,这条消息会在经过TTL秒后“死亡”,成为Dead Letter。如果既配置了消息的TTL,又配置了队列的TTL,那么较小的那个值会被取用
Dead Letter Exchange
刚才提到了,被设置了TTL的消息在过期后会成为Dead Letter。其实在RabbitMQ中,一共有三种消息的“死亡”形式:
1、消息被拒绝。通过调用basic.reject或者basic.nack并且设置的requeue参数为false
2、消息因为设置了TTL而过期
3、消息进入了一条已经达到最大长度的队列
如果队列设置了Dead Letter Exchange(DLX),那么这些Dead Letter就会被重新publish到Dead Letter Exchange,通过Dead Letter Exchange路由到其他队列
四、RabbitMQ配置
(一)、RabbitMQ 常用命令
1、Vhost虚拟机
每个RabbitMQ服务器都能创建虚拟主机(virtual host),简称vhost。每个vhost本质上是一个独立的小型RabbitMQ服务器,拥有自己独立的队列、交换器及绑定关系等,并且它拥有自己独立的权限,RabbitMQ默认创建vhost为 /
”
创建vhost
rabbitmqctl add_vhost {
vhost}
查看所有vhost
rabbitmqctl list_vhosts
删除指定vhost
rabbitmqctl delete_vhost {
vhost}
2、用户管理
在RabbitMQ中,用户是访问控制的基本单元,且单个用户可以跨越多个vhost进行授权
创建用户
rabbitmqctl add_user {
username} {
password}
修改密码
rabbitmqctl change_password {
username} {
password}
清除密码
rabbitmqctl clear_password {
username}
验证用户
rabbitmqctl authenticate_user {
username} {
password}
删除用户
rabbitmqctl delete_user {
username}
用户列表
rabbitmqctl list_users
3、权限管理
用户权限指的是用户对exchange,queue的操作权限,包括配置权限,读写权限。配置权限会影响到exchange,queue的声明和删除。读写权限影响到从queue里取消息,向exchange发送消息以及queue和exchange的绑定(bind)操作
RabbitMQ中,权限控制是以vhost为单位,创建用户时,将被指定至少一个vhost,默认的vhost是 “ / ”
授予权限
rabbitmqctl set_permissions [-p vhost] {
user}{
conf}{
write}{
read}
配置项 | 说明 |
---|---|
vhost | 授权用户访问指定的vhost |
user | 用户名 |
conf | 一个用于匹配用户在哪些资源上拥有可配置权限的正则表达式,例如:".*"表示全部 |
write | 一个用于匹配用户在哪些资源上拥有可写权限的正则表达式 ,例如:".*"表示全部 |
read | 一个用于匹配用户在哪些资源上拥有可读权限的正则表达式,例如:".*"表示全部 |
收回权限
rabbitmqctl clear_permissions [-p vhost] {username}
虚拟主机权限列表
rabbitmqctl list_permissions [-p vhost]
查看指定用户权限
rabbitmqctl list_user_permissions {username}
4、角色分配
rabbitmq的角色有5种类型
rabbitmqctl set_user_tags {
username} {
tag…}
User为用户名
Tag为角色名(对应的administrator,monitoring,policymaker,management,或其他自定义名称)
也可以给同一用户设置多个角色,例:
rabbitmqctl set_user_tags hncscwc monitoring policymaker
配置项 | 说明 |
---|---|
none其他 | 无任何角色,新创建的用户默认角色为none |
management普通管理者 | 可以访问web管理页面,无法看到节点信息,也无法对策略进行管理 |
policymaker策略制定者 | 包含management的所有权限,并可以管理策略和参数,但无法查看节点的相关信息 |
monitoring监控者 | 包含management的所有权限,并可以看到所有连接(启用management plugin的情况下)、信道及节点相关信息(进程数,内存使用情况,磁盘使用情况等) |
administartor超级管理员 | 包含minitoring的所有权限,并可以管理用户、虚拟主机、权限、策略、参数 |
5、Web端管理
RabbitMQ Management 插件可以提供Web界面来管理RabbitMQ中的虚拟主机、用户、角色、队列、交换器、绑定关系、策略、参数等,也可用于监控RabbitMQ服务的状态及一些统计信息
启动插件
rabbitmq-plugins enable rabbitmq_management
关闭插件
rabbitmq-plugins disable rabbitmq_management
插件列表:其中标记为[E*]为显示启动,其中标记为[e*]为隐式启动,开启此功能后需要重启服务才可以正式生效
rabbitmq-plugins list
6、RabbitMQ 管理
[root@servers sbin]# ./rabbitmq-server #启动,ctrl + c 退出及关闭
[root@servers sbin]# ./rabbitmq-server -detached #在后台启动服务
[root@servers sbin]# ./rabbitmqctl stop #关闭服务
[root@C7--13 sbin]# ./rabbitmq-server status #查看状态
7、查看队列列表
rabbitmqctl list_queues[-p vhost][queueinfoitem…]
返回列 | 说明 |
---|---|
name | 队列名称 |
durable | 队列是否持久化 |
auto_delete | 队列是否自动删除 |
arguments | 队列参数 |
policy | 应用到队列上的策略名称 |
pid | 队列关联的进程ID |
owner_pid | 处理排他队列连接的进程ID |
exclusive | 队列是否排他 |
8、查看交换器列表
rabbitmqctl list_exchanges [-p vhost][exchangeinfoitem…]
返回列 | 说明 |
---|---|
name | 交换器名称 |
type | 交换器类型 |
durable | 交换器是否持久化 |
auto_delete | 交换器是否自动删除 |
internal | 是否是内置交换器 |
arguments | 交换器的参数 |
policy | 交换器的策略 |
9、查看绑定关系的列表
rabbitmqctl list_bindings [-p] [bindinginfoitem…]
返回列 | 说明 |
---|---|
source_name | 消息来源的名称 |
source_kind | 消息来源的类别 |
destination_name | 消息目的地的名称 |
destination_kind | 消息目的地的种类 |
routing_key | 绑定的路由键 |
arguments | 绑定的参数 |
10、查看连接信息列表
rabbitmqctl list_connections [connectioninfoitem …]
返回列 | 说明 |
---|---|
pid | 与连接相关的进程ID |
name | 连接名称 |
port | 服务器端口 |
host | 服务器主机名 |
peer_port | 服务器对端端口。当一个客户端与服务器连接时,这个客户端的端口就是peer_port |
peer_host | 服务器对端主机名称,或IP |
ssl | 是否启用SSL |
state | 连接状态,包括starting\tning\opening\running\flow\blocking\blocked\closing\closed |
channels | 连接中的信道个数 |
protocol | 使用的AMQP协议版本 |
user | 与连接相关的用户名 |
vhost | 与连接相关的vhost名称 |
timeout | 连接超时时长,单位秒 |
11、查看信道列表
rabbitmqctl list_channels [channelinfoitem…]
返回列 | 说明 |
---|---|
pid | 与连接相关的进程ID |
connection | 信道所属连接的进程ID |
name | 信道名称 |
number | 信道的序号 |
user | 与连接相关的用户名 |
vhost | 与连接相关的vhost名称 |
transactional | 信道是否处于事务模式 |
confirm | 信道是否处于 publisher confirm模式 |
consumer_count | 信道中的消费者个数 |
messages_unacknowledged | 已投递但是还未被ack的消息个数 |
messages_uncommitted | 已接收但是还未提交事务的消息个数 |
acks_uncommitted | 已ack收到但是还未提交事务的消息个数 |
messages_unconfirmed | 已发送但是还未确认的消息个数 |
perfetch_count | 消费者的Qos个数限制,0表示无上限 |
global_prefetch_count | 整个信道的Qos个数限制 |
12、查看消费者列表
rabbitmqctl list_consumers [-p vhost]
返回列 | 说明 |
---|---|
arguments | 参数 |
채널_피드 | 채널 프로세스 ID |
소비자_태그 | 소비자 마크 |
prefetch_count | 소비자의 Qos 수에 대한 제한 , 0은 상한이 없음을 의미합니다. |
대기열_이름 | 대기열 이름 |