饿了么技术运营是如何摆平那些恼人事故的

《饿了么技术运营是如何摆平那些恼人事故的》要点:
本文介绍了饿了么技术运营是如何摆平那些恼人事故的,希望对您有用。如果有疑问,可以联系我们。

饿了么

饿了么技术运营部、风控管理部高级总监

作者:徐盎

编辑:孙淑娟

徐盎,擅长精益运维、精细化风控,通过与公司其他团队协作、推动并完善运维信息化、标准化、服务化的建设,逐步实现自动化运维及交付,数据可视化,进而做到低成本的保障系统稳定;通过数据与规则适配,以及产品设计、人工审计、风控平台建设使每一元补贴用在公司既定目标的实现上.

饿了么平台不仅做外卖,还有蜂鸟、早餐和未来餐厅,以及很多其他的一些平台,正处在快速扩张阶段.整个外卖的产品链条长,从用户下单到最后配送到达,时间大概是30分钟左右,对时效性的要求非常强.

从技术的角度来看,饿了么遇到的最大挑战是事故.本文将围绕事故展开,分成两部分内容:技术运营经历与心得.第一部分经历又分为三个阶段:精细化分工、保稳定(容量和变更)和增效.第二部分心得,是作者对运维服务的理解.

一、技术运营经历

技术运营的职责是尽最大的努力协同更多的人来达成保稳定的目标,可以划分为两个阶段:运维保障、运维服务.现在,饿了么处在运维服务的阶段,技术运营团队作为乙方,把开发出来的产品,开发测试后的服务,做维护,保障稳定、调优性能、提高资源的利用率.

在业务快速扩张阶段,技术团队需要做哪些事情呢?

首先,第一阶段,精细化分工.

通过精细化分工促进并行提速,让专业的人利用专业的知识、最有效的工作方式提高工作效率及代码吞吐量,建立沟通渠道加速决策、信息流通保稳定.

精细化分工分为三部分内容:

第一部分是做数据库拆分和代码解耦.技术工作集中在数据库的拆分,先纵向拆分,不得已才做横向拆分,为了更快地服务业务的扩张,又夹杂了一些对代码解耦的工作.

所谓代码解耦,是把原来的代码系统想象成一个泥球,把它逐渐拆分成很多块.现在是有十多个业务模块,每一模块里面都有专门的团队来维护,内部又会划分域.

饿了么是数据库、代码拆分并行在做.然后,启动了强制接入新发布系统和单实例、单运用,也就是物理拆分.

在整个的代码解耦和精细化分工的过程当中,他们碰到了很多问题,其中比较典型的两类事故是:

  • 事故1:超时,后端服务慢,引发连锁反应,导致前端服务雪崩.用户的请求耗时依赖于 RPC 调用路径上服务的响应时间.当其中某个节点变慢,整个集群都不可用,一般救急措施是要按照调用链从前往后按顺序停服务,然后在从后往前启动服务.

    当这类问题发生的时候,如果没有熔断机制,前端的服务因依赖关系造成雪崩,而且服务不能自己恢复.加了熔断机制之后,当后端问题节点重启或是网络抖动恢复后,前端服务也会自己恢复.

  • 事故2:连续三天商户需要不断重试才能接单,这与Redis治理有关.当交换机发生 Bug 导致网络抖动,受影响最大的就是 Redis,在网络抖动期间积压的请求会建立太多 Redis 连接,连接过多会导致 Redis 响应延迟从 1ms 飙升到 300ms.由于 Redis 请求慢导致服务的处理速度被拖慢,而外部请求仍在积压,最后引起雪崩.

    刚开始出现故障的时候,因 Zabbix 的监控周期长,运维工程师监控不到.后来,他们用了三天的时间进行压测复现,才排查出来故障点.事后,运维工程师打造了一种新的基础设施监控工具,实现方式是每 10 秒钟把 /proc 目录下的所有指标收集起来,基本能做到 3 分钟内定位问题.

    还有丢包的重传也会严重影响 Redis 的性能,因为一个 HTTP 引擎到后端有可能产生几十个甚至上百次的 Redis 请求,其中有一次被命中重试,对服务的影响都是致命的.

