Redis基础
Redis 是一个开源的,内存中的数据结构存储系统,可以用作 Nosql 数据库、高速缓存和消息队列。它是一个高性能的 key-value 数据库,运行在内存中,但是可以持久化到磁盘。
1. 特点
-
速度快(内存读取)
-
支持多种数据结构(字符串、哈希、列表、集合、有序集合)
-
支持数据备份(master-slave)
-
支持数据持久化(RDB,AOF)
-
支持高可用(Redis-Sentinel)和集群(Redis-Cluster)
2. 数据结构
-
字符串: set 和 get,做最常用的的 K/V 缓存,一个键最大能存储 512MB。还可以用作计数器。
-
哈希: 将结构化的数据放入缓存。读写缓存时,可以操作 Hash 里的某个字段。
-
列表: 存储一些列表型的数据结构,比如文章列表、数据分页、消息队列。
-
集合: 自动去重数据,交集、并集、差集等操作。
-
有序集合: 去重数据并排序,比如排行榜应用。
3. 线程模型
redis 是单线程的。它采用 I/O 多路复用机制同时监听多个 socket,将 socket 产生的事件放入队列,事件分派器每次从队列中取出一个事件,并交给对应的事件处理器进行处理。
redis 使用文件事件处理器,包含 4 个部分:
-
多个 socket
-
I/O 多路复用程序
-
文件事件分派器
-
事件处理器(包括:连接应答处理器、命令请求处理器、命令回复处理器)
redis支持高并发
-
基于内存操作,读写速度快
-
单线程省去了线程切换的消耗
-
I/O多路复用机制
4. 安装启动
$ tar -xzf redis-5.0.8.tar.gz
$ cd redis-5.0.8
$ make
$ src/redis-server redis.conf
5. 连接服务器
$ redis-cli -h 127.0.0.1 -p 6379 -a password
127.0.0.1:6379> AUTH password #验证密码是否正确
OK
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> SELECT index #切换数据库,默认使用0号库(0-15)
OK
127.0.0.1:6379[index]> QUIT #关闭当前连接
6. 持久化机制
(1)RDB 持久化:将某个时间点的内存快照保存到一个 RDB 文件中,该文件是一个经过压缩的二进制文件,通过它可以恢复内存数据。
RDB 是 Redis 默认的持久化方式,在指定目录下生成一个 dump.rdb 文件。持久化过程是由服务器进程 fork 一个子进程,先将内存数据写入临时文件,完成后再替换旧文件。
- 通过 SAVE 和 BGSAVE 命令对数据进行持久化,生成 RDB 文件。
Redis 是单线程的,SAVE 命令会阻塞 redis 主进程,阻塞期间服务器不能处理用户请求。
BGSAVE 命令不会阻塞主进程,会 fork 一个子进程,由子进程负责持久化数据,服务器进程继续处理用户请求。
- 通过配置文件
redis.conf 配置文件中的 save 配置项,让服务器每隔一段时间自动执行 BGSAVE。
save 900 1 #服务器在900秒之内,对数据库进行了至少1次修改。
save 300 10 #服务器在300秒之内,对数据库进行了至少10次修改。
save 60 10000 #服务器在60秒之内,对数据库进行了至少10000次修改。
(2)AOF持久化:服务器在执行完一个写命令后,以协议格式将写命令追加到服务器的AOF缓冲区的末尾,然后定期将缓冲区的数据写入 AOF 文件,保存到磁盘。
AOF 默认是不开启的,可以修改 redis.conf 来开启。
appendonly yes #开启AOF持久化
appendfsync everysec #每秒钟同步一次,默认策略
AOF重写
AOF重写是为了解决AOF文件过大的问题。重写过程是服务器进程 fork 一个子进程,保存服务器当前的数据库状态。
子进程重写期间,服务器进程需要执行以下三个工作:
-
处理用户请求
-
将写命令追加到现有的AOF文件
-
将写命令追加到AOF重写缓冲区(保证数据的一致性)
当子进程完成AOF重写后,向服务器进程发送一个信号。服务器进程将AOF重写缓冲区中的内容全部写入到新的AOF文件,并替换旧的文件。
-
通过rewriteaof命令重写AOF
-
通过配置文件参数 auto_aof_rewrite_min_size,auto_aof_rewrite_percent
选择 RDB 还是 AOF?
-
RDB 非常适合大规模的数据恢复,如果业务对数据一致性要求不高,RDB 是很好的选择,否则使用 AOF 方式。
-
如果想保证数据一致性,同时又希望保持高效率,可以同时使用 RDB 和 AOF 两种方式。启动服务时会优先加载 AOF 文件。
7. 内存淘汰策略
通过 redis.conf 中 maxmemory <bytes> 设置 Redis 的最大内存,或者 config set 命令在运行时动态配置 Redis 的内存。
当 Redis 使用内存达到 maxmemory,根据 maxmemory-policy 策略来淘汰数据,回收内存。
- volatile-lru
- allkeys-lru
- volatile-random
- allkeys-random
- volatile-ttl
- no-envicition 不淘汰 key,默认算法
8. 过期删除策略
key 的过期时间可以通过 set 设置 key 的时候指定,也可以通过 expire 命令指定。persist key 命令设置 key 永不过期。
- 定时删除:对于每一个设置了过期时间的 key 都会创建一个定时器,一旦到达过期时间就立即删除。
- 惰性删除:当访问一个 key 时,判断该 key 是否过期,过期则删除。
- 定期删除:每隔一段时间,扫描 Redis 中过期时间的 key,并清除部分过期的 key。
Redis 同时使用了定期删除和惰性删除。
9. redis-sentinel架构
(1)redis Master-Slave主从复制模式下,如果 Master 节点出现故障,Slave 节点无法自动切换成 Master,需要人工干预。redis-sentinel 是redis官方推荐的高可用性解决方案,它是一个独立运行的进程。多个 sentinel 进程协同工作,组成一套分布式的架构。监视相同 Master,Slave 的 Sentinel 通过 master 的发布/订阅消息机制来相互发现。
Sentinel 的作用:
-
Master 状态检测。
-
如果 Master 异常,则会进行 Master-Slave 切换,将其中一个 Slave 作为 Master,将之前的 Master 作为 Slave。
-
Master-Slave 切换后,master_redis.conf、slave_redis.conf 和 sentinel.conf 的内容都会发生改变,即 master_redis.conf 中会多一行 slaveof 的配置,sentinel.conf 的监控目标会随之调换。
(2)Sentinel 工作方式:
-
每个 Sentinel 以每秒一次的频率向 Master,Slave 以及其他 Sentinel 实例发送一个 PING 命令。
-
如果一个实例距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel 标记为主观下线。
-
如果 Master 被标记为主观下线,则正在监视 Master 的所有 Sentinel 要以每秒一次的频率确认 Master 进入了主观下线状态。
-
当有足够数量的 Sentinel 在指定的时间范围内确认 Master 进入了主观下线状态, 则 Master 会被标记为客观下线。
-
在一般情况下, 每个 Sentinel 会以 10 秒一次的频率向 Master,Slave 发送 INFO 命令。当 Master 被标记为客观下线时,Sentinel 向 Master,Slave 发送 INFO 命令的频率变为每秒一次。
-
若没有足够数量的 Sentinel 同意 Master 已经下线, Master 的客观下线状态就会被移除。若 Master 重新向 Sentinel 的 PING 命令返回有效回复, Master 的主观下线状态就会被移除。
主观下线(Subjectively Down,SDOWN),指的是单个 Sentinel 实例对某个 redis 服务器做出的下线判断。sentinel down-after-milliseconds <masterName> <timeout> 。
客观下线(Objectively Down, ODOWN),指的是多个 Sentinel 实例对 Master 做出 SDOWN 判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的 Master 下线判断,然后开启 failover。sentinel monitor <masterName> <ip> <port> <quorum>。
故障转移的触发条件是 Master 处于 ODOWN 状态。选举出一个 Sentinel 作为 leader,根据 Slave 与 Master 断开连接时长、优先级、复制量、run id等选出一个 Slave 来完成 failover。leader 发送 slaveof no one 命令到选出的 Slave,升级为 Master,并向其他 Slave 发送 slaveof <masterIP> <masterPort> 命令重新配置 Master。
客户端通过 Sentinel 获取 redis Master 地址:
(1)获取所有的 Sentinel 节点,遍历得到一个可用的 Sentinel 节点;
(2)在可用的 Sentinel 节点上执行 sentinel get-master-addr-by-name <MasterName> 命令来获取 Master 地址和端口号;
(3)获取到 Master 节点信息,执行 role 或者 info replication 命令验证节点;
(4)客户端订阅 Sentinel 频道,Master 节点变化后,Sentinel 发布频道消息通知客户端。
10. redis-cluster
-
无中心结构,所有节点彼此互联。
-
任一节点的fail是通过集群中超过半数的节点检测失效时才生效,最少需要三个节点。
- 任一节点失效,集群就不可用了,所以每个节点必须至少有一个 Slave 节点,故障转移时使用。
-
客户端连接集群任一可用节点即可。
-
集群把所有的物理节点映射到 [0-16383] 哈希槽上。
集群内置了 16384 个哈希槽,当需要存储一个 key/value 时,redis 先对 key 使用 CRC16 算法得到一个数值,再把这个数值对 16384 求余运算。这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 将哈希槽映射到不同的节点。