원칙 특성의 요약 및 실현 rocketmq

면책 조항 :이 문서는 블로거 원본입니다, 소스를 표시하시기 바랍니다. https://blog.csdn.net/u010597819/article/details/89856951

다음 문서를 참조하는 각 모듈 시작 프로세스에 대한 자세한 정보 https://blog.csdn.net/u010597819/article/details/86646245를


메시지 보내기

  1. 요청 네임 서버는 테마에 따라 전달받을
  2. 선택 라우팅 정보 메시지 큐 MessageQueue가
  3. 당신은 sendLatencyFaultEnable을 사용하는 경우
  4. 마지막 인덱스 (난수가 존재하지 않는 경우) 증가, 브로커는 유효 후 첨자 큐에 대응하는리스트 MessageQueue가 큐를 읽을 경우 및 동일한 이전 리턴 큐 brokerName에 마지막 brokerName은 비어 있거나
  5. brokerName에있어서, 존재하는 경우, 여기서 brokerName latencyFaultTolerance 취득에 따른 기록 가능한 대기열의 번호를, 그 정보의 큐 selectOneMessageQueue 액세스 테마로 방출 난수 이상 걸리며, queueId 취재 속성 반환 브로커 앞에하세요 큐 사용
  6. 큐 번호에 직접 액세스 마지막 인덱스의 증가에 따라 나머지 큐를 취할 반환
  7. 직접 마지막 인덱스에서 대기열의 수는 수익을 얻기 위해 큐의 나머지 부분을 증가하지만, lastBrokerName 마지막 이름 brokerName은 동일하지
  8. 브로커 역할
  9. 사업을 처리하는 마스터 생산
  10. 슬레이브 동기 마스터는 정기적으로 지역 뉴스를 모두 동기 및 비동기 모드를 지원합니다

동일한 주제에 대한 메시지는 다중 마스터 폴링 메시지 브로커는 브로커가 동기 또는 비동기 데이터 동기화를 지원할 수있다 마스터, 마스터 - 슬레이브로 전송된다.
이러한 디자인의 장점은 서비스의 수준을 확장하고 확장이 강한로드 밸런싱 할 수 있다는 것입니다,하지만 당신은 비동기에서 메인 리프레시의 트레이드 오프 결정 및 구현에서 동시에 고 가용성 솔루션을 필요로

소비자 뉴스

우리는 동시, 그룹, 클러스터 모드에 따라 무질서 방법은 더 많은 소비자를 밀어 논의하기 위해 (점은 그룹에 추상화의 지점을 최적화 모드를 가리 키도록).
이 문서는 프로세스가 가지 않을 것이다 사항

  1. 소비자는 주제에 가입, 더 많은 소비자들이 동일한 주제에 가입 할 수 있습니다, 그룹 그룹은 동일하거나 상이 할 수 있습니다
  2. 단 하나의 소비자와 그룹은 푸시 메시지를 받게됩니다
  3. 그런 다음 각 그룹은 다른 그룹은 소비자가 푸시 메시지를 수신이 있어야합니다
  4. 브로드 캐스트 모드는 모든 소비자가 푸시 메시지는받을 수 있다는 것입니다
  5. 시작 소비자
  6. 등록 패킷 그룹의 소비자 정보
  7. RMQ 풀 모델 설계 되었기 때문에, 푸시 메시지 브로커를 수신,이 메시지는 풀 메시지를 밀어 첨자를 구현 유지하는 것이 필요하다
  8. 만약 로컬 파일에서 브로드 캐스트 모드, 인덱스 유지 보수
  9. 원격 브로커 클러스터 모델의 경우, 인덱스 유지 보수
  10. 메시지 큐 MessageQueue가 패키지 pullRequest에 따른 요청을 당기는 브로커 요청 메시지를 당겨
  11. 소비자의 선택 그룹에 따르면 메시지를 소비 당겨, 그래서 소비자의 동일한 그룹에 속하는 로컬 시작보다 지역 뉴스 소비 속도를 빠르게하지 않을 것이다,이 모델은 그룹이 경우 소비자와 일대일 관계지만 있음을 알 수있다 뉴스의 동시 생산, 메시지를 소비하는 소비자의 많은 표시하기 때문에 여러 마스터 브로커는 향후 3 개 마스터의 마지막 최종 것이다 브로커보다 약간 더 빠르게 (마스터에서 빠른 속도의 지역 소비를 증가 ) 장면? ? ?
