如何将AI能力与大数据技术结合,助力数据分析治理等工作的效率大幅提升,优化大数据引擎的性能及成本? 了解详情
写点什么

大促突围:京东到家基于 Canal 的数据异构设计

  • 2021-05-14
  • 本文字数:5906 字

    阅读完需:约 19 分钟

大促突围:京东到家基于Canal的数据异构设计

今天的内容分享将主要包含以下四个方面:

  • 介绍京东到家的订单履约业务背景

  • 在业务背景的基础上说明订单的底层存储方案

  • 基于存储方案的数据异构设计与实践

  • 面向复杂度的架构设计方法论


简单来看,面向复杂度的架构设计方法论与上面 3 个部分没有直接关系,把这部分内容放到文章中来讲,主要是因为数据异构本质上也是解决了软件的写入复杂度问题。在这个基础上,我们向上抽象一层,来讨论一下面向复杂度的架构设计方法论。

一、京东到家订单履约业务背景


从用户提交订单到服务履约系统,我们大致经历了支付、下发商家、商家确认、订单打印、拣货、下发物流、配送、妥投等环节。这是一个基本的新零售履约流程。这里,我标蓝了一些流程。比如:下发商家、订单打印等环节。主要是因为这些环节是我们要和商家交互的功能点,当我们把订单下发给商家时,首当其冲的环节是商家要确认这个订单,并且开始履约流程。但是,在我们的实际业务中,商家在大促期间往往会出现履约瓶颈,忙到看不到我们下发的订单,甚至不忙的时候也会看不到我们的订单已经下发到他们的系统中,商家需要一个提示功能。这也就是我们的提示音需求。


提示音需求需要不断的查询底层存储 ES,并提示给商家有订单到达了,需要他们去履约,如果商家没有看到,就不断查询,不断提示。就是这样的一个循环查询量级,在大促期间,订单量级增大,查询量级增大。基本上每次大促都会把我们的 ES 查到 CPU 飙高,甚至出现不可用的情况。为了保护履约系统,我们做的临时方案是做一个功能开关,在大促期间对提示音功能降级。可是这样的降级并不是我们想要的。因为最终商家还是收不到提示。导致履约质量下降。于是我们就面临一个问题“存储组件无法支撑大促时提示音业务的查询请求量。

二、底层数据源的职责分工


要解决我们面临的查询量级问题,就必须首先分析一下底层的存储方案。以上,是我对到家订单履约系统底层存储的一个整体概括。

1.Redis

Redis 在履约系统中主要承载的一个职责是 worker 跑批任务的存储和查询。因我们在系统中大量运用了跑批任务来实现最终一致性的一个设计,而 Redis 的 Zset 结构正好满足了这样的需求,将时间作为分值,不断的提供近期任务的查询是 Redis 充当的根本职能。这里解释一下 Redis 为什么没有承载过多的查询职能。Redis 虽然性能更好一些,但是,在数据量和查询复杂度上,没有 ES 支持的好,关键点是我们的查询条件复杂度是比较高的,所以,Redis 没有承载过多的查询职能。

2.MySQL

MySQL 在履约系统存储中的职能是持久化存储订单数据,这里主要还是使用其强大的事务机制,以保障我们的数据是正确写入的。这是其他的两个组件所不支持的。


从履约流程上来看,我们将数据做了冷热分离,热点数据是我们在履约中的订单(也就是未完成的订单),而完成的订单,由于其使用率不会太高,所以,我们称之为冷数据。这样的一个拆分也就是上图中对应的业务库和历史库。业务库是热库,而历史库则是冷库。这样的一个冷热分离思想,使我们的单库单表数据量级维持在千万级别。从而避免了对应的分库分表复杂度。


从部署架构上看,我们对业务库进行了大量的主从分割。其中 biz slave 是我们的业务库从库,它也会承载一些履约中的订单查询职能。接下来的 big data slave 集群则是大数据抽数据用做统计分析。最后的 delay slave 设置延迟一定时间消费 binlog 则是为了防止 master 被误操作而兜底的。比如有人错误执行了删除 db 的命令,这样的一个延迟消费的机制就可以利用 binlog 进行兜底回滚。

