Redis使用总结

一、Redis介绍

1.Redis简介

Redis是一种key-value形式的nosql数据库。

Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。

Redis是C语言开发的,官方并不提供windows版本,所有的版本都是基于linux的。但是微软的一个团
队将redis移植到了windows,所以在Windows上也可以使用redis。

Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

2.Nosql介绍

  • NoSQL,泛指非关系型的数据库,NoSQL即Not-Only SQL,它可以作为关系型数据库的良好补充。随
    着互联网web2.0网站的兴起,非关系型的数据库现在成了一个极其热门的新领域,非关系数据库产品
    的发展非常迅速。
  • 应用方面
    • High performance - 对数据库高并发读写的需求
    • Huge Storage - 对海量数据的高效率存储和访问的需求
    • High Scalability && High Availability- 对数据库的高可扩展性和高可用性的需求
  • NoSQL数据库的四大分类
    • 键值(Key-Value)存储数据库
      • 相关产品: Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB
      • 典型应用: 内容缓存,主要用于处理大量数据的高访问负载。
      • 数据模型: 一系列键值对
    • 列存储数据库
      • 相关产品:Cassandra, HBase, Riak
      • 典型应用:分布式的文件系统
      • 数据模型:以列簇式存储,将同一列数据存在一起
    • 文档型数据库
      • 相关产品:CouchDB、MongoDB
      • 典型应用:Web应用(与Key-Value类似,Value是结构化的)
      • 数据模型: 一系列键值对
    • 图形(Graph)数据库
      • 相关数据库:Neo4J、InfoGrid、Infinite Graph
      • 典型应用:社交网络
      • 数据模型:图结构

3.Redis网站

redis官方下载地址:https://redis.io/download

redis中文版网址:https://www.redis.net.cn

redis官方下载地址redis-5.0.6版本:http://download.redis.io/releases/

4.使用场景

  • 缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)
  • 分布式集群架构中的session分离。
  • 聊天室的在线好友列表。
  • 任务队列。(秒杀、抢购、12306等等)
  • 应用排行榜。
  • 网站访问统计。
  • 数据过期处理(可以精确到毫秒)

二、Redis环境搭建

2.1(Linux mini版-CentOS 7)

1.下载安装gcc

redis是C语言开发,并且建议在linux上运行,。安装redis需要先将官网下载的源码进行编译,编译依赖gcc环境,如果没有gcc环境,需要gcc来安装编译环境。如果存在就不用安装了

> yum install gcc-c++ -y

2.wget文件下载工具

下载一些软件或从远程服务器恢复备份到本地服务器,wget 非常稳定,它在带宽很窄的情况下和不稳定网络中有很强的适应性.如果是由于网络的原因下载失败,wget会不断的尝试,直到整个文件下载完毕;如果是服务器打断下载过程,它会再次联到服务器上从停止的地方继续下载。这对从那些限定了链接时间的服务器上下载大文件非常有用。

> yum -y install wget

3.下载redis的源码

> wget http://download.redis.io/releases/redis-5.0.6.tar.gz

下载完的文件路径

> cd /

4.tar源码解压缩

> tar zxvf redis-5.0.6.tar.gz

5.编译源代码

源码编译后会得到redis的可执行文件

//切换路径
> cd redis-5.0.6
//编译
> make

6.安装到/usr/local/redis

make install PREFIX=/usr/local/redis

7.切换路径

切换到安装路径,看到如下文件则安装成功。

cd /usr/local/redis/bin

image-1662340696145

2.2(Windows版)

1.下载安装

2.解压即可使用

  • 解压路径:D:\software\DB\Redis\Redis-x64-3.2.100

3.启动服务

  • 双击运行redis-server.exe

4.启动客户端

  • 双击运行redis-cli.exe

三、Redis启动与关闭

3.1前端启动模式(不推荐)

缺点

  • 旧版本中ssh命令窗口关闭则redis-server程序结束
  • 最新版的redis并不会因为ssh连接的关闭而关闭,但是还是会占用ssh连接
  • 故此不推荐使用此方法

1.切换路径到安装路径

> cd /usr/local/redis/bin

2.启动服务

> ./redis-server

3.客户端连接

[root@localhost bin]# ./redis-cli 

//客户端开启后,输入ping,返回PONG就是连接成功
127.0.0.1:6379> ping
PONG

4.关闭服务

直接将ssh关闭并不能关闭服务,可以使用ctrl+c关闭服务

3.2守护进程模式(推荐)

  • 以守护进程模式启动的话需要redis.conf 配置文件
  • 在配置文件中设置redis 的启动模式
  • 从redis源码目录redis-5.0.6 中复制redis.conf 文件到/usr/local/redis/bin 目录下
  • 然后修改其中的配置信息

1.复制配置文件

赋值配置文件/redis-5.0.6/redis.conf到 /usr/local/redis/bin

[root@localhost redis-5.0.6]# cp /redis-5.0.6/redis.conf /usr/local/redis/bin

2.修改配置文件

发现vim命令无法使用

//切换到安装路径
[root@localhost redis-5.0.6]# cd /usr/local/redis/bin
//安装vim命令
[root@localhost bin]# yum install vim -y

修改为daemonize yes

[root@localhost bin]# vim redis.conf 

image-1662340780780

