背景

交易系统可能不是技术难度最深的,但是业务复杂度最高的,一个订单从提交到最后真正生产成功要经历几十个系统,涉及的接口交互,MQ等可能达上百个。任何一个环节出问题都会导致这一单的异常,而且交易不像单纯的资讯门户可以靠静态化或者缓存抗住大并发,交易系统里面涉及到大量的资源(库存,优惠券,优惠码等)消费,订单生成等需要写入持久化的操作不是单纯的异步或者缓存化可以解决的,而且对库存等敏感信息不能出现并发扣减等。

细节的设计非常多,下面挑出比较典型的一些方面,给大家介绍下京东到家交易系统的架构设计和关键问题的处理方案。

历程

系统Set化

初期的订单系统和首页,单品页,购物车业务逻辑层等都是在一个大项目里。非常适合初期人员少,业务复杂度低,快速迭代,不断探索试错的过程,但是随着业务的发展,出现了以下问题:

  • 系统的流量和业务复杂度也越来越大,大家共用一个大项目进行开发部署,相互影响,协调成本变高;

  • 不同的业务模块,流量和重要级别不同需要的部署策略和容灾降级限流等措施也不一样,要分而治之;

解决方案
项目Set化,这个过程中要注意Set化的边界问题,粒度太大了效果不好,太小了设计过度了,反而会增加维护和开发成本;

分库分表

问题
随着订单的并发量的不断攀升,特别是在双十一,618等大促的时候,单组DB(一主多从)存在着明显的压力,单个主库的连接数是有限的。大单量,大并发的时候,数据库越来越成为了我们的瓶颈。

解决方案
针对接单数据库我们采取的常规做法分库,根据订单号进行Hash分布到不同的多个数据库中,代码方面我们是继承了Spring的AbstractRoutingDataSource,实现了determineCurrentLookupKey方法。对业务代码只有很少的耦合。

另外下发到个人中心数据库的订单信息,每天不断的累计到DB中,存在以下风险:

  • MySQL的单表容量超过单机限制

  • 穿透缓存到达DB的数据查询也是非常有问题的。

目前我们采取对个人中心的表按照pin进行分库分表。
但是对于后端生产系统对于订单数据的查询操作,特别是涉及到多条件组合的情况,由于数据量大,多个表数据的关联,无论分不分表或者读写分离对这个场景都不能很好的解决。

这种场景下我们采用了ES,在写入DB的时候同步写入ES。你可能会问ES失败了,数据不一致怎么办,ES失败了DB回滚,Worker标识状态,重新迎接下一次轮询。

前端下单和后端生产分离

问题
ToC端和ToB端的业务场景不同,前端对互联网用户的更多的是快速响应,抗住流量压力,而后端的场景需要稳定的全量的数据,要在接单的数据库基础上进行补全数据;两个端职责不同,不能互相影响;

解决方案
ToC和ToB分离,前端App或者H5用户下单和后端订单真正的生产相分离;前端订单系统挂掉了,不影响后端的生产;后端的生产挂了,对用户的下单也是无感知的。只是对配送的时效体验上会有影响,不是阻断性的。

我们ToC的订单系统和ToB的是两个不同的独立数据库,互不影响;订单管道的Woker都是基于TBSchedule的分布式管理,多个Woker并行处理,下发时机都在毫秒级;

并行控制提升效率

问题
交易的流程依赖的系统非常多,拿提单按钮来举例,结算页的”提单”按钮,点一次就会触发20+个接口。随着业务复杂度的提升,单纯的串行执行效率越来越低,前端用户的体验越来越差。我们要求TP999在500ms以内的响应速度。

解决方案
我们梳理了服务的依赖关系等,对没有前后依赖的接口进行放到线程池里面异步执行,类似:查询库存,查询商品信息,查询促销信息等都并行执行。此步执行的时间,是并行接口里面最长的一个执行的时间。这样一来整个提单的操作提升了几百毫秒。

另外资源(库存,优惠券,优惠码,促销等)的消费和回滚,我们也采用了并行的方式,每一种资源类都实现消费和回滚的接口。如下图:

每个资源类都是一个Task的成员变量,Task实现了Callable接口。这样一来,不但整个提单大接口的效率提升了,对于资源消费和回滚环节,程序和业务的扩展性提升了很多。比如新增一种资源,这时候只需实现消费和回滚接口,然后扔到线程池里面就完成了。

异步

在服务端可能需要针对提单请求做一些附属的事情,这些事情其实用户并不关心或者用户不需要立即拿到这些事情的处理结果,这种情况就比较适合用异步的方式处理这些事情,思路就是将订单交易的业务整理出来,哪些是不影响主流程的,例如:发短信,保存最近使用地址,清除购物车商品,下发订单给个人中心等等。这些都是在提单之后的异步线程去做。对于下发给个人中心的操作,如果失败,我们会有Woker补偿机制;

