简介


引自中文官网:

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API,是当今最流行的一款NOSQL数据库。

它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

特点

  • Redis是单线程的,可处理1秒10w的并发(数据都在内存中)

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。

  • Redis支持多种类型数据结构,不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。

  • Redis支持数据的备份,即master-slave模式的数据备份

Redis为什么选择单线程?

为什么Redis这么快?

明明是单线程为什么Redis处理速度可以达到1s10w的并发量?

  • 纯内存KV操作
  • 内部是单程实现的(不需要创建/销毁线程,避免上下文切换,无并发资源竞争的问题)
  • 异步非阻塞的I/O多路复用
  • 优化的数据结构(Redis有诸多可以直接应用的优化数据结构的实现,应用层可以直接使用原生的数据结构提升性能)

纯内存KV操作为啥快?

相比于从磁盘读取数据,Redis操作内存,纯内存数据库,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)

且一般都是简单的存取操作,线程占用的时间很多,时间的花费主要集中在IO上,所以读取速度快

单线程怎么快了?

单线程保证了系统没有线程上下文的切换和竞争条件,也就不会出现所谓的死锁现象,避免了锁定和解锁的操作

多路复用又是啥?

这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗)

我们知道,Redis是通过与客户端之间创建socket连接的方式进行通信的

传统的I/O阻塞模型(Blocking I/O)

当使用 read 或者 write 对某一个文件描述符(File Descriptor 以下简称 FD)进行读写时,如果当前 FD 不可读或不可写,整个 Redis 服务就不会对其它的操作作出响应,导致整个服务不可用。

Redis 是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务。

类比:在班级里面,班主任需要去检查每一个同学的作业,假如班主任必须按照顺序去检查每个学生的作业,先检查A,再检查B、C、D。。。。,如果中间有一个学生没做完,班主任就只能在那里等,后续所有学生都没办法去检查。

同理:类似于循环处理socket,这一个操作没有数据就在那里等着,后续所有操作都排队

多线程方式

类比:班主任使用影分身术,创建26个分身,每个分身负责检查一个学生的作业,每多一个学生就增加一个分身

同理:类似于为每一个socket创建一个进程或者线程处理。

弊端:当涉及到公用资源上,就会导致资源竞争和锁问题,上下文的切换也会导致效率的下降(如果每个分身都需要在电脑上进行记录,而电脑只有一台的时候就需要进行竞争)
资源的损耗,开启了大量的进程或线程(一个教室站那么多人不会很挤吗?)

I/O 多路复用

类比:**班主任以逸待劳,一个人杵在讲台上,A同学举手说写完了就去检查A同学的,检查完回讲台接着杵着。B、C同学说写完了,就按顺序检查B同学和C同学的作业,以此类推,当然中间没人举手还是可以看一下手机的。

同理:将用户socket对应的fd注册进epoll,然后epoll监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。

这样,整个过程只在调用select、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。
**
Redis(Remote DIctionary Server) - 图1
在 I/O 多路复用模型中,最重要的函数调用就是 select,该方法的能够同时监控多个文件描述符的可读可写情况,当其中的某些文件描述符可读或者可写时,select 方法就会返回可读以及可写的文件描述符个数。

那一样会阻塞,为什么这里又叫多路复用了呢?

正因为阻塞I/O只能阻塞一个I/O操作,而I/O复用模型能够阻塞和监听多个I/O操作,所以才叫做多路复用。