开心一刻

今天小学女同学给我发消息
她:你现在是毕业了吗
我:嗯,今年刚毕业
她给我发了一张照片,怀里抱着一只大橘猫
她:我的眯眯长这么大了,好看吗
我:你把猫挪开点,它挡住了,我看不到
她:你是 sb 吗,滚
我解释道:你说的是猫呀
可消息刚发出,就出现了红色感叹号,并提示:消息已发出,但被对方拒收了

kafka搭建

出于简单考虑,基于 docker 搭建一个 kafka 节点;因为一些原因,国内的 Docker Hub 镜像加速器都不可用了,目前比较靠谱的做法是搭建个人镜像仓库,可参考:Docker无法拉取镜像解决办法,我已经试过了,是可行的,但还是想补充几点

  1. sync-image-example.yml 只需要修改最后的镜像拷贝,其他内容不需要改

    支持一次配置多个镜像的拷贝

  2. 镜像拷贝

    docker 镜像拷贝命令的格式

    skopeo copy docker://docker.io/命名空间/镜像名:TAG docker://阿里云镜像地址/命名空间/镜像名:TAG

    我们以 kafka 为例,去 Docker Hub 一搜,好家伙,搜出来上万个

    我们将搜索条件精确化一些,搜 wurstmeister/kafka

    点进去,它在 Docker Hub 的地址是:

    https://hub.docker.com/r/wurstmeister/kafka

    那它的 docker 地址就是

    docker://docker.io/wurstmeister/kafka

    其他的镜像用类似的方式去找,所以最终的拷贝命令类似如下:

    skopeo copy docker://docker.io/wurstmeister/kafka:latest docker://registry.cn-hangzhou.aliyuncs.com/qingshilu/wurstmeister_kafka:latest

    如果一切顺利,那么在我们的阿里云个人镜像仓库就能看到我们拷贝的镜像了

  3. 如何 pull

    在个人仓库点镜像名,会看到 操作指南

    我们只关注前两步,就可以将镜像 pull 下来

镜像获取到之后,就可以搭建 kafka 了;因为依赖 zookeeper,我们先启动它

docker run -d --name zookeeper-test -p 2181:2181 \
--env ZOO_MY_ID=1 \
-v zookeeper_vol:/data \
-v zookeeper_vol:/datalog \
-v zookeeper_vol:/logs \
registry.cn-hangzhou.aliyuncs.com/qingshilu/wurstmeister_zookeeper

然后启动 kafka

docker run -d --name kafka-test -p 9092:9092 \
--env KAFKA_ZOOKEEPER_CONNECT=192.168.2.118:2181 \
--env KAFKA_ADVERTISED_HOST_NAME=192.168.2.118 \
--env KAFKA_ADVERTISED_PORT=9092 \
--env KAFKA_LOG_DIRS=/kafka/logs \
-v kafka_vol:/kafka \
registry.cn-hangzhou.aliyuncs.com/qingshilu/wurstmeister_kafka

不出意外的话,都启动成功

如果出意外了,大家也别慌,用 docker log 去查看日志,然后找对应的解决方案

# 1.先找到启动失败的容器id
docker ps -a
# 2.用 docker log 查看容器启动日志
docker log 容器id

如果需要开启 kafkaSASL 认证,可参考:Docker-Compose搭建带SASL用户密码验证的Kafka 来搭建

Kafka Tool

详情可查看:kafka可视化客户端工具(Kafka Tool)的基本使用

创建 Topic:test-topic,并发送一条消息

此时 test-topic 中有 1 条消息

消费者 poll

代码很简单

/**
* @author: 青石路
*/
public class MsgConsumer { private static final Logger LOGGER = LoggerFactory.getLogger(MsgConsumer.class); public static void main(String[] args) {
Properties props = new Properties();
props.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.2.118:9092");
props.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
props.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "test_group");
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
// 如果在kafka中找不到当前消费者的偏移量,则设置为最旧的
props.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
props.put(ConsumerConfig.MAX_POLL_RECORDS_CONFIG, 500);
KafkaConsumer<String, String> consumer = new KafkaConsumer<String,String>(props);
// 订阅主题
consumer.subscribe(Collections.singleton("test-topic"));
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
LOGGER.info("records count = {}", records.count());
records.forEach(record -> LOGGER.info("{} - {} - {}", record.offset(), record.key(), record.value()));
// consumer.commitAsync();
consumer.close();
}
}

