百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

我又和redis超时杠上了(redis的超时机制)

mhr18 2024-11-02 11:54 19 浏览 0 评论

背景

经过上次redis超时排查,并联系云服务商解决之后,redis超时的现象好了一阵子,但是最近又有超时现象报出,但与上次不同的是,这次超时的现象发生在业务高峰期,在简单看过服务器的各项指标以后,发现只有cpu的使用率在高峰期略高,我们是8核cpu,高峰期能达到90%的使用率,其余指标都相对正常。

但究竟是不是cpu占比高的问题导致redis超时的呢?还有待商榷,因为cpu调度程序慢本质上也是个概率性事件。

解决思路

略带侥幸的联系云服务商

有了上次的经验过后,我也是联系了云服务商那边也排查下是否还存在上次超时的原因,但其实还是有直觉,这次的原因和上次超时是不一样的(备注:上次超时是由于云服务商那边对集群的流量隔离做的不够好,导致其他企业机器流量影响到了我们的机器,且发生在业务低峰期),这次发生在业务高峰期。

果然,云服务商得出的结论也是之前出问题的机器以及迁移走了,并且他们也和我同时展开排查。

抓包分析

在ecs服务器上进行抓包,当出现超时时,关闭tcpdump进行分析。

tcpdump 漏包了?

在dump下抓包文件后,经过wireshark分析,并没有发现丢包信息,想着应该是tcpdump漏包了。

tcpdump 出现漏包的情况

[webserver@hw-sg1-test-0001 ~]$ sudo tcpdump -i eth0 tcp  port 6379   -w p.cap -W 2 -G 3600 -C 2000
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

可以看到默认的抓包大小262144 bytes,在业务高峰期如果每个包最大长度都在这个值,很可能就导致缓冲区满了,而之前一次抓包分析为什么就没有这个问题呢,因为那是在业务低峰期,tcpdump丢包概率比较小。

sudo tcpdump -i eth0 tcp  port 6379   -w p5.cap -W 2 -G 3600 -C 2000
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
^C147940 packets captured
468554 packets received by filter
318544 packets dropped by kernel

packets dropped by kernel 说明tcpdump丢弃了某些包,因为tcpdump在处理包时,是先将包放到一个缓冲区进行分析,当缓冲区满的时候会直接进行丢弃,这样导致我在用wireshark分析包的时候,就会出现有些包找不到的情况。

在缩小抓取的包大小和去掉域名解析后,不再漏包了。

[webserver@hw-sg1-backend-0003 ~]$ sudo tcpdump -i eth0 tcp  port 6379   -w p5.cap -W 2 -G 3600 -C 2000 -n -s 1520
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 1520 bytes
^C21334 packets captured
21454 packets received by filter
0 packets dropped by kernel

抓包分析超时情况

redis客户端超时时间设置的200ms,可以看到2894687号包是redis服务器发送给客户端的包,然后2897927是客户端发送给redis服务端的rst,正常情况客户端收到redis服务端的psh信号的包应该会回复一个ack的,但是客户端却在200ms以后回复了一个rst,说明了什么问题?

我们的客户端是golang写的,可以想到的情况是,客户端程序在读取包过程协程会有切换上下文操作,当客户端发现有可读包时并切回go协程的时候,会首先判断当前读操作是否超时,如果超时,则直接调用close方法关闭连接了。

那么close方法是发送rst信号吗,正常不应该是fin信号?
非也,close方法如果关闭的时候,连接读缓冲区的数据还有未被应用程序读取的话,那么此时close方法的调用会发送rst信号。

可见,问题的确是出在客户端了,并且看上去像是客户端来不及读取服务端的消息。看到这里,其实我心里已经百分之八九十确定是cpu的使用率达到瓶颈了。

云服务商来信了

在分析到上一个步骤的时候,云服务商告诉我,他们知道原因了,是ecs服务的磁盘吞吐量达到瞬时上线,说故障点是和超时的故障点是吻合的。

