写点什么

备战 618,京东如何保障系统稳定性?

2019 年 4 月 25 日

备战618,京东如何保障系统稳定性?

每年 618 的大促都是一场技术团队大练兵的时候。作为技术研发人员,在这场战斗中,加深了对线上系统的敬畏之心,通过系统的备战,在技术上也得到了提升。大战在即,如何保障系统稳定,我们的备战思路是什么?


首先确定自己的备战思路,梳理核心流程、找出薄弱点,对薄弱点进行优化,针对业务进行资源隔离,同时协调压测对优化结果进行验证,并针对场景准备预案,比如降级开关在什么场景下开启,以及降级之后的影响有哪些等等,后面还要实际演练,防止实际情况发生时准备好的预案不可用。


我们知道,618 期间发生的问题都不是小问题,所以,如何做到更周密的筹备,我们可以秉承如下几个原则:


• 墨菲定律:任何事都没有表面看起来那么简单;所有的事都会比你预计的时间长;会出错的事总会出错;如果你担心某种情况发生,那么它就更有可能发生。


• 二八原则:19 世纪末意大利经济学家巴莱多认为,在任何一组东西中,最重要的只占其中一小部分,约 20%,其余 80%尽管是多数,却是次要的,这就是二八法则。二八法则告诉我们,不要平均地分析、处理和看待问题,要把主要精力花在解决主要问题、抓主要项目上。


我们可以利用墨菲定律来梳理系统薄弱点,那些总是小问题不断的地方,一定会在某天酿成大的灾难,必须尽早解决。还可以利用二八原则梳理黄金流程,那些出了问题可能极大影响公司或影响用户的地方,就是不容有失的黄金流程。



我们以此为思路,从四个方面进行逐一介绍。


梳理薄弱点


梳理系统架构


备战第一步,就是要对系统做一次全面的梳理诊断,其目的就是要甄别出系统的薄弱点。而梳理的第一步,就是要梳理出系统架构。通过梳理系统架构,梳理系统的层次结构和调用关系,由此排查系统调用的瓶颈和薄弱点。如是否有服务节点是热点或单点服务,是否有过长的调用链路,是否存在业务耦合相互影响等等。


以我现在负责的京东服务市场为例,服务市场采用 SOA 微服务化的架构设计理念,将服务市场设计为模块化和层次化的架构风格,高层次模块调用低层次模块,低层次模块通过接口向上提供服务。而复杂的调用链路,必然造成业务之间的相互影响,所以,通过对服务市场从部署、数据库访问、服务 PRC 调用、消息接收等进行了纵向垂直部署隔离,实现即使任一垂直域无论因为服务器还是数据库问题,影响不会扩散到其他业务上。这我会在后面详细讲述如何实现纵向垂直部署隔离。



梳理系统薄弱点


无论系统架构是以哪种形式展示,我们都希望能够通过梳理把系统的薄弱点甄别出来。那系统薄弱点都有哪些特征呢?通过哪些手段能检查出系统薄弱点?


我们想一下,系统薄弱点可能引发哪些灾难,严重的有系统宕机,服务不可用,性能下降,404,CPU 100%,OOM 等等,所以,可能产生上述隐患的点就是我们要关注的系统薄弱点。对于系统薄弱点,我们可以通过以下几点进行排查:


• 检查没有脱库的功能:我们知道大促时的流量可能是平时的 2~10 倍,所以一些平时性能还好的查询接口,极有可能因调用量猛增,造成性能的极剧下降,如果其中的某些接口还是查询数据库的,那可能就会给数据库产生极大的压力,极端情况可能造成数据库 CPU 100%,出现服务不可用,因为数据库本身的架构设计就不是抗量的,所以对没有必要查库的功能进行脱库改造,以保证数据库的稳定,是非常重要的,尤其是那些严重依赖数据库的系统。


• 检查慢 sql:不是所有的功能都能实现脱库的,所以慢 sql 的检查就是为了保证数据库的稳定,因为一个慢 sql 就有可能把数据库的 CPU 打到 100%,一是由于慢 sql 最容易出现的是没有索引,二是由于慢 sql 大多是关联查询、嵌套查询,以及使用聚合函数等造成的,还有就是慢 sql 大多需要回源查询,大量的请求会造成查询能力特别慢,还会造成其他请求无法获取连接,影响正常服务。所以,对于那些特别依赖数据库的系统,要每日订阅慢 sql,进行优化。优化就是优化数据库索引,将慢 sql 变成快 sql。


