简介

这篇文章介绍Kafka的Broker工作流程,包括其中控制器的选举过程;kafka副本的leader选举以及leader和follower故障流程;简单讲述了生产环境中如何调整分区副本;kafka的文件存储机制以及日志文件的删除策略;最后了解下kafka中使用的页缓冲和零拷贝的原理。

一. 工作流程

这一部分大体了解下kafka Broker的工作流程,看一下zookeeper在kafka broker工作中发挥的作用,那些重要数据在zookeeper中存储。

1.1. zookeeper作用

zookeeper在kafka中扮演了重要的角色,kafka使用zookeeper进行元数据管理,保存broker注册信息,包括主题(Topic)、分区(Partition)信息等,选择分区leader,在低版本kafka消费者的offset信息也会保存在zookeeper中。如图使用zookeeper客户端PrettyZoo查看内容如下:

下面具体看一下某些重要节点的作用。

Broker节点

kafka在zookeeper上存储的brokers节点信息如下:

其中/brokers/ids/[0...n]:是使用临时节点存储在线的是各个服务节点的信息,当下线后自动删除;

{"listener_security_protocol_map" : {"PLAINTEXT" : "PLAINTEXT"},"endpoints" : [ "PLAINTEXT://192.168.31.32:9091" ],"jmx_port" : -1,"features" : { },"host" : "192.168.31.32","timestamp" : "1646557610504","port" : 9091,"version" : 5
}

/brokers/seqid:辅助生成的brokerId,当用户没有配置broker.id时,ZK会自动生成一个全局唯一的id。

/brokers/topics/{topicName}:持久化数据节点存储topic的分区副本分配信息。在/brokers/topics/{topicName}//partitions/0/state中记录了leaderisr队列的内容。

{"controller_epoch" : 5,"leader" : 3,"version" : 1,"leader_epoch" : 4,"isr" : [ 2, 3 ]
}

其中_transaction_offsets,是事务存储的节点。

Consumers节点

0.9版本之前用于保存offset信息,0.9版本之后offset存储在kafka主题中。

Controller和/Controller_epoch节点

/controller:保存控制器(broker的leader, 这里的leader要和副本的leader区分开,这里的leader是kafka集群中所有broker的leader)对应的brokerId信息等

/controller_epoch:这里用来解决脑裂问题,存放的是一个整形值(纪元编号,也称为隔离令牌)
其他的节点

/config/topics:存储动态修改主题级别的配置信息

/config/clients:存储动态修改客户端级别的配置信息

/config/changes:动态修改配置时存储相应的信息

/admin/delete_topics:在对主题进行删除操作时保存待删除主题的信息

/isr_change_notification:保存Kafka副本ISR列表发生变化时通知的相应路径

1.2. kafka broker的leader选举

1.2.1 leader选举的种类

这里需要先明确一个概念leader选举,因为kafka中涉及多处选举机制,容易搞混,kafka由三个方面会涉及到选举:

  • broker(控制器)选leader
  • 分区多副本选leader
  • 消费者选leader

本文会讲述Broker选leader和分区选leader的过程,后面将消费者的时候在说消费者选leader的过程。

1.2.2 Broker选举过程

在kafka集群中由很多的broker(也叫做控制器),但是他们之间需要选举出一个leader,其他的都是follower。broker的leader有很重要的作用,诸如:创建、删除主题、增加分区并分配leader分区;集群broker管理,包括新增、关闭和故障处理;分区重分配(auto.leader.rebalance.enable=true,后面会介绍);分区leader选举。

下面看一下Broker的leader选举过程和故障处理

如图可以大概描述如下:

  1. 集群中第一个启动的broker会在zookeeper中创建临时节点/controller来让自己成为控制器,当其他的broker启动也会在zookeeper中创建临时节点/controller,但是会发现节点已经存在,此时会受到一个异常,此时就会在zookeeper中创建一个watch对象,方便这些broker接受leader的变更消息;
  2. 如果主leader因为网络问题与zookeeper断开连接或者发生异常退出了,其他的broker就可以通watch接收到控制器的变更通知,开始尝试去创建临时节点/controller,如果有一个broker创建成功了,就和上面说的一样,其他的broker也会收到异常通知,此时就说明集群中broker的leader已经确定,其他的broker只能创建watch对象了
  3. 集群中broker的leader发生异常退出,在选举出新的leader之后,会检测这个异常的broker上面是否有分区副本的leader,如果有就是发起分区的leader选举,选出新额分区leader,然后更新ISR队列数据

