在Redis的运维使用过程当中你遇到过那些问题,又是如何解决的呢?本文收集了一些Redis的常见问题以及解决方案,与你们一同探讨。css
码字不易,欢迎你们转载,烦请注明出处;谢谢配合html
bigkeys是指key不恰当设定,抑或是key对应的value值占用内存空间过大;具体表现为如下几种情形:python
为何咱们必须警戒bigkey呢?其实bigkey主要有如下几个方面的危害:redis
固然,若是bigkey访问频率不高,也仅会形成节点间内存使用不均;而当bigkey访问频繁时,其带来的影响是不可想象的,因此平常在开发运维的过程当中应该警戒bigkey的存在。数据库
了解到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了,那么咱们应该如何处理它呢?
在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。
hotkeys是在Redis实例中某些key的操做频次远高于其余key,那么这些被频繁操做的热点key咱们就称之为hotkeys。
hotkeys有什么危害呢?以Redis-Cluster模式为例,存在hotkeys的节点,将面临如下挑战:
Redis4.0以后客户端提供了hotkeys发现的相关命令,咱们能够经过 redis-cli --hotkeys 来发现hotkeys;
Redis4.0以前咱们也能够经过客户端,代理端,服务端,机器端等多个方面来发现hotkeys:
咱们了解到hotkeys的危害,并能够经过技术手段找到hotkeys之后,咱们该怎么对系统作优化呢?
首先针对hotkeys过时,面临的重建问题,可使用如下有效手段来尽量的减小key重建的过程:
针对Redis集群的优化,包括但不限于如下几种方式:
hotkeys的表现形式是请求的分配不均,问题恶化将致使Redis集群请求倾斜,甚至集群雪崩,咱们能够经过多种途径来均衡请求,避免单个节点过热;若是hotkeys的超时实现太短,可能会致使大量请求涌入到DB,并发重建key,能够经过合理的锁机制或者设置合理的超时时间来避免。
缓存穿透是大量请求的key在缓存中没有,直接请求到DB,使缓存失去保护数据库的做用;例如:黑客刻意构建大量缓存中没有的key,致使每次处理请求都须要去访问数据库。
正常缓存处理流程
经过以上流程图咱们对缓存穿透有了必定的了解,那该如何解决此类问题呢?一般解决的方式有两种:
(1) 对空值进行缓存,设置较短的失效时间;
分析:咱们对null进行缓存,Redis须要更大的内存空间;此方案适用于请求key变化不频繁的状况;如何黑客恶意攻击,每次构建的不一样的请求key,这种方案并不能从根本上解决此问题。
(2) 使用布隆过滤器,布隆过滤器优点在于检索一个元素是否在一个集合内;咱们能够利用布隆过滤器来判断请求的key是否在合理的范围内,若是不存在,则直接过滤掉。
分析:能够利用Redis的 BitMap来实现布隆过滤器,用其来缓存目标数据集变化不频繁,而请求key变化频繁的状况。
缓存雪崩是指因为缓存集中过时或者缓存不可用,致使大量请求直接导向数据库。在高并发的状况下,巨大的请求量有可能致使数据库的崩溃,甚至致使整个应用体系的全盘崩溃;缓存失去保护是数据库的做用,而巨大致使流量流向数据库就是缓存雪崩的表现形式。
咱们知道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的内存使用达到限制时(可经过maxmemory <bytes>设置),会根据根据淘汰策略来移除Keys;有以下淘汰策略:
lru:Least Recently Used 最近最少使用
lfu:Least Frequently Used 最不常用
本文介绍了bigkeys,hotkeys,缓存穿透,缓存雪崩,阻塞等问题;然而咱们在实际应用中不免会遇到各类各样的问题,本文难以一一列举;可是面对问题咱们要沉着冷静,了解清楚问题的现象与本质,找到问题的症结所在,随后在对症下药即可以解决问题。