前言

我们都知道Redis很快,我们还总是听别人说Redis是单线程的,那么单线程的Redis为什么那么快呢?

1. Redis单线程的本质

其实,Redis并不是单线程,我们之所以会一直称Redis是单线程,这是因为Redis在处理客户端的读写请求时,只有一个主线程,而在处理以下这些操作时,Redis会fork出其他的子线程来处理:

  • 主从数据同步

  • 切片集群数据同步

  • 过期键值异步删除

  • AOF或RDB持久化

所以整体来看Redis并不是单线程。

在Redis6.0中引入的多线程机制,实际上只是将网络IO读写处理这块逻辑变成多线程,因为在Redis6.0以前的版本中, 网络IO请求也是在主线程中进行处理,随着互联网应用的高并发访问以及网络硬件性能的提升,在主线程中进行网络IO处理已经成为Redis的瓶颈,因此使用多线程来处理网络IO请求,可以显示提高Redis响应速度,而对于键值对的读写,仍然由主线程一个线程进行处理,这样可以仍然可以不用加锁也能保证读写操作的原子性,避免多线程互斥机制带来的性能损耗。

2. 单线程为什么那么快?

通过前面的介绍,我们知道,Redis并非完全是单线程,但在处理网络IO和数据读写等Redis核心功能时,Redis确实是由主线程处理的,那么我们就不禁有个疑问,Redis的单线程为什么那么快呢?

总结了以下大概有以下四个方面的原因:

  • 内存操作

  • 高效的底层数据结构

  • 多路复用IO模型

  • 避免多线程切换开销

2.1 内存操作

Redis是内存数据库,读写操作都在内存中,学过计算机基础的我们都知道,CPU读取内存的速度要比读取磁盘的速度快得多,所以单台Redis服务器每秒能处理数十万的读取也就不足为怪了,事实上,基于内存的读写操作,是Redis能这么快的最重要的原因。

2.2 高效的底层数据结构

我们都知道Redis提供了五种非常好用的数据类型:String,List,Hash,Set,Sorted Set。

Redis有六种底层数据结构,分别为哈希表,压缩列表,跳表,整数数组,简单动态字符串。

数据类型与其底层数据结构对应关系如下图所示

总结来说就是:

  • String:Redis没有使用C语言内置的字符数组,而是将字符数组封装为简单动态字符串(SDS),虽然SDS比C语言原生字符数组更费内存,但通过空间换时间,可以将很多C语言字符数组时间复杂度为O(n)的操作转为O(1),提高处理速度,比如strlen命令获取String长度时,对于C语言的字符数组,需要遍历数组才能知道,时间复杂度为O(n),而简单动态字符串已经保存了字符串的长度,因此可以直接获取,时间复杂度为O(1)。

  • Hash:在数据量还不多的情况下,Hash类型使用压缩列表(ZipList)保存元素,因为元素不多,所以查找也比较快,如果数据增长到设定的值,就改为哈希表,而哈希表查找元素的时间复杂度为O(1),所以也是相当快的。

  • List:List的底层数据结构为双向链表和压缩列表组合而成的,也称为快速链表(QuickList),因此List类型非常适合头尾插入弹出的操作,因此如果要把Redis作为队列的话,选择List是非常高效的。

  • Sorted Set:当元素数量不多时,Sorted Set使用的是压缩列表,只有当元素超过设定值时,才使用跳表和哈希表。

  • Set:在元素的数值都是整数时,Set使用整数数组保存数据,如果元素数量达到设置的值,则改为哈希表。

Redis是一个Key-Value健值对数据库,我们上面介绍的五种类型是指Key-Value中的Value,对于所有Key到Value之间的映射,Redis也是采用哈希表,这个哈希表也叫全局哈希表,如下图所示:

2.3 多路复用IO模型