// 消费者与group分组是一对一关系
ConcurrentMap<String/* group */, MQConsumerInner> consumerTable = new ConcurrentHashMap<String, MQConsumerInner>();


출처 : https://www.jianshu.com/p/824066d70da8

이름 서버

네임 서버는 그림의 역할, 브로커 검색 서비스를 아주 명확하고있다. 공식 설명입니다 : 이름 서버가 라우팅 정보 제공 업체입니다. 생산자 또는 소비자 클라이언트 브로커는 테마에 의해 해당 목록을 찾을 수 있습니다

Name server serves as the routing information provider. 
Producer/Consumer clients look up topics to find the corresponding broker list.

可以看出命名服务器的重要性,如果重要的角色,当然必须要求是高可用的,那么命名服务器可以部署为集群,那么集群中各个命名服务器节点的数据是否需要同步,如果需要如果同步?分布式一致性如何保证?
看过源码的同学应该知道,没看过的同学可以查看文章开头列出的源码学习博文。在启动每个broker时会向所有的命名服务器发送上报信息的,并且会启动线程30秒上报一次
所以命名服务器并不是越多越好,由于是30秒上报一次信息,命名服务器是默认10秒扫描一次broker的活跃状态,所以是有可能broker宕机后broker非活跃状态有10秒的无感知

事务消息

从官方的事务实现案例中可以看到LocalTransactionState事务的状态由3种(commit、rollback、未知),了解过分布式一致性算法的同学应该对2-PC,3-PC有所了解,看到此处状态便能猜到实现采用2-PC模式,在官网中也已经给出了答案,采用2阶段提交模式实现消息的分布式一致性。当然该算法的弊端有兴趣的同学可以参考《从Paxos到Zookeeper》一书,里面给出了非常详细介绍,此处不再赘述

public enum LocalTransactionState {
    COMMIT_MESSAGE,
    ROLLBACK_MESSAGE,
    UNKNOW,
}

使用方法可以参考官方案例,实现TransactionListener接口

executeLocalTransaction方法:发送prepare(准备)消息并根据事务id缓存事务的状态,发送消息的方式为同步模式
checkLocalTransaction方法:上个方法发送prepare(准备)消息后没有得到响应,broker将会发送校验消息检查事务状态,该方法将会被调用,读取本地事务状态

  1. 客户端发送消息至broker
  2. broker预写入消息,响应预写入状态
  3. 如果成功提交commit消息,否则提交rollback消息
  4. broker接收消息进行提交或rollback消息,并删除预处理消息
  5. broker启动默认1分钟扫描一次客户端本地事务状态,进行兜底处理事务消息

메시지 추적 - 메시지 추적

EnableMsgTrace는 메시지 전에 전송됩니다 DefaultMQProducer, 메시지를 보낼 템플릿의 사용을 추적하는 후크 방법을 만들 때 메시지 추적을 가능하게 지정하기 전에 호출 후 후크 방법 후, 추적 정보의 일부 출력

  1. 등록 후크 방법
public DefaultMQProducer(final String producerGroup, RPCHook rpcHook, boolean enableMsgTrace,final String customizedTraceTopic) {
    this.producerGroup = producerGroup;
    defaultMQProducerImpl = new DefaultMQProducerImpl(this, rpcHook);
    //if client open the message trace feature
    if (enableMsgTrace) {
        try {
            AsyncTraceDispatcher dispatcher = new AsyncTraceDispatcher(customizedTraceTopic, rpcHook);
            dispatcher.setHostProducer(this.getDefaultMQProducerImpl());
            traceDispatcher = dispatcher;
            this.getDefaultMQProducerImpl().registerSendMessageHook(
                new SendMessageTraceHookImpl(traceDispatcher));
        } catch (Throwable e) {
            log.error("system mqtrace hook init failed ,maybe can't send msg trace data");
        }
    }
}
  1. 후크 메소드를 호출