我们执行下,输出日志如下

竟然 poll 不到消息,为什么呀?

我们调整下代码,循环 poll

while (true) {
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));
LOGGER.info("records count = {}", records.count());
records.forEach(record -> LOGGER.info("{} - {} - {}", record.offset(), record.key(), record.value()));
}

我们再执行下,输出日志如下

消费者 poll 的过程中会先判断当前消费者是否在 消费者组 中,如果不在,会先加入消费者组,在加入过程中,ConsumerCoordinator 会对这个消费者组 Rebalance,整个过程中该消费者组内的所有消费者都不能工作,而 poll 又配置了超时时间(100 毫秒),如果在超时时间内,当前消费者还未正常加入消费者组中,那么 poll 肯定是拉取不到数据的;根据日志可以看出,第 3 次 poll 的时候,消费者已经正常加入消费者组中,那么就能 poll 到数据了

很多小伙伴可能可能会有这样的疑问

平时在项目中使用的时候,从来没有感受到这样的问题,为什么呢

原因有以下几点

  1. poll 的超时时间设置比较长,超时时间内消费者能够正常加入到消费者组中
  2. 消费者随项目的启动创建,存活周期与项目一致,那么只有前几次 poll 的时候,可能会因为消费者未加入到消费者组中而拉取不到数据,而一旦消费者成功加入到消费者组之后,那么只要 Topic 中有数据,poll 肯定能拉取到数据;从整个次数占比来看,poll 拉取不到数据的异常情况(Topic 中有可拉取的数据,但 poll 不到)占比非常小,小到可以忽略不计了

所以你们感受不到这样;但如果某些场景下,比如 DataX 从 kafka 读数据

异源数据同步 → DataX 为什么要支持 kafka?

消费者要不断新建,那么 poll 不到数据的异常情况的占比就会上来了,那就需要通过一些机制来降低其所造成的的影响了,比如说重试机制

总结

  1. 示例代码:kafka-demo
  2. 如果大家平时用 docker 比较多,推荐通过搭建个人镜像仓库来解决镜像拉取超时的问题
  3. kakfa 消费者 poll 的时候,消费者如果不在消费者组中,会先加入消费者组,那么超时时间内可能 poll 不到数据,可以通过增大超时时间,或者重试机制来降低 poll 不到数据的异常次数(Topic 中没有可拉取的数据而 poll 不到的情况不算异常情况)