Redis高性能的另一个重要的原因是采用多路复用IO模型,由于Redis是单线程处理网络请求的,如果采用阻塞IO模型,那么对于每一个请求,Redis需要从接收连接->读取连接数据->处理命令->返回数据整个流程处理完成后才能处理处理下一个请求,如果是这样的话,那么Redis的快就无从谈起了。

而采用非阻塞模型IO,虽然可以避免阻塞,但这种模型会在内核空间与用户空间来回复制全部要监听的FD(文件描述符),除了之外,我们还无法得知哪个FD已经就绪了,需要遍历所有的FD才能知道,同样是即费空间又费时间,因此对于需要支持高并发的Redis来说,显然也是不可接受的。

而多路复用IO模型则不同了,多路复用IO模型同样也是非阻塞的,其内置的红黑树可以高效地添加或查找FD,且只会将已经就绪的的FD从内核空间复制到用户空间,因此很多网络应用处理请求时都是使用多路复用IO模型,Redis也不例外。

多路复用IO模型在不同的操作系统有不同的实现,如selec和poll,还有更性能更好的epoll,Redis不同操作系统的多路复用IO模型都有封装。

2.4 避免多线程切换

因为将数据保存在内存中,并且有高效的数据结构和使用多路利用IO模型,所以Redis读取数据非常快速,这时候,你可能会想,是不是将Redis改为多线程,可以更好提升Redis的吞吐量,处理更多并发请求呢?

其实不然,正因为Redis读取非常快,所以如果采用多线程的话,会产生以下两个问题:

  • 多线程切换带来的额外开销:因为Redis读写非常快速,因为如果采用多线程,那么线程切换就非常频繁,所以如果采用多线程的话,Redis大部分时间可能都在切换线程。

  • 数据加锁的性能损耗:多线程访问同一个数据的话,为了避免竞争,肯定需要加锁保证数据操作的原子性,而加锁与等待锁的释放,让多个线程在读取同一个数据需要排队等待,所以效率并不比单线程强多少。

3 怎么让Redis更快

单台Redis服务器,已经非常快了,那么,有什么办法能让Redis更快呢?

  • 使用AOF或RDB数据备份:有了数据备份,可以在服务器宕机时,更快地恢复

  • 主从分离:让从服务器分担主服务器的压力,实现更快地响应

  • 切片集群:除了主从,切片集群让数据分散到不同服务器,多台服务器可分担读写的压力

  • 避免bigkey:bigkey是指键值过大或者集合元素过多,占用太多的带宽与CPU运算,导致主线程阻塞,所以要避免在Redis存储比较大的值,比如对于value来说,不要超过10KB,对于集合元素,元素的数量最好不要超过1000

4 小结

从上面的分析我们可以看,Redis并不是像我们认为的是单线程,在处理持久化等耗时任务时,Redis也是采用多线程的处理方式,不过,Redis在处理请求时只有一个主线程,但仍然做非常快速的响应,这是由于Redis的数据读写都在内存中,而内存的访问是非常快速的,另外Redis为每一种数据类型都精心设计了高效的底层数据结构,而在处理网络请求时,则采用基于多路复用的IO模型,使得Redis可以高并地处理更多的请求。

