DefaultMQProducerImplファイルがsendDefaultImplを持って、ルーティング情報を取得する方法を、行くためにここからメッセージを送信するときは、ここでは拡大しませんそれについて話します。
この方法では内部、同期モードは、メッセージは、再試行の数に応じて送信されていない移動し続ける selectOneMessageQueue再試行ロジック。
用(;回<timesTotal;回++){ 文字列lastBrokerName =ヌル== MQ?ヌル:mq.getBrokerName(); メッセージキューmqSelected = this.selectOneMessageQueue(topicPublishInfo、lastBrokerName)。 (もし!mqSelected = NULL){ MQ = mqSelected。 brokersSent [回] = mq.getBrokerName()。 試す{ beginTimestampPrev =にSystem.currentTimeMillis(); 長いcostTime = beginTimestampPrev - beginTimestampFirst。 IF(タイムアウト<costTime){ callTimeout = TRUE。 ブレーク; } sendResult = this.sendKernelImpl(MSG、MQ、communicationMode、sendCallback、topicPublishInfo、タイムアウト- costTime)。 endTimestamp =のSystem.currentTimeMillis(); this.updateFaultItem(mq.getBrokerName()、endTimestamp - beginTimestampPrev、偽); スイッチ(communicationMode){ ケースASYNC: リターンヌル。 ケースONEWAY: リターンはnull; ケースSYNC: もし(sendResult.getSendStatus()= SendStatus.SEND_OK!){ IF(this.defaultMQProducer.isRetryAnotherBrokerWhenNotStoreOK()){ 続けます。 } } 戻りsendResult。 デフォルト: 休憩; } }キャッチ(RemotingException電子){ endTimestamp =にSystem.currentTimeMillis(); this.updateFaultItem(mq.getBrokerName()、endTimestamp - beginTimestampPrev、真の); log.warn(String.Formatの( "sendKernelImpl例外、一度再送InvokeID:%sは、RT:%のSMS、ブローカー:%sの"、invokeID、endTimestamp - beginTimestampPrev、MQ)、E); log.warn(msg.toString())。 例外= E; 持続する;
selectOneMessageQueueは、ここで実際にselectOneMessageQueue内部MQFaultStrategy内部オブジェクトと呼ばれます。
私の個人的な見解、この評価関数が特に重要であるので、MQのデフォルトは、このロジックを使用するのではなく、これは私たちの研究を妨げないではないということ。ここselectOneMessageQueueのMQFaultStrategyです
パブリックメッセージキューselectOneMessageQueue(最終TopicPublishInfo TPINFO、最終列lastBrokerName){ IF(this.sendLatencyFaultEnable)は{ {試みる 。INTインデックス= tpInfo.getSendWhichQueue()getAndIncrement(); (I 0 = int型。私は++; iがtpInfo.getMessageQueueList()サイズ()<)のために{ int型POS = Math.abs(インデックス++)%tpInfo.getMessageQueueList()サイズ()。 (posが<0)であれば 、POS = 0。 メッセージキューMQ = tpInfo.getMessageQueueList()(POS)を取得します。 戻りMQ。 IF(latencyFaultTolerance.isAvailable(mq.getBrokerName())){ もし(ヌル== lastBrokerName || mq.getBrokerName()に等しい(lastBrokerName)) } } 、最終列notBestBroker = latencyFaultTolerance.pickOneAtLeast()。 INT writeQueueNums = tpInfo.getQueueIdByBroker(notBestBroker)。 IF(writeQueueNums> 0){ 最終メッセージキューMQ = tpInfo.selectOneMessageQueue()。 (もし!notBestBroker = NULL){ mq.setBrokerName(notBestBroker)。 mq.setQueueId(tpInfo.getSendWhichQueue()getAndIncrement()%のwriteQueueNums)。 } MQを返します。 }他{ latencyFaultTolerance.remove(notBestBroker)。 } }キャッチ(例外e){ log.error(E「メッセージキューを選択する際にエラーが発生しました」)。 } )(tpInfo.selectOneMessageQueueを返します。 } tpInfo.selectOneMessageQueue(lastBrokerName)を返します。 }
sendLatencyFaultEnableがfalseの場合、デフォルトはfalseです。その後、メッセージ内の(それは各ブローカーユニットのメッセージキューは、各ブローカ構成によって指定されたキューは、キューの長さを有することを意味する)全て+1各メッセージキューキュー番号を削除し、最後の故障雑草アウトbrokerNameにしています。
そこだけ2ブローカーあなたはほとんどの問題を解決することができれば問題はありますが、ブローカーの多くは、その後、我々は時間次元の希望MQを持っている場合、ブローカーは、ときに利用可能に推定することができます。特にrocketmqため、場合ブローカが変化するので、生産者に通知することが初めてではなく、回転中に得られた非同期。また、非同期ポーリングは、ブローカーとネームサーバ間の生活探ります。
オープンsendLatencyFaultEnable言葉は、つまり、メッセージを送信する前に、このブローカーが利用可能である推定し、それがある場合は、直接利用可能戻りました。上記のコード:
もし(ヌル== lastBrokerName || mq.getBrokerName()。等号(lastBrokerName))
私はそれが間違っている必要があると感じ、それがmq.getBrokerName()。NotEqualsでなければなりません(lastBrokerName)
ブローカーが利用可能であるかどうかを判断するlatencyFaultTolerance.isAvailable呼び出しがあり、これは約どのように来ますか?
実際には、sendDefaultImpl時間に関係なく、メッセージが正常か送られているかどうかの、更新するために、ここになり、内部プロデューサーupdateFaultItemのMQFaultStrategy呼ばれるlatencyFaultTolerance
ここでMQFaultStrategyと重要な方法のいくつかの重要なメンバーは以下のとおりです。
プライベート長い[] latencyMax = {50L、100L、550L、1000L、2000L、3000L、15000L}。 プライベート長い[] notAvailableDuration = {0L、0L、30000L、60000L、120000L、180000L、600000L}。 公共ボイドupdateFaultItem(最終列brokerNameに、最終的な長いcurrentLatency、ブール分離){ IF(this.sendLatencyFaultEnable){ 長時間= computeNotAvailableDuration(分離30000:currentLatency)。 this.latencyFaultTolerance.updateFaultItem(brokerNameに、currentLatency、持続時間)。 } } プライベートロングcomputeNotAvailableDuration(最終長currentLatency){ (I = latencyMax.length値int - 1; I> = 0; i--)のために{ (currentLatency> = latencyMax [I])場合 [I] this.notAvailableDurationを返します。 } 0を返します。 }
メッセージsendDefaultImplを送信する時には、のみ送信するには、この分離は、一般的に、偽でそうcomputeNotAvailableDuration期間を介して取得するメッセージを送信するには、この時間の時間の消費も大きく、より大きなlatencyMaxシリアル番号を取得するには、0である、notAvailableDurationから取りますより長い期間に。
障害がある場合は、アイソレーションがtrueの場合、このブローカーを考慮利用できない時間が180000Lで、3分です
updateFaultItemのLatencyFaultToleranceImplに進みます。
@Override 公共ボイドupdateFaultItem(最終文字列名、最終長いcurrentLatency、最終長いnotAvailableDuration){ FaultItem古い= this.faultItemTable.get(名); IF(ヌル==古い){ 最終FaultItem faultItem =新しいFaultItem(名前); faultItem.setCurrentLatency(currentLatency)。 faultItem.setStartTimestamp(のSystem.currentTimeMillis()+ notAvailableDuration)。 古い= this.faultItemTable.putIfAbsent(名前、faultItem)。 (もし!古い= NULL){ old.setCurrentLatency(currentLatency)。 old.setStartTimestamp(のSystem.currentTimeMillis()+ notAvailableDuration)。 } }他{ old.setCurrentLatency(currentLatency)。 old.setStartTimestamp(のSystem.currentTimeMillis()+ notAvailableDuration)。 } }
ここでは名前が示すように、faultitemを構築するcurrentLatencyに時間がかかるの開始から終了までのメッセージを送信するために最後で、名前はブローカー名で、問題の科目があり、間違っている、次のタイムスタンプ推定starttimestampが可能です。
様々な重要な方法で探し続けFaultItem:
@Override 公共INTのcompareTo(最終FaultItem他){ IF(this.isAvailable()= other.isAvailable()!){ IF(this.isAvailable()) リターン-1。 IF(other.isAvailable()) リターン1。 } IF(this.currentLatency <other.currentLatency) リターン-1。 他の場合(this.currentLatency> other.currentLatency){ 1を返します。 } IF(this.startTimestamp <other.startTimestamp) リターン-1。 それ以外の場合(this.startTimestamp> other.startTimestamp){ 1を返します。 } 0を返します。 } パブリックブールisAvailable(){ リターン(のSystem.currentTimeMillis() - startTimestamp)> = 0。 }
それが利用可能なブローカを発見した場合バック上記のコードと組み合わさselectOneMessageQueue MQFaultStrategy戦略には、直接返します。あなたは見つけることができない場合と同様のリターンは見つけるpickOneAtLeast呼び出します
パブリック文字列pickOneAtLeast(){ 最終列挙<FaultItem>要素=のthis.faultItemTable.elements()。 一覧<FaultItem> tmpList =新しいLinkedListは<FaultItem>(); (elements.hasMoreElements()){ながら 最終FaultItem faultItem = elements.nextElement()。 tmpList.add(faultItem)。 } {IF(tmpList.isEmpty()!) Collections.shuffle(tmpList)。 Collections.sort(tmpList)。 最終INT半分= tmpList.size()/ 2。 (半分<= 0){もし tmpList.get(0).getNameを返します()。 }他{ 最終INT I = this.whichItemWorst.getAndIncrement()%の半分; tmpList.get(I).getName()を返します。 } } はnullを返します。 }
品質に従ってソートするランダムに選択された再のbrokerNameにの前半部から良い、次いでソート後、faultiitemサポートしてい