Consumer的client端
示例代码
Properties props = new Properties();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
props.put(ConsumerConfig.GROUP_ID_CONFIG, "DemoConsumer");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
props.put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "30000");
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.ByteArrayDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.ByteArrayDeserializer");
consumer = new KafkaConsumer<>(props);
this.topic = topic;
consumer.subscribe(Collections.singletonList(this.topic));
//下面的传入一个listener这个部分的注释如果需要对partition在当前的consumer中分配或者取消分配时做一定的操作时(比如取消分配时提交offset),可以实现这个接口。
//subscribe(List<String> topics, ConsumerRebalanceListener listener)
while(true) {
ConsumerRecords<Integer, String> records = consumer.poll(1000);
for (ConsumerRecord<Integer, String> record : records) {
System.out.println("Received message: (" + record.key() + ", " + record.value()
+ ") at offset " + record.offset());
}
consumer.commitSync()
}
生成KafkaConsumer实例
@SuppressWarnings("unchecked")
private KafkaConsumer(ConsumerConfig config,
Deserializer<K> keyDeserializer,
Deserializer<V> valueDeserializer) {
try {
log.debug("Starting the Kafka consumer");
根据配置信息,得到如下三个配置的配置值,并检查配置的合法:
1,读取request.timeout.ms配置项的值,默认值为40秒。用于配置请求的超时时间。
2,读取session.timeout.ms配置项的值,默认值为30秒,用于配置当前的consumer的session的超时时间,也就是client端多长时间不给server发送心跳就表示这个client端超时。
3,读取fetch.max.wait.ms配置项的值,默认值为500ms。用于配置从server中读取数据最长的等待时间。
this.requestTimeoutMs = config.getInt(
ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG);
int sessionTimeOutMs = config.getInt(
ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG);
int fetchMaxWaitMs = config.getInt(
ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG);
如果请求超时时间不是一个大于session的超时时间的值或者请求超时时间不是一个大于fetch的最大等待时间的值时,表示requestTimeoutMs的配置不合法,直接throw exception.
if (this.requestTimeoutMs <= sessionTimeOutMs ||
this.requestTimeoutMs <= fetchMaxWaitMs)
throw new ConfigException(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG
+ " should be greater than " + ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG
+ " and " + ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG);
this.time = new SystemTime();
MetricConfig metricConfig = new MetricConfig().samples(
config.getInt(ConsumerConfig.METRICS_NUM_SAMPLES_CONFIG))
.timeWindow(config.getLong(
ConsumerConfig.METRICS_SAMPLE_WINDOW_MS_CONFIG),
TimeUnit.MILLISECONDS);
这里得到对应的consumer的client端id的client.id配置,如果这个值没有配置时,默认随机生成一个。
clientId = config.getString(ConsumerConfig.CLIENT_ID_CONFIG);
if (clientId.length() <= 0)
clientId = "consumer-" + CONSUMER_CLIENT_ID_SEQUENCE.getAndIncrement();
List<MetricsReporter> reporters = config.getConfiguredInstances(
ConsumerConfig.METRIC_REPORTER_CLASSES_CONFIG,
MetricsReporter.class);
reporters.add(new JmxReporter(JMX_PREFIX));
this.metrics = new Metrics(metricConfig, reporters, time);
读取retry.backoff.ms配置的值,默认值为100ms,用于配置重试的间隔周期。
this.retryBackoffMs = config.getLong(
ConsumerConfig.RETRY_BACKOFF_MS_CONFIG);
根据重试的间隔周期加上metadata.max.age.ms配置项的值生成Metadata实例,
配置metadata.max.age.ms项默认值为5分钟,用于设置metadata定期重新读取的生命周期。
this.metadata = new Metadata(retryBackoffMs,
config.getLong(ConsumerConfig.METADATA_MAX_AGE_CONFIG));
读取bootstrap.servers配置的要读取的kafka brokers的配置列表,并根据broker的连接信息,生成Cluster实例,并把Cluster实例更新到metadata的实例。
List<InetSocketAddress> addresses = ClientUtils.parseAndValidateAddresses(
config.getList(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG));
this.metadata.update(Cluster.bootstrap(addresses), 0);
String metricGrpPrefix = "consumer";
Map<String, String> metricsTags = new LinkedHashMap<String, String>();
metricsTags.put("client-id", clientId);
生成NetworkClient的实例,生成实例需要如下几个配置文件:
1,配置项connections.max.idle.ms,默认值9分钟,用于配置连接最大的空闲时间(每个连接的最大连接队列为100)。
2,配置项reconnect.backoff.ms,默认值50ms,用于配置连接断开后重新连接的间隔时间。
3,配置项send.buffer.bytes,默认值128kb,用于配置SOCKET的SO_SNDBUF发送数据的缓冲区大小。
4,配置项receive.buffer.bytes,默认值32kb,用于配置SOCKET的SO_RCVBUF接收数据的缓冲区大小。
5,读取request.timeout.ms配置项的值,默认值为40秒。用于配置请求的超时时间。
ChannelBuilder channelBuilder = ClientUtils.createChannelBuilder(
config.values());
NetworkClient netClient = new NetworkClient(
new Selector(config.getLong(
ConsumerConfig.CONNECTIONS_MAX_IDLE_MS_CONFIG),
metrics, time, metricGrpPrefix, metricsTags, channelBuilder),
this.metadata,
clientId,
100, // a fixed large enough value will suffice
config.getLong(ConsumerConfig.RECONNECT_BACKOFF_MS_CONFIG),
config.getInt(ConsumerConfig.SEND_BUFFER_CONFIG),
config.getInt(ConsumerConfig.RECEIVE_BUFFER_CONFIG),
config.getInt(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG), time);
根据retry.backoff.ms配置的值,生成一个ConsumerNetworkClient的实例。
this.client = new ConsumerNetworkClient(netClient, metadata, time,
retryBackoffMs);
读取auto.offset.reset配置项的值,默认值为latest。可配置("latest", "earliest", "none"),这个配置用于在读取partition的offset超出范围时,对offset进行重置的规则。
OffsetResetStrategy offsetResetStrategy = OffsetResetStrategy.valueOf(
config.getString(
ConsumerConfig.AUTO_OFFSET_RESET_CONFIG).toUpperCase());
生成用于管理订阅的topic的partition的状态管理的组件,用于管理partition的状态与当前的offset的信息。
this.subscriptions = new SubscriptionState(offsetResetStrategy);
生成用于管理相同的一个groupId下的多个client端的partition的分区控制,
通过partition.assignment.strategy配置,默认实例为RangeAssignor。
List<PartitionAssignor> assignors = config.getConfiguredInstances(
ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
PartitionAssignor.class);
生成用于对consumer进行协调的实例,这个实例依赖如下配置:
1,配置项group.id,用于配置consumer对应的订阅的组名称,相同的组的多个client端进行协调消费处理。
2,读取session.timeout.ms配置项的值,默认值为30秒,用于配置当前的consumer的session的超时时间,也就是client端多长时间不给server发送心跳就表示这个client端超时。
3,配置项heartbeat.interval.ms,默认值3秒,用于定时向server发送心跳的时间间隔。
4,根据retry.backoff.ms配置的值来设置读取信息失败的重试间隔。
5,配置项enable.auto.commit,默认值true,设置是否自动提交消费过的offset的值的设置。
5,配置项auto.commit.interval.ms,默认值5秒,如果设置有自动提交offset时,自动提交的间隔时间。
this.coordinator = new ConsumerCoordinator(this.client,
config.getString(ConsumerConfig.GROUP_ID_CONFIG),
config.getInt(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG),
config.getInt(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG),
assignors,
this.metadata,
this.subscriptions,
metrics,
metricGrpPrefix,
metricsTags,
this.time,
retryBackoffMs,
new ConsumerCoordinator.DefaultOffsetCommitCallback(),
config.getBoolean(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG),
config.getLong(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG));
根据key.deserializer配置与value.deserializer配置的key,value的反序列化的配置,生成反序列化消息的实例。这个类必须是实现Deserializer接口的类。
if (keyDeserializer == null) {
this.keyDeserializer = config.getConfiguredInstance(
ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
Deserializer.class);
this.keyDeserializer.configure(config.originals(), true);
} else {
config.ignore(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG);
this.keyDeserializer = keyDeserializer;
}
if (valueDeserializer == null) {
this.valueDeserializer = config.getConfiguredInstance(
ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
Deserializer.class);
this.valueDeserializer.configure(config.originals(), false);
} else {
config.ignore(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG);
this.valueDeserializer = valueDeserializer;
}
生成用于具体读取消息的读取实例,这个实例依赖如下几个配置信息:
1,配置项fetch.min.bytes,默认值1,用于设置每次读取的最小byte数。
2,配置项fetch.max.wait.ms,默认值500ms,用于设置每次读取的最大等待时间。
3,配置项max.partition.fetch.bytes,默认值1MB,用于设置每个partition每次读取的最大的数据量。
4,配置项check.crcs,默认值true,用于设置是否校验数据的完整性。
根据retry.backoff.ms配置的值来设置读取信息失败的重试间隔。
this.fetcher = new Fetcher<>(this.client,
config.getInt(ConsumerConfig.FETCH_MIN_BYTES_CONFIG),
config.getInt(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG),
config.getInt(ConsumerConfig.MAX_PARTITION_FETCH_BYTES_CONFIG),
config.getBoolean(ConsumerConfig.CHECK_CRCS_CONFIG),
this.keyDeserializer,
this.valueDeserializer,
this.metadata,
this.subscriptions,
metrics,
metricGrpPrefix,
metricsTags,
this.time,
this.retryBackoffMs);
config.logUnused();
AppInfoParser.registerAppInfo(JMX_PREFIX, clientId);
log.debug("Kafka consumer created");
} catch (Throwable t) {
// call close methods if internal objects are already constructed
// this is to prevent resource leak. see KAFKA-2121
close(true);