文档章节

「前任的50种死法」开发踩坑案例--慢就是错

o
 osc_gu9d45li
发布于 2019/04/09 10:35
字数 1549
阅读 9
收藏 0

钉钉、微博极速扩容黑科技,点击观看阿里云弹性计算年度发布会!>>>

背景

《50 ways to say goodbye》中文名《前任的50种死法》是我之前报的英语班里外教老师放给我们听的歌。老外说很困惑为什么我们还在听《Take me home,Country Road》这种老掉牙的歌。

《前任的50种死法》里因为生女友的气幻想她的各种死法:飞机坠机、晒日光浴被晒死、被狮子吃掉、泡澡被淹死……

等等,听着咋就这么像做项目:看起来根本就不可能的原因,结果服务被整死了。本系列文章汇总了50个项目中“下水被鲨鱼吃掉”这样的离奇的服务出错分析。

案例分析-超时导致接口报500错误

引发问题

我做的heimdal和carter这两个产品一期上线,heimdal是k8s的事件监听服务。在设计为了验证是否有事件丢失、对事件的处理是否正确等正确性验证,carter作为heimdal的事件处理,并对外直接暴露接口提供服务。一期使用了mysql做存储。因为mysql非常成熟,不会干扰对结果的验证。

但实际上因为涉及各种过滤式的查询。用sql来查询的时候,这么来说吧,如果直接写sql语句要嵌套几十个in的子查询。在代码编写的时候为了适应各种情况,分查询语句的,就是说要建立多次连接。

来看上面的数据,resource这个接口TP90已经超过2秒了。上游调用在服务治理框架OCTO中显示上游因为设置了超时时间为2秒,结果有0.4%的请求都调用失败了。因为在核心链路里有10次重试,而且如果10次重试还是获取不到结果,会在请求层失败。调用方看到这个错误会再次发起请求,实际上是可以得到正确结果的。但是上游会有监控报警,触发了报警,上游同学就来找我了。

我记得第一次处理这个问题是晚上11点多在地铁上。用手机连vpn处理的。怎么应急处理这种事情呢?就是将堵塞的mysql慢查询kill掉。

问题解决初版

综合考虑已有问题的影响:实际上对业务没有影响。所以决定先按照原有的计划先完成标签管理系统hydra。用hydra的标签过滤来代替几十个in的子查询。这个方法可以彻底解决对mysql的压力。

hydra采用ElasticSearch做底层存储,将原有的sql查询转化为ES查询。并且因为标签的修改频率低,延时不敏感。我在编写客户端引用包的时候做了客户端本地缓存处理。缓存最近30条查询条件,每100ms取拉取最新条件对应的结果。所以条件命中的情况下,10ms完全可以返回结果。下面是端到端(最上游调用方的耗时,中间有很多网络传输)的响应耗时数据:

因为2s超时,而时间上TP99可以在200ms内返回。所以理论上是完全可以解决问题的。

看起来很完美,线下环境运行非常正常。但是线上环境运行了1天之后,超时现象却又复发了!在cat日志上还发现了大量由于mysql引起的错误。

mysql优化

下面是cat监控得到的结果,主要问题是数据库获取物理连接超时和内存溢出!

我们刚上线的服务qps每秒都没有几个请求,由于占用数据库连接池太多而引起内存溢出很蹊跷。并且查看数据库日志,并没有特别严重的慢查询。了解到这不是背后的根因,但是同时也暴露出另外一个问题:数据库参数设置是不合理的。

由于目前的报错实际上对业务没有影响。所以决定先不解决真正问题,而先借这个契机对数据库进行一版优化。主要做了两个优化:

第一,由于之前有部分的服务是主从延时敏感的,后面的同学新建服务的时候都一直采用“只读主库”的路由方式。考虑carter实际上对主从延时不敏感,同时从库需要一定的流量来保证万一主库出现问题进行主从切换的时候,从库是真正的热备,不需要额外的激活操作。所以将carter改成主从分离。

第二,对物理连接不是很苛刻的情况下,可以适当调大checkoutTimeout这个参数,以免不断的重连造成性能的反而下降。

通过这一版优化,cat上的错误日志确实是消失了。但是仍然超时!

解决根因

