Redis的单线程架构

前言

在一定的策略下适度地初始化线程池的线程数有利于提高CPU的利用率,达到高效率地在同一段时间内处理多个任务,最佳的线程数量一般是

最佳线程数=(线程等待的时间与线程CPU执行时间之比+1)*CPU核数

像笔者电脑电脑的CPU为8核,假设DB操作、RPC操作、缓存操作等为900毫秒,CPU运行时间为100毫秒,那么以此公式要达到CPU利用率最高,合适的线程数应该为80个。

是不是线程数越多越好呢?

答案肯定是否定的,大名鼎鼎的redis就是单线程的,但它却非常地高效,基本操作都能达到十万量级每秒。

单线程的redis性能为何如此之高?

这段内容部分参考了《Redis开发与运维》,这本书笔者认为十分地实用,有兴趣的话可以买来一睹作者的妙笔。

一般来说单线程相较于多线程的处理能力要差,相当于吃麦麦,假设我是hx,在我面前有100个麦麦脆汁鸡,单线程就是要我自己一个人去消灭眼前的食物,多线程则是有多个hx去消灭麦麦脆汁鸡,其效率肯定是多线程的要高。redis使用单线程却能够达到每秒万级的处理能力主要归结于以下几点。

1.redis是纯内存访问,redis将所有的数据都放在内存中,内存的响应时间在100纳秒之内,它是redis达到每秒万级别访问的重要基础。

它不同于mysql这种关系型数据库的点在于,mysql在读写数据时都属于I/O操作,有学过计算机组成原理的都知道I/O设备和CPU之间的处理速度有着量级的差距,在早期CPU处理现行程序时,运行到I/O操作,往往需要中断现行程序,等待I/O操作完成,这使得CPU的利用率非常地低,到现在虽然有着I/O处理机的技术,但是与CPU相比还是天差地别。

虽然mysql支持多线程访问,在分库、分表以及优化sql语句的前提下,I/O操作带来的延迟依旧不可忽视,同时若不为sql语句上表级锁,行级锁在多线程条件下又会出现脏读,不可重复读,幻读等问题,上了锁,又会带来性能的下降。

相反,redis基于内存的、单线程的模式就不会有上诉的问题。
2. 单线程避免了线程切换和竞态产生的消耗。

现如今的操作系统都是抢占式的调度,多线程会使得CPU频繁地进行任务的切换,CPU执行任务的效率也就会降低,这也是在开发过程中,为什么要按照一定的策略来初始化线程池的线程数,对于服务端开发来说,锁和线程切换通常是性能杀手。
3. Redis采用了非阻塞的I/O,Redis使用epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接,读写,关闭都转换为事件,不在网络I/O上浪费过多的时间,这点又与mysql这种非关系型数据库不同。

什么是I/O多路复用技术?

多路指的是网络连接,复用指的是一个线程

  • I/O 多路复用是一种同步I/O,实现一个线程可以监视多个文件句柄
  • 一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作
  • 没有文件句柄就绪就会阻塞应用程序,交出CPU

有关epoll的技术笔者能力有限,详情请看:https://juejin.cn/post/6882984260672847879

具体点就是:

用epoll技术创建多个网络连接到redis的单线程中,线程监控网络连接的活跃状态,一旦检测到便通知应用程序进行相应的读写操作,这里得益于epoll事件驱动的特点,网络连接多少是不限制的,线程检测到活跃的时间复杂度永远是O(1)。

结尾

每个数据库都有优缺点,mysql数据库有上述的缺点,它也有对现实关系抽象的优点。Redis有上述的优点,但它也怕命令执行过长而导致Redis服务端阻塞的缺点。非关系型数据库有其优缺点,关系型数据库有其优缺点,每个数据库的特点都还不一样,只能说是选择适合自己业务的数据库来使用。

在高并发开发,笔者更喜欢用Redis辅助mysql数据库,这里就涉及到Redis远程客户端操作服务端的技术了,在本篇不过多叙述。

posted @ 2021-10-04 14:39  蜡笔小新不吃青椒  阅读(140)  评论(0编辑  收藏  举报
Live2D