向音乐致敬:盘点vivo三年的极致Hi-Fi之路
06-17
在日常工作中,团队一般使用腾讯云CKafka作为消息队列。 CKafka提供了开箱即用的高可靠消息队列能力,让我们在日常生活中可以放心使用,减少运维投入。
但即便如此,我们仍然需要学习 Kafka 的一些基本概念和功能,以便我们能够在实际应用中高效、高质量地充分利用 Kafka 的能力。基本业务概念本节主要讲解在软件业务层面,我们会接触到Kafka中的消息Message 这个概念。
对于消息队列系统来说,最基本的自然就是“消息”。在Kafka中,“消息”就是Message,它是Kafka中数据传输的基本单位。
多条消息会批量写入Kafka。这同一批消息称为一组消息。
生产者和消费者 生产者和消费者的概念很容易理解:生成消息的服务称为“生产者”Producer,也称为“发布者”Publisher 或 Writer。 需要获取消息的服务称为“Consumer”,也称为“订阅者”SubScriber 或 Reader。
主题和分区 在 Kafka 中,并非所有消息都有队列。 Kafka消息按照Topic进行分类。
一个Topic可以分为多个“分区”Partition。 这里需要注意的是,同一个分区内,消息的顺序是可以保证的。
也就是说:如果消息A早于消息B到达分区,那么消费者获取消息时,必须先获取消息A,再获取消息B。 但是,如果有多个分区,则顺序无法保证消息。
例如,当一个消费者监听多个分区时,无法保证消息A和消息B被读取的时间。 既然如此,分区还有什么用呢?事实上,Partition就是用来做负载均衡的。
当消费者向某个主题发送消息时,Kafka 默认会尽可能均匀地将消息分发到多个分区。作为消费者监听主题时,需要配置监听哪些分区。
一个消费者可以监控多个分区。消费者和分区之间的对应关系也称为“所有权关系”。
Offset Offset是一个递增的整数值,Kafka会自动递增该值,然后自动写入每个分区。中间。
在同一个分区中,一个偏移值唯一对应一条消息。另外,由于offset是递增的,因此还可以用来区分多条消息之间的顺序。
Consumer的重启动作不会影响offset的值,因为这是Kafka维护的值。 Broker和集群 独立的Kafka服务器称为Broker。
一个或多个代理可以形成一个“集群”代理集群。虽然Kafka是一个分布式消息队列系统,但是在集群中,Kafka仍然是一个准中心化的系统架构。
换句话说,每个集群中仍然有一个主代理,称为控制器。 每个集群都会自动选举一个集群控制器。
控制器负责以下操作:管理集群、为代理分配分区以及监控代理。 在集群中,一个分区会属于一个broker,这个broker也被称为该分区的leader。
同时,分区还可以分配给多个broker进行分区复制——如果其中一个broker发生故障,剩余的broker可以尽快接管leader的位置。如果我们使用云原生的Kafka,一般不需要太担心这个问题。
安装/运维基本概念 Kafka部署架构 如果自己安装Kafka,需要提前安装的软件是Java和Zookeeper。我当时就很疑惑,为什么要多一个Zookeeper?事实上,Kafka使用Zookeeper来保存集群中的元数据和消费者信息。
这体现了Java强大而完整的生态系统,各种解决方案都可以找到现有的轮子。 Zookeeper还支持集群部署。
ZooKeeper 集群称为 Ensemble。由于ensemble也采用了选举机制,因此每个ensemble中的节点数为奇数,不建议超过7个。
如果我们使用云原生的Kafka,则不需要太担心这个细节。主题参数 部署完broker和Zookeeper后,我们就可以创建主题了。
创建主题时需要配置一些参数。主要需要特别注意的是: num.partitions:新主题的默认分区数。
在后续的运维中,分区的数量只会增加,不会减少。在腾讯云CKafka中,这个对应的是“分区数”配置log.retension.ms:根据时间决定topic中的数据可以保存多长时间。
这个对应CKafka接口中的“retension.ms”参数log.retension.bytes:根据存储空间决定Topic中可以保存多少数据。该参数在CKafka中不支持log.segment.bytes:表示日志段文件的大小根据存储空间确定。
该参数在CKafka中不支持log.segment.ms:表示根据时长确定日志段大小。对应CKafka接口中的“segment.ms”参数。
如果Partition数量不是必需参数,如何选择? 前面说过,在同一个分区中,消息的顺序是可以保证的。因此,对于可靠性要求不高但顺序性要求较高的小型系统,可以采用单分区方案。
但是这种方案其实是非常危险的:首先,单个分区意味着只能有一个消费者,否则就会出现消息重复消费的问题。在生产项目中进行单点部署几乎是不可接受的。
虽然在Kafka内部,单个分区内的消息顺序是可以保证的,但是如果生产者不能保证,那么Kafka内部的消息顺序仍然不真实。的。
因此,对于顺序要求较强的消息队列系统,不建议使用时间顺序,而是使用逻辑顺序/逻辑时钟来区分消息的顺序。 所以在实际生产环境中,我们应该适当分配分区数量。
如果需要排序,你不应该依赖Kafka的排序机制,而应该使用额外的机制来确保它。 Kafka生产者架构图 生产者向Kafka Broker发送消息一般都是使用各语言的SDK完成。
下面的框图展示了SDK完成的逻辑。首先,生产者发送消息之前,需要将消息封装到生产者记录中。
记录中包含的所需信息是主题和值(即消息体)信息。另外,分区和密钥信息是可选的,但相对很少使用。
Key参数的作用将在后面解释。 当消息写入Kafka Broker时,Broker会回调SDK,将消息最终落地的分区以及该分区中的偏移量信息返回给SDK,最后根据需要返回给Producer 。
消息发送 Kafka生产者有两种消息发送方式:同步和异步。 同步发送方式是指生产者发送的每条消息都需要按照上述结构图的流程进行处理:消息发送后,等待Kafka Broker的结果响应,然后再进行进一步处理。
Kafka Broker返回的错误包括两类错误: 可重试错误:当遇到此类错误时,生产者可以直接重试发送。比如网络错误、集群错误等。
不可重试的错误:遇到此类错误时,生产者只能考虑报警、记录日志、修改软件逻辑等,例如消息过大等。 异步发送方式是指生产者通过SDK发送消息后直接返回; SDK在后台处理消息发送和响应处理,然后通过回调通知生产者进行进一步处理。
生产者参数 还有一些参数可以在生产者启动之前配置。读者可以在各个语言的SDK中具体搜索: acks:消息发送到Kafka Broker。
由于实际上有多个broker,所以消息需要复制多次。该参数表示需要等待多少个broker响应才认为消息成功: 0:表示不需要等待broker响应 1:表示leader响应就足够了 all:表示需要所有broker响应 buffer.memory:生产者的缓冲区尺寸。
单位是消息数。当缓冲区满时,SDK会根据maxblock.ms等待并阻塞一段时间,然后再重试。
如果缓冲区仍满,则会抛出异常或返回错误。 Compression.type:消息压缩格式,可选值有:snappy、gzip、lz4retries:重试次数,重试间隔为retry.backoff.ms,默认为msbatch.size:一个batch的数据大小,以字节为单位。
为了减少网络传输的消耗,Kafka生产者不会一次性发送一条消息,而是分批发送。当批量大小达到该参数时,会立即发出。
linger.ms:发送批次之前的缓冲时间。当batch的大小没有达到batch.size时,SDK不会按住消息不发送。
相反,它会等待一段时间,然后发送内存中的批次。 Client id:用于标识生产的自定义字符串或 max.id.flight.requests.per.connection:该参数是指生产者在收到服务器响应之前可以发送的消息数量。
设置为1可以保证消息顺序,但相应的效率会降低 request.timeout.ms:生产者发送数据后等待响应的时间。 Key的作用 生产者记录中的key有两个用途:作为消息附加消息可用于确定写入哪个分区。
默认分区器允许将具有相同密钥的消息写入同一分区。如果key == null,则默认使用轮询方式写入分区。
如果key不为空,则根据哈希结果确定分区 生产者也可以通过自定义分区器实现业务的特定分区功能。详情请参见各个Language SDKKafka消费者 一个Kafka消费者隶属于其对应的消费者组。
每个组订阅一个主题,每个消费者消费一部分消息。整个组通过消耗不同的分区来实现负载均衡。
每个group都有一个group.id,用于标识一个消费者组,对应业务中的一个消费者业务。 不要让消费者数量超过分区数量,否则会造成重复消费问题。
因此,在选择分区时,宁可多用,不可节省。更多的分区也可以更合理地在消费者之间分配负载。
分区Reoke/Rebalance 每个消费者可以对应一个或多个分区;多个消费者组成一个组,覆盖主题的所有分区。但当消费者和分区数量发生变化时,所有权关系需要重新分配。
此操作称为重新平衡。至于是热开关还是冷开关,由业务方决定。
当消费者调用 subscribe() 监听消息时,可以传入 ConsumerRebalanceListener 实例来监听事件。需要注意的事件有: onPartitionsRevoked():这是重新平衡开始之前的事件。
注意此时消费者应该停止消费,并且commit的offset值已经完成但还没有提交onPartitionsAssigned():这是重新平衡的结束,即分区重新分配结束后的时间。大多数情况下,消费者不需要特别处理任何事情,但可以执行一些消费过程的重启动作。
提交和偏移 如前所述,一条消息可以与kafka中分区中的偏移值进行匹配。对应。
对于消费者来说,分区-偏移量对还可以用来标识当前消费者已经获取的消息的进度,也可以被消费者用来寻址Kafka中的历史消息。 当某条消息消费完成后,消费者会将offset值提交给Kafka,让Kafka识别并保存某个消费者组的消费进度。
消费者下次请求事件时,默认会继续从这个偏移量获取。 Consumer更新offset到Kafka的动作称为“提交”commit。
如果消费者崩溃或者有新消费者加入群组,则会触发重新平衡。重新平衡完成后,每个消费者可能会被分配到不同的分区。
为了继续前面的工作,消费者需要读取每个分区最后提交的偏移量,然后从指定的偏移量开始继续处理。该操作通常在SDK中完成。
然而,在上述切换过程中,由于分布式系统的分布式、异步特性,我们可能不可避免地会遇到一些不一致的情况,具体表现为消息的重复处理和漏处理。因此,我们任何时候都不能简单地依赖Kafka本身提供的消息队列机制。
相反,我们还需要在各自的业务系统中进行一定的防御性编程,以避免错误处理。 一般来说,SDK有以下几种提交方式: 自动提交:当enable.auto.commit为true时,API会定期异步提交。
因此,如果触发再平衡时仍有部分数据未提交,则再平衡后可能会出现其他消费者之间的重复消费。主动提交:当enable.auto.commit为false时,业务方需要主动提交,调用相关API进行提交。
(主动)异步提交:其实就是主动提交的异步版本。简单来说,就是一个后台异步提交的过程。
提交特定偏移量:此模式显式提交特定分区的偏移量值。参考文献 The Definitive Guide to Kafka - 本文的框图基本上是参考这本书来绘制的。
本文根据 Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License 获得许可。原作者:amc.欢迎转载,但必须按照上述许可协议注明出处。
版权声明:本文内容由互联网用户自发贡献,本站不拥有所有权,不承担相关法律责任。如果发现本站有涉嫌抄袭的内容,欢迎发送邮件 举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。
标签:
相关文章
06-17
06-17
06-21
06-08
06-18
06-18
06-17
最新文章
【玩转GPU】ControlNet初学者生存指南
【实战】获取小程序中用户的城市信息(附源码)
包雪雪简单介绍Vue.js:开学
Go进阶:使用Gin框架简单实现服务端渲染
线程池介绍及实际案例分享
JMeter 注释 18 - JMeter 常用配置组件介绍
基于Sentry的大数据权限解决方案
【云+社区年度征文集】GPE监控介绍及使用