简介
引自中文官网:
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模式。
**
在 I/O 多路复用模型中,最重要的函数调用就是 select,该方法的能够同时监控多个文件描述符的可读可写情况,当其中的某些文件描述符可读或者可写时,select 方法就会返回可读以及可写的文件描述符个数。
那一样会阻塞,为什么这里又叫多路复用了呢?
正因为阻塞I/O只能阻塞一个I/O操作,而I/O复用模型能够阻塞和监听多个I/O操作,所以才叫做多路复用。