3.启动服务

[root@localhost bin]# ./redis-server redis.conf

4.启动服务成功

在当前的ssh窗口中仍然可以通过客户端访问
image-1662340798691

5.客户端访问

即redis-cli(Redis Command Line Interface),它是Redis自带的基于命令行的Redis客户端。

补充

  • 直接启动redis-cli 将默认连接运行在本机的6379端口的redis服务。可以使用-h 参数连接指定IP地址
    的服务, -p 参数指定服务运行的端口号。

  • 如果不是本机(127.0.0.1)需要修改redis.conf,将bind 127.0.0.1更改为bind 192.168.0.111(Redis服务器地址)。只要修改了bind中的值,protected-mode(redis.conf配置中的内容)保护模式就不起作用

    [root@localhost bin]# vim redis.conf
    
    bind 127.0.0.1修改为bind 192.168.0.111
    

语法:./redis-cli -h [IP地址] -p [端口号]

[root@localhost bin]# ./redis-cli

//客户端开启后,输入ping,返回PONG就是连接成功
127.0.0.1:6379> ping
PONG

6.关闭

守护模式可以使用kill 进程id 关闭

//查看进程id
[root@localhost bin]# ps -ef|grep redis

//结束进程
[root@localhost bin]# kill 6838

image-1662340824805
守护模式也可以使用客户./redis-cli shutdown 命令关闭

//先ctrl+c结束命令输入,再关闭redis
[root@localhost bin]# ./redis-cli shutdown

四、Redis桌面客户端

1.下载RedisDesktopManager

官方下载:https://redisdesktop.com/download

github地址:https://github.com/uglide/RedisDesktopManager/releases

2.安装

3.连接Redis服务器

  • 连接失败:原因是防火墙没有开放6379端口

image-1662340858182

  • 修改修改redis.conf

    [root@localhost bin]# vim redis.conf
    
  • 修改防火墙设置

    • 防火墙命令不能生效,需要安装

      yum install firewall -y
      
    • 关闭防火墙(上线不能关闭防火墙) / 开放6379端口。

      //方式一:关闭防火墙
      systemctl stop firewalld
      
      //方式二:开放6379端口
      	firewall-cmd --zone=public --add-port=6379/tcp --permanent
      	//重启防火墙
      	systemctl restart firewalld.service
      
  • RedisDesktopManager重新连接就可以了

五、Redis数据类型及命令

1.数据类型

  • 都是key-value形式的数据,key都是字符串,value分不同的数据类型
  • string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

1.1 String(字符串)

1.1.1 简介
  • string 是 redis 最基本的类型,可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
  • string 类型是二进制安全的。是 redis 的 string 可以包含任何数据。如jpg图片或者序列化的对象。
  • string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。
1.1.2 常用命令
SET key value
//设置指定 key 的值,有空格的时候需要添加 ' '
set name zhangsan
set name 'zhang san'

GET key
//获取指定 key 的值。
get name

DEL key
//删除指定 key 的值
del name

INCR key
//将 key 中储存的数字值增1,key对应的数据类型必须为数字
incr age

DECR key
//将 key 中储存的数字值减1,key对应的数据类型必须为数字
decr age

INCRBY key increment
//将 key 所储存的值加上给定的增量值(increment)
incrby age 5

DECRBY key increment
//将 key 所储存的值加上给定的减量值(increment)
decrby age 5

APPEND key value
//如果 key 已经存在并且是一个字符串, APPEND 命令将指定的 value 追加到该 key 原来值(value)的末尾
append name lisi

1.2 Hash(哈希)

1.2.1简介
  • hash叫散列类型,它提供了字段和字段值的映射。字段值只能是字符串类型,不支持散列类型、集合类
    型等其它类型。相当于一个key对应一个map。
  • hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象
  • Redis 中每个 hash 可以存储 2^32 - 1 键值对(40多亿)。
  • hash 中对应的field不能重复,重复了就会将value的值覆盖。
1.2.2常用命令
HSET key field value
//将哈希表 key 中的字段 field 的值设为 value 。
hset student name zhangsan
hset student age 20

HGET key field
//获取存储在哈希表中指定字段的值。
hget student name
hget student age

HDEL key field1 [field2]
//删除一个或多个哈希表字段
hdel student name age
hdel student name

HEXISTS key field
//查看哈希表 key 中,指定的字段是否存在。
hexists student age

HKEYS key
//获取所有哈希表中的字段
hkeys student

HVALS key
//获取哈希表中所有值
hvals student

HGETALL key
//获取在哈希表中指定 key 的所有字段和值
hgetall student

HINCRBY key field increment
//为哈希表 key 中的指定字段的整数值加上增量 increment(增量可以是负数)
hincrby student age 5

HLEN key
//获取哈希表中字段的数量
hlen student

HMGET key field1 [field2]
//获取所有给定字段的值(可以获取多个字段的值)
hmget student name age

HMSET key field1 value1 [field2 value2 ]
//同时将多个 field-value (域-值)对设置到哈希表 key 中
hmset student gradeId 1 gender man

HSETNX key field value
//只有在字段 field 不存在时,设置哈希表字段的值。
hsetnx student score 98

1.3 List(列表)