浅谈单线程的Redis快的原因是什么相关推荐

  1. Redis快的原因:内存操作 单线程没有切换开销 多路复用IO

    Redis 完全基于内存,绝大部分请求是纯粹的内存操作,非常迅速,数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度是 O(1). 采用单线程,避免了不必要的上下 ...

  2. 得物技术浅谈深入浅出的Redis分布式锁

    一.什么是分布式锁 1.1 分布式锁介绍 分布式锁是控制不同系统之间访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来保证一致性. 1.2 ...

  3. Redis快的原因:线程切换 IO 内存 数据结构 VM机制

    1采用单线程,避免了不必要的上下文切换 2使用多路I/O复用模型,非阻塞IO: 3完全基于内存 4数据结构简单,对数据操作也简单 5Redis直接自己构建了VM 机制

  4. 浅谈开关电源MOS管发热的原因

    MOS管是FET的一种,可制造成增强型或耗尽型,有P型或N型,无论是那种,其工作原理本质都是一样的.MOS管种类和作用众多,在电源的使用中主要用到其开关作用. MOS管常加在输入端栅极的电压来控制输出 ...

  5. 浅谈IP分片的大小及其原因

    一.IP分片的定义 IP分片是网络上传输IP报文的一种技术手段.IP协议在传输数据包时,将数据报文分为若干分片进行传输,并在目标系统中进行重组,这一过程称为分片. 二.进行IP分片的原因 数据链路层具 ...

  6. 印度金融产品谷歌上架问题浅谈-内含常见google下架封号原因

    Google Play作为东南亚.南亚出海必上的商店,如何上架,如何提高自己应用在Google Play的排名是甲乙方关心的问题. 但是伴随着Google Play优化,应用被下架是个头疼的问题,下架 ...

  7. redis线程阻塞原因排插_每次面试都要被问:为什么采用单线程的Redis也会如此之快?...

    众所周知,Redis在内存库数据库领域非常地火热,它极高的性能和丰富的数据结构为我们的开发提供了极大的便利. 但我们也听说了,Redis是单线程的,为什么采用单线程的Redis也会如此之快呢?这篇文章 ...

  8. Redis设计与实现 -- 浅谈Redis持久化

    在讲解Redis持久化相关的话题之前,我们需要了解的是Redis为什么这么快?也就是Redis的IO模型 – 多路复用. 我们一句话概括为什么Redis这么快: Redis是单线程的,使用多路复用的I ...

  9. 四、redis比mysql快的原因

    redis比mysql快的原因 Mysql数据存储是存储在表中,查找数据时要先对表进行全局扫描或者根据索引查找,这涉及到磁盘的查找,磁盘查找如果是按条点查找可能会快点,但是顺序查找就比较慢: 而Red ...

最新文章

  1. 笔记-计算机网络基础-网络存储技术
  2. Siebel Issue:Siebel菜单栏无法在IE7/8下展开问题解决方案
  3. python下电影_Python3.6实现根据电影名称(支持电视剧名称),获取下载链接的方法...
  4. matlab没有pso工具箱,MATLAB-PSO工具箱
  5. 上市公司与不上市公司的区别
  6. 割线法求解过程_浸入边界法求解流固耦合问题
  7. 关于调用Thread.sleep() 哪条线程休眠问题
  8. 二级C语言考试环境注意事项
  9. 2014手游渠道分成比例汇总
  10. 凭什么软件测试入门就有一万+工资,为什么?我不相信。
  11. 获取指定年月的月初跟月末的时间戳
  12. open3d画3D矩形框
  13. 新手学习 python 的好工具:PyScripter
  14. 2020金融科技领域最具商业合作价值企业盘点
  15. SQL in 模糊查询的问题
  16. [异常检测]Learning Regularity in Skeleton Trajectories for Anomaly Detection in Videos
  17. python12306源码_春运了,Python大神分享爬取12306车票信息的例子,附抢票源码
  18. QT 绘图工具-QCustomPlot
  19. Android之指纹解锁
  20. 腾讯开源的标星 12k 的力作

热门文章

  1. seo是什么,seo是什么职位缩写
  2. 关于 vue项目 中实现导入Excel表 + 预览生成的Excel
  3. Web前端开发:HTML、CSS
  4. 留言板(php+数据库)
  5. Viola-Jones检测器(VJ)---学习笔记
  6. 计算机视觉学习6_棋盘格_相机模型与参数标定
  7. 【分享Oracle练习二】
  8. 单条视频播放量破2000w,一首《孤勇者》就能盘活一个账号?
  9. 《世界棒球》:日本职棒
  10. 如何抓取BT天堂电影数据