【kafka-04】kafka线上问题以及高效原理

Kafka系列整体栏目


内容 链接地址
【一】afka安装和基本核心概念 https://zhenghuisheng.blog.csdn.net/article/details/142213307
【二】kafka集群搭建 https://zhenghuisheng.blog.csdn.net/article/details/142253288
【三】springboot整合kafka以及核心参数详解 https://zhenghuisheng.blog.csdn.net/article/details/142346016
【四】kafka线上问题以及高效原理 https://zhenghuisheng.blog.csdn.net/article/details/142371986

kafka线上问题以及高效原理

一,kafka线上问题以及高效原理

在前面几篇中,讲解了kakfa的安装部署,以及springboot如何整合kafka的使用,然而在实际的开发中,往往会遇到很多生产中的问题中需要解决,往往需要提前配置好参数,以及根据不同场景解决不同的业务

1,如何保证kafka消息不丢失问题

虽然说kafka是更加趋向于大数据方面,用于数据分发和流失计算等,允许丢失部分数据,但是在某些场合中,也是需要保证消息是不能丢失的,如金融行业,订单数据等。为了保证数据不丢失,不管是任何一种消息队列,都需要考虑三个方面,生产者方面、broker方面和消费者三个方面进行考虑。

1.1,生产者方面

在生产者方面,当消息往broker中投递时,需要通过设置ack机制来保证消息确认机制,通过设置不同的参数来决定消息是否会丢失。为了保证消息不丢失,可以在配置文件中奖ack的值设置成-1

  • ack=0时, 性能最高,消息直接异步给完broker就行,不需要broker任何答复,缺点就是容易丢消息
  • ack=1时, 性能其次,需要leader结点将数据成功写入到本地日志,但是不需要等待集群中的follower写入,如果出现leader挂掉,但是follower未及时同步,那么在follower变成leader之后,就会丢失这部分消息
  • ack=-1时,性能最低,但是安全性最高, 生产者端需要等待broker集群中的leader和副本都成功写入日志

1.2,broker方面

在架构层面,可以部署一套多个结点的broker集群模式,最好是每台机器对应一个broker,然后每个broker配置一个副本,从而保证broker的高可用性,即使某个节点甚至是leader主节点挂了,也能通过选举出其他结点进行故障转移,从而保证消息不丢失

1.3,消费者方面

在kafka中,消费者默认会使用自动提交的方式提交消费的偏移量到broker中,比如5s提交一次,那么如果消费者消费完了某段偏移量的消息之后,在提交到topic中时结点突然挂了,导致topic那边没有成功的记录该消费者的偏移量,导致服务重启之后,新的消费者重新消费这5s的消息,也可能造成消息丢失。

因此最好设置成自动提交偏移量到broker中,需要关闭默认的自动提交,然后设置这个 ack-mode的value值为manual , 指定手动提交确认模式,使用 Acknowledgment 对象来手动确认消费。

java 复制代码
enable-auto-commit: false
ack-mode: manual

2,如何保证不重复消费

消息重复消费,主要分为两个方面:一个是生产者重复投递,一个是消费者重复消费同一条

生产者因为网络抖动的原因,导致broker没有及时的给生产者反馈,导致生产者触发了重试策略,又往broker中投递了同一条数据,这就导致了重复投递,因此可以设置以下参数保证生产者的幂等性

java 复制代码
enable.idempotence=true

消费者这边,首先还是这个自动提交的问题,需要改成手动提交偏移量到topic,需要将这个自动提交

java 复制代码
enable-auto-commit: false

另一个就是可以通过幂等性来保证消息不重复消费,比如给每条消息设置一个唯一id,将消息的id加入的缓存中,或者加入到数据库设置唯一索引等等方式

3,如何解决消息积压问题

在解决积压问题之前,首先需要明白kafka内部消费的几个原理,首先是关于消费者组的问题,一个partition分区中数据只能被消费者组中的一个消费者消费,也就是说最好的情况就是如有10个分区,那么最好就有10个消费者,如果消费者组中增加消费者也没用,因为所有已有的分区都已有消费者进行消费。因此假设说如果消费者小于partition分区的个数,那么就可能出现一个消费者得消费两个分区或者以上,因此这种情况就可以增加消费者的个数来解决积压问题。

第二个问题就是业务场景是否支持rebanlance机制,举个例子,假设已有10个分区,10个消费者,但是突然消费者被移除了一个,那么kakfa就会触发这种机制,就是说此时有一个分区没有消费者消费了,那么kafka就会将这个分区通过这种rebanlance机制分配给其他消费者消费,那么此时就是存在一个消费者得消费两个分区的消息,那么就会降低整个系统的吞吐量