我们这里使用的是线程池的模式进行异步处理的,处理过程中有几个问题需要注意下:

  1. 线程池的队列不建议使用无界队列,它的默认大小是整数的最大值,这样在突发流量的时候会导致内存暴涨,影响服务;建议使用ArrayBlockingQueue

  2. 不推荐使用CallerRunsPolicy,即在线程和队列都达到max的时候,退回此请求到主线程。这样在突发流量或者接口提供方性能下降的时候导致主线程数暴增,影响整体服务。可以直接使用拒绝的策略,后续的Woker可以对异常单就行补偿;

依赖治理

订单交易上百个接口,几十个系统交互。各服务直接的依赖关系如何治理是一个很重要的问题。如下图:

问题
一个服务依赖这么多服务,每个服务除自身的原因外,还受到网络原因等其他外部因素的影响,高并发情况下任何一个依赖的服务的波动都会造成整个大服务的阻塞,进而导致系统“雪崩”。

解决方案
那这些服务特别是不是阻断流程的服务,我们可以采用降级的处理,例如调用超时了给设定默认值,调用量比较大,所依赖的服务严重超时并影响整个调用方时,可以通过配置直接提供有损服务,不调用此服务。

我们解决此类问题是使用自己开发的基于Zookeeper的“鲁班系统”,其原理就是Zookeeper相应的Znode节点下的数据做为对接口的开关或者降级情况的配置等。当相应的节点的数据发生变化的时候,对此节点监听的所有服务器都会受到通知,并将此变更同步到本地的缓存中;本地缓存我们使用的ConcurrentHashMap。当然也可以使用Guava Cache等开源组件,注意并发的场景就可以了;

然后再结合我们的UMP监控系统对系统的可用率,调用量等情况进行降级时机的判定,对Zookeeper相应节点的数据做动态配置;

履约

问题
针对订单履约的过程清晰可追溯,我们自己开发了UDP上报系统,对一次提单中操作的所有接口,几十个系统的交互进行了详细记录;

解决方案
出参入参,是否异常,IP等信息均做了上报。通过Spring的AOP方式,开发了一个自定义注解,对添加了注解的方法UDP方式写入到ES集群中;而且我们实现了工具化,任何项目引入我们的Jar包,做简单配置就可以向我们的UDP服务端上报信息了。随着现在的信息量变大,我们正在考虑升级架构,UDP Client端发送信息到Kafka,然后Storm实时在线分析形成最终需要的数据落地到ES集群中;

此系统大大提升了我们定位解决问题的效率。

未来展望

多渠道分拆

微信,app,h5等多渠道隔离,单独部署单独发布。各渠道互不影响。以后再灰度就要单台->单set->单渠道->全量

监控

画了一个效果图,服务依赖的治理根据透明可视化。一个大服务依赖的接口众多,如果像下面我画的这个图这样,不同颜色代表不同的接口状态。鼠标附上去会展示详细信息;以后还可以做成,图形和后台服务程序联动,图中的一个节点就是一个服务,通过拖拽等方式,实现和后台程序联动达到降级的效果;

接单xml数据化

如果以后订单量持续增加,每次操作多张表,单量上升的时候系统压力会上升,我们可以对订单库的表数据存储进行XML化,每个订单只操作一张表,存储一条数据,(XML化相对JSON可能解析的时候性能会稍微差一些,但是对于问题的查询可视化程度更高)然后在下发到后台的ToB生产数据库的时候,异步Worker还原成多表;

结算页缓存化

这个其实我们已经有技术方案,流程图已经出来了。后期就会上。目前提单的时候众多参数是从结算页从URL里面带过去的。虽然我们做了数字签名但是,在安全性和接口数据传输效率上还不是最好的。大致方案就是在用户进入结算页后将数据缓存化,当用户刷新结算页的时候,非敏感信息直接从缓存取,不用重复调用接口,提交订单的时候也入参就很简单了,一个Key就可以了。


=>更多文章请参考《中国互联网业务研发体系架构指南》https://blog.csdn.net/Ture010Love/article/details/104381157

=>更多行业权威架构案例、领域标准及技术趋势请关注微信公众号 '软件真理与光':

更多权威内容关注公众号:软件真理与光

