小象履约系统总结
悬挂链
1.定义
悬挂链全称叫悬挂输送链,悬挂链的线体可在空中上下坡和转弯,占地面积小,减少店面内分拣人员把商品从货架拿到道口的人工操作,节约人力。
2.作用
传输商品,辅助合单的硬件设备
合单
1.什么是合单
1.什么是履约
履约是指在用户使用小象app采购完商品之后,到货物送到用户手中的过程
2.什么是分拣
指分拣人员、分拣工具巡回于商品的储存场所,按照客户订单要求,从经过的货位或者货架上挑选出所需的商品。
3.什么是合单
商品经过合单设备的分配,从所有分拣商品中,把相同订单的商品在一个下链口进行合并,之后进行打包操作。
4.合单在履约中处于什么角色
2.合单的方式
1.人工合流:分拣员用分拣设备pda,对在不同分拣区的商品,在打包口按照订单维度进行聚合,为打包服务做准备
2.悬挂链
3.人工合流+悬挂链
悬挂链合单的业务操作
1.什么场景会使用悬挂链进行合单
2.悬挂链合单有几个状态
3.悬挂链有几个动作
1.载具上链
2.载具下链
3.门店道口复位按钮复位
悬挂链的技术实现
用http方式和上位机进行网络交互,美团履约悬挂链系统处理上位机上报的指令,并且按照订单维度在指定的道口进行载具的聚合
1.上位机和悬挂链硬件是什么关系
上位机封装在悬挂链硬件上面,来和履约系统交互
2.悬挂链怎么和上位机交互来完成合单
3.悬挂链在和上位机交互时合单状态的变化
系统思考
1.悬挂链系统如何保证稳定
如何能够保障系统的稳定性呢?我们需要从预防、发现、处理和复盘四方面来进行着手。
1.预防
梳理所有可能出现问题的地方,并实施应对措施。主要有以下几个方面:
现象 | 策略 | 备注 |
---|---|---|
依赖的系统出现问题 | 隔离+降级+超时+重试(可选的) | 隔离:是为了保障相互不影响,例如业务拆分。降级:保证在数据库/内存/nginx有一套兜底数据。超时:是为了防止服务恶化,因此任何外部调用,都要设置超时时间。重试:系统的自我修复,提高系统的可用性和最终一致性。 |
依赖的基础组件出现问题 | 降级(备选方案) | 例如redis。此中间件在系统直接去除了! |
依赖的软硬件故障或者网络故障 | 冗余备份(多机房部署) | |
流量负载过大 | 快速扩容or限流 | 正常业务的话,能够快速扩容;异常流量的话,能够进行流量限制。 |
系统设计或者开发时产品的bug | 标准测试流程+review机制+上线规范 | 任何一次线上操作,要考虑出现的问题,以及预案(例如洗数据时,需要考虑如果洗失败,如何进行快速恢复)。自动化回归测试需要去做 |
2.发现
核心基础设施监控:CPU的平均使用率、CPU峰值的持续时间、内存的平均使用情况等。
应用级别监控:JVM进程的内存、内部线程的数量、磁盘IO等。
服务质量监控:请求所需的平均时间、每分钟请求的平均速度、每天峰值的请求速度、分拣单数、请求日志以及请求错误数。
3.处理
及时止损:例如上线导致故障,第一时间应该快速回滚,及时止损,而不是追问题改代码
工具化、平台化:预案不能依赖特定的人,例如降级要有一键开关,而不是需要某个人去x平台改个参数,y平台改个超时
及时通报:及时对外同步故障的影响,跟进人,修复进度,便于相关团队知晓、协助
4.复盘
当出现故障时,处理问题是第一优先级,暴漏出来的问题,也是我们的财富,我们要重视每一次事件,从中学习,将其完善到预案中,确保以后不会再现。
2.悬挂链系统如何扩展
1.业务的扩展性
1.细化和悬挂链系统异常上报的指令的交互,不能因为一个下链口损坏等情况,就停止门店悬挂链的使用
2.订单高峰期,载具上链之前可以先判断是否有可用的下链口,否则会出现载具一直在悬挂链上回流的情况,做好排队逻辑,不要进行无意义的载具上链指令,浪费网络带宽
3.门店道口的管理配置同步给上位机,数据控制在悬挂链系统
4.履约单取消逻辑,此时是履约监听自己产生的消息之后调用各个系统接口去通知,应该在分拣系统独自监听履约取消的消息,系统解耦
5.可以修改悬挂链配置的入口太多,不好维护,尤其mcc无法感知修改人
2.代码的扩展性
1.在分拣和悬挂链交互的时候,因为redis的舍弃,配置可以通过定时任务缓存到内存中,当配置有修改时,强制把配置刷取一份到内存,没有必要每次都查询数据库
2.可以采用thrift异步调用接口的方式
3.在代码中经常会用到履约状态的判断,但是此状态在分拣系统也维护了一份,和履约系统不是很一致,可以统一管理下
4.状态字段如果从履约中心传给下游系统,下游系统还有额外的判断,应该把数值灰度履约系统,例如是否使用悬挂链
3.数据库的扩展性
1.所有分拣系统和悬挂链系统交互的产生的表结构都应该是合单表,而不是悬挂链什么什么表,因为悬挂链只是合单的一种方式,而且不是独有的方式
2.悬挂链指令表和操作记录表可以设置历史表,减小数据库压力
解决的问题
背景
- 交互方式:履约监听交易订单支付完成消息并创建履约单同时RPC触发交易订单更新状态为履约中
- 问题:交易系统创建订单的消息是通过线程池发送的,但是线程池内部逻辑没有处理完机器就重启的情况,会导致消息丢失,
- 解决方案:履约添加主动拉取订单支付成功且需要履约的订单,生成履约单更改订单状态;注意:履约单创建要幂等
履约实现演变
-
前提:mafka不丢消息;履约系统,订单系统不长时间宕机;数据库不长时间宕机;crane可以进行调度操作
-
实现1
1.定时查询支付完成的订单
2.调用创建履约单的接口创建履约单,但是在创建履约单的中间环节(创建分拣单)失败,回调订单,订单状态从支付完成变成了履约中
3.定时任务只记录执行时间段,没有记录失败的订单号
4.按照出错时间段进行重试,此时订单状态已经变成了履约中,查询不到,此订单重试失败
实现2
1.定时查询支付完成的订单
2.查询到数据,扔到创建履约的mq里面
2.1.系统重启,因为查询订单获取的是系统时间,重启时间段过程无法获取到支付完成订单,如果订单系统消息丢失,补偿机制无法感知
2.2.crane延迟调度,因为查询订单获取的是系统时间,所以已经延迟调度的时间段是无法获取到支付完成订单,如果在延迟调度时间段,订单系统消息丢失,补偿机制无法感知
实现3
1.初始化执行时间段在数据库
2.按照数据库的执行时间段作为查询支付完成的订单的时间段
3.查询到数据,扔到创建履约的mq里面
4.不管是系统重启,还是crane延迟调度都可以保证订单的获取操作
db
CREATE TABLE `mall_delivery_compensate_task` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT ,
`end_time` varchar(128) default '' COMMENT '结束时间段,例如:10:05:00',
`execute_time` bigint(20) unsigned NOT NULL COMMENT '执行时间',
`create_time` bigint(20) unsigned NOT NULL COMMENT '创建时间',
`modify_time` bigint(20) unsigned NOT NULL COMMENT '修改时间',
PRIMARY KEY (`id`),
KEY `idx_execute_time` (`execute_time`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='履约订单补偿任务表';
预期效果
需要履约的订单100%能进入履约流程,只是时间长短的问题