Simple Consumer Scala API
官方example:
https://cwiki.apache.org/confluence/display/KAFKA/0.8.0+SimpleConsumer+Example
该模式下
- 可以指定offset消费,同时也需要对offset进行管理
- 在建立消费连接之前要确认所消费分区的leader broker
- 要手动处理leader change
查询Topic元数据,找到leader
查询topic、分区的leader、replicas、isr等信息同样要建立SimpleConsumer连接,发送TopicMetadataRequest请求,获取响应TopicMetadataResponse中的List
offset查询
offset查询同样通过SimpleConsumer连接,构造kafka.javaapi.OffsetRequest请求,获取OffsetResponse
- kafka.api.OffsetRequest.EarliestTime() 分区最小偏置
- kafka.api.OffsetRequest.LatestTime() 分区最大偏置
对应OffsetRequest.scala两个常量val LatestTime = -1L
与val EarliestTime = -2L
TopicAndPartition topicAndPartition = new TopicAndPartition(topic, partition);
Map<TopicAndPartition, PartitionOffsetRequestInfo> requestInfo = new HashMap<TopicAndPartition, PartitionOffsetRequestInfo>();
//请求信息K:分区 V:分区offset请求,whichTime可以是kafka.api.OffsetRequest.EarliestTime()、kafka.api.OffsetRequest.LatestTime()或unix时间戳
requestInfo.put(topicAndPartition, new PartitionOffsetRequestInfo(whichTime, 1));
//构造请求
kafka.javaapi.OffsetRequest request = new kafka.javaapi.OffsetRequest(requestInfo, kafka.api.OffsetRequest.CurrentVersion(), clientName);
OffsetResponse response = consumer.getOffsetsBefore(request);
return offsets[0];
PartitionOffsetRequestInfo的第二个参数是offset返回的个数,第一个就是请求的offset,其他值与日志segment配置大小有关,应该是会包含个segment段的关键offset,可以参考这个bolg:http://cfchou.github.io/blog/2015/04/23/a-closer-look-at-kafka-offsetrequest/
消费数据
通过Topic元数据查询找到leader后,通过该leader查询offset,再构造FetchRequest,获取FetchResponse提取数据
//构造请求,fetchSize为一次fetch的byte大小,这个值如若小于一个message大小,会返回空消息
FetchRequest req = new FetchRequestBuilder()
.clientId(clientName)
.addFetch(topic, partition, offset, fetchSize)
.build();
//获取响应
FetchResponse fetchResponse = simpleConsumer.fetch(req);
if(fetchResponse.hasError())
{
System.out.println("fetchResponse has error, error code: " + fetchResponse.errorCode(topic, partition));
//可能是offset错误,或者kafka宕机,发生了leader change,这里需要重新获取leader
}
//获取指定partition消息,因为FetchRequest里可以add多个addFetch
for (MessageAndOffset messageAndOffset : fetchResponse.messageSet(topic, partition))
{
//每条消息的payload
ByteBuffer payload = messageAndOffset.message().payload();
//下一个offset
nextOffset = messageAndOffset.nextOffset();
}
leader change
kafka宕机实际上是通过zk进行检测的,当zk上broker临时节点不在时应会告知kafka集群重新进行leader选举,应用中需要进行一段时间的等待,可参考例子中的代码。