1.3.1简介
  • Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
  • 数据结构:双向链表,有序, 可以重复,插入效率低;类似java中LinkedList集合
  • 一个列表最多可以包含 2^32 - 1 个元素 (4294967295, 每个列表超过40亿个元素)
  • 从同一方向插入和取出就类似 先进先出的特点
  • 从左侧插入,从右侧取出,就实现了 队列 形式先进后出的特点
1.3.2常用命令
LPUSH key value1 [value2]
//将一个或多个值插入到列表头部
lpush name aaa   //存放1个值
lpush name aaa ccc ddd  //存放3个值

RPUSH key value1 [value2]
在列表中添加一个或多个值
rpush name aaa   //存放1个值
rpush name aaa ccc ddd  //存放3个值

LLEN key
//获取列表长度
llen name

LRANGE key start stop
//获取列表指定范围内的元素,0:第一个值  -1:结尾
lrange name 0 -1

LINDEX key index
//通过索引获取列表中的元素
lindex name 0

LPOP key
//移出并获取列表的第一个元素
lpop name

RPOP key
//移除列表的最后一个元素,返回值为移除的元素
rpop name

LPUSHX key value
//将一个值插入到已存在的列表头部
lpushx name ooo

LSET key index value
//通过索引设置列表元素的值
lset name 0 fff

LREM key count value
//移除列表元素
 count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
 count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
 count = 0 : 移除表中所有与 VALUE 相等的值。
lpush num 1 5 3 2 4 6 a b c 1 2 3 4
lrem num 1 3 //从左侧删除1个3
lrem num -1 3 //从右侧删除1个3
lrem num 0 3 //删除所有3

1.4 Set(集合)

1.4.1简介
  • Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
  • Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
  • 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。
  • 数据结构:无序,唯一,插入删除效率高;通过散列函数(hash)计算一个位置。
1.4.2常用命令
SADD key member1 [member2]
//向集合添加一个或多个成员
sadd name aaa ccc ddd

SMEMBERS key
//返回集合中的所有成员,返回结果是无序的
smembers name

SISMEMBER key member
//判断 member 元素是否是集合 key 的成员
sismembers name aaa

SREM key member1 [member2]
//移除集合中一个或多个成员
srem name aaa ccc

SCARD key
//获取集合的成员数
scard name

SDIFF key1 [key2]
//返回给定所有集合的差集,把集合元素多的放在前面
sadd name1 aaa ccc eee
sadd name2 aaa bbb ccc ddd eee
sdiff name2 name1

SINTER key1 [key2]
//返回给定所有集合的交集
sadd name1 aaa ccc eee
sadd name2 aaa bbb ccc ddd eee
sinter name1 name2

SUNION key1 [key2]
//返回所有给定集合的并集
sadd name1 aaa ooo fff
sadd name2 aaa bbb ccc ddd eee
sunion name1 name2

1.5 有序集合(sorted set) / Zset

1.5.1简介
  • Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
  • 不同的是每个元素都会关联一个double类型的分数。通过分数来为集合中的成员进行从小到大的排序。
  • 有序集合的成员是唯一的,但分数(score)却可以重复。
  • 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
  • 集合中最大的成员数为 2^32 - 1 (4294967295, 每个集合可存储40多亿个成员)。
1.5.2常用命令
ZADD key score1 member1 [score2 member2]
# 向有序集合添加一个或多个成员,或者更新已存在成员的分数
zadd name 20 zhangsan
zadd name 40 lisi
zadd name 10 wangwu

ZRANGE key start stop [WITHSCORES]
# 通过索引区间返回有序集合指定区间内的成员; WITHSCORES将分数也一起显示出来
zrange name 0 -1
zrange name 0 -1 withscores

ZRANK key member
# 返回有序集合中指定成员的索引
zrank name zhangsan

ZSCORE key member
# 返回有序集中,成员的分数值
zscore name zhangsan

ZCARD key
# 获取有序集合的成员数
zcard name

ZREM key member [member ...]
# 移除有序集合中的一个或多个成员
zrem name zhangsan lisi

ZCOUNT key min max
# 计算在有序集合中指定区间分数的成员数
zcount name 10 100

ZINCRBY key increment member
# 有序集合中对指定成员的分数加上增量 increment
zincreby name 15 zhangsan

2.通用服务器命令

  • 切换数据库:select [index]

    # 切换到第一个数据库,也是默认的数据库
    select 0
    
  • 查看当前数据库中的key:keys [partten]

    keys *
    
  • 删除key:del [key]

    del name
    
  • 查看key的数据类型:type [key]

    type name
    
  • 查看key是否存在:exists [key]

    exists name
    
  • 设置key的生存时间:expire [key] [seconds]

    //设置过期时间:3秒
    expire name 3
    
  • 设置 key 的过期时间以毫秒计:PEXPIRE [key]milliseconds

    expire name 1000
    
  • 移除 key 的过期时间,key 将持久保持:PERSIST [key]

  • 修改 key 的名称:RENAME [key] newkey

    rename name firstname
    
  • 清空当前数据库中的数据:flushdb

    flushdb
    
  • 删除所有数据库中的数据:flushall

    flushall
    

六、Redis消息模式