3.Elasticsearch

ES 在数据存储中承担了几乎所有的查询职责,这主要取决于它支持复杂查询,并有天然分布式的特点。在数据量复杂度解决方案上,避免了 MySQL 分库分表的复杂度。这里我们一共有 3 个 ES 集群。其中 HOT ES 和 Full ES 也是进行了冷热分离,这样对我们的查询流量进行拆分。有助于保证履约系统的稳定性。


而第三套集群 Remind Elastic Cluster 则是为了解决我们上述提示音的问题。在有提示音集群之前,我们所有的提示音查询流量都是打到热集群的。也正是这样的一个访问量需求,导致了我们的热集群时有发生 CPU 飙高,接口响应缓慢,卡顿业务线程。所以,我们对热集群进行了进一步的拆分,于是就正式提出了提示音单独集群的方案。

三、写入复杂度问题


当确定冗余一套提示音集群以后,我们面临的问题就是上述这样的一个写入复杂度问题,从图上来看,我们在拆分这套集群之前,订单中心每次操作一次订单写入。面临的是 3 个数据源的写入工作,这对研发人员是非常不友好的,维护难度过大。于是,我们就开始考虑用异构中间件的方式来去写入这套 ES 数据。


异构中间件的优势是屏蔽了数据同步的复杂度,但是随之而来的是数据写入链路可靠性、及时性等问题。而且,数据传输本身一般都具有高可用的需求,之前高可用在业务应用上,因为业务应用的集群方式本身是计算高可用的。但异构中间件则要在这高可用、可靠性、及时性三个维度上满足我们的要求。

四、数据异构产品选型


在上述分析之后,我们也陆续调研了一些异构产品,在数据类型支撑上没有太大差别,常用的存储组件,这些异构中间件都是支持的。所以,我们更在意以上 3 个指标。社区活跃度代表了后续的维护性以及开源产品快速的问题响应,可用性方面的需求是非常强烈的,最终采用 Canal 的根本原因还是在学习成本和熟练度上。

五、Canal 简介

这里简单说一下我对于 Canal 的理解,以便于后续有意向应用 Canal 的同学有一个简单的了解。



Step1 Load&Store: Connection 从 Zookeeper 获取到当前消费的 binlog filename 和 position 信息。随后将该信息附带到 dump 协议里,mysql master 开始推送 binlog 数据。Binlog 经过 Parser 解析投递到 Sink,Sink 则承载了过滤消息的作用,过滤掉没有订阅的 binlog 事件,最终把消息存储到 Store 中。


Step2:Send&Ack:用任务 worker 的方式,不断扫描 store,最终将 store 中的数据发送到目的地,目的地可以是具体的存储,也可以是 mq 产品。图中,我用了 kafka 也主要是因为我们的实践方案。投递消息完成之后将消息 ACK 给 Store 组件。


Step3:Update MetaInfo:这个时候数据虽然发送了。但是,我们的元信息 binlog 的 filename 和 position 仍然没有更新,在这个操作上,Canal 仍然采取了异步的方式去同步该信息。


Canal 这种异步通信的设计要求你的系统必须具备可回溯、重试、幂等、延迟特点。


以上,是我对整个 Canal 的一个理解,图中的两个 HA,后续将会和大家说到。这里,我讲 Canal 的工作的角色、运作规则都是从一个 4R 视角来说明的,这是为了后续来讲复杂度方法论的时候大家也好理解一些。

六、提示音功能基于 Canal 数据异构实践


提示音异构生产部署方式如上图。我们部署了两台 Deployer 用于数据传输的高可用。同时把消息投递到了 kafka,利用 adapter 的集群部署进行批量消费,插入到提示音集群的 ES 中。


在顺序性保障上采用了订单 id hash 的策略,保证在 partition 上是有序的。这样也就保证了在业务操作上是整体有序的。


