17 May 2019

小象履约系统总结

悬挂链

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%能进入履约流程,只是时间长短的问题



blog comments powered by Disqus