Redis知识点总结

Redis

官网教程

一、源码安装

1.1下载

[root@redis-server ~]# wget https://download.redis.io/releases/redis-6.2.6.tar.gz

1.2安装

[root@redis-server ~]# tar -xf redis-6.2.6.tar.gz
[root@redis-server ~]# cd redis-6.2.6
[root@redis-server redis-6.2.6]# make && make install

1.3配置

分类

名称说明
NETWORK网络
GENERAL常规
SNAPSHOTTING快照
REPLICATION复制
SECURITY安全
CLIENTS客户端
MEMORY MANAGEMENT内存管理
[root@redis-server redis-6.2.6]# cp redis.conf /etc/
[root@redis-server redis-6.2.6]# cd ~
[root@redis-server ~]# vim /etc/redis.conf
# 默认端口6379,注意是TLS/SSL下面的
port 6379
# 绑定ip,如果是内网可以直接绑定 127.0.0.1, 或者忽略, 0.0.0.0是外网
bind 0.0.0.0
# 守护进程启动,即后台运行
daemonize yes
# 超时,0代表关闭
timeout 300
loglevel notice
# 日志文件
logfile /var/log/redis_6379.log
# 并发连接数量
maxclients 10000
# 数据库目录
dir /var/lib/redis/6379
# 分区
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
# 存储文件
dbfilename dump.rdb
# 密码 abcd123
requirepass abcd123

1.4启动

[root@redis-server ~] redis-server /etc/redis.conf
[root@redis-server ~]# netstat -ntulp | grep 6379

# 关闭,关闭的时候如果非6379,需要在shutdown前面加-p port,有密码的话需要加-a 密码
[root@redis-server ~]# redis-cli shutdown

#直接关闭不保存内存
[root@redis-server ~]# redis-cli shutdown nosave

二、使用

2.1 连接服务

# 连接数据库,-h可以指定ip,-p指定port,默认是本机ip,6379端口
[root@redis-server ~]# redis-cli -h 127.0.0.1  -p 6379

# 输入密码
127.0.0.1:6379> auth abcd123
OK

# 测试连接是否正常
127.0.0.1:6379> ping
PONG  # 表示正常

# 断开连接
127.0.0.1:6379> exit

2.2操作库

默认库编号0~15,默认进入的库是0,每个库的数据都是相关独立的

# 选择库格式:select 库编号
127.0.0.1:6379> select 1
127.0.0.1:6379[1]>

2.3操作变量

  • 存储数据
# 设置单个变量格式:set 变量名 值
127.0.0.1:6379> set name bhlu

# 设置多个变量格式:mset 变量名1 值1 变量名2 值2 ...
127.0.0.1:6379> mset name lulu age 24 addr wuxi

# 设置变量,如果变量存在就不替换,不存在则新建,默认是xx
127.0.0.1:6379> set addr wuxi nx
  • 查看数据
# 查看单个数据:get 变量名
127.0.0.1:6379> get name
"lulu"

# 查看多个数据:mget 变量名1 变量名2
127.0.0.1:6379> mget age addr
1) "24"
2) "wuxi"

# 查看变量类型
127.0.0.1:6379> type addr
string
  • keys使用
# 查看有没有该变量,有会返回变量,无返回(empty array)
127.0.0.1:6379> keys name
1) "name"

# 匹配:* --> 全部;? --> 一个字符
127.0.0.1:6379> keys *
1) "addr"
2) "name"
3) "age"

127.0.0.1:6379> keys ???
1) "age"
  • 移动变量
# 将age变量移动到1号库
127.0.0.1:6379> get age
"24"
127.0.0.1:6379> move age 1
(integer) 1
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get age
"24"
  • 判断变量是否存在
# 存在返回1
127.0.0.1:6379> exists name
(integer) 1
# 失败返回0
127.0.0.1:6379> exists aaa
(integer) 0
  • 设置变量存活时间,以及查看变量存活时间
# 设置变量超时时间,ex代表秒为单位,px代表毫秒为单位
127.0.0.1:6379> set age 25 ex 10
OK
127.0.0.1:6379> set addr wuxi px 10
OK

# 设置变量存活时间格式:expire 变量名 存活时间
127.0.0.1:6379> expire name 10
(integer) 1

# 查看变量存活时间格式:ttl 变量名
127.0.0.1:6379> ttl name
(integer) 6  # 还剩6s
127.0.0.1:6379> ttl name
(integer) 4  # 还剩4s
127.0.0.1:6379> ttl name
(integer) -2  # 不存活了
  • 查看变量类型
# 格式:type 变量名
127.0.0.1:6379> type addr
string
  • 删除变量
# 格式:del 变量名1 变量名2 ...
127.0.0.1:6379> del addr name

# 清空当前库的数据
127.0.0.1:6379> flushdb

# 清空所有库的数据
127.0.0.1:6379> flushall
  • 保存数据
# 因为1.3的配置文件,文件是存在/var/lib/redis/dump.rdb中的
127.0.0.1:6379> save

三、知识点

3.1内存清除策略

当内存空间不足,删除内存里已经存储的数据的方式
内存清除策略是软件的开发者写好的功能程序并定义的名称方便运维调用。
根据需要选择使用那种内存清除策略即可。

策略分类说明名称删除范围
LRU删除最近最少使用的volatile-lru针对设置了TTL的key
LRU删除最近最少使用的allkeys-lru针对所有的key
LFU删除使用频率最少的volatile-lfu针对设置了TTL的key
LFU删除使用频率最少的allkeys-lfu针对所有的key
RANDOM随机删除volatile-random针对设置了TTL的key
RANDOM随机删除allkeys-random针对所有的key
volatile-ttl删除快要过期的volatile-ttl针对所有的key
noeviction不删除noeviction针对所有的key
  • maxmemory:最大内存,字节为单位
  • maxmemory-policy:定义使用策略

