kafka 事务代码实现(生产者到server端的事务)
kafka的事务指的是2个点 ① 生产者到kafka服务端的事务保障 ②消费者从kafka拉取数据的事务
kafka提供的事务机制是 第①点, 对于第②点来说 只能自己在消费端实现幂等性。
我们来介绍第①点, 因为生产者producer写到kafka可能会出现消息重复,比如 设置ack=all,写入到kafka的leader时,leader挂掉了,
没有及时反馈ack,导致生产者再次发送消息就会出现重复消息落盘。这种情况可以设置kafka的属性用来开启幂等。但是这种幂等
只能保证 producer没有挂掉的情况下,因为幂等的原理是 kafka缓存了一份 pid,partition,seqnumber 的数据,如果命中则说明之前缓存了,
但是如果producer挂掉了重启后,它的pid就会变化,partition也有可能变化,就会导致消息会出现重复状况。所以kafka 0.11版本加入了事务机制
开启时事务后,会存在 transaction_id , 封装成( transaction_id, pid,partition,seqnumber, 消费到哪条记录等等) 保存在kafka上,如果producer 挂了重新
启动的时候,会自动寻找kafka中的这个 transaction_id,找到的话就会恢复到挂掉之前的状态 ,然后进行消费。kafka事务保证了 要么全部成功,要么全部失败。
还有一个很重要的点是 要在consumer端 设置 isolation.level 为 read_committed状态,它默认是read_uncommitted状态,这是什么意思呢? 接下来详细说明一下:
目前producer是双线程设计,后台的Sender线程负责实际的消息发送。当Sender线程构造消息batch发送时,它会尝试去读取事务状态,如果发现已经abort,则立即将未发送的batch全部fail掉——这就是为什么你注释Thread.sleep后则不能发送的原因。当你加入了Thread.sleep之后batch发送时主线程在休眠,尚未执行到abortTransaction,故Sender线程成功地发送了消息到Kafka broker。
另外,你需要为consumer端配置isolation.level = read_committed。这样不管哪种情况你都不会读取到任何未提交的消息。默认是read_uncommitted,即使abort的消息,只要是成功发送到Kafka了,consumer就能读取到。
1、也就是开启事务之后,生产者调用send发送数据时他就会直接向kafka插入数据,只不过是这个数据后面追加了一个状态,这个状态是read_uncommited代表未提交,只有producer调用了commitTransaction时候 这些数据在kafka中才会都标记为read_commited。
producer实现代码如下:
public class producer { public static void main(String[] args) throws ExecutionException, InterruptedException {
Properties props = new Properties();
props.put("bootstrap.servers","hadoop102:9092,hadoop103:9092,hadoop104:9092");
props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
props.put("acks","all");
props.put("retries","2");
props.put("batch.size","16384");
props.put("transactional.id","tran-wb2"); //事务ID,开启事务下面幂等也要开启
props.put("enable.idempotence", "true"); //开启幂等
// 一定要在消费者方设置 isolation.level为 read_committed,表示只读取已提交事务状态的记录
Producer<Object, Object> producer = new KafkaProducer<>(props); producer.initTransactions();
producer.beginTransaction();
try {
for (int i = 0; i <100 ; i++) {
Future<RecordMetadata> first = producer.send(new ProducerRecord<>("first", i + "sad ", i + 1 + "s d"));
//first.get(); 加上get可以实现同步发送操作
if (i==20){
throw new RuntimeException("测试异常回滚");
}
}
} catch (RuntimeException e){
System.out.println(e.toString());
producer.abortTransaction(); //出现异常,就进行回滚,这样所有消息都会失败
producer.close();
return;
} producer.commitTransaction(); //没有异常就 事务提交
producer.close();
}
}
消费者代码
public class consumer { public static void main(String[] args) throws InterruptedException { Properties properties = new Properties();
properties.put("bootstrap.servers", "hadoop102:9092,hadoop103:9092,hadoop104:9092");
properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
properties.put("group.id", "wangbingsaa");
properties.put("isolation.level", "read_committed"); //一定要设置 只拉取 已提交事务状态的记录,这样无论什么条件都可以
// properties.put("auto.offset.reset","earliest"); //设置拉取的位置
properties.put("enable.auto.commit", "false"); //关闭自动提交
properties.put("auto.commit.interval.ms", "1000"); //自动提交间隔 Consumer<String, String> consumer = new KafkaConsumer<>(properties); consumer.subscribe(Collections.singletonList("first")); ConsumerRecords<String, String> records = consumer.poll(4000); //如果拉取时长超过4000毫秒 就不拉取
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, partitoon = %d key = %s, value = %s%n", record.offset(), record.partition(),record.key(), record.value());
}
consumer.commitSync(); //手动提交
}
}
kafka 事务代码实现(生产者到server端的事务)的更多相关文章
- HBase 协处理器编程详解第一部分:Server 端代码编写
Hbase 协处理器 Coprocessor 简介 HBase 是一款基于 Hadoop 的 key-value 数据库,它提供了对 HDFS 上数据的高效随机读写服务,完美地填补了 Hadoop M ...
- JS学习十四天----server端运行JS代码
server端运行JS代码 话说,当今不在client使用JS代码才是稀罕事.因为web应用的体验越来越丰富,client用JS实现的逻辑也越来越多,这造成的结果就是某些差点儿一致的逻辑须要在clie ...
- 上机题目(0基础)- Java网络操作-Socket实现client和server端通信二(Java)
上一节实现了client像server端发送请求.本节将实现server端向client回传信息.实现原理非常easy,在原来的基础上.在server端实现输出流,在client实现输入流就可以,详细 ...
- golang如何优雅的编写事务代码
目录 前言 需求 烂代码示例 重构套路 一.提前返回去除if嵌套 二.goto+label提取重复代码 三.封装try-catch统一捕获panic 前言 新手程序员概有如下特点 if嵌套特别多.重复 ...
- Kafka源码分析(三) - Server端 - 消息存储
系列文章目录 https://zhuanlan.zhihu.com/p/367683572 目录 系列文章目录 一. 业务模型 1.1 概念梳理 1.2 文件分析 1.2.1 数据目录 1.2.2 . ...
- Hadoop基于Protocol Buffer的RPC实现代码分析-Server端
http://yanbohappy.sinaapp.com/?p=110 最新版本的Hadoop代码中已经默认了Protocol buffer(以下简称PB,http://code.google.co ...
- Hadoop基于Protocol Buffer的RPC实现代码分析-Server端--转载
原文地址:http://yanbohappy.sinaapp.com/?p=110 最新版本的Hadoop代码中已经默认了Protocol buffer(以下简称PB,http://code.goog ...
- 搭建分布式事务组件 seata 的Server 端和Client 端详解(小白都能看懂)
一,server 端的存储模式为:Server 端 存 储 模 式 (store-mode) 支 持 三 种 : file: ( 默 认 ) 单 机 模 式 , 全 局 事 务 会 话 信 息 内 存 ...
- Linux下的C Socket编程 -- server端的继续研究
Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...
随机推荐
- 一起来找茬:记一起 clang 开启 -Oz 选项引发的血案
作者:字节跳动终端技术 -- 刘夏 前言 笔者来自字节跳动终端技术 AppHealth (Client Infrastructure - AppHealth) 团队,在工作中我们会对开源 LLVM 及 ...
- Spring专题2: DI,IOC 控制反转和依赖注入
合集目录 Spring专题2: DI,IOC 控制反转和依赖注入 https://docs.spring.io/spring/docs/2.5.x/reference/aop.html https:/ ...
- jstl split 分割字符串?
1. 在已经获得数据的前提下,对数据进行分割,分割后的结果是一个数组,可以通过数组获得我们需要的数据 2. value 是获得值 需要${} 的方式获取, var 是设置变量. var = " ...
- Transformer可解释性:注意力机制注意到了什么?
原创作者 | FLPPED 论文: Self-Attention Attribution: Interpreting Information Interactions Inside Transform ...
- IDEA学习系列之Module概念
感谢原文作者:小manong 原文链接:https://www.jianshu.com/p/fcccc37fcb73 简单应用:IDEA Maven创建多个Module相互依赖 1.Module的概念 ...
- 前端也能做AI
殷圣魁 58架构师 7月16日 原文链接 前言 相信不少人看过一篇人工智能已经能实现自动编写HTML,CSS的文章,人工智能开始取代前端的一部分工作.前端开发行业真的被人工智能取代吗? 1.人工智能发 ...
- Linux Shell脚本攻略复习
1. 打开终端后的提示符中,$表示普通用户,#表示管理员用户root,root是linux系统中权限最高的用户. 2. shell脚本通常是一个#!起始的文本文件,其中#!位于解释器路径之前. 例如: ...
- #import和#include区别
#import与#include的类似,都是把其后面的文件拷贝到该指令所在的地方 #import可以自动防止重复导入 #import <> 用于包含系统文件 #import"&q ...
- java创建一个子类对象是会调用父类的构造方法会不会创建父类
1.子类在创建实例后,类初始化方法会调用父类的初始化方法(除了Java.lang.Object类,因为java.lang.Object类没有父类),而这种调用会逐级追述,直到java.lang.Obj ...
- java常用类,包装类,String类的理解和创建对象以及StringBuilder和StringBuffer之间的区别联系
一.包装类的分类: 1.黄色部分的父类为Number 继承关系: Boolean Character 其他六个基本数据类型 2.装箱和拆箱 理解:一个例子,其他的都相同 装箱:Integer inte ...