// 同步调用
private SendResult sendKernelImpl(final Message msg,
                                  final MessageQueue mq,
                                  final CommunicationMode communicationMode,
                                  final SendCallback sendCallback,
                                  final TopicPublishInfo topicPublishInfo,
                                  final long timeout) throws MQClientException, RemotingException, MQBrokerException, InterruptedException {
    ...
            if (this.hasSendMessageHook()) {
                context = new SendMessageContext();
                context.setProducer(this);
                context.setProducerGroup(this.defaultMQProducer.getProducerGroup());
                context.setCommunicationMode(communicationMode);
                context.setBornHost(this.defaultMQProducer.getClientIP());
                context.setBrokerAddr(brokerAddr);
                context.setMessage(msg);
                context.setMq(mq);
                String isTrans = msg.getProperty(MessageConst.PROPERTY_TRANSACTION_PREPARED);
                if (isTrans != null && isTrans.equals("true")) {
                    context.setMsgType(MessageType.Trans_Msg_Half);
                }

                if (msg.getProperty("__STARTDELIVERTIME") != null || msg.getProperty(MessageConst.PROPERTY_DELAY_TIME_LEVEL) != null) {
                    context.setMsgType(MessageType.Delay_Msg);
                }
                this.executeSendMessageHookBefore(context);
            }...
            SendResult sendResult = null;
            switch (communicationMode) {
				// 异步模式会在异步发送之后回调after钩子方法
                case ASYNC:
                    ...

            if (this.hasSendMessageHook()) {
                context.setSendResult(sendResult);
                this.executeSendMessageHookAfter(context);
            }

            return sendResult;
        } catch (RemotingException e) {
            if (this.hasSendMessageHook()) {
                context.setException(e);
                this.executeSendMessageHookAfter(context);
            }
            throw e;
        } catch (MQBrokerException e) {
            if (this.hasSendMessageHook()) {
                context.setException(e);
                this.executeSendMessageHookAfter(context);
            }
            throw e;
        } catch (InterruptedException e) {
            if (this.hasSendMessageHook()) {
                context.setException(e);
                this.executeSendMessageHookAfter(context);
            }
            throw e;
        } ...
}

// 异步调用
private void sendMessageAsync(
    final String addr,
    final String brokerName,
    final Message msg,
    final long timeoutMillis,
    final RemotingCommand request,
    final SendCallback sendCallback,
    final TopicPublishInfo topicPublishInfo,
    final MQClientInstance instance,
    final int retryTimesWhenSendFailed,
    final AtomicInteger times,
    final SendMessageContext context,
    final DefaultMQProducerImpl producer
) throws InterruptedException, RemotingException {
    this.remotingClient.invokeAsync(addr, request, timeoutMillis, new InvokeCallback() {
        @Override
        public void operationComplete(ResponseFuture responseFuture) {
            RemotingCommand response = responseFuture.getResponseCommand();
            if (null == sendCallback && response != null) {

                try {
                    SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response);
                    if (context != null && sendResult != null) {
                        context.setSendResult(sendResult);
                        context.getProducer().executeSendMessageHookAfter(context);
                    }
                } catch (Throwable e) {
                }

                producer.updateFaultItem(brokerName, System.currentTimeMillis() - responseFuture.getBeginTimestamp(), false);
                return;
            }

            if (response != null) {
                try {
                    SendResult sendResult = MQClientAPIImpl.this.processSendResponse(brokerName, msg, response);
                    assert sendResult != null;
                    if (context != null) {
                        context.setSendResult(sendResult);
                        context.getProducer().executeSendMessageHookAfter(context);
                    }
...
}

추천

출처blog.csdn.net/u010597819/article/details/89856951