解决问题先看现象。下面是出现问题的那段时间的内存和cpu。能够看到有明显的攀升和尖刺。

从cat日志上找到耗时最长的那个记录,点进入看到有个方法调用是不该出现的。就是本来我做了客户端本地缓存,那就不应该在实际请求的时候走远程调用。除非超过了30个的存储限制,本地缓存失效!

果然,因为线上环境比线下复杂,30个不够用了。通过配置管理改成150个缓存,问题解决。上面内存和cpu是显示了1个月的数据。可以看到调整之后内存和cpu使用情况恢复了正常。

总结

慢就是错。响应速度不符合预期要当做错误进行彻底的排查。

相关阅读

编写代码的「八荣八耻」(上篇)

编写代码的「八荣八耻」- 以开关上线为荣,以自信编码为耻

稳定性「三十六计」- 配额管控

 

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。
平时代码中用不到设计模式?Are you kidding me?

引子 平时我是个反应非常慢的人。有多慢呢?大概是两年前有次团队内部开会时,我听到同学说平时代码中用不到设计模式,我当时没有回答。两年后我终于反应过来了:“Are you kidding me?我每天...

osc_3xmkn220
04/16
2
0
设置默认的超时和重试是一个基础设施的基本素养

What 本篇应该是稳定性「三十六计」系列的一篇:超时重试。但是「设置默认的超时和重试是一个基础设施的基本素养」这句话我在我们组内三次开会的时候都说了。表达了我的一个理念。 Why 为什么...

osc_wa6zijqd
04/16
2
0
稳定性「三十六计」- 无状态化

背景 随着容器化、云原生等的流行,DevOps团队也在不断鼓吹「以无状态为荣,以有状态为耻」。因为有状态的服务难以部署、难以扩展。下面我举几个自己工作中实际的例子。 实例1-依赖系统目录结...

osc_gd4rlfym
2019/04/17
1
0
史上最强《Java 开发手册》泰山版王者归来!

阿里妹导读:潜力修炼一年之久的《Java 开发手册(泰山版)》今天发布!此次共计新增 34 条规约,修改描述 90 处,其中错误码规则更是第一次提出完整的解决方案,大家参考错误码示例表,欢迎...

阿里云官方博客
04/22
878
0
史上最强《Java 开发手册》泰山版王者归来!

阿里妹导读:潜力修炼一年之久的《Java 开发手册(泰山版)》今天发布!此次共计新增 34 条规约,修改描述 90 处,其中错误码规则更是第一次提出完整的解决方案,大家参考错误码示例表,欢迎...

osc_cl1ufvfd
04/23
29
0

没有更多内容

加载失败,请刷新页面

加载更多

SO_REUSEADDR和SO_REUSEPORT有何不同? - How do SO_REUSEADDR and SO_REUSEPORT differ?

问题: The man pages and programmer documentations for the socket options SO_REUSEADDR and SO_REUSEPORT are different for different operating systems and often highly confusing.......

法国红酒甜
34分钟前
28
0
asp.net core之SignalR

SignalR 是什么? ASP.NET Core SignalR 是一个开源的实时框架,它简化了向应用中添加实时 Web 功能的过程。 实时 Web 功能是服务器端能够即时的将数据推送到客户端,而无需让服务器等待客户端...

一介草民Coder
今天
24
0
如何通过日期属性对数组进行排序 - How to sort an array by a date property

问题: Say I have an array of a few objects: 说我有一些对象的数组: var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}]; How can I sort......

javail
今天
22
0
技术教程| 百度鹰眼历史轨迹查询:轨迹抽稀功能

本文作者:用****9 本篇教程中,我们将详细地说明鹰眼历史轨迹查询(gettrack接口)中,如何通过vacuate_grade选项对轨迹进行抽稀,以及不同的抽稀力度对轨迹产生的影响。 上一篇教程中,我们...

百度开发者中心
前天
24
0
Quartz的Misfire处理规则 错过任务执行时间的处理机制

调度(scheduleJob)或恢复调度(resumeTrigger,resumeJob)后不同的misfire对应的处理规则 CronTrigger withMisfireHandlingInstructionDoNothing ——不触发立即执行 ——等待下次Cron触发频率...

独钓渔
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部