1.队列模式

  • 就是"传递消息的队列"。与任务队列进行交互的实体有两类,一类是生产者(producer),另一类则是消费者(consumer)。生产者将需要处理的任务放入任务队列中,而消费者则不断地从任务独立中读入任务信息并执行。

  • 使用Redis实现任务队列首先想到的就是Redis的列表类型,因为在Redis内部,列表类型是由双向链表实现的。

  • 实现任务队列,只需让生产者将任务使用LPUSH加入到某个键中,然后另一个消费者不断地使用RPOP命令从该键中取出任务即可。

image-1662340903363

1.1实现方式

方式一:

LPOP指令在队列为空时处于轮询状态。

  • 生产者
# 生产者只需将task LPUSH到队列中
127.0.0.1:6379> LPUSH queue aaa
(integer) 1
127.0.0.1:6379> LRANGE queue 0 -1
1) "aaa"
  • 消费者
# 消费者只需从队列中LPOP任务,如果为空则轮询。
127.0.0.1:6379> LPOP queue
"aaa"
方式二:

BLPOP指令可以在队列为空时处于阻塞状态。就不用处于轮询的状态。

  • 生产者

    # 生产者只需将aaa LPUSH到队列中
    127.0.0.1:6379> LPUSH queue aaa
    (integer) 1
    127.0.0.1:6379> LRANGE queue 0 -1
    1) "aaa"
    
  • 消费者

    127.0.0.1:6379> BLPOP queue 0   //0表示无限制等待
    //消费者当队列为空则处于阻塞状态。
    
  • 生产者

    # 生产者将bbb LPUSH到队列中,处于阻塞状态的消费者离开返回
    127.0.0.1:6379> LPUSH queue bbb
    (integer) 1
    
  • 消费者

    # 消费者立刻"消费",取出bbb。
    127.0.0.1:6379> BLPOP queue 0
    1) "queue"
    2) "task"
    

2.发布订阅模式

2.1发布订阅模式

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

Redis 客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
image-1662340920612

2.2实现步骤

  • 创建订阅频道,可以是多个客户端订阅相同频道(bdqn:频道名)

    ./redis-cli -h 192.168.0.111
    
    subscribe bdqn
    
  • 再重新开启个 redis 客户端,然后在同一个频道 bdqn 发布消息,订阅者就能接收到消息

    ./redis-cli -h 192.168.0.111
    
    public bdqn "this is message"
    

七、Redis持久化

Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,
需要将数据从内存中同步到硬盘中,这一过程就是持久化。Redis支持两种方式的持久化,一种是RDB
方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。

Redis 的持久化策略有两种:

  • **RDB:**快照形式是直接把内存中的数据保存到一个 dump 的文件中,定时保存,保存策略。
  • **AOF:**把所有的对 Redis 的服务器进行修改的命令都存到一个文件里,命令的集合。Redis 默认是快照 RDB 的持久化方式。

当 Redis 重启的时候,它会优先使用 AOF 文件来还原数据集,因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。你甚至可以关闭持久化功能,让数据只在服务器运行时存。

1.RDB模式

1.1工作原理

  • 当 Redis 需要做持久化时,Redis 会 fork 一个子进程,子进程将数据写到磁盘上一个临时 RDB 文件中。当子进程完成写临时文件后,将原来的 RDB 替换掉,这样的好处是可以 copy-on-write。

1.2优缺点

  • 优点:

    • 这种文件非常适合用于备份:比如,你可以在最近的 24 小时内,每小时备份一次,并且在每个月的每一天也备份一个 RDB 文件
    • 可以随时将数据集还原到不同的版本。RDB 非常适合灾难恢复。
  • 缺点:

    • 如果需要尽量避免在服务器故障时丢失数据,RDB模式不合适

1.3介绍

  • RDB方式的持久化是通过快照(snapshotting)完成的

  • 在间隔的时间内检测key对应值的变化,然后持久化

  • 默认 Redis 是会以快照"RDB"的形式将数据持久化到磁盘的一个二进制文件 dump.rdb。

  • 在redis.conf配置文件中默认有此下配置。

    #   In the example below the behaviour will be to save:
    #   after 900 sec (15 min) if at least 1 key changed(15分钟之后至少有1个key发生变化)
    #   after 300 sec (5 min) if at least 10 keys changed(5分钟之后至少有10个key发生变化)
    #   after 60 sec if at least 10000 keys changed(1分钟之后至少有10000个key发生变化)
     Note: you can disable saving completely by commenting out all "save" lines.
     (可以注释掉三行save,使保存点失效)
    #
    #   可以通过sava ""直接将以下的三行sava保存点全部删除。
    #   It is also possible to remove all the previously configured save
    #   points by adding a save directive with a single empty string argument
    #   like in the following example:
    
    #   save ""
    save 900 1
    save 300 10
    save 60 10000
    
  • 在redis.conf中配置dbfilenam指定rdb快照文件的名称(默认的名称dump.rdb)不用更改

    # The filename where to dump the DB
    dbfilename dump.rdb
    
  • 问题总结:
    通过RDB方式实现持久化,一旦Redis异常退出,就会丢失最后一次快照以后更改的所有数据。这就需
    要开发者根据具体的应用场合,通过组合设置自动快照条件的方式来将可能发生的数据损失控制在能够
    接受的范围。如果数据很重要以至于无法承受任何损失,则可以考虑使用AOF方式进行持久化。

