Redis到底是多线程还是单线程?线程安全吗
总结:
redis是单线程,线程安全
redis可以能够快速执行的原因:
(1) 在绝大多数情况下, 请求仅涉及内存操作且运行高效
(2) 该系统采用了单线程设计以减少不必要的上下文切换和竞争条件
(3) 该系统使用了无阻塞输入输出技术, 并采用了多路复用机制以提高吞吐量
IO多路复用中包括三种方式:select, poll, epoll. 需要注意的是, select和poll这两种机制存在潜在的安全问题, 而epoll则是完全可靠的.
基于epoll构建了一个简单的事件驱动框架。这个框架将读、写、关闭以及连接操作都被转化为一系列事件,并通过epoll的多路复用特性实现了高效的资源利用。值得注意的是,在这个设计中,并非所有的条件都是完全独立的。其中三个条件并非完全独立,特别是当处理的任务都是耗时操作时(当处理的任务都是耗时操作时),系统的吞吐量将显著下降)。由此可见,在特定场景下,redis选择了最适合的技术架构。
原文:
0. redis单线程问题
The single-threaded model represents a network request module that utilizes a single thread (thereby enabling the elimination of concurrency safety considerations), implying that a single thread handles all network requests, while other modules continue to employ multiple threads.
1. 为什么说redis能够快速执行
(1) 绝大部分请求是纯粹的内存操作(非常快速)
(2) 采用单线程,避免了不必要的上下文切换和竞争条件
(3) 非阻塞IO - IO多路复用
2. redis的内部实现
内部采用了 epoll 以及自定义的简单事件框架。通过 epoll 的机制将读、写、断开连接等操作转化为特定事件,并充分利用 epoll 的多路复用特性。确保在进行 i/o 操作时不会有任何等待现象发生。这三条条件并非完全独立存在;尤其是第一条条件更为关键,在特殊场景下 redis 选择了最适合的技术架构来满足需求
3. Redis关于线程安全问题
Redis采用了一种线程封闭的理念,在每个Redis实例内部将任务封装到一个独立的线程中;这种设计自然地实现了对线程安全问题的有效防护。然而,在某些情况下(例如涉及多个Redis操作的复合操作),仍然会使用普通的锁机制;如果涉及复杂的操作链,则可能需要分布式锁机制。
4. IO多路复用
要弄清问题先要知道问题的出现原因
原因:
因为进程的执行流程呈线性特征(即按顺序依次处理),因此当调用低效系统I/O操作(如读取、写入以及接受等)时,可能会导致进程在此处长时间停滞;此时该进程因此被此操作所阻塞而暂时无法进行其他活动;这种现象很常见。
下面将讨论的一个问题是:两个进程之间的通信关系中存在一定的挑战性。具体而言,在服务器端执行读取操作:read(sockfd1, buf, bufsize)时,在客户端未发送数据的情况下(即读取操作为阻塞调用),该操作会等待直至直到客户端执行写入操作:write(sockfd, outbuf, size) 发送相应的数据为止。这样的场景在客户-服务器通信中通常不会引起问题。
在多个客户端与服务器进行通信的过程中,在一个客户端sockfd1的读操作被阻塞后,在另一个客户端的数据到达另一套接字sockfd2时,在该读操作(read(sockfd1,...))上仍无法继续执行;此时就会出现服务无法及时响应第二个客户端的问题。
I/O多路复用来解决!
I/O多路复用:
继续前面的问题,在这里我们考虑存在多个客户端连接( sockfd1、sockfd2、sockfd3……sockfdn) 同时监听这些客户端。一旦其中一个客户端发送数据时就会立即离开 select 的阻塞状态,并随后会调用 read 方法以获取接收到的消息内容。接着系统会再次进入 select 阻塞等待模式进行数据处理循环;这种设计的好处在于即使其中一个客户端被阻塞无法及时处理当前的数据请求也不会影响到其他客户端的数据接收能力。