3.2持久化存储

实现方式有2种:分别是 RDB文件AOF文件

  • RDB文件:指的就是数据库目录下的 dump.rdb 文件redis运行服务后,会根据配置文件的设置的存盘频率,把内存里的数据复制到数据库目录下的dump.rdb文件里(覆盖保存)
  • AOF文件:redis服务AOF文件(与mysql服务的binlog日志文件的功能相同)是一个文件,记录连接redis服务后执行的写操作命令并且是以追加的方式记录写操作命令,默认没有开启,使用需要人为启用。

RDB

# 查看配置文件存盘频率
[root@redis ~]# grep -n '^save' /etc/redis/6379.conf 
219:save 900 1  # 第219行,900秒内,有1个变量改变,就保存到dump.rdb文件中
220:save 300 10  # 第200行,300秒内,有10个变量改变,就保存到dump.rdb文件中
221:save 60 10000  # 第221行,60秒内,有100000个变量改变,就保存到dump.rdb文件中

# 这里为了更好的演示效果,将220行替换成save 120 10
# 2分钟内且有>=10个变量改变 就把内存里的数据复制到dump.rdb文件里
[root@redis ~]# redis-cli shutdown
[root@redis ~]# sed -i '220s/.*/save 120 10/' /etc/redis/6379.conf
[root@redis ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@redis ~]# redis-cli
127.0.0.1:6379> mset a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 j 9 k 10
OK
127.0.0.1:6379> exit
# 等待2分钟之后,备份文件
[root@redis ~]# grep "^dir" /etc/redis/6379.conf 
dir "/var/lib/redis/6379"
[root@redis ~]# cp /var/lib/redis/6379/dump.rdb .

# 清空数据
[root@redis ~]# redis-cli
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> keys *
(empty list or set)

# 恢复数据
[root@redis ~]# redis-cli shutdown
[root@redis ~]# cp ~/dump.rdb /var/lib/redis/6379/
cp: overwrite ‘/var/lib/redis/6379/dump.rdb’? y
[root@redis ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@redis ~]# redis-cli 
127.0.0.1:6379> mget a h j
1) "1"
2) "8"
3) "9"
  • 优点:高性能的持久化实现,创建一个子进程来执行持久化,先将数据写入临时文件,持久化过程结束后,再用这个临时文件替换上次持久化好的文件,整个过程中进场不进任何磁盘IO操作,适合大规模数据恢复,且对数据完整性要求不高的场景
  • 缺点:意外宕机时,丢失最后一次持久化的所有数据

AOF

[root@redis ~]# redis-cli
127.0.0.1:6379> config set appendonly yes  # 启动aof文件
OK
127.0.0.1:6379> config rewrite  # 保存配置
OK
127.0.0.1:6379> mset x 1 y 2 z 3
OK
127.0.0.1:6379> keys *
1) "x"
2) "z"
3) "y"
127.0.0.1:6379> exit

# 无需等待,直接复制
[root@redis ~]# cp /var/lib/redis/6379/appendonly.aof .
[root@redis ~]# redis-cli
127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> exit

# 恢复数据
[root@redis ~]# redis-cli shutdown
[root@redis ~]# cp ~/appendonly.aof /var/lib/redis/6379/
cp: overwrite ‘/var/lib/redis/6379/appendonly.aof’? y
[root@redis ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@redis ~]# redis-cli
127.0.0.1:6379> keys *
1) "z"
2) "x"
3) "y"
127.0.0.1:6379> exit

# 如果aof有问题,是可以修复的
[root@redis ~]# redis-cli shutdown
[root@redis ~]# echo 111 >> /var/lib/redis/6379/appendonly.aof
[root@redis ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@redis ~]# tail -1 /var/log/redis_6379.log 
3501:M 04 Jul 23:01:34.919 # Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>
[root@redis ~]# redis-check-aof --fix /var/lib/redis/6379/appendonly.aof 
...
Continue? [y/N]: y
Successfully truncated AOF
[root@redis ~]# /etc/init.d/redis_6379 start
/var/run/redis_6379.pid exists, process is already running or crashed
[root@redis ~]# rm -rf /var/run/redis_6379.pid 
[root@redis ~]# /etc/init.d/redis_6379 start
Starting Redis server...
[root@redis ~]# redis-cli
127.0.0.1:6379> keys *
1) "y"
2) "z"
3) "x"
127.0.0.1:6379> get x
"1"
  • 优点:可以灵活设置持久化方式,出现意外宕机时,仅可能丢失1秒的数据
  • 确定:持久化文件的体积通常会大于RDB方式,执行fsync策略时的速度可比RDB方式慢
  • 相关配置
    • appendfsync always:时时记录,并完成磁盘同步
    • appendfsync everysec:每秒记录一次,并完成磁盘同步
    • appendfsync no:写入aof ,不执行磁盘同步

3.3数据类型

字符类型

字符串:可以是英文字母或汉字

# 递增数字
127.0.0.1:6379> incr num
(integer) 1
# 递减数字
127.0.0.1:6379> decr num
(integer) 0

# 增加/减少指定整数
127.0.0.1:6379> incrby num 2
(integer) 2
127.0.0.1:6379> decrby num 5
(integer) -3

# 拼接字符串
127.0.0.1:6379> set addr wuxi
OK
127.0.0.1:6379> get addr
"wuxi"
127.0.0.1:6379> append addr " xinwu"
(integer) 10
127.0.0.1:6379> get addr
"wuxi xinwu"

# 查看字符串长度
127.0.0.1:6379> strlen addr
(integer) 10

# 切片
127.0.0.1:6379> getrange addr 0 -1
"wuxi xinwu"
127.0.0.1:6379> getrange addr 0 3
"wuxi"