1.4测试方式

  • 修改配置文件

    vim redis.conf
    
    # 测试的时候可以设置
    save 900 1
    save 300 10
    save 10 3
    
  • 在10s内多次执行写操作

    set name 111
    set name 222
    set name 333
    set name 444
    
  • 重启服务数据被保存下来

    ./redis-cli -h 192.168.0.111 shutdown  //关闭服务
    ./redis-server -h 192.168.0.111 //开启服务
    ./redis-cli -h 192.168.0.111 shutdown //客户端连接
    

2.AOF模式

2.1工作原理

  • 使用 AOF 做持久化,每一个写命令都通过 write 函数追加到 appendonly.aof 中
  • AOF 可以做到全程持久化,只需要在配置中开启 appendonly yes。这样 Redis 每执行一个修改数据的命令,都会把它添加到 AOF 文件中,当 Redis 重启时,将会读取 AOF 文件进行重放,恢复到 Redis 关闭前的最后时刻

2.2优缺点

  • 优点:

    • 可以设置不同的 Fsync 策略,AOF的默认策略是每秒钟 Fsync 一次,在这种配置下,就算发生故障停机,也最多丢失一秒钟的数据。
  • 缺点:

    • 对于相同的数据集来说,AOF 的文件体积通常要大于 RDB 文件的体积。
    • 根据所使用的 Fsync 策略,AOF 的速度可能会慢于 RDB。

2.3介绍

  • 默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启 appendonly yes

  • 开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。

  • AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的

  • 默认的文件名是appendonly.aof,可以通过appendfilename

    # Append Only File记录最后一次修改文件的方式,默认使用同步策略
    # The Append Only File is an alternative persistence mode that provides
    # much better durability. For instance using the default data fsync policy
    # (see later in the config file) Redis can lose just one second of writes in a
    # dramatic event like a server power outage, or a single write if something
    # wrong with the Redis process itself happens, but the operating system is
    # still running correctly.
    #
    # AOF and RDB persistence can be enabled at the same time without problems.
    # If the AOF is enabled on startup Redis will load the AOF, that is the file
    # with the better durability guarantees.
    #
    # Please check http://redis.io/topics/persistence for more information.
    
    appendonly yes
    
    # The name of the append only file (default: "appendonly.aof")
    appendfilename "appendonly.aof"
    
  • 默认情况下持久化操作说明:

    # The default is "everysec", as that's usually the right compromise between
    # speed and data safety. It's up to you to understand if you can relax this to
    # "no" that will let the operating system flush the output buffer when
    # it wants, for better performances (but if you can live with the idea of
    # some data loss consider the default persistence mode that's snapshotting),
    # or on the contrary, use "always" that's very slow but a bit safer than
    # everysec.
    #
    # More details please check the following article:
    # http://antirez.com/post/redis-persistence-demystified.html
    #
    # If unsure, use "everysec".
    
    # appendfsync always #每执行一个写命令就要写入文件并同步到磁盘
    appendfsync everysec #表示对写操作进行累积,每秒同步一次,在故障时只会丢失 1 秒钟的数据
    # appendfsync no     #将写命令缓冲到缓冲区,等待操作系统同步到磁盘
    

2.4测试方式

  • 开启aop持久化

    appendonly yes
    
  • 重启服务,执行写操作

    ./redis-cli -h 192.168.0.111 shutdown 
    ./redis-server -h 192.168.0.111
    set name zhangsan
    cat appendonly.aof
    