1.2.3. 脑裂问题

什么是脑裂

说起脑裂,那么什么是脑裂,出字面意思上理解,就是一分为二有了多个脑袋。在分布式系统的高可用情况下很容易出现这种问题,简单来说就是因为网络或者其他的原因导致leader出现假死状态,此时会触发leader选举,这样就会出现两个leader进而产生一系列问题。

kafka broker的leader相当于整个kafka集群的master,负责很多重要的工作(上文有,此处不再累述),broker是通过抢占的方式在zookeeper中注册临时节点/controller来时实现的,先到先得。由于zookeeper的临时节点的有效性是通过session来判断的,若在session timeout时间内,controller所在的broker断开,就会触发重新选举。

那么发生脑裂又会什么影响?

从上文可以知道,broker的leader主要是用于管理主题的,那些发生脑裂之后创建主题、增加分区的操作都会报错;但是现有的主题的读写是不影响的,这是因为读写是获取分区的元数据在任意一个broker中有可以拿到。

发生脑裂的情况?

broker的leader进行GC的时间超过zookeeper session timeout;broker的leader发生网络故障。

kafka的解决方案

为了解决Controller脑裂问题,zookeeper中有一个持久节点/controller_epoch,存放的是一个整形值的epoch number(纪元编号,也称为隔离令牌),集群中每选举一次控制器,就会通过Zookeeper创建一个数值更大的epoch number,如果有broker收到比这个epoch数值小的数据,就会忽略消息。

1.2.4. 羊群效应

在早期的kafka版本中,如果宕机的那个Broker上的Partition比较多, 会造成多个Watch被触发,造成集群内大量的调整,导致大量网络阻塞,这种羊群效应会导致zookeeper过载的隐患。之后kafka有一个controller的概念(也就是broker的leader)来对分区副本的状态进行管理,当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。

在使用zookeeper的分布式中,这种脑裂和羊群效应都是不可避免的。

1.3. 触发leader选举

现阶段的kakfa集群中,只需要broker的leader在zookeeper去注册相应的监听器,其他的broker很少去监听zookeeper的数据变化,但是每个broker还是需要对/controller进行监听;当/controller节点发生数据变化的时候,每个broker都会更新自身内存中保存的activeControllerId

/controller节点被删除时,集群中的broker会进行选举,如果broker在节点被删除前是控制器的话,在选举前还需要有一个下线的操作(关闭相应的资源,比如关闭状态机、注销相应的监听器等)。如果有特殊需要,可以手动删除/controller节点来触发新一轮的选举。当然关闭控制器所对应的broker以及手动向/controller节点写入新的brokerid的所对应的数据同样可以触发新一轮的选举。

二. leader和follower

2.1. kafka的副本

kafka副本的作用就是提高数据的可靠性,系统默认副本数量是1,生产环境一般配置数量是2个,保证数据可靠性;否则副本太多会增加磁盘的存储空间,增加网络上的数据传输,降低效率。

kafka的副本分为leaderfollower,其中leader数据读写,follower只负责数据同步。关于副本有下面三个概念:

  • ISR:表示和leader保持同步的follower集合
  • OSR:表示followerleader同步延时过多的副本
  • AR:分区中所有副本统称为AR(Assigned Repllicas),AR = ISR + OSR,一个分区的AR集合在分配的时候就被指定,并且只要不发生重分配的情况,集合内部副本的顺序是保持不变的,而分区的ISR集合中副本的顺序可能会改变。

这里ISR在上一篇文章中也介绍了,如果follower长时间没有向leader发送通信请求或者同步数据,这个follower将会被提出ISR队列,这个时间阈值是由replica.lag.time.max.ms参数设置的,默认是30s

