序文
最新の4.8.0DLedgerモードでは、メッセージを送信するときに、ノードからのackがパイプラインを通過するため、メッセージ送信のスループットが大幅に向上します。
以前のバージョン(4.7.1などのバージョン4.8.0より前)では、DLedgerモードに関して、ソースコードを確認したところ、以下の状況が見つかりました。その一部は4.8.0では最適化されていません。
詳細な説明
マスターとスレーブ間のネットワークは、tpsの送信に影響を与えます
メッセージを送信するときは、スレーブノードのクォーラムが戻るのを待つackを同期的にブロックする必要があるため、メッセージ送信のパフォーマンスに大きな影響を与えます。
/**
* Handle the append requests:
* 1.append the entry to local store
* 2.submit the future to entry pusher and wait the quorum ack
* 3.if the pending requests are full, then reject it immediately
*
* @param request
* @return
* @throws IOException
*/
@Override
public CompletableFuture<AppendEntryResponse> handleAppend(AppendEntryRequest request) throws IOException {
// 前面删除了很多代码
DLedgerEntry dLedgerEntry = new DLedgerEntry();
dLedgerEntry.setBody(request.getBody());
DLedgerEntry resEntry = dLedgerStore.appendAsLeader(dLedgerEntry);
return dLedgerEntryPusher.waitAck(resEntry, false);
//后面删除了一些代码
}
4.8.0では、ackアクションはパイプラインを介して非同期であり、メッセージを送信しているワーカースレッドをすばやく解放して、後続のメッセージ送信要求を処理できます。
実際、このackアクションの実際のシナリオでは、ネットワークの問題がtps送信のボトルネックになる可能性があります。たとえば、私が使用しているクラウド仮想マシン、rocketmqクラスターが展開されているノードは同じネットワークセグメントになく、実際のホストベースは遠く離れている可能性があります。pingを実行すると、0.3〜0.4ミリ秒の時間が必要であることがわかりました。つまり、1つのリクエストアクションには少なくとも0.3msかかり、0.3msは単なるping時間です。実際には、アクションリクエストrtはもっと長くなる可能性があります。1msで平均3つのtcpリクエストを処理できる場合でも、最大数は1のは3000です。1つのackには少なくとも2つの通信(要求+応答)が必要です。つまり、送信tps、単一ノード送信tpsは3000/2を超えることはできず、tpsは1500のみです。私の環境は圧力テスト済みです。送信tpsは1000未満です。 。
もう一つの問題は、スレーブノードに問題がある場合、それはマスターの送信TPSに大きな影響を与えるということです。私は、スレーブノードのいずれかが押されていたことをシミュレートし、TPSが低かったです。
4.8.0を使用した最適化では、DLedgerの送信tpsは非DLedgerの約半分です。たとえば、通常のモデルは6Wで、DLedgerは3Wに達する可能性があり、これは私の環境にとって恐ろしい改善です。
古いバージョンを解決する方法
4.7.1で、DLedgerの送信tpsが非常に低い場合、解決策は、送信側のスレッド数のデフォルト構成を変更し、スピンロックを再入力ロックに変更して、IOブロッキングによって引き起こされるCPU使用率を解決することです。スレッドを追加することにより、送信者のスレッド数が適切に設定されている限り、tpsの送信はかなりの量になります。これら2つの構成については、前に書かれたこの記事を参照してください。RocketMQブローカーがメッセージコミットを処理するときに、ロックで使用するかどうかスピンロックまたはリエントリーロック。4.8.0は、デフォルトの2つの構成を使用できます。基本的に、スレッド数の増加を考慮する必要はありません。
4.8.0より前のバージョンでは、スレッド数を増やすことで送信tpsが低いという問題を解決できますが、ackのために、スレーブノードとのネットワークフラッシュによって、putメッセージがロックを長時間保持する可能性もあります。共通システムがビジー状態で、電流制限をトリガーします。最善の提案は、バージョン4.8.0にアップグレードすることです。
マスターとスレーブの非同期レプリケーションに違いはありません
4.8.0より前のバージョンのDLedgerモデルでは、マスタースレーブ同期二重書き込みと非同期メッセージレプリケーションの間に違いはありません。これらはすべて同期ブロッキングメソッドです。DLedgerCommitLogクラスでは、putMessageメソッドが呼び出され、非同期操作はありません。
@Override
public CompletableFuture<PutMessageResult> asyncPutMessage(MessageExtBrokerInner msg) {
return CompletableFuture.completedFuture(this.putMessage(msg));
}
@Override
public CompletableFuture<PutMessageResult> asyncPutMessages(MessageExtBatch messageExtBatch) {
return CompletableFuture.completedFuture(putMessages(messageExtBatch));
}
したがって、バージョン4.8.0にアップグレードすることをお勧めします。
古いバージョンはオフヒープメモリをサポートしていません
DLedgerモデルのもう1つの問題は、メッセージを送信するときにオフヒープメモリの使用をサポートしていないことです。この問題は4.8.0では修正されていません。非DLedgertransientStorePoolEnable
は、構成パラメータを使用してオフヒープメモリを有効にすることを選択できます。G.メッセージ処理の送信。メッセージを送信するときは、最初にオフヒープメモリに書き込み、ページキャッシュに非同期で書き込み、次にディスクなどをフラッシュすることができます。ページキャッシュから読み取り、読み取りと書き込みの分離を実現します。DLedgerは現在、mmapを介してページキャッシュに直接書き込みます。ソースコードを見てこの問題を見つけたとき、それは非常に奇妙であり、この構成が実際にサポートされていないことを作成者に確認しました。ねえ、私は上司に本番環境でこの構成をオンにして3Gメモリをセットアップするように依頼しました。その結果は無駄でした。
つまり、DLedgerを使用する場合は、4.8.0にアップグレードすることを強くお勧めします。