3.AOF文件重写

  • 记录最后一次的写操作,然后写入到文件,这样就可以对appendonly.aof文件优化。
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size grows by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (if no rewrite has happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
# AOF 自动重写
# 当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写
# 它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那么AOF大小使用初始大小)
# 基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动
# 同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况
# 设置 percentage 为0就关闭这个特性

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

4.两种方式的选择

  • 如果你非常关心数据,但仍然可以承受数分钟内的数据丢失,那么只能使用 RDB 持久。
  • AOF 将 Redis 执行的每一条命令追加到磁盘中,处理巨大的写入会降低Redis的性能。
  • 数据库备份和灾难恢复:定时生成 RDB 快照非常便于进行数据库备份,并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度快。
  • Redis 支持同时开启 RDB 和 AOF,系统重启后,Redis 会优先使用 AOF 来恢复数据,这样丢失的数据会最少。

八、Redis主从复制

8.1简介

  • 持久化保证了即使redis服务重启也会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到
    内存中,但是当redis服务器的硬盘损坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以
    避免这种单点故障。

    image-1662340963138
    解释:

  • 主redis中的数据有两个副本(replication)即从redis1和从redis2,即使一台redis服务器宕机其
    它两台redis服务也可以继续提供服务。

  1. 主redis中的数据和从redis上的数据保持实时同步,当主redis写入数据时通过主从复制机制会复制
    到两个从redis服务上。
  2. 只有一个主master,可以有多个从slave。主从复制不会阻塞master,在同步数据时,master 可以
    继续处理client 请求,一个redis可以即是主也可以是从

8.2实现步骤

  • 同一个虚拟机:/usr/local/redis/bin文件夹复制两份slave1,slave2
    image-1662340987245

  • slave1和slave2中修改配置文件redis.conf中 # replicaof 和自己的port端口

    # replicaof <masterip> <masterport>  指定master的ip和端口
    replicaof 192.168.0.111 6379
    
    # slave1自己的端口
    port 6381
    
    # replicaof <masterip> <masterport>  指定master的ip和端口
    replicaof 192.168.0.111 6379
    
    # slave2自己的端口
    port 6382
    
  • 分别启动master、slave1、slave2服务

    ./redis-server -h 192.168.0.111 -p 6379
    ./redis-server -h 192.168.0.111 -p 6381
    ./redis-server -h 192.168.0.111 -p 6382
    
    //可以查看架构中的主从情况
    info replication
    
  • master写入数据,slave中查看master中的数据

九、Redis哨兵机制

9.1简介

1.原因

  • Redis的主从复制模式下, 一旦主节点由于故障不能提供服务, 需要人工将从节点晋升为主节点, 同时还要通知应用方更新主节点地址, 很多应用场景这种故障处理的方式是无法接受的。 从2.8开始正式提供Redis Sentinel(哨兵)架构来解决这个问题。

2.哨兵机制

  • Sentinel(哨兵)进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用(HA),其已经被集成在redis2.6+的版本中,Redis的哨兵模式到了2.8版本之后就稳定了下来。哨兵(sentinel) 会不断地检查你的Master和Slave是否运作正常。当被监控的某Redis节点出现问题时, 哨兵(sentinel) 可以通过 API 向管理员或者其他应用程序发送通知。当一个Master不能正常工作时,哨兵(sentinel) 会开始一次自动故障迁移操作。
  • 可以完成以下工作:
    • 监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
    • 提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
    • 自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
      image-1662341005424

    3.监控过程

  1. 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
  2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-aftermilliseconds选项所指定的值,则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)。
  3. 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态。
  4. 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)。
  5. 在一般情况下, 每个Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  6. 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就被移除。

4.主观下线和客观下线

  1. 主观下线(Subjectively Down, 简称 SDOWN)和 客观下线(Objectively Down, 简称 ODOWN)
  2. sdown是主观下线,就一个哨兵如果自己觉得一个master宕机了
  3. odown是客观下线,如果quorum数量的哨兵都觉得一个master宕机了
  4. sdown达成的条件:如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就认为master主观下线
  5. odown达成的条件:如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那就认为master客观下线

5.quorum和majority

  1. quorum:确认odown的最少的哨兵数量
  2. majority:授权进行主从切换的最少的哨兵数量
  3. 每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个哨兵来做切换,这个哨兵还得得到majority哨兵的授权,才能正式执行切换
  4. 如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换,但是如果quorum >= majority,那么必须有quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换

6.为什么哨兵至少3个节点?

  • 哨兵集群必须部署2个以上节点。如果哨兵集群仅仅部署了个2个哨兵实例,那么它的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),如果其中一个哨兵宕机了,就无法满足majority>=2这个条件,那么在master发生故障的时候也就无法进行主从切换。

9.2实现步骤

1.sentinel.conf默认配置

# 设置端口
port 26379
# 是否守护进程启动
daemonize no
# 守护进程运行的时候需要保留pidfile
pidfile /var/run/redis-sentinel.pid
# 日志文件
logfile "/root/log/sentinel.log"
## sentinel monitor <master-name> <ip> <redis-port> <quorum>
## quorum的解释如下:
##(1)至少多少个哨兵要一致同意,master进程挂掉了,或者slave进程挂掉了,或者要启动一个故障
转移操作
## (2)quorum是用来识别故障的,真正执行故障转移的时候,还是要在哨兵集群执行选举,选举一个哨
兵进程出来执行故障转移操作
## (3)假设有5个哨兵,quorum设置了2,那么如果5个哨兵中的2个都认为master挂掉了; 2个哨兵中
的一个就会做一个选举,选举一个哨兵出来,执行故障转移; 如果5个哨兵中有3个哨兵都是运行的,那么
故障转移才会被允许执行。
# 原文是:Note that whatever is the ODOWN quorum, a Sentinel will require to
# be selected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
sentinel monitor mymaster 127.0.0.1 6379 3
# down-after-milliseconds,超过多少毫秒跟一个redis实例断了连接(ping不通),哨兵就可能认
为这个redis实例挂了

# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
# parallel-syncs,新的master别切换之后,同时有多少个slave被切换到去连接新master,重新做
同步,数字越低,花费的时间越多
# 比如:master宕机了,4个slave中有1个切换成了master,剩下3个slave就要挂到新的master上面
去
# 这个时候,如果parallel-syncs是1,那么3个slave,一个一个地挂接到新的master上面去,1个挂
接完,而且从新的master sync完数据之后,再挂接下一个。
# 如果parallel-syncs是3,那么一次性就会把所有slave挂接到新的master上去
sentinel parallel-syncs mymaster 1
#failover-timeout,执行故障转移的timeout超时时长,Default is 3 minutes.
sentinel failover-timeout mymaster 180000

