纯内存KV操作
- redis的操作都是在内存实现的,众所周知,在计算机的世界中,CPU的速度是远大于内存的速度的,同时内存的速度也是远大于硬盘的速度, 所以非常快.所以内存的大小对于redis至关重要,其次是cpu
整体流程
- 服务启动,开始网络端口监听,等待客户端请求
- 客户端想服务端发起连接请求,创建客户端连接对象,完成连接
- 将socket信息注册到epoll,设置超时时间为时间事件的周期时长,等待客户端发起请求
- 客户端发起操作数据库请求(如GET)
- epoll收到客户端的请求,可能多个,按照顺序处理请求
- 接收请求参数,接收完成后解析请求协议,得到请求命令
- 执行请求命令,即操作redis数据库
- 将结果返回给客户端
事件分类
- 文件事件:主要是网络I/O的读写,请求的接收和回复
- 时间事件:单次/多次执行的定时器,如主从复制、定时删除过期数据、字典rehash等
单线程优势
- 使用单线程可以省去多线程时CPU上下文会切换的时间,也不用去考虑各种锁的问题,不存在加锁释放锁操作,没有死锁问题导致的性能消耗。对于内存系统来说,多次读写都是在一个CPU上,没有上下文切换效率就是最高的!既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章的采用单线程的方案
- redis分为不同的阶段,部分阶段应对客户端请求 or 后台处理 是多线程设计(随着版本迭代扩展),而处理DB命令一定是单线程的,通过两者结合保证了高效运转
多线程版本演化
3.0
- 在执行BGSAVE和BGREWRITEAOF这两条命令时,就会fork一个子进程进行RDB后台持久化和AOF的后台重写。
4.0
- Redis 在 v4.0 版本的时候就已经引入了的多线程来做一些异步操作,此举主要针对的是那些非常耗时的命令,通过将这些命令的执行进行异步化,避免阻塞单线程的事件循环 增加了一些的非阻塞命令如 UNLINK、FLUSHALL ASYNC、FLUSHDB ASYNC,针对的是后台异步操作
6.0
- Redis 6.0之后,Redis 正式在核心网络模型中引入了多线程,也就是所谓的 I/O threading,至此 Redis 真正拥有了多线程模型.针对程序请求实现了多线程
从上图中可以看出只有以下3个地方用的是多线程,其他地方都是单线程:
- 接收请求参数
- 解析请求参数
- 请求响应,即将结果返回给client
很明显以上3点各个请求都是互相独立互不影响的,很适合用多线程
总结
在保证db操作单线程的情况下,让Redis发挥CPU一部分多核多线程的实力。我们不难发现,Redis 的多线程不过是顺势而为罢了,如果单线程没有瓶颈,就不会产生使用多线程的Redis。再结合现状来看,毕竟时代变了,从多年前的单核服务器,到后来的双核,四核服务器,再到现在动辄八核,十六核的服务器: 单线程模型固然简单,代码清晰,但是在摩尔定律失效,多核多线程的时代洪流下,有谁能够拒绝多线程的好处呢?