【交易架构day4】京东到家交易系统的演进之路相关推荐

  1. 京东到家交易系统的演进之路

    背景 交易系统可能不是技术难度最深的,但是业务复杂度最高的,一个订单从提交到最后真正生产成功要经历几十个系统,涉及的接口交互,MQ等可能达上百个.任何一个环节出问题都会导致这一单的异常,而且交易不像单 ...

  2. 【商品架构day3】京东商品系统的演进之路 - 如何抗住亿级流量

    本文来自京东尤凤凯老师的分享.商品,黄金交易流程最基础.最核心的环节,无商品不电商.商品数据无处不在,商家(采销.供应商)发布管理.供应商下采购单.仓储配送.促销.搜索.商详页展现.购物支付.财务结算 ...

  3. 【交易架构day8】洋码头交易系统的演进之路——先生存后发展

    按:我们谈系统演化,本质上是一个动态进化的过程,谁先做.谁后做,第一枪打在哪.这是关键.先保生存.再发展是比较好的策略.本文来自洋码头架构师张志强.涂文杰两位的分享. 1. 交易1.0 和许多业务优先 ...

  4. 【商品架构day7】京东商品系统的演进之路:从0到10亿流量的挑战

    本文来自京东赖晨东老师的分享.主要从POP商品简介.POP商品系统的架构演进.以及一些实战的架构珠玑3个方面来介绍京东POP商品系统. POP商品系统的特征是业务复杂,也是新业务的发源地,更是核心的基 ...

  5. 华为架构师8年经验谈:从单体架构到微服务的服务化演进之路

    本次分享的技术大纲如下: 传统应用开发面临的挑战 服务化实践 服务化不是银弹 服务化架构的演进方向 一 .传统应用开发面临的挑战 挑战1-- 研发成本高 主要体现在如下几个方面: 代码重复率高 在实际 ...

  6. 大型互联网公司架构演进之路汇总

    最近,我的朋友整理了各大互联网公司的架构演进相关介绍,让我们一起看一看各大互联网公司在成长过程中遇到过哪些问题,又是如何解决问题的.希望对你有帮助! 建议收藏保存,也欢迎点赞转发哦! 支付宝和蚂蚁花呗 ...

  7. 京东到家定位系统演化

    文章概要 引言 依托达达的高效配送和大量优秀零售合作伙伴,京东到家为消费者提供生鲜蔬果.日用百货.医药健康.鲜花蛋糕.个护美妆等海量商品 1 小时配送到家的极致服务体验,在整个服务过程中,京东到家基于 ...

  8. 各大互联网公司架构演进之路汇总 | 2020最新最全

    △Hollis, 一个对Coding有着独特追求的人△ 整理 l Hollis 来源 l Hollis(ID:hollischuang) 在互联网行业中,有两种优秀的技术人,一种是热衷于分享技术的,一 ...

  9. 各大互联网公司架构演进之路汇总 - 分享自@开发者头条

    大型网站架构演化历程 Web 支付宝和蚂蚁花呗的技术架构及实践 支付宝的高可用与容灾架构演进 聚划算架构演进和系统优化 (视频+PPT) 淘宝交易系统演进之路 (专访) 淘宝数据魔方技术架构解析 秒杀 ...

最新文章

  1. [JS] - onmusewheel事件(兼容IE,FF,opera,safari,chrome)
  2. 动态备份SQL-SERVER数据库——SQLDMO
  3. 的产品很好为什么卖不好?
  4. TrueType、PostScript 和 OpenType 字体之间的区别是什么? truetype vs opentype
  5. 华为波兰销售总监被捕;苹果将推三款新 iPhone;ofo 用冻结款还债 | 极客头条...
  6. 爬虫实践-微博关键词搜索抓取
  7. ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp
  8. angular4与高德地图的结合
  9. cisco2811 pppoe上网配置供参考
  10. MangaEditor(漫画编辑器)v1.10b官方版
  11. 手机输入法带拼音声调_五笔已经淘汰,拼音到达瓶颈,百度重拳出击,全新输入方式来袭!...
  12. 用 WebGL 探索动画和交互技术(一个学习案例)
  13. c语言中字符型char数据在内存中占,互联网常识:在c语言中char型数据在内存中的储存形式为什么...
  14. 洛谷 P2672 推销员
  15. 复合梯形的matlab求解,MATLAB 利用复合梯形公式求解积分
  16. 【掘金 - 自动签到功能的实现】 - 让我们使用【ios/iphone 快捷指令自动化】实现一个社区每天自动签到小脚本
  17. Centos 通过 Nginx 和 vsftpd 构建图片服务器
  18. Autolayout第三方库Masonry的入门与实践
  19. WmiPrvSe.exe 的 cpu 占用
  20. 人工智能时代的幼儿教育软件

热门文章

  1. 橙狮Scratch编程
  2. win7无法信息服务器安装程序,主编为你win7系统纯净版安装程序提示“microsoft注册服务器已停止工作”的解决方法...
  3. win32-c语言实现俄罗斯方块
  4. grep 命令使用(2)
  5. javascript 实现中文按照拼音首字母排序
  6. Unirech腾讯云国际版代充-使用RDP文件登录到Windows云服务器实例教程
  7. 99乘法口诀表用for循环
  8. 论单片机IO引脚驱动能力的提高
  9. 详解 Samaritan——饿了么最新开源的透明代理
  10. 老外码农酒后吐槽,该说的不该说的全说了!!