列表类型

  • 列表类型(list)可以存储一个有序的字符串列表
  • 常用的操作是向列表两端添加元素,或者获得列表的某一个片段
  • 列表类型内部是使用双向链表(double linked list)实现的,获取越接近两端的元素速度就越快
  • 使用链表的代价是通过索引访问元素比较慢
  • 这里的列表有点像栈,先进后出
# LPUSH命令用来向列表左边增加元素,返回值表示增加元素后列表的长度
127.0.0.1:6379> lpush numbers 1 2 3
(integer) 3
127.0.0.1:6379> lpush numbers 4 5
(integer) 5

# LRANGE通过下标取出列表所有元素
127.0.0.1:6379> lrange numbers 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
127.0.0.1:6379> lrange numbers 0 2
1) "5"
2) "4"
3) "3"

# RPUSH命令用来向列表右边增加元素,返回值表示增加元素后列表的长度
127.0.0.1:6379> RPUSH numbers 111 222
(integer) 7
127.0.0.1:6379> lrange numbers 0 -1
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
6) "111"
7) "222"

# LPOP从列表左侧弹出元素,返回弹出的元素
127.0.0.1:6379> LPOP numbers
"5"
127.0.0.1:6379> lrange numbers 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "111"
6) "222"

# RPOP从列表右侧弹出元素,返回弹出的元素
127.0.0.1:6379> RPOP numbers
"222"
127.0.0.1:6379> lrange numbers 0 -1
1) "4"
2) "3"
3) "2"
4) "1"
5) "111"

# LLEN获取列表长度
127.0.0.1:6379> LLEN numbers
(integer) 5

# LINDEX获取列表指定索引的值
127.0.0.1:6379> LINDEX numbers 0
"4"
127.0.0.1:6379> LINDEX numbers -1
"111"

# LSET设置列表指定索引的值
127.0.0.1:6379> LSET numbers 0 444
OK
127.0.0.1:6379> LINDEX numbers 0
"444"

# LINSET 列表 BEFOR 已存在元素 要插入的元素:在指定元素前插入
127.0.0.1:6379> lrange numbers 0 -1
1) "444"
2) "3"
3) "2"
4) "1"
5) "111"
127.0.0.1:6379> LINSERT numbers BEFORE 444 333
(integer) 6
127.0.0.1:6379> lrange numbers 0 -1
1) "333"
2) "444"
3) "3"
4) "2"
5) "1"
6) "111"

# LINSET 列表 AFTER 已存在元素 要插入的元素:在指定元素后插入
127.0.0.1:6379> LINSERT numbers AFTER 444 555
(integer) 7
127.0.0.1:6379> lrange numbers 0 -1
1) "333"
2) "444"
3) "555"
4) "3"
5) "2"
6) "1"
7) "111"

Hash类型

  • 散列类型(hash)的键值也是一种字典结构,其存储了字段(field)和字段值的映射
  • 字段值只能是字符串
  • 散列类型适合存储对象。使用对象类别和 ID 构成键名,使用字段表示对象的属性,而字段值则存储属性值
# HSET设置单个值,MHSET设置多个值
127.0.0.1:6379> HSET user1 name bhlu
(integer) 1
127.0.0.1:6379> HMSET user2 name lulu addr wuxi
OK

# HGET获取单个值,HMGET获取多个值
127.0.0.1:6379> HGET user1 name
"bhlu"
127.0.0.1:6379> HMGET user2 name addr
1) "lulu"
2) "wuxi"

# HGETALL获取所有字段和值
127.0.0.1:6379> HGETALL user1
1) "name"
2) "bhlu"

# HKEYS获取所有字段,HVALS获取所有值
127.0.0.1:6379> HKEYS user2
1) "name"
2) "addr"
127.0.0.1:6379> HVALS user2
1) "lulu"
2) "wuxi"

# HEXISTS判断值是否存在,存在返回1,不存在返回0
127.0.0.1:6379> HEXISTS user2 name
(integer) 1
127.0.0.1:6379> HEXISTS user2 age
(integer) 0

# HSETNX当字段不存在就赋值,存在不操作,赋值成功返回1,赋值失败返回0
127.0.0.1:6379> HSETNX user2 age 24
(integer) 1
127.0.0.1:6379> HSETNX user2 age 222
(integer) 0
127.0.0.1:6379> HGET user2 age
"24"

# HINCRBY数字递增
127.0.0.1:6379> HINCRBY user2 age 2
(integer) 26
127.0.0.1:6379> HGET user2 age
"26"

# HDEL删除字段
127.0.0.1:6379> HDEL user2 age
(integer) 1
127.0.0.1:6379> HKEYS user2
1) "name"
2) "addr"

# HLEN获取字段数量
127.0.0.1:6379> HLEN user2
(integer) 2

集合类型

  • 集合中的每个元素都是不同的
  • 无序集合:没有顺序
# SADD增加元素,SMEMBERS查看所有元素,SREM删除元素
127.0.0.1:6379> SADD names bhlu lulu maomao 
(integer) 3
127.0.0.1:6379> SMEMBERS names
1) "maomao"
2) "bhlu"
3) "lulu"
127.0.0.1:6379> SREM names lulu maomao
(integer) 2
127.0.0.1:6379> SMEMBERS names
1) "bhlu"

# SISMEMBER判断元素是否在集合中,存在返回1,不存在返回0
127.0.0.1:6379> SISMEMBER names bhlu
(integer) 1
127.0.0.1:6379> SISMEMBER names lulu
(integer) 0

# 集合运算,SINTER交集,SUNION并集,SDIFF差集
127.0.0.1:6379> SADD s1 a b c
(integer) 3
127.0.0.1:6379> SADD s2 b c d
(integer) 3
127.0.0.1:6379> SINTER s1 s2
1) "c"
2) "b"
127.0.0.1:6379> SUNION s1 s2
1) "b"
2) "c"
3) "a"
4) "d"
127.0.0.1:6379> SDIFF s1 s2
1) "a"
127.0.0.1:6379> SDIFF s2 s1
1) "d"