在链路上采用 kafka 来传输,主要还是应对大促期间 binlog 数据量级的特点,保证插入到 ES 之前有缓冲 buffer 的一个作用。这也是直连方式的弱点,直连方式在大数据量短时间写入时,对目的地存储组件有可能会造成瞬间的大量插入,从而损耗目的地存储组件的资源,可能影响到业务使用。但是,长链路也有数据延迟的缺点,如果对数据时效要求比较高的业务。还是建议用直连方式来搭建对应的异构方案。


在 META Manager 上使用 Zookeeper 来存储,与 Deployer 的 HA 形成有效配合。


问题一:(网络环境问题)kafka 不可用



在实践中,我们遇到第一个比较有代表性的问题是 kafka 集群不可用,直接导致 ES 数据断层,从而影响到商家的履约体验。


首先,kafka 集群所在的网络环境和机器主机发生问题,deployer 的 store 数据存满,直接导致 delay 了 8 个小时。提示音没有提示,也会有电脑端的管理系统同步订单,但是需要人工刷新,所以,过了很久我们才发现这样一个问题。紧急把访问切到之前的 ES 热集群,之后,我们重新把 kafka 服务部署到可用状态,数据虽然慢慢追上了,但是原来在 kafka 中没有被 adapter 消费的一部分数据却丢掉了,这主要还是因为设置的 kafka 落盘频率问题。



丢数据在数据异构的需求中是不可容忍的事情,索性这次事故基本上锁定了丢数据的原因,所以,我们将 Zookeeper 中的 jouralName 和 position 设置到对应的事故之前的位置,将数据重新跑到 ES 中,至此问题解决。


  • 总结一


  • 总结二



至此,总结以上两点,数据异构的实践在问题监控、报警、及时降级方面是非常重要的。希望这样的总结经验能够让大家少走弯路。


问题二:Deployer 故障,自动 HA



Deployer 机器发生故障,系统自动 HA 到备机,任务得以继续消费。总起来说,问题二并没有给我们的业务带来任何的损耗,但是,还是比较经典的一个案例。这主要反应出来,对于数据异构这样一个需求。它的链路上所有环节,基本上都是有高可用的要求的。



Canal 一共提供两种 HA,其中 Deployer 的 HA 是靠 Zookeeper 的临时节点和重试机制实现的,而 Mysql 的 HA 则是靠一个单独的线程不断的 Detect 来实现的。


但是 MySQL 的 HA,只能用 GTID 的模式,这是因为 Mysql master 和 slave 的 binlogfile name、position 是不一样的。如果用 master 的 binlogfilename 和 position 去 slave 发送 dump 协议,这会出现无法匹配的问题。但是 GTID 是全局有序的,这也就保证了 Mysql 的 HA 只在 GTID 模式下才可用。



谈到高可用,提出上述总结。这里我与大家互动了一个问题:“单机器部署两台 Canal 实例是否算是高可用?”答案是:“不算高可用,原因是单机部署了两台 Deployer,但是机器如果故障,两台 Deployer 均不可用。”


问题比较有代表性,也有一些同学掉进了坑里。这里我与大家一起回顾一下高可用的范围:多机器、多机房、多地区、多国家。范围越大,高可用自然越是稳定。但是带来的成本和数据传输要求也越高,一般都是根据业务量级和重要程序进行取舍的。


  • 总结三



以上就是我在数据异构中的一些经验教训。下面我们将问题向上抽象,聊一聊面向复杂度的架构设计方法论。

七、面向复杂度的架构设计方法论

1.4R 模型


大家是否发现,我在和大家聊 Canal 或是到家的数据异构方案时,更多的都是以角色、关系、规则这种描述方法。相信大家也不是第一次碰到这种描述方式,在很多的架构中,都是这样的一种描述方法。就像上图中,说到的 Parser、Sink、Store。这些角色的职责是什么?他们是如何配合完成 Canal 这样的一个产品功能的呢?


4R 模型本质上就是一个视角,它是 Rank、Role、Relation、Rule 这 4 个单词的首字母构成,它强调了描述方法、也强调了我们要用这样的视角来看待我们的系统。这样整体来看,系统会更加清晰和简洁。

2.区分复杂度