如果leader发送故障,就会从ISR中选举出新的leader

2.2. leader选举流程

分区leader的选举由kafkabroker leader(后面文章会以controller代替broker leader的描述)负责具体实施。

当创建分区(创建主题或增加分区都有创建分区的动作)或分区上线(比如分区中原先的leader副本下线,此时分区需要选举一个新的leader上线来对外提供服务)的时候都需要leader选举。选举的时候将会从AR集合中副本的顺序查找第一个存活的副本,并且要保证这个副本在ISR队列中。

另外当分区发生重分配的情况(下面会讲)也是需要执行leader选举,此时从重分配的AR列表中找到第一个存活的副本,且这个副本在目前的ISR队列中。

再有就是当某一个borker节点关闭的时候,位于这个节点上的leader副本都会下线,所以与此对应的分区需要执行leader的选举。此时将会从AR列表中找到第一个存活的副本,且这个副本在目前的ISR列表中,另外还要确保这个副本不处于正在被关闭的节点上。

2.3. Unclean leader选举

kafka还提供了一个参数配置:unclean.leader.election.enable,默认是true,参数规定是否允许非ISR的副本成为leader,如果设置为true,当ISR队列是空,ISR为空说明leader和follower都挂掉了,此时将选择那些不在ISR队列中的副本选择为新的leader,这写副本的消息可能远远落后于leader,所以可能会造成丢失数据的风险。生产环境中建议关闭这个参数,设置为false。

2.4. leader和follower故障流程

2.4.1. LEO和HW

在生产环境中可能会出现follower和leader出现故障,那么Kafka是如何处理这些故障的呢?下面简单介绍一下流程,在讲流程之前,先了解一下LEO和HW这两个概念。

  • LEO(log end offset):每个副本的最后一个offset,LEO就是最新的offset+1
  • HW(high watermark):所有副本中最小的LEO;

LEO和HW的概念产生其实是因为,数据先写入leader,然后follower拉取数据进行同步,但是同步速度不一致,会出现先后问题,那个这是后副本的offset是不一样的,此时kafka会使用所有副本中最小的offset+1,也是HW。

2.4.2. follower故障流程

此时假如Broker1上的follower发生故障会出现什么情况呢?首先Broker1上的follower会被踢出ISR队列中,但是leader和其他的follower都还是会继续接受数据,并不会收到影响,对应的LEO和HW都会往后移动;如果此时发生故障的Broker1上的follower恢复后,此时Broker1上的follower会读取本地磁盘记录的上次HW位置,并将log文件中高于HW的部分截取掉,从HW开始向Leader进行同步;直到Broker1上的follower的LEO大于等于该分区的HW,此时说明这个follower追上了leader,就会将其重新加入ISR队列中。

2.4.3. leader故障流程

上面了解了follower故障的情况,那么如果leader发生故障呢?接着上面的图片来看,首先如果Broker0上的leader发生故障之后,也是一样会先从ISR队列中被踢出,然后从ISR中选出一个新的Leader来;此时为了保证多个副本之间的数据一致性,其他的follower会先将各自的log文件中高于HW的部分截取掉,然后从新的leader同步数据(由此可知这只能保证副本之间数据一致性,并不能保证数据不丢失或者不重复)。

2.5. 分区副本的调整

从上一篇文章知道在kafka集群中分区的副本分布是做到尽量的均匀的分配的到各个节点中,以此来保证每台机器的读写吞吐量是均匀的,但是出现某些broker宕机,会导致leader都集中在几台broker中,造成读写压力过大,并且就算恢复了宕机的broker,原来的leader也会变成follower并无法分担压力,造成集群负载不均衡。

2.5.1 Leader Partition自动平衡

为了解决上述问题kafka出现了自动平衡的机制。kafka提供了下面几个参数进行控制:

  • auto.leader.rebalance.enable:自动leader parition平衡,默认是true
  • leader.imbalance.per.broker.percentage:每个broker允许的不平衡的leader的比率,默认是10%,如果超过这个值,控制器将会触发leader的平衡
  • leader.imbalance.check.interval.seconds:检查leader负载是否平衡的时间间隔,默认是300秒

