记一次服务宕机、优化全流程(以后也可以装X了)

news2025/7/7 15:27:53

视频地址: https://www.bilibili.com/video/BV1924y1y7jN


221115上午10点的时候客户反应进入小程序慢,打开监控发现服务pv已经超过了历史之最(印象中最高的是100w),这次到了400w。原因是因为推广了一个发红包的活动。

数据体现

最终pv峰值达到了 400w/小时,5分钟峰值 60w, 1分钟峰值 12w,单个服务1分钟峰值 4.6w


整体数据面板


接口访问排行榜


一分钟峰值


一分钟 exhibition峰值


exhibition 承受的压力

一天整体的访问量是 1377w, exhibition 510w


问题现象

我们后台大概有50多个服务,其实有一个服务是 exhibition,承载了C端用户的主要访问量,exhibition 服务一直重启,我们把节点从 12个扩容到28个依旧扛不住压力。

其它服务的 pod都是看似正常的,exhibition 服务的表象是 pod一直在重启。


问题排查

1、排查所有其它服务

主要是用来判断下游服务是否已经宕机了,其它服务的 pod都是正常,也没有重启,然后就跳过这项。


2、排查压力原因

我们使用的是阿里云的数据库,有很好的监控,查看数据库的压力都很小,cpu 在50%的样子,然后我就把 pod节点从 12、16、20、28, 但是用依旧扛不住。


3、热点接口问题排查

请求最多的接口是 /information 接口,平均响应时间到了 8s+, 仔细看了这个接口却发现也没法优化,因为在正常的时候,它是没问题的,下面是前天和今天的数据
接口平均时间都是在 0.3s 以下


4、连接池排查

我们的服务里面配置了 256个工作线程,但是数据库连接池里面的只配置了50,遂即调到了 200,但是用依旧扛不住。 (ps:这时候的数据库也没有达到顶峰)

server:     
  undertow:    
    io-threads: 16    
    worker-threads: 256

5、结果

到了 13.40的时候流量慢慢下来了,这个时候服务也就恢复了正常,但这不是结束,客户说周四的晚上还会推一波流量,所以就有了我们下面的优化。

另外可能很多人第一反应就是限流,我们也做了,如果不限流一个 pod都起不来,以前对于限流也没有什么思考,现在觉得:限流的第一步是要考虑你的系统最大并发量,不然限流就是个借口。

exhibition 服务在1.5w/min 的时候就开始挂机,顶峰4.5w, 或许我们的服务达不到4.5w,但绝对不会是1.5w。


总结:系统优化

其实很简单,承受大部分流程的就是这个 exhibition 服务,我们要保证它的可用性,要找到它短板,并准备好限流策略。

下面是阿里云的 EDAS全链路追踪工具,通过这个工具,我们可以看到一次请求的全链路,每一个步骤的耗时

优化的手段主要是

  1. 通过 EADS 去找热点接口超时的数据,分析超时的原因
  2. 去看异常采集服务都抛出了些什么异常
  3. 脑子思考

1、慢SQL

慢sql一定是要优化的,这是致命的,并发一大将会全部阻塞。在这之前我们已经做过一轮的慢sql的优化了,并且复杂的查询都已经迁移到 ADB大数据库里面了。

因为是使用阿里云的数据库,所以可以直接查看哪些是慢sql,简单的sql它可以直接给出优化。


2、热点接口优化

上面说到我们的热点接口是 information 接口,正常情况它是没什么性能问题的,但也经不住调用次数那么多。

ps:热点接口一定一定不能是慢sql,不然就死定了,这个接口我们优化过,所以不属于慢接口。

解决办法:

  1. 从业务出发让前端做本地缓存,减少调用的次数。

3、下游服务超时

通过观察日志、EDAS分析,我们发现有很多的下游服务宕机了

  1. 基础SDK,我们有基于单表的增删改查SDK
  2. 错误采集服务
  3. 飞书通知

日志中可以看到很多调用这三个服务超时的问题,但是我们也检查过我们的基础SDK和错误采集服务,为什么没发现呢?

基础SDK和错误采集服务都是些基础的新增查询操作,它们的pod节点很少,但是服务也没有挂,所以我们检查 pod的时候发现它们都是正常运行,并且没有重启。

