在Redis的运维使用过程中你遇到过那些问题,又是如何解决的呢?本文收集了一些Redis的常见问题以及解决方案,与大家一同探讨。

码字不易,欢迎大家转载,烦请注明出处;谢谢配合

你的Redis有bigkeys吗?

什么是bigkeys

bigkeys是指key不恰当设定,抑或是key对应的value值占用内存空间过大;具体表现为以下几种情形:

  • key值不恰当设定(比较少见),key设定冗长
  • String类型 value值长度过大
  • Hash,List,Set,Zset 包含元素个数过多

bigkeys有什么危害

为什么我们必须警惕bigkey呢?其实bigkey主要有以下几个方面的危害:

  • 内存使用不均匀,例如:在Redis-Cluster模式中,bigkey会造成节点内存使用不均匀。
  • 超时阻塞,由于Redis是单线程架构,操作bigkey耗时较长,有可能造成Redis阻塞。
  • 网络拥阻,例如:一个bigkey占用空间是1M,每秒访问1000次,将造成1000M的流量,可能造成打满机器带宽。

当然,如果bigkey访问频率不高,也仅会造成节点间内存使用不均;而当bigkey访问频繁时,其带来的影响是不可想象的,所以日常在开发运维的过程中应该警惕bigkey的存在。

如何找到bigkeys

了解到bigkey危害,我们该如何发现bigkeys呢?

Redis在设计之初就考虑到bigkeys的问题,我们可以使用 redis-cli --bigkeys 来发现bigkeys的分布情况;之后你如果想进一步了解bigkeys的具体情况可以使用 debug object <key> 来确定该key的具体信息。参考以下示例:

利用redis-cli --bigkeys找到bigkey,具体生产环境执行时强烈建议在从节点实行,如果担心OPS太高,可以使用 -i 0.1 ,表示每100条scan命令休眠0.1秒;其实该命令实现的原理就是利用我们常用的scan + type + strlen/hlen/llen/scard/zcard 命令实现的,具体可以从redis-cli.c的源码中探寻。

[root@VM_0_16_centos src]# redis-cli -p 6380 --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 100 SCAN commands (not usually needed). [00.00%] Biggest string found so far 'h' with 1 bytes
[00.00%] Biggest string found so far 'hello' with 105 bytes
[00.00%] Biggest string found so far 'heml' with 1434 bytes -------- summary ------- Sampled 3 keys in the keyspace!
Total key length in bytes is 10 (avg len 3.33) Biggest string found 'html' has 1434 bytes 0 lists with 0 items (00.00% of keys, avg size 0.00)
0 hashs with 0 fields (00.00% of keys, avg size 0.00)
3 strings with 1540 bytes (100.00% of keys, avg size 513.33)
0 streams with 0 entries (00.00% of keys, avg size 0.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)

执行结果是发现String类型的"html"为bigkey,我们紧接着来了解"html"的具体信息;使用
debug object <key> 命令,还有如果是对于元素个数较多的数据结构,该命令可能会阻塞redis实例,所以强烈建议在从节点执行

[root@VM_0_16_centos src]# redis-cli -p 6380
127.0.0.1:6379> debug object html
Value at:0x7f0b13a665c0 refcount:1 encoding:raw serializedlength:251 lru:12181323 lru_seconds_idle:229
127.0.0.1:6379> strlen html
(integer) 1434

我们发现key为"html"的String类型的value长达1434个字节,以上便是演示查找bigkeys的过程;除了以上方式我们可以在bigkeys影响redis正常提供服务之前,通过 scan + debug object 对怀疑的bigkeys进行逐个检查。

当然你如果担心执行相关命令会对正式环境有一定的影响,你也可以通过对RDB进行备份,然后根据RDB文件的结构,对RDB中的数据进行逐个分析同样的可以找到bigkey,不过这种方式的开发成本会有些高;使用者可以依据自己的实际情况来酌情判断。

如何处理bigkeys

经过一番折腾,我们终于找到bigkeys了,那么我们应该如何处理它呢?

在Redis4.0之前版本,由于DEL命令是同步删除的,针对String类型的bigkeys确实可以使用DEL命令,删除速度相对较快,一般不会阻塞redis;然而对于元素个数较多的数据结构,使用DEL命令来删除可能会阻塞redis实例;针对 Hash 结构,我们可以利用 HSCAN + HDEL 删除元素的成员,成员删除之后再利用 DEL 删除key;其余数据类似都是渐进的方式先删除成员,再删除key。

