Redis常见问题及解决方案

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

码字不易,欢迎你们转载,烦请注明出处;谢谢配合html

你的Redis有bigkeys吗?

什么是bigkeys

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

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

bigkeys有什么危害

为何咱们必须警戒bigkey呢?其实bigkey主要有如下几个方面的危害:redis

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

固然,若是bigkey访问频率不高,也仅会形成节点间内存使用不均;而当bigkey访问频繁时,其带来的影响是不可想象的,因此平常在开发运维的过程当中应该警戒bigkey的存在。数据库

如何找到bigkeys

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

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实例,因此强烈建议在从节点执行bash

[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,缓存穿透,缓存雪崩,阻塞等问题;然而咱们在实际应用中不免会遇到各类各样的问题,本文难以一一列举;可是面对问题咱们要沉着冷静,了解清楚问题的现象与本质,找到问题的症结所在,随后在对症下药即可以解决问题。 

相关文章
相关标签/搜索