Q:
在尝试读取 socket1 的数据时,在其他 socket 接收到数据之前,请确保完成对 socket1 的读取操作以避免阻塞问题。此外,在获取数据后也需要启动相应的线程处理逻辑。这样的机制与多线程 IO 模式有何不同?
A:
1.CPU本来就是线性的不论什么都需要顺序处理并行只能是多核CPU
其本质是旨在解决多个数据流的同步访问问题,在处理单个数据流阻塞时可能会影响整个系统的响应时间,并与多线程机制没有关联。
相较于多线程模式而言,在进行线程切换时需要进入内核系统进行操作,并会带来时间与资源上的消耗。另一方面,I/O多路复用技术无需切换进程,运行效率显著提升,尤其是针对高并发场景表现出色. nginx正是采用这种技术架构 ,因此其性能表现优异.不过在编程逻辑和实现细节上相比而言更为简便,I/O多路复用由于其复杂的内部实现而显得更加繁琐.
5. 使用Redis有哪些好处?
(1) 运行效率高是因为数据以内存形式存储,在这种情况下类似于使用HashMap。与类似的数据结构如HashMap相比,在查询和操作方面都具备最优的时效性能特征。该算法的时间复杂度具有常数阶特性,并且通过优化实现了高效的查找和更新操作。
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash
(3) 采用事务机制进行操作,在该机制下所有的数据修改均具有原子性特征。即该机制的特点在于每次修改要么能够完整无误地被保存到数据库中、要么整个修改过程完全无效。
(4) 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除
6. Redis相比memcached有哪些优势?
memcached的所有值都是基本类型的字符串;而Redis作为一个替代方案,则支持包括更多数据类型的存储。
(2) redis的速度比memcached快很多
(3) redis可以持久化其数据
(4)Redis支持数据的备份,即master-slave模式的数据备份。
(5) 基于不同的底层模型,在这些应用中它们之间的底层实现方式以及与客户端之间的通信应用协议各不相同。Redis直接实现了虚拟机机制,并且这种设计选择是基于常规的系统调用流程进行操作的话。
(6)value大小:redis最大可以达到1GB,而memcache只有1MB
7. Redis常见性能问题和解决方案:
(1) Master应避免进行任何持久化操作,包括但不限于RDB内存快照操作和AOF日志文件生成。( save命令会导致rdbSave函数被调用,从而导致主线程被阻塞,特别是当内存快照较大时会对系统的性能产生显著的影响;此外,AOF文件过大可能会影响主节点在重启时的恢复速度)
当数据的重要性较高时,一个_SLAVE_实例开启AOF备份数据,并将同步策略配置为每隔一秒执行一次同步操作.
主要针对主从复制效率及网络连接稳定性的要求, Master和Slave最好是同属一个局域网环境.
(4) 尽量避免在压力很大的主库上增加从库
(5) 在主从复制过程中应避免采用图状结构, 建议采用单向链表结构以确保系统稳定性. 具体而言, 这样的架构设计能够有效规避单一节点失效的风险. 通过这种架构设计, 我们可以使Slave能够替代并接管Master角色. 这种架构设计不仅有助于提升系统的可靠性, 而且在发生Node失效时, 可以立即切换为Slave1承担起 Master 的职责, 而不会影响其他Node的功能.
8. Redis的回收策略
volatile-lru:在设置了过期时间的数据库表中(server.db[i].expires),选择移除最久未被使用的数据进行移除操作。
volatile-ttl:从包含有到期时间数据集(server.db[i].expires)中筛选即将到期的数据并将其移除
基于时间的不可预测机制:当设置有到期时间时,在(server.db[i].expires)中随机抽取并删除相关数据。
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
请关注当前提到的6种机制。这些关键字决定了它们是针对那些已经设置了过期时间的数据集合进行淘汰还是从所有数据集中进行淘汰。随后的lru、ttl以及random代表了三种不同的淘汰策略。另外还有一种永远不会被回收的策略。
使用策略规则:
- 当数据呈现幂律分布特征时(即一部分数据具有显著的高频访问特性而另一部分则呈现出相对较低频的访问特性),建议采用allkeys-lru策略
如果数据呈现均匀分布,则建议采用allkeys-random方法。
9. 五种I/O模型介绍
IO 多路复用是5种I/O模型中的第3种,对各种模型讲个故事,描述下区别:
故事的主要情节包括老李前往购买火车票,在三天后成功获得一张退票。参与人员包括老李、黄牛、售票员以及快递员;往返于火车站之间共用时1小时。
1.阻塞I/O模型
老李去火车站买票,排队三天买到一张退票。
耗费:在车站吃喝拉撒睡 3天,其他事一件没干。
2.非阻塞I/O模型
老李去火车站买票,隔12小时去火车站问有没有退票,三天后买到一张票。
耗费:往返车站6次,路上6小时,其他时间做了好多事。
3.I/O复用模型
1.select/poll
老李前往火车站购买车票,并托付给一位名为"黄牛"的中介进行操作。每隔六小时联系该中介查询进展情况。经过三天的努力工作后成功买到车票。随后,在取款并领取车票后完成整个流程。
耗费:往返车站2次,路上2小时,黄牛手续费100元,打电话17次
2.epoll
老王决定去看电影。
他特意选择了这家电影院。
因为票价相对较低,
所以他选择了这家电影院的原因在于价格因素,
并且他觉得这里的服务也很好。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话
4.信号驱动I/O模型
老李前往火车站购买车票,并向售票员留下了电话号码。当老李收到车票后(接着前往火车站完成付款并领取车票),售票员会通过电话与他联系。
耗费:往返车站2次,路上2小时,免黄牛费100元,无需打电话
5.异步I/O模型
老李前往火车站购买车票,在购票时向售票员提供了联系电话。当取得车票后,售票员通过电话联系了老李,并安排快递员将车票送到他家中。
耗费:往返车站1次,路上1小时,免黄牛费100元,无需打电话
1同2的区别是:自己轮询
2同3的区别是:委托黄牛
3同4的区别是:电话代替黄牛
4同5的区别是:电话通知是自取还是送票上门