如上图,将复杂度问题分为技术方向和业务方向两个部分,其中灰色的部分,一般都有一些开源软件来帮我们解决,比如 Dubbo、Spring、Canal 等。而红色的部门正是我们日常工作中所不能避免的复杂度。


这些复杂度问题,如果平时不加以重视,忽视掉的复杂度问题最终则会演变成为不可维护的技术债务,最终打掉系统的可维护性,只能重新推倒重来了。很多重构行为都是因为复杂度的忽视累积而成的后果。所以,学会如何区分复杂度就是比较重要的点了。比如这次 Canal 的数据异构,同时面临了数量级复杂度和写入复杂度两个。

3.复杂度的架构设计环


同样,面向复杂度的架构设计方法论,最终会归结到业务实现上。下面描述一下具体的步骤含义:


  • 1-需求:产品同学提出需求描述,或一句话需求、或完善的 PRD 文档


  • 2-判断:对需求进行判断,需要什么样的数据量,什么样的峰值,是否要高可用等等,如果不能理解清楚,则找对应的需求人员不断澄清,直到清晰为止


  • 3-复杂度识别:将需求精确化以后,对需求的复杂度问题进行识别,比如业务复杂度问题、数据量复杂度问题


  • 4-拆解到备选架构:针对识别出来的复杂度设计出多个具体的架构方案。比如采用 ES 存储数据屏蔽分库分表的数据量复杂度、采用数据异构的方式写入数据,从而屏蔽数据写入的复杂度。


  • 5-取舍:对备选架构进行取舍,任何的架构方案都有好的一面和坏的一面。在不同的时间都有不同的选择,这里建议大家从简单、合适、演进三个架构原则来进行方案取舍,选择最适合自己的那一套方案。


  • 6-架构方案 4R:用 4R 视角来设计系统分层、角色、关系、规则。以这种视角设计出来一套抽象模型


  • 7-实现需求:将 4R 架构模型实践即可。



同样,将本需求的一个架构设计环案例呈现给大家。(由于部分设计有保密性,4R 此处用 Canal4R 代替)


以上,就是我和大家分享的全部内容啦,谢谢大家!

Q&A

Q1:订单表中,如果有一些商品 id,那么同步到 ES 中也是 id 吗,不会关联出 name 打成宽表存到 ES 吗?

A1:具体的映射字段需要在 Adapter 中配置映射即可,存入到 ES 中的情况也与配置的映射是直接且唯一关系。是否宽表要在实际应用中把控字段的个数。


Q2:Canal 部署 deploy 主从和 canal-adapter 有没有遇到官方的 bug?有,改动了哪些?

A2:遇到过 Column not match 的异常.具体看 Canal 的 TSDB 来解决。


Q3:这套复杂度方法论如何落地到实际应用?

A3:需要对系统进行 4R 视角拆分、识别复杂度类型并按照架构设计环的方式来评定需求。


Q4:平时的 Canal 有消息延迟吗?

A4:有一定延迟的,binlog 的数量、网络等因素,都会造成一定的延迟,所以,建议异构还是要建立在业务数据可延迟的基础上的。


Q5:我主要用 canal-adapter 读取 Kafka 中的 binlog 日志然后写到数据库中,Kafka 中有多个表的日志,我 rdb 目录下的 yml 文件只配置了一个表的为什么其他的表也会同步?

A5:Yml 的作用是配置映射关系,具体的过滤职能在 Deployer 的 Sink 配置。


Q6:异构数据是直接同步原表吗,还是做了关联?

A6: 做了关联,直接在 Adapter 中配置对应映射关系即可。


Q7:请问为什么不直接增加热集群的节点和分片,而是重新建一套 ES 集群呢?

A7: 这里主要还是一个数据拆分的思想,如果通过提高配置来解决访问量问题,那么,随着业务量级增加,流量混在一起,对应的 ES 集群流程会呈现不可评估的情况。本质上还是一个数据存储职责的问题。


Q8:如何保证 Zookeeper 的高可用?

A8: Zookeeper 本身就是高可用的,如果想在机房或异地方面做高可用,建议做主备同步、多集群部署等手段。


Q9:新集群的查询请求峰值是多少?

