Redis为何是单线程

转自:https://www.zhihu.com/question/23162208 https://www.zhihu.com/question/55818031mysql

Redis为何是单线程的?redis

由于CPU不是Redis的瓶颈。Redis的瓶颈最有多是机器内存或者网络带宽。(以上主要来自官方FAQ)既然单线程容易实现,并且CPU不会成为瓶颈,那就瓜熟蒂落地采用单线程的方案了。关于redis的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求,参见:How fast is Redis?
sql


若是万一CPU成为你的Redis瓶颈了,或者,你就是不想让服务器其余核闲置,那怎么办?数据库

那也很简单,你多起几个Redis进程就行了。Redis是keyvalue数据库,又不是关系数据库,数据之间没有约束。只要客户端分清哪些key放在哪一个Redis进程上就能够了。redis-cluster能够帮你作的更好。
缓存


单线程能够处理高并发请求吗?安全

固然能够了,Redis都实现了。服务器

有一点概念须要澄清,并发并非并行。网络

(相关概念:并发性I/O流,意味着可以让一个计算单元来处理来自多个客户端的流请求。并行性,意味着服务器可以同时执行几个事情,具备多个计算单元
多线程


Redis整体快速的缘由:架构

采用队列模式将并发访问变为串行访问(?)

单线程指的是网络请求模块使用了一个线程(因此不需考虑并发安全性),其余模块仍用了多个线程。


整体来讲快速的缘由以下:

1)绝大部分请求是纯粹的内存操做(很是快速)

2)采用单线程,避免了没必要要的上下文切换和竞争条件

3)非阻塞IO

内部实现采用epoll,采用了epoll+本身实现的简单的事件框架。epoll中的读、写、关闭、链接都转化成了事件,而后利用epoll的多路复用特性,毫不在io上浪费一点时间

这3个条件不是相互独立的,特别是第一条,若是请求都是耗时的,采用单线程吞吐量及性能可想而知了。应该说redis为特殊的场景选择了合适的技术方案。


======

1. Redis服务端是个单线程的架构,不一样的Client虽然看似能够同时保持链接,但发出去的命令是序列化执行的,这在一般的数据库理论下是最高级别的隔离(serialize)
2. 用MULTI/EXEC 来把多个命令组装成一次发送,达到原子性
3. 用WATCH提供的乐观锁功能,在你EXEC的那一刻,若是被WATCH的键发生过改动,则MULTI到EXEC之间的指令所有不执行,不须要rollback
4. 其余回答中提到的DISCARD指令只是用来撤销EXEC以前被暂存的指令,并非回滚


做者:顾小宇
连接:https://www.zhihu.com/question/35949129/answer/81798934
来源:知乎
著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。

多线程对同一个Key操做时,Redis服务是根据先到先做的原则,其余排队(可设置为直接丢弃),由于是单线程。

修改默认的超时时间,默认2秒。可是大部份的操做都在30ms之内。


========


1. 使用Redis有哪些好处?

(1) 速度快,由于数据存在内存中,相似于HashMap,HashMap的优点就是查找和操做的时间复杂度都是O(1)

(2) 支持丰富数据类型,支持string,list,set,sorted set,hash

(3) 支持事务,操做都是原子性,所谓的原子性就是对数据的更改要么所有执行,要么所有不执行

(4) 丰富的特性:可用于缓存,消息,按key设置过时时间,过时后将会自动删除


2. Redis相比memcached有哪些优点?

(1) memcached全部的值均是简单的字符串,redis做为其替代者,支持更为丰富的数据类型

(2) redis的速度比memcached快不少

(3) redis能够持久化其数据

(4)Redis支持数据的备份,即master-slave模式的数据备份。

(5)、使用底层模型不一样

它们之间底层实现方式 以及与客户端之间通讯的应用协议不同。

Redis直接本身构建了VM 机制 ,由于通常的系统调用系统函数的话,会浪费必定的时间去移动和请求。

(6)value大小:redis最大能够达到1GB,而memcache只有1MB



3. 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的一些其余特色:

(1)Redis是单进程单线程的

redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销

(2)读写分离模型

经过增长Slave DB的数量,读的性能能够线性增加。为了不Master DB的单点故障,集群通常都会采用两台Master DB作双机热备,因此整个集群的读和写的可用性都很是高。
读写分离架构的缺陷在于,不论是Master仍是Slave,每一个节点都必须保存完整的数据,若是在数据量很大的状况下,集群的扩展能力仍是受限于单个节点的存储能力,并且对于Write-intensive类型的应用,读写分离架构并不适合。

(3)数据分片模型

为了解决读写分离模型的缺陷,能够将数据分片模型应用进来。

能够将每一个节点当作都是独立的master,而后经过业务实现数据分片。

结合上面两种模型,能够将每一个master设计成由一个master和多个slave组成的模型。

(4)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种机制,volatile和allkeys规定了是对已设置过时时间的数据集淘汰数据仍是从所有数据集淘汰数据,后面的lru、ttl以及random是三种不一样的淘汰策略,再加上一种no-enviction永不回收的策略。

      使用策略规则:

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

      二、若是数据呈现平等分布,也就是全部的数据访问频率都相同,则使用allkeys-random