Redis4.0版本之后则支持了Lazy Delete Free模式,你可以使用 UNLINK 命令来删除bigkeys,它的实现是异步的,具体可以从redis-cli.c的源码中探寻,你需要先确认打开了lazyfree相关配置。

bigkeys总结

bigkeys的表现形式是内存分配不均;频繁操作的实际影响是有可能造成超时阻塞,网络拥阻;解决思路是事前监控,事中找到bigkeys,并通过正确的方式删除bigkeys。

你的Redis有hotkeys吗?

什么是hotkeys?

hotkeys是在Redis实例中某些key的操作频次远高于其他key,那么这些被频繁操作的热点key我们就称之为hotkeys。

hotkeys有什么危害?

hotkeys有什么危害呢?以Redis-Cluster模式为例,存在hotkeys的节点,将面临以下挑战:

  • 请求分配不均,存在hotkeys的节点面临较大的访问压力
  • 缓存击穿,hotkeys过期时,大量请求将直接导向DB
  • 缓存雪崩,击垮存在hotkeys的节点,导致不能正常提供服务

如何发现hotkeys呢?

Redis4.0之后客户端提供了hotkeys发现的相关命令,我们可以通过 redis-cli --hotkeys 来发现hotkeys;

Redis4.0之前我们也可以通过客户端,代理端,服务端,机器端等多个方面来发现hotkeys:

  • 在客户端建立全局字典表,对key和调用次数进行统计;缺点:侵入客户端
  • 如果你的集群是通过proxy + redis 的方式搭建的,那你可以很方便的从代理端对key和调用次数进行监控;缺点:限制代理模式的集群
  • 在服务端可以利用 monitor,对服务端接收的请求进行监控;缺点:侵入服务端,在高并发情况下会使内存暴增,适合短时间使用
  • 如果你不想侵入服务端与客户端,可以对服务端接收的请求进行抓包,分析以及监控;例如使用ELK(Elasticsearch + Logstach + kinbana)用packetbeat进行抓包。

如何处理hotkeys?

我们了解到hotkeys的危害,并可以通过技术手段找到hotkeys以后,我们该怎么对系统做优化呢?

首先针对hotkeys过期,面临的重建问题,可以使用以下有效手段来尽可能的减少key重建的过程:

  • 设置互斥锁,保证由一个线程完成热点key的重建,避免大量的请求直接导向DB
  • "永不过期",将hotkeys的过期时间设置较长的时间,或者永不过期;等待hotkeys触发的热点事件过去后再考虑过期。

针对Redis集群的优化,包括但不限于以下几种方式:

  • hotkeys表现就是请求分配不均;我们可以以此为出发点,来想办法使请求尽可能的分布平均;例如:利用<hotkeys_n,value> ,n为随机数,尽可能的多个实例都有该数据,在访问时在n的范围内取随机数以此来分摊请求;此方式需要一定的代码改造;
  • 本地缓存,此方式需要对热点信息有预知,例如:电商产品大促,热点产生在可以预知的范围内,便可以考虑此方式;
  • 集群的热点数据的节点的扩容,此方式原理同第一种方式相同,不同点在于不需要对代码进行改造,而是直接增加hotkeys对应节点的数据副本,使多个节点都具备提供该数据的读取能力,以此来均衡请求。

hotkeys总结

hotkeys的表现形式是请求的分配不均,问题恶化将导致Redis集群请求倾斜,甚至集群雪崩,我们可以通过多种途径来均衡请求,避免单个节点过热;如果hotkeys的超时实现过短,可能会导致大量请求涌入到DB,并发重建key,可以通过合理的锁机制或者设置合理的超时时间来避免。

Redis缓存穿透

什么是缓存穿透

缓存穿透是大量请求的key在缓存中没有,直接请求到DB,使缓存失去保护数据库的作用;例如:黑客刻意构建大量缓存中没有的key,导致每次处理请求都需要去访问数据库。

正常缓存处理流程

 
缓存穿透处理流程
 
缓存穿透的流程便是故意构建缓存中没有的key导致,所有的请求必须查库;缓存失去其保护数据库的意义。

