Kafka
1. 为什么要使用 kafka?
缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够
多的机器来保证冗余,
kafka
在中间可以起到一个缓冲的作用,把消息暂存
在
kafka
中,下游服务就可以按照自己的节奏进行慢慢处理。
解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为
一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获
取扩展能力。
冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅
topic
的服务消费到,供多个毫无关联的业务使用。
健壮性:消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会
影响主要业务的正常进行。
异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异
步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列
中放入多少消息就放多少,然后在需要的时候再去处理它们。
2. Kafka 消费过的消息如何再消费?
kafka
消费消息的
offset
是定义在
zookeeper
中的, 如果想重复消费
kafka
的消
息,可以在
redis
中自己记录
offset
的
checkpoint
点(
n
个),当想重复消费消息
时,通过读取
redis
中的
checkpoint
点进行
zookeeper
的
offset
重设,这样就可以
达到重复消费消息的目的了
3. kafka 的数据是放在磁盘上还是内存上,为什么速度会快?
kafka
使用的是磁盘存储。
速度快是因为:
1.
顺序写入:
因为硬盘是机械结构,每次读写都会寻址
->
写入,其中寻址是一个
“
机械动
作
”
,它是耗时的。所以硬盘
“
讨厌
”
随机
I/O
, 喜欢顺序
I/O
。为了提高读写硬盘的速
度,
Kafka
就是使用顺序
I/O
。
2.
Memory Mapped Files
(内存映射文件):
64
位操作系统中一般可以表示
20G
的数据文
件,它的工作原理是直接利用操作系统的
Page
来实现文件到物理内存的直接映射。完
成映射之后你对物理内存的操作会被同步到硬盘上。
3.
Kafka
高效文件存储设计:
Kafka
把
topic
中一个
parition
大文件分成多个小文件段,通
过多个小文件段,就容易定期清除或删除已经消费完文件,减少磁盘占用。通过索引信
息可以快速定位
message
和确定
response
的 大 小。通过
index
元数据全部映射到
memory
(内存映射
文件),
可以避免
segment file
的
IO
磁盘操作。通过索引文件稀疏存储,可以大幅降低
index
文
件元数据占用空间大小。
注:
1.
Kafka解决查询效率的手段之一是将数据文件分段,比如有100条Message,它们的offset
是从 0 到 99。假设将数据文件分成 5 段,第一段为 0-19,第二段为 20-39,以此类推,
每段放在一个单独的数据文件里面,数据文件以该段中 小的 offset 命名。这样在查找
指定 offset 的
Message 的时候,用二分查找就可以定位到该 Message 在哪个段中。
2.
为数据文件建 索引数据文件分段 使得可以在一个较小的数据文件中查找对应 offset
的 Message 了,但是这依然需要顺序扫描才能找到对应 offset 的 Message。
为了进一步提高查找的效率,Kafka 为每个分段后的数据文件建立了索引文件,文件名
与数据文件的名字是一样的,只是文件扩展名为.index。
4. Kafka 数据怎么保障不丢失?
分三个点说,一个是生产者端,一个消费者端,一个
broker
端。
生产者数据的不丢失:
kafka
的
ack
机制:在
kafka
发送数据的时候,每次发送消息都会有一个确认反馈
机制,确保消息正常的能够被收到,其中状态有
0
,
1
,
-1
。
如果是同步模式:
ack
设置为
0
,风险很大,一般不建议设置为
0
。即使设置为
1
,也会随着
leader
宕机丢失数据。所以如果要严格保证生产端数据不丢失,可设置为
-1
。
如果是异步模式:
也会考虑
ack
的状态,除此之外,异步模式下的有个
buffer
,通过
buffer
来进行
控制数据的发送,有两个值来进行控制,时间阈值与消息的数量阈值,如果
buffer
满了数据还没有发送出去,有个选项是配置是否立即清空
buffer
。可以设置为
-1
,
永久阻塞,也就数据不再生产。异步模式下,即使设置为
-1
。也可能因为程序员
的不科学操作,操作数据丢失,比如
kill -9
,但这是特别的例外情况。
注:
ack=0:producer 不等待 broker 同步完成的确认,继续发送下一条(批)信息。
ack=1(默认):
producer 要等待leader成功收到数据并得到确认,才发送下一条message。
ack=-1:producer 得到 follwer 确认,才发送下一条数据。
消费者数据的不丢失:
通过
offset commit
来保证数据的不丢失,
kafka
自己记录了每次消费的
offset
数
值,下次继续消费的时候,会接着上次的
offset
进行消费。
而
offset
的信息在
kafka0.8
版本之前保存在
zookeeper
中,在
0.8
版本之后保存
到
topic
中,即使消费者在运行过程中挂掉了,再次启动的时候会找到
offset
的
值,找到之前消费消息的位置,接着消费,由于
offset
的信息写入的时候并不
是每条消息消费完成后都写入的,所以这种情况有可能会造成重复消费,但是不
会丢失消息。
唯一例外的情况是,我们在程序中给原本做不同功能的两个
consumer
组设置
KafkaSpoutConfig.bulider.setGroupid
的时候设置成了一样的
groupid
,这种情况会
导致这两个组共享同一份数据,就会产生组
A
消费
partition1
,
partition2
中的消
息,组
B
消费
partition3
的消息,这样每个组消费的消息都会丢失,都是不完整
的。 为了保证每个组都独享一份消息数据,
groupid
一定不要重复才行。
kafka
集群中的
broker
的数据不丢失:
每个
broker
中的
partition
我们一般都会设置有
replication
(副本)的个数,生产
者写入的时候首先根据分发策略(有
partition
按
partition
,有
key
按
key
,都没
有轮询)写入到
leader
中,
follower
(副本)再跟
leader
同步数据,这样有了备
份,也可以保证消息数据的不丢失。
5. 采集数据为什么选择 kafka?
采集层 主要可以使用
Flume, Kafka
等技术。
Flume
:
Flume
是管道流方式,提供了很多的默认实现,让用户通过参数部署,
及扩展
API.
Kafka
:
Kafka
是一个可持久化的分布式的消息队列。
Kafka
是一个非常通用的系
统。你可以有许多生产者和很多的消费者共享多个主题
Topics
。
相比之下
,Flume
是一个专用工具被设计为旨在往
HDFS
,
HBase
发送数据。它对
HDFS
有特殊的优化,并且集成了
Hadoop
的安全特性。
所以,
Cloudera
建议如果数据被多个系统消费的话,使用
kafka
;如果数据被设
计给
Hadoop
使用,使用
Flume
。
6. kafka 重启是否会导致数据丢失?
1. kafka
是将数据写到磁盘的,一般数据不会丢失。
2.
但是在重启
kafka
过程中,如果有消费者消费消息,那么
kafka
如果来不及提交
offset
,
可能会造成数据的不准确(丢失或者重复消费)。
7. kafka 宕机了如何解决?
先考虑业务是否受到影响
kafka
宕机了,首先我们考虑的问题应该是所提供的服务是否因为宕机的机器而
受到影响,如果服务提供没问题,如果实现做好了集群的容灾机制,那么这块就
不用担心了。
节点排错与恢复
想要恢复集群的节点,主要的步骤就是通过日志分析来查看节点宕机的原因,从
而解决,重新恢复节点。
8. 为什么 Kafka 不支持读写分离?
在
Kafka
中,生产者写入消息、消费者读取消息的操作都是与
leader
副本进行
交互的,从 而实现的是一种
主写主读
的生产消费模型。
Kafka
并不支持
主写从读
,因为主写从读有
2
个很明显的缺点
:
数据一致性问题
:数据从主节点转到从节点必然会有一个延时的时间窗口,这个
时间 窗口会导致主从节点之间的数据不一致。某一时刻,在主节点和从节点中
A
数据的值都为
X
, 之后将主节点中
A
的值修改为
Y
,那么在这个变更通知到从
节点之前,应用读取从节点中的
A
数据的值并不为最新的
Y
,由此便产生了数
据不一致的问题。
延时问题:
类似
Redis
这种组件,数据从写入主节点到同步至从节点中的过程
需要经历 网络
→
主节点内存
→
网络
→
从节点内存 这几个阶段,整个过程会耗费
一定的时间。而在
Kafka
中,主从同步会比
Redis
更加耗时,它需要经历 网络
→
主节点内存
→
主节点磁盘
→
网络
→
从节 点内存
→
从节点磁盘 这几个阶段。对
延时敏感的应用而言,主写从读的功能并不太适用。
而
kafka
的
主写主读
的优点就很多了:
1.
可以简化代码的实现逻辑,减少出错的可能
;
2.
将负载粒度细化均摊,与主写从读相比,不仅负载效能更好,而且对用户可控
;
3.
没有延时的影响
;
4.
在副本稳定的情况下,不会出现数据不一致的情况。
9. kafka 数据分区和消费者的关系?
每个分区只能由同一个消费组内的一个消费者
(consumer)
来消费,可以由不同的
消费组的消费者来消费,同组的消费者则起到并发的效果。
10. kafka 的数据 offset 读取流程
1.
连接
ZK
集群,从
ZK
中拿到对应
topic
的
partition
信息和
partition
的
Leader
的相关信息
2.
连接到对应
Leader
对应的
broker
3. consumer
将
⾃
自
⼰
己保存的
offset
发送给
Leader
4. Leader
根据
offset
等信息定位到
segment
(索引
⽂
文件和
⽇
日志
⽂
文件)
5.
根据索引
⽂
文件中的内容,定位到
⽇
日志
⽂
文件中该偏移量
量
对应的开始
位置读取相应
⻓
长度的数据并返回给
consumer
11. kafka 内部如何保证顺序,结合外部组件如何保证消费者的顺
序?
kafka
只能保证
partition
内是有序的,但是
partition
间的有序是没办法的。爱奇
艺的搜索架构,是从业务上把需要有序的打到同
⼀
个
partition
。
12. Kafka 消息数据积压,Kafka 消费能力不足怎么处理?
1.
如果是
Kafka
消费能力不足,则可以考虑增加
Topic
的分区数,并且同时
提升消费组的消费者数量,消费者数
=
分区数。(两者缺一不可)
2.
如果是下游的数据处理不及时:提高每批次拉取的数量。批次拉取数据过
少(拉取数据
/
处理时间
<
生产速度),使处理的数据小于生产的数据,也
会造成数据积压。
13. Kafka 单条日志传输大小
kafka
对于消息体的大小默认为单条最大值是
1M
但是在我们应用场景中
,
常常
会出现一条消息大于
1M
,如果不对
kafka
进行配置。则会出现生产者无法将消
息推送到
kafka
或消费者无法去消费
kafka
里面的数据
,
这时我们就要对
kafka
进
行以下配置:
server.properties
replica
.fetch.max.bytes
: 1048576
broker
可复制的消息的最大字节数
,
默认为
1
M
message
.max.bytes
: 1000012
kafka
会接收单个消息
size
的最大限制, 默认为
1
M
左右
注意:
message.max.bytes
必须小于等于
replica.fetch.max.bytes
,否则就会导致
replica
之间数据同步失败。