为什么说阻塞是Redis的噩梦:

  Redis是典型的单线程架构,所有的读写操作都是在一条主线程中完成的。当Redis用于高并发场景时,这条线程就变成了它的生命线。如果出现阻塞,哪怕是很短时间,对于应用来说都是噩梦。

  导致阻塞问题的原因:

  • 内在原因:不合理地使用API或数据结构、CPU饱和、持久化阻塞等
  • 外在原因:CPU竞争、内存交换、网络问题等

  一、发现阻塞

  • 应用方加入异常监控,如日志系统,比如Java语言中的logback或log4j
  • Redis监控系统,如CacheCloud

  二、内在原因

  1.API或数据结构使用不合理

  通常Redis执行命令速度非常快,但是,如果对一个包含上万个元素的hash结构执行hgetall操作,由于数据量比较大且命令算法复杂度是O(n),这条命令执行速度必然很慢。

  对于高并发的场景应该尽量避免在大对象上执行算法复杂度超过O(n)的命令。

  (1)如何发现慢查询

  Redis原生提供慢查询统计功能,执行slowlog get{n}命令可以获取最近的n条慢查询命令,默认对于执行超过10毫秒的命令都会记录到一个定长队列中,线上实例建议设置为1毫秒便于及时发现毫秒级以上的命令。

  (2)发现慢查询后如何调整

  • 修改为低算法复杂度的命令
  • 调整大对象:缩减大对象数据或把大对象拆分为多个小对象,防止一次命令操作过多的数据。大对象拆分过程需要视具体的业务决定,如用户好友集合存储在Redis中,有些热点用户会关注大量好友,这时可以按时间或其他维度拆分到多个集合中。

  (3)如何发现大对象

bigjun@myubuntu:~$ redis-cli -h 192.168.131.130 -p  --bigkeys

# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per SCAN commands (not usually needed). [00.00%] Biggest string found so far 'XML' with bytes
[00.00%] Biggest list found so far 'hot:user:list' with items -------- summary ------- Sampled keys in the keyspace!
Total key length in bytes is (avg len 9.00) Biggest string found 'XML' has bytes
Biggest list found 'hot:user:list' has items strings with bytes (91.67% of keys, avg size 43.64)
lists with items (08.33% of keys, avg size 5.00)
sets with members (00.00% of keys, avg size 0.00)
hashs with fields (00.00% of keys, avg size 0.00)
zsets with members (00.00% of keys, avg size 0.00)
streams with entries (00.00% of keys, avg size 0.00)

  2.CPU饱和

  单线程的Redis处理命令时只能使用一个CPU。而CPU饱和是指Redis把单核CPU使用率跑到接近100%。使用top命令很容易识别出对应Redis进程的CPU使用率。CPU饱和是非常危险的,将导致Redis无法处理更多的命令,严重影响吞吐量和应用方的稳定性。对于这种情况,首先判断当前Redis的并发量是否达到极限,建议使用统计命令redis-cli -h {ip} -p {port} --stat获取当前Redis使用情况

bigjun@myubuntu:~$ redis-cli -h 192.168.131.130 -p  --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
.05K (+)
.05K (+)
.05K (+)
.05K (+)
.05K (+)
.05K (+)
.05K (+)
.05K (+)
.05K (+)
...

  然后根据info commandstats统计信息分析出命令不合理开销时间:

