1.问题描述
最近项目中在排查问题时发现,使用kafka-console-consumer.sh后使用两次grep管道后查询结果有部分符合条件的数据未被筛选出来。
2.排查过程
使用kafka-console-consumer.sh命令加两次grep过滤数据,命令如下:
./bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic mop_capacitySync --consumer.config auth/admin.conf --from-beginning|grep 2021030300004731|grep 2208191701120075
结果如图:
只使用一个grep过滤结果如图:
./bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic mop_capacitySync --consumer.config auth/admin.conf --from-beginning|grep 2021030300004731
经过对比发现:sync_time":"2023-03-13 10:00:33"之后的数据明显也是符合上条查询条件的,但是没有被查询到。
后网上搜索发现,kafka消费时结果是动态的,grep只有对静态的文件可以查询到数据。
在动态标准输出结果grep查询时需要使用--line-buffered
--line-buffered
Force output to be line buffered. By default, output is line buffered when standard output is
a terminal and block buffered otherwise
上面意思是:
-
强制输出结果使用行缓冲
-
默认情况下,如果标准输入时终端,则使用line bufferred
-
否则,使用块缓冲
肤浅理解为:当grep过滤条件前查询数据为标准输出时,也就是动态的。会先将结果缓存在缓冲区,当达到块缓存大小限制时,才会写入文件中,而未达到块缓存大小时会被放在缓冲区,未写入文件。这是就搜索不到。而使用line bufferred是强制将行缓存刷新到文件中。
其他:发现在使用tail 命令后加grep也存在同样的问题。
3.解决方案
使用-line-buffered,grep当带上了 --line-buffer 的时候,每输出一行,就刷新一次。
命令为:
./bin/kafka-console-consumer.sh --bootstrap-server 127.0.0.1:9092 --topic mop_capacitySync --consumer.config auth/admin.conf --from-beginning| grep --line-buffered "2021030300004731" |grep 2208191701120075
查询结果如下:
问题解决。
4.分析
研究了下关于linux下文件缓冲详解,分为全缓存、行缓存、和无缓存。
标准文件编程库采用FILE类型描述文件流,与低级I/O函数相比,最大的特性就是应用及增加了缓冲功能(低级I/O函数只使用了文件系统自带的缓冲功能),文件的输入输出以"缓冲块"为单位批量完成,并且根据"缓冲块"大小,提供了三种缓冲模式。
(1)全缓冲(_IOFBF):一般读写普通磁盘文件采用全缓冲模式。
(2)行缓冲(_IOLBF):比如调用fgets函数从标准输入流stdin中输入字符,当且仅当客户输入回车换行时,函数才返回。
(3)无缓冲(_IONBF):比如stderr采用无缓冲模式
-line-buffered就是使用了行缓存。大概搞明白了问题的原因以及解决办法。但是针对linux具体的的缓存原理还是有点不是很清晰,以及是块缓存和行缓存的具体缓存流程。
就这样吧,如果有哪位大佬有更清楚易懂的linux文件块缓存和行缓存的缓存流程,可以一起学习下。不胜感激。