解决缓存穿透

通过以上流程图我们对缓存穿透有了一定的了解,那该如何解决此类问题呢?通常解决的方式有两种:

(1) 对空值进行缓存,设置较短的失效时间;

 

分析:我们对null进行缓存,Redis需要更大的内存空间;此方案适用于请求key变化不频繁的情况;如何黑客恶意攻击,每次构建的不同的请求key,这种方案并不能从根本上解决此问题。

(2) 使用布隆过滤器,布隆过滤器优势在于检索一个元素是否在一个集合内;我们可以利用布隆过滤器来判断请求的key是否在合理的范围内,如果不存在,则直接过滤掉。

 

分析:可以利用Redis的 BitMap来实现布隆过滤器,用其来缓存目标数据集变化不频繁,而请求key变化频繁的情况。

Redis缓存雪崩

什么是缓存雪崩

缓存雪崩是指由于缓存集中过期或者缓存不可用,导致大量请求直接导向数据库。在高并发的情况下,巨大的请求量有可能导致数据库的崩溃,甚至导致整个应用体系的全盘崩溃;缓存失去保护是数据库的作用,而巨大导致流量流向数据库就是缓存雪崩的表现形式。

如何预防及避免

  • 设置合理的过期策略,避免缓存集中过期。
  • hotkeys分片存储,避免请求数据的倾斜,导致缓存。
  • hotkeys设置合理的过期时间或者“永不过期”。

Redis阻塞

我们知道Redis是单线程模型,如果线上Redis发生阻塞对整个应用将是毁灭性的;那什么原因会导致Redis阻塞呢?

API或数据结构使用不合理

常见的是在生产上执行时间复杂度高的命令如: KEYS,可以通过RENAME 方式将命令修改为不易猜测的,避免开发运维人员的不当执行。
数据结构的不合理,如存在频繁操作bigkeys,有可能造成阻塞,将bigkeys拆分成成员较小的key。

CPU饱和

Redis单实例OPS可以到达平均10W+左右,如果你的Redis实例OPS已经达到较高的数值,那你可以考虑集群的水平扩展,来降低实例的OPS;但是你的Redis实例OPS不高,CPU使用率较高,那你应该检查应用是否使用了时间复杂度较高的命令。

持久化阻塞

我们知道Redis可以进行持久化来防止数据的丢失;RDB方式,主进程会fork一个共享内存子进程来创建RDB文件,如果fork耗时过长,必然将阻塞主进程。
AOF刷盘,通常我们设置的刷盘策略是everysec,但由于磁盘压力过大,fsync有可能耗时较长,当时间大于1秒时,为了保证数据安全,下次fsync调用将阻塞知道上次调用结束。

其他原因

CPU竞争:Redis是CPU密集型应用,应避免跟其他CPU密集型应用部署在一起
内存交换:Redis由于从内存中直接读取,所以响应速度很快;当内存严重不足时,可能会存在内存交换,这将影响Redis的执行效率;通过cat /proc/$pid/smaps | grep Swap 来确认是否有频繁的内存交换。
网络问题:连接数限制或者网络延时等也有可能导致阻塞

Redis淘汰策略

当Redis的内存使用达到限制时(可通过maxmemory <bytes>设置),会根据根据淘汰策略来移除Keys;有如下淘汰策略:

  • allkeys-random:在所有keys中随机移除
  • allkeys-lru:在所有keys中使用lru移除
  • allkeys-lfu:在所有keys中使用lfu移除
  • volatile-random:在过期keys中随机移除
  • volatile-lru:在过期keys中使用lru移除
  • volatile-lfu:在过期keys中使用lfu移除
  • volatile-ttl:移除即将过期
  • noevction:不移除任何key,空间不足时将抛出error

lru:Least Recently Used 最近最少使用
lfu:Least Frequently Used 最不经常使用

总结

本文介绍了bigkeys,hotkeys,缓存穿透,缓存雪崩,阻塞等问题;然而我们在实际应用中难免会遇到各种各样的问题,本文难以一一列举;但是面对问题我们要沉着冷静,了解清楚问题的现象与本质,找到问题的症结所在,随后在对症下药便可以解决问题。

 
 
 

