当数据库中的主键字段自动递增为递增字段时,kafka connect jdbc在丢失和重复行方面是否安全?
fcg9iug31#
在自动递增模式下是绝对不安全的。问题是事务隔离和由此产生的可见性特征—事务开始的顺序(以及它们可能获取的任何自动递增字段的值)与这些事务提交的顺序不同。这个问题在混合工作负载中尤其明显,在混合工作负载中,事务可能需要不同的时间才能完成。因此,作为一个观察者,您将在表中看到的是可见记录中的临时“间隙”,直到这些事务完成。if事务 T0 键0在 T1 带钥匙 1 ,但是 T1 先完成,Kafka连接源连接器将观察到的效果 T1 ,发布记录并将水印提前到密钥 1 . 稍后, T0 最终将提交,但此时源连接器将继续。这是一个已报告的问题,kafka connect文档对于已知的限制并不透明(尽管该问题自2016年起就向kc jdbc团队公开)。一种解决方法是使用时间戳模式(它本身并不安全),并通过 timestamp.delay.interval.ms 财产。根据合流文件:在具有特定时间戳的行出现之后,我们需要等待多长时间才能将其包含在结果中。您可以选择添加一些延迟,以允许时间戳较早的事务完成。第一次执行将获取所有可用记录(即从时间戳0开始),直到当前时间减去延迟。接下来的每一次执行都将获得从上次获取到当前时间减去延迟后的数据。这解决了一个问题(尴尬),但引入了另一个问题。现在,在时间戳延迟的持续时间内,源-接收器将落后于表的“尾部”(也就是说),潜在事务在该宽限期内提交的可能性很小。宽限期越长-滞后时间越长。因此,在需要近实时消息传递的应用程序中,这可能不是一个选项。您可以尝试放宽源-接收器查询的隔离级别,但这会带来其他影响,特别是当您的应用程序依赖于事务发件箱模式来保证消息传递时。使用kafka connect的一个安全解决方案是使用cdc(changedatacapture)或等效工具,并将源接收器指向cdc表(将按提交顺序)。您可以使用原始的cdc或debezium作为“便携”变体。这将添加到数据库i/o,但会给连接器一个线性历史记录。
T0
T1
1
timestamp.delay.interval.ms
bihw5rsg2#
为此,我对它进行了分析,并得出结论,除非您处理的是非事务性数据库,否则对pk列使用“递增”模式是不安全的。这是因为自动递增的pks的序列号是在事务期间(执行insert时)分配的,但行仅在事务提交时出现,因此它们可能会出现无序。想象一个并不罕见的场景:事务a向一个表插入数据,并将pk“1”分配给该行。事务b向同一个表插入数据,并将pk“2”分配给该行。事务b首先提交如果connect作业现在执行读取,它将首先读取行“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%安全,因为我必须处理的数据库不符合ansisql,kafka connect jdbc的时间戳相关特性也不起作用。
2条答案
按热度按时间fcg9iug31#
在自动递增模式下是绝对不安全的。问题是事务隔离和由此产生的可见性特征—事务开始的顺序(以及它们可能获取的任何自动递增字段的值)与这些事务提交的顺序不同。这个问题在混合工作负载中尤其明显,在混合工作负载中,事务可能需要不同的时间才能完成。因此,作为一个观察者,您将在表中看到的是可见记录中的临时“间隙”,直到这些事务完成。if事务
T0
键0在T1
带钥匙1
,但是T1
先完成,Kafka连接源连接器将观察到的效果T1
,发布记录并将水印提前到密钥1
. 稍后,T0
最终将提交,但此时源连接器将继续。这是一个已报告的问题,kafka connect文档对于已知的限制并不透明(尽管该问题自2016年起就向kc jdbc团队公开)。
一种解决方法是使用时间戳模式(它本身并不安全),并通过
timestamp.delay.interval.ms
财产。根据合流文件:在具有特定时间戳的行出现之后,我们需要等待多长时间才能将其包含在结果中。您可以选择添加一些延迟,以允许时间戳较早的事务完成。第一次执行将获取所有可用记录(即从时间戳0开始),直到当前时间减去延迟。接下来的每一次执行都将获得从上次获取到当前时间减去延迟后的数据。
这解决了一个问题(尴尬),但引入了另一个问题。现在,在时间戳延迟的持续时间内,源-接收器将落后于表的“尾部”(也就是说),潜在事务在该宽限期内提交的可能性很小。宽限期越长-滞后时间越长。因此,在需要近实时消息传递的应用程序中,这可能不是一个选项。
您可以尝试放宽源-接收器查询的隔离级别,但这会带来其他影响,特别是当您的应用程序依赖于事务发件箱模式来保证消息传递时。
使用kafka connect的一个安全解决方案是使用cdc(changedatacapture)或等效工具,并将源接收器指向cdc表(将按提交顺序)。您可以使用原始的cdc或debezium作为“便携”变体。这将添加到数据库i/o,但会给连接器一个线性历史记录。
bihw5rsg2#
为此,我对它进行了分析,并得出结论,除非您处理的是非事务性数据库,否则对pk列使用“递增”模式是不安全的。这是因为自动递增的pks的序列号是在事务期间(执行insert时)分配的,但行仅在事务提交时出现,因此它们可能会出现无序。想象一个并不罕见的场景:
事务a向一个表插入数据,并将pk“1”分配给该行。
事务b向同一个表插入数据,并将pk“2”分配给该行。
事务b首先提交
如果connect作业现在执行读取,它将首先读取行“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%安全,因为我必须处理的数据库不符合ansisql,kafka connect jdbc的时间戳相关特性也不起作用。