1. Redis简介
Redis 之所以称之为字典服务,是因为 Redis 是一个 key-value 存储系统。支持存储的 value 类型很多,包括 String(字符串)、List(链表)、Set(集合)、Zset(sorted set --有序集合)和 Hash(哈希类型)等。
NoSQL(“non-relational”, “Not Only SQL”),泛指非关系型的数据库。随着互联网 web2.0 网站的兴起,传统的关系数据库在处理 web2.0 网站,特别是超大规模和高并发的 SNS 类型的 web2.0 纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据应用难题。
1. 键值存储数据库:Map 一样的 key-value 对。典型代表就是 Redis。
2. 列存储数据库:关系型数据库是典型的行存储数据库。其存在的问题是,按行存储的数据在物理层面占用的是连续存储空间,不适合海量数据存储。按列存储则可实现分布式存储,适合海量存储。典型代表是 HBase。
3. 文档型数据库:是 NoSQL 与关系型数据的结合,最像关系型数据库的 NoSQL。典型代表是 MongoDB。
4. 图形(Graph)数据库:存放一个节点关系的数据库,例如描述不同人间的关系。典型代表是 Neo4J。
2. Redis的用途
Redis 在生产中使用最多的场景就是做数据缓存。即客户端从 DBMS 中查询出的数据首先写入到
Redis 中,后续无论哪个客户端再需要访问该数据,直接读取 Redis 中的即可,不仅减小了 RT
(响应时间),而且降低了 DBMS 的压力。

根据 Redis 缓存的数据与 DBMS 中数据的同步性划分,缓存一般可划分为两类:实时同步缓存,与阶段性同步缓存。
实时同步缓存是指,DBMS 中数据更新后,Redis 缓存中的存放的相关数据会被立即清除,以促使再有对该数据的访问请求到来时,必须先从 DBMS 中查询获取到最新数据,然后再写入到 Redis。
阶段性同步缓存是指,Redis 缓存中的数据允许在一段时间内与 DBMS 中的数据不完全一致。而这个时间段就是这个缓存数据的过期时间。
2.1 Redis特性

性能极高:Redis 读的速度可以达到 11w 次/s,写的速度可以达到 8w 次/s。原因:
1. Redis 的所有操作都是在内存中发生的。
2. Redis 是用 C 语言开发的。
3. Redis 源码非常精细(集性能与优雅于一身)。
4. Redis 源码很少。早期版本只有 2w 行左右。从 3.0 版本开始,增加了集群功能,代码变为了 5w 行左右。
5. 持久化:Redis 内存中的数据可以进行持久化,其有两种方式:RDB 与 AOF。
6. 高可用集群:Redis 提供了高可用的主从集群功能,可以确保系统的安全性。
7. 丰富的数据类型:Redis 是一个 key-value 存储系统。支持存储的 value 类型很多,包括String(字符串)、List(链表)、Set(集合)、Zset(sorted set --有序集合)和 Hash(哈希类型)等,还有 BitMap、HyperLogLog、Geospatial 类型。
7.1. BitMap:一般用于大数据量的二值性统计。
7.2. HyperLogLog:其是 Hyperlog Log,用于对数据量超级庞大的日志做 去重统计。
7.3. Geospatial:地理空间,其主要用于地理位置相关的计算。
8. 强大的功能:Redis 提供了数据过期功能、发布/订阅功能、简单事务功能,还支持 Lua 脚本扩展功能。
9. 客户端语言广泛:Redis提供了简单的 TCP 通信协议,编程语言可以方便地的接入 Redis。
10. 支持 ACL 权限控制:之前的权限控制非常笨拙。从 Redis6 开始引入了 ACL 模块,可以为不同用户定制不同的用户权限。
ACL,Access Control List,访问控制列表,是一种细粒度的权限管理策略,可以针对任意用
户与组进行权限控制。目前大多数 Unix 系统与 Linux 2.6 版本已经支持 ACL 了。
Zookeeper 早已支持 ACL 了。
Unix 与 Linux 系统默认使用是 UGO(User、Group、Other)权限控制策略,其是一种粗粒度的权限管理策略。
11. 支持多线程 IO 模型:Redis 之前版本采用的是单线程模型,从 6.0 版本开始支持了多线程模型。
2.2 Redis 的 IO 模型
Redis 客户端提交的各种请求是如何最终被 Redis 处理的?
Redis 处理客户端请求所采用的处理架构,称为 Redis 的 IO 模型。
不同版本的 Redis 采用的 IO 模型是不同的。
2.2.1 单线程模型
对于 Redis 3.0 及其以前版本,Redis 的 IO 模型采用的是纯粹的单线程模型。即所有客户端的请
求全部由一个线程处理。