192.168.131.130:> info commandstats
# Commandstats
cmdstat_type:calls=,usec=,usec_per_call=0.25
cmdstat_scan:calls=,usec=,usec_per_call=8.50
cmdstat_monitor:calls=,usec=,usec_per_call=1.00
cmdstat_del:calls=,usec=,usec_per_call=70.00
cmdstat_mset:calls=,usec=,usec_per_call=34.00
cmdstat_replconf:calls=,usec=,usec_per_call=2.47
cmdstat_llen:calls=,usec=,usec_per_call=0.00
cmdstat_script:calls=,usec=,usec_per_call=115.57
cmdstat_incr:calls=,usec=,usec_per_call=6.60
cmdstat_rpush:calls=,usec=,usec_per_call=41.00
cmdstat_dbsize:calls=,usec=,usec_per_call=1.00
cmdstat_client:calls=,usec=,usec_per_call=15.75
cmdstat_bgsave:calls=,usec=,usec_per_call=296.00
cmdstat_get:calls=,usec=,usec_per_call=10.56
cmdstat_eval:calls=,usec=,usec_per_call=8205714.00
cmdstat_lrange:calls=,usec=,usec_per_call=38.00
cmdstat_set:calls=,usec=,usec_per_call=21.00
cmdstat_keys:calls=,usec=,usec_per_call=40.90
cmdstat_strlen:calls=,usec=,usec_per_call=1.36
cmdstat_save:calls=,usec=,usec_per_call=1410.00
cmdstat_evalsha:calls=,usec=,usec_per_call=20.00
cmdstat_info:calls=,usec=,usec_per_call=71.79
cmdstat_ping:calls=,usec=,usec_per_call=1.25
cmdstat_command:calls=,usec=,usec_per_call=280.00
cmdstat_mget:calls=,usec=,usec_per_call=9.00
cmdstat_psync:calls=,usec=,usec_per_call=1608.00

  3.持久化阻塞

  对于开启了持久化功能的Redis节点,需要排查是否是持久化导致的阻塞。

  • fork阻塞:ork操作发生在RDB和AOF重写时,Redis主线程调用fork操作产生共享内存的子进程,由子进程完成持久化文件重写工作。如果fork操作本身耗时过长,必然会导致主线程的阻塞。
  • AOF刷盘阻塞:当我们开启AOF持久化功能时,文件刷盘的方式一般采用每秒一次,后台线程每秒对AOF文件做fsync操作。当硬盘压力过大时,fsync操作需要等待,直到写入完成。如果主线程发现距离上一次的fsync成功超过2秒,为了数据安全性它会阻塞直到后台线程执行fsync操作完成。这种阻塞行为主要是硬盘压力引起。
  • HugePage写操作阻塞:子进程在执行重写期间利用Linux写时复制技术降低内存开销,因此只有写操作时Redis才复制要修改的内存页。对于开启Transparent HugePages的操作系统,每次写命令引起的复制内存页单位由4K变为2MB,放大了512倍,会拖慢写操作的执行时间,导致大量写操作慢查询。

  三、外在原因

  1.CPU竞争

  • 进程竞争:Redis是典型的CPU密集型应用,不建议和其他多核CPU密集型服务部署在一起。当其他进程过度消耗CPU时,将严重影响Redis吞吐量。可以通过top、sar等命令定位到CPU消耗的时间点和具体进程,这个问题比较容易发现,需要调整服务之间部署结构。
  • 绑定CPU:部署Redis时为了充分利用多核CPU,通常一台机器部署多个实例。常见的一种优化是把Redis进程绑定到CPU上,用于降低CPU频繁上下文切换的开销。这个优化技巧正常情况下没有问题,但是存在例外情况,当Redis父进程创建子进程进行RDB/AOF重写时,如果做了CPU绑定,会与父进程共享使用一个CPU。子进程重写时对单核CPU使用率通常在90%以上,父进程与子进程将产生激烈CPU竞争,极大影响Redis稳定性。因此对于开启了持久化或参与复制的主节点不建议绑定CPU。

  2.内存交换

  内存交换(swap)对于Redis来说是非常致命的,Redis保证高性能的一个重要前提是所有的数据在内存中。如果操作系统把Redis使用的部分内存换出到硬盘,由于内存与硬盘读写速度差几个数量级,会导致发生交换后的Redis性能急剧下降。

  (1)识别内存交换:

bigjun@myubuntu:~$ redis-cli -h 192.168.131.130 -p  info server | grep process_id
process_id: root@myubuntu:~# cat /proc//smaps | grep Swap
Swap: kB
SwapPss: kB
Swap: kB
SwapPss: kB
Swap: kB
SwapPss: kB
Swap: kB
SwapPss: kB
...

  (2)预防内存交换:

  • 保证机器充足的可用内存。
  • 确保所有Redis实例设置最大可用内存(maxmemory),防止极端情况下Redis内存不可控的增长。
  • 降低系统使用swap优先级。

  3.网络问题

  (1)连接拒绝

  • 网络闪断(网络割接或者带宽耗尽)
  • Redis连接拒绝(超过客户端最大连接数)
  • 连接溢出(进程限制或backlog队列溢出)

  (2)网络延迟

  网络延迟取决于客户端到Redis服务器之间的网络环境。主要包括它们之间的物理拓扑和带宽占用情况。常见的物理拓扑按网络延迟由快到慢可分为:同物理机>同机架>跨机架>同机房>同城机房>异地机房。但它们容灾性正好相反,同物理机容灾性最低而异地机房容灾性最高。

  网络延迟问题经常出现在跨机房的部署结构上,对于机房之间延迟比较严重的场景需要调整拓扑结构,如把客户端和Redis部署在同机房或同城机房等。
  带宽瓶颈通常出现在以下几个方面:

  • 机器网卡带宽。
  • 机架交换机带宽。
  • 机房之间专线带宽。

  (3)网卡软中断

  网卡软中断是指由于单个网卡队列只能使用一个CPU,高并发下网卡数据交互都集中在同一个CPU,导致无法充分利用多核CPU的情况。网卡软中断瓶颈一般出现在网络高流量吞吐的场景。

Redis(七)Redis的噩梦:阻塞的更多相关文章

  1. 高可用Redis(七):Redis持久化

    1.什么是持久化 持久化就是将数据从掉电易失的内存同步到能够永久存储的设备上的过程 2.Redis为什么需要持久化 redis将数据保存在内存中,一旦Redis服务器被关闭,或者运行Redis服务的主 ...

  2. SpringBoot入门 (七) Redis访问操作

    本文记录学习在SpringBoot中使用Redis. 一 什么是Redis Redis 是一个速度非常快的非关系数据库(Non-Relational Database),它可以存储键(Key)与 多种 ...

  3. 【Redis】Redis学习(七) Redis 持久化之RDB和AOF

    Redis 持久化提供了多种不同级别的持久化方式:一种是RDB,另一种是AOF. RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot). AOF ...

  4. Redis学习——Redis持久化之RDB备份方式保存数据

    从这一个介绍里面知道,redis比memcache作为缓存数据库强大的地方,一个是支持的数据类型比较多,另一个就是redis持久化功能. 下面就介绍Redis的持久化之RDB! 一:什么是redis的 ...

  5. redis基础:redis下载安装与配置,redis数据类型使用,redis常用指令,jedis使用,RDB和AOF持久化

    知识点梳理 课堂讲义 课程计划 1. REDIS 入 门 (了解) (操作)   2. 数据类型 (重点) (操作) (理解) 3. 常用指令   (操作)   4. Jedis (重点) (操作) ...

  6. redis系列-redis的使用场景

    redis越来越受大家欢迎,提升下速度,做下缓存,完成KPI之利器呀.翻译一篇文章<<How to take advantage of Redis just adding it to yo ...

  7. 【Redis】Redis的基本安装及使用

    在Linux上安装Redis Redis的安装很简单.基本上是下载.解压.运行安装脚本.我用的Redis版本是3.2.1. [nicchagil@localhost app]$ wget -q htt ...

  8. vagrant系列教程(四):vagrant搭建redis与redis的监控程序redis-stat(转)

    上一篇php7环境的搭建 真是火爆,仅仅两天时间,就破了我之前swagger系列的一片文章,看来,大家对搭建环境真是情有独钟. 为了访问量,我今天再来一篇Redis的搭建.当然不能仅仅是redis的搭 ...

  9. Redis、Redis+sentinel安装(Ubuntu 14.04下Redis安装及简单测试)

    Ubuntu下Redis安装两种安装方式: 1.apt-get方式 步骤: 以root权限登录,切换到/usr目录下. 接下来输入命令,apt-get install redis-server,如图: ...

  10. Redis学习——Redis事务

    Redis和传统的关系型数据库一样,因为具有持久化的功能,所以也有事务的功能! 有关事务相关的概念和介绍,这里就不做介绍. 在学习Redis的事务之前,首先抛出一个面试的问题. 面试官:请问Redis ...

