我有一个基于Spring Boot的KStreams应用程序,在其中我要跨多个主题联接数据。当某个主题出现延迟时,什么是/最好的处理情况?我已经阅读了How to manage Kafka KStream to Kstream windowed join?等链接。
这是我的示例代码(Spring Boot App),用于生成针对2个主题的模拟数据-员工和财务。以下员工主题代码:
private void sendEmpData() {
IntStream.range(0, 1).forEach(index -> {
EmployeeKey key = new EmployeeKey();
key.setEmployeeId(1);
Employee employee = new Employee();
employee.setDepartmentId(1000);
employee.setEmployeeFirstName("John);
employee.setEmployeeId(1);
employee.setEmployeeLastName("Doe");
kafkaTemplateForEmp.send(EMP_TOPIC, key, employee);
});
}
与金融主题类似:
private void sendFinanceData() {
IntStream.range(0, 1).forEach(index -> {
FinanceKey key = new FinanceKey();
key.setEmployeeId(1);
key.setDepartmentId(1000);
Finance finance = new Finance();
finance.setDepartmentId(1000);
finance.setEmployeeId(1);
finance.setSalary(2000);
kafkaTemplateForFinance.send(FINANCE_TOPIC, key, finance);
});
}
与这些记录关联的时间戳类型是 TimeStampType.CREATE_TIME ,我假设它与 事件时间 < / strong>在流中。
我有一个简单的KStreams应用程序,它为财务主题重新设置了密钥,以使财务流密钥与员工流密钥匹配,然后按如下所示进行联接:
employeeKStream.join(reKeyedStream,
(employee, finance) -> new EmployeeFinance(employee.getEmployeeId(),
employee.getEmployeeFirstName(),
employee.getEmployeeLastName(),
employee.getDepartmentId(),
finance.getSalary(),
finance.getSalaryGrade()),
JoinWindows.of(windowRetentionTimeMs), //30 seconds
Joined.with(
employeeKeySerde,
employeeSerde,
financeSerde)).to(outputTopic, Produced.with(employeeKeySerde, employeeFinanceSerde));
如果在财务主题中,具有匹配键的记录在30秒后到达,则不会发生联接。关于如何解决此问题的任何见解都将有所帮助。预先谢谢你。
P.S .:此数据是虚构的。如果它与您的部门ID /薪水相符,则仅是巧合。 :)
答案 0 :(得分:0)
如果在财务主题中,具有匹配键的记录在30秒后到达,则不会发生联接。
默认情况下,Kafka Streams使用24h宽限期,因此,即使有滞后或无序的数据,您的加入也应该起作用。请注意,Kafka中的 lag 始终引用 read 路径!
30秒钟后到达金融主题
但是,我认为您并不是真的有 lag 滞后(从某种意义上说,您回读了),但是上游的 write 被延迟了-在这种情况下,事件时间可能分配不正确:
请注意,在写入Kafka主题且您未明确指定时间戳时,生产者将在调用send()
时分配时间戳,而不是在创建ProducerRecord
实例时分配时间戳。如果要在创建ProducerRecord
时分配时间戳,则需要将要分配的时间戳手动传递到构造函数中(不确定Spring Boot是否允许您执行此操作)。
作为替代方法(以防万一您无法显式设置记录时间戳),可以将时间戳嵌入值中(当然,这需要您更改Employee
和Finance
类。这些数据可以通过Kafka Streams使用,您可以在自定义TimestampExtractor
中使用它来获取自定义时间戳,而不是记录时间戳。