如果不支持这种rebanlance机制,就是不影响其他的消费者消费以及不影响整体系统的吞吐量。比如这个order的topic主题,已有4个分区和4个消费者,此时都在正常消费,c1对应partition1,依次对应,假如此时c3这个消费者突然消费不过来,然后消息一直是挤压在partition中,此时加消费者也没用,但是又不能影响其他消费者的支持消费,那么需要如何设计和解决这种积压问题

其解决方案如下,就是新加一个order2的主题,然后c3这个消费者不做具体的信息消费,而是只作一个转发,将数据转发到新的order2的这个主题中,将原先一个partition和消费者拆分成多个partition和多个消费者。从而在不进行rebanlance的情况下,既不影响整体的吞吐量,也解决了这个消息积压的问题。

除此之外,消费者这边也可以采用多线程,优化硬件,如cpu、内存和磁盘等。

4,kafka如何设计一个延时队列

在kafka中,内部并没有设计这个延时队列,因此如果想通过kakfa实现一个延时队列,那么需要内部自定义设计。比如存在一个支付场景,假设某个订单30分钟没有支付,那么需要主动的关闭这个订单,需要如何设计和实现。

针对上面这个场景,首先需要知道kafka的存储原理,在kakfa中,内部采用的是顺序写的原理,也就是说partition前面写入的内容的时间一定是比partition后面写入的内容的时间是更早的,明白这个原理之后,那么多就可以采用定时任务的形式来进行消费

如创建一个order_30的topic主题,专门存储用户下单后未立马支付的订单。假设在第一个分区中,已经有1000条这种信息,那么就可以开启一个定时任务,每隔30s检测一次,从头开始轮询,如第一条数据到期,那么就对这条消息进行消费,并且修改partition的偏移量,依次下去。

java 复制代码
@Service
public class RetryTask {
    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    @Scheduled(fixedDelay = 5000)
    public void retryMessages() {
        xxx
    }
}

5,kafka事务使用

在kakfa中,内部也存在事务概念,但是和mysql不同,kafka的事务只支持批量消息整体,也就是说批量消息要么同时成功,要么同时失败。 Kafka事务主要用于保证消息的一致性和避免消息丢失或重复消费。

核心概念

  • 事务:一组生产操作的集合,要么全部成功,要么全部失败。
  • 事务ID:每个事务都有一个唯一的事务ID,Kafka用来标识和跟踪事务。
  • 事务日志:Kafka维护事务日志以跟踪事务的状态和相关的偏移量。
  • 原子性:事务中的消息要么全部提交,要么全部回滚,保证数据的一致性。

在配置文件中,需要配置以下参数

java 复制代码
spring:
  kafka:
    producer:
      acks: all
      enable-idempotence: true
      transaction-id-prefix: my-transactional-id

事务的实现方式如下,也是需要在方法上面加上 Transactional 注解

java 复制代码
@Transactional
public void sendTransactionalMessages(String topic, String message) {
    kafkaTemplate.executeInTransaction(kafkaTemplate -> {
        kafkaTemplate.send(topic, message);
        // 可以发送多条消息
        return true; // 返回true表示事务成功提交
    });
}

Kafka的事务机制适用于需要保证消息处理一致性的场景,主要适用于金融交易系统和订单处理系统

6,kafka高性能原因

6.1,零拷贝

首先内部采用了零拷贝:https://blog.csdn.net/zhenghuishengq/article/details/140721001

kafka采用的是sendfile的零拷贝方式, 只需要两次上下文切换,两次DMA拷贝,0次或者1次的CPU拷贝 。解决了最初的4次上下文,4次DMA,2次CPU拷贝,详细参考上面那篇文章。

6.2,顺序写

内部采用了顺序写:https://zhenghuisheng.blog.csdn.net/article/details/129080088

通过顺序写和顺序读,减少 寻找磁道和盘面时间 ,从而提高整体的性能,详情参考上面这篇文章

6.3,批量操作

kafka内部采用的都是批量的操作,如生产者批量将数据写入缓冲区中,然后批量的缓冲区数据投递到broker中,消费者批量的上报偏移量等。都是通过大量的批量操作来实现数据的传输

相关推荐
RainbowSea15 小时前
6. RabbitMQ 死信队列的详细操作编写
java·消息队列·rabbitmq
RainbowSea15 小时前
5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
java·消息队列·rabbitmq
数据智能老司机16 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机16 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
数据智能老司机17 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
IT成长日记17 小时前
【Kafka基础】Kafka工作原理解析
分布式·kafka
州周19 小时前
kafka副本同步时HW和LEO
分布式·kafka
爱的叹息20 小时前
主流数据库的存储引擎/存储机制的详细对比分析,涵盖关系型数据库、NoSQL数据库和分布式数据库
数据库·分布式·nosql
程序媛学姐20 小时前
SpringKafka错误处理:重试机制与死信队列
java·开发语言·spring·kafka
千层冷面21 小时前
RabbitMQ 发送者确认机制详解
分布式·rabbitmq·ruby