但是在生产环境中是不开启这个自动平衡,因为触发leader partition的自动平衡会损耗性能,或者可以将触发自动平和的参数leader.imbalance.per.broker.percentage的值调大点。

2.5.2 手动调整副本分配

会导致服务器的性能不一样,服务器磁盘不足或者其他的原因需要将性能好,磁盘空间大的服务器节点多存放副本,那么在生产环境中如何去手动调整分区副本的分布比例呢?

下面先创建一个测试的主题:

下面演示一下如何更新分区间的副本配比,首先创建一个assign-replicas.json的文件,内容如下:

{"version": 1,"partitions": [{"topic": "test-assign", "partition": 0, "replicas": [1, 2]},{"topic": "test-assign", "partition": 1, "replicas": [1, 2]},{"topic": "test-assign", "partition": 2, "replicas": [1, 2]}]
}


接着执行命令:

bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file assign-replicas.json --executebin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file assign-replicas.json --verify


最后看一个这个主题的副本分布情况:

bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic test-assign

2.5.3. 增加副本因子

生产环境中由于某个主题的重要等级需要提升,考虑增加副本。下面演示下如何增加副本

创建一个Json文件:add-relication-factor.json

{"version": 1,"partitions": [{"topic": "test-assign", "partition": 0, "replicas": [3, 2, 1]},{"topic": "test-assign", "partition": 1, "replicas": [1, 3, 2]},{"topic": "test-assign", "partition": 2, "replicas": [2, 1, 2]}]
}

执行副本存储计划:

bin/kafka-reassign-partitions.sh --zookeeper localhost:2181 --reassignment-json-file add-relicati
on-factor.json --execute

三. 文件存储机制

3.1. 存储结构

在kafka中主题(Topic)是一个逻辑上的概念,分区(partition)是物理上的存在的。每个partition对应一个log文件,该log文件中存储的就是Producer生产的数据。Producer生产的数据会被不断追加到该log文件末端。为防止log文件过大导致数据定位效率低下,kafka采用了分片和索引机制,将每个partition分为多个segment,每个segment包括.index文件、.log文件和.timeindex等文件。这些文件位于文件夹下,该文件命名规则为:topic名称+分区号。

上图对应的是某一个主题的文件结构图,一个主题是对应多个分区,一个分区对应一个日志(Log),如果只通过一个log文件记录的话,这就会导致日志过大,导致数据定位效率低下,所以kafka采用了分片和索引机制。

kafka引入了日志分段(LogSegment),将日志分为多个较小的文件;Log会存储在配置的log.dirs文件夹内,而每个LogSegment由三个文件组成:偏移量索引文件(.index后缀)、时间戳的索引文件(.timeindex后缀)和消息数据文件(.log后缀);注意这里面还有一个leader-epoch-checkpoint文件,保存的是Leader Epoch的值(解决副本数据一致性需要)。

目录结构如下:

├── long-topic-0├── 00000000000000000000.index├── 00000000000000000000.log├── 00000000000000000000.timeindex├── 00000000000000000113.index├── 00000000000000000113.log├── 00000000000000000113.timeindex└── leader-epoch-checkpoint

分段文件名规则:分区的第一个segment是从0开始的,后续每个segment文件名为上一个segment文件最后一条消息的offsetofsset的数值最大为64位(long类型),20位数字字符长度,没有数字用0填充。

log文件默认写满1G后,会进行log rolling形成一个新的分段(segment)来记录消息,这里面的分段大小取决于:log.segment.bytes参数决定。

indextimeindex文件在刚使用时会分配10M的大小,当进行log rolling后,它会修剪为实际的大小,所以看到前几个索引文件的大小,只有几百K。

查看log文件内容的方法:

./bin/kafka-run-class.sh kafka.tools.DumpLogSegments --files 00000000000000000000.log  --print-data-log

3.2. log、timeindex和index文件的对应关系

log文件写入4k(这里可以通过log.index.interval.bytes设置)数据,就会写入一条索引信息到index文件中,这样的index索引文件就是一个稀疏索引,它并不会每条日志都建立索引信息。