我知道这个后,第一时间的疑惑是,为啥磁盘吞吐会影响到网络传输,云服务商给的解释是磁盘吞吐达到瞬时上线后,对服务整体是有影响的,我又看了下ecs的监控图标,发现监控图标显示的磁盘吞吐远远没有云服务商提到的那么多。



尽管云服务商坚持是磁盘iops达到了上限,但还是不能说服我 磁盘的iops瞬时上限会那么大影响到网络传输。

于是有了接下来第二天的抓包分析。

第二天的抓包分析

基于对昨天的分析,我怀疑到了cpu头上,如果cpu切换进程缓慢,协程调度缓慢,那么的确是有可能发生超时的。由于目前的监控缺少对协程调度延迟的监控,所以决定加上这一指标。

golang1.17后 runtime包提供了协程调度延迟的直方图统计信息,而go prometheus的client其实以已经支持将这个信息转换为prometheus内置的指标类型,metric名称是go_sched_latencies_seconds,而我们之前试用prometheus的client包注册的collector 是兼容到go1.16以及之前的版本,所以没有当改用到最新的collector后,client如期返回了go_sched_latencies_seconds 直方图信息。

将这个信息展示在grafana里。于是有了第二天协程调度延迟的信息。p999在业务高峰期间达到了100ms,也是与超时时间吻合的。协程调度延迟指的是协程变为可运行状态后到被真正执行这段时间等待被调度的时间,这里都高达100ms了,如果加上cpu线程,进程切换上下文时间,很有可能是超过了redis client端设置的200ms超时上限。

为了排除掉是磁盘原因引起的超时。
我在7点又进行了抓包分析,发现和昨天抓到包的情况是一致的,客户端最后来不及回应服务端的包最后发送rst了。


然后看了下此时机器磁盘吞吐情况,发现图中箭头处也处于高峰期,但是磁盘吞吐量并未上去,而升上去的点正是抓包带来的,怀疑是抓包写入文件导致磁盘吞吐量涨上去了。于是又问了服务商要磁盘达到瞬时峰值的日志。


发现报瞬时峰值的日志也和抓包时间吻合,所以已经确认磁盘吞吐达到上限是抓包导致的,网络超时是和磁盘吞吐无关的,反而应该是cpu使用率达到上限了,虽然没有100%,也是8核,但毕竟cpu某个核达到上限是概率性事件,而对于redis这种时延敏感性应用,一但发生,那么超时是有可能的。

完美解决

于是,在业务低峰期将我们三台ecs服务进行了cpu配置提升,提升后效果很明显,超时在高峰期不见了,协程调度延迟也大大减少。

总结

1,对于抓包分析,还是疏忽了,加上包限制大小,能很好的防止tcpdump抓包时丢包的情况。
2,对于任何第三方的说法要有自己的判断力,像这次如果中途去将磁盘扩容显然是不能解决问题的。
3,性能问题分析真是像一个侦探破案的过程,不断列出证据,不断排除掉干扰因素,不断论证的过程也是性能分析的魅力所在吧,就像这次看到cpu的确比较高了,但是究竟是不是客户端问题呢?我又抓包论证了的确是客户端问题,那究竟是不是协程调度问题呢?我又列出协程调度延迟。

相关推荐

MYSQL数据同步(mysql数据同步方式)

java开发工程师在实际的开发经常会需要实现两台不同机器上的MySQL数据库的数据同步,要解决这个问题不难,无非就是mysql数据库的数据同步问题。但要看你是一次性的数据同步需求,还是定时数据同步,亦...

SpringBoot+Redis实现点赞收藏功能+定时同步数据库

由于点赞收藏都是高频率的操作,如果因此频繁地写入数据库会造成数据库压力比较大,因此采用redis来统计点赞收藏浏览量,之后定时一次性写入数据库中,缓解数据库地压力。一.大体思路设计redis中的储存结...

双11订单洪峰:Codis代理层如何扛住Redis集群搞不定的120万QPS?

