1. Redis简介
Redis,Remote Dictionary Server,远程字典服务,由意大利人 Salvatore Sanfilippo(又名 Antirez)开发,是一个使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、NoSQL 开源内存数据库,其提供多种语言的 API。
Redis 之所以称之为字典服务,是因为 Redis 是一个 key-value 存储系统。
NoSQL
NoSQL(“non-relational”, “Not Only SQL”),泛指非关系型的数据库。传统的关系数据库在处理超大规模和高并发的 SNS 类型 的 web2.0 纯动态网站时出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,特别是大数据应用难题。
- 键值存储数据库:典型代表是 Redis。
- 列存储数据库:典型代表是 HBase。
关系型数据库是典型的行存储数据库。其存在的问题是,按行存储的数据在物理层面占用的是连续存储空间,不适合海量数据存储。而按列存储则可实现分布式存储,适合海量存储。
- 文档型数据库:最像关系型数据库的 NoSQL。典型代表是 MongoDB。
- 图形(Graph)数据库:典型代表是 Neo4J。
Redis 的用途
Redis 在生产中使用最多的场景就是做数据缓存。即客户端从 DBMS 中查询出的数据首先写入到 Redis 中,后续无论哪个客户端再需要访问该数据,直接读取 Redis 中的即可,不仅减小了 RT,而且降低了 DBMS 的压力。
根据 Redis 缓存的数据与 DBMS 中数据的同步性划分,缓存一般可划分为两类:
- 实时同步缓存
DBMS 中数据更新后,Redis 缓存中的存放的相关数据会被立即清除,以促使再有对该数据的访问请求到来时,必须先从 DBMS 中查询获取到最新数据,然后再写入到 Redis。
- 阶段性同步缓存。
Redis 缓存中的数据允许在一段时间内与 DBMS 中的数据不完全一致。而这个时间段就是这个缓存数据的过期时间。
Redis 特性
能够做缓存的技术、中间件很多,例如MyBatis 自带的二级缓存、Memched 等。只所以在生产中做缓存的产品几乎无一例外的会选择 Redis,是因为它有很多其它产品所不具备的特性。
- 性能极高:Redis 读的速度可以达到 11w 次/s,写的速度可以达到 8w 次/s。
- Redis 的所有操作都在内存中。
- Redis 是用 C 语言开发。
- Redis 源码非常精细(集性能与优雅于一身)。
- 简单稳定
- 持久化:Redis 内存中的数据可以进行持久化,其有两种方式:RDB 与 AOF。
- 高可用集群:Redis 提供了高可用的主从集群功能,可以确保系统的安全性。
- 丰富的数据类型
- 强大的功能:Redis 提供了数据过期功能、发布/订阅功能、简单事务功能,还支持 Lua 脚本扩展功能。
- 客户端语言广泛:Redis提供了简单的 TCP 通信协议,编程语言可以方便地的接入 Redis。
- 支持 ACL 权限控制:之前的权限控制非常笨拙。从 Redis6 开始引入了 ACL 模块(一种细粒度的权限管理策略,可以针对任意用户与组进行权限控制)
- 支持多线程 IO 模型:Redis 之前版本采用的是单线程模型,从 6.0 版本开始支持了多线 程模型。
Redis 的 IO 模型
Redis 处理客户端请求所采用 的处理架构,称为 Redis 的 IO 模型。不同版本的 Redis 采用的 IO 模型是不同的。
单线程模型
对于 Redis 3.0 及其以前版本,Redis 的 IO 模型采用的是纯粹的单线程模型。即所有客户 端的请求全部由一个线程处理。
采用了多路复用技术,常见的有三种多路选择算法:
- select 模型:底层使用数组,性能较低
- poll 模型:采用的是轮询算法。该模型对客户端的就绪处理是有延迟的。
- epoll 模型的选择算法:采用的是回调方式。根据就绪事件发生后的处理方式的不同, 又可分为 LT 模型与 ET 模型。
每个客户端若要向 Redis 提交请求,都需要与 Redis 建立一个 socket 连接,并向事件分发器(会根据不同的就绪事件,将任务交由不同的事件处理器处理)注册一个事件。一旦该事件发生就表明该连接已经就绪。而一旦连接就绪,事件分发器就会感知到,然后获取客户端通过该连接发送的请求,并将由该事件分发器所绑定的这个唯一的线程来处理。如果该线程繁忙,则将该任务写入到任务队列等待线程处理。
混合线程模型
从 Redis 4.0 版本开始,Redis 中就开始加入了多线程元素。处理客户端请求的仍是单线 程模型,但对于一些比较耗时但又不影响对客户端的响应的操作,就由后台其它线程来处理。 例如,持久化、对 AOF 的 rewrite、对失效连接的清理等。
多线程模式
Redis 6.0 版本,才是真正意义上的多线程模型。因为其对于客户端请求的处理采用的是多线程模型。
多线程 IO 模型中的“多线程”仅用于接受、解析客户端的请求,然后将解析出的请求写入到任务队列。而对具体任务(命令)的处理,仍是由主线程处理。这样做使得用户无需考虑线程安全问题,无需考虑事务控制,无需考虑像 LPUSH/LPOP 等命令的执行顺序问题。
总结:
- 单线程模型
可维护性高,性能高。性能会受到影响,且由于单线程只能使用一个处理器,会形成处理器浪费。
- 多线程模型
结合了多线程与单线程的优点,避开了它们的所有不足。并非是一个真正意义上的 “多线程”,因为真正处理“任务”的线程仍是单线程
2. Redis 的安装与配置
官网:Redis
将 Redis 安装到 Linux 系统中
1 | yum -y install gcc gcc-c++ |
Redis 是由 C/C++ 语言编写的,而从官网下载的 Redis 安装包需要编译后才可安装,所以必须要使用相关编译器。对于 C/C++ 语言的编译器,使用最多的是 gcc 与 gcc-c++
- 上传到虚拟机后进行解压:
1 | tar -zxvf redis-7.03.tar.gz -C /opt/apps |
为了方便可以将解压后的文件目录改为redis
1 mv redis-7.0.3/ redis
- 编译:
编译过程是根据 Makefile 文件进行的,解压包中已经存在该文件,进入到解压目录中,然后执行编译命令 make。
- 安装:
编译过后执行 make install 进行安装。可以看到,共安装了三个组件:redis 服务器、客户端与一个性能测试工具 benchmark。
安装完成后打开/usr/local/bin 目录,可以看到出现了很多的可执行文件。
echo $PATH 可以看到,/usr/local/bin 目录是存在于该系统变量中的。
Redis 的启停
Redis 的停止:
1 | redis-cli shutdown |
方式一:前台启动
在任意目录执行 redis-server 命令即可启动 Redis。这种启动方式会占用当前命令行窗口。可以直接 ctrl+c 结束进程。
方式二:命令式后台启动
1 | nohub redis-server & |
使用 nohub 命令,最后再添加一个&符,可以使要启动的程序在后台以守护进程方式运行。这样的好处是,进程启动后不会占用一个会话窗口,且其还会在当前目录,即运行启动命令的当前目录中创建一个 nohup.out 文件用于记录 Redis 的操作日志。
方式三:配置式后台启动
可以通过修改 Linux 中 Redis 的核心配置文件 redis.conf 达到后台启动的目的。redis.conf 文件在 Redis 的安装目录根下。
将 no 改为 yes
修改后再启动 Redis,就无需再键入 nohup 与&符了,但必须要指定启动所使用的 Redis 配置文件。
使用 nohup redis-server &命令启动 Redis 时,启动项中已经设置好了 Redis 各个参数的默认值,Redis 会按照这些设置的参数进行启动。但这些参数是可以在配置文件中进行修改的,修改后,需要在启动命令中指定要加载的配置文件,这样,配置文件中的参数值将覆盖原默认值。
Redis 已经给我们提供好了配置文件模板,就是 redis.conf 文件。对 redis.conf 配置文件做了修改,要在开启 Redis 时需要显示指出要加载的配置文件。配置文件应紧跟在 redis-server 的后面。
1 | redis-server /opt/apps/redis/redis.conf |
为了方便起见,我们可以给该命令设置别名:
1
2
3
4
5
6 >#查看所有别名
>alias
>#设置别名
>alias redis-server='redis-server /opt/apps/redis/redis.conf'
>#删除别名
>unalias redis-server
Redis 的连接
Redis 是一个内存数据库服务器,就像 MySQL 一样,对其操作也需要通过客户端进行。若要使远程主机上的客户端能够连接并访问到服务端的 Redis,则服务端首先要做如下配置。
绑定客户端 IP
Redis 可以通过修改配置文件来限定可以访问自己的客户端 IP。
默认配置只允许当前主机访问 Redis,不需要限定访问的客户端可以直接注释掉
关闭保护模式
默认保护模式是开启的,其只允许本机的客户端访问
设置访问密码
默认没有密码。
设置后没有通过密码登录的用户,无法读/写 Redis。
使用密码:
禁止/重命名命令
禁用 flushall 命令,也可以在双引号内重命名命令,防止其他用户使用
客户端连接
Redis 客户端也像 MySQL 客户端一样有多种类型:命令行客户端、图形界面客户端、Java 代码客户端。
- Redis 提供了基本的命令行客户端。打开命令行客户端的命令为:
1 | redis-cli -h Redis服务器IP -p Redis端口号 -a 密码 |
连接本机 Redis,且端口号没有改变(6379),则-h 与-p 选项可以省略不写;-a 也可以省略
- 图形界面客户端
Redis 的图形界面客户端中较出名的是 Redis Desktop Manager 。该软件在0.8.8 版本后变为了商业化收费软件。 官网为:https://resp.app/
连接需要关闭防火墙
- Java 代码客户端
所谓 Java 代码客户端就是一套操作 Redis 的 API,其作用就像 JDBC 一样,所以 Java 代码客户端其实就是一个或多个 Jar 包,提供了对 Redis 的操作接口。最常用也是最有名的是 Jedis。
3. Redis 配置文件详解
打开配置文件:
- 1-6 行用于说明,如果要启动 Redis,需要指出配置文件的路径。
- 8-16 行用于说明当前配置文件中可以使用的的容量单位及意义。
- 18 行用于说明这些容量单位没有大小写之分。
includes
指定要在当前配置文件中包含的配置文件。
目的主要是便于配置信息管理:可以将不同场景的配置都进行单独定义,然后在当前核心配置文件中根据不同场景选择包含进不同的配置文件。
如注释所述,需要将包含的配置文件写在最后一行,包含的配置文件中的参数会覆盖当前配置文件中的参数
modules
Redis 配置文件中可以通过加载不同的第三方模块,来增强、扩展 Redis 的功能。
network
Network 配置模块是比较重要的部分,主要进行网络相关的配置。
- bind
指定可以访问当前 Redis 服务的客户端 IP,默认只允许本地访问
- protected-mode
默认保护模式是开启的。其只允许本机的客户端访问
- port
Redis 监听的连接端口号,默认 6379
- tcp-backlog
tcp-backlog 是一个 TCP 连接的队列,其主要用于解决高并发场景下客户端慢连接问题。这里设置的值就是这个队列的长度。该队列与 TCP 连接的三次握手有关。不同的 Linux 内核,backlog 队列中存放的元素(客户端连接)类型是不同的。
Linux 内核 2.2 版本之前,该队列中存放的是已完成了第一次握手的所有客户端连接。当然,此时的 backlog 队列中的连接具有两种状态:未完成三次握手的连接状态为 SYN_RECEIVED,已完成三次握手的连接状态为 ESTABLISHED。只有 ESTABLISHED 状态的连接才会被 Redis 处理。
Linux 内核 2.2 版本之后 TCP 系统中维护了两个队列:SYN_RECEIVED 队列与 ESTABLISHED 队列。此时的 backlog 就是 ESTABLISHED 队列。
查看 Linux 内核版本:
1 | uname -a |
TCP 中的 backlog 队列的长度在 Linux 中由内核参数 somaxconn 来决定。所以在 Redis 中该队列的长度由 Redis 配置文件设置与 somaxconn 来共同决定:取它们中的最小值。
查看当前 Linux 内核中 somaxconn 的值:
1 | cat /proc/sys/net/core/somaxconn |
默认是128
高并发场景下,backlog 的值最好要大一些,否则可能会影响系统性能。 修改/etc/sysctl.conf 文件,在文件最后添加如下内容:
1 | net.core.somaxconn=2048 |
执行以下命令或重启虚拟机生效:
1 | sysctl -p |
- timeout
空闲超时。当客户端与 Redis 间的空闲时间超过该时长后,连接自动断开。单位秒。默认值为 0,表示永远不超时。
- tcp-keepalive
该配置主要用于设置 Redis 检测与其连接的所有客户端的存活性时间间隔,单位秒。一般是在 timeout 设置为 0 时进行配置。
大多数软件都是由客户端定时发送“心跳”给服务器
general
- daemonize
该配置可以控制 Redis 启动是否采用守护进程方式,即是否是后台启动。yes 是采用后 台启动。
- pidfile
该配置用于指定 Redis 运行时 pid 写入的文件,不同的启动方式,pid 文件的产生效果是不同的:
- 采用守护进程方式启动(daemonize 为 yes):pid 文件为/var/run/redis.pid。
- 采用前台启动(daemonize 为 no):不生产 pid 文件
- loglevel
配置日志的级别。Redis 中共有四个级别,由低到高依次是:debug > verbose > notice(默认值)> warning。详细介绍可以参考注释
- logfile
指定日志文件。如果设置为空串,则强制将日志记录到标准输出设备(显示器);使用守护进程启动方式则会将日志发送到设备/dev/null(空设备)。
- databases
设置数据库的数量,默认16个。连接默认使用 0 号数据库,可以使用 select <dbid>在每个连接的基础上选择不同的数据库
security
用户设置 ACL 权限、Redis 访问密码相关配置。该模块中最常用的就是 requirepass 属性
clients
该模块用于设置与客户端相关的属性,其中仅包含一个属性 maxclients。
maxclients 用于设置 Redis 可并发处理的客户端连接数量,默认值为 10000(Redis 内部占用32个)。如果达到了该最大连接数,则会拒绝再来的新连接,并返回一个异常信息:已达到最大连接数。
注意:该值不能超过 Linux 系统支持的可打开的文件描述符最大数量阈值。可以通过修改/etc/secutiry/limits.conf 文件修改该值
1 | ulimit -n #查看阈值 |
注释中的 important 有关集群创建,需要注意
memory management
该配置可以控制最大可用内存及相关内容移除问题。
- maxmemory
将内存使用限制设置为指定的字节数。当达到内存限制时,Redis 将根据选择的逐出策略 maxmemory-policy 尝试删除符合条件的 key。 如果不能按照逐出策略移除 key,则会给写操作命令返回 error,但不会影响只读的命令
- maxmamory-policy
该属性用于设置,当达到 maxmemory 时,Redis 将如何选择要移除的内容。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 I/O
该配置模块用于配置 Redis 对多线程 IO 模型的支持。
- io-threads
该属性用于指定要启用多线程 IO 模型时,要使用的线程数量。建议至少预留一个核心(用于数据持久化)。没必要别开,会占用大量cpu资源
查看当前系统信息:lscpu
- io-threads-do-reads
该属性用于启用多线程 IO 模型中的多线程处理读请求的能力。
总结:如果需要改配置,一定要先看注释,网络信息不一定对