精细化分工的第二部分是组建水平团队,例如大数据是水平团队,业务线是竖向团队,划分之后,从整个业务的发展走势图上升曲线非常陡,可以推断技术并没有防碍业务的快速发展,也就是技术的吞吐量、新产品研发效率是健康的.

期间,运维工程师还做了几件事,比如把监控分为 Metric、Log、Trace、基础设施四个部分.组建 Noc 团队,负责应急响应,当发现有问题的时候,及时把信息通过 Oncall 通报给各成员.还有梳理各类扫除,接入发布、 SOA,降级熔断开发等.

大扫除

大扫除的概念是什么呢?就是工程师对历史的事故进行分析之后,大概做出技术总结,把经常犯的一些错误,列成一些可做的规程,给所在部门的骨干进行宣传.具体内容包括:

  • SOA 的服务治理,这里主要强调的是领域划分,高内聚低耦合.
  • 对公共组件的治理.这里的数据库 Redis 由两个专业的团队组成,一个是 DA,一个是 DBA.DA 治理的主要方案是收集各个产业伙伴的信息,规划容量,治理开发的使用姿势,把经验固化到研发流程里.
  • 业务指标的梳理,包括对 TPS 的概念设定(状态轮转后再根据返回状态打点)、状态的停滞时间和状态的堆积深度,这个堆积深度主要是后端一些服务的状态轮转.
  • 对超时链的合理设定和重试机制.
  • 外部依赖及开关.为什么强调外部依赖呢?外部依赖可以分为两类,一类是跟其他公司的合作,例如调用其他公司的支付接口.还有一类依赖是团队之间的依赖,这里请不要相信任何人的服务,Bug 随时都会发生.
  • 关键路径.为什么要设置关键路径呢?一个是熔断,一个是降级.当非关键路径出现问题的时候,直接把它降掉就行了,不要影响关键路径.另外一个好处是接下来做补偿的时候,可以有针对性去做.
  • 日志.团队在日志上发生的事故也很多,可以逐个通过案例进行宣讲.
  • 正在实现中的制定盲演习目标.因为八九百个技术工程师之间的代码交互本身是一个复杂系统,业务又是一个非常长的业务链,关键路径涉及的服务超过 100个,简单的功能测试是可以的,但是容量大的时候,将很难定位他们之间存在的问题,比如 A 团队和 B 团队之间的代码耦合验收.这时想到的解决方案就是盲演习.盲演习除了在业务方可以做验收之外,还可以做基础设施,包括 Redis 集群、 MySQL 集群和网络.曾经做过一个测试,把一个 Redis 实例上的包量,按照百分之一的丢包率计算,导致整个全站的业务都掉底.当时整个 Redis 集群有12台,有几百个实例,其中一个实例有问题,就造成这么大的影响.通过盲演习,技术正在寻求单个节点宕机影响最小化的解决方案.

第二阶段,保稳定期.头号敌人是容量问题.

在业务快速扩张阶段,影响系统稳定性最大的敌人是容量,类似温水煮青蛙,或突然雪崩.因为不同语言判定容量的方式不同,饿了么1000多个服务组成的复杂系统,业务场景快速变换,服务变更频繁等等因素,导致容量问题困扰了近一年的时间.

最后采用的是定期线上全链路压测的方法,发动了一次百人战役,历时一个多月,整改了近 200 个隐患点,基本解决了容量问题.即便在低谷期的时候,也采用全联路压制.还可以配合技术在上线前的压测一起来做,然后把这些数据统筹起来进行分析.

秒杀事故

在 517 秒杀大促准备阶段,技术的运营思路是想用日常服务的集群来对抗秒杀,活动前把整个的容量提高了两倍多.但是当日订单量飙涨,秒杀开始后的那几秒钟,瞬时并发请求达到平常的 50 倍.当流量洪峰到来的时候,洪峰直接把前端 Nginx 的网络拥塞了.