log日志文件是顺序写入,大体上由message+实际offset+position组成,而索引文件的数据结构则是由相对offset(4byte)+position(4byte)组成。

kafka查询一条offset对应实际消息时,可以通过index进行二分查找,获取最近的低位offset,然后从低位offset对应的position开始,从实际的log文件中开始往后查找对应的消息。

时间戳索引文件,它的作用是可以查询某一个时间段内的消息,它的数据结构是:时间戳(8byte)+ 相对offset(4byte),如果要使用这个索引文件,先要通过时间范围找到对应的offset,然后再去找对应的index文件找到position信息,最后在遍历log文件,这个过程也是需要用到index索引文件的。

3.3. 文件清理策略

从上面知道消息数据会被不断追加到该log文件末端,这就会面临一个问题,就是log文件越来越大,磁盘空间是一定的,那么此时kakfa可以通过配置log.cleanup.policy参数,默认是delete(删除,按照一定的保留策略直接删除不符合条件的日志分段LogSegment),另一个是compact(压缩,日志压缩就是根据key来保留最后一条消息)两种。

3.3.1. delete删除

kafka中默认的日志保存时间为7天,可以通过调整如下参数修改保存时间。

  • log.retention.hours:最低优先级小时,默认7天
  • log.retention.minutes:分钟
  • log.retention.ms:最高优先级毫秒
  • log.retention.check.interval.ms:负责设置检查周期,默认5分钟
  • file.delete.delay.ms:延迟执行删除时间
  • log.retention.bytes:当设置为-1时表示运行保留日志最大值(相当于关闭);当设置为1G时,表示日志文件最大值

具体的保留日志策略有三种:

  • 基于时间策略
    日志删除任务会周期检查当前日志文件中是否有保留时间超过设定的阈值来寻找可删除的日志段文件集合;这里需要注意log.retention参数的优先级:log.retention.ms > log.retention.minutes > log.retention.hours,默认只会配置log.retention.hours参数,值为168即为7天。
    删除过期的日志段文件,并不是简单的根据日志段文件的修改时间计算,而是要根据该日志段中最大的时间戳来计算的,首先要查询该日志分段所对应的时间戳索引文件,查找该时间戳索引文件的最后一条索引数据,如果时间戳大于0就取值,否则才会使用最近修改时间。
    在删除的时候先从Log对象所维护的日志段的跳跃表中移除要删除的日志段,用来确保已经没有线程来读取这些日志段;接着将日志段所对应的所有文件,包括索引文件都添加上.deleted的后缀;最后交给一个以delete-file命名的延迟任务来删除这些以.deleted为后缀的文件,默认是1分钟执行一次,可以通过file.delete.delay.ms来配置。
  • 基于日志大小策略
    日志删除任务会周期性检查当前日志大小是否超过设定的阈值(log.retention.bytes,默认是-1,表示无穷大),来寻找可删除的日志段文件集合。
  • 基于日志起始偏移量
    该策略判断依据是日志段的下一个日志段的起始偏移量 baseOffset是否小于等于 logStartOffset,如果是,则可以删除此日志分段。
    这里说一下logStartOffset,一般情况下,日志文件的起始偏移量 logStartOffset等于第一个日志分段的 baseOffset,但这并不是绝对的,logStartOffset的值可以通过 DeleteRecordsRequest请求、使用 kafka-delete-records.sh 脚本、日志的清理和截断等操作进行修改。

3.3.2. compact压缩

日志压缩对于有相同key的不同value值,只保留最后一个版本。如果应用只关心 key对应的最新 value值,则可以开启 Kafka相应的日志清理功能,Kafka会定期将相同 key的消息进行合并,只保留最新的 value值。

3.4. kafka高效读写原因

kafka之所以可以快速读写的原因如下:

  1. kafka是分布式集群,采用分区方式,并行操作
  2. 读取数据采用稀疏索引,可以快速定位消费数据
  3. 顺序写磁盘
  4. 页缓冲和零拷贝

