当前位置:   article > 正文

为什么 redis 单线程却能支撑高并发?_多路复用机制 单线程反而避免了多线程的频繁上下文切换问题

多路复用机制 单线程反而避免了多线程的频繁上下文切换问题

纯内存操作
核心是基于非阻塞的 IO
多路复用机制 单线程反而避免了多线程的频繁上下文切换问题

1)不需要各种锁的性能消耗

Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。

总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁、释放锁操作,没有因为可能出现死锁而导致的性能消耗。

2)单线程多进程集群方案

单线程的威力实际上非常强大,单核cpu效率也非常高,多线程自然是可以比单线程有更高的性能上限,但是在今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。

所以“单线程、多进程的集群”不失为一个时髦的解决方案。

3)CPU消耗

采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。

但是如果CPU成为Redis瓶颈,或者不想让服务器其他CUP核闲置,那怎么办?

可以考虑多起几个Redis进程,Redis是key-value数据库,不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪个Redis进程上就可以了。

所谓I/O多路复用

回到我们的主题。所谓I/O多路复用指的是这样一个过程:我们拿到了一堆文件描述符(不管是网络相关的、还是磁盘文件相关等等,任何文件描述符都可以), 通过调用某个函数告诉内核:“这个函数你先不要返回,你替我监视着这些描述符,当这堆文件描述符中有可以进行I/O读写操作的时候你再返回”。

当调用的这个函数返回后,我们就能知道哪些文件描述符可以进行I/O操作了。

那么有哪些函数可以用来进行I/O多路复用呢?在Linux世界中有这样三种机制可以用来进行I/O多路复用:

  1. select
  2. poll
  3. epoll

Redis 采用网络IO多路复用技术,来保证在多连接的时候系统的高吞吐量。

多路: 指的是多个socket网络连接;
复用: 指的是复用一个线程。多路复用主要有三种技术:select,poll,epoll。epoll是最新的, 也是目前最好的多路复用技术。

简单说epoll和select/poll最大区别是:
1.epoll内部使用了mmap共享了用户和内核的部分空间,避免了数据的来回拷贝
2.epoll基于事件驱动,epoll_ctl注册事件,并注册callback回调函数,epoll_wait只返回发生的事件,避免了像select和poll对事件的整个轮询操作。

nginx中使用了epoll,是基于事件驱动模型的。由一个或多个事件收集器来收集或者分发事件,epoll就属于事件驱动模型的事件收集器,将注册过的事件中发生的事件收集起来,master进程负责管理worker进程。

Redis常见性能问题和解决方案:

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件;(Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照;AOF文件过大会影响Master重启的恢复速度)

(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...;这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

Redis的回收策略

  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  • allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
  • allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
  • no-enviction(驱逐):禁止驱逐数据

注意这里的6种机制,

(1)volatile和allkeys规定了,是对已设置过期时间的数据集淘汰数据,还是从全部数据集淘汰数据。

(2)后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略。

使用策略规则:

1、如果数据呈现幂律分布,也就是一部分数据访问频率高,一部分数据访问频率低,则使用allkeys-lru

2、如果数据呈现平等分布,也就是所有的数据访问频率都相同,则使用allkeys-random

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/151233
推荐阅读
相关标签
  

闽ICP备14008679号