关于前端:面试官问Redis-是单线程还是多线程我懵了

1次阅读

共计 2559 个字符,预计需要花费 7 分钟才能阅读完成。

咱们平时看到介绍 Redis 的文章,都会说 Redis 是单线程的。然而咱们学习的时候,比方 Redis 的 bgsave 命令,它的作用是在后盾异步保留以后数据库的数据到磁盘,那既然是异步了,必定是由别的线程去实现的,这怎么还能说 Redis 是单线程的呢?

其实通常说的 Redis 是单线程,次要是指 Redis 对外提供键值存储服务的次要流程,即网络 IO 和键值对读写是由⼀个线程来实现的。除此外 Redis 的其余性能,比方长久化、异步删除、集群数据同步等,是由额定的线程执⾏的。在这一点上 Node 也是一样的,个别提到 Node 也是单线程的,但其实 Node 只有一个主线程是单线程,其余异步工作则由其余线程实现。这样做的起因是避免有同步代码阻塞,导致主线程被占用后影响后续的程序代码执行。

因而,严格地说 Redis 并不是单线程。然而咱们⼀般把 Redis 称为单线程高性能,这样显得 Redis 更强一些。

Redis 为什么用单线程

Redis 为什么用单线程?在答复这个问题前,先来看大家都很相熟的数据库 MySQL,它应用的就是多线程。MySQL 不会每有一个连贯就创立一个线程,因为线程过多会带来额定的开销,其中包含创立销毁线程的开销、调度线程的开销等,同时也会升高计算机的整体性能。这个正是多线程会遇到的难点。

此外多线程零碎中通常会存在被多线程同时拜访的共享资源,比方一个共享的数据结构,当有多个过程要批改这个共享资源时,为了保障共享资源的正确性,就须要有额定的机制进行保障,而这个额定的机制,也会带来额定的开销。还是以 MySQL 举例,MySQL 引入了锁机制来解决这个问题。

从下面不难看出,多线程开发中并发访问控制是⼀个难点,须要精密的设计能力解决。如果只是简略地解决,比方简略地采⽤⼀个粗粒度互斥锁,只会呈现不现实的后果。即使减少了线程,零碎吞吐率也不会随着线程的减少而减少,因为大部分线程还在期待获取访问共享资源的互斥锁。而且,大部分采纳多线程开发引入的同步原语爱护共享资源的并发拜访,也会升高零碎代码的易调试性和可维护性。

而正是以上这些问题,才让 Redis 采⽤了单线程模式。

看到这里大家可能有点纳闷,后面说了 Redis 不是单线程,当初咱们也说了 Redis 的键值对读写操作应用采纳了单线程模式,那么它的其余线程是是什么样的呢?

主过程的其它线程

Redis 3.0 版本后,主过程中除了主线程解决网络 IO 和命令操作外,还有 3 个辅助 BIO 线程。这 3 个 BIO 线程别离负责解决,文件敞开、AOF 缓冲数据刷新到磁盘,以及清理对象这三个工作队列,从而防止这些工作对主 IO 线程的影响。

Redis 在启动时,会同时启动这三个 BIO 线程,然而 BIO 线程只有在须要执行相干类型后台任务时才会唤醒,其余工夫会休眠期待工作。

多过程

除了主过程,在以下场景如果须要进行重负荷工作的解决,Redis 会 fork 一个子过程来解决:

  • 收到 bgrewriteaof 命令: Redis fork 一个子过程,而后子过程往长期 AOF 文件中写入重建数据库状态的所有命令。写入结束后,子过程会告诉父过程把新增的写操作追加到长期 AOF 文件。最初将临时文件替换旧的 AOF 文件,并重命名。
  • 收到 bgsave 命令: Redis 构建子过程,子过程将内存中的所有数据通过快照做一次长久化落地,写入到 RDB 中。
  • 当须要进行全量复制: master 启动一个子过程,子过程将数据库快照保留到 RDB 文件。在写完 RDB 快照文件后,master 会把 RDB 发给 slave,同时将后续新的写指令都同步给 slave。

Redis6.0 多线程

多线程是 Redis6.0 推出的一个新个性。正如下面所说 Redis 是外围线程负责网络 IO,命令解决以及写数据到缓冲,而随着网络硬件的性能晋升,单个主线程解决⽹络申请的速度跟不上底层⽹络硬件的速度,导致网络 IO 的解决成为了 Redis 的性能瓶颈。

而 Redis6.0 就是从单线程解决网络申请到多线程解决,通过多个 IO 线程并⾏解决网络操作晋升实例的整体解决性能。须要留神的是对于读写命令,Redis 依然使⽤单线程来解决,这是因为持续使⽤单线程执行命令操作,就不⽤为了保障 Lua 脚本、事务的原⼦性,额定开发多线程互斥机制了。

须要留神的是在 Redis6.0 中,多线程机制默认是敞开的,须要在 redis.conf 中实现以下两个设置能力启用多线程。

  • 设置 io-thread-do-reads 配置项为 yes,示意启用多线程。
io-threads-do-reads yes
  • 设置线程个数。⼀般来说, 线程个数要小于 Redis 实例所在机器的 CPU 核数, 例如,对于⼀个 8 核的机器来说,Redis 官⽅倡议配置 6 个 IO 线程。
io-threads 6

多线程流程

来具体看一下在 Redis6.0 中,主线程和 IO 线程是如何合作实现申请解决的。

全副流程分为以下 4 阶段:

阶段一:服务端和客⼾端建设 Socket 连贯,并调配解决线程

当有客⼾端申请和实例建设 Socket 连贯时,主线程会创立和客户端的连贯,并把 Socket 放入全局期待队列中。而后主线程通过轮询办法把 Socket 连贯调配给 IO 线程。

阶段二:IO 线程读取并解析申请

主线程把 Socket 调配给 IO 线程后,会进⼊阻塞状态期待 IO 线程实现客户端申请读取和解析。

阶段三:主线程执⾏申请操作

IO 线程解析完申请后,主线程以单线程的⽅式执⾏这些命令操作。

阶段四:IO 线程回写 Socket 和主线程清空全局队

主线程执行完申请操作后,会把须要返回的后果写入缓冲区。而后,主线程会阻塞期待 IO 线程把这些后果回写到 Socket 中,并返回给客户端。等到 IO 线程回写 Socket 结束,主线程会清空全局队列,期待客户端的后续申请。

总结

看完了这篇文章,置信大家对 Redis 是单线程的说法曾经有了大抵概念。咱们说它是单线程,次要是因为在以前的版本中网络 IO 和键值对读写是由⼀个线程来实现的。而之所以说 Redis 是多线程,则是因为 Redis6.0 当前的版本里,网络 IO 的局部变为了多线程解决。而且除了主线程,还有 3 个辅助 BIO 线程,别离是 fsync 线程、close 线程、清理回收线程。当然不能遗记的是,想要体验多线程机制,就得通过批改配置文件开启多线程性能。

举荐浏览

原创内容每每被盗?从源头对资源盗用说 NO

严重危害正告!Log4j 执行破绽被公开!

正文完
 0