我最近致力于基于Apache Kafka的水平可扩展和高性能数据摄取系统。目标是在文件到达的几分钟内读取,转换,加载,验证,丰富和存储风险源。系统收到银行上游风险提要并处理数据以计算和汇总多个风险提供系统和运行的运行信息。
性能SLA限制执行数据到流的验证,转换和丰富,并排除任何批处理。
本文介绍了我在项目中采用的方法。
第一个决定是使用Apache Kafka并将传入的文件记录流式传输到Kafka。
Apache Kafka被选为底层分布式消息传递平台,因为它支持高吞吐量线性写入和低延迟线性读取。它结合了分布式文件系统和企业消息传递平台的功能,非常适合存储和传输数据的项目。
Kafka的扩展能力,弹性和容错能力是集成的关键驱动因素。
链式拓扑中的Kafka主题用于提供可靠,自平衡和可扩展的摄取缓冲区。使用一系列Kafka主题来存储中间共享数据作为摄取管道的一部分被证明是一种有效的模式。
传入的风险源以不同的形式提供给系统,但本文档将重点关注CSV文件源负载。系统读取文件源并将分隔的行转换为AVRO表示,并将这些AVRO消息存储在“原始”Kafka主题中。
内存和存储方面的限制要求我们从传统的XML或JSON对象转向AVRO。AVRO被选为数据格式的原因有很多:
与远程调用数据库相反,决定使用本地存储来使数据处理器能够查询和修改状态。我们为处理引擎提供了本地Redis数据存储,用于在数据流通过这些组件时丰富数据。因此,通过提供快速的本地商店来丰富飞行中的数据,我们能够提供更好的性能。
自定义富集组件处理来自上游“原始”Kafka主题的传入数据,查询其本地存储以丰富它们并将结果写入下游Kafka主题“丰富”以进行验证。
选择Redis作为参考数据存储的原因:
该系统具有以分布式方式运行的多个处理器,并且每个节点都需要可靠的本地缓存。
每行数据都通过适用的验证规则传递。我们实现了模式DSL,使系统能够使用谓词逻辑定义验证规则。所有常见的逻辑运算符(AND,OR,EQUAL,NOT EQUAL,IN RANGE,NULL,NOT NULL)与一些自定义运算符(LOOKUP)一起得到支持。
数据验证过程取决于特定条件,实现的模式具有验证规则和条件映射。
验证规则是根据数据类型动态构建的,并应用于数据。并收集验证错误并将其发送到异常服务。
使用跨越多个JVM的原子计数器记录数据验证成功或失败。
系统的职责是通知文件,切片和运行级别的风险运行处理完成情况。那么,我们如何才能实现这一目标呢?事件管理器组件负责此任务。该组件负责跟踪通过不同阶段(加载,验证等)的预期和实际记录数量。一旦舞台计数器相同,舞台就被标记为完整。
如果计数器不一样怎么办?事件管理器实现了时间窗口的概念,在该时间窗口之间进程寻找计数器。一旦时间窗口过去,如果阶段尚未设置为完成,则该阶段被标记为失败。
叶节点状态有助于确定其父节点状态; 例如,属于切片的文件状态确定了切片的状态。
参考数据包括许多不同的数据集,一些是静态的,另一些是动态的。这些数据集在Redis中提供,并在不同频率上刷新(新风险运行切片到达时,源系统中的新数据或每日基础)。
数据处理器必须等待缓存实体的可用性才能处理流。
要求是为风险运行应用特定版本的参考数据集。这需要在不扩展内存要求的情况下实现版本控制。数据集存储在内存中,以避免缓存未命中和访问文件系统。
Redis的有序集数据结构用于存储带有分数的记录,该分数是数据添加到缓存时的时间戳。有序集合中的平均大小写插入或搜索是O(N),其中N是集合中元素的数量。下面提供了Redis排序集数据的直观表示:
+-------------------+
| KEY |
+-------------------+
+---------------+ +-------------------+
| SCORE | | UNIQUE MEMBER 1 |
+---------------+ +-------------------+
+---------------+ +-------------------+
| SCORE | | UNIQUE MEMBER 2 |
+---------------+ +-------------------+
+---------------+ +-------------------+
|… | | … |
+---------------+ +-------------------+
需要每个流处理来维持处理状态。在这种情况下,我们有一个分布在多个节点上的处理引擎。因此,处理状态在这些节点之间共享。现在所有节点都能够修改相同的状态,我们需要确保多个节点不应该最终覆盖彼此的更改。
这是Redis中的分布式锁实现对于效率和准确性至关重要。系统存储了所有共享计数器,用于跟踪Redis中的进程。由于Redis是单线程的,因此每个操作都是原子的。Redis中的INCR操作是一个原子操作,它返回递增的值并确保不同的进程不接管相同的密钥。
原文标题《System Design on Kafka and Redis》
译者:February
不代表云加社区观点,更多详情请查看原文链接
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系外文翻译,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。