原因很简单,它们的工作线程都已经满了,新来的任务都进去了队列等待,队列满了就会拒绝,但是在队列中的请求就会耗时很长,甚至超时,而我们的exhibition服务一直在等它们返回就造成线程阻塞。

基础SDK和错误采集服务不会宕机的原因是因为它是正常工作的,没有内存不足,只是排队工作而言。

exhibition 服务宕机的原因,是因为我们配置了存活检测机制,当连续3次请求服务都得不到结果的时候就会重启,而我们256个工作线程都在工作或者阻塞了,没有线程来处理我们的存活检测,导致存活不过就被重启了。

至于飞书通知就没什么好说了,第三方的工具,一样的先进入队列,然后开始拒绝,队列的就阻塞了。

解决办法:

  1. 下游服务也跟着扩容,并加上存活检测,及时发现瓶颈
  2. 去掉飞书通知

4、内部服务调用整改

服务多了,内部之间的调用也会很多,大多数人都会选择使用 域名的方式去调用,但这样其实会走一遍外网会耗时更多也可能被防火墙拦截,而昨天通过 域名调用的次数有 43w

解决办法:

  1. 统一改成 k8s内部端点 访问

5、连接池

之前我们的MySQL连接池配置的是 50,但是服务的工作线程是256,也匹配把MySQL的连接池配置到 200。

Redis 连接池,之前redis连接池也是50个,现在也改成了200,线上redis支持的连接数是2w个。

6、Redis 慢日志

Redis也是使用的阿里云的,发现也会有不少的慢日志,如果是发生在高并发的时候也是致命的,查看了发现是因为一个操作使用 keys 命令,全表扫描了。

解决办法:

  1. 找到具体的地方,去掉这个操作,设置过期时间不去使用 keys 命令

7、内部接口逻辑处理慢

有一个给用户发消息的接口,这是一个个循环消息推送,需要组装数据和调用第三方接口

解决办法:
接口做成异步去调用,设置单独的一个线程池,并且设置好线程数、拒绝策略、阻塞队列的大小


N、接口限流

除了做优化本身我们也做了限流策略,用来做兜底。

N-1、基于城市限流
我们有 550w的 openId,其中有手机号的有289w,通过阿里云的归属地查询接口把这289w的数据全部洗到一张表里面,策略就是 保新弃旧

status = 1 就标识限制不能请求,这时候我们会返回http状态为 401,前端接收到了就会给一个友好的提示。

限流的代码也很简单,就是写一个过滤器 (比拦截器好,从过滤器到拦截器这中间要做很多事情,没必要)

这里其实还有2个问题

  • 这个查询的SQL性能如何
  • 限流策略如何精确

当我创建完这张表的时候,我查询了一下这个SQL,耗时在 60-80ms 之间

SELECT open_id  FROM im_region_limit_rule WHERE open_id = 'oTfJO5XKWeMfwOGzsJeU6DcBBBUY' AND status = 1

对于将近300w的数据表来说,好像也还不错了?(已经创建了 openId + status 的联合索引,并且不需要回表,执行分析也是 row = 1),但在高并发情况依旧是不行,后面尝试了很多的策略都不行,

  • 比如修改索引为 hash
  • 修改引擎为 MyISAM

最后没办法上到线上一看,平均耗时当在 2ms 左右,所有猜想 Navicat 这类的工具主要是耗时在了创建和释放连接上了,而我们的代码是有连接池的

这样简单推算一下,我们数据库16核的,2个节点,工作线程有 64个

2 ms/次 * 64线程 * 500 = 64000次/秒

表很简单,限流策略也很简单,但是如果你的服务被击溃了,你的脑子将是混沌的,思考能力急速下降,流量是花钱投放来了,这时候的时间就等于金钱了,为了最高效的解决问题,其实我们应该提前去把限流的脚本写好,到时候按照批次执行就好了,这里我准备了三个SQL

  1. 有的手机号是异常手机号查询不到归属地的,第一步限流 —— 26w
  2. 越秀在全国25个城市有楼盘,限流掉非这25个城市的手机号 —— 134w
  3. 越秀的总部在广州,我们在深圳,限流掉非这两个城市的数据 —— 214w

