Redis 知识 -- Redis 线程相关知识

本文最后更新于:3 天前

单线程

Redis Server 是多线程的,只是它的请求处理的整个流程是单线程的

由于 Redis 是内存级 IO 操作,与磁盘级IO相比快几个量级,如果 Redis 采用多线程模型,那么A线程IO操作时切换到B线程进行CPU计算,可能还没切换完成A线程就已经完成IO操作了。也就是说频繁的线程切换可能会导致CPU浪费更多,不比单线程等待IO浪费的少。所以单线程可能效率会更高。

单线程模型还带了以下好处:

  1. 没有了多线程上下文切换的性能损耗,不存在多进程或者多线程导致的切换而消耗 CPU

  2. 没有了访问共享资源加锁的性能损耗,没有因为可能出现死锁而导致的性能消耗

  3. 开发和调试非常友好,可维护性高

单线程处理最大的缺点就是,如果前一个请求发生耗时比较久的操作,那么整个Redis就会阻塞住,其他请求也无法进来,直到这个耗时久的操作处理完成并返回,其他请求才能被处理到。

所以,我们在使用Redis时,一定要避免非常耗时的操作,例如使用时间复杂度过高的方式获取数据、一次性获取过多的数据、大量key集中过期导致Redis淘汰key压力变大等等,这些场景都会阻塞住整个处理线程,直到它们处理完成,势必会影响业务的访问。

多线程

Redis Server 本身是多线程的,除了请求处理流程是单线程之外,Redis 内部还有其他工作线程在后台执行,它负责异步执行某些比较耗时的任务,例如 AOF 每秒刷盘、AOF 文件重写都是在另一个线程中完成的。

而在 Redis 4.0 之后,Redis引入了 lazyfree 的机制,提供了 unlink、flushall aysc、flushdb async 等命令和 lazyfree-lazy-eviction、lazyfree-lazy-expire 等机制来异步释放内存,它主要是为了解决在释放大内存数据导致整个 redis 阻塞的性能问题。

在删除大key时,释放内存往往都比较耗时,所以Redis提供异步释放内存的方式,让这些耗时的操作放到另一个线程中异步去处理,从而不影响主线程的执行,提高性能。

到了 Redis 6.0,Redis又引入了多线程来完成请求数据的协议解析,进一步提升性能。它主要是解决高并发场景下,单线程解析请求数据协议带来的压力。请求数据的协议解析由多线程完成之后,后面的请求处理阶段,包括执行命令的核心模块,依旧还是单线程排队处理。

总结

Redis使用单线程,配合IO多路复用技术,可以完成多个连接的请求处理。而且正是由于它的使用定位是内存数据库,这样几乎所有的操作都在内存中完成,它的性能可以达到非常之高。

同时,单线程没有了线程上下文切换和访问共享资源加锁的性能损耗,而且单线程模型对程序的开发和调试非常友好,因此Redis使用单线程模型也就在情理之中了。

Redis在最近的版本也对多线程进行了优化,用于解决释放大内存数据和请求数据协议解析对Redis产生的性能影响,进一步提升了Redis的性能。

单线程结合上述场景可以达到非常高的性能,同时也存在耗时操作阻塞整个线程的问题,我们在使用Redis时要避免耗时过长的操作,才能更好地发挥Redis的性能。