原文参考:https://www.jianshu.com/p/ff7dd5b349f1
一、CAP理论概述
1、cap
分布式系统中,一致性、可用性、分区容错性不可兼得,最多只可同时满足两个。
C(Consistency 一致性):
* A read is guaranteed to return the most recent write for a given client.
* 在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
* 注:在一个节点上修改数据,在另一个节点上能读取到修改后的数据
* 某个节点的数据更新结果对后面通过其它节点的读操作可见
* 立即可见,称为强一致性
* 部分或者全部感知不到该更新,称为弱一致性
* 在一段时间(通常该时间不固定)后,一定可以感知该更新,称为最终一致性
A(Availability 可用性):
* A non-failing node will return a reasonable response within a reasonable amount of time(no error or timeout)
* 在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
* 注:在用户可容忍的范围内返回数据
* 一个没有发生故障的节点必须在有限的时间内返回合理的结果
* Vs数据库的HA:一个节点宕机,其它节点仍然可用
P(Partition Tolerance 分区容错性):
* The system will continue to function when network partitions occur.
* 以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
* 注:一个分布式集群,分成多个小的集群,小的集群内部可相互通信,对于用户透明
* 部分节点宕机或者无法与其它节点通信时,各分区间还可保持分布式系统的功能
简单来说:
C:不管访问集群中的哪个节点,返回的结果都是一样的。
A:集群中的一个或者某个节点挂掉,仍然可以提供服务。
P:集群内部出现通信故障,服务A的数据没法同步到其他节点时,客户端访问服务A,服务A仍然能返回未同步到其他节点的数据。
二、kafka ISR实现CAP中可用性与数据一致性的动态平衡
1、kafka ISR实现CAP中可用性与数据一致性的动态平衡
Kafka的数据复制方案接近于Master-Slave,不同的是,Kafka既不是完全的同步复制,也不是完全的一步复制,而是基于ISR的动态复制方案。
ISR,In-Sync Replica,每个Partition的Leader都会维护这样一个列表,其中包含了所有与之同步的Replica。每次写入数据时
,只有ISR中的所有Replica都复制完,Leader才会将这条数据置为Commit,它才能被Consumer消费。
与同步复制不同的是,这个ISR是由Leader动态维护的,如果Follower不能紧跟上Leader,它将被Leader从ISR中移除,待它
重新“跟上”Leader后,会被Leader再次加入ISR中。每次改变ISR后,Leader会将最新ISR持久化到Zookeeper中。
那么如何判断Follower是否“跟上”Leader?
如果Follower在replica.lag.time.max.ms时间内未向Leader发送Fetch请求(数据复制请求),则Leader将其从ISR中移除。
2、为什么使用ISR方案
Leader可移除不能及时与之同步的Follower,所以与同步复制相比可以避免最慢的Follower拖慢整体速度,提高系统可用性。
从Consumer角度来看,ISR中所有Replica都始终处于同步状态,从而与异步复制相比提高了数据一致性。
3、ISR相关配置
Broker的min.insync.replicas参数制定了Broker所要求的ISR最小长度,默认值为1.极限情况下ISR可以只包含Leader,但此时如果Leader宕机,则该Partition不可用,
可用性不可保证。
只有被ISR中所有Replica同步的消息才被commit,但是Producer在写数据时,Leader不需要ISR中所有Replica同步该数据才确认收到数据。
Producer可以通过acks参数指定最少需要多少个Replica确认收到该消息才视为该消息发送成功。acks默认值为1,即Leader收到该消息后立即告诉Producer收到该消息,
此时如果在ISR中的消息复制完该消息前Leader宕机,那该条消息会丢失。推荐做法是:将acks设置为all或-1,此时只有ISR中的所有Replica都收到该数据(也及消息被commit),
Leader才会告诉Producer该消息发送成功,这样保证了不会有未知的数据丢失。
三、kafka的高性能
顺序写磁盘
将写磁盘的过程变为顺序写,可极大提高对磁盘的利用率。Consumer通过offset顺序消费这些数据,且不删除已经消费的数据,从而避免随机写磁盘的过程。
Kafka删除旧数据的方式是删除整个Segment对应的log文件和整个index文件,而不是删除部分内容。
充分利用Page Cache
Page Cache的优点:
I/O Scheduler会将连续的小块写组装成大块的物理写从而提高性能。
I/O Scheduler会尝试将一些写操作重新按顺序排好,从而减少磁头移动时间。
充分利用所有空闲内存(非JVM内存)。
读操作可以直接在Page Cache内进行。如果消费和生产速度相当,甚至不需要通过物理磁盘交换数据。
如果进程重启,JVM内的Cache会失效,但Page Cache仍然可用。
零拷贝
Kafka中存在大量网络数据持久化到磁盘(Producer到Broker)和磁盘文件通过网络发送(Broker到Consumer)的过程,
这个过程中,传统模式下要进行数据的四次拷贝,但是Kafka通过零拷贝技术将其减为了一次,大大增加了效率,
零拷贝技术:
传统的读取文件数据并发送到网络的步骤如下:
(1)操作系统将数据从磁盘文件中读取到内核空间的页面缓存;
(2)应用程序将数据从内核空间读入用户空间缓冲区;
(3)应用程序将读到数据写回内核空间并放入socket缓冲区;
(4)操作系统将数据从socket缓冲区复制到网卡接口,此时数据才能通过网络发送。
“零拷贝技术”只用将磁盘文件的数据复制到页面缓存中一次,然后将数据从页面缓存直接发送到网络中(发送给不同的订阅者时,都可以使用同一个页面缓存),避免了重复复制操作。
如果有10个消费者,传统方式下,数据复制次数为4*10=40次,而使用“零拷贝技术”只需要1+10=11次,一次为从磁盘复制到页面缓存,10次表示10个消费者各自读取一次页面缓存。
减少网络开销
批处理:
批处理减少了网络传输的overhead,又提高了写磁盘的效率。
Kafka的API做中,从send接口来看,一次只能发送一个ProducerRecord,但是send方法并不是立即将消息发送出去,而是通过batch.size和linger.ms控制实际发送频率,
从而实现批量发送。
数据压缩降低网络负载
高效的序列化方式