Redis为什么这么快

QA:Redis到底有多快?

使用redis自带的benchmark脚本测试:

cd /usr/local/soft/redis-6.0.9/src
redis-benchmark -t set,lpush -n 100000 -q

结果:
SET: 136239.78 requests per second 每秒钟处理 13 万多次 set 请求
LPUSH: 132626.00 requests per second 每秒钟处理 13 万多次 Ipush 请求

redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"

结果:

script load redis.call('set','foo','bar'): 125628.14 requests per second---每秒钟125628.14次lua脚本调用

从测试结果上看,说明Redis的QPS 10万还是比较准确的,在高性能的服务器上性能还能更强。

Redis为什么这么快原理

总结起来主要是三点:
1、 纯内存结构
2、 请求处理单线程
3、 多路复用机制

内存

  KV结构的内存数据库,时间复杂度O(1)。
  第二个,按照正常的思路来讲,要实现这么高的并发性能,是不是要创建非常多的线程?为什么我们说Redis是单线程的呢?这个单线程说的到底是什么?

单线程

  这里说的单线程其实指的是处理客户端的请求是单线程的,可以把它叫做主线程。
  从4.0的版本之后,还引入了一些线程处理其他的事情,比如清理脏数据、无用连接的释放、大key的删除。

把处理请求的主线程设置成单线程有什么好处呢?

1、 没有创建线程、销毁线程带来的消耗
2、 避免了上线文切换导致的CPU消耗
3、 避免了线程之间带来的竞争问题,例如加锁释放锁死锁等等

那么这里有一个问题,就算单线程确实有你说的这些好处,但是会不会白白浪费了 CPU 的资源吗?也就是说只能用到单核。

官方的解释是这样的:
在Redis中单线程已经够用了,CPU不是redis的瓶颈。Redis的瓶颈最有可能是机器内存或者网络带宽。既然单线程容易实现,又不需要处理线程并发的问题,那就顺理成章地采用单线程的方案了。

  注意,因为请求处理是单线程的,不要在生产环境运行长命令,比如keys, flushall, flushdb。否则会导致请求被阻塞。

同步非阻塞I/O

同步非阻塞I/O,多路复用处理并发连接——什么是多路复用?

单线程为什么这么快?

因为Redis是基于内存的操作。

虚拟存储器(虚拟内存Virtual Memory)

计算机里面的内存我们叫做主存,硬盘叫做辅存。
主存可看作一个很长的数组,一个字节一个单元,每个字节有一个唯一的地址,这个地址叫做物理地址(Physical Address)。

早期的计算机中,如果CPU需要内存,使用物理寻址,直接访问主存储器。

但是这种方式有几个弊端:
1、一般的操作系统都是多用户多任务的,所有的进程共享主存。如果每个进程都独占一块物理地址空间主存很快就会被用完。我们希望在不同的时刻,不同的进程可以共用同一块物理地址空间。
2、如果所有进程都是直接访问物理内存,那么一个进程就可以修改其他进程的内存数据,导致物理地址空间被破坏,程序运行就会出现异常。
咋办呢?对于物理内存的使用,应该有一个角色来协调和指挥。
我们想了一个办法,在CPU和主存之间增加一个中间层。CPU不再使用物理地址访问主存,而是访问一个虚拟地址,由这个中间层把地址转换成物理地址,最终获得数据。 这个中间层叫做MMU (Memory Management Unit),内存管理单元。

我们访问MMU就跟访问物理内存一样,所以把虚拟出来的地址叫做虚拟内存(Virtual Memory)。在每一个进程开始创建的时候,都会分配一段虚拟地址,然后通过虚拟地址和物理地址的映射来获取真实数据,这样进程就不会直接接触到物理地址,甚至不知道自己调用的哪块物理地址的数据。
目前,大多数操作系统都使用了虚拟内存,如Windows系统的虚拟内存、Linux系统的交换空间等等。Windows的虚拟内存(pagefile.sys)是磁盘空间的一部分。
在32位的系统上,虚拟地址空间大小是232=4G。在64位系统上,最大虚拟地址空间大小是多少?是不是264=1024*1024TB?实际上没有用到64位,因为用不到这么大的空间,而且会造成很大的系统开销。Linux—般用低48位来表示虚拟地址空间, 也就是2^48=256T。

cat /proc/cpuinfo
# address sizes : 43 bits physical, 48 bits virtual

实际的物理内存可能远远小于虚拟内存的大小。
总结:引入虚拟内存的作用:
1、通过把同一块物理内存映射到不同的虚拟地址空间实现内存共享
2、对物理内存进行隔离,不同的进程操作互不影响
3、虚拟内存可以提供更大的地址空间,并且地址空间是连续的,使得程序编写、链接更加简单。
Linux/GNU的虚拟内存又进一步划分成了两块:

多路复用原理

总结

Redis抽象了一套AE事件模型,将IO事件和时间事件融入一起,同时借助多路复用机制的回调特性(Linux上用epoll),使得IO读写都是非阻塞的,实现高性能的网络处理能力。
我们一直在说的Redis新版本多线程的特性,意思并不是服务端接收客户端请求变成多线程的了,它还是单线程的。
严格意义上来说,Redis从4.0之后就引入了多线程用来处理一些耗时长的工作和后台工作,那不然的话,如果真的只有一个线程,那些耗时的操作肯定会导致客户端请求被阻塞。我们这里说的多线程,确切地说,叫做多线程I/O。

为什么要用多线程来处理I/O呢?

多线程I/O

服务端的数据返回给客户端,需要从内核空间copy数据到用户空间,然后回写到 socket (write调用),这个过程是非常耗时的。所以多线程I/O指的就是把结果写到socket的这个环节是多线程的。处理请求依然是单线程的,所以不存在线程并发安全问题。

posted @   snail灬  阅读(58)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示