Kafka Topic 中明明有可拉取的消息,为什么 poll 不到的更多相关文章

  1. 解决 MySQL 比如我要拉取一个消息表中用户id为1的前10条最新数据

    我们都知道,各种主流的社交应用或者阅读应用,基本都有列表类视图,并且都有滑到底部加载更多这一功能, 对应后端就是分页拉取数据.好处不言而喻,一般来说,这些数据项都是按时间倒序排列的,用户只关心最新的动 ...

  2. 源码分析Kafka 消息拉取流程

    目录 1.KafkaConsumer poll 详解 2.Fetcher 类详解 本节重点讨论 Kafka 的消息拉起流程. @(本节目录) 1.KafkaConsumer poll 详解 消息拉起主 ...

  3. RocketMQ中PullConsumer的消息拉取源码分析

    在PullConsumer中,有关消息的拉取RocketMQ提供了很多API,但总的来说分为两种,同步消息拉取和异步消息拉取 同步消息拉取以同步方式拉取消息都是通过DefaultMQPullConsu ...

  4. RocketMQ 拉取消息-文件获取

    看完了上一篇的<RocketMQ 拉取消息-通信模块>,请求进入PullMessageProcessor中,接着 PullMessageProcessor.processRequest(f ...

  5. 【mq读书笔记】消息拉取长轮训机制(Broker端)

    RocketMQ并没有真正实现推模式,而是消费者主动想消息服务器拉取消息,推模式是循环向消息服务端发送消息拉取请求. 如果消息消费者向RocketMQ发送消息拉取时,消息未到达消费队列: 如果不启用长 ...

  6. 【RocketMQ】消息的拉取

    RocketMQ消息的消费以组为单位,有两种消费模式: 广播模式:同一个消息队列可以分配给组内的每个消费者,每条消息可以被组内的消费者进行消费. 集群模式:同一个消费组下,一个消息队列同一时间只能分配 ...

  7. 【mq读书笔记】消息拉取

    疑问:PullRequest何时添加? PullMessageService提供延迟添加与立即添加2种方式 疑问:PullRequest是在什么时候创建的呢? 1.上上图中 PullRequest p ...

  8. canal从mysql拉取数据,并以protobuf的格式往kafka中写数据

    大致思路: canal去mysql拉取数据,放在canal所在的节点上,并且自身对外提供一个tcp服务,我们只要写一个连接该服务的客户端,去拉取数据并且指定往kafka写数据的格式就能达到以proto ...

  9. FLUME安装&环境(二):拉取MySQL数据库数据到Kafka

    Flume安装成功,环境变量配置成功后,开始进行agent配置文件设置. 1.agent配置文件(mysql+flume+Kafka) #利用Flume将MySQL表数据准实时抽取到Kafka a1. ...

  10. Kafka消费者拉取数据异常Unexpected error code 2 while fetching data

    Kafka消费程序间歇性报同一个错: 上网没查到相关资料,只好自己分析.通过进一步分析日志发现,只有在拉取某一个特定的topic的数据时报错,如果拉取其他topic的数据则不会报错.而从这个异常信息来 ...

随机推荐

  1. ajax - 初步介绍

    进入ajax了,想要进入vue还有一个前提就是要把ajax给熟悉一下,看一看客户端与服务器之间是怎么一个通信的过程,第一天主要是先了解了一下ajax的一些介绍,ajax嘛,在进入之前,肯定是要了解一下 ...

  2. 谈谈你对 Vue 生命周期的理解?

    生命周期是什么? Vue 实例有一个完整的生命周期,也就是从 开始创建.初始化数据.编译模版.挂载 Dom -> 渲染.更新 -> 渲染.卸载等一系列过程,我们称这是 Vue 的生命周期. ...

  3. 24 slide的pdf没有高亮开关

    安卓 app slide的pdf没有高亮开关

  4. oeasy 教您玩转 linux 010207 黑客帝国 matrix

    我们来回顾一下 上一部分我们都讲了什么? 蒸汽机车sl 变身小机车-l 变身飞天机车-F 让我们再开一次车 sl 上次还想看看黑客帝国来着?! 黑客帝国Matrix apt search matrix ...

  5. rtmp流程解析

    如果rtmp推流地址:rtmp://服务器地址:rtmp端口/路径/名称对应的websocket地址:ws://服务器地址:websocket端口/路径/名称.flv举例:live作为路径,s作为流名 ...

  6. FindBugs质量管理

    1. FindBugs是什么 FindBugs 是一个静态分析工具,它检查类或者 JAR 文件,将字节码与一组缺陷模式进行对比以发现可能的问题.有了静态分析工具,就可以在不实际运行程序的情况对软件进行 ...

  7. 查询当前网段的所有在用IP

    查询当前网段的所有在用IP For /L %i in (0,1,254) DO ping 192.168.10.%i >>D:\IP.txt https://www.cnblogs.com ...

  8. VSCode的安装

    VSCode(visual studio code),是一款功能强大且易用的编辑器.支持JavaScript.Node.js,也提供其他语言如(C ++,C#,Python,PHP,Go)的扩展插件. ...

  9. Java还是C#?我该如何选择?给年轻人的建议...

    一.年轻人应该通吃 其实这不应该是我们真正的主题,而且入了行的也很少会java还是c#这么比,但初学的,java和c#往往就代表了两大流派,java代替了j2ee,c#代替了.net,ok,没有关系, ...

  10. 【Vue】12 VueRouter Part2 路由与传参

    [编程式导航] 我们希望在路由跳转之前执行某一些功能... <template> <div id="app"> <h2>这是App.vue组件的 ...