Confluent connect-jdbc和一次交付

时间:2018-04-23 05:31:46

标签: apache-kafka confluent-kafka

如果将数据库中的主键字段自动递增为递增字段,kafka-connect-jdbc在丢失和重复行方面是否安全?

2 个答案:

答案 0 :(得分:1)

我为此目的进行了分析,并得出结论,使用"递增"带有PK列的模式,除非您正在处理非事务性数据库。这是因为自动递增的PK的序列号在事务期间(执行INSERT时)被分配,但行仅在事务提交时出现,因此它们可能出现乱序。想象一下不那么罕见的情景:

  • 事务A对表执行INSERT并且PK" 1"被分配给该行。
  • 事务B对同一个表执行INSERT并且PK" 2"被分配到那一行。
  • 交易B首先提交
  • 如果连接作业现在执行读取,它将读取行" 2"首先,它会记住" 2"是它读的最后一行
  • 交易A提交第二个,现在只提交行" 1"变得可见。
  • 由于连接作业稍后仅扫描行> 2,行" 1"不会被读。

为了克服这样的错过行,你可以考虑在你的jdbc驱动程序配置中使用DIRTY READ,但是你会看到可能参与后来回滚但不应该被读取的事务的插入。

而不是"递增"我建议你考虑"时间戳"或者"时间戳+递增"模式。 https://docs.confluent.io/current/connect/connect-jdbc/docs/source_config_options.html#mode 并设置" timestamp.delay.interval.ms"适当地配置为不按顺序完成的长时间运行的事务的容差。我无法从经验中说出,如果100%安全,因为我必须处理的数据库不符合ANSI SQL,并且kafka-connect-jdbc的时间戳相关功能不会出现这种情况。工作。

答案 1 :(得分:0)

在自动递增模式下绝对不安全。问题是事务隔离和由此产生的可见性特征-事务开始的顺序(以及它们可能获取的任何自动递增字段的值)与这些事务提交的顺序不同。在混合工作负载中,此问题尤其明显,在这种情况下,事务可能需要花费不同的时间才能完成。因此,作为观察员,您将在表中看到的是可见记录中的临时“空白”,直到这些事务完成为止。如果键0的事务T0在键T1的{​​{1}}之前开始,但1首先完成,则Kafka Connect源连接器将观察T1的影响,发布记录,并将水印前进到键T1。稍后,1最终将提交,但是到那时,源连接器将继续前进。

这是reported issue,并且Kafka Connect文档对已知限制并不透明(尽管自2016年以来KC JDBC团队一直在讨论该问题)。

一种解决方法是使用时间戳记模式(这本身并不安全),并通过T0属性添加延迟。按照Confluent documentation

  

出现具有特定时间戳记的行之后需要等待多长时间,然后才将其包括在结果中。您可以选择添加一些延迟,以允许时间戳较早的事务完成。第一次执行将获取所有可用记录(即从时间戳0开始),直到当前时间减去延迟为止。接下来的每次执行都会从上一次获取数据到当前时间减去延迟。

这(尴尬地)解决了一个问题,但引入了另一个问题。现在,在发生时间戳延迟的持续时间内,源宿将滞后于表的“尾部”(可以说),这是在潜在宽限期内提交潜在事务的机会。宽限期越长,滞后时间就越长。因此,在需要近实时消息传递的应用程序中,这可能不是一个选择。

您可以尝试放宽源接收器查询的隔离级别,但这还有其他含义,特别是如果您的应用程序依靠transaction outbox pattern来保证消息传递。

Kafka Connect的一个 safe 解决方案是采用CDC(更改数据捕获)或等效方法,并将源接收器指向CDC表(按提交顺序)。您可以使用原始CDC或Debezium作为“便携式”变体。这将添加到数据库I / O,但为连接器提供了线性历史记录以供处理。