2.搭建环境

  • 复制解压路径中的sentinel.conf到每一个redis实例

    cp /redis-5.0.6/sentinel.conf /usr/local/redis/master
    cp /redis-5.0.6/sentinel.conf /usr/local/redis/slave1
    cp /redis-5.0.6/sentinel.conf /usr/local/redis/slave2
    
  • 修改master中sentinel.conf的配置文件,启动哨兵进程

    # 设置端口(保持默认)
    port 26379
    
    ## sentinel monitor <master-name> <ip> <redis-port> <quorum>
    sentinel monitor mymaster 192.168.0.111 6379 2
    
    # sentinel down-after-milliseconds <master-name> <milliseconds> 改为3000ms(3s)
    sentinel down-after-milliseconds mymaster 3000
    
    ./redis-sentinel sentinel.conf
    
  • 修改slave1中sentinel.conf的配置文件,启动哨兵进程

    # 设置端口(保持默认)
    port 26381
    
    ## sentinel monitor <master-name> <ip> <redis-port> <quorum>
    sentinel monitor mymaster 192.168.0.111 6379 2
    
    # sentinel down-after-milliseconds <master-name> <milliseconds> 改为3000ms(3s)
    sentinel down-after-milliseconds mymaster 3000
    
    ./redis-sentinel sentinel.conf
    
  • 修改slave2中sentinel.conf的配置文件,启动哨兵进程

    # 设置端口(保持默认)
    port 26382
    
    ## sentinel monitor <master-name> <ip> <redis-port> <quorum>
    sentinel monitor mymaster 192.168.0.111 6379 2
    
    # sentinel down-after-milliseconds <master-name> <milliseconds> 改为3000ms(3s)
    sentinel down-after-milliseconds mymaster 3000
    
    ./redis-sentinel sentinel.conf
    

image-1662341034978

3.测试6379下线和重新上线

  • 模拟master宕机

    ./redis-cli -h 192.168.0.111 -p 6379 shutdown
    

    image-1662341046933
    模拟6379由管理员上线

./redis-server redis.conf

image-1662341069747

十、Redis集群

10.1 集群简介

  • Redis 集群是一个可以在多个 Redis 节点之间进行数据共享的设施(installation)。
  • Redis 集群不支持那些需要同时处理多个键的 Redis 命令, 因为执行这些命令需要在多个 Redis 节点之间移动数据, 并且在高负载的情况下, 这些命令将降低 Redis 集群的性能, 并导致不可预测的行为。
  • Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
  • Redis 集群提供了以下两个好处:
    • 将数据自动切分(split)到多个节点的能力。
    • 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续处理命令请求的能力。

10.2 集群数据共享

  • Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现: 一个 Redis 集群包含 16384 个哈希槽(hash slot), 数据库中的每个键都属于这 16384 个哈希槽的其中一个, 集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 keyCRC16 校验和

  • 集群中的每个节点负责处理一部分哈希槽。 举个例子, 一个集群可以有三个哈希槽, 其中:

    • 节点 A 负责处理 0 号至 5500 号哈希槽。
    • 节点 B 负责处理 5501 号至 11000 号哈希槽。
    • 节点 C 负责处理 11001 号至 16384 号哈希槽。
  • 如果用户将新节点 D 添加到集群中, 那么集群只需要将节点 A 、B 、 C 中的某些槽移动到节点 D 就可以了。

  • 与此类似, 如果用户要从集群中移除节点 A , 那么集群只需要将节点 A 中的所有哈希槽移动到节点 B 和节点 C , 然后再移除空白(不包含任何哈希槽)的节点 A 就可以了。

  • 因为将一个哈希槽从一个节点移动到另一个节点不会造成节点阻塞, 所以无论是添加新节点还是移除已存在节点, 又或者改变某个节点包含的哈希槽数量, 都不会造成集群下线

10.3redis-cluster架构图

image-1662341087434

10.4创建并使用 Redis 集群

1.说明

  • Redis 集群由多个运行在集群模式(cluster mode)下的 Redis 实例组成, 实例的集群模式需要通过配置来开启, 开启集群模式的实例将可以使用集群特有的功能和命令。
  • 以下是一个包含了最少选项的集群配置文件示例:
port 7000 #端口
cluster-enabled yes #启动集群模式
cluster-config-file nodes.conf #
cluster-node-timeout 5000
appendonly yes
  • 文件中的 cluster-enabled 选项用于开实例的集群模式, 而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf
  • 节点配置文件无须人为修改, 它由 Redis 集群在启动时创建, 并在有需要时自动进行更新。
  • 要让集群正常运作至少需要三个主节点**, 不过在刚开始试用集群功能时, 强烈建议使用六个节点: 其中三个为主节点, 而其余三个则是各个主节点的从节点。