反思下来,出现问题的原因是秒杀场景的经验少,对活动带来洪峰数据的预估过低,URL 的限流未区分优先级等等.改进措施是专门针对秒杀搭建了一套系统,主要做了分级保护、建立用户端缓存、泳道、云集群和竞争缓存等.

第三阶段,增效.通过工具、资源、架构改造,提高效率.

事故1:连续两周蜂鸟配送出现各类事故

原因是消息不断的批量重试导致 RMQ 堆积,UDP 句柄耗尽,熔断判定使用姿势不对.可以看出,新业务在快速交付过程中,代码质量、外部组建的使用姿势是事故高危隐患点.

事故2:MySQL

SQL 慢查询,从每周的 2 到 3 起,降低到近期很少出现.解决办法是使用组件治理.组件治理首先是服务化自己的资源、容量.第二个是设限流,做降级.第三个主要是限制开发的一些姿势.

这三点做完之后,接下来技术做了自动化相关的一些工作,主要是信息、标准化和编排.再一个是前置指标KPI,就是当一些组件刚使用起来时,要做一些量化的考虑.把这几条做到以后,技术基本上能避免出现大的故障问题.

对于使用姿势的治理,对稳定的收益最大.这里特别介绍几个关键点:

  • 必须要有对组件精通的伙伴,看过源码,了解社区里碰到的所有的坑,还要深入业务开发一线,了解业务场景,初步判定组件在业务中的使用场景.
  • 工程师进行知识传递,通过各种渠道把标准化、开发规范、集群化、开发使用姿势等知识点传递到位.
  • 尽快把经验或红线固化到资源申请、架构评审等流程、工具里.

事故3:RMQ

在饿了么,RMQ 的使用场景非常多,有 Python,也有 Java.2016年年初的时候,工程师虽然做了一个技术、配置的梳理,还是留有很多的场景是没有想到的,主要涉及的问题有如下几个:

  • 分区,就是技术在做割接的时候,核心交换是升级换设备.当设备网络割接完了,虽然在 RMQ 集群里面的配置是可以自恢复的,但是仍然还有很多集群没有做到自恢复.所以,技术特意预留了一个冷备 RMQ 集群,把现网所有的配置都部署到那一个冷备集群里面去.线上 20 多个 RMQ 集群中,如有一个宕掉的时候,可以及时切过来.
  • 队列堵塞.主要是追查消费能力,因为业务飙升,消费能力不够,极容易导致队列堵塞.
  • 使用场景.举例来说,在发送、接收消息的时候,如果每发一个消息,每收一个消息,都重建一次链接或者都重建 Queue.这种重建会导致 RMQ 内部的一个Event机制.当请求增长到一定程度的时候,就会直接影响 RMQ 的吞吐量,RMQ 的容量会掉到是原来的十分之一.

老大难:故障定位、恢复效率

故障定位慢的最主要原因是饿了么整个系统的信息量太大,当一个问题出现的时候,主导这个事故定位的工程师拿到的信息非常多,比如拿到三个信息,他很难决定到底是什么故障,需要如何检测出来.

当前的做法是进行碎片化、地毯式的大扫荡来排障.什么是地毯式的大扫荡呢?就是把足够多的信息先拿到,进行分工,要求涉及的每个工程师都来查看.内容涉及到外卖、商户、支付和物流,然后还有基础业务和网络监控,外网的一些流量,还有服务器的一些负担等等.

这时,技术工程师的有序自证就变得非常重要,当前能做到的是每一个人能看到当前负责的服务是不是有问题.还需要做的就是提供工具,比如交换机的丢包、服务器的丢包.通过一些工具,让技术工程师及时发现问题,但是这个过程是需要时间的.

另外一个是在自证的时候,一定要仔细地检查.作为团队中的一个成员,每一个技术工程师负责相应的板块,但一旦因为个人疏忽或是自检不足造成一些失误,要自己“刷锅”.故障定位后,提升恢复效率解决问题才是关键.

