目录
前言
大家对redis 比较熟悉吧,只要做项目都会用到redis,提高系统的吞吐。小米商城抢购高峰18k的qps,redis 在其中扮演着非常重要的角色。有时我们操作不当,redis 阻塞了,影响了整个业务。我记得2018年的时候,顺丰就出现了一个事故,有同学在线上对redis的一个操作,直接阻塞了,影响公司的整个业务,后面这位同学被辞退了。如果他对redis比较了解的话,也不会出现这样的事故。
redis 为什么会阻塞,与它的本身设计有一定关系。大家都知道redis 是单线程的,这个并完全正确,只是说我们对数据的读写是在主线程中完成的。但RDB,aof 重写,删除都是在子线程完成的。我们说的阻塞就是阻塞的主线程,redis 为什么会这么设计,抽时间我会详细讲解。这篇文章我主要从客户端,磁盘,主从节点,切片集群实例 多方面取阐述这个问题。
客户端交换时的阻塞
客户端的功能,与redis 服务器建立连接就有对网络IO的影响,对数据库的增删改查操作。redis 采用的是多路复用机制,避免了主线程一直处在等待网络连接或请求到来的状态,所以,网络 IO 不是导致 Redis 阻塞的因素。剩下的也就是增删改查对redis 的影响,这部分功能也是redis 主要的任务,复杂度高的肯定会阻塞redis。
那么怎么判断操作复杂度高不高?就是看复杂度的O(N),这个复杂度也可以看作是空间复杂度。N越大复杂度越高,越容易阻塞。我们可以对照redis 官网的命令,进行查看。一般集合的操作都是O(N) 的复杂度。比如HGETALL,SMEMBERS,以及集合的聚合统计操作,交,并,差集。这些操作特殊是集合的全量查询和聚合操作。
我们看了查询,删除会不会造成redis 阻塞了。当然会了,删除操作的本质是释放键值对占用的内存空间。它不仅释放内存空间,在Redis 释放内存时,操作系统会把释放掉的内存块插入到一个空闲内存块链表,以便后续进行管理和分配。这个过程需要时间并且会阻塞当前释放内存的应用程序。元素数量越大,这个操作消耗的时间越多,越容易阻塞,这就是我们所说的bigkey 删除。
还有就是清空数据库的操作例如( FLUSHDB 和 FLUSHALL 操作)必然也是一个潜在的阻塞风险,因为它涉及到删除和释放所有的键值对。