双11订单洪峰下的技术挑战每年的双11购物节,都是对电商平台技术架构的极限考验。当零点钟声敲响,海量用户瞬间涌入,订单量呈指数级增长,系统需要承受每秒数十万甚至上百万次的请求。作为电商系统的核心组件之...

基于spring boot + MybatisPlus 商城管理系统的Java开源商城系统

前言Mall4j项目致力于为中小企业打造一个完整、易于维护的开源的电商系统,采用现阶段流行技术实现。后台管理系统包含商品管理、订单管理、运费模板、规格管理、会员管理、运营管理、内容管理、统计报表、权限...

商品券后价产品设计方案(显示券后价)

如何设计一套高效、准确且稳定的券后价计算系统,是电商产品设计中的关键挑战之一。本文详细介绍了商品券后价的产品设计方案,从背景目标、功能设计、系统实现逻辑到异常处理机制等多个方面进行了全面阐述。一、背景...

外观(门面)模式-Java实现(java 门面模式)

定义外观模式(FacadePattern),也叫门面模式,原始定义是:为了子系统中的一组接口提供统一的接口。定义一个更高级别的接口,使子系统更易于使用。大大降低应用程序的复杂度,提高了程序的可维护性...

Mall - 用 SpringBoot 实现一个电商系统

目前最为主流的Web开发技术,包括SpringBoot、MyBatis、MongoDB、Kibina、Docker、Vue等,都是开发者十分需要掌握的技术。有没有一个全面而又实际的项目,能把这...

腾讯云国际站:哪些工具能实现可视化运维?

本文由【云老大】TG@yunlaoda360撰写开源工具Grafana:开源的可视化平台,可与Prometheus、Elasticsearch、MySQL等多种数据源集成,将复杂监控数据转化...

系统稳定性保障全流程实战:事前、事中、事后 Java 代码详解

在互联网架构中,系统稳定性是生命线。本文基于“事前预防、事中管控、事后复盘”三阶段模型,结合Java实战代码,深度解析如何构建高可用系统,让你的服务稳如磐石!一、事前:未雨绸缪,筑牢防线1.发...

Java面试题:拆分微服务应该注意哪些地方方,如何拆分?

在拆分微服务时,需要综合考虑业务、技术和组织等多方面因素,以下是关键注意事项及拆分策略的详细说明:一、拆分注意事项1.业务边界清晰化单一职责原则:每个服务应专注于单一业务能力,例如订单服务仅处理订单...

软件性能调优全攻略:从瓶颈定位到工具应用

性能调优是软件测试中的重要环节,旨在提高系统的响应时间、吞吐量、并发能力、资源利用率,并降低系统崩溃或卡顿的风险。通常,性能调优涉及发现性能瓶颈、分析问题根因、优化代码和系统配置等步骤,调优之前需要先...

Docker Compose实战,多容器协同编排的利器,让开发部署更高效!

开篇导读你是否有过这样的经历?启动一个项目,数据库、Redis、Web服务得一个个敲dockerrun?想让别人复现你的开发环境,却得发一堆复杂的启动命令?明明都是容器,为什么不能“一键启动”所...

如何设计Agent的记忆系统(agent记忆方法)

最近看了一张画Agent记忆分类的图我觉得分类分的还可以,但是太浅了,于是就着它的逻辑,仔细得写了一下在不同的记忆层,该如何设计和选型先从流程,作用,实力和持续时间的这4个维度来解释一下这几种记忆:1...

不了解业务和技术术语怎么做好产品和项目?

基础技术术语术语分类解释API开发技术应用程序接口,不同系统间数据交互的协议(如支付接口、地图接口)。SDK开发工具软件开发工具包,包含API、文档和示例代码,帮助快速接入服务。RESTfulAPI...

Docker 架构详解与核心概念实战图解:一文读懂容器的前世今生

不懂Docker架构,你只是“用容器的人”;理解了它的底层逻辑,才能成为真正的高手!在学习Docker之前,很多同学可能会陷入一个误区:“反正我用dockerrun就能跑起服务,架构这种...

取消回复欢迎 发表评论: