背景

redis-K,V数据库,因其高性能的操作性和支持丰富的数据结构,目前大量被用于衔接应用层和关系数据库中间的缓存层。随着使用的场景越来越多,和数据量快速的递增,在生产环境中经常会遇到相关的性能瓶颈问题。这时候就需要借助一些外部的手段来分析瓶颈根源在哪,对症下药提升性能。

常见性能问题及问题分析过程

1、生产系统刚开始运行阶段,系统稳定。但是运行一段时间后,发现部分时间段系统接口响应变慢。查看客户端日志经常会出现这样的错误:

redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out。

2、生产环境长时间的运行后,经常会有接口返回数据失败的情况,或者是从监控上发现数据库压力某一时间暴增。查看客户端日志发现这样的错误:

redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool

3、突然间服务不能访问,返回错误:

redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

当然在实际生产情况中,还有各种各样的异常情况,但是在客户端普遍表现为上面几种场景,下面我们来一步步分析上面的问题。

问题一:

首先从客户端反馈的日志,怀疑是服务器和客户端间的网络问题。为排除这个问题,我们编写脚本,在客户端定时ping服务端(redis服务),持续运行一段后,发现未有丢包的情况,排除网络问题。

查看redis服务端日志,未发现有异常情况。查看redis服务器资源监控,发现每几分钟左右,IO会有一波峰值,但是CPU和带宽压力都在正常范围。

这里介绍下我们的redis部署模式:一主一从通过redis自带的sentinal做HA,主从均有开启持久化。初步怀疑间隔性IO操作占用资源导致redis读写变慢(在此,抛出一个问题:在服务器资源CPU和带宽均未达到瓶颈的情况下,持续的IO高峰操作是否会影响物理内存的读写)。接下来采取的措施是:关闭主库的持久化,用从库来做持久化,但是这种模式下存在一个问题,如果主发生故障,sentinal做主从切换后问题同样存在,大家有更好的建议可以指点下。

运行一段时候,发现问题有所改善,但是依然还是会有time out的情况,只有继续排查问题。由于redis操作采用单线程,考虑会不会有某些慢查询导致time out。执行slowlog查看慢查询语句,发现有大量的keys命令操作,keys命令在大量并发情况下性能非常差,结合官方给出的warning

正式环境中,尽量避免使用keys,接下来找出使用keys的代码做优化,至此,time out问题解决。

问题二:

从错误日志看,是提示无法获取连接。有两种情况:

1、客户端的连接池满了,无法创建新的连接

检查客户端连接最大限制maxActive是否足够

2、redis服务端连接溢出,无法分配新的连接

检查服务端tcp连接:netstat -nat|grep -i "6379"|wc -l

检查服务端连接是否达到最大值:查看服务端支持的最大连接:CONFIG GET maxclients,查看当前服务端建立的   连接:connected_clients

通过上述检查后,发现redis服务端connected_clients连接数持续过高,经常在最大值徘徊。但是结合客户端配置的最大连接配置maxActive,计算出所有客户端连接占满的情况下最大的连接数也达不到connected_clients的连接数。

执行client list命令,发现大量的client的idle时间特别长:

正常的client连接,在持续使用的情况下,是不可能空闲这么长时间,连接长时间空闲,客户端也会关闭连接。

查看redis服务端下面两项配置:

timeout:client连接空闲多久会被关闭(这个配置容易被误导为:连接超时和操作执行超时)

tcp-keepalive:redis服务端主动向空闲的客户端发起ack请求,以判断连接是否有效

检查上述配置发现 timeout和tcp-keepalive均未启用(均为0),这种情况下,redis服务端没有有效的机制来确保服务端已经建立的连接是否已经失效。当服务器和客户端网络出现闪断,导致tcp连接中断,这种情况下的client将会一直被redis服务端所持有,就会出现上面我们看到的idle时间特长的client连接。

接下来设置timeout和tcp-keepalive来清理失效的连接。

上面问题中提到的数据库某一时间压力暴增,是由于在缓存模式下,redis请求失败,请求的压力瞬间集中到数据库。

问题三:

从错误提示,可以看出是向磁盘保存数据失败。引起这个问题的原因一般是内存不足,但是生产环境我们一般都会为系统分配足够的内存运行,而且查看内存情况也显示还有可用内存。

查看redis日志,发现有这个错误:Can’t save in background: fork: Cannot allocate memory

redis在保存内存的数据到磁盘时,为了防止主进程假死,会Fork一个子进程来完成这个保存操作。但是这个Fork的子进程会需要分配和主进程相同的内存,这时候就相当于需要的内存double了,如果这时候可用内存不足以分配需要的内存,将会导致Fock子进程失败而无法保存数据到磁盘。

修改linux内核参数:vm.overcommit_memory=1。至此,问题解决。

overcommit_memory有三种取值:0, 1, 2

0::检查是否有足够的可用内存供进程使用;有则允许申请,否则,内存申请失败,并把错误返回给应用进程;

1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何;

2:表示内核允许分配超过所有物理内存和交换空间总和的内存。

优化措施总结

1、结合实际使用场景,考虑是否需要用到redis的持久化,如果单纯用来做应用层的缓存(在缓存未命中的情况下访问数据库),可以关闭持久化。

2、缓存模式下,尽量为每块缓存设置时效性,避免冷数据长时间占用资源。

3、生产环境中尽量避免使用keys操作,由于redis是单线程模式,大量的keys操作会阻塞其他的命令执行。

4、设置合理的内存回收策略,保证内存可用性的同时能适当的提供缓存的命中率。

5、提前计算出系统可能会用的内存大小,合理的分配内存。需要注意在开启持久化模式下,需要预留更多的内存提供给Fock的子进程做数据磁盘flush操作。

深入探讨研究

如果redis服务端未设置timeout,客户端会如何处理长时间未使用的连接?

这个问题可以从分析redis的sdk源码查找答案,不过这个过程会比较枯燥。

接下来我们直接通过抓取客户端和服务端的tcp数据包来获取答案:

这里我用wireshark来抓取中间的tcp数据包,下面是抓取了一个完整的redis连接(从发起到结束)的tcp数据包

从上面可以看到,从tcp3次握手建立连接,到最后客户端发送reset包给服务端终止了这个连接。

追踪整个tcp的数据流:

*2
$4
AUTH
$8
password
+OK
*1
$4
PING
+PONG
*1
$4
PING
+PONG
*1
$4
QUIT
+OK
从tcp数据流可以看出,整个tcp连接中间经历的操作:

1、客户端发送密码建立连接,服务端响应OK

2、客户端发送PING命令校验连接,服务端响应PONG表示成功

3、客户端再次发送PING命令校验连接,服务端响应PONG表示成功

4、客户端发送QUIT命令退出连接,服务端响应OK表示退出成功

当服务端响应QUIT命令OK后,客户端发送RESET的tcp包终止整个tcp连接。中间客户端发起了两次PING命令校验连接和一次QUIT命令来退出连接,每次间隔30s,加起来整个连接存活了90s。

---------------------
作者:_crisis
来源:CSDN
原文:https://blog.csdn.net/crisis_hiding/article/details/81490158
版权声明:本文为博主原创文章,转载请附上博文链接!

redis性能优化——生产中实际遇到的问题排查总结的更多相关文章

  1. redis性能优化、内存分析及优化

    redis性能优化.内存分析及优化 1.优化网络延时 2.警惕执行时间长的操作 3.优化数据结构.使用正确的算法 4.考虑操作系统和硬件是否影响性能 5.考虑持久化带来的开销 5.1 RDB 全量持久 ...

  2. 《吐血整理》Redis 性能优化的 13 条军规!史上最全

    Redis 是基于单线程模型实现的,也就是 Redis 是使用一个线程来处理所有的客户端请求的,尽管 Redis 使用了非阻塞式 IO,并且对各种命令都做了优化(大部分命令操作时间复杂度都是 O(1) ...

  3. 吊打面试官系列:Redis 性能优化的 13 条军规大全

    1.缩短键值对的存储长度 键值对的长度是和性能成反比的,比如我们来做一组写入数据的性能测试,执行结果如下: 从以上数据可以看出,在 key 不变的情况下,value 值越大操作效率越慢,因为 Redi ...

  4. 大型系统的Redis性能优化

    问题描述 系统背景:大型线上Java服务集群(活跃用户数上千万),业务重度使用Redis存储个管理Session,业务并发量>1WQPS,基本上每个请求都需要访问Redis(可能是多次),使用了 ...

  5. Redis性能优化之redis.cnf配置参数

    redis调优总结 1.相应的参数调优 加内存2.redis使用结构调优3.使用合理的数据类型说明:redis存储的数据为redis hash(字符映射表) 单key多字段结构. 1)调整配置文件中配 ...

  6. redis性能优化

    redis日志截图:

  7. 【性能优化】404- 从 12.67s到1.06s 性能优化实战

    作者:jerryOnlyZRJ 来源:https://juejin.im/post/5b6fa8c86fb9a0099910ac91 本文是对之前同名文章的修正,将所有webpack3的内容更新为we ...

  8. 网站性能优化实战——从12.67s到1.06s的故事

    文章摘自https://juejin.im/post/5b0b7d74518825158e173a0c 作为互联网项目,最重要的便是用户体验.在举国“互联网+”的热潮中,用户至上也已经被大多数企业所接 ...

  9. 前端project与性能优化(长文)

    原文链接:http://fex.baidu.com/blog/2014/03/fis-optimize/ 每一个參与过开发企业级 web 应用的前端project师也许都曾思考过前端性能优化方面的问题 ...

随机推荐

  1. 前端知识点也可以当做面试题含vue

    一.webpack3.x打包工具 三大组成结构.package.json.webpack.config.js.serve.js 1.Package.json:下载目录需要的依赖包 2.Webpack. ...

  2. pyqt5_实例:修改xml文件中节点值

    需求: 将类似如下xml文件的externalid节点值修改成不重复的值 实现该功能的代码Func.py: #coding=utf-8 ''' Created on 2019年10月15日 @auth ...

  3. PLC可编程控制器的结构和工作原理

    PLC的可编程控制器由的功能结构由cpu中央处理器,存储器和输入输出借口三部分组成 CPU Cpu的功能是完成plc所有的的控制和监视, Cpu中央处理去由控制器,寄存器,运算器.通过数据总线,地址总 ...

  4. 一键部署open***服务

    一键部署超级简单易用的openvpn服务器,支持多证书+多账号[密码]认证 一. 服务器端部署 项目地址:https://github.com/guoew/openvpn-install 1.1. 下 ...

  5. Spring_管理bean的生命周期

    Spring IOC 容器对 Bean 的生命周期进行管理的过程:通过构造器或工厂方法创建 Bean 实例为 Bean 的属性设置值和对其他 Bean 的引用将 Bean 实例传递给 Bean 后置处 ...

  6. excel操作数据实用技能

    写代码写习惯了,在做数据预处理时也总是习惯性地用python.pandas来做处理,但其实有时候根本不需要写代码,用excel也能达到目的,甚至比写代码快很多,写代码要半天,excel只要几秒钟.下面 ...

  7. 是时候扔掉cmder, 换上Windows Terminal

    作为一个Windows的长期用户,一直没有给款好用的终端,知道遇到了 cmder,它拯救一个习惯用Windows敲shell命令的人. 不用跟我安利macOS真香!公司上班一直用macOS,一方面确实 ...

  8. Redis 入门到分布式 (二)API的理解和使用

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 内容: 通用命令 单线程架构 数据结构和内部编码 一.常用的通用命令: keys       计算所有的 ...

  9. Java实现 LeetCode 563 二叉树的坡度(又是一个遍历树)

    563. 二叉树的坡度 给定一个二叉树,计算整个树的坡度. 一个树的节点的坡度定义即为,该节点左子树的结点之和和右子树结点之和的差的绝对值.空结点的的坡度是0. 整个树的坡度就是其所有节点的坡度之和. ...

  10. java实现第五届蓝桥杯生物芯片

    生物芯片 X博士正在研究一种生物芯片,其逻辑密集度.容量都远远高于普通的半导体芯片. 博士在芯片中设计了 n 个微型光源,每个光源操作一次就会改变其状态,即:点亮转为关闭,或关闭转为点亮. 这些光源的 ...