2.环境准备

  • 1.复制多个Redis实例

    cp -rf /usr/local/redis/bin /usr/local/redis/cluster/redis1
    cp -rf /usr/local/redis/bin /usr/local/redis/cluster/redis2
    cp -rf /usr/local/redis/bin /usr/local/redis/cluster/redis3
    cp -rf /usr/local/redis/bin /usr/local/redis/cluster/redis4
    cp -rf /usr/local/redis/bin /usr/local/redis/cluster/redis5
    cp -rf /usr/local/redis/bin /usr/local/redis/cluster/redis6
    
  • 2.修改每一个Redis的配置文件redis.conf。为了好测试,6个redis实例的端口分别是6381~6386

    port 6379
    # 启动集群模式
    cluster-enabled yes
    
  • 3.创建脚本命令启动所有的redis实例

    # 在/usr/local/redis/cluster目录中添加startall.sh命令
    cd /usr/local/redis/cluster
    # 创建startall.sh
    touch startall.sh
    # 授予权限(执行权限)
    chmod +x startall.sh或者 chmod 777 startall.sh
    

    4.startall.sh文件中的内容

    cd redis1
    ./redis-server redis.conf
    cd ../redis2
    ./redis-server redis.conf
    cd ../redis3
    ./redis-server redis.conf
    cd ../redis4
    ./redis-server redis.conf
    cd ../redis5
    ./redis-server redis.conf
    cd ../redis6
    ./redis-server redis.conf
    
  • 5.启动redis实例

    //切换到脚本路径
    cd /usr/local/redis/cluster
    //启动所有redis服务
    ./startall.sh
    

3.创建集群

  • 创建集群

    # 选项 --replicas 1 表示我们希望为集群中的每个主节点(master)创建一个从(slave)。
    ./redis-cli --cluster create 192.168.0.111:6381 192.168.0.111:6382 192.168.0.111:6383 192.168.0.111:6384 192.168.0.111:6385 192.168.0.111:6386 --cluster-replicas 1
    
    # 选项 --replicas 1 表示我们希望为集群中的每个主节点(master)创建一个从(slave)。
    ./redis-cli --cluster create 192.168.0.102:6381 192.168.0.102:6382 192.168.0.102:6383 192.168.0.102:6384 192.168.0.102:6385 192.168.0.102:6386 --cluster-replicas 1
    

    容易出现的问题

image-1662341103739

  • 连接集群

随便找到一个redis实例,客户端连接。哨兵不需要配,连配置文件都不用复制,集群会自己管理。

./redis-cli -h 192.168.0.111 -p 6381

# 查看集群信息
cluster info  # 查看集群的信息
cluster nodes # 查看节点的详细信息

# 添加测试数据
192.168.0.111:6381> set name aaaa
	# 以上命令会产生提示(error) MOVED 5798 192.168.0.102:6382 #错误信息:

# 需要重新客户端连接,就不用管 数据插入到哪个master的槽中了
./redis-cli -h 192.168.0.111 -p 6381 -c

# 添加测试数据
192.168.0.111:6381> set name aaa
# -> Redirected to slot [5798] located at 192.168.0.102:6382  #会自动添加数据到指定的槽中

4.集群添加节点

  • 复制redis实例,配置端口6387,并启动实例

  • 添加redis实例到集群中

    # ./redis-cli --cluster add-node 新节点的ip:端口 现有集群ip:端口(集群中已经存在的任何一个都可以)
    ./redis-cli --cluster add-node 192.168.0.111:6387 192.168.0.111:6381
    
    # 登录客户端之后查看节点的信息,发现6387是个master,但是还没有分配槽。
    ./redis-cli -h 192.168.0.111 -p 6381 -c
    cluster nodes
    

    image-1662341130830
    给新添加的节点分配槽

–cluster-from:表示slot目前所在的节点的node ID,多个ID用逗号分隔;也可以从所有节点中分写all
–cluster-to:表示需要新分配节点的node ID
–cluster-slots:分配的slot数量

# 从指定节点分槽
./redis-cli --cluster reshard 192.168.0.111:6381 --cluster-from
2846540d8284538096f111a8ce7cf01c50199237,e0a9c3e60eeb951a154d003b9b28bbdc0be
67d5b,692dec0ccd6bdf68ef5d97f145ecfa6d6bca6132 --cluster-to
46f0b68b3f605b3369d3843a89a2b4a164ed21e8 --cluster-slots 4000

# 从所有节点分槽
./redis-cli --cluster reshard 192.168.0.111:6381 --cluster-from all --cluster-to
ff4c213f7fb4b13764487f2683c6f5c7aeb890f0 --cluster-slots 4000

image-1662341145064

  • 为该新节点添加slave

我们向集群中添加了一个新的节点6387,如果只有一个主节点的情况下,高可用性会下降。那么我们就应该给这个节点增加一个备份节点提高可用性。我们再添加一个节点6388,按照之前的配置方法配置,然后启动。

add-node: 后面的分别跟着新加入的slave、slave对应的master
–cluster-slave:表示加入的是slave节点
–cluster-master-id:表示slave对应的master的node ID

redis-cli --cluster add-node 192.168.0.111:6388 192.168.0.111:6387 --cluster-slave 
--cluster-master-id ff4c213f7fb4b13764487f2683c6f5c7aeb890f0
  • 测试

    ./redis-cli -h 192.168.0.111 -p 6387 -c
    
  • 测试哨兵是否自动配置

    # 模拟6387宕机
    kill -9 2401
    
    # 随便连接一个客户端,只要测试数据正常,就代表哨兵起作用了。
    ./redis-cli -h 192.168.0.102 -p 6388 -c
    # 重新查看下节点信息
    cluster nodes
    
    # 再模拟6387上线
    ./redis-server redis.conf
    # 随便连接一个客户端
    ./redis-cli -h 192.168.0.102 -p 6388 -c
    # 重新查看下节点信息,6387将会变成slave
    cluster nodes
    

image-1662341173435
image-1662341178130