1. Redis 的单线程模型采用了多路复用技术。
2. 对于多路复用器的多路选择算法常见的有三种:select 模型(底层是数组)、poll 模型、epoll 模型。
2.1 poll 模型的选择算法:采用的是轮询算法。该模型对客户端的就绪处理是有延迟的。
2.2 epoll 模型的选择算法:采用的是回调方式(就绪之后立马就进入事件分发器处理,如果有多个的话会有队列)。根据就绪事件发生后的处理方式的不同,又可分为 LT 模型与 ET 模型。
每个客户端若要向 Redis 提交请求,都需要与 Redis 建立一个 socket 连接,并向事件分发器注册一个事件。
一旦该事件发生就表明该连接已经就绪。而一旦连接就绪,事件分发器就会感知到,然后获取客户端通过该连接发送的请求,并将由该事件分发器所绑定的这个唯一的线程来处理。
如果该线程还在处理多个任务,则将该任务写入到任务队列等待线程处理。之所以称为事件分发器,是因为它会根据不同的就绪事件,将任务交由不同的事件处理器去处理。
2.2.2 混合线程模型
从 Redis 4.0 版本开始,Redis 中就开始加入了多线程元素。处理客户端请求的仍是单线程模型,
但对于一些比较耗时但又不影响对客户端的响应的操作,就由后台其它线程(子线程)来处理。
例如,持久化、对 AOF 的 rewrite、对失效连接的清理等。

2.2.3 多线程模型
Redis 6.0 版本,才是真正意义上的多线程模型。因为其对于客户端请求的处理采用的是多线程模型。

多线程 IO 模型中的“多线程”仅用于接受、解析客户端的请求,然后将解析出的请求写入到任务队列。而对具体任务(命令)的处理,仍是由主线程处理。
这样做用户无需考虑线程安全问题,无需考虑事务控制,无需考虑像 LPUSH/LPOP 等命令的执行顺序问题。
2.2.4 优缺点总结
(1) 单线程模型
优点:可维护性高,性能高。不存在并发读写情况,所以也就不存在执行顺序的不确定性,不存在线程切换开销,不存在死锁问题,不存在为了数据安全而进行的加锁/解锁开销。
缺点:性能会受到影响,且由于单线程只能使用一个处理器,所以会形成处理器浪费。
(2) 多线程模型
优点:其结合了多线程与单线程的优点,避开了它们的所有不足。
缺点:该模型没有明显不足。如果非要找其不足的话就是,其并非是一个真正意义上的 “多线程”,因为真正处理“任务”的线程仍是单线程。所以,其对性能也是有些影响的。
3. Redis的启动与配置
3.1 前台启动
redis-server
开启之后可以查看到当前的redis进程,默认端口号为6379.
3.2 命令式后台启动
使用 nohub 命令,最后再添加一个&符,可以使要启动的程序在后台以守护进程方式运行。
这样的好处是,进程启动后不会占用一个会话窗口,且其还会在当前目录,即运行启动命令的当前目录中创建一个 nohup.out 文件用于记录 Redis 的操作日志。
nohup redis-server &
3.2.1 Redis的停止
redis-cli shutdown
3.3 配置式后台启动
使用 nohup 命令可以使 Redis 后台启动,但每次都要键入 nohup 与&符,比较麻烦。
可以通过修改 Linux 中 Redis 的核心配置文件 redis.conf 达到后台启动的目的。
将 daemonize 属性值由 no 改为 yes,使 Redis 进程以守护进程方式运行。
修改后再启动 Redis,就无需再键入 nohup 与&符了,但必须要指定启动所使用的Redis 配置文件。
redis.conf 文件在Redis 的安装目录根下。
redis-server /path/to/redis.conf
3.4 连接前的配置
Redis 是一个内存数据库服务器,就像 MySQL 一样,对其操作也需要通过客户端进行。
若要使远程主机上的客户端能够连接并访问到服务端的 Redis,则服务端首先要做如下配置。
3.4.1 绑定客户端IP

