在工作期间,笔者有幸参与了下单链路的开发、维护工作,在这期间有经历下单从0到1的搭建,也有随着业务发展不得不进行系统重构的经验。“提交订单”这一词大家应该都是再熟悉不过了,不管你是不是软件研发人员,还是普通使用电商APP购买商品的用户,只要你在购买商品时必然会遇到。既然“提交订单”这么频繁的被使用到,作为任何电商APP来说,那么它的稳定性就尤为重要。
那么站在技术视角看下单链路,会发现几个特点
-
高QPS/TPS,流量大
-
订单数据正确性要求极高
-
监控告警时快速定位能力
-
结算页到订单创建成功的所见即所得
-
易被恶意流量刷单
-
依赖下游服务非常之多
-
业务逻辑很复杂
本篇文章就挑几个在日常研发中可能会遇到比较明显的问题,以及是怎么进行应对的。
2.1 线上告警频繁,精准定位问题耗时较长
告警机制,这个大家最熟悉不过的了,作为技术人的对这可以说是又爱又恨吧。即讨厌线上频繁告警的打扰,又担心真正发生告警时的定位难。常见的主流监控,Zabbix、Promethues、Open-Falcon等主要监控的指标还是以应用维度为主,主要监控指标如下。
-
Dubbo接口:请求量、耗时、异常量。
-
JVM :GC次数、GC耗时、各个内存区域的大小、当前线程数、死锁线程数。
-
线程池:活跃线程数、任务队列大小、任务执行耗时、拒绝任务数。
如图,类似于这种告警应该是比较熟悉的。那么这里的问题也很明显,下游接口异常到底影响的是哪个链路呢?针对这种特定业务场景,如订单结算页、提交订单,这类接口级别的监控又该怎么做呢?那首先简单介绍下在一次下单请求中可能遇到的问题
-
下游接口调用告警
-
强依赖接口和业务可降级接口,怎么进行区分?
-
当告警来了,怎么确认是下单链路所依赖的接口呢?
-
下游接口告警了,是预期内的业务异常还是非预期内的呢?
-
-
接口rt&接口QPS抖动告警
!由于热门商品、大促等活动节日的存在,所以下单链路会经常出现这类告警
-
AVG RT的下降,怎么识别是否正常?
-
QPS的突然升高,升高的原因是啥呢?到底是下单链路阻塞了导致用户一直重试,还是发生了抢购呢?
-
依赖的中间件发生抖动告警
-
怎么快速感知是MQ、Redis、DB等的异常?
-
-
应用自身出现异常告警
-
普通业务异常:例如当前APP版本不支持XXX新业务,非法请求核心参数缺失
-
非预期异常:新上线的业务代码整出了异常导致下单阻断
-
怎么区分普通业务异常和非预期异常?
-
普通业务异常:例如当前APP版本不支持XXX新业务,非法请求核心参数缺失 -
非预期异常:新上线的业务代码整出了异常导致下单阻断
-
-
2.2 当购买期间商品信息发生变更,怎么保障用户的购买体验呢
在用户购买东西时,首先会看到订单结算页面,这个上面会展示商品价格
,售后保障
,到货时效
,优惠信息
等,这时用户在确认条款后会提交订单,那么在订单生成后订单详情看到的理论是需要和在结算页看到的信息是完全一致的。但是由于结算页和提交订单是分开的请求,那么这个时间GAP以及实现差异终究可能会带来不一致的情况发生。如果是普通库存的话,给用户直接重新展示订单结算页也还行,要是抢购商品的话,那这个体验就会有比较大的影响。
2.3 依赖方数据返回不合法,该如何及时感知
订单的数据是相当复杂的,需要依赖商品、库存、营销、商家等数据信息,不同的业务场景对生成的订单数据就会存在一定的要求。
那么这件事情的必要性,就在于可以在系统上线之前,通过回归测试及流量回放验证来及时发现是依赖方接口导致的问题还是自身系统代码bug带来的影响。
那么问题来了,既然决定好好治理,那么怎么治理呢?怎么以最小的人力、技术成本实现这些治理呢?这个时候大量参考了现在同行业内针对下单场景稳定性相关的方案。现在就逐一介绍以上问题最终选择的解决方案。
3.1 自定义实现告警机制的基础日志数据埋点
针对接口级的定制化告警,采用了自定义日志埋点的方式,格式如下:
{current_time}|{trace_id}|{span_id}| {function_name}|{rt}|{error_code}|{error_message}|{user_id}
-
function_name:用来具体区分哪个接口
-
error_code:接口错误码,用来唯一标识接口异常原因,重点就是这个,这个指标数据输出的精细程度决定了定位问题的速度
-
rt:接口响应时间
这里简单画个图,直观的体现下需要关注下单链路中哪些指标
现在介绍一下每个指标的作用:
-
网关QPS:观察C端的实时入口流量
-
自身服务QPS:观察到达服务本身的流量
-
网关QPS > 自身QPS,可以考虑是否网关侧发生了限流
-
当自身QPS下降过高
-
-
-
-
网关QPS没什么波动,那么这个时候考虑网关问题
-
网关QPS也同步下降,前置导购链路流量问题,如商详/购买浮层 是否发生阻断性异常
-
-
-
自身业务异常:输出下单阻断的业务原因,又称为预期内异常
-
自身其它运行时异常:如NPE,称为非预期内异常,此时错误码会统一输出SYS_ERROR,一般此类会重点关注
-
下游接口RPC异常:此时会输出是下游哪个接口导致的阻断,如
-
商品查询接口超时 -> QEURY_SKU(RPC_TIMEOUT)
-
用户接口查询网络异常 -> QUERY_USER(NETWORK_EXCEPTION)
-
-
下游接口业务异常:如
-
优惠已失效 -> CONSUME_DISCOUNT(INVALID),这里会通过识别下游接口返回的code码来区分不同的业务异常,所以在日常需求中要求下游接口提供方确保返回码的含义就是这个原因
-
返回了未约定的code码,统一会返回如XXX(BIZ_ERR),看到此类错误码的时候,就会及时反馈给下游服务Owner去跟进这个问题
-
-
中间件访问异常:
-
SQL执行异常
-
网络连接RST异常
-
-
自身服务接口AVG RT/SUCCESS RT
-
这里主要说一下SUCCESS RT,这个指标是可以最准确的反馈出最近RT是否存在波动
-
-
自身服务接口AVG QPS/SUCCESS QPS
-
这里的success qps很重要,当发生抢购的时候,整体QPS会大幅上升,这个时候可以SUCCESS QPS来判断当前成单量是不是稳定
-
-
-
-
如果是浅库存抢购,这个指标不会有太大波动
-
接口被刷了,这个指标也不会有太大波动,且会出现OPERATION_TOO_FREQUENTLY频次限流错误码
-
-
!通过将接口每次请求的埋点日志输出到指定文件中,后续经过监控组采集以及分析得到了如下几个主要的大盘:
1. 确认订单&创建订单错误码大盘
从图中可很直观的发现当前有哪些原因导致的下单失败,如版本过低限制、库存售罄、下单频次过高等原因,这样就能很直观的发现
-
从异常名可以看出是有很明显业务语义的,这样便于大家理解
-
针对下游接口调用,会输出具体某个接口(也可以给对应接口定义别名)的某个类型错误,如优惠核销的超时、优惠已失效、优惠已使用
另外还设计了基于机器IP的过滤,这种做法的好处是,在发布过程中,如果下单出现了任何阻塞性异常,都可以很快的感知到,从而可以快速做到SOP响应处理。
对于链路中的业务弱依赖接口,这里不会有错误码体现,这里依然还是借助于监告警机制。
2. QPS&RT指标数据
这里主要日常监控观察主要会注重成功量QPS,特别是发布期间完全可以依赖于这些指标数据。例如发布期间这个时候在抢购,有了这个就能做到心中有数了。这里简单说明一下成功量就是接口业务执行成功的含义。
-
错误码环比涨幅超指定阈值 -
接口RT环比涨幅超指定阈值 -
接口成功量QPS环比下跌超过指定阈值
然后再将这些告警机制接入飞书、短信等通知,那么哪怕是在周末外出游玩的时间,有任何下单链路的异常告警,只需要打开手机看一眼就能快速定位到问题的根因所在了,岂不美哉?
以上就是针对下单告警机制的精细化处理了,除此之外,有了这些数据后,也对其它一些指标数据也进行了完善,如:
-
高频访问用户
-
不同入口的实时下单量
-
当前热门购买商品
3.2 基于版本号的商品信息&数据一致性校验
1. 商品价格变更
商品改价这个在电商中应该是比较常见的,那么如果是在秒杀时改价,那么此时提示用户“商品价格”变更可能对用户的体感就没那么好。针对这类问题可以采用商品信息+版本号机制。
用户在订单结算页看到的商品数据版本会交由客户端携带至提交订单,此时提交订单可以校验该版本的生效时间是XX秒内,确保这个时间内订单提交不受改价影响,这样可以给到用户一个较好的购买体验。这个XX时间就需要业务来进行权衡了。
2. 数据一致性校验
通过以上的UML图可以看到,由于确认订单和创单是两次请求,那么保证数据防篡改是第一要求,而且有了这个验签机制后,用户自己通过简单传参刷创单接口就变得更加困难了。对于迭代版本中新增生成sign的参数,这边主要采用version版本的方式,不同的version对应参与生成version的参数有所不同。
-
version1,参数 a、b、c
-
version2,参数a、b、c、d
有了防篡改的保障后,那么接下来就只需要在下单资源扣减之前,针对这些核心数据进行一致性校验即可,如订单金额、展示给用户的售后标签等等。这样的话在出现不一致时可以给到用户友好的提示,并且对可以及时进行告警通知。
3.3 订单数据正确性校验&及时告警机制
一致性校验节点旨在创单落库节点前给恒久不变的规则(如:订单支付金额 = 应收金额 – 优惠 )提供下单前的兜底校验及可选告警措施。不太适合落地多变的规则。如果是多变规则需要写到对应业务模块以异常形式告出。大家自行判断所属业务属于哪一种。
订单数据完整性校验致力于保障订单在整个生命周期中数据的正确性。为用户打造一站式的校验、预警解决方案。提供以下能力:
-
可插拔式接入
-
场景定制化
-
动态降级
-
规则、预警可扩展
-
统一流程处理
-
商家地址返回手机号存在掩码问题,必要数据缺失 -
优惠接口在某种特定业务场景下未返回对应的优惠信息 -
订单金额计算是否一致与用户看到的一致
-
基于错误码大盘及监控机制的问题快速定位
-
核心接口全局监控,高灵敏度感知任何阻塞下单的问题 -
监控机制实时告警
-
下单链路一致性机制保障,所见即所得
-
创单数据正确性兜底校验
在下单的稳定性治理过程中,从面对线上告警的盲目无措,逐渐演进到面对日常迭代变更、突发流量场景的镇定自若。在日常工作中,持续关注、发现线上潜在的问题以及不合理的设计,然后尽量通过合理机制&实现来进行保障。作为一名研发人员,不能确保不犯错,但能尽最大努力及时发现错误,敬畏生产。几套打完收工,可以手握小茶壶,静看风波了。
活动推荐
*文/ chaka
关注得物技术,每周一三五晚18:30更新技术干货
本篇文章来源于微信公众号:得物技术
本文来自投稿,不代表TakinTalks稳定性技术交流平台立场,如若转载,请联系原作者。