Kafka是分布式发布-订阅消息系统,它最初是由LinkedIn公司开发的,以后成为Apache项目的一部分,Kafka是一个分布式,可划分的,冗余备份的持久性的日志服务,它主要用于处理流式数据。html
缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间能够起到一个缓冲的做用,把消息暂存在kafka中,下游服务就能够按照本身的节奏进行慢慢处理。java
解耦和扩展性:项目开始的时候,并不能肯定具体需求。消息队列能够做为一个接口层,解耦重要的业务流程。只须要遵照约定,针对数据编程便可获取扩展能力。编程
冗余:能够采用一对多的方式,一个生产者发布消息,能够被多个订阅topic的服务消费到,供多个毫无关联的业务使用。数组
健壮性:消息队列能够堆积请求,因此消费端业务即便短期死掉,也不会影响主要业务的正常进行。缓存
异步通讯:不少时候,用户不想也不须要当即处理消息。消息队列提供了异步处理机制,容许用户把一个消息放入队列,但并不当即处理它。想向队列中放入多少消息就放多少,而后在须要的时候再去处理它们。网络
ISR:In-Sync Replicas 副本同步队列
AR:Assigned Replicas 全部副本
ISR是由leader维护,follower从leader同步数据有一些延迟(包括延迟时间replica.lag.time.max.ms和延迟条数replica.lag.max.messages两个维度, 当前最新的版本0.10.x中只支持replica.lag.time.max.ms这个维度),任意一个超过阈值都会把follower剔除出ISR, 存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。多线程
broker 是消息的代理,Producers往Brokers里面的指定Topic中写消息,Consumers从Brokers里面拉取指定Topic的消息,而后进行业务处理,broker在中间起到一个代理保存消息的中转站。架构
5.kafka中的 zookeeper 起到什么做用,能够不用zookeeper么异步
zookeeper 是一个分布式的协调组件,早期版本的kafka用zk作meta信息存储,consumer的消费状态,group的管理以及 offset的值。考虑到zk自己的一些因素以及整个架构较大几率存在单点问题,新版本中逐渐弱化了zookeeper的做用。新的consumer使用了kafka内部的group coordination协议,也减小了对zookeeper的依赖,socket
可是broker依然依赖于ZK,zookeeper 在kafka中还用来选举controller 和 检测broker是否存活等等。
Kafka的复制机制既不是彻底的同步复制,也不是单纯的异步复制。彻底同步复制要求All Alive Follower都复制完,这条消息才会被认为commit,这种复制方式极大的影响了吞吐率。而异步复制方式下,Follower异步的从Leader复制数据,数据只要被Leader写入log就被认为已经commit,这种状况下,若是leader挂掉,会丢失数据,kafka使用ISR的方式很好的均衡了确保数据不丢失以及吞吐率。Follower能够批量的从Leader复制数据,并且Leader充分利用磁盘顺序读以及send file(zero copy)机制,这样极大的提升复制性能,内部批量写磁盘,大幅减小了Follower与Leader的消息量差。
leader会维护一个与其基本保持同步的Replica列表,该列表称为ISR(in-sync Replica),每一个Partition都会有一个ISR,并且是由leader动态维护 ,若是一个follower比一个leader落后太多,或者超过必定时间未发起数据复制请求,则leader将其重ISR中移除 。
Cache Filesystem Cache PageCache缓存
顺序写 因为现代的操做系统提供了预读和写技术,磁盘的顺序写大多数状况下比随机写内存还要快。
Zero-copy 零拷技术减小拷贝次数
Batching of Messages 批量量处理。合并小的请求,而后以流的方式进行交互,直顶网络上限。
Pull 拉模式 使用拉模式进行消息的获取消费,与消费端处理能力相符。
增长线程
提升 batch.size
增长更多 producer 实例
增长 partition 数
设置 acks=-1 时,若是延迟增大:能够增大 num.replica.fetchers(follower 同步数据的线程数)来调解;
跨数据中心的传输:增长 socket 缓冲区设置以及 OS tcp 缓冲区设置。
1(默认) 数据发送到Kafka后,通过leader成功接收消息的的确认,就算是发送成功了。在这种状况下,若是leader宕机了,则会丢失数据。
0 生产者将数据发送出去就无论了,不去等待任何返回。这种状况下数据传输效率最高,可是数据可靠性确是最低的。
-1 producer须要等待ISR中的全部follower都确认接收到数据后才算一次发送完成,可靠性最高。当ISR中全部Replica都向Leader发送ACK时,leader才commit,这时候producer才能认为一个请求中的消息都commit了。
11.kafka unclean 配置表明啥,会对 spark streaming 消费有什么影响
unclean.leader.election.enable 为true的话,意味着非ISR集合的broker 也能够参与选举,这样有可能就会丢数据,spark streaming在消费过程当中拿到的 end offset 会忽然变小,致使 spark streaming job挂掉。若是unclean.leader.election.enable参数设置为true,就有可能发生数据丢失和数据不一致的状况,Kafka的可靠性就会下降;而若是unclean.leader.election.enable参数设置为false,Kafka的可用性就会下降。
kafka在Broker端提供了一个配置参数:unclean.leader.election,这个参数有两个值:
true(默认):容许不一样步副本成为leader,因为不一样步副本的消息较为滞后,此时成为leader,可能会出现消息不一致的状况。
false:不容许不一样步副本成为leader,此时若是发生ISR列表为空,会一直等待旧leader恢复,下降了可用性。
一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成
header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成。
当magic的值为1的时候,会在magic和crc32之间多一个字节的数据:attributes(保存一些相关属性,
好比是否压缩、压缩格式等等);若是magic的值为0,那么不存在attributes属性
body是由N个字节构成的一个消息体,包含了具体的key/value消息
一样是逻辑上的概念,是Kafka实现单播和广播两种消息模型的手段。同一个topic的数据,会广播给不一样的group;同一个group中的worker,只有一个worker能拿到这个数据。换句话说,对于同一个topic,每一个group均可以拿到一样的全部数据,可是数据进入group后只能被其中的一个worker消费。group内的worker可使用多线程或多进程来实现,也能够将进程分散在多台机器上,worker的数量一般不超过partition的数量,且两者最好保持整数倍关系,由于Kafka在设计时假定了一个partition只能被一个worker消费(同一group内)。
要肯定Kafka的消息是否丢失或重复,从两个方面分析入手:消息发送和消息消费。
一、消息发送
Kafka消息发送有两种方式:同步(sync)和异步(async),默认是同步方式,可经过producer.type属性进行配置。Kafka经过配置request.required.acks属性来确认消息的生产:
0---表示不进行消息接收是否成功的确认;
1---表示当Leader接收成功时确认;
-1---表示Leader和Follower都接收成功时确认;
综上所述,有6种消息生产的状况,下面分状况来分析消息丢失的场景:
(1)acks=0,不和Kafka集群进行消息接收确认,则当网络异常、缓冲区满了等状况时,消息可能丢失;
(2)acks=一、同步模式下,只有Leader确认接收成功后但挂掉了,副本没有同步,数据可能丢失;
二、消息消费
Kafka消息消费有两个consumer接口,Low-level API和High-level API:
Low-level API:消费者本身维护offset等值,能够实现对Kafka的彻底控制;
High-level API:封装了对parition和offset的管理,使用简单;
若是使用高级接口High-level API,可能存在一个问题就是当消息消费者从集群中把消息取出来、并提交了新的消息offset值后,还没来得及消费就挂掉了,那么下次再消费时以前没消费成功的消息就“诡异”的消失了;
解决办法:
针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入Leader和Follower以后再确认消息发送成功;异步模式下,为防止缓冲区满,能够在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态;
针对消息重复:将消息的惟一标识保存到外部介质中,每次消费时判断是否处理过便可。
消息重复消费及解决参考:https://www.javazhiyin.com/22910.html
在 Kafka 中,生产者写入消息、消费者读取消息的操做都是与 leader 副本进行交互的,从 而实现的是一种主写主读的生产消费模型。
Kafka 并不支持主写从读,由于主写从读有 2 个很明 显的缺点:
(1)数据一致性问题。数据从主节点转到从节点必然会有一个延时的时间窗口,这个时间 窗口会致使主从节点之间的数据不一致。某一时刻,在主节点和从节点中 A 数据的值都为 X, 以后将主节点中 A 的值修改成 Y,那么在这个变动通知到从节点以前,应用读取从节点中的 A 数据的值并不为最新的 Y,由此便产生了数据不一致的问题。
(2)延时问题。相似 Redis 这种组件,数据从写入主节点到同步至从节点中的过程须要经 历网络→主节点内存→网络→从节点内存这几个阶段,整个过程会耗费必定的时间。而在 Kafka 中,主从同步会比 Redis 更加耗时,它须要经历网络→主节点内存→主节点磁盘→网络→从节 点内存→从节点磁盘这几个阶段。对延时敏感的应用而言,主写从读的功能并不太适用。
kafka每一个partition中的消息在写入时都是有序的,消费时,每一个partition只能被每个group中的一个消费者消费,保证了消费时也是有序的。
整个topic不保证有序。若是为了保证topic整个有序,那么将partition调整为1.
18.消费者提交消费位移时提交的是当前消费到的最新消息的offset仍是offset+1?
offset+1
Kafka并无使用JDK自带的Timer或者DelayQueue来实现延迟的功能,而是基于时间轮自定义了一个用于实现延迟功能的定时器(SystemTimer)。JDK的Timer和DelayQueue插入和删除操做的平均时间复杂度为O(nlog(n)),并不能知足Kafka的高性能要求,而基于时间轮能够将插入和删除操做的时间复杂度都降为O(1)。时间轮的应用并不是Kafka独有,其应用场景还有不少,在Netty、Akka、Quartz、Zookeeper等组件中都存在时间轮的踪迹。
底层使用数组实现,数组中的每一个元素能够存放一个TimerTaskList对象。TimerTaskList是一个环形双向链表,在其中的链表项TimerTaskEntry中封装了真正的定时任务TimerTask.
Kafka中究竟是怎么推动时间的呢?Kafka中的定时器借助了JDK中的DelayQueue来协助推动时间轮。具体作法是对于每一个使用到的TimerTaskList都会加入到DelayQueue中。Kafka中的TimingWheel专门用来执行插入和删除TimerTaskEntry的操做,而DelayQueue专门负责时间推动的任务。再试想一下,DelayQueue中的第一个超时任务列表的expiration为200ms,第二个超时任务为840ms,这里获取DelayQueue的队头只须要O(1)的时间复杂度。若是采用每秒定时推动,那么获取到第一个超时的任务列表时执行的200次推动中有199次属于“空推动”,而获取到第二个超时任务时有须要执行639次“空推动”,这样会无端空耗机器的性能资源,这里采用DelayQueue来辅助以少许空间换时间,从而作到了“精准推动”。Kafka中的定时器真可谓是“知人善用”,用TimingWheel作最擅长的任务添加和删除操做,而用DelayQueue作最擅长的时间推动工做,相辅相成。
参考:https://blog.csdn.net/u013256816/article/details/80697456
参考:https://blog.csdn.net/u013256816/article/details/89135417
https://blog.csdn.net/yanshu2012/article/details/54894629
————————————————
版权声明:本文为CSDN博主「徐周」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处连接及本声明。
原文连接:https://blog.csdn.net/qq_28900249/article/details/90346599