N-2、基于ip限流

第一步是上面的城市限流,如果第一步还是扛不住的话,那就需要第二步了。

原理差不多,也是把访问的ip、访问次数、访问地域存到一个表里面去,每分钟异步更新一下数据,然后去实时查询

  1. 先是限流非 25个楼盘的城市ip
  2. 再是限流非广州和深圳的ip
  3. 限流深圳访问大的ip
  4. 限流广州访问量小的 ip (为什么呢?因为越秀总部在广州,大的访问量应该在他们那里,如果他们领导打不开,那就完蛋)

虽然策略差不多,但是这里的实现思路变了,变得更有趣了,不再是代码侵入式了。

k8s里面有个组件是 路由Ingress, 你可以在你需要限流的服务里面配置一个 annotations ,让它在访问你的服务时候先去访问 B服务,通过B服务的结果来判断是否要访问你的服务。
并且它可以实时修改,实时生效,支持传参,可以实现不同的策略替换,上面的基于城市的限流,也可以放到这个里面了。

metadata:
  annotations:
    nginx.ingress.kubernetes.io/auth-url: >-
      http://XXXXXXXX:8000/mirror/rate/limit?limitType=user

M、另外再说一下机器的配置

M-1、K8S

360核, 796G


M-2、MySQL

双节点 16核 128G


M-3、Redis

16G双节点


M-4、ADB


结果:

哎、本来今天晚上也就是17号,说是会有一波推广,刚好可以验证这次优化,但却只是小推广,太失望了…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/18500.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java练习题第二十七期:幸运的袋子

作者:有只小猪飞走啦 博客地址:文章目录前言一,题目二,解析三,代码前言 本博客是小博主在做Java算法题的过程中一些觉得可以分享的题目,希望对你们有帮助,如果哪里写错了或者有更好的解法&…

详解Unity中的Nav Mesh新特性|导航寻路系统 (一)

前言 之前我们讲解过Unity的Nav Mesh系统,其中提到过这个新版的Nav Mesh,它解决现有Nav Mesh的几个缺陷,比如无法动态烘焙,无法按照Agent的半径和高度适当的判断可行路径。现在新版Nav Mesh可以彻底解决这个问题!某种…

实验送样、数据分析样品、组名命名规范

俗话说巧妇难为无米之炊,而样品就是“米”,没有样品,就无法开展实验,无法获得数据,无法毕业,无法发文章。鉴于样品的重要性,非常有必要对样品进行详细且规范的记录,方便他人也方便自…

Java 线上机器 CPU 100 的一次排查过程

文章目录1. 问题发生2. 数据库连接关闭问题排查3. 问题的进一步排查4. 解决方法1. 问题发生 日常敲代码突然收到生产环境异常告警,线上有一台机器 CPU 使用率飙升到 100 触发扩容,工作群里一下子鸡飞狗跳。 出现问题,首先当然是查看监控和日…

在群晖NAS上搭建导航页_通过Web Station搭建

一、业务需求 1.1、需求说明 我们在使用群晖NAS的过程中,随着时间的推移会安装各种各样的软件内容和管理工具,而这些内容又都是一些网页界面(特别是一些在Docker中搭建的工具)时间久了我们也记不住那么多工具的Web界面地址&#…

激活Windows时出现错误代码0xC004C003怎么办?

Windows是我们最常见的电脑操作系统,那么如果我们在尝试激活Windows时出现错误代码0xC004C003,应该如何解决? 什么是Windows激活错误0xC004C003,出现该错误的原因是什么? Windows操作系统为了抑制盗版软件&#xff0c…

3D建模就业前景如何?加班多吗?值不值得入行

加班其实都还好🤔,因为这个岗位是按照项目进度考核(算钱)的,老手做一个模型要5,6个小时,新手可能需要10个小时,新人刚入行,做东西效率跟不上😰需要加班来弥补是肯定有的事…

SpringMVC-整合详解

SpringMVC-整合详解 MVC 什么是MVC? 它是一种开发模式,它是模型视图控制器的简称。所有的web应用都是基于MVC开发的 M: 模型层,它是模型视图控制器的简称。所有的web应用都是基于MVC开发 V: 视图层,html、javascript、vue等都是视图层,用…

