この記事では、プロセスのプルメッセージコンシューマを追跡します。Javaクライアントの場合は、カフカの生産者と消費者は、同じネットワークNetworkClient IOクラスを再利用します。
KafkaConsumer#pollOnce入口は、主な手順を抽出します:
// 設定FetchRequest要求、コレクション内の要求未オブジェクト、送信待ち fetcher.sendFetches(); // 未送信の要求を削除し、#の送信呼び出しNetworkClient、NetworkClinet#ポーリング client.poll(pollTimeout、nowMs、新しい新PollCondition() { @Override 公共 ブールshouldBlock(){ // バックグラウンドスレッドを、完成したかもしれないことでのFETCHので、運用WEが条件条件のために必要な、この投票 // )(WEは、世論調査で不必要にブロックしないことEnsure®に 戻ります!fetcher.hasCompletedFetches(); } }); // ユーザにデータを戻す リターン fetcher.fetchedRecords()。
フェッチャ#のsendFetches
公共 同期 int型sendFetches(){ // 構成されたプルメッセージ要求。どのノードが、パーティションから、メッセージを引っ張るどの位置 の地図<ノード、FetchSessionHandler.FetchRequestData> fetchRequestMap = prepareFetchRequests(); のため(のMap.Entry <ノードFetchSessionHandler.FetchRequestData>のエントリ:fetchRequestMap.entrySet()){ 最終ノードfetchTarget = entry.getKey(); 最終 FetchSessionHandler.FetchRequestDataデータ= entry.getValue(); // ビルダによって構成される1 FetchRequestオブジェクト 最終 FetchRequest.Builderリクエスト= FetchRequest.Builder .forConsumer(この.maxWaitMs、この.minBytes、data.toSend()) .isolationLevel(IsolationLevelを) .setMaxBytes(この.maxBytes) の.metadata(data.metadata()) .toForget(data.toForget())。 もし(log.isDebugEnabled()){ log.debug( "{} {}} {ブローカに送信" 、IsolationLevelを、data.toString()、fetchTarget)。 } client.send(fetchTarget、リクエスト) // 4给RequestFutureCompletionHandler.future添加RequestFutureListener .addListener(新しい RequestFutureListener <ClientResponse> (){ @Override 公共 ボイドするonSuccess(ClientResponseのRESP){ 同期(フェッチャ。本){ FetchResponse応答 = (FetchResponse)resp.responseBody(); FetchSessionHandlerハンドラ = sessionHandler(fetchTarget.id())。 もし(ハンドラ== NULL ){ log.error( "応答をフェッチ無視ノード{}のFetchSessionHandlerを見つけることができません。" 、 fetchTarget.id())。 返す場合。 } (!handler.handleResponse(応答)){ 返します。 } 設定 <TopicPartition>パーティション= 新しい HashSetの<> (response.responseData()のkeySet()。)。 FetchResponseMetricAggregator metricAggregator = 新しいFetchResponseMetricAggregator(センサ、パーティション)。 用(のMap.Entry <TopicPartition、FetchResponse.PartitionData> エントリ:response.responseData()のentrySet()){ TopicPartitionパーティション = entry.getKey()。 長いですFetchOffset = data.sessionPartitions()(パーティション).fetchOffsetを取得します。 FetchResponse.PartitionDataなFetchData = entry.getValue()。 log.debug( "} {フェッチオフセットにおける{}パーティションの{}} {データをフェッチ返却" 、 IsolationLevelを、のFetchOffset、パーティションなFetchData)。 // 数据放入completedFetches、最终返回给用户把10. completedFetches.add(新しいCompletedFetch(パーティションのFetchOffset、なFetchData、metricAggregator、 sensors.fetchLatency.record(resp.requestLatencyMs())。 resp.requestHeader()apiVersion())); } } } @Override 公共 ボイドONFAILURE(のRuntimeException e)は{ 同期(フェッチャ本){ FetchSessionHandlerハンドラ = sessionHandler(fetchTarget.id())。 もし(!ハンドラ= ヌル){ handler.handleError(E); } } } })。 } を返す)(fetchRequestMap.sizeします。 }
ConsumerNetworkClientの#センド
公共 RequestFuture <ClientResponse>送信(<?>ノードノード、AbstractRequest.Builder requestBuilder){ 長い今= time.milliseconds()。 // 2.使用RequestFutureCompletionHandler作为回调函数 RequestFutureCompletionHandler completionHandler = 新しいRequestFutureCompletionHandler(); ClientRequest clientRequest = client.newClientRequest(node.idString()、requestBuilder、今、真、 completionHandler)。 // 3.请求放入未送信集合 unsent.put(ノード、clientRequest)。 // 私たちはキューに入れられたリクエストを送信できるように、それは世論調査でブロックしている場合には、クライアントをウェイクアップ client.wakeup(); 返すcompletionHandler.futureを。 }
ConsumerNetworkClientの#投票
// 送信要求が未送信ではない、とNOネットワークIO (今)trySend; // 実際の書き込みと読み出しデータネットワーク // 6.送信要求 @ 7は、応答受信 // 8 RequestFutureCompletionHandlerトリガーコールバック クライアント。世論調査(0 、今); // 9.コールバックRequestFutureListenerの中でトリガー )(firePendingCompletedRequests。
NetworkClient#handleCompletedReceives
プライベート 無効 handleCompletedReceives(一覧<ClientResponse>応答、長い今){ のために(NetworkReceiveが受け取る:この.selector.completedReceives()){ String型のソース = receive.source(); InFlightRequest REQ = inFlightRequests.completeNext(ソース)。 構造体responseStruct = parseStructMaybeUpdateThrottleTimeMetrics(receive.payload()、req.header、 throttleTimeSensor、今)。 場合(log.isTraceEnabled()){ log.trace( "完成は相関IDと{}の{}のノードから受信{}、受信{}" 、req.destination、 req.header.apiKey()、req.header.correlationId()、responseStruct)。 } AbstractResponse本体 = AbstractResponse.parseResponse(req.header.apiKey()、responseStruct)。 もし(req.isInternalRequest &&体のinstanceof MetadataResponse) metadataUpdater.handleCompletedMetadataResponse(req.header、今、(MetadataResponse)体); それ以外の 場合(req.isInternalRequest &&体のinstanceof ApiVersionsResponse) handleApiVersionsResponse(応答、REQ、今、(ApiVersionsResponse)体); 他に // 此处给応答添加元素 //(偽、ヌル、レスポンスにしたいんヘッダ、コールバック、createdTimeMs、timeMs、)新しい新しいClientResponseリターン; // 直接応答コールバック要求に割り当てられ // メーカー送信コールバックメッセージは、ユーザーがパラメータを経由して渡される // 消費コールバック・メッセージを引っ張ることにより、ConsumerNetworkClient番号の送信は、RequestFutureCompletionHandlerで指定されている ;(今req.completed(本体))responses.add } }
NetworkClient#completeResponses
プライベート 無効 completeResponses(一覧<ClientResponse> 回答){ のために(ClientResponseレスポンス:レスポンス){ しようと{ // callback.onComplete(この); response.onComplete(); } キャッチ(例外e){ log.error( "要求の完了に不明なエラー:" 、E)。 } } }
RequestFutureCompletionHandler#onCompleteの
公共 ボイドonCompleteの(ClientResponse応答){ この .response = 応答。 pendingCompletion.add(この); }
ConsumerNetworkClient#firePendingCompletedRequests
プライベート 無効firePendingCompletedRequests(){ boolean型 completedRequestsFired = 偽; 用(;;){ RequestFutureCompletionHandler completionHandler = pendingCompletion.poll()。 もし(completionHandler == nullの) ブレーク。 completionHandler.fireCompletion(); completedRequestsFired = 真; } // それは、この将来の完成のために投票にブロックしている場合には、クライアントをウェイクアップ 場合(completedRequestsFired) client.wakeup(); }
ConsumerNetworkClient.RequestFutureCompletionHandler#fireCompletion
公共 ボイドfireCompletion(){ 場合(E =!ヌル){ future.raise(E); } そう であれば(response.wasDisconnected()){ RequestHeader requestHeader = response.requestHeader()。 INT相関= requestHeader.correlationId()。 log.debug( "キャンセル{}要求{}、相関IDを{}によるノードに{}切断される" 、 requestHeader.apiKey()、requestHeader、相関、response.destination())。 future.raise(DisconnectException.INSTANCE)。 } それ以外の 場合(response.versionMismatch()!= NULL ){ future.raise(response.versionMismatch())。 } 他{ future.complete(応答)。 } }
RequestFuture#の完全な
公共 のボイドの完全な(T値){ しようと{ 場合(値のinstanceof のRuntimeException) スロー 新しい(「完了するための引数がのRuntimeExceptionのインスタンスにすることはできません」、IllegalArgumentExceptionを)。 場合(!result.compareAndSet(INCOMPLETE_SENTINEL、値)) スロー 新しい IllegalStateExceptionを(「すでに完了しているリクエストの将来を完了するために無効な試みを」); fireSuccess(); } 最後に{ completedLatch.countDown()。 } } プライベート のボイドfireSuccess(){ T値 = 値(); 一方、(真){ RequestFutureListener <T>リスナー= listeners.poll()。 もし(リスナー== nullの) ブレーク。 // 终于调到RequestFutureListener listener.onSuccess(値)。 } }
あなたは、ハートビートスレッドを考慮していない場合は、消費者最初のポーリング要求が送信された場合にはデータ、ではない、応答が読み込まれ、同時に書き込むためにネットワークイベントを処理するために、第二の世論調査にあるように、戻ってきていません。
終えた後、個人的に私は、コールチェーンが非常に長い感じ。事を感じ、全体の一つのスレッドだけが、枝を取るたびに、それは彼らがシングルスレッド、高速のために待っていないということですインスピレーションを与えて、同じではありません。