单进程单线程的Redis如何可以高并发

一、基本原理
采用多路 I/O 复用技术可让单个线程高效的处理多个链接请求(尽可能减小网络IO的时间消耗)
(1)为何不采用多进程或多线程处理?mysql

多线程处理可能涉及到锁 
多线程处理会涉及到线程切换而消耗CPU

(2)单线程处理的缺点?redis

没法发挥多核CPU性能,不过能够经过在单机开多个Redis实例来完善

二、Redis不存在线程安全问题?
Redis采用了线程封闭的方式,把任务封闭在一个线程,天然避免了线程安全问题,不过对于须要依赖多个redis操做的复合操做来讲,依然须要锁,并且有多是分布式锁sql

三、什么是多路I/O复用(Epoll)
(1) 网络IO都是经过Socket实现,Server在某一个端口持续监听,客户端经过Socket(IP+Port)与服务器创建链接(ServerSocket.accept),成功创建链接以后,就可使用Socket中封装的InputStream和OutputStream进行IO交互了。针对每一个客户端,Server都会建立一个新线程专门用于处理
(2) 默认状况下,网络IO是阻塞模式,即服务器线程在数据到来以前处于【阻塞】状态,等到数据到达,会自动唤醒服务器线程,着手进行处理。阻塞模式下,一个线程只能处理一个流的IO事件
(3) 为了提高服务器线程处理效率,有如下三种思路数据库

1)非阻塞【忙轮询】:采用死循环方式轮询每个流,若是有IO事件就处理,这样可使得一个线程能够处理多个流,可是效率不高,容易致使CPU空转

(2)Select代理(无差异轮询):能够观察多个流的IO事件,若是全部流都没有IO事件,则将线程进入阻塞状态,若是有一个或多个发生了IO事件,则唤醒线程去处理。可是仍是得遍历全部的流,才能找出哪些流须要处理。若是流个数为N,则时间复杂度为O(N)

(3)Epoll代理:Select代理有一个缺点,线程在被唤醒后轮询全部的Stream,仍是存在无效操做。 Epoll会哪一个流发生了怎样的I/O事件通知处理线程,所以对这些流的操做都是有意义的,复杂度下降到了O(1)

四、其它开源软件采用的模型缓存

Nginx:多进程单线程模型 
Memcached:单进程多线程模型

 

Redis为何是单线程的?安全

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

 

若是万一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以前被暂存的指令,并非回滚


多线程对同一个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

相关文章
相关标签/搜索