# SCARD获取集合中元素的个数
127.0.0.1:6379> SCARD s1
(integer) 3

# SRANDMEMBER随机获取集合中的元素,count为正数不会取出相同的值,count为负数可能取出相同的值
127.0.0.1:6379> SRANDMEMBER s1 
"b"
127.0.0.1:6379> SRANDMEMBER s1 2
1) "a"
2) "c"
127.0.0.1:6379> SRANDMEMBER s1 6
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> SRANDMEMBER s1 -5
1) "a"
2) "a"
3) "a"
4) "a"
5) "b"

# SPOP随机弹出一个元素,返回弹出的那个元素
127.0.0.1:6379> SPOP s1
"a"
  • 有序集合
    • 在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数
    • 通过这个分数,使我们不仅可以进行无序集合的操作,还可以进行指定分数范围元素的操作
    • 虽然集合中每个元素都是不同的,但是它们的分数却可以相同
    • 有序集合和列表是相似的,但是底层实现是不同的。
    • 列表是通过链表,越靠近两端的数据获取越快,而有序集合是使用散列表和跳跃表实现的,所以越考中间的数据获取越快;列表无法简单调整某个元素的位置,但是有序集合可以;有序集合要比列表类型更耗内存
# ZADD添加元素,ZADD key score1 member1 score2 member2
127.0.0.1:6379> ZADD len 178 bhlu 40 maomao 160 lulu
(integer) 3

# ZRANGE通过访问查看元素,加WITHSCORES就也显示score
127.0.0.1:6379> ZRANGE len 0 -1
1) "maomao"
2) "lulu"
3) "bhlu"
127.0.0.1:6379> ZRANGE len 0 -1 WITHSCORES
1) "maomao"
2) "40"
3) "lulu"
4) "160"
5) "bhlu"
6) "178"

# ZSCORE查看指定元素的分数
127.0.0.1:6379> ZSCORE len bhlu
"178"

# ZRANGEBYSCORE查看指定分数范围的元素
127.0.0.1:6379> ZRANGEBYSCORE len 140 180
1) "lulu"
2) "bhlu"
127.0.0.1:6379> ZRANGEBYSCORE len 140 180 WITHSCORES
1) "lulu"
2) "160"
3) "bhlu"
4) "178"

# ZINCRBY增加元素的分数
127.0.0.1:6379> ZINCRBY len 3 maomao
"43"
127.0.0.1:6379> ZSCORE len maomao
"43"

# 查看集合中元素的个数
127.0.0.1:6379> ZCARD len
(integer) 3

# ZCOUNT查看指定分数范围的元素个数
127.0.0.1:6379> ZCOUNT len 140 189
(integer) 2

# ZREM删除元素
127.0.0.1:6379> ZREM len lulu
(integer) 1

# ZRANK查看元素的排名,升序排列
127.0.0.1:6379> ZRANK len maomao
(integer) 0

# ZREVRANK查看元素的排名,降序排列
127.0.0.1:6379> ZREVRANK len maomao
(integer) 1

四、案例

下面的示例我都是用的redis-4.0.8版本

4.1集群

环境准备

节点服务器系统主机名IP地址安装服务及工具
ClientCentos7.9(64位)test-server192.168.88.2redis-cli
Manager服务器Centos7.9(64位)manager192.168.88.10redis-trib.rb
redis1服务器Centos7.9(64位)redis1192.168.88.11redis-4.0.8
redis2服务器Centos7.9(64位)redis2192.168.88.12redis-4.0.8
redis3服务器Centos7.9(64位)redis3192.168.88.13redis-4.0.8
redis4服务器Centos7.9(64位)redis4192.168.88.14redis-4.0.8
redis5服务器Centos7.9(64位)redis5192.168.88.15redis-4.0.8
redis6服务器Centos7.9(64位)redis6192.168.88.16redis-4.0.8

配置manager服务器到各个节点的免密,方便统一安装软件,修改配置文件

[root@manager ~]# for i in {1..6}; do echo "192.168.88.1$i redis$i" >> /etc/hosts; done
[root@manager ~]# ssh-keygen
# 一直回车
[root@manager ~]# for server in redis{1..6}; do ssh-copy-id root@$server; done

配置nfs挂载,安装包挂载到/data下

[root@manager ~]# for server in redis{1..6}; do ssh root@$server "mkdir /data && mount fs:/data /data"; done

配置redis服务器

安装redis

# 这里我提前已经解压好了,在fs中
[root@manager ~]# for server in redis{1..6}; do ssh root@$server "cd /data/redis-4.0.8 && make && make install"; done

[root@manager ~]# for server in redis{1..6}; do ssh root@$server "bash /data/redis-4.0.8/utils/install_server.sh"; done
# 一直回车默认即可

配置redis

# 首先关闭redis
[root@manager ~]# for server in redis{1..6}; do ssh root@$server "/etc/init.d/redis_6379 stop"; done
# 这里我写了个简单的脚本放在挂载的/data/conf.sh
[root@manager ~]# vim /data/conf_redis.sh
#!/bin/bash

IP=$(ifconfig eth0 | grep "inet " | awk '{print $2}')
# 启用集群功能
sed -i '/cluster-enabled yes/ccluster-enabled yes' /etc/redis/6379.conf
# 设置绑定本机IP
sed -i "/^bind/cbind $IP" /etc/redis/6379.conf
# 保存集群信息的配置文件
sed -i '/cluster-config-file nodes-6379.conf/ccluster-config-file nodes-6379.conf' /etc/redis/6379.conf
# 集群中主机的连接超时时间
sed -i '/cluster-node-timeout 15000/ccluster-node-timeout 5000' /etc/redis/6379.conf

