96SEO 2026-02-19 22:48 19
机制查看源码发现是使用两阶段提交策略而事务提交是checkpoint完成后才执行那么如果checkpoint设置间隔时间比较长时事务未提交之前后端应该消费不到数据而观察实际现象为写入kafka的消费数据可以立马消费。

CheckpointingMode.EXACTLY_ONCE输出输出到kafka。
编写任务2消费任务的结果topic打印控制台验证结果。
根据现象查看源码分析原因。
StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);env.enableCheckpointing(1000*60l,
CheckpointingMode.EXACTLY_ONCE);env.getCheckpointConfig().setCheckpointStorage(file:///flink/checkpoint);//
超时时间checkpoint没在时间内完成则丢弃env.getCheckpointConfig().setCheckpointTimeout(50000L);
//10秒env.getCheckpointConfig().setMaxConcurrentCheckpoints(2);env.getCheckpointConfig().setTolerableCheckpointFailureNumber(1);//最小间隔时间前一次结束时间与下一次开始时间间隔env.getCheckpointConfig().setMinPauseBetweenCheckpoints(1000);
KafkaSource.Stringbuilder().setBootstrapServers(127.0.0.1:9092).setTopics(test001).setGroupId(my-group)
.setStartingOffsets(OffsetsInitializer()).setStartingOffsets(OffsetsInitializer.committedOffsets()).setValueOnlyDeserializer(new
SimpleStringSchema()).build();DataStreamSourceString
WatermarkStrategy.noWatermarks(),
根据上面的介绍自己计算这边的超时时间满足条件即可properties.setProperty(transaction.timeout.ms,900000);
properties.setProperty(bootstrap.servers,
127.0.0.1:9092);KafkaSinkString
KafkaSink.Stringbuilder().setBootstrapServers(192.168.65.128:9092).setRecordSerializer(KafkaRecordSerializationSchema.Stringbuilder().setTopic(test002).setValueSerializationSchema(new
SimpleStringSchema()).build()).setKafkaProducerConfig(properties).setDeliverGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
.setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE).setTransactionalIdPrefix(flink-xhaodream-).build();map.sinkTo(sink);//
StreamExecutionEnvironment.getExecutionEnvironment();env.setParallelism(1);env.enableCheckpointing(1000*150l,
CheckpointingMode.EXACTLY_ONCE);env.getCheckpointConfig().setCheckpointStorage(file:///flink/checkpoint);
properties1.put(isolation.level,read_committed);KafkaSourceString
KafkaSource.Stringbuilder().setBootstrapServers(127.0.0.1:9092).setTopics(test002).setGroupId(my-group2).setProperties(properties1).setStartingOffsets(OffsetsInitializer.committedOffsets(OffsetResetStrategy.LATEST)).setValueOnlyDeserializer(new
SimpleStringSchema()).build();DataStreamSourceString
WatermarkStrategy.noWatermarks(),
任务1开启后无论是否执行checkpoint任务checkpoint都可以正常消费数据与预期不符合。
的源码找到跟与两阶段提交相关的代码1.18源码中TwoPhaseCommittingSink有重构。
kafkasink实现TwoPhaseCommittingSink接口实现创建Commiter和Writer。
{PrecommittingSinkWriterInputT,
IOException;SimpleVersionedSerializerCommT
getCommittableSerializer();PublicEvolvingpublic
}--------------------------------------
KafkaWriterState,TwoPhaseCommittingSinkIN,
KafkaRecordSerializationSchemaIN
transactionalIdPrefix;KafkaSink(DeliveryGuarantee
transactionalIdPrefix,KafkaRecordSerializationSchemaIN
deliveryGuarantee;this.kafkaProducerConfig
kafkaProducerConfig;this.transactionalIdPrefix
transactionalIdPrefix;this.recordSerializer
创建CommitterInternalOverridepublic
KafkaCommitter(kafkaProducerConfig);}InternalOverridepublic
SimpleVersionedSerializerKafkaCommittable
KafkaWriterIN(deliveryGuarantee,kafkaProducerConfig,transactionalIdPrefix,context,recordSerializer,context.asSerializationSchemaInitializationContext(),Collections.emptyList());}InternalOverridepublic
KafkaWriter(deliveryGuarantee,kafkaProducerConfig,transactionalIdPrefix,context,recordSerializer,context.asSerializationSchemaInitializationContext(),recoveredState);}InternalOverridepublic
SimpleVersionedSerializerKafkaWriterState
KafkaWriterStateSerializer();}VisibleForTestingprotected
在KafkaWriter中snapshotState方法中发现如果deliveryGuarantee
DeliveryGuarantee.EXACTLY_ONCE的开启事务的判断逻辑。
StatefulSink.StatefulSinkWriterIN,
KafkaWriterState,TwoPhaseCommittingSink.PrecommittingSinkWriterIN,
DeliveryGuarantee.EXACTLY_ONCE)
(currentProducer.hasRecordsInTransaction())
Collections.singletonList(KafkaCommittable.of(currentProducer,
producerPool::add));LOG.debug(Committing
producercurrentProducer.commitTransaction();producerPool.add(currentProducer);return
Collections.emptyList();}Overridepublic
DeliveryGuarantee.EXACTLY_ONCE)
getTransactionalProducer(checkpointId
1);currentProducer.beginTransaction();}return
Collections.singletonList(kafkaWriterState);}
KafkaCommitter的commit()方法发现producer.commitTransaction();操作
LoggerFactory.getLogger(KafkaCommitter.class);public
UNKNOWN_PRODUCER_ID_ERROR_MESSAGE
recoveryProducer;KafkaCommitter(Properties
kafkaProducerConfig;}Overridepublic
commit(CollectionCommitRequestKafkaCommittable
committable.getTransactionalId();LOG.debug(Committing
transactionalId);OptionalRecyclable?
committable.getProducer();FlinkKafkaInternalProducer?,
recyclable.FlinkKafkaInternalProducer?,
?map(Recyclable::getObject).orElseGet(()
getRecoveryProducer(committable));---
事务提交producer.commitTransaction();producer.flush();recyclable.ifPresent(Recyclable::close);}
发现除了设置checkpoint还需要kafkasink单独设置.才会实现输出端的开启事务因此在任务1中添加设置setDeliverGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
KafkaSink.Stringbuilder().setBootstrapServers(192.168.65.128:9092).setRecordSerializer(KafkaRecordSerializationSchema.Stringbuilder().setTopic(test002).setValueSerializationSchema(new
SimpleStringSchema()).build()).setKafkaProducerConfig(properties).setDeliverGuarantee(DeliveryGuarantee.EXACTLY_ONCE)
.setDeliveryGuarantee(DeliveryGuarantee.EXACTLY_ONCE).setTransactionalIdPrefix(flink-xhaodream-).build();
再次验证任务任务2依然可以正常消费。
这是有一点头大不明白为什么想到既然开启事务肯定有事务的隔离级别查询了kafka的事务隔离级别有两种分别是读已提交和读未提交默认消费事务是读未提交。
committed此隔离级别保证消费者只能读取已经提交的消息。
这意味着事务中的消息在提交之前对消费者是不可见的。
使用此隔离级别可以避免消费者读取到未提交的事务消息确保消费者只读取到已经持久化的消息。
读未提交Read
Uncommitted此隔离级别允许消费者读取未提交的消息。
这意味着事务中的消息在提交之前就对消费者可见。
使用此隔离级别可以实现更低的延迟但可能会导致消费者读取到未提交的事务消息。
在任务2中添加isolation.levelread_committed设定读取消费事务级别为读已提交再次测试发现任务1执行完checkpoint前任务2消费不到数据。
而命令行可以及时消费任务1的输出topic可可以消费到数据。
结果与预期相同。
Properties();properties1.put(isolation.level,read_committed);KafkaSourceString
KafkaSource.Stringbuilder().setBootstrapServers(127.0.0.1:9092).setTopics(test002).setGroupId(my-group2).setProperties(properties1)
setCommitOffsetsOnCheckpoints(boolean)
总共支持三种不同的语义保证DeliveryGuarantee。
对于
DeliveryGuarantee.AT_LEAST_ONCE
DeliveryGuarantee.EXACTLY_ONCEFlink
的故障发生重复。
DeliveryGuarantee.AT_LEAST_ONCE:
会重新处理旧数据。
DeliveryGuarantee.EXACTLY_ONCE:
的前缀transactionIdPrefix对不同的应用是唯一的以保证不同作业的事务
推荐查看1.14版本和1.18版本结合起来看在一些细节处理上有差异。
如果查看1.18版本源码不太好理解两阶段提交可以查看1.14.5的源码发现FlinkKafkaProducer被标记废除请改用
在1.14.5中TwoPhaseCommitSinkFunction为抽象类有明确定开启事务、预提交和提交的抽象方法比较好理解。
的依赖发现没有直接使用TwoPhaseCommitSinkFunction但是查看源码可以看到使用了commiter和kafkawriter对象
context.metricGroup().addGroup(user);return
KafkaWriter(deliveryGuarantee,kafkaProducerConfig,transactionalIdPrefix,context,recordSerializer,new
InitContextInitializationContextAdapter(context.getUserCodeClassLoader(),
metricGroupSupplier),states);}--
事务提交在kafkaCommitterOverridepublic
OptionalCommitterKafkaCommittable
KafkaCommitter(kafkaProducerConfig));}Overridepublic
OptionalGlobalCommitterKafkaCommittable,
DeliveryGuarantee.EXACTLY_ONCE)
Collections.singletonList(KafkaCommittable.of(currentProducer,
producerPool::add));LOG.debug(Committing
DeliveryGuarantee.EXACTLY_ONCE)
getTransactionalProducer(checkpointId
1);currentProducer.beginTransaction();}return
ImmutableList.of(kafkaWriterState);}1.14.5
版本TwoPhaseCommitSinkFunction是一个抽象类
FlinkKafkaProducer.Semantic#AT_LEAST_ONCE}
FlinkKafkaProducer.Semantic#EXACTLY_ONCE}
org.apache.flink.connector.kafka.sink.KafkaSink}.*/
TwoPhaseCommitSinkFunctionIN,FlinkKafkaProducer.KafkaTransactionState,FlinkKafkaProducer.KafkaTransactionContext
{PrecommittingSinkWriterInputT,
IOException;SimpleVersionedSerializerCommT
getCommittableSerializer();PublicEvolvingpublic
FlinkKafkaProducer继承TwoPhaseCommitSinkFunction会重写其中的方法查看重写开启事务的方法--
FlinkKafkaProducer.KafkaTransactionState
EXACTLY_ONCE:FlinkKafkaInternalProducerbyte[],
开启kafka的procder的事务producer.beginTransaction();return
FlinkKafkaProducer.KafkaTransactionState(producer.getTransactionalId(),
FlinkKafkaProducer.KafkaTransactionState
FlinkKafkaProducer.KafkaTransactionState(currentTransaction.producer);}return
FlinkKafkaProducer.KafkaTransactionState(initNonTransactionalProducer(true));default:throw
UnsupportedOperationException(Not
customPartitioner,FlinkKafkaProducer.Semantic
KafkaSerializationSchemaWrapper(topicId,
serializationSchema),producerConfig,semantic,kafkaProducersPoolSize);}
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback