kafka消费者如何读同一生产者消息_kafka 消费者拉取消息

本文详细跟踪了Kafka消费者拉取消息的流程,从KafkaConsumer#pollOnce开始,涉及FetchRequest构造、NetworkClient的send和poll操作,直至数据返回给用户。整个过程在一个线程中完成,通过不断的请求和响应处理,确保了消息的获取。
摘要由CSDN通过智能技术生成

本文只跟踪消费者拉取消息的流程。对于 java 客户端, kafka 的生产者和消费者复用同一个网络 io 类 NetworkClient。

入口在 KafkaConsumer#pollOnce 中,抽出主要步骤:

//构造 FetchRequest 请求,将请求对象放入 unsent 集合,等待发送

fetcher.sendFetches();//取出 unsent 中的请求,调用 NetworkClient#send,NetworkClinet#poll

client.poll(pollTimeout, nowMs, newPollCondition() {

@Overridepublic booleanshouldBlock() {//since a fetch might be completed by the background thread, we need this poll condition//to ensure that we do not block unnecessarily in poll()

return !fetcher.hasCompletedFetches();

}

});//返回数据给用户

return fetcher.fetchedRecords();

Fetcher#sendFetches

public synchronized intsendFetches() {//构造拉取消息请求。从哪个节点,哪个分区,什么位置拉取消息

Map fetchRequestMap =prepareFetchRequests();for (Map.Entryentry : fetchRequestMap.entrySet()) {final Node fetchTarget =entry.getKey();final FetchSessionHandler.FetchRequestData data =entry.getValue();//1. 借助 Builder 构造 FetchRequest 对象

final FetchRequest.Builder request =FetchRequest.Builder

.forConsumer(this.maxWaitMs, this.minBytes, data.toSend())

.isolationLevel(isolationLevel)

.setMaxBytes(this.maxBytes)

.metadata(data.metadata())

.toForget(data.toForget());if(log.isDebugEnabled()) {

log.debug("Sending {} {} to broker {}", isolationLevel, data.toString(), fetchTarget);

}

client.send(fetchTarget, request)//4. 给 RequestFutureCompletionHandler.future 添加 RequestFutureListener

.addListener(new RequestFutureListener() {

@Overridepublic voidonSuccess(ClientResponse resp) {synchronized (Fetcher.this) {

FetchResponse response=(FetchResponse) resp.responseBody();

FetchSessionHandler handler=sessionHandler(fetchTarget.id());if (handler == null) {

log.error("Unable to find FetchSessionHandler for node {}. Ignoring fetch response.",

fetchTarget.id());return;

}if (!handler.handleResponse(response)) {return;

}

Set partitions = new HashSet<>(response.responseData().keySet());

FetchResponseMetricAggregator metricAggregator= newFetchResponseMetricAggregator(sensors, partitions);for (Map.Entryentry : response.responseData().entrySet()) {

TopicPartition partition=entry.getKey();long fetchOffset =data.sessionPartitions().get(partition).fetchOffset;

FetchResponse.PartitionData fetchData=entry.getValue();

log.debug("Fetch {} at offset {} for partition {} returned fetch data {}",

isolationLevel, fetchOffset, partition, fetchData);//10. 把数据放入 completedFetches,最终返回给用户

completedFetches.add(newCompletedFetch(partition, fetchOffset, fetchData, metricAggregator,

resp.requestHeader().apiVersion()));

}

sensors.fetchLatency.record(resp.requestLatencyMs());

}

}

@Overridepublic voidonFailure(RuntimeException e) {synchronized (Fetcher.this) {

FetchSessionHandler handler=sessionHandler(fetchTarget.id());if (handler != null) {

handler.handleError(e);

}

}

}

});

}returnfetchRequestMap.size();

}

ConsumerNetworkClient#send

public RequestFuture send(Node node, AbstractRequest.Builder>requestBuilder) {long now =time.milliseconds();//2. 使用 RequestFutureCompletionHandler 作为回调函数

RequestFutureCompletionHandler completionHandler = newRequestFutureCompletionHandler();

ClientRequest clientRequest= client.newClientRequest(node.idString(), requestBuilder, now, true,

completionHandler);//3. 请求放入 unsent 集合

unsent.put(node, clientRequest);//wakeup the client in case it is blocking in poll so that we can send the queued request

client.wakeup();returncompletionHandler.future;

}

