本文主要介绍了自己近两个月重构产品推荐引擎后端的实时数据流同步架构,抛弃了之前的 Spark Streaming, 选择了基于 Kafka Stream 以及 Kafka Connect 做一些轻量级的实时 ETL.
数据流同步架构
+-------+ +---------------+
| Redis +<-+ +->+ Elasticsearch |
+-------+ | | +---------------+
| |
| |
| |
+--------------+ +----+---+------+
+---+ Kafka Stream | | Kafka Connect |
| +------+-------+ +-------+-------+
| ^ ^
| | |
| | |
| +-----+------------------+------+
+--->+ Kafka |
+---+--------------------+------+
^ ^
|Maxwell |
| |
+---+----+ +-------+------+
| binlog | | tracking log |
+----+---+ +--------------+
^
|
|
+---+---+
| MySQL |
+-------+
binlog 到 Kafka 工具选型,maxwell vs canal
从数据的生产者来看,我们的数据源主要由产品数据库 MySQL(binlog) 和前端用户行为日志埋点两部分构成。binlog 到 Kafka 我选用了 zendesk/maxwell 而不是国内使用较多的 alibaba/canal. 原因主要是因为我们的产品库目前还比较单一,maxwell 使用和部署比较简单,而且能以已经解析好的 schema 数据进入 Kafka, 这对后面对接的 Elasticsearch 非常友好。新版的 canal 其实也具备了直接生产到 Kafka 和 Elasticsearch 的能力了,但就到 Kafka 这一环来说,canal 在使用上还是有一些不便利的地方,maxwell 在一些细节上更为便利些。但是需要注意的是,maxwell 在生产环境上需要自己定制 HA 方案,就我们的实测发现,产品起步阶段的量级用 maxwell 毫无压力。
Kafka Stream, 实时 ETL 的好工具
国内 Kafka Stream 的文档相对还是不多的,Kafka 官网和 confluent 的文档比较详细,可以读一读。在尝试 Kafka Stream 之前,因为自己对 Spark 熟悉一些,尝试了 Spark Streaming 作为实时数据同步任务。使用过程中我们发现一些痛点:
- Spark 开发起来太重了,对小团队有较高的使用成本
- CICD 融入 K8S 比较困难,开发迭代较慢
- 资源消耗高,不适合小公司/初创公司
在读了一些 Kafka Stream 的文档后,我首先写了一个 kafka-stream-filter
作为 binlog 到 Kafka 的路由分发器。觉得确实和文档里说的一样,非常轻,使用 Kafka Stream 只需要像其它普通库一样使用,但是可以完美结合 Kafka 的水平 scale 能力,没有水平扩展的压力。部署上,我可以像普通 Java 应用一样部署在 K8S 上,运维管理上比较统一。资源上也能节约不少,测试环境上数据量小一点的内存分配 500MB 以内足够了。
Kafka Stream 的定位并不是一个 ETL 的全能工具,它聚焦在以 Kafka 为核心的 ETL, 数据输出也通常在 Kafka 的其它 topic 中。
Kafka Connect, 沟通 Kafka 和其它存储系统的桥梁
如果说 Kafka Stream 可以专注于实时 ETL 并将数据存储在 Kafka 中,那么 Kafka Connect 解决的问题则是如何将 Kafka 和外部存储系统对接了。官方的 Kafka Connect 已经为我们准备好了很贴心的同步框架,容错、任务数扩展等都比较完善。即使自己从头开发,开发成本也不算高。后文我会开源自己设计的 kafka-connect-redis
和 kafka-connect-elasticsearch
. 同步协议上参考了 maxwell, 有点类似 Event Sourcing.