以上设置后,只允许当前主机访问当前的 Redis,其它主机均不可访问。
所以,如果不想限定访问的客户端,只需要将该行注释掉即可。
3.4.2 关闭保护模式
默认保护模式是开启的。其只允许本机的客户端访问,即只允许自己访问自己。
但生产中应该关闭,以确保其它客户端可以连接 Redis。

3.4.3 设置访问密码
为 Redis 设置访问密码,可以对要读/写 Redis 的用户进行身份验证。
没有密码的用户可以登录 Redis,但无法访问。

1. 登录时不使用密码

2. 登录时使用密码

3. 退出时使用密码

3.4.4 禁止/重命名命令
在学习过程中暂时不禁用它们,flushal 与 flushdb。它们都是用于直接删除整个 Redis数据库的。

3.5 Redis客户端分类
3.5.1 命令行客户端

-h:指定要连接的 Redis 服务器的 IP
-p:指定要连接的 Redis 的端口号
若连接的是本机 Redis,且端口号没有改变,保持默认的 6379,则-h 与-p 选项可以省略不写。
3.5.2 图形界面客户端

3.6 Redis配置文件详解
3.6.1 基础说明
第 1-6 行用于说明,如果要启动 Redis,需要指出配置文件的路径。
第 8-16 行用于说明当前配置文件中可以使用的的容量单位及意义。
第 18 行用于说明这些容量单位没有大小写之分。
3.6.2 includes
指定要在当前配置文件中包含的配置文件。
这样做的目的主要是便于配置信息管理:可以将不同场景的配置都进行单独定义,然后在当前核心配置文件中根据不同场景选择包含进不同的配置文件。
3.6.3 modules
Redis 配置文件中可以通过加载不同的第三方模块,来增强、扩展 Redis 的功能。
3.6.4 network
三次握手,四次挥手



bind

protected-mode

port

tcp-backlog

当客户端想要与服务器建立 TCP 连接时(发送 SYN 包),服务器可能正在处理其他任务,无法立即完成连接的建立。为了处理这种并发的连接请求,操作系统内核会为每个监听中的端口(比如 Redis 的 6379 端口)维护一个队列。这个队列就是 Backlog 队列。
tcp-backlog 是一个 TCP 连接的队列,其主要用于解决高并发场景下客户端慢连接问题。这里设置的值就是这个队列的长度。该队列与 TCP 连接的三次握手有关。不同的 Linux 内核,backlog 队列中存放的元素(客户端连接)类型是不同的。
Linux 内核 2.2 版本之前,该队列中存放的是已完成了第一次握手的所有客户端连接,其中就包含已完成三次握手的客户端连接。当然,此时的 backlog 队列中的连接也具有两种状态:未完成三次握手的连接状态为 SYN_RECEIVED,已完成三次握手的连接状态为 ESTABLISHED。只有 ESTABLISHED 状态的连接才会被 Redis 处理。
Linux 内核 2.2 版本之后 TCP 系统中维护了两个队列:SYN_RECEIVED 队列与 ESTABLISHED
队列。SYN_RECEIVED 队列中存放的是未完成三次握手的连接,ESTABLISHED 队列中存放的是已完成三次握手的连接。此时的 backlog 就是 ESTABLISHED 队列。
查看linux内核版本

为了确保 Redis 的 Backlog 队列达到你期望的长度,你必须同时检查并调整两个地方的值,并且要让系统的 somaxconn
值至少不小于 Redis 配置的 tcp-backlog
值。


修改过后可以重启虚拟机,也可以通过执行如下命令来使新的修改生效。
systcl -p
timeout
检测用户是否"掉线"或"发呆",释放资源,避免占着线路不说话的用户。
空闲超时。当客户端与 Redis 间的空闲时间超过该时长后,连接自动断开。
单位秒。默认值为 0,表示永远不超时。
tcp-keepalive
每隔一段时间就检查一下线路是否正常,发现网络故障,清理"僵尸连接"。

