kafka精准一次、事务、幂等性
Kafka事务
消息中间件的消息保障的3个级别
- At most once 至多一次。数据丢失。
- At last once 至少一次。数据冗余
- Exactly one 精准一次。好!!!
如何区分只要盯准提交位移、消费消息这两个动作的时机就可以了。
当:先消费消息、再提交位移。
如果提交位移这一步挂了,就会再消费一遍消息。重复消费====》〉》至少一次
当:先提交位移、再消费消息。
提议位移成功、消费消息失败,那么数据就丢失了====》〉》至多一次
如何精准一次呢?
幂等和事务!
幂等
对接口的多次调用所产生的结果和一次调用的结果是一样的。
即:(第一次调用,中途挂了,再次调用==一次调用) 为true
如何实现?
在v2版本的消息存储格式用有两个字段。produce_id(简称pid) 、first sequence

每个新的生产者实例在初始化的时候都会被分配一个pid,每个pid,消息发送到每一个分区都有序列号 sequence,序列号会从0开始递增,每发送一条消息,<PID,分区> 对应的序列号的值会➕1。这个序列号值(SN)在broker的内存中维护。只有当SN_new=SN_old+1.
broker才会接收这个消息。
如SN_new < SN_old+1 说明消息重复了,这个消息可以直接丢掉。
如SN_new>SN_old+1 说明消息丢失了,有数据还没有卸写入。抛乱序异常OutOforderSequenceException。
即用序列号来保证消息的顺序消费。
注意 所记录的这个序列号是针对 每一对<PID,分区> 所以这个幂等实现的是单会话、单分区的。
如何保证多个分区之间的幂等性呢?
事务
保证对多个分区写入操作的原子性,要么全部成功、要么全部失败。将应用程序的生产消息、消费消息、提交消费位移当作原子操作来处理。
用户显示指定一个事务id: transactionalId。这个事务id是唯一的
从生产者角度来考虑,事务保证了生产者会话消息的幂等发送 和跨生产者会话的事务恢复.
- 生产者会话消息的幂等发送:如有有两个相同事务id的生产者,新的创建了 旧的就会被kill
- 某个生产者实例宕机了,新的生产者实例可以保证未完成的旧事务要么被提交 要没被中断
实现过程,以consume-transform-produce为例。
package com.hzbank.yjj.transaction;import com.hzbank.yjj.producer.CustomerPartitioner;
import com.hzbank.yjj.producer.ProducerlnterceptorPrefix;
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.errors.ProducerFencedException;
import org.apache.kafka.common.serialization.StringDeserializer;
import org.apache.kafka.common.serialization.StringSerializer;import java.time.Duration;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;public class TransactionConsumeTransformProduce {public static final String brokerList = "localhost:9092";public static Properties getConsumerProps(){Properties props =new Properties();props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerList);props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());props.put(ConsumerConfig.GROUP_ID_CONFIG,"groupId");props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG,false);return props;}public static Properties getProducerProps(){Properties props =new Properties();props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, brokerList);props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName());props.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG,"transactionalId");return props;}public static void main(String[] args) {//初始化生产者和消费者KafkaConsumer<String, String> consumer = new KafkaConsumer<>(getConsumerProps());consumer.subscribe(Collections.singletonList("topic-source"));KafkaProducer<String, String> producer = new KafkaProducer<>(getProducerProps());//初始化事务producer.initTransactions();while (true){ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));if(!records.isEmpty()){HashMap<TopicPartition, OffsetAndMetadata> offsets = new HashMap<>();//开启事务producer.beginTransaction();try {for (TopicPartition partition : records.partitions()) {List<ConsumerRecord<String, String>> partitionRecords = records.records(partition);for (ConsumerRecord<String, String> record : partitionRecords) {System.out.println("获取到了topic-source发送过来的数据"+record.value());System.out.println("do some ");ProducerRecord<String, String> producerRecord = new ProducerRecord<>("topic-sink", record.key(), record.value());producer.send(producerRecord);}// 获取最近一次的消费位移long lastConsumedOffset = partitionRecords.get(partitionRecords.size() - 1).offset();offsets.put(partition,new OffsetAndMetadata(lastConsumedOffset+1));}//提交消费位移producer.sendOffsetsToTransaction(offsets,"groupId");//提交事务producer.commitTransaction();} catch (ProducerFencedException e) {System.out.println("异常了");producer.abortTransaction();}}}}}
1. 找到TransactionCoordinator。
TransactionCoordinator负责分配和管理事务。
FindCoordinatorRequest 发送请求找到TransactionCoordinator所在的broker节点。返回其对应的node_id、 host、 port 信息
transactionalId 的哈希值计算主题_transaction_state 中的分区编号
根据分区leader副本找到所在的broker节点,极为Transaction Coordinator节点
2. 获取pid
通过InitProducerIdRequest向TransactionCoordinator 获取pid 为当前生产者分配一个pid。
String transactionalId; 事务id
int transactionTimeoutMs; 事务状态更新超时时间
3. 保存pid
TransactionCoordinator 第一次收到事务id会和对应pid保存下来,以消息(事务日志消息)的形式保存到主题_transaction_state中,实现持久化
InitProducerIdRequest还会出发一下任务:
- 增加pid对应的producer_epoch.具有相同 PID 但 producer_epoch 小 于该 producer_叩och 的其他生产者新开启的事务将被拒绝 。
- 恢复( Commit)或中止( Ab。此)之前的生 产 者未完成的 事务
4. 开启事务
通过 KafkaProduc町的 beginTransaction()方法。调用该方法后,生产者本 地会标记己经开启了 一个新的事务 ,只有在生产者发送第一条消息之后 TransactionCoordinator 才会认为该事务 己经开启 。
5. Consume-Transform-Produce
整个事务处理数据。
-
AddPartitionsToTxnRequest:让 TransactionCoordinator 将<transactionld, TopicPartition>的对应关系存储在主题
transaction state 中
-
ProduceRequest:生产者通过 ProduceRequest 请求发送消息( ProducerBatch)到用户 自定义主题中
-
AddOffsetsToTxnRequest:TransactionCoordinator 收到这个AddOffsetsToTxnRequest请求,通过 groupId 来推导出在一consumer_offsets 中的分区
-
TxnOffsetCommitRequest:发送 TxnOffsetCommitRequest 请求给 GroupCoordinator,从而将本次事务中 包含的消费位移信息 offsets 存储到主题 consumer offsets 中
6. 提交或者终止事务
KafkaProducer 的 commitTransaction()方法或 abortTransaction()方法。
写不下去了,暂时就先理解这么多了,后面再多结合源码去看看。
参考:书籍《深入理解 Kafka:核心设计与实践原理》
相关文章:
kafka精准一次、事务、幂等性
Kafka事务 消息中间件的消息保障的3个级别 At most once 至多一次。数据丢失。At last once 至少一次。数据冗余Exactly one 精准一次。好!!! 如何区分只要盯准提交位移、消费消息这两个动作的时机就可以了。 当:先消费消息、…...
centos 7.9 下利用miniconda里的pyinstaller打包python程序为二进制文件操作方法
centos 7.9 下利用miniconda里的pyinstaller打包python程序为二进制文件操作方法 一.centos 7.9 操作系统安装 参考:https://blog.csdn.net/qq_46015509/article/details/134572030?utm_sourceminiapp_weixin 安装完成后用后台连接工具连上虚拟机 二.安装python3 …...
Motion Plan之基于采样的路径规划算法笔记
Motion Plan之搜索算法笔记 背景: 基于采样算法是一种在路径规划中广泛应用的有效方法。它通过在图中随机选择点来生成一个简化的搜索图,从而加速搜索过程。这种方法的主要优点包括减少内存使用,避免计算错误,具有动态障碍物对抗…...
idea里面常用插件
这里列出了一系列常用的 IntelliJ IDEA 插件,它们可以提高开发效率、简化操作,以及帮助进行代码分析和优化。以下是每个插件的简要介绍: GenerateAllSetter:生成对象的所有 set 方法和 get 方法,方便对象之间的转换。该…...
回归算法优化过程推导
假设存在一个数据集,包含工资、年龄及贷款额度三个维度的数据。我们需要根据这个数据集进行建模,从而在给定工资和年龄的情况下,实现对贷款额度的预测。其中,工资和年龄是模型构建时的两个特征,额度是模型输出的目标值…...
某高品质房产企业:借助NineData平台,统一数据库访问权限,保障业务安全
该企业是中国领先的优质房产品开发及生活综合服务供应商。在 2022 年取得了亮眼的业绩表现,销售额市场占有率跻身全国前五。业务涵盖房产开发、房产代建、城市更新、科技装修等多个领域。 2023 年,该企业和玖章算术(浙江)科技有限…...
Arduio开发STM32所面临的风险
据说micro_ros用到了arduino,然后用arduino搞stm32需要用到这个Arduino STM32的东西,然后这里申明了:这些代码没有经过严格测试,如果是向心脏起搏器,自动驾驶这样要求严格的的情况下,这个东西不能保证100%不发生问题&a…...
精准人脉引流软件的开发流程与涉及到的技术
一、精准人脉引流软件的开发流程 1. 确定需求:首先,我们需要明确软件的需求,包括目标用户、功能需求、性能需求等。这些需求将直接影响到软件的开发方向和最终效果。 2. 系统设计:根据需求,进行系统设计,…...
Mysql数据库 20.DCL数据控制语言
因这类SQL语言开发人员操作较少,主要是数据库管理员(DBA)使用,所以前文没有提及,这篇文章进行补充说明 DCL数据控制语言 用来管理数据库用户,控制数据库的访问权限 1.管理用户 1.1 查询用户 select * f…...
使用CMake交叉编译Arm Linux程序
下载安装aarch64-linux-gnu-gcc arm交叉编译工具链 apt-get install aarch64-linux-gnu-gccapt-get install aarch64-linux-gnu-gcc创建编译目录构建makefle 注意,工具链文件的指定一定要紧跟cmake命令之后,不能放到 … 后面构建arm架构cmake mkdir arm…...
训练日志——logging
目录 基础使用日志的6个级别打印日志修改打印级别 高级应用logging的组成记录器Loggers处理器Handlers过滤器Filterformatter格式创建关联打印日志 配置文件参考 基础使用 日志的6个级别 打印日志 import logginglogging.debug(调试日志) logging.info(消息日志) logging.war…...
尺度为什么是sigma?
我们先看中值滤波和均值滤波。 以前,我认为是一样的,没有区分过。 他们说,均值滤波有使图像模糊的效果。 中值滤波有使图像去椒盐的效果。为什么不同呢?试了一下,果然不同,然后追踪了一下定义。 12345&…...
迭代器模式
自定义 Counter 结构体类型,并实现迭代器。其他语言的场景,读取数据库行数据时,使用的就是迭代器。我们使用for语言遍历数组,也是一种迭代。 结构体对象实现 Iterator trait,创建自定义的迭代器,只需要实现…...
C++ 修饰符、存储类、运算符、循环、判断
一、C修饰符类型: C允许在char、int、double数据类型前放置修饰符。 数据类型修饰符: ◆ signed:表示变量可以存储负数。对于整型变量来说,signed 可以省略,因为整型变量默认为有符号类型。 ◆ unsigned࿱…...
2023 hnust 湖南科技大学 信息安全管理课程 期中考试 复习资料
前言 ※老师没画重点的补充内容★往年试卷中多次出现或老师提过的,很可能考该笔记是奔着及格线去的,不是奔着90由于没有听过课,部分知识点不一定全,答案不一定完全正确 题型 试卷有很多题是原题 判断题(PPTÿ…...
N皇后问题解的个数
暴力递归 #include <stdio.h>int count0,a[15],flag; void queen(int,int); int main(){int n;scanf("%d",&n);queen(n,n);printf("%d",count); } void queen(int n,int n0){if(n<1){flag1;for(int i1;i<n0;i){for(int j1;j<n0;j){if(…...
php订单发起退款(余额和微信支付)
index.html <a class="btn btn-danger btn-change btn-tuikuan btn-disabled" href="javascript:;"><i class="fa fa-tuikuan"></i> 订单退款</a>-->order.js // 为表格绑定事件Table.api.bindevent(table);//退款…...
【SpringCloud】认识微服务、服务拆分以及远程调用
SpringCloud 1.认识微服务 1.1单体架构 单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署 单体架构的优缺点: 优点: 架构简单,部署成本低 缺点: 耦合度高(维护困难&#x…...
Mysql基础操作(命令行)
文章目录 Mysql基础操作(命令行)背景创建数据库选择数据库查看所有表查看表结构向表插入数据插入第一条插入第二条插入第三条 查询表数据修改表数据删除表数据 Mysql基础操作(命令行) 背景 docker安装mysql8,映射本地…...
网站遇到DDOS攻击怎么办?
最近我的网站不幸又遇到了几乎是我见到过的最大一次 DDoS 攻击,并且几乎是没有反映的时间,直接接到腾讯云的短信通知“运营商封堵”,直接造成几个小时无法访问,解封后再次遭受到大流量 DDoS 攻击,再次被“腾讯云平台封…...
从“按钮变色”到“文本互动”:用Tkinter StringVar改造你的第一个GUI小游戏
从“按钮变色”到“文本互动”:用Tkinter StringVar改造你的第一个GUI小游戏 当你第一次用Tkinter做出那个点击按钮会变色的程序时,那种成就感可能还记忆犹新。但很快你会发现,真正的GUI应用远不止于此——用户输入、动态反馈、状态更新才是交…...
告别MATLAB环境:保姆级教程教你用App Designer打包独立EXE(含Runtime配置避坑)
MATLAB App Designer应用打包实战:从开发到分发的全流程指南 在工程计算和科研领域,MATLAB一直是不可或缺的工具。随着App Designer的推出,开发交互式GUI应用变得前所未有的简单。但当你完成了一个优秀的应用后,如何让没有MATLAB环…...
3分钟快速上手:d2s-editor暗黑2存档编辑器的完整使用指南
3分钟快速上手:d2s-editor暗黑2存档编辑器的完整使用指南 【免费下载链接】d2s-editor 项目地址: https://gitcode.com/gh_mirrors/d2/d2s-editor 还在为暗黑破坏神2单机角色培养而苦恼吗?想要快速体验不同职业的顶级装备搭配却不想花费数百小时…...
终极指南:如何用联想拯救者工具箱免费掌控你的笔记本性能
终极指南:如何用联想拯救者工具箱免费掌控你的笔记本性能 【免费下载链接】LenovoLegionToolkit Lightweight Lenovo Vantage and Hotkeys replacement for Lenovo Legion laptops. 项目地址: https://gitcode.com/gh_mirrors/le/LenovoLegionToolkit 想要彻…...
3分钟解放B站缓存视频:m4s-converter让你的收藏永不丢失
3分钟解放B站缓存视频:m4s-converter让你的收藏永不丢失 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾因B站视频突然下架而…...
告别定向测试!用SystemVerilog随机约束给你的芯片验证“开盲盒”
芯片验证的"开盲盒"革命:SystemVerilog随机约束实战指南 在数字IC验证的世界里,工程师们长期被定向测试的繁琐所困扰——编写无数特定场景的测试用例,像拼图一样试图覆盖所有可能的芯片行为。但随着设计复杂度呈指数级增长&#x…...
从SGL到XSimGCL:图对比推荐中的“简化”革命与性能跃迁
1. 图对比学习推荐算法的演进之路 推荐系统领域近年来最令人兴奋的突破之一,就是图对比学习技术的引入。作为一名长期跟踪推荐算法发展的从业者,我亲眼见证了从传统协同过滤到图神经网络的演进,再到如今对比学习带来的性能飞跃。这就像是从手…...
搞定微信小程序云开发`cloud.callFunction`报错:从`-501000`到成功获取`openid`的保姆级避坑指南
微信小程序云开发实战:从-501000报错到稳定获取openid的完整解决方案 第一次接触微信小程序云开发时,很多人都会被cloud.callFunction报错-501000搞得焦头烂额。这个看似简单的错误代码背后,往往隐藏着从环境配置到代码调用的系统性认知偏差。…...
别再只用欧氏距离了!用Python手把手教你实现DTW算法,搞定语音识别中的时间对齐难题
突破时间维度限制:用Python实战DTW算法解决语音对齐难题 当你在开发语音识别系统时,是否遇到过这样的困扰——同一句话被不同用户以不同语速说出,导致传统距离计算方法完全失效?想象一下这样的场景:用户A快速说出"…...
Java 流程控制语句详解(第3-4课时)
Java 流程控制语句详解(第3-4课时):分支、循环与实操案例 流程控制语句是 Java 编程的核心逻辑载体,也是从“简单变量运算”走向“复杂逻辑实现”的关键一步。第3-4课时重点讲解分支语句、循环语句的用法,结合 JDK 12+ 新特性,搭配4个高频实操案例,帮助新手快速掌握流程…...