• 检查 ump 和 log:人常说,研发人员有两只眼睛,一只是监控报警,另一只就是日志,所以无论什么情况监控报警日志一定不能少。因为有了监控就能做到即时发现问题,有了日志就能做到迅速定位问题。否则,出了问题,就是两眼一抹黑,一通胡猜。我经常看到,当有些问题从客服那里投诉过来,才发现,要么该有的监控没有,要么有监控却没有报警,以及在解决问题时总是找不到关键的日志,只能干着急。


• 检查 jsf、mysql、jmq 等 timeout:设置 timeout 实际上是一种快速失败策略,使系统具备自我保护的能力。检查超时,一是检查该有的设置有没有,二是检查设置的时间是否过长。没有超时设置,则系统就没有自我保护的能力,这自不必说,当大量请求连接因为长时间运行而无法得到释放时,系统的资源很快就会被耗尽,从而造成了服务的不可用。而过长的设置,同样在访问量大的时候,就会导致请求连接积压,这也会导致系统的 CPU 快速飙升。那超时应该设置多少合适,这需要具体情况具体分析,但一个查询请求设置 10s 超时肯定是跟没设置一样的。


• 检查 redis 热 key、大 key、慢日志:热 key 和 大 key 是不同的,热 key 是某些 key 可能会被突然暴增的流量大量访问,这些 key 又碰巧集中存储在同一分片上,从而使得该分片的 IO、CPU 等资源吃紧,极端情况下迫使 redis 进行 failover 主从切换,但切换后的瞬时流量可能又一下子击穿 redis,迫使 redis 再次 failover,如此反复,服务几乎就是不可用的。而大 key 则是某些 key 存储的 value 很大,或者结果集很多,也是在可能暴增的流量下,大 key 不合理的查询,使得 value 在 IO 传输中阻塞,这情况和慢 sql 很像,又因为 redis 是单线程,所以大 key 查询造成 IO 问题就会很容易凸显出来。所以,如果检查出热 key 或大 key,就建议进行修改。


• 检查 master-slave 同步延迟:master-slave 同步延迟很大可能造成数据不一致性,这有可能影响业务正常运营,如创建订单写到 master,然后从 slaver 查询订单,但由于延迟太大,就可能影响用户查不到,你可能会说,这还好吧,慢 1~2s 不会有太大影响,但这个逻辑如果放在创建订单之后马上查询订单,根据查到的订单创建结算,在这个场景下,如何查询 slave 找不订单,就是不可接受的,这可能导致流程代码出错。所以,需要评估这种延迟是否对业务产生影响。


• 检查定时 worker 全量扫描任务:定时 worker 大多数是在运行数据订正的任务,而数据订正往往又需要查询大量数据进行比对,其实,这都还好,不好的就是几次深分页的查询,可能造成数据库性能的极剧下降。所以,检查定时 worker,尤其要避免慢 sql 和大数据集的查询,否则会造成人为的流量洪峰。还有,检查定时 worker 的执行频率,检查不同 worker 的执行时间,尽量避免不同 worker 同时执行,检查定时 worker 执行的服务器是否单独部署。


与运营沟通 618 运营节奏,应战调用量高峰:提前与运营沟通运营节奏,可以做到知己知彼,并可以预知流量可能流向哪里,这可以有针对性的进行备战。


梳理黄金流程


黄金流程也称核心流程,什么是黄金流程,就是那些出了问题可能极大影响公司或影响用户的地方,就是不容有失的黄金流程。以服务市场为例,服务市场包括服务发布、服务审核、服务订购、服务结算、服务使用共五个环节,那其中哪些是重中之重的核心环节呢?服务市场是面向供需双方的双边市场,以需求方为大头,所以服务订购和服务使用是服务市场的核心环节。


梳理黄金流程,我们要整理出它的大致流向和关键节点,通过系统流向和关键节点发现系统设计不合理的地方,以服务市场交易流程问题,我们看到在履约中心订单完成后,通过观察者模式发送消息、创建订购、推送结算的设计是存在风险的,因为每个观察者失败了就失败了,且每个观察者的业务逻辑都不是幂等逻辑。这种设计的不合理,就必须通过梳理黄金流程来发现。