# 批量运行脚本
[root@manager ~]# for server in redis{1..6}; do ssh root@$server "bash /data/conf_redis.sh"; done

# 启动服务
[root@manager ~]# for server in redis{1..6}; do ssh root@$server "/etc/init.d/redis_6379 start"; done

# 查看服务,显示两个服务说明启动成功
[root@manager ~]# for server in redis{1..6}; do ssh root@$server "echo $server && netstat -ntulp | grep redis-server "; done
# tcp        0      0 192.168.88.16:16379     0.0.0.0:*               LISTEN      1485/redis-server 1 
# tcp        0      0 192.168.88.16:6379      0.0.0.0:*               LISTEN      1485/redis-server 1 

配置manager服务器

[root@manager ~]# yum install rubygems ruby -y
[root@manager ~]# gem install /data/redis-3.2.1.gem
[root@manager ~]# cp /data/redis-4.0.8/src/redis-trib.rb /usr/local/bin/
[root@manager ~]# chmod +x /usr/local/bin/redis-trib.rb 
# 测试是否成功
[root@manager ~]# redis-trib.rb help

创建集群

命令格式:redis-trib.rb create --replicas 每个主服务器的从服务器台数 ip地址:端口 ip地址:端口 ip地址:端口 ....

# 这里一共6台服务器,3主3从
[root@manager ~]# redis-trib.rb create --replicas 1 192.168.88.11:6379 192.168.88.12:6379 192.168.88.13:6379 192.168.88.14:6379 192.168.88.15:6379 192.168.88.16:6379
...
Can I set the above configuration? (type 'yes' to accept): yes
...
[OK] All 16384 slots covered

查看集群状态

格式:redis-trib.rb check 任意节点ip:端口

[root@manager ~]# redis-trib.rb check 192.168.88.11:6379
[root@manager ~]# redis-trib.rb check 192.168.88.12:6379
[OK] All 16384 slots covered.

查看集群信息格式:redis-trib.rb info 任意节点ip:端口

[root@manager ~]# redis-trib.rb info 192.168.88.12:6379
[OK] 0 keys in 3 masters.

存储数据

连接格式:redis-cli -c -h 任意节点ip -p 端口(这里-c一定要加)

# 这里存放数据是根据hash值存放到各服务器上
[root@test-server ~]# redis-cli -c -h 192.168.88.11
192.168.88.11:6379> keys *
(empty array)
192.168.88.11:6379> 
192.168.88.11:6379> set a 1
-> Redirected to slot [15495] located at 192.168.88.13:6379
OK
192.168.88.13:6379> set b 2
-> Redirected to slot [3300] located at 192.168.88.11:6379
OK
192.168.88.11:6379> set c 3
-> Redirected to slot [7365] located at 192.168.88.12:6379
OK
192.168.88.12:6379> set d 4
-> Redirected to slot [11298] located at 192.168.88.13:6379
OK
192.168.88.13:6379> set e 5
OK
192.168.88.13:6379> keys *
1) "a"
2) "e"
3) "d"
192.168.88.13:6379> get b
-> Redirected to slot [3300] located at 192.168.88.11:6379
"2"

测试其中一台主服务器故障

[root@manager ~]# redis-trib.rb check 192.168.88.11:6379 | grep 'M:'
# 找到pid然后kill掉,我这边使用/etc/init.d/redis_6379 stop发现关不掉
[root@redis3 ~]# ps -ef | grep redis-server

# 再次观察,发现slave顶上来了
[root@manager ~]# redis-trib.rb check 192.168.88.11:6379 | grep 'M:'

# 查看keys有没有少
[root@manager ~]# redis-trib.rb info 192.168.88.11:6379

添加服务器

如果挂的redis3修复好了,会自动加入到集群,所以这里需要准备一个新的redis服务器

节点服务器系统主机名IP地址安装服务及工具
redis7Centos7.9(64位)redis7192.168.88.17redis-4.0.8
redis8Centos7.9(64位)redis8192.168.88.18redis-4.0.8

准备新服务器环境

[root@manager ~]# echo -e "192.168.88.17 redis7\n192.168.88.18 redis8" >> /etc/hosts
[root@manager ~]# ssh-copy-id root@redis7
[root@manager ~]# ssh-copy-id root@redis8
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "mkdir /data && mount fs:/data /data"; done
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "cd /data/redis-4.0.8 && make && make install"; done
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "bash /data/redis-4.0.8/utils/install_server.sh"; done
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "/etc/init.d/redis_6379 stop"; done
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "bash /data/conf_redis.sh"; done
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "/etc/init.d/redis_6379 start"; done
[root@manager ~]# for server in redis{7..8}; do ssh root@$server "echo $server && netstat -ntulp | grep redis-server"; done
redis7
tcp        0      0 192.168.88.17:6379      0.0.0.0:*               LISTEN      1608/redis-server 1 
tcp        0      0 192.168.88.17:16379     0.0.0.0:*               LISTEN      1608/redis-server 1 
redis8
tcp        0      0 192.168.88.18:16379     0.0.0.0:*               LISTEN      1514/redis-server 1 
tcp        0      0 192.168.88.18:6379      0.0.0.0:*               LISTEN      1514/redis-server 1 

添加redis主服务器redis7,命令格式:redis-trib.rb add-node 新服务器ip:端口 集群内任意主机ip:端口

[root@manager ~]# redis-trib.rb add-node 192.168.88.17:6379 192.168.88.11:6379
[OK] New node added correctly.
# 但是看到新添加的主服务器是没有hash slots,没有hash slots就没有存储机会
[root@manager ~]# redis-trib.rb info 192.168.88.11:6379