Redis常见问题及解决方案的更多相关文章

  1. redis常见问题和解决方案

    转载:https://www.cnblogs.com/aspirant/p/6820262.html [原创]那些年用过的Redis集群架构(含面试解析) redis常见问题和解决方案 持久化.主从问 ...

  2. Redis实战(十)Redis常见问题及解决方案

    序言

  3. Redis 常见问题总结

    1. 简单介绍一下 Redis 呗! 简单来说 Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的 ,也就是它是内存数据库,所以读写速度非常快, ...

  4. 《PDF.NE数据框架常见问题及解决方案-初》

    <PDF.NE数据框架常见问题及解决方案-初> 1.新增数据库后,获取标识列的值: 解决方案:    PDF.NET数据框架,已经为我们考略了很多,因为用PDF.NET进行数据的添加操作时 ...

  5. Codis——分布式Redis服务的解决方案

    Codis——分布式Redis服务的解决方案 之前介绍过的 Twemproxy 是一种Redis代理,但它不支持集群的动态伸缩,而codis则支持动态的增减Redis节点:另外,官方的redis 3. ...

  6. XHTML CSS 常见问题和解决方案

    原文地址:XHTML CSS 常见问题和解决方案 作为前端开发人员,在日常的页面制作时,不可避免的会碰上这样那样的问题,我挑选了其中的一些进行总结归档,希望对大家会有所帮助: 1.如何定义高度很小的容 ...

  7. 虚拟机centOS中安装Redis,主机Redis Destop Manager不能访问虚拟机Redis server的解决方案

    今天在学些redis的时候碰到个问题,发现主机Redis Destop Manager不能访问虚拟机Redis server的解决方案,找了一些网上的资料,原因可能有两个,整理记录下来: 1. Red ...

  8. Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方

    Linux Redis 重启数据丢失解决方案,Linux重启后Redis数据丢失解决方案 >>>>>>>>>>>>>> ...

  9. 自学华为IoT物联网_06 智慧家庭物联网常见问题及解决方案

    点击返回自学华为IoT物流网 自学华为IoT物联网_06 智慧家庭物联网常见问题及解决方案 1. 家庭中遇到的问题 2.1 华为智慧家庭概念的发展历程 2.2 华为智慧家庭的解决方案架构 智慧家庭主要 ...

随机推荐

  1. Jenkins+Docker+Git+Harbor流水线打包

    Jenkins+Docker+Git+Harbor流水线打包 环境: CentOS Linux release 7.6.1810 (Core) 192.168.247.214 Jenkins+dock ...

  2. Python 软件安装

    安装Python解释器 Python目前已支持所有主流操作系统,在Linux,Unix,Mac系统上自带Python环境,在Windows系统上需要安装一下,超简单 打开官网https://www.p ...

  3. MySQL/MariaDB数据库的主从级联复制

      MySQL/MariaDB数据库的主从级联复制 作者:尹正杰  版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.主从复制类型概述 1>.主从复制 博主推荐阅读: https://ww ...

  4. Linux基础命令-查看基本硬件信息

    Linux基础命令-查看基本硬件信息 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查看CPU信息 [root@node101.yinzhengjie.org.cn ~]# l ...

  5. 最大m子段和

    最大m子段和 定义一串子段s1,s2,s3 ... sn-1,sn 求m段不交叉最大子段和 解:设dp[i][j]代表前j个数分成i段的最大和(包括a[j]) 状态转移方程: dp[i][j]=Max ...

  6. ZOJ - 3265: Strange Game (优化 二分图匹配)

    pro:有一个长度为N的数组a[i],要求选择k[i]>0,使得b[i]=a[i]^k[i]%M中出现的不同数最多.N<=200, M<=1e9: sol:a^x%p的个数的有限的, ...

  7. intellij高亮字体背景颜色

    https://blog.csdn.net/aosica321/article/details/52956419 https://blog.csdn.net/lxzpp/article/details ...

  8. “Another git process seems to be running in this repository...”Git此问题解决

    Git中显示:Another git process seems to be running in this repository, e.g.an editor opened by 'git comm ...

  9. 解决bash: less: command not found

    问题描述 使用less命令查找日志时,less命令未找到: 解决办法 安装less,执行如下命令: npm install -g less

  10. Postgresql operator does not exist: numeric = character varying

    )),series_name from svcm_t_series_res: 原来series_id是numeric型,现在转换为varchar(64):