资源隔离


梳理依赖资源(docker、vip、mysql、jimdb、es、jsf、jmq),及目前资源的服务器状况是否健康(cpu、memory、dish 等),进行纵向垂直部署隔离,实现即使任一垂直域无论因为服务器还是数据库问题,影响不会扩散到其他业务上,而这也是所谓的分离技术。


docker 资源


梳理系统 docker 资源部署情况,设定 x 轴是各个业务线,y 轴是业务系统,整理出一张二维表,根据之前梳理的系统架构图,可以清晰的看到各业务线下各个业务系统在不同机房的部署情况,如是否双机房部署,是否有热备机房,是否部署资源不合理等。机房 1 和机房 2 之间是两个不同的地域部署,所以通过地域可以实现容灾。还有,虽然系统都是一套代码,但可以根据各业务线的具体情况,某些业务线不需要的某些系统就不部署,因为代码走不到那里,并可根据业务调用量,合理配置资源情况。


梳理资源,一是梳理自己的资源部署情况,二是需要对上下游依赖系统,做到资源对齐(为了效率考虑,目前很多应用正常情况是同机房调用)譬如:如果上游部署在 3 个机房,机房 A、机房 B、机房 C,流量配比是 5.3.2,那我们也应该按照该比例部署。



数据仅为示例,不是真实数据;表格形式仅供参考


vip 资源


检查 vip 配置,避免因为 docker 扩容或缩容,导致的 vip 配置错误,将扩容的 docker 加到 vip 中,将缩容的 docker 从 vip 中去掉。检查运营商的 IP 解析情况,譬如,需要支持电信、联通、移动、教育网等。当然,并不是所有业务系统都提供对外服务。热备机房不挂 vip,否则就会有线上流量了。当主力机房出问题的时候,通过将问题机房的 vip 飘到热备机房,从而实现流量切换。



数据仅为示例,不是真实数据;表格形式仅供参考


MySQL 隔离


在 docker 资源的部署背景下,我们绘制 mysql 资源的部署情况,其中,有些业务线下的机房虽然有部署系统,但该业务线的流程是已经脱库的,所以就可以不配置数据库。还有某些流程在某些业务线下只有读操作,没有写操作的,所以,数据库只配置读库,而不配置写库。以及最重要的,不同业务线的应该使用不同的从库,并根据查询数据库的业务量,合理配置从库资源规格。mysql 与 docker 尽可能在同机房部署,这也可以有效的实现系统容灾。



数据仅为示例,不是真实数据;表格形式仅供参考


Redis / Solr / ES 隔离


绘制 redis、solr、es 部署情况与绘制 mysql 思路一样。特别说下,服务市场部署 redis 与 mysql 不同之处在于,redis 是一主一从架构,各业务线共享同一 redis 集群,但不同系统之间使用不同的 redis 集群,所以,如果 redis 挂了,还是会影响所有业务线的,而避免 redis 宕机,则就要注意前面提到的,检查 redis 的大 key 和热 key。



数据仅为示例,不是真实数据;表格形式仅供参考


JSF 业务隔离


梳理业务依赖关系,调整 jsf 调用链路,通过 jsf 分组进行业务隔离,这其实是最重要的,也是最难的,也只有把这个做好,才能实现各业务线出了问题不会相互影响。我们知道,一个系统里,既有 provider 也有 consumer,我们要做的就是保证在某一个业务线内,该业务线内 consumer 一定调用该业务线内的 provider 的,如服务市场的业务线 B,那一定是大前台在业务线 B 下只能调用业务线 B 的商品中心、交易中心、服务引擎等,而这实现就是通过 jsf 的分组别名,这没有啥技术含量,就是要了解业务依赖关系,认真仔细。由于系统是一套代码,对于那些有部署系统,但不提供 jsf 的服务分组,我们可以设置为 disable,以此区分和隔离。