四. 页缓冲和零拷贝

4.1. 页缓冲

在 Kafka 中,大量使用了 PageCache, 这也是 Kafka 能实现高吞吐的重要因素之一。

首先看一下读操作,当一个进程要去读取磁盘上的文件内容时,操作系统会先查看要读取的数据页是否缓冲在PageCache 中,如果存在则直接返回要读取的数据,这就减少了对于磁盘 I/O的 操作;但是如果没有查到,操作系统会向磁盘发起读取请求并将读取的数据页存入 PageCache 中,之后再将数据返回给进程,就和使用redis缓冲是一个道理。

接着写操作和读操作是一样的,如果一个进程需要将数据写入磁盘,操作系统会检查数据页是否在PageCache 中已经存在,如果不存在就在 PageCache中添加相应的数据页,接着将数据写入对应的数据页。另外被修改过后的数据页也就变成了脏页,操作系统会在适当时间将脏页中的数据写入磁盘,以保持数据的一致性。

4.2. 零拷贝

零拷贝并不是不需要拷贝,而是减少不必要的拷贝次数,通常使用在IO读写过程中。常规应用程序IO过程如下图,会经过四次拷贝:

  • 数据从磁盘经过DMA到内核的Read Buffer;
  • 内核态的Read Buffer到用户态应用层的Buffer
  • 用户态的Buffer到内核态的Socket Buffer
  • Socket Buffer到网卡的NIC Buffer

从上面的流程可以知道内核态和用户态之间的拷贝相当于执行两次无用的操作,之间切换也会花费很多资源;当数据从磁盘经过DMA 拷贝到内核缓存(页缓存)后,为了减少CPU拷贝的性能损耗,操作系统会将该内核缓存与用户层进行共享,减少一次CPU copy过程,同时用户层的读写也会直接访问该共享存储,本身由用户层到Socket缓存的数据拷贝过程也变成了从 内核到内核的CPU拷贝过程,更加的快速,这就是零拷贝,IO流程如下图。

Java的JDK NIO中方法transferTo()方法就能够实现零拷贝操作,这个实现依赖于操作系统底层的sendFile()实现的:

public void transferTo(long position, long count, WritableByteChannel target);

底层调用的是:

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

但是需要注意零拷贝和系统底层有很大的关系,所以是否可以进行零拷贝的系统调用的看具体的操作系统是否实现。

下面看一下Java nio的零拷贝例子:

import java.io.*;
import java.nio.channels.FileChannel;public class ZeroCopy {public static void main(String[] args) {File source = new File("G:/source.zip");File target = new File("G:/target.zip");NioZeroCopy(source, target);}public static void NioZeroCopy(File source, File target) {try (FileChannel sourceChannel = new FileInputStream(source).getChannel();FileChannel targetChannel = new FileOutputStream(target).getChannel();) {for(long count = sourceChannel.size(); count > 0;) {long transfer = sourceChannel.transferTo(sourceChannel.position(), count, targetChannel);sourceChannel.position(sourceChannel.position() + transfer);count -= transfer;}} catch (IOException e) {System.out.println("异常:" + e.getMessage());}}}