分配hash slots给新的主机,上面创建集群结束的时候或者check的时候,都会显示一共有多少个hash slots
命令格式:redis-trib.rb reshard 集群内任意主机ip:端口

# 这里是16384  /4=4096
[root@manager ~]# redis-trib.rb check 192.168.88.11:6379
[OK] All 16384 slots covered.

[root@manager ~]# redis-trib.rb reshard 192.168.88.12:6379
# 移除多少个hast slots
How many slots do you want to move (from 1 to 16384)? 4096
# 把4096个槽给哪台主数据库服务器 (新主机的id)
What is the receiving node ID? 0afd2591d19a7f1b1bd95cc92bf5f0714cbd5571  # 新主机的节点ID
# 提供4096个槽 主机的id (all 表示当前所有主服务器一起提供4096个槽给新主机)
Source node #1:all
# 确认前3步的配置 yes 同意 no 退出
Do you want to proceed with the proposed reshard plan (yes/no)? yes

[root@manager ~]# redis-trib.rb info 192.168.88.14:6379
192.168.88.14:6379 (853bdcbc...) -> 2 keys | 4096 slots | 1 slaves.
192.168.88.11:6379 (112e39ab...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.12:6379 (f113038e...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.17:6379 (0afd2591...) -> 1 keys | 4096 slots | 0 slaves.
[OK] 5 keys in 4 masters.
0.00 keys per slot on average.

测试插入数据,可不可以存储到新的服务器中

[root@test-server ~]# redis-cli -c -h 192.168.88.11
192.168.88.11:6379> set h 11
-> Redirected to slot [11694] located at 192.168.88.17:6379
OK
192.168.88.17:6379> set name aa
OK
192.168.88.17:6379> set age 25
OK
192.168.88.17:6379> set addr wuxi
-> Redirected to slot [12790] located at 192.168.88.14:6379
OK

[root@manager ~]# redis-trib.rb info 192.168.88.14:6379
192.168.88.14:6379 (853bdcbc...) -> 3 keys | 4096 slots | 1 slaves.
192.168.88.11:6379 (112e39ab...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.12:6379 (f113038e...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.17:6379 (0afd2591...) -> 4 keys | 4096 slots | 0 slaves.
[OK] 9 keys in 4 masters.
0.00 keys per slot on average.

添加redis8到集群中,命令格式:redis-trib.rb add-node --slave 新服务器ip:端口 集群内任意主机ip:端口

[root@manager ~]# redis-trib.rb add-node --slave 192.168.88.18:6379 192.168.88.11:6379
# 会自动成功redis7的从
[root@manager ~]# redis-trib.rb info redis1:6379
redis1:6379 (112e39ab...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.17:6379 (0afd2591...) -> 4 keys | 4096 slots | 1 slaves.
192.168.88.12:6379 (f113038e...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.14:6379 (853bdcbc...) -> 3 keys | 4096 slots | 1 slaves.
[OK] 9 keys in 4 masters.
0.00 keys per slot on average.

移除服务器

命令格式:redis-trib.rb del-node 集群中任意主机的Ip:端口 被移除主机的id

# 首先移除一个从服务器,因为直接移除主服务器是不行的,需要将hash slots分给其他主机
[root@manager ~]# redis-trib.rb check redis1:6379 | grep 192.168.88.18
S: 77e38a8a919c2f28ec138e64883d7d7e8f86080e 192.168.88.18:6379

[root@manager ~]# redis-trib.rb del-node redis8:6379 77e38a8a919c2f28ec138e64883d7d7e8f86080e
>>> Removing node 77e38a8a919c2f28ec138e64883d7d7e8f86080e from cluster redis8:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

# 移除之后redis8上redis服务会自动关闭
[root@manager ~]# ssh redis8 "netstat -ntulp | grep redis-server"

移除主服务器,移除之前需要将hash slots释放掉,命令格式:redis-trib.rb reshard 集群中任意主机ip:端口

[root@manager ~]# redis-trib.rb check redis1:6379 | grep 192.168.88.17
M: 0afd2591d19a7f1b1bd95cc92bf5f0714cbd5571 192.168.88.17:6379
[root@manager ~]# redis-trib.rb reshard 192.168.88.11:6379
# 释放hash slots的个数
How many slots do you want to move (from 1 to 16384)?
# 接收这些hash slots的个数,这里没法平均分配,所以填任意主服务器就行,不要填要移除的那个
What is the receiving node ID? 112e39abbdc2f817a0afa96839cfac45231056b1
# 从哪台主服务器上移除
Source node #1:0afd2591d19a7f1b1bd95cc92bf5f0714cbd5571
Source node #2:done  # 结束
# 是否同意之前的操作
Do you want to proceed with the proposed reshard plan (yes/no)? yes

# 可以看到要删的那个主服务器的hash slots全部分配给其他服务器了
[root@manager ~]# redis-trib.rb info 192.168.88.11:6379
192.168.88.11:6379 (112e39ab...) -> 5 keys | 8192 slots | 1 slaves.
192.168.88.17:6379 (0afd2591...) -> 0 keys | 0 slots | 0 slaves.
192.168.88.12:6379 (f113038e...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.14:6379 (853bdcbc...) -> 3 keys | 4096 slots | 1 slaves.
[OK] 9 keys in 4 masters.
0.00 keys per slot on average.

# 进行删除
[root@manager ~]# redis-trib.rb del-node 192.168.88.17:6379 0afd2591d19a7f1b1bd95cc92bf5f0714cbd5571
>>> Removing node 0afd2591d19a7f1b1bd95cc92bf5f0714cbd5571 from cluster 192.168.88.17:6379
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.

[root@manager ~]# redis-trib.rb info 192.168.88.11:6379
192.168.88.11:6379 (112e39ab...) -> 5 keys | 8192 slots | 1 slaves.
192.168.88.12:6379 (f113038e...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.14:6379 (853bdcbc...) -> 3 keys | 4096 slots | 1 slaves.
[OK] 9 keys in 3 masters.
0.00 keys per slot on average.

平均分配hash slots

命令格式:redis-trib.rb rebalance 集群内任意节点IP:端口

[root@manager ~]# redis-trib.rb info 192.168.88.11:6379
192.168.88.11:6379 (112e39ab...) -> 5 keys | 8192 slots | 1 slaves.
192.168.88.12:6379 (f113038e...) -> 1 keys | 4096 slots | 1 slaves.
192.168.88.14:6379 (853bdcbc...) -> 3 keys | 4096 slots | 1 slaves.
[OK] 9 keys in 3 masters.
0.00 keys per slot on average.

# 平均分配
[root@manager ~]# redis-trib.rb rebalance 192.168.88.11:6379

[root@manager ~]# redis-trib.rb info 192.168.88.11:6379
192.168.88.11:6379 (112e39ab...) -> 4 keys | 5461 slots | 1 slaves.
192.168.88.12:6379 (f113038e...) -> 2 keys | 5462 slots | 1 slaves.
192.168.88.14:6379 (853bdcbc...) -> 3 keys | 5461 slots | 1 slaves.
[OK] 9 keys in 3 masters.
0.00 keys per slot on average.

添加从服务器到指定主服务器

命令格式:redis-trib.rb add-node --slave --master-id 主服务器ID 新服务器IP:端口 集群中任意服务器IP:端口

[root@manager ~]# redis-trib.rb add-node --slave --master-id 112e39abbdc2f817a0afa96839cfac45231056b1 192.168.88.18:6379 192.168.88.11:6379

常见问题

  1. 添加服务器的时候,不小心添加错了,然后删掉之后,再次添加会出现这个错误

[ERR] Node 192.168.88.xx:6379 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
连接192.168.88.xx的主机的redis,输入cluster reset,使用keys *查看是否有数据,如果有数据,还需要输入flushall,然后再次连接即可

  1. 因为安装redis之后,它会自己启动,需要手动关闭,然后再去修改配置文件,再启动
  2. 在创建集群的时候,如果失败,可以rm -rf var/lib/redis/6379/*,然后重新安装即可

4.2主从复制

工作原理

第1步:slave向master发送sync命令
第2步:master启动后台存盘进程,并收集所有修改数据命令
第3步:master完成后台存盘后,传送整个数据文件到slave
第4步:slave接收数据文件,加载到内存中完成首次完全同步,后续有新数据产生时,master继续收集数据修改命令依次传给slave,完成同步

  • 常用命令介绍
info replication  # 查看复制信息
slave of 主服务器IP 主服务器端口  # 添加本机成为主服务器的从服务器
config rewrite  # 保存到配置文件
slaveof no one  # 临时恢复为主服务器,想要永久需保存到配置文件
config set requirepass xxxxx  # 临时设置密码,想要永久需保存到配置文件
config get requirepass  # 查看密码
auth xxxxxx  # 输入密码
config set masterauth xxxxxx  # 设置连接master服务器密码
config get masterauth  # 获取master连接密码

配置一主一从

节点服务器系统主机名IP地址安装服务及工具
MasterCentos7.9(64位)redis1192.168.88.11redis-4.0.8
SlaveCentos7.9(64位)redis2192.168.88.12redis-4.0.8
  • Master
[root@redis1 ~]# cd /data/redis-4.0.8/
[root@redis1 redis-4.0.8]# make && make install
[root@redis1 redis-4.0.8]# ./utils/install_server.sh 
# 一直回车默认即可
[root@redis1 redis-4.0.8]# /etc/init.d/redis_6379 stop
[root@redis1 redis-4.0.8]# sed -i '/^bind/cbind 192.168.88.11' /etc/redis/6379.conf
[root@redis1 redis-4.0.8]# /etc/init.d/redis_6379 start
[root@redis1 redis-4.0.8]# redis-cli -h 192.168.88.11
192.168.88.11:6379> ping
PONG
# 查看本机角色
192.168.88.11:6379> info replication
role:master
connected_slaves:0
  • Slave
[root@redis2 ~]# cd /data/redis-4.0.8/
[root@redis2 redis-4.0.8]# make && make install
[root@redis2 redis-4.0.8]# ./utils/install_server.sh
[root@redis2 redis-4.0.8]# /etc/init.d/redis_6379 stop
[root@redis2 redis-4.0.8]# sed -i '/^bind/cbind 192.168.88.12' /etc/redis/6379.conf
[root@redis2 redis-4.0.8]# /etc/init.d/redis_6379 start
[root@redis2 redis-4.0.8]# redis-cli -h 192.168.88.12
192.168.88.12:6379> ping
PONG
# 设置主服务器
192.168.88.12:6379> slaveof 192.168.88.11 6379
OK
192.168.88.12:6379> info replication
role:slave
master_host:192.168.88.11
# 将配置写到配置文件中
192.168.88.12:6379> CONFIG REWRITE
OK
192.168.88.12:6379> exit
[root@redis2 redis-4.0.8]# tail -1 /etc/redis/6379.conf 
slaveof 192.168.88.11 6379
  • Master
[root@redis1 redis-4.0.8]# redis-cli -h 192.168.88.11
192.168.88.11:6379> info replication
role:master
connected_slaves:1
slave0:ip=192.168.88.12,port=6379,state=online,offset=210,lag=0

测试数据是否能够同步

# Master存数据
192.168.88.11:6379> mset a 1 b 2 c 3
OK

# Slave读数据
192.168.88.12:6379> get a
"1"
192.168.88.12:6379> get b
"2"
192.168.88.12:6379> get c
"3"

配置一主多从

在上面一主一从的基础上,再准备一个redis服务器

节点服务器系统主机名IP地址安装服务及工具
MasterCentos7.9(64位)redis1192.168.88.11redis-4.0.8
Slave1Centos7.9(64位)redis2192.168.88.12redis-4.0.8
Slave2Centos7.9(64位)redis3192.168.88.13redis-4.0.8
  • Slave2
[root@redis3 ~]# cd /data/redis-4.0.8/
[root@redis3 redis-4.0.8]# make && make install
[root@redis3 redis-4.0.8]# ./utils/install_server.sh 
# 一直回车默认即可
[root@redis3 redis-4.0.8]# /etc/init.d/redis_6379 stop
[root@redis3 redis-4.0.8]# sed -i '/^bind/cbind 192.168.88.13' /etc/redis/6379.conf
[root@redis3 redis-4.0.8]# /etc/init.d/redis_6379 start
[root@redis3 redis-4.0.8]# redis-cli -h 192.168.88.13
192.168.88.13:6379> ping
PONG
192.168.88.13:6379> info replication
# Replication
role:master
connected_slaves:0
...
# 成为192.168.88.11的从服务器
192.168.88.13:6379> slaveof 192.168.88.11 6379
OK
192.168.88.13:6379> info replication
# Replication
role:slave
master_host:192.168.88.11
master_port:6379
...
192.168.88.13:6379> config rewrite
OK
192.168.88.13:6379> keys *
1) "a"
2) "c"
3) "b"

配置主从从

这里为了省事,就将上面一主多从的场景为基础,然后配置主从从架构。
MasterSlave1不需要变动

  • Slave2
# 设置本机成为Slave1的从
192.168.88.13:6379> slaveof 192.168.88.11 6379
OK
192.168.88.13:6379> config rewrite
OK
192.168.88.13:6379> info replication
# Replication
role:slave
master_host:192.168.88.12
master_port:6379
...

哨兵服务

什么是哨兵服务:监视主从复制结构中主服务器,发现主服务器无法连接后,会把对应的从升级为主数据库服务器,继续监视新的主数据库服务器,坏掉的主数据库服务器恢复后,会自动做当前主服务器的从主机。哨兵服务+redis主从服务 能够实现redis服务高可用和数据的自动备份,但远比Redis集群的资金成本和运维成本要低。

这里以上面的主从从架构作为示例,再添加一个哨兵服务器,也可以添加多个的,配置都是一样的

节点服务器系统主机名IP地址安装服务及工具
MasterCentos7.9(64位)redis1192.168.88.11redis-4.0.8
Slave1Centos7.9(64位)redis2192.168.88.12redis-4.0.8
Slave2Centos7.9(64位)redis3192.168.88.13redis-4.0.8
sentinelCentos7.9(64位)redis4192.168.88.13sentinel服务
  • sentinel
[root@redis4 ~]# cd /data/redis-4.0.8/
[root@redis4 redis-4.0.8]# make && make install
[root@redis4 ~]# mkdir /usr/local/sentinel && cd /usr/local/sentinel
[root@redis4 sentinel]# vim sentinel.conf
bind 192.168.88.14
port 26379
sentinel monitor redis_server 192.168.88.11 6379 1
# 如果主服务器设置了密码,需要插入下面这一行,这里有一个点需要注意,如果主服务器设置了密码,那么从服务器一定也要设置一个相同的密码
# sentinel auth-pass redis_server 123456   
# 启动服务
[root@redis4 sentinel]# nohup redis-sentinel /usr/local/sentinel/sentinel.conf &
[1] 1629
[root@redis4 sentinel]# nohup: ignoring input and appending output to ‘nohup.out’ # 回车即可
[root@redis4 sentinel]# netstat -ntulp | grep :26379
tcp        0      0 192.168.88.14:26379     0.0.0.0:*               LISTEN      1629/redis-sentinel

模拟Master宕机,看主节点有没有切到Slave1

# Master
[root@redis1 ~]# redis-cli -h 192.168.88.11
192.168.88.11:6379> mset name bhlu addr wuxi
OK
192.168.88.11:6379> exit
[root@redis1 ~]# redis-cli -h 192.168.88.11 shutdown

# Slave1
[root@redis2 ~]# redis-cli -h 192.168.88.12
192.168.88.12:6379> get name
"bhlu"
192.168.88.12:6379> mget name addr
1) "bhlu"
2) "wuxi"
192.168.88.12:6379> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.88.13,port=6379,state=online,offset=36296,lag=1
...
192.168.88.12:6379> mset company jsic school wuxi
OK

模拟Slave1再宕机,看主节点有没有切到Slave2

# Slave1
[root@redis2 ~]# redis-cli -h 192.168.88.12 shutdown

# Slave2
[root@redis3 ~]# redis-cli -h 192.168.88.13
192.168.88.13:6379> mget name addr company school
1) "bhlu"
2) "wuxi"
3) "jsic"
4) "wuxi"
192.168.88.13:6379> info replication
# Replication
role:master
connected_slaves:0
...
192.168.88.13:6379> set date 20240704
OK

如果Master启动,观察是否还会不会回到集群

# Master
[root@redis1 ~]# /etc/init.d/redis_6379 start
Starting Redis server...
192.168.88.11:6379> info replication
# Replication
role:slave
master_host:192.168.88.13
master_port:6379
...
192.168.88.11:6379> get date
"20240704"

再将Slave1启动,发现架构变了,变成一主多从了

# Slave1
[root@redis2 ~]# /etc/init.d/redis_6379 start
[root@redis2 ~]# redis-cli -h 192.168.88.12
192.168.88.12:6379> info replication
# Replication
role:slave
master_host:192.168.88.13
master_port:6379
...
192.168.88.12:6379> get date
"20240704"
  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值