在进行 jsf 分组隔离时,因为工作量很大,很是耗神,还有就会想到一个问题,一个系统提供几十个甚至上百个 jsf 接口出去,为什么分组命名会千奇百怪,几乎是每个 jsf 分组都有自己的命名,但仔细想来 jsf 接口可以做到细粒度隔离,因为 jsf 可以实现进程隔离和线程隔离,这使得即使是同一系统的 provider,也可以实现进一步的细分业务,来隔离各业务间的相互影响。



数据仅为示例,不是真实数据;表格形式仅供参考


JMQ 业务隔离


jmq 大量应用在系统解耦的场景中,而 jmq 同样有 provider 和 consumer,它不像 jsf 那样灵活,可以支持多个分组,jmq 只能控制哪些系统生产消息,哪些系统可消费消息。因为 jmq 是通过 topic 进行消息传递的,我们不能给每个业务线申请一个 topic,所以 jmq 的隔离更多的是,梳理业务依赖关系,对那些不会生产或消费 jmq 的业务线,设置 topic 为 disable,确定消息会被哪些系统生产,又会被哪些系统消费。



数据仅为示例,不是真实数据;表格形式仅供参考


压测


压测不是为了把系统压挂,是否需要测出峰值,需按照业务场景决定。很多业务,可能就需要知道自己的峰值。压测一定是根据当前调用量进行评估,以 2~10 倍为预期值进行压测,压测还要选在掉用量少的时间,并逐步加量。压测尽量做到服务器及依赖资源的隔离,如果无法做到,需要控制好量。尤其当压测会查询数据库的服务,一定不要把数据库压出问题来,如果压出问题,就违背了压测的初衷,压测是为了把系统的瓶颈压出来,而不是把系统压出问题来。即使是完全读取缓存的服务,也会因压测造成系统性能的下降,因为数据在传输过程中的序列化和反序列化,以及对多线程的切换,都会造成 CPU 的飙升,还有注意磁盘空间是否会被日志打满,诸如以上等等问题,不要因为压测造成一场线上事故。


压测我们要关注哪些是结果指标,有并发数、TPS、TP99、成功率,这些结果指标能有效反应服务的好坏,以及关注被压测服务的 docker 的 CPU、内存、load 等系统性能。所以,压测策略一定是逐步加量,从并发 10 - 50 - 100 - 200 - 500,观察服务的 TPS、TP99、成功率是否有降低,还有被压测机从 1 - 5 容器数增加,对比单机服务性能是否有所提升。所以,压测的目的是为了能检验服务能力是否支持可水平扩展,即加机器就可以抵抗洪峰。




最后,压测一定要制定计划,今天压什么,明天压什么,还有跟兄弟团队打好招呼,因为别的团队也会压测,如果他的服务会调用到你这里,而这是你也在压测这个接口,结果超出预期的流量就可能造成意想不到的麻烦。


预案


预案准备至关重要,它能保证系统在出问题时,进行及时止损,避免大出血。止损主要以降级开关来实现有损降级,以保证核心黄金流程不受到影响。因为系统业务演进多是混沌的,所以需要对系统的降级开关进行有效的梳理,哪些是有用的,那些是无效的,还要协调兄弟团队,一起沟通 618 备战方案,确定演练方案,联合备战。


对降级开关的梳理,不能只停留在知道有这个开关的基础上,还要知道这个降级开关在什么场景下开启,以及降级之后的影响有哪些等等,降级逻辑必须场景化,否则出了问题,开关开还是不开,都没有一个准则。



总结


当然,在备战 618 的过程中,有很多事要做,不仅仅是业务隔离和压测,还要在梳理系统薄弱点过程中发现潜藏的问题,进行针对性的优化改造。这里有个题外话要说,备战过程中,我偶尔会听到一些声音,让我非常生气。


一是说,”之前没出问题,所以觉得就没问题“。我见过多少次线上事故,就是因为思想上的怠慢,问题并不是不知道,就是本着侥幸的思想,觉得之前没问题,觉得现在就没有问题。这种想法我认为就是错的,之前没问题,不代表它不是问题,是问题就是问题。我犯过错一个错误,就是大上周上线报警出一个问题,排查有个慢 sql 查库,然后进行了修改,不急不慢改一周准备第二天晚上上线,结果第二天早上就被人刷了,数据库 CPU 直接干到 80%,好在这个功能有降级,且业务之间进行隔离部署,没有造成很大的影响。所以,发现问题一定要即时修改。


