事情起因是这样的。我们环境需要用到kafka,现在都是使用容器化的部署,大佬就找了个github星最多docker-kafka连接给我,建议我用这个来搭建。我们开发环境已经有了zk,所以就让我用kafka连上面的zk。kafka搭起来了,生产者可以生产。但是消费者始终是消费不到消息。使用tcpdump抓包也可以确认,消息已经发送到kafka。但是消费者始终无法消费。猜想是不是那个步骤执行错了。所以就按照https://github.com/wurstmeister/kafka-docker的官方文档一步一步来做。
wurstmeister docker-kafka tutorial:http://wurstmeister.github.io/kafka-docker/
发现里面有一步骤怎么也走不通:
$KAFKA_HOME/bin/kafka-console-consumer.sh --topic=topic --zookeeper=$ZK
本地查看脚本的帮助,也没有这个参数,类似功能的是--bootstrap-server
的参数:
D:\Programs\kafka_2.11-2.4.0\bin\windows>kafka-console-consumer.bat --help
This tool helps to read data from Kafka topics and outputs it to standard output
.
Option Description
------ -----------
--bootstrap-server <String: server to REQUIRED: The server(s) to connect to.
connect to>
--consumer-property <String: A mechanism to pass user-defined
consumer_prop> properties in the form key=value to
the consumer.
--consumer.config <String: config file> Consumer config properties file. Note
that [consumer-property] takes
precedence over this config.
--enable-systest-events Log lifecycle events of the consumer
in addition to logging consumed
messages. (This is specific for
system tests.)
--formatter <String: class> The name of a class to use for
formatting kafka messages for
display. (default: kafka.tools.
DefaultMessageFormatter)
--from-beginning If the consumer does not already have
an established offset to consume
from, start with the earliest
message present in the log rather
than the latest message.
--group <String: consumer group id> The consumer group id of the consumer.
--help Print usage information.
--isolation-level <String> Set to read_committed in order to
filter out transactional messages
which are not committed. Set to
read_uncommittedto read all
messages. (default: read_uncommitted)
--key-deserializer <String:
deserializer for key>
--max-messages <Integer: num_messages> The maximum number of messages to
consume before exiting. If not set,
consumption is continual.
--offset <String: consume offset> The offset id to consume from (a non-
negative number), or 'earliest'
which means from beginning, or
'latest' which means from end
(default: latest)
--partition <Integer: partition> The partition to consume from.
Consumption starts from the end of
the partition unless '--offset' is
specified.
--property <String: prop> The properties to initialize the
message formatter. Default
properties include:
print.
timestamp=true|false
print.
key=true|false
print.
value=true|false
key.separator=<key.
separator>
line.separator=<line.
separator>
key.deserializer=<key.
deserializer>
value.
deserializer=<value.deserializer>
Users can also pass in customized
properties for their formatter; more
specifically, users can pass in
properties keyed with 'key.
deserializer.' and 'value.
deserializer.' prefixes to configure
their deserializers.
--skip-message-on-error If there is an error when processing a
message, skip it instead of halt.
--timeout-ms <Integer: timeout_ms> If specified, exit if no message is
available for consumption for the
specified interval.
--topic <String: topic> The topic id to consume on.
--value-deserializer <String:
deserializer for values>
--version Display Kafka version.
--whitelist <String: whitelist> Regular expression specifying
whitelist of topics to include for
consumption.
查了官方文档,也没有这个参数,类似功能的是一个--bootstrap-server
的参数,在api config 里面是bootstrap.servers
:
于是很确认地,这个文档应该是写错了,于是给项目提了一个issue,建议他们修正tutorial的错误。
https://github.com/wurstmeister/kafka-docker/issues/564
然后收到一个开发者的回复说:
cricket007: --zookeeper actually is an option. Both will work equally until Zookeper is removed from Kafka
cricket007: That doesn’t mean it’s removed yet.
还附上了添加这个使用--bootstrap-server
替代--zookeeper
的官方wiki:
KIP-500: Replace ZooKeeper with a Self-Managed Metadata Quorum
大概的意思就是说,过去kafka的partitions(分区)和brokers(经纪人)的元数据存储在zk里面,而且是使用zk来选举那个broker(经纪人)做controller(控制者)。为了解决consumer对zk依赖产生其他的限制,所以就让consumer从broker获取元数据信息了。
于是我大概明白了。好的软件如果要因为更改架构设计而更改接口或者参数,会有一个弃用的过渡期。在这个过渡期一般会兼容过去的接口和参数。在过渡期中旧接口被标记为弃用,新的用户使用会逐渐减少对旧接口的依赖。经过一个过渡期后,在某一个大版本的迭代直接移除旧的接口和功能。
如Elasticsearch
移除type
就是一个很好的例子。
所以我猜测,最新版本consumer
接口的zookeeper.connect
配置已经配移除了。
于是我查询kafka各个版本的文档,果然证实了自己的想法。
在kafka 0.10.0版本的时候,consumer
接口新加了bootstrap.server
配置,与此同时zookeeper.connect
被标记为弃用(deprecated)。
在kafka 2.1.0版本的时候,consumer
接口的zookeeper.connect
参数再也找不到了。自然连接的脚本也无法使用这个参数了。
综上所述,如果你使用的是kafka v0.10.0
版本以前的kafka,则使用kafka-console-consumer.sh
只能够通过--zookeeper
参数连接kafka集群。如果你使用的是kafka v0.10.0
到 kafka v2.1.0
以前的版本,则可以使用--bootstrap-server
或--zookeeper
两个参数连接kafka
集群。如果你使用的是kafka v2.1.0
及以上的版本,则只能够通过--bootstrap-server
参数连接kafka
集群。
与此同时,我一开始遇到的问题,貌似也有头绪。因为我搭建环境的时候zookeeper
已经存在的话,可能已经有kafka
把元数据信息放在了zookeeper
。由于之前连上的版本是kafka v0.10.0
之前的版本,所以消费者必须直连zookeeper
获取kafka的元数据信息。但是我后面注册到zookeeper
的kafka broker
是基于2.4.0
版本的,必须通过broker
获取元数据信息。按比较好的设计来说,集群里多个版本的代码启动的服务,应该都降级到集群中最低版本的功能来运行。但是2.4.0
的kafka broker已经无法使用低版本的broker controller election
(经纪人控制者选举),估计是2.1.0
移除的。所以导致消费者一直无法正确与kafka broker
建立连接的问题,并且报出 The coordinator is not available
的问题。
最终,在服务器另外启了一个干净的zookeeper
解决了这个问题。。。当然这是开发环境的解决方案。如果是生产环境,同一个集群最好还是不要混用kafka版本。
来源:CSDN
作者:Duncan_Tree_Zhou
链接:https://blog.csdn.net/u013547195/article/details/104478971