【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中,消费者批量的上报偏移量等。都是通过大量的批量操作来实现数据的传输

相关推荐
蒋大钊!1 小时前
分布式锁实现与原理探究:介绍总结
分布式
不喜欢就睡大觉2 小时前
Zookeeper+消息队列(kafka)
分布式·zookeeper·kafka
BD_Marathon3 小时前
Hadoop入门两道面试题
大数据·hadoop·分布式
YCyjs4 小时前
Zookeeper
分布式·zookeeper·kafka
小马爱打代码6 小时前
分布式系统的概念与设计模式
java·分布式·设计模式
goTsHgo9 小时前
spark的stage划分的原理
大数据·分布式·spark
xuchengxi-java9 小时前
SpringBoot Kafka发送消息与接收消息实例
spring boot·后端·kafka
a栋栋栋11 小时前
Redisson分布式锁
分布式
kk_17780361913 小时前
电商安全新挑战:筑起数字防御长城,守护业务与数据安全
分布式·安全