核心交易链路架构设计与演进

  前言
  
  随着双11进入千亿时代,电商平台正在向“全球化,娱乐互动化,无线化,全渠道”发展。
  
  为实现全民互动,电商平台会进行低价预售,狂欢红包,购物券,红包雨,商品半价,满n减1等多种促销方式。
  
  核心交易链路设计
  
  每笔剁手操作都会经历一系列核心系统处理,如图:
  
  如此眼花缭乱的玩法,底层是多个核心系统的支撑,整个系统要保证在交易高峰下的海量订单有序,准确,顺滑。
  
  预算扣减及红包领取
  
  红包发放要保证精确预算控制,预算发放的红包总金额不能超过预算的金额。
  
  每条预算在数据库中是一条记录,在高并发场景下,可能会成为单热点瓶颈,维护过多的记录表,可能造成数据倾斜。
  
  预算控制和用户无关,无需实现单元化。用户的红包信息则需要实现单元化,发放流程涉及到预算扣减,扣减操作后,用户需要尽快收到红包。
  
  因单元化和非单元化的数据处于不同数据中心,可能造成跨机房调用,也就引入了不确定性。
  
  所以红包系统和预算系统需要解决高并发场景下的预算扣减和用户收取红包的一致性。
  
  分桶方案
  
  通过分析历史数据,我们将预算拆分为多个子预算,瓶颈分配到多个数据库中,根据红包发放请求的userId进行路由。在子预算余额不足时,路由到主预算中。 每个子预算的扣减并不相等,肯定有一部分子预算会出现余额不足的情况,所以主预算要比子预算多分配一些金额。当多个子预算余额非常少时,可以对子预算进行回收,避免预算分片的碎片化。
  
  数据库优化
  
  为提升记录表性能,需要对数据库操作进行梳理及优化。设想这个场景主要有3条sql:
  
  两条插入语句
  
  一条更新语句
  
  更新语句是造成热点的瓶颈,为减少更新导致的独占锁,可以将3条sql合在一起,通过一次网络传输到达数据库服务器,同时在更新语句中设置余额大于等于0的条件,这样可以避免在扣减之前再查询一次余额,而仅仅通过判断sql错误码就能识别余额是否足,减少了对数据库的压力。
  
  更新语句添加commit_on_success标签,保证事务成功后立即提交事务,不用等到客户端获取更新结果再发起commit,减少了一次网络交互,同时记录的独占锁可以立即释放。
  
  更新语句添加target_affect_row 1 标签,保证如果满足条件的记录不存在,事务应该失败,而不是返回影响行数为0。
  
  可以将多个事务封装成一个数据库的写入单位。整体优化后系统qps可以摸高到30w。
  
  红包展示
  
  用户领取红包后需要在多个系统终端中进行红包展示,比如领了多少红包,金额是多少等。 统计这些会比较消耗数据库性能,同时展示红包也是比较高频的需求。采用缓存可以解决这个问题,但是随之而来的问题是缓存的失效处理。红包本身涉及多个生命周期,到底在哪个缓解设置缓存失效是合理的呢?
  
  在用户的红包每次进行状态变更时都会更新modify_time,所以采用读时更新缓存:
  
  采用事务内一致性读取缓存,将当前时间设置为缓存生效时间,如果用户没有红包,则生效时间为2000年1月1日。
  
  当查询到用户用红包时,会同时查询出红包的最后更新时间,然后和缓存生成时间做比较,当用户红包数据更新时间大于缓存生成时间,则判断缓存失效。
  
  这样可以利用数据库索引,同时减少返回信息,对数据库的消耗比较少。
  
  红包使用
  
  在业务规则角度进行了红包使用控制,每次只能使用10个红包,红包使用场景qps也很高放大到红包系统qps是10倍。每次红包使用需要更新10个红包状态,产生10条红包使用的流水,还需要产生至多10条红包相关的业务单据。
  
  一次红包使用场景涉及到大量cpu资源进行sql解析,一次下单涉及到多个sql,对网络消耗较大。我们采用batch insert语法优化插入性能,更新语句采用多条方式提升更新性能。在业务系统中生成一个大sql发送给数据库服务器,减少网络交互。
  
  比如这次下单操作涉及到5个红包,可以通过一个sql将5个红包余额更新为0,同时加入金额锁保证红包的并发更新。设置语句的target_affect_row 5标签,如果某个红包已经被其他订单并发下单使用,事务会提交失败,可以通过数据库返回的错误码识别出这一情况。
  
  可靠性保障
  
  上面的情况只是处理非单元化场景预算,系统需要在预算扣减之后写入单元化的用户数据中。两种数据处于不同数据库,需要保证操作的一致性。同时在红包领取后,在1s内展示用户红包,这种情况一般采用跨库事务框架来解决。 但跨库事务不能做到严格的事务一致性,严格的事务一致会造成性能的极大下降,于是采用内部的一致性消息jbus实现。
  
  jbus
  
  jbus思想是业务在事务中插入一条消息记录,建立一套消息订阅和分发系统对消息进行处理。消息的记录和业务记录在一个数据库中,可以做到事务一致性。 多个消息订阅者可以共享一条消息记录,因此不会增加过多的数据库性能损耗。做到1s内消息消费,则可以保证用户看到自己领取的红包。
  
  同时建立监控系统对消息挤压进行监控,可以及时发现消息的积压问题,同时在消费出现问题时进行流程完整性的保障。
  
  流程前置处理
  
  下单系统涉及到访问物流系统获取运费模版,计算运费价格,之前的架构会调用远程服务,获取计算结果,这种方式会将下单峰值带到下游依赖的系统中,需要下游系统具备同样的峰值承载能力,提高了整个核心链路的成本,同时稳定性也带来了复杂和挑战。
  
  流程前置处理后,下单系统不再需要请求物流系统,而是直接访问运费模板缓存服务器,通过前置下单运费计算模块在本地计算出运费,减少了对于远程服务的调用和依赖,提升了系统性能,增强了系统稳定性。
  
  提升开发效率(TMF2)
  
  随着业务玩法的越来越丰富,参与的团队越来越多,多个团队在一套平台开发造成的效率浪费越来越多。
  
  为提升开发效率架构进行了升级,业务级代码和平台级代码分离,平台级代码对交易相关能力进行分类抽取,抽象提取对外提供支撑服务,业务方根据团队能力自助式定制逻辑开发,无需平台团队介入,大幅提高开发效率。
  
  为达到业务和平台分离的架构目的,主要通过能力模型,配置模型,所生成对配置数据贯穿业务配置主线和业务运行主线来实现。
  
  通过对交易建模,抽象,收敛,形成了交易基础能力层,采用功能域->能力->扩展点方式进行表达。
  
  在下单环节中归纳十几个功能域,优惠,支付,交付,价格,订单,结算,税费等,针对这些域进行能力扩展,同时开放给业务方进行定制,适应不同业务场景需求。
  
  同时引入产品概念,将多个域能力进行整合,对业务方提供满足业务功能的能力包,进一步提高业务研发效率。
  
  整个架构中,业务能力,产品,场景属于平台能力,业务方定制功能都在业务包中,这样可以做到业务和平台分离,业务之间隔离,使得平台开发人员和业务开发人员之间互不干扰,提升整体协作和交付效率。
  
  业务技术挑战
  
  营销平台核心系统:
  
  优惠计算系统能力:

http {
# 定义image日志格式
log_format imagelog '[$time_local] www.hengda157.com' $image_file www.fengshen157.com/' www.dasheng178.com' $image_type ' ' $body_bytes_sent ' ' $status;
# 开启重写日志
rewrite_log on;

server {
root /home/www;

location / {
# 重写规则信息
error_log logs/rewrite.log notice;
# 注意这里要用‘’单引号引起来,避免{}
rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg|gif)$' /data?file=$3.$4;
# 注意不能在上面这条规则后面加上“last”参数,否则下面的set指令不会执行
set $image_file $3;
set $image_type $4;
}

location /data {
# 指定针对图片的日志格式,来分析图片类型和大小
access_log logs/ www.tiaotiaoylzc.com/ images.log mian;
root /data/images;
# 应用前面定义的变量。判断首先文件在不在,不在再判断目录在不在,如果还不在就跳转到最后一个url里
try_files /$arg_file /image404.html;
}
location = /image404.html {
# 图片不存在返回特定的信息
return 404 "image not found\n";
  
  优惠计算,折扣价多少,订单可用多少购物券,抵扣多少金额
  
  优惠规则引起处理优惠和优惠之间关系,商家多少优惠券可以满减券可以叠加使用
  
  多级缓存框架负责将优惠数据按照功能,热度等因素进行多级缓存,及缓存的不同实现
  
  交易系统和金钱打交道,稍有不慎会带来资损,所以数据一致性和业务正确性是平台最大的挑战。
  
  挑战:
  
  优惠数据产生和使用经历多个数据源,db,tair,vsearch等
  
  单元化部署结构导致数据在多个机房存储
  
  优惠和外部资金,搜索关联,业务链路复杂
  
  缺少主动发现和补偿机制来保障最终正确,可能造成客诉和资损
  
  目标:
  
  底层抽取模型,形成统一结构
  
  支持多种数据源,db,tair,自定义对比方式
  
  支持增量和全量对账
  
  业务可配置化,快速上线能力,线上不一致发现能力,及时处理及预警能力
  
  实时对账: 底层基于storm流式计算框架,上层增加调度任务管理,数据源,对账脚本管理,监控报警管理等模块。用户可以通过实现简单对账脚本,完成数据对账工作。实时对账通过db的drc消息触发。
  
  离线对账: 通过定时任务,扫码db或定时拉取表数据,将需要对账内容组成元数据消息,datacheck根据消息内容执行对应数据脚本对账,得到最终结果。
  
  多级缓存框架
  
  交易相关核心链路每到大促时节,数据热点都会变成最需要解决的问题。同时对于数据一致性有一定的要求,于是好的缓存系统,做好防止热点数据击穿,提升热点数据访问效率就显得尤为重要。
  
  三级缓存结构
  
  预热缓存,通过历史数据可以预测出一些热点数据,同时参与大促的活动在一定周期内是禁止编辑的,活动开始后将预热数据提前写到本地缓存中,实现堆内,堆外数据预热
  
  热点缓存,存储活动相关热点数据,无法预测的购买行为数据可以按照周期内qps排序,保障top热点数据常驻缓存
  
  全量数据缓存,可采用tair
  
  特点:
  
  统一不同缓存实现的接口,业务代码无需关注底层实现
  
  多级缓存精细控制,各级缓存的写操作,tair&db一体化,db限流等
  
  做到任意一级缓存可拆分,粒度精细到某一级缓存(包括db)
  
  数据预热,采用统一数据结构包装预热数据,单机生成数据(文件)后,提供数据接口进行分发
  
  如图:
  
  热点数据缓存与驱除
  
  两个小时内数据有效,在周期内针对数据访问qps和最近一次时间点进行排序,最后的驱除。 hotsensor针对周期内单位时间做滑动窗口,窗口长度采样采用1.5s或2h,采样窗口划分为20个格子,通过一定算法统计20个格子平均滑动窗口累计平均值。
  
  hotsensor计算方式:
  
  多级缓存场景中,某个key到下一级缓存查询,多key时需要组装每次查询结果,可以进行封装,统一代码风格。
  
  总结
  
  利用平台提供模块化,可视化配置的技术组件,开放服务和元数据来快速定制独有商业形态,多个渠道数据进行沉淀,实现了“大中台,小前台”的业务划分,支撑了业务的快速发展和低成本创新的目标。

猜你喜欢

转载自www.cnblogs.com/qwangxiao/p/10355837.html
今日推荐