还有,应急演习很重要.应急演习直接关系到系统恢复的效率,当一个集群出问题的时候,技术能不能快速的恢复.

二、运营心得本次分享大部分围绕事故来讲.每一次事故的出现都不是偶然的,很多问题是可以通过正确的使用姿势、提前做容量预估、灰度等方法规避的.如果说技术只是就事论事把这一件事情解决的话,事故往往在另外一个时间点还会出现.

这就要求工程师以思考的方式去做事,比如做事故复盘、事故报道审核,还有验收小组等.然后,通过在各个阶段,多次把一个事故涉及的关键点提出来,不断地进行总结并制定可行的操作规范.

问题的解决往往需要思维模式的转变,需要伙伴们多想想怎么从日常重要紧急的事务里抽离出时间思考.

还有要敢于折腾.折腾是什么概念呢?就是要不断的演习、捣乱,工程师对于维护的系统,自己要非常的熟悉,这样在定位和解决故障的时候,就会非常精准.

最后一个是灯下黑的问题,特别是基础设施这块.这在当时让人很头疼,查一个问题在基础设施上花费的时间是十多分钟到一个小时.后来有一个小伙伴改变思路,做出了一套系统,帮助团队非常好地解决了这个大问题.所以敢于思考,勤于尝试是饿了么技术团队非常重要的一个心得.

文章来自微信公众号:51CTO技术栈

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