随机推荐

  1. 用Python怎么telnet到网络设备

    0.前言 Telnet协议属于TCP/IP协议族里的一种,对于我们这些网络攻城狮来说,再熟悉不过了,常用于远程登陆到网络设备进行操作,但是,它的缺陷太明显了,就是不安全,信息明文传送,极容易被攻击窃取 ...

  2. Ubuntu 搭建Zookeeper服务

    1.下载安装包 官方下载地址http://apache.fayea.com/zookeeper/ 2.安装 安装前确保系统已安装过JDK,JDK安装过程可参照 2.1 解压下载好的tar.gz安装包到 ...

  3. android系统中对ffmpeg封装最好的免费SDK

    android系统中对ffmpeg封装最好的免费SDK; 无论个人还是公司,都免费商用, 欢迎下载. https://github.com/LanSoSdk/LanSoEditor_common 可能 ...

  4. .net core 3.0 Signalr - 04 使用Redis做底板来支持横向扩展

    在实际的系统中,可能需要多台机器部署;然而,Signalr的连接信息是跟站点走的,举个例子 推送系统部署了A.B两个服务器,张三访问A服务器,李四访问B服务器,当张三通过A服务器向李四推送的时候,A服 ...

  5. navicat安装及其简单使用

    一.安装 下载地址:https://pan.baidu.com/s/1bpo5mqj 下载完之后,直接解压出来就能用,看一下解压之后的目录: 双击打开下面这个文件(可以把它添加一个桌面快捷方式,或者添 ...

  6. 理解LSTM网络--Understanding LSTM Networks(翻译一篇colah's blog)

    colah的一篇讲解LSTM比较好的文章,翻译过来一起学习,原文地址:http://colah.github.io/posts/2015-08-Understanding-LSTMs/ ,Posted ...

  7. 《Java语言程序设计》编程练习8.9(游戏:#字游戏)

    8.9 (游戏:#字游戏)在并字游戏中,两个玩家使用各自的标志(一方用X则另一方就用O),轮流填写3x3的网格中的某个空格.当一个玩家在网格的水平方向.垂直方向或者对角线方向上出 现了三个相同的X或三 ...

  8. Ubuntu部署Tomcat Web服务

    在Ubuntu平台中安装TomCat 本文将为大家介绍TomCat在Ubuntu平台中如何进行部署使用,带你快速入门使用TomCat TomCat简介 Tomcat是Apache 软件基金会(Apac ...

  9. ssrf漏洞学习(PHP)

    自己最近原本是想深入的学习一下关于xss.csrf的东西的,可是感觉这些东西需要有很好的js的基础来进行学习..还有感觉自己感觉也差不多该要学习内网渗透了..正好ssrf在内网这一块也是比较有用的.于 ...

  10. JAVA阻塞(IO)和非阻塞(NIO)

    查看这篇文章,了解更多关于Java的阻塞和非阻塞替代创建套接字的信息. 套接字使用TCP / IP传输协议,是两台主机之间的最后一块网络通信. 您通常不必处理它们,因为它们之上构建了协议,如HTTP或 ...