Kafka
1.kafka为什么不基于内存?
答:因为kafka是基于scala和java实现的。需要运行在jvm中,如果是基于内存实现,会在堆中进行大量数据读写,会频繁 full gc。
2.kafka为什么快
答:1.顺序读写:省去了大量磁头寻址的时间。
2.0拷贝:减少不必要的拷贝次数
3.mmap: 将磁盘文件映射到内存,通过修改内存即可以修改磁盘文件
问题:不可靠,因为写到mmap的数据并没有真正写到磁盘上,需要程序主动flush才能写入
3.kakfa如何保证消息 不丢失?
答 1.生产者丢失 网络问题没有发送成功
解决:判断消息发送的回调结果。引入重试机制。
2.消费者丢失 消费者拿到消息还没消费,挂掉了,然后offset自动提交
解决:关闭自动提交,消息消费完再手动提交
引发问题:消息可能重复消费
3.kakfa自身丢失 leader所在的broker挂掉。但是数据没有被follower同步
解决:设置acks=all 表示所有副本都要接收到该消息才算成功。
扩展: acks=1 表示消息被leader接收计算成功
4.kafka 消息保证不重复消费?
解决
(1)、可在内存中维护一个set,只要从消息队列里面获取到一个消息,先查询这个消息在不在set里面,如果在表示已消费过,直接丢弃;如果不在,则在消费后将其加入set当中。
(2)、如何要写数据库,可以拿唯一键先去数据库查询一下,如果不存在在写,如果存在直接更新或者丢弃消息。
(3)、如果是写redis那没有问题,每次都是set,天然的幂等性。
(4)、让生产者发送消息时,每条消息加一个全局的唯一id,然后消费时,将该id保存到redis里面。消费时先去redis里面查一下有么有,没有再消费。
(5)、数据库操作可以设置唯一键,防止重复数据的插入,这样插入只会报错而不会插入重复数据。
5.kafka如何保证消费顺序?
解决:1.每一个topic只有一个分区
2.发送消息时指定分区\
6.kakfa的leader和foller 如何同步数据?
答:kafka的复制机制既不是完全的同步复制,也不是单纯异步复制。完全同步复制要求all live follow都复制完,这条消息才被认为commit。非常影响吞吐率。而异步复制,数据只要被leader写入log则认为已经commit,如果leader挂掉了的话,容易造成数据丢失。kafka的ISR机制很好的均衡了确保数据不丢失以及吞吐率。follow可以批量的从leader复制数据,而且leader充分利用了磁盘的顺序读写以及sendfile机制,极大的提高了复制性能,内部批量写磁盘,大大减少了follow和leader的信息量差。
7.消息积压怎么解决
1.扩容消费端。2.优化业务逻辑,提高消费能力。
8.ISR机制
ISR就是kafka某个分区中维护的同步集合,该集合就是ISR。每一个partitino都有一个ISR,它是由leader动态维护。只要处于ISR集合中的副本,就意味着follower副本和leader副本保持同步状态,同时也只有处于ISR集合中的副本才能被选举为leader
kafka的Replica
- kafka的topic可以设置N个副本(replica),副本数最好小于broker数量,其实一般就是一个broker最多一个replica,可以用broker id指定partition replica。
- 创建副本的单位是topic的分区,每个分区有一个leader和0到多个follower,我们把多个replica分为leader replica和follower replica。
- 当producer在向partition中写数据时,根据ack机制,默认为ack=1,只会leader中写入数据,然后leader中的数据会复制到其他的replica中,follower会周期性的从leader中pull数据,但是对于数据的读写操作都在leader replica中,follower副本只有当leader副本挂掉之后才重新选去leader,follower并不向外提供服务。
9.ack机制
我们知道如果需要往kafka里面发送消息,需要producer完成,那么我们怎么保证消息是否发送成功呢。kafka提供了消息确认机制。也就是说我们通过配置来决定发送到对应分区的几个副本就算成功。我们可以通过配置acks参数指定。
-
acks = 0,意味着producer发送消息出去就认为发送成功。但是这种也非常容易丢失数据,比如发送的对象无能被序列化或者网卡发生故障等。
-
acks = 1,意味着leader收到消息并写入分区数据文件返回成功消息则认为发送成功。在这个模式下,如果发生正常的 Leader 选举,生产者会在选举时收到一个 LeaderNotAvailableException 异常,如果生产者能恰当地处理这个错误,它会重试发送悄息,最终消息会安全到达新的 Leader 那里。不过这个模式也可能会丢失数据,就是当leader写好后,在复制到follower副本之前leader崩溃了。
-
acks = -1,意味着 Leader 在返回确认或错误响应之前,会等待所有同步副本都收到悄息。如果和 min.insync.replicas 参数结合起来,就可以决定在返回确认前至少有多少个副本能够收到悄息,生产者会一直重试直到消息被成功提交。不过这个非常慢,因为生产者需要等待所有副本消息才能继续发消息。
10.集群部署
kafka linux 集群部署
1.修改 config/service.properties
broker.id 每个kafka必须唯一
advertised.listeners=PLAINTEXT://+ 当前服务器ip 端口
zookeeper.connect 集群zookeeper地址
-kafka 运行日志存放路径
log.dirs=/usr/local/kafka_2.12-2.2.2/log/kafka
-topic 在当前broker上的分片个数,与broker保持一致
num.partitions=3
2.修改 zookeeper.properties
目录必须存在 不存在要手动建文件夹
#修改为自定义的zookeeper数据目录
dataDir=/usr/local/kafka_2.12-2.2.2/zookeeper
#修改为自定义的zookeeper日志目录
dataLogDir=/usr/local/kafka_2.12-2.2.2/log/zookeeper
#注释掉
#maxClientCnxns=0
#设置连接参数,添加如下配置
tickTime=2000 #为zk的基本时间单元,毫秒
initLimit=10 #Leader-Follower初始通信时限 tickTime*10
syncLimit=5 #Leader-Follower同步通信时限 tickTime*5
#设置broker Id的服务地址
server.0=172.27.178.79:2888:3888
server.1=172.27.178.80:2888:3888
server.2=172.27.178.81:2888:3888
在kafka_2.12-2.2.2 目录下新建文件夹 zookeeper
跳转 zookeeper 目录,执行 echo 0 > myid,其中 0 为本服务器kafka broker.id
3.启动zookeeper
分别在各个服务器启动zookeeper
跳转到kafka 目录
cd /home/app/kafka_2.12-2.2.2
nohup ./bin/zookeeper-server-start.sh ./config/zookeeper.properties > ./log/zookeeper/zookeeper.log 2>1 &
4.启动kafka
待zookeeper启动完成,依次在各服务器启动kafka
跳转到kafka 目录
cd /home/app/kafka_2.12-2.2.2
nohup ./bin/kafka-server-start.sh ./config/server.properties > ./log/kafka/kafka.log 2>1 &
5.验证安装是否成功
跳转kafka目录
cd /home/app/kafka_2.12-2.2.2
在某台服务器上创建话题
./bin/kafka-topics.sh -create --zookeeper
172.27.178.79:2181,172.27.178.80:2181,172.27.178.81:2181 -replication-factor 3 --partitions 3 --topic test
在某台服务器上创建生产者
./bin/kafka-console-producer.sh --broker-list 172.27.178.79:9092,172.27.178.80:9092,172.27.178.81:9092 --topic test
在其他服务器上创建消费者
./bin/kafka-console-consumer.sh --bootstrap-server 172.27.178.79:8092,172.27.178.80:8092,172.27.178.81:9092 --topic test11 -- from-geginning
在生产者上发送消息,看消费者服务器是否能接收
6.关闭kafka
ps -ef | grep kafka
关闭所有kafka 进程 每个服务器有四个进程