general
daemonize
该配置可以控制 Redis 启动是否采用守护进程方式,即是否是后台启动。yes 是采用后台启动。
pidfile
该配置用于指定 Redis 运行时 pid 写入的文件,无论 Redis 是否采用守护进程方式启动,pid 都会写入到该配置的文件。
注意,如果没有配置 pid 文件,不同的启动方式,pid 文件的产生效果是不同的:

采用守护进程方式启动(后台启动,daemonize 为 yes):pid 文件为/var/run/redis.pid。
采用前台启动(daemonize 为 no):不生产 pid 文件
loglevel
配置日志的级别。Redis 中共有四个级别,由低到高依次是:
- debug:可以获取到很多的信息,一般在开发和测试时使用。
- verbose:可以获取到很多不太有用的信息,但不像 debug 级别那么多。
- notice:可以获取到在生产中想获取到的适当多的信息,默认级别。
- warning:只记录非常重要/关键的信息。
logfile
指定日志文件。如果设置为空串,则强制将日志记录到标准输出设备(显示器)。
如果使用的是守护进程启动方式,设置为空串,则意味着会将日志发送到设备/dev/null(空设备)。
databases
设置数据库的数量。默认数据库是 0 号数据库。
可以使用 select <dbid>在每个连接的基础上选择一个不同的数据库,其中 dbid 是介于
0 和'databases'-1'之间的数字。
security
用户设置 ACL 权限、Redis 访问密码相关配置。该模块中最常用的就是 requirepass 属性。
clients
该模块用于设置与客户端相关的属性,其中仅包含一个属性 maxclients。
maxclients 用于设置 Redis 可并发处理的客户端连接数量,默认值为 10000。如果达到了该最大连接数,则会拒绝再来的新连接,并返回一个异常信息:已达到最大连接数。
注意,该值不能超过 Linux 系统支持的可打开的文件描述符最大数量阈值。查看该阈值的方式如下。修改该值,可以通过修改/etc/secutiry/limits.conf 文件(自己查)。

memory management
该配置可以控制最大可用内存及相关内容移除问题。
maxmemory
将内存使用限制设置为指定的字节数。当达到内存限制时,Redis 将根据选择的逐出策略 maxmemory-policy 尝试删除符合条件的 key。
如果不能按照逐出策略移除 key,则会给写操作命令返回 error,但对于只读的命令是没有影响的。
maxmemory-policy
该属性用于设置,当达到 maxmemory 时,Redis 将如何选择要移除的内容。当然,如果没有符合相应策略的内容要删除,则在执行写入命令时会给出 errors 的响应。Redis 中支持 8 种移除策略:
- volatile-lru:使用近似 LRU 算法移除,仅适用于设置了过期时间的 key。(最近最少使用)
- allkeys-lru:使用近似 LRU 算法移除,可适用于所有类型的 key。(最常用策略)
- volatile-lfu:使用近似 LFU 算法移除,仅适用于设置了过期时间的 key。(最不经常使用)
- allkeys-lfu:使用近似 LFU 算法移除,可适用于所有类型的 key。
- volatile-random:随机移除一个 key,仅适用于设置了过期时间的 key。
- allkeys-random:随机移除一个 key,可适用于所有类型的 key。
- volatile-ttl:移除距离过期时间最近的 key。(优先清理快过期的)
- noeviction:不移除任何内容,只是在写操作时返回一个错误,默认值。
maxmemory-samples
该属性用于指定挑选要删除的 key 的样本数量。样本的选择采用的是 LRU 算法,其不能修改。但从样本中再选择要移除的 key,则采用的是 maxmamory-policy 指定的策略。
maxmemory-eviction-tenacity
设置移除容忍度。数值越小表示容忍度越低,需要移除的数据移除延迟越小;
数值越大表示容忍度越高,需要移除的数据移除延迟越大。
threaded/IO
io-threads
该属性用于指定要启用多线程 IO 模型时,要使用的线程数量。

io-threads-do-reads
该属性用于启用多线程 IO 模型中的多线程处理读请求的能力。