起步 处理器架构,参考 x86是指intel的开发的一种32位指令集 intel和amd早期的cpu都支持这种指令集 AMD比Intel率先制造出了商用的兼容x86的CPU,AMD称之为AMD64 Intel选择了设计一种不兼容x86的全新64为指令集,称之为IA-64,后来支持AMD64的指令集,
pscp pscp -P 22 C:\work\test.txt root@192.168.1.5:/home/data pscp -P 22 root@192.168.1.5:/home/data/test.txt C://work// 检索 find / -name default.config
文件处理 ls -a # 显示所有文件 ls -l # 显示详细信息 ls -d # 显示路径 mkdir /目录名称 # 创建目录 cd /目录名称 # 切换目录 pwd # 显示当前路径 rmdir /目录名称 # 删除目录 cp -rp [目录名称] [目标目录] # 复制目录到目标目录 cp
准备一台电脑(我就用联想拯救者r7000演示) 参考博客制作启动盘 插上U盘,启动电脑,一直按F2 进入如下页面后,将U盘设置为第一启动项,点击exit,保存并退出 之后进入如下页面,选择第三项 进入如下页面,选择第四项 进入如下页面,选择第一项,选中后,先不要点Enter 按e键,将inst.st
认识 Linux系统是参考了UNIX系统作为模板开发的,但没有使用UNIX的代码;是UNIX的一种,但不是衍生版 在Linux内核的基础上开发是发行版 分区 逻辑分区永远从5开始 步骤 挂载:可理解为分配盘符,挂载点即是盘符名;不同之处:Linux中是以空目录名称作为盘符 Hda 第一块硬盘 Hda
文件处理命令 以 . 开头的文件是隐藏文件 以 - 开头表示这是一个文件 以 d 开头表示是一个目录 以 l 开头表示是一个软链接 第一个root是所有者,第二个root是所属组 ls -h 以文件默认大小后缀 显示 ls -i 查看i节点(唯一标识) 所有者:只能有一个,可变更 所属组:只能有一个
参考 01 02 03 前提环境 本地安装VirtualBox,并安装CentOS8,配置网络后,window系统上putty能连接到CentOS8服务器 配置步骤 右键服务器复制 启动复制后的服务器,查看ip和hostname发现和原来的服务器一样,需要修改 hostname # 查看主机名 vi
文件搜索命令 星号匹配任意字符,问号匹配任意单个字符 -iname 根据文件名查找且不区分大小写 -ok 命名会有一个询问的步骤 如果没有找到指定文件,可输入命令:updatedb 更新文件资料库;除tmp目录不在文件资料库收录范围之内 locate -i 文件名 # 检索时不区分大小写 which
安装环境 安装最新版的Virtual Box,点击安装 下载centos8镜像 创建虚拟机,可参考 选择下载到本地的镜像 设置启动顺序 点击启动 启动过程中报错:“FATAL:No bootable medium found!” 1.没有选择iso镜像 2.光驱没有排在第一位置 3.镜像只能选择x8
Linux严格区分大小写 所有内容文件形式保存,包括硬件 Linux不靠扩展名区分文件类型 挂载:将设备文件名和挂载点(盘符)连接的过程 Linux各个目录的作用 bin表示二进制 服务器注意事项 远程服务器不允许关机,只能重启 重启时应该关闭服务 不要在服务器访问高峰运行高负载命令 远程配置防火墙
IDE连接Linux,上传下载文件 参考1 参考2 连接Linux 上传下载文件 本地项目打包后上传 查看是否上传成功,右键下载 补充 后端项目开发完成后,需clean掉临时文件target文件夹,且只推送修改过的文件 前端项目开发的过程中,需要在每个子组件中使用scoped,确保每个子组件中的编码
起步 LTS与普通版本的区别 LTS版本的发布周期更长,更加稳定 安装jdk sudo mkdir /usr/lib/jvm # 在Ubuntu中创建目录 pscp D:\安装包\linux源码包\jdk-8u291-linux-x64.tar.gz chnq@192.168.0.102:/tmp
前言 最近在b站上看了兄弟连老师的Linux教程,非常适合入门:https://www.bilibili.com/video/BV1mW411i7Qf 看完后就自己来试着玩下,正好手上有台空闲的电脑就尝试不使用虚拟机的方式安装Linux系统 安装步骤 制作启动盘 下载ISO镜像,我这里下载的是Cen
新建虚拟电脑 设置内存和处理器 设置硬盘大小 完成 设置 查看光驱 设置启动顺序 点击启动 选择第1项 进入图形安装界面 选择安装位置,开始安装 设置root密码 重启 登录 查看本地文件夹 配置网络,点击设置 查看宿主机ip C:\Users\ychen λ ipconfig 无线局域网适配器 W
源码包安装需手动下载后安装 二进制包则在package目录下 rpm命令管理rpm包 若某个rpm包依赖于某个模块,需要到网站www.rpmfind.net查询该模块依赖的包,安装这个包后自动安装模块,之后就能安装rpm包了 安装升级时使用包全名 查询卸载时使用包名 虚拟机中的Linux系统安装rp
首先进入命令模式,再输入以下命令 命令模式用于输入命令 插入模式可对文件编写操作 编辑模式下的命令是在冒号后输入 :12, 15d # 删除指定范围的行,这里是删除12到15行 :n1,n2s/old/new/g ## 表示从n1行到n2行,old表示旧的字符串 vim使用小技巧:自定义快捷键,如快
使用源码包安装,需要自己指定安装位置,通常是 /usr/local/软件名/ linux中要想启动执行文件,应使用绝对路径 /绝对路径/rpm包名 start ## 执行方式一 service rpm包名 start ## 执行方式二 使用源码包安装后,由于自定义安装路径,就不能使用service命
网络命令 在收邮件的用户中,输入 mail 可查看邮件信息,输入序列号查看详细信息 在mail命令下,输入h 查看所有邮件的列表 输入:d 序列号 # 删除邮件 last # 统计所有用户登录或重启时间,用于日志查询 lastlog # 显示包括未登录用户的登录时间 lastlog -u 用户id
若要使用yum管理,必须能连接网络,首先配置网络IP 进入yum源文件中启动容器 使用yum源头安装rpm包不需要进入package路径,同时也不需要使用包全名,会有yum自动管理 安装软件组
简介 client即是本机安装的docker,相当于git Docker_host相当于centos系统 registry则是docker仓库,相当于GitHub 镜像用于创建docker容器,一个镜像可以创建多个docker容器 容器是由镜像创建的运行实例,(镜像相当于类,容器相当于类创建的对象)