Redis重视影响Redis性能的因素,如:
要尽可能避免性能异常场景,还要做好异常应对方案。影响Redis性能的潜在风险:
本文研究Redis内部的阻塞式操作及应对方案。
Redis的网络I/O和KV对读写都由主线程完成。若在主线程执行操作耗时太长,就会引起主线程阻塞。但Redis既有服务客户端请求的键值对增删改查操作,也有保证可靠性的持久化操作,还有主从复制时的数据同步操作。哪些会引起阻塞?
Redis要和不同对象交互,有不同操作:
Redis使用I/O多路复用,避免主线程一直处在等待网络连接或请求到来的状态,所以,网络I/O并非导致Redis阻塞因素。
KV对的crud操作是Redis和客户端主要交互,也是Redis主线程执行的主要任务。复杂度高crud操作势必阻塞Redis。
最基本标准:看操作复杂度是否O(N)。Redis涉及集合的操作复杂度通常O(N):
集合自身的删除也可能阻塞。
Q:不就直接数据删除,咋阻塞主线程?
A:删除本质是释放KV对占用内存空间。
释放内存只是第一步,为高效管理内存,应用程序释放内存时,os要把释放掉的内存块插入一个空闲内存块的链表,以便后续管理和再分配。这过程耗时,且会阻塞当前释放内存的应用程序。
所以,若突然释放大量内存,空闲内存块链表操作时间就会增加,导致Redis主线程阻塞。
最常见于删除含大量元素的集合,即删除bigkey。不同元素数量集执行删除耗时:
集合类型 | 10万(8字节) | 100万(8字节) | 10万(128字节) | 100万(128字节) |
|---|---|---|---|---|
Hash | 50ms | 962ms | 91ms | 1980ms |
List | 25ms | 133ms | 29ms | 283ms |
Set | 42ms | 821ms | 75ms | 1347ms |
Sorted Set | 53ms | 809ms | 61ms | 991ms |
Redis数据库级操作:清空数据库,如FLUSHDB、FLUSHALL也是重大阻塞风险,涉及删除、释放所有KV对。
磁盘I/O费时费力,Redis开发者早就设计为:
都由子进程负责执行,慢速的磁盘I/O就不阻塞主线程。
但Redis直接记录AOF日志时,会根据不同写回策略对数据做落盘保存。
一个同步写盘操作耗时大约1~2ms,若大量写操作需记录在AOF日志,并同步写回,就会阻塞主线程。
主从集群中的主库需:
主库在复制过程,创建、传输RDB都由子进程完成,不阻塞主线程。
但从库,接收RDB文件后,需用FLUSHDB命令清空当前数据库,恰好撞车三大阻塞点。从库清空当前数据库后,还要把RDB文件载入内存,RDB文件越大,加载越慢。
所以,一般这两类操作对Redis主线程阻塞影响不大。
但若使用Redis Cluster,且同时正好迁移大key,就会阻塞主线程,因Redis Cluster使用的同步迁移。
当无大key时,分片集群的各实例在进行交互时一般不会阻塞主线程。
在主线程中执行以上操作,势必导致主线程长时间无法服务其它请求。
为避免阻塞式操作,Redis提供异步线程机制:Redis会启动一些子线程,把一些任务移交子线程,让它们在后台处理。使用异步线程机制执行操作,可以避免阻塞主线程。
以上这些阻塞式操作可以被异步执行吗?
在分析阻塞式操作的异步执行的可行性前,先了解异步执行对操作的要求。
若一个操作能被异步执行,说明它不是Redis主线程关键路径上的操作。
客户端把请求发给Redis后,等Redis返回数据结果:
那Redis的写操作(如SET,HSET,SADD)属于关键路径吗?这需要客户端根据业务需要区分:
因为HSET和SADD操作,若field或member不存在,Redis返回1,否则返0。而SET操作返回的结果都是OK
因为若Redis内存超过maxmemory,再写入数据时,Redis返回的结果是OOM error,这种情况下,客户端需要感知有错误发生才行
Redis读都是关键路径操作,因为客户端发起读请求后,就会等待返回读取数据,再处理后续。所以,涉及读操作,无法异步!
推荐使用SCAN命令,分批读取数据,再在客户端进行聚合计算。
无需给客户端返具体数据,不算关键路径操作。
“大K删除”、“清空数据库”同理,都可用后台子线程异步执行。
为保证数据可靠性,Redis实例需保证AOF日志中的操作记录已落盘,这操作虽需实例等待,但不会返回具体数据结果给实例。所以,可使用一个子线程执行。
从库想对客户端提供数据存取服务,须将RDB文件加载完成。所以,这也属于关键路径操作,须让从库的主线程执行。把主库数据量大小控制在2~4GB左右,以保证RDB文件能以较快的速度加载。
综上,可使用Redis异步子线程机制实现大K删除,清空数据库及AOF日志同步写。
本文已收录在Github,关注我,紧跟本系列专栏文章,咱们下篇再续!