A9: 大约 2000-4000 QPS。


Q10:怎么把握冗余尺度呢?

A10: 冗余的维度在机器、机房、地区、国家是不断增加的。维度越大,对应的高可用方案越可靠,但是,对应的费用以及实现复杂度也会变高。因为这种冗余方案肯定会有数据 copy。


嘉宾介绍:

张磊,京东到家高级研发工程师。

  • 8 年+软件研发经验,曾先后就职于链家地产、互动吧、寺库网等公司,任研发人员或团队 leader,在解决业务系统设计落地方面拥有丰富经验;

  • 现就职于达达-京东到家,主要负责订单履约、金额拆分、计费相关业务域的研发设计工作。业余时间主攻软件复杂度优化。


本文转载自:dbaplus 社群(ID:dbaplus)

原文链接:大促突围:京东到家基于Canal的数据异构设计

2021-05-14 08:001885

评论

发布
暂无评论
发现更多内容

2022-09-07:给你一个由正整数组成的数组 nums 。 数字序列的 最大公约数 定义为序列中所有整数的共有约数中的最大整数。 例如,序列 [4,6,16] 的最大公约数是 2 。 数组的一个

福大大架构师每日一题

算法 rust 福大大

通过Jenkins构建CI/CD实现全链路灰度

阿里巴巴中间件

阿里云 云原生 jenkins 全链路灰度

C++学习------clocale头文件的源码学习

桑榆

c++ 源码阅读 9月月更

构筑校园防线  “云资环”助力精准防控

神奇视野

揭秘 · 机器人酒店

澳鹏Appen

人工智能 nlp 语音识别 数据标注 语音标注

mysql存储引擎

周杰伦本人

9月月更

云备份服务CBR

创意时空

给我一起学jdbc之sql注入

楠羽

JDBC 笔记 9月月更

概述大数据技术在智能运维中四大挑战

穿过生命散发芬芳

智能运维 9月月更

如何让百度搜索结果显示网站 logo

源字节1号

网站建设 网站开发

JAVA StreamAPI

流火

Stream API java 8 的新特性

一起玩转!SOFA 飞船 Layotto 星球登陆计划

SOFAStack

golang 微服务 云原生 新手指南 开源软件

面试突击81:什么是跨域问题?如何解决?

王磊

Java 面试

SLO新解,一种行之有效的故障处理方法

华明

监控系统 SLO 稳定性保障

程序员成长那些事儿

图灵教育

程序员 进阶 代码 计算机

SD-WAN网络编排原理

阿泽🧸

9月月更 网络编排

2022年中国新能源汽车用户体验指数(UEI)

易观分析

新能源汽车 UEI

程序员成长那些事儿

图灵社区

程序员 进阶 代码 计算机

「趣学前端」来逛逛数字博物馆

叶一一

小程序 前端 9月月更

人工智能、机器学习和深度学习,到底有什么区别?

Finovy Cloud

人工智能 云计算 影视渲染

【译】像CSS一样在Flutter里应用滤镜效果

iofod jude

「趣学前端」关于iframe跨域通信

叶一一

前端 iframe 跨域 9月月更

关于C语言结构体(struct),你不知道的用法?(初阶篇)

Albert Edison

指针 C语言 结构体 9月月更

英特尔oneAPI工具大幅提升腾讯云数据库MySQL的性能

科技之家

SpringBoot源码 | prepareEnvironment方法解析

六月的雨在InfoQ

源码 springboot 源码刨析 SpringBoot实战 9月月更

每日一R「22」内存:堆与栈

Samson

学习笔记 ​Rust 9月月更

Unity 关于低版本是否可以引用高版本构建内容的可行性验证

CoderZ

C# dll Unity3D 9月月更

极狐GitLab CI 月来袭!2小时 get CI 流水线设计秘籍

极狐GitLab

DevOps gitlab 运维 CI/CD 持续交付

一文讲透B端和C端产品经理的区别

产品海豚湾

产品经理 SaaS 职业发展 B端产品 9月月更

大促突围:京东到家基于Canal的数据异构设计_架构_dbaplus社群_InfoQ精选文章