Luga Lee
作者Luga Lee·2020-03-03 22:02
系统架构师·None

Redis 线程模型浅析

字数 2135阅读 3385评论 0赞 1

Redis 线程模型



概述

在早期的版本, Redis 作为一个 经典的 内存服务器,需要处理很多来自外部的网络请求,使用 基于 I/O 多路复用机制同时监听多个文件描述符的可读和可写状态,由于绝大多数的操作都是 在 纯内存 环境下 , 故其 处理速度会非常地快 。

However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For the next releases, the plan is to make Redis more and more threaded__

然而 Redis 4.0 之后的版本, 抛弃了单线程模型这一设计, 在执行 一些命令时就会使用主处理线程之外的其他线程,例如 UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC 等非阻塞的删除操作 。

架构设计

从Redis本身产品定位来讲,无论是基于单线程or多线程模型,其本质无非是为了更好的发挥其特性,比如开发效率、运行性能。

虽然 Redis 在较新的版本中引入了多线程,不过是在部分命令上引入的,其中包括非阻塞的删除操作,在整体的架构设计上,主处理程序还是单线程模型的。由此得出:

1、 Redis 服务使用单线程模型处理绝大多数的网络请求

2、 Redis服务使用多线程模型处理非阻塞的删除操作,例如: UNLINK 、 FLUSHALL ASYNC 和 FLUSHDB ASYNC

单线程模型

Redis 从一开始就选择使用单线程模型处理来自客户端的绝大多数网络请求,这种考虑其实是多方面的, 依据官方所提供的 相关资料,其中最重要的几个原因如下:

1、 CPU资源非 Redis服务 器 性能瓶颈

2、使用单线程模型也能并发的处理客户端的请求

3、使用单线程模型能带来更好的可维护性,方便开发和调试

原因1是最终使用单线程模型的决定性因素,2、3原因是使用单线程模型带来的好处。

客户端命令的请求获取 (socket 读)、解析、执行、内容返回 (socket 写) 等等都是由一个线程处理,所有操作是一个个挨着串行执行的 (主线程),这也是 Redis 有 “单线程” 定义的来源。

单线程机制使得 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等 “ 线程不安全 ” 的命令都可以无锁进行 。

多线程模型

目前对于单线程 Redis 来说,性能瓶颈主要在于网络的 IO 消耗, 优化主要有两个方向 :

1、 提高网络 IO 性能,典型的实现像使用 DPDK 来替代内核网络栈的方式

2、 使用多线程充分利用多核,典型的实现像Memcached

多线程 模型 机制有两大直观优点:

1、 可以充分利用服务器CPU资源,目前主线程只能利用一个核

2、 多线程任务可以 缓解 Redis同步IO读写负荷

通常 情况下,Redis 使用同步非阻塞 IO,通过多路复用机制 (linux 上用 epoll) 封装成事件驱动机制。非阻塞 IO 在调用时不会导致进程因为等待IO事件而阻塞,通 过 epoll的机制,在IO事件发生时通过异步的方式通知用户态进程处理,这点极大地提高了IO的处理效率 。

多线程特性在社区也被反复提了很久后,Redis作者antirez终于 在 Redis 6加入多线程。

因为读写网络的read/write系统调用在Redis执行期间占用了大部分CPU时间,如果把网络读写做成多线程的方式对性能会有很大提升。现在已经实现了第一版,write side即回复客户端这部分已经完成了,并且去掉了主线程和IO线程之间的互斥锁,采用busy loop的形式来等待io线程工作结束,这部分能够有50%的性能提升。

Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。之所以这么设计是不想Redis因为多线程而变得复杂,需要去控制 key、lua、事务、 LPUSH/LPOP 等等的并发问题 。

总结

Redis 选择基于单线程模型处理客户端的请求主要是因为 CPU不是 Redis服务器的瓶颈,所以使用多线程模型带来的性能提升并不能抵消它带来的开发成本和维护成本,系统的性能瓶颈也主要在网络 I/O 操作上;而 Redis 引入多线程操作也是出于性能上的考虑,对于一些大键值对的删除操作,通过多线程非阻塞地释放内存空间也能减少对 Redis 主线程阻塞的时间,提高执行的效率 。

参考

l https://redis.io/topics/faq#redis-is-single-threaded-how-can-i-exploit-multiple-cpu--cores

l http://antirez.com/news/126

l https://github.com/antirez/redis/tree/unstable

__

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

1

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广