kafka是中间件 主要作用是为了削峰和解耦

akf原则
将中间件划分为xyz三个层次

x轴为主备,同样的数据会保存几份,主挂了,备可以同样的保证数据安全,具有副本的概念,同样会有主从,比如做出读写分离的方案。但是kafka只提供了主备,拒绝主从读写分离,这种会造成一致性的问题。kafka为了追求吞吐量,只在主可以做读写。
y轴根据业务划分服务,可以分为日志服务,购物服务等,这是逻辑上面的topic的概念,每个服务处理自己服务内部的一些事物。
z轴是分片处理,对于一个日志topic服务,可以通过hash等方式,每个分片去处理这个服务的一部分数据。分区内部是有序的,但是分区外部是无序的,kafka里面有offset去处理顺序的问题

kafka 数据完整备份还原 kafka主备_kafka 数据完整备份还原

kafka中有 几个定义 topic broker controller partition group producer consumer
topic 是逻辑上的定义,具体可以根据业务来划分,比如日志的topic
broker主要可以理解为一个个服务器,是实际的,一个日志的topic可以放在多个服务器上面

控制器controller作用
选举Leader和ISR
控制器从ZK的/brokers/topics加载一个topic所有分区的所有副本,从分区副本列表中选出一个作为该分区的leader,并将该分区对应所有副本置于ISR列表,其他分区类似;其他topic的所有分区也类似。
同步元数据信息包括broker和分区的元数据信息
控制器架子ZK的/brokers/ids以及上一个步骤得到的topic下各分区leader和ISR将这些元数据信息同步到集群每个broker。
而且通过下面所阐述的监控机制当有broker或者分区发生变更时及时更新到集群保证集群每一台broker缓存的是最新元数据。
broker加入的监听和处理
控制器启动时就起一个监视器监视ZK/brokers/ids/子节点。当存在broker启动加入集群后都会在ZK/brokers/ids/增加一个子节点brokerId,控制器的监视器发现这种变化后,控制器开始执行broker加入的相关流程并更新元数据信息到集群。
broker崩溃的监听与处理
控制器启动时就起一个监视器监视ZK/brokers/ids/子节点。当一个broker崩溃时,该broker与ZK的会话失效导致ZK会删除该子节点,控制器的监视器发现这种变化后,控制器开始执行broker删除的相关流程并更新元数据信息到集群。
topic变化监听与处理

partition是broker具体的分片,一个broker可以包裹着多个partition,可以当做主从,主要是为了分片安全,kafka中,副本不支持读写分离,否则会造成数据不一直等问题
producer是生产者,将数据丢入partition中,这时候可以是无序的,但是放入partition的时候,会变的有序化,consumer处理的时候也会有序,丢入是会以kv结构,k相同即会丢入同一partition中。
consumer是消费者,partition和consumer的对应关系是 1:1 1:N 绝对不能N:1
一个partition交给多个consumer,还可以保持有序,但是如果多个partition同时让一个consumer消费,可能顺序不一致,一个先后的数据不一致导致问题,比如同样的id,一次更新为3,一次更新为5,给了不同的consumer,不同的线程处理,顺序不对会出错
group是一个一个的组,比如es的组消费partition,mysql的组消费partition,一个partition中的数据,可以被多个不同的组进行消费

kafka 数据完整备份还原 kafka主备_kafka_02


在consumer消费的时候,kafka可以定义是同步消费还是异步的进行消费,如果是异步的话,比如设置5秒内异步,异步速度会快,但是如果异步的话,可能在消费的这5秒内数据会丢失,同步的话,如果没处理还顺序,先持久offset,后写入数据的话,可能会offset写入成功,数据写入失败

在以前旧版本中,kafka会和zookeeper共同使用,zookeeper是一个分布式协调工具,他记录了kafka中partition的偏移量,每次consumer消费拉取的时候,找到偏移量直接拉取数据即可,数据丢失也可以查看偏移量继续。现在最新的kafka版本,会有一个topic,里面记录了所有topic的偏移量,然后会写入到磁盘中。在producer这里也是有同样的问题,以前也是放在zookeeper中,查询那些broker可用,现在每个broker中自己维护,新的也可以不使用zookepeer。但是zookeeper作为分布式协调工具,还是一直需要的

在使用kafka的时候,会有一个admin-api的概念,使用人员去拿到所有的broker使用实例,决定去使用具体的broker

kafka 数据完整备份还原 kafka主备_分布式_03

kafka是采取的pull拉取的策略,每次consumer消费完,会拉取一批数据进行处理,通过offset去维护,省去频繁拉取
activitymq采取的是push partition推送的策略,这样的话可能会导致网卡打满,consumer来不及消费,就要给partition再传回去状态,确认等操作,更为繁杂

kafka在消费的时候可以使用单线程和多线程两种操作

单线程的优势就是简单方便没有什么问题,但是消费速度慢

多线程的话消费快,但是会衍生一些问题,比如partition的消费顺序性问题,一个partition里的数据,交给多个线程处理,线程具有隔离性,每个处理一部分的offset可能其中一个挂了,隔离导致写入不同的db或者redis中,无法处理,所以解决方法,可以将后面持久化的在内聚合一,比如多个线程写到不同的redis中,最后再落入同一个db库中,再将offset统一的刷到磁盘中,当其中的一个线程失败的时候,可以在同一个db中回滚,offset也会保存了之前的数据。这些分布式 中间件或者缓存的作用,瓶颈永远到在db这里,所以在前面处理了绝大数的业务问题,最后落入到db的流量是稳定可控的,保证了系统的稳定性

kafka 数据完整备份还原 kafka主备_java_04


kafka 在消费的时候,可以分为分区,分消息消费,分消息是安全的,数据可以保证安全,但是粒度太细了,效率太低,分区的话,可以按照批次拉取消息,然后多线程处理数据,但是对于分区提交offset,还是有丢失消息的风险,只能去权衡。

kafka快的原因
写入到partition的时候,是追加的方式,顺序的,所以他写入到磁盘,是顺序写的方式,远远大于磁盘随机写的的方式。顺序写的话,通过磁盘存取的数据的index,index可存取offset和timestamp,通过偏移量直接找到数据

sendfile 0拷贝,没有的话,需要从pagecache拷贝到程序,在用程序拷贝到pagecache,多拷贝了两次,有了之后,直接从内核进行查询数据,省去了拷贝,为什么kafka可以这样,因为他只是对数据进行了转移,并没有对数据进行操作

kafka 数据完整备份还原 kafka主备_java_05


kafka的可靠性

ack 分为 0 1 -1

0:消息发出就结束,不管结果如何,极有可能会丢数据

1:是在发送到pagecache的时候,再进行确认,默认情况下,只关注leader里面的信息,从节点不关注

-1是在分布式的情况下使用,最严苛,所有的副本都要同步,一致,OSR有默认延时时间(10S),一个数据发到partition中,如果在10s内同步完成,那么所有节点都是ISR,如果有一个没有同步完成,那么就是OSR,已经被踢出了节点

kafka 数据完整备份还原 kafka主备_kafka_06


HW:发送到主节点,但是还没同步到副本之前的所有的数据,这个之前的数据都是安全的

LEO:发送到主节点的所有数据,这会有数据不一致的情况

kafka 数据完整备份还原 kafka主备_kafka 数据完整备份还原_07

kafka 数据完整备份还原 kafka主备_kafka_08