Kafka知识总结之Broker原理总结相关推荐

  1. 三万字 | Kafka 知识体系保姆级教程宝典

    本文目录: 一.消息队列     Apache Pulsar     Pulsar 与 Kafka 对比 二.Kafka基础 三.Kafka架构及组件 四.Kafka集群操作 五.Kafka的Java ...

  2. 四万字32图,Kafka知识体系保姆级教程宝典

    目录 一.消息队列 1. 消息队列的介绍 2. 消息队列的应用场景 3. 消息队列的两种模式 4. 常用的消息队列介绍 5. Pulsar 6. Kafka与Pulsar对比 7. 其他消息队列与Ka ...

  3. Kafka知识体系总结【附大厂高频面试题】

    目录 0- 知识图谱 1- 消息队列 1.1- 消息队列的介绍 1.2- 消息队列的应用场景 1.3- 消息队列的两种模式 1.3.1- 点对点模式 1.3.2- 发布/订阅模式 1.4- 常用的消息 ...

  4. Kafka知识总结之消费者简单使用

    本文简述 这篇文件主要是讲kafka消费者相关使用,诸如,offset的使用,消费者的相关配置,多线程消费模式和springboot整合.至于这些里面涉及到原理等相关深入的知识会放到下一篇文件kafk ...

  5. Kafka知识总结及面试题

    文章目录 概念 Kafka基础概念 命令行 Kafka 数据存储设计 kafka在zookeeper中存储结构 生产者 生产者设计 消费者 消费者设计 面试题 kafka设计 请说明什么是Apache ...

  6. 2021年大数据Kafka(九):kafka消息存储及查询机制原理

    全网最详细的大数据Kafka文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 kafka消息存储及查询机制原理 一.Kafka数据存储机制 ...

  7. Kafka核心设计与实践原理总结:进阶篇

    作者:未完成交响曲,资深Java工程师!目前在某一线互联网公司任职,架构师社区合伙人! kafka作为当前热门的分布式消息队列,具有高性能.持久化.多副本备份.横向扩展能力.我学习了<深入理解K ...

  8. Stream Processing: Apache Kafka的Exactly-once的定义 原理和实现

    2018年,Apache Kafka以一种特殊的设计和方法实现了强语义的exactly-once和事务性.热泪盈眶啊! 这篇文章将讲解kafka中exactly-once和事务操作的原理,具体为 (1 ...

  9. 《深入理解Kafka:核心设计与实践原理》笔误及改进记录

    2019年2月下旬笔者的有一本新书--<深入理解Kafka:核心设计与实践原理>上架,延续上一本<RabbitMQ实战指南>的惯例,本篇博文用来记录现在发现的一些笔误,一是给购 ...

最新文章

  1. 为什么二级菜单会被挡住_二级建造师为什么这么难考?2021年二建考试也会很难吗?...
  2. 低版本系统兼容的ActionBar(四)添加Tab+添加自定义的Tab视图+Fragment
  3. [SOJ] DAG?
  4. kafka partition分配_Kafka架构原理,也就这么回事
  5. 云服务器登陆修改文件,香港云服务器使用注意事项(windows版)
  6. Qt工作笔记-两种方法从容器中筛选出父类和子类(继承法、typeid法)
  7. 我的世界java版地牢种子_我的世界手机版地牢种子代码汇总
  8. Java从入门到精通 第5章 数据类型
  9. Raki的统计学习方法笔记0x1章:统计学习及监督学习概论
  10. 浅析机关单位人力资源内部控制
  11. 使用Python找丑数
  12. 疑难杂症之虚拟机安装(一) 安装系统黑屏问题
  13. 《智慧工地单点解析系列(一)—— 劳务实名制》
  14. MybatisPlus中乐观锁的配置
  15. TTL、Ping包最大字节数、网络时延、抖动、丢包率,看完瞬间变大神!
  16. 电磁波极化原理及仿真
  17. C语言 正序分解整数
  18. 无胁科技-TVD每日漏洞情报-2022-12-15
  19. 网站为什么只能重置密码,而不能真正的“找回密码”
  20. 华为HCIP—Datacom(821新增)

热门文章

  1. 【Python】实现图片切成patch,以及有间隙的拼接代码
  2. 【转载】C++的就业状况与方案。
  3. Echarts系列之怎么让文字纵向显示
  4. 虚拟主机的服务器配置在哪,配置Apache服务器下的虚拟主机设置有什么要求?景安...
  5. 展会圆满收官 柏克利招商峰会业绩闪亮
  6. KVG制作-【Arduino指纹解锁 智能家居系列-01】DIY自制的智能门禁,AS608指纹解锁+红外线遥控解锁。附演示视频。
  7. 鸿蒙os系统支持oppo手机吗,华为霸气官宣!毫无保留的开放鸿蒙OS系统:所有国产手机都能使用...
  8. VHDL语言Process
  9. Google Earth Engine(GEE)——Output of image computation is too large (29 bands for 828828 pixels = 96.
  10. 达人评测 天玑1100和骁龙888哪个处理器好