redis面试:redis 6.0 多线程的实现机制

Redis官方在 2020 年 5 月正式推出 6.0 版本,提供很多振奋人心的新特性,所以备受关注。其主要特性如下:

  • 多线程处理网络IO
  • 客户端缓存
  • 细粒度权限控制(ACL);
  • RESP3协议的使用
  • 用于复制的RDB文件不再有用,将立即被删除
  • RDB 文件加载速度更快;

redis6.0之前为什么不使用多线程

  • 使用redis时,几乎不存在CPU成为瓶颈的情况,redis主要受限于内存和网络
  • 在一个普通的linux系统上,redis通过使用pipelining每秒可以处理100万个请求,所以如果应用程序主要使用 Q ( N ) Q(N) Q(N)或者 O ( l o g ( N ) ) O(log(N)) O(log(N))的命令,它几乎不会占用太多CPU
  • 使用了单线程后,可维护性高。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度,同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗

redis通过AE事件模型以及IO多路复用等技术,处理性能非常高,因此没有必要使用多线程

单线程机制让redis内部实现的复杂度大大降低,hash的惰性rehash、lpush等【线程不安全】的命令都可以无锁进行

redis 6.0 之前单线程指的是redis只有一个线程干活么?

不是,Redis 在处理客户端的请求时,包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的「单线程」

其中执行命令阶段,由于 Redis 是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个 Socket 队列中,当 socket 可读则交给单线程事件分发器逐个被执行。
在这里插入图片描述
此外,有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写)

那redis6.0为什么要引入多线程?

随着硬件性能提升,redis的性能瓶颈可能出现网络IO的读写,也就是:单个线程处理网络读写的速度跟不上底层网络硬件的速度

读写网络的read/write系统调用占用了redis执行期间大部分CPU时间,瓶颈主要在于网络的IO消耗,优化主要有两个方向

  • 提高网络 IO 性能,典型的实现比如使用 DPDK来替代内核网络栈的方式、零拷贝技术。
  • 使用多线程充分利用多核,提高网络请求读写的并行度,典型的实现比如 Memcached。

零拷贝技术有其局限性,无法完全适配redis这一复杂的网络IO模型。而DPDK技术通过旁路网卡IO绕过内核协议栈的方式又太过于复杂以及需要内核甚至硬件的支持,所以我们只能从后者下手啦。

主要注意的是,redis多IO线程模型只用来处理网络读写请求,对于redis的读写命令,依然是单线程处理

这是因为:

  • 网络处理经常是瓶颈,需要通过多线程并行处理可提高性能
  • 继续使用单线程执行读写命令,不需要为了保证LUA脚本、事务等开发多线程安全机制,实现更简单

架构图如下:
在这里插入图片描述

主线程与 IO 多线程是如何实现协作呢?Redis 6.0 多线程的实现机制?)

  • 主线程负责接收建立连接过程,获取socket放入全局等待读处理队列
  • 主线程通过轮询将可读socket分配给IO线程
  • 主线程阻塞等待IO线程读取socket完成
  • 主线程执行IO线程读取和解析出来的redis请求命令
  • 主线程阻塞等待 IO 线程将指令执行结果回写回 socket完毕;
  • 主线程清空全局队列,等待客户端后继的请求

在这里插入图片描述
在这里插入图片描述
该设计有如下特点:

  • IO 线程要么同时在读 Socket,要么同时在写,不会同时读或写。
  • IO 线程只负责读写 Socket 解析命令,不负责命令处理。

开启多线程后,是否会存在线程并发安全问题?

不存在。

从实现机制可以看出,redis的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程顺序执行

所以我们不需要去考虑控制 Key、Lua、事务,LPUSH/LPOP 等等的并发及线程安全问题。

在这里插入图片描述

Redis6.0与Memcached多线程模型对比:

相同点:都采用了master线程—worker线程的模型

不同点:

  • memcached执行主逻辑也是在worker线程里面,模型更进简单,实现了真正的线程隔离
  • redis把处理逻辑交还给了master线程,虽然在一定程序上增加了模型复杂度,但也解决了线程并发安全等问题

Redis 6.0 默认是否开启了多线程?

Redis 6.0 的多线程默认是禁用的,只使用主线程。如需开启在conf文件进行配置

io-threads-do-reads yes
io-threads 线程数

官方建议:4 核的机器建议设置为 2 或 3 个线程,8 核的建议设置为 6 个线程,线程数一定要小于机器核数,尽量不超过8个。

线程数并不是越大越好,官方认为超过了 8 个基本就没什么意义了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值