ConsumerNetworkClient#poll

//5. 发送 unsent 中的请求,并没有产生网络 io

trySend(now);//真实的网络数据写和读//6. 发送请求//7. 接收响应//8. 触发 RequestFutureCompletionHandler 回调

client.poll(0, now);//9. 触发 RequestFutureListener 中的回调

firePendingCompletedRequests();

NetworkClient#handleCompletedReceives

private void handleCompletedReceives(List responses, longnow) {for (NetworkReceive receive : this.selector.completedReceives()) {

String source=receive.source();

InFlightRequest req=inFlightRequests.completeNext(source);

Struct responseStruct=parseStructMaybeUpdateThrottleTimeMetrics(receive.payload(), req.header,

throttleTimeSensor, now);if(log.isTraceEnabled()) {

log.trace("Completed receive from node {} for {} with correlation id {}, received {}", req.destination,

req.header.apiKey(), req.header.correlationId(), responseStruct);

}

AbstractResponse body=AbstractResponse.parseResponse(req.header.apiKey(), responseStruct);if (req.isInternalRequest && body instanceofMetadataResponse)

metadataUpdater.handleCompletedMetadataResponse(req.header, now, (MetadataResponse) body);else if (req.isInternalRequest && body instanceofApiVersionsResponse)

handleApiVersionsResponse(responses, req, now, (ApiVersionsResponse) body);else

//此处给 responses 添加元素//return new ClientResponse(header, callback, destination, createdTimeMs, timeMs, false, null, response);//直接把请求的 callback 赋值给响应//生产者发送消息的 callback,是用户通过参数传入的//消费者拉取消息的 callback,是在 ConsumerNetworkClient#send 指定的,是 RequestFutureCompletionHandler

responses.add(req.completed(body, now));

}

}

NetworkClient#completeResponses

private void completeResponses(Listresponses) {for(ClientResponse response : responses) {try{//callback.onComplete(this);

response.onComplete();

}catch(Exception e) {

log.error("Uncaught error in request completion:", e);

}

}

}

RequestFutureCompletionHandler#onComplete

public voidonComplete(ClientResponse response) {this.response =response;

pendingCompletion.add(this);

}

ConsumerNetworkClient#firePendingCompletedRequests

private voidfirePendingCompletedRequests() {boolean completedRequestsFired = false;for(;;) {

RequestFutureCompletionHandler completionHandler=pendingCompletion.poll();if (completionHandler == null)break;

completionHandler.fireCompletion();

completedRequestsFired= true;

}//wakeup the client in case it is blocking in poll for this future‘s completion

if(completedRequestsFired)

client.wakeup();

}

ConsumerNetworkClient.RequestFutureCompletionHandler#fireCompletion

public voidfireCompletion() {if (e != null) {

future.raise(e);

}else if(response.wasDisconnected()) {

RequestHeader requestHeader=response.requestHeader();int correlation =requestHeader.correlationId();

log.debug("Cancelled {} request {} with correlation id {} due to node {} being disconnected",

requestHeader.apiKey(), requestHeader, correlation, response.destination());

future.raise(DisconnectException.INSTANCE);

}else if (response.versionMismatch() != null) {

future.raise(response.versionMismatch());

}else{

future.complete(response);

}

}

RequestFuture#complete

public voidcomplete(T value) {try{if (value instanceofRuntimeException)throw new IllegalArgumentException("The argument to complete can not be an instance of RuntimeException");if (!result.compareAndSet(INCOMPLETE_SENTINEL, value))throw new IllegalStateException("Invalid attempt to complete a request future which is already complete");

fireSuccess();

}finally{

completedLatch.countDown();

}

}private voidfireSuccess() {

T value=value();while (true) {

RequestFutureListener listener =listeners.poll();if (listener == null)break;//终于调到 RequestFutureListener

listener.onSuccess(value);

}

}

如果不考虑心跳线程,consumer 第一次 poll 是不会有数据的,此时请求才发出去,响应还没回来,必须在第二次 poll 时,才能同时处理网络读写事件。

跟完之后,个人觉得调用链还是挺长的。一点感觉,全程只有一个线程,但是每次走的分支都不一样,给人的启发就是,单线程只要不等待,速度也很快。

原文:https://www.cnblogs.com/allenwas3/p/11617514.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值