高校实验室设备管理系统设计与实现-计算机毕业设计源码+LW文档

数据库代码: /* Navicat MySQL Data Transfer Source Server : mysql5 Source Server Version : 50562 Source Host : localhost:3306 Source Database : ssmgxsyssbglxthsg3511cg ​ Target Server Type : MYSQL Target Server Versio…

Linux磁盘分区和管理

文章目录一 添加硬盘,创建Linux分区1.首先准备一块新的硬盘2.检查系统是否识别了硬盘3.对磁盘进行分区3-1 创建MBR磁盘分区3-2 创建文件系统3-3 挂载文件系统二 创建交换空间2-1 创建分区2-2 设置分区类型2-3 格式化交换空间2-4 激活交换空间三 删除磁盘的分区3-1 备…

【GPU】Nvidia CUDA 编程高级教程——利用蒙特卡罗法求解近似值(CUDA-Aware MPI)

博主未授权任何人或组织机构转载博主任何原创文章,感谢各位对原创的支持! 博主链接 本人就职于国际知名终端厂商,负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作,目前牵头6G算力网络技术标准研究。 博客…

11.24直播预告 | AIGC,看热闹不如看门道

如果把AI比作既富含能源,又无限神秘的海域,那么AIGC这条近半年内流经学术界和创投圈的支流,也无疑既带来了无数机遇,又蕴藏未知风险。 几天前,将门-TechBeat社区的专题(《AIGC的八大前沿创新》)…

Allegro基本规则设置指导书

Allegro基本规则设置指导书 下面介绍基本规则设置指导书之Analysis Modes 点击set-up-constrains-Modes 调出Analysis Modes,这个是所有DRC的总开关 下面介绍常用的一些开关设置 Design Options (Soldermask) 从上往下 阻焊到阻焊的间距 阻焊到pad和走线间距 阻焊到shape…

leecode #加一#二进制求和

题目描述: 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。 你可以假设除了整数 0 之外,这个整数不会以零开头。 分析:对数…

简单版的采用前后端分离模式实现SpingBoot新增查询功能

目录 后端代码编写 前端代码编写 首页展示: 新增: 开发工具:IDEA、HbuilderX 技术点:后端:SpringBoot,前端:ElementUIvue,采用前后端分离模式实现。 后端代码编写 目录: 代码…

多线程高并发笔记

一、基础知识 1. 线程打断的三种方法 interrupt() 打断某个线程(其实只是设置一个标志位)isInterrupted() 查询某线程是否被打断过(查询是否设置了标志位)static interrupted() 查询当前线程是否被打断过,并重置打断…

计算机毕业设计ssm+vue基本微信小程序的今日菜谱系统

项目介绍 谈到外出就餐,我们除了怕排队,也怕这家餐厅的服务员不够用,没人为我们点餐,那么一餐饭排队一小时,点餐恐怕也要花个半小时,这样不仅给消费者的用餐体验大打折扣同时也给商家的口碑造成了严重负面的影响,所以开发今日菜谱微信小程序系统是必须也是必然的。 本系统采用微…

vue2 sass 安装及使用

最近在看前端。其一因为手里有个项目uniapp的里面使用了sass,但是有sass报错,其次想自己写个vue2后台,感觉sass写起来科学点。但是……版本这个东西……太费劲了…… vue2-cli集成webpack,使用vue create 项目名后再安装sass相当…

C++程序设计期末考试复习试题及解析 3(自用~)

DDL1.题目及分析1.对象数组的析构顺序2.浅拷贝的隐患delete p 还是 delete[]p ?类似的题,自行查阅3.常数据成员的初始化4.默认构造函数5.cin、cout所属类6.重载7.静态数据成员8.多态8.联编9.内联函数10.引用11.static12.构造Complex类13.静态成员函数14.抽象类15.标…

[一篇读懂]C语言二讲:运算符与表达式

[一篇读懂]C语言二讲:运算符与表达式1. 算术运算符与关系运算符1 运算符分类2 算术运算符及算术表达式3 关系运算符与关系表达式【例】关系运算符的使用。4 运算符优先级2. 逻辑运算符与赋值运算符,求字节运算符1 逻辑运算符与逻辑表达式【例】逻辑运算符…