redis:一个非关系型键值对数据库,我们用它缓存和获取数据时,知道速度很快。当知道redis使用的是单线程后,不免有个疑问,为什么单线程还能那么快?
首先,厘清一个事实,Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。
多线程的优缺点
优点:
1,资源利用率更高(能更加充分的使用cpu资源)
2,程序响应更快 (多个线程可以并行,无需等待上个任务执行结束)
所以:对于一个多线程的系统来说,在有合理的资源分配的情况下,可以增加系统中处理请求操作的资源实体,进而提升系统能够同时处理的请求数,即吞吐率。
缺点:
1:设计有时会更复杂;
2:上下文切换的开销;
3:增加资源消耗:
线程在运行的时候,需要从计算机里得到一些资源,除了CPU,线程还需要一些内存来维持它本地的堆栈,还需要占用操作系统中的一些资源来管理线程。
4:线程的死锁:较长时间等待或资源竞争以及死锁等多线程症状。
5:共享资源的并发访问控制问题
回到问题本身,redis快的答案无非两点:完全基于内存,IO多路复用
为什么Redis使用IO多路复用而不是Socket 编程模型
Socket 模型实现网络通信时的步骤
1:调用 socket 函数,创建一个套接字。我们通常把这个套接字称为主动套接字(Active Socket);
2:调用 bind 函数,将主动套接字和当前服务器的 IP 和监听端口进行绑定;
3:调用 listen 函数,将主动套接字转换为监听套接字,开始监听客户端的连接;
由于Redis 的主执行流程是由一个线程在执行,使用基本的 Socket 编程模型的话,只能对一个监听套接字或一个已连接套接字进行监听。这种处理方式的效率比较低
IO多路复用:一个服务端进程可以同时处理多个套接字描述符
其发展可以分select->poll->epoll三个阶段来描述。
select就是轮询遍历每个文件描述符,检测该描述符是否就绪,然后再进行处理,在Linux上限制个数一般为1024个;
poll解决了select1024个的限制
epoll解决了个数的限制也解决了轮询的方式
redis epoll 单线程
epoll不是只有单线程一种实现方式,Memcached采用了多线程,Nginx采用了多进程
文件事件是对套接字操作的抽象,每当一个套接字准备好执行连接应答、写入、读取、关闭等操作时,就会产生一个文件事件。因为一个服务器通常会连接多个套接字,所以多个文件事件有可能会并发地出现。
Redis6.0为什么要引入多线程呢
Redis将所有数据放在内存中,内存的响应时长大约为100纳秒,对于小数据包,Redis服务器可以处理80,000到100,000 QPS,这也是Redis处理的极限了,对于80%的公司来说,单线程的Redis已经足够使用了。
但随着越来越复杂的业务场景,有些公司动不动就上亿的交易量,因此需要更大的QPS。常见的解决方案是在分布式架构中对数据进行分区并采用多个服务器,但该方案有非常大的缺点,例如要管理的Redis服务器太多,维护代价大;某些适用于单个Redis服务器的命令不适用于数据分区;数据分区无法解决热点读/写问题;数据偏斜,重新分配和放大/缩小变得更加复杂等等。
所以总结起来,redis支持多线程主要就是两个原因:
1,可以充分利用服务器 CPU 资源,目前主线程只能利用一个核
2,多线程任务可以分摊 Redis 同步 IO 读写负荷
网友评论