二是说,”之前的逻辑不是我写的,我就改了这些,那些代码我不太清楚“。这种说辞更不可接受,你连你改的代码上下文都不了解,你改什么代码,你能不改错么。所以,我要求大家,之前的代码不管谁写的,我不管了,但现在代码在你手上,你就必须负责把它写好,不能总是个临时方案,开个分支出去,最后代码一团浆糊。举个例子,上线新代码为了能实现快速降级,通常使用开关进行切换,这时系统里就会有新老两套代码,那老代码什么时候删除,如果当时写代码的人不负起责任,代码就那么放着,也不删,那后面不仅系统代码会越来越臃肿,而且代码的可读性也会越来越差。甚至不小心弄错了开关,还会出现意外的彩蛋什么的。


来到京东,今年(2019)是我的第 6 个 618,和往年一样,必须保障系统稳定,最后,以曾国藩的一句话作为文本的总结,”结硬寨,打呆仗“。


最后,感谢王洪涛对本文的校订。


2019 年 4 月 25 日 15:489741

评论 2 条评论

发布
用户头像
薄弱点还需要人工梳理,感觉微服务架构的基础设施还是不完善,能让机器统计的为啥还要用人去统计一些不准确的信息。
2019 年 09 月 12 日 09:46
回复
用户头像
兄弟666啊,来我们公司吧,在泰国,收入大几万,邀请你v我TH0631280401
2019 年 04 月 27 日 15:50
回复
没有更多了
发现更多内容

真实 Java 笔试题

旭霁

Java 面试

LeetCode 1232. Check If It Is a Straight Line

liu_liu

LeetCode

Spring整合MyBatis详细分析

Java收录阁

mybatis

软件产品开发流程

Interstate5

软件开发 软件开发流程

面试官浅析程序员面试过程中的二三事

joe

互联网 个人成长 方法 职场 文化

程序员的晚餐 | 5月9日 炖蹄髈

清远

程序员人生

小棉袄,最终却没有变成你的防弹衣

小天同学

个人成长 成长 感悟 母亲节 感恩

理解雾计算(Fog Computing)与边缘计算(Edge Computing)

老任物联网杂谈

雾计算 Fog Computing 边缘计算 Edge Computing

如何打造个人品牌?

石云升

个人 品牌

Android Studio NDK 编译 Bsdiff 库

码农亮哥

android-studio ndk bsdiff

Scrum精髓 - Scrum的核心到底是什么

Bob Jiang

Scrum 敏捷 Scrum精髓 敏捷精髓

ROS与OpenAI结合使用教程(概览)

辣么大

DevOps怎样影响开发运维人员

脚动两轮男之漂流小王子

DevOps

关于查尔斯-斯特里克兰

黄大路

提升认知 小说 个人提升 认识自己

数据挖掘|cross_val_score交叉验证使用

黄大路

Python 数据挖掘 学习 数据分析

回"疫"录(11):别让善良寒了心

小天同学

疫情 回忆录 现实纪录 纪实

Java小想法: JDK许可证

范学雷

Java 编程语言

高仿瑞幸小程序 05 更正轮播组件的高度计算

曾伟@喵先森

小程序 微信小程序 前端

来了来了,2020 首场 Meetup ,可!

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

Redis 命令执行过程(上)

程序员历小冰

redis 源码分析

数据库连接池的大小

Java收录阁

数据库

如何快速对应用系统做一个360度画像诊断?

姜戈

Java 运维 多线程 网络 内存

向上管理第一项:路径P背后的目标B

kimmking

管理

《你好架构师之 压榨硬件价值的利器容器(Docker)》

再见小飞侠

白话计算机网络通信过程

WB

计算机网络 转行程序员

软件产品的信息安全问题

Interstate5

软件开发 信息安全

做程序员有未来吗

这小胖猫

程序员 个人成长 职业规划 技术人

Redis学习笔记(集合类型)

编程随想曲

redis

模块化设计思想产品设计应用

燕陈华

产品设计 模块化流程 流程图

软件产品信息安全 - 数据分类

Interstate5

软件开发 信息安全 数据分类

产品经理中必会SQL技能,相关内容研发可不予支持

韩超

MySQL sql 产品经理

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

备战618,京东如何保障系统稳定性?-InfoQ