redis学习笔记-2

2022/1/25 19:05:43

本文主要是介绍redis学习笔记-2,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

视频实操总结

redis安装部署

环境准备
1、准备三台机器,修改主机名,配置hosts文件,设置互信
hostnamectl set-hostname db03
cat >/etc/hosts <<EOF
172.16.190.129 db01
172.16.190.128 db02
172.16.190.130 db03
EOF
#ssh-keygen 
[root@db02 ~]# ssh-copy-id -i .ssh/id_rsa.pub root@db02  #ansible认证需要自己信任自己
目录规划
/data/soft #软件下载路径
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}  #redis安装路径
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb #redis数据目录
/root/scripts/redis_shell.sh     #运维脚本
安装步骤
mkdir /data/soft -p
mkdir /opt/redis_cluster/redis  -p
mkdir /opt/redis_cluster/redis_6379/{conf,logs,pid} -p
mkdir /data/redis_cluster/redis_6379 -p
wget http://download.redis.io/releases/redis-6.2.6.tar.gz -P  /data/soft/ #-P 指定下载位置
tar -zxf /data/soft/redis-6.2.6.tar.gz -C /opt/redis_cluster/
ln -s /opt/redis_cluster/redis-6.2.6/ /opt/redis_cluster/redis #建立软连接方便后期升级
make  #编译
make install #编译安装,将编译文件可执行命令复制到$PATH环境变量目录下,使命令可执行

 

配置文件说明
### 配置文件放在了安装目录
cat > /opt/redis_cluster/redis_6379/conf/redis_6379.conf <<EOF  
### 以守护进程模式启动 
daemonize yes
### 绑定的主机地址
bind $(hostname -i)  
### 监听端口
port 6379
### pid 文件和 log 文件的保存地址
pidfile /opt/redis_cluster/redis_6379/pid/redis_6379.pid 
logfile /opt/redis_cluster/redis_6379/logs/redis_6379.log 
### 设置数据库的数量,默认数据库为 0
databases 16
### 指定本地持久化文件的文件名,默认是 dump.rdb
dbfilename redis_6379.rdb
### 本地数据库的目录
dir /data/redis_cluster/redis_6379
EOF
redis启停
#redis-server /opt/redis_cluster/redis_6379/conf/redis_6379.conf
#redis-cli -h db01 shutdown
错误锦集
6652:C 18 Jan 2022 11:21:41.615 # Can't chdir to '/data/redis_cluster/redis_6379': No such file or directory
#缺少数据目录,新建即可
6659:M 18 Jan 2022 11:22:45.613 * monotonic clock: POSIX clock_gettime
6659:M 18 Jan 2022 11:22:45.617 # Warning: Could not create server TCP listening socket ###:6379: Name or service not known
6659:M 18 Jan 2022 11:22:45.617 # Failed listening on port 6379 (TCP), aborting.
​
# 检查配置文件发现配置文件串行

redis字符类型

redis string
127.0.0.1:6379> set k2 100
OK
127.0.0.1:6379> incr k2 #INCR命令将字符串值解析成整型,默认加1并保存为新字符串
(integer) 101
127.0.0.1:6379> incrby k2 100  #解析成整型 加的值在后面
(integer) 201
127.0.0.1:6379> get k2
"201"
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  #一次存储多个值
OK
127.0.0.1:6379> mget k1 k2 k3    #一次获取多个值
1) "v1"
2) "v2"
3) "v3
127.0.0.1:6379> EXISTS k1  #检查键值是否存在
(integer) 1
127.0.0.1:6379> del k1   #删除键值
(integer) 1
127.0.0.1:6379> EXISTS k1
(integer) 0
127.0.0.1:6379> type k2  #返回键值存储类型
string
127.0.0.1:6379> ttl k2   #检测键值过期时间,-1 永不过期 -2键值已删除
(integer) -1
127.0.0.1:6379> EXPIRE k2 10  #设置键值过期时长为10s
(integer) 1
127.0.0.1:6379> ttl k2 
(integer) 6
127.0.0.1:6379> ttl k2
(integer) -2
127.0.0.1:6379> get k2
(nil)
redis 列表
127.0.0.1:6379> RPUSH k6 A #RPUSH 命令可向 list 的右边(尾部)添加一个新元素 
(integer) 1
127.0.0.1:6379> LPUSH k6 b #LPUSH 命令可向 list 的左边(头部)添加一个新元素 
(integer) 2
127.0.0.1:6379> LRANGE k6 0 -1
1) "b"
2) "A"
127.0.0.1:6379> LRANGE k6 0 1 #LRANGE 可以从 list 中取出一定范围的元素
1) "b"
2) "A
​
127.0.0.1:6379> LRANGE k6 0 5  ##完整列表
1) "d"
2) "c"
3) "b"
4) "A"
127.0.0.1:6379> rpop k6 1 #从右边删除一个元素
1) "A"
127.0.0.1:6379> lpop k6 1 #从左边边删除一个元素
1) "d"
127.0.0.1:6379> LRANGE k6 0 5 ##完整列表
1) "c"
2) "b"
redis 哈希(hash)
127.0.0.1:6379> hmset test:1999 name wtl  age 28 job daye  #HMSET 指令设置 hash 中的多个域
OK
127.0.0.1:6379> hget test:1999  name #hget获取单个域
"wtl"
127.0.0.1:6379> hmget test:1999 name age job #hmget 取回一系列值
1) "wtl"
2) "28"
3) "daye"
127.0.0.1:6379> hget test:1999  age;  #hget只能取到第一个值 其他值获取不到
(nil)
127.0.0.1:6379> HMSET test:1999 qq 1116  #可以继续插入写的列(hash不一定需要指定冒号和数字)
OK
127.0.0.1:6379> HGETALL test:1999 #HGETALL获取域内所有值
1) "name"
2) "wtl"
3) "age"
4) "28"
5) "job"
6) "daye"
7) "qq"
8) "1116"
redis集合
127.0.0.1:6379> sadd set 123 321  #SADD 指令把新的元素添加到 set 中
(integer) 1
127.0.0.1:6379> SMEMBERS set  #获取值
1) "123"
2) "321"
127.0.0.1:6379> sadd k7 123 321 222 333 123  ##set集合不能出现重复数据,出现的重复数据不会被插入
(integer) 4
127.0.0.1:6379> SMEMBERS k7   #无序插入
1) "123"
2) "222"
3) "321"
4) "333"
127.0.0.1:6379> SREM k7 123 #删除集合的指定值
(integer) 1
127.0.0.1:6379> SMEMBERS k7
1) "222"
2) "321"
3) "333"
127.0.0.1:6379> sadd  k11 1 2 3 4 
(integer) 4
127.0.0.1:6379> sadd  k12 1  5
(integer) 2
127.0.0.1:6379> SDIFF k11 k12  #差集
1) "2"
2) "3"
3) "4"
127.0.0.1:6379> SINTER k11 k12 #交集
1) "1"
127.0.0.1:6379> SUNION k11 k12 #并集
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"

redis 持久化

优缺点
redis持久化分为rdb和aof方式;
rdb:基于快照的持久化,速度更快,一般用作备份,主从复制也是依赖于 rdb 持久化功能
aof:以追加的方式记录 redis 操作日志的文件。可以最大程度的保证 redis 数据安全,类似于 mysql 的 binlog
核心配置
#rdb
dir /data/redis_cluster/redis_6379
dbfilename redis_6379.rdb
save 900 1    #900 秒(15 分钟)内有 1 个更改
save 300 10  #300 秒(5 分钟)内有 10 个更改
save 60 10000  #60 秒内有 10000 个更改
#AOF 
appendonly yes  #是否打开 aof 日志功能
appendfsync always  #每 1 个命令,都立即同步到 aof
appendfsync everysec #每秒写 1 次 
appendfsync no  #写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到 aof.
实施过程
###rdb
1、cp redis_6379.conf{,bak} #备份配置文件
2、配置文件新增rdb配置
3、插入1000条数据,观察rdb文件变化
for i in {1..1000};  do redis-cli set k_${i} v_${i}; echo "${i} is ok"; done
changes in 300 seconds. Saving...  #100-300秒 开始保存
Background saving started by pid 1927 #备份pid建立
DB saved on disk        #数据保存到磁盘上
RDB: 4 MB of memory used by copy-on-write #RDB:通过复制写入的4 MB内存
Background saving terminated with success  #保存背景终止了成功
从命令执行到文件保存到磁盘经过了大概5分钟
###可以通过修改参数缩短内存写入磁盘时间
​
###AOF 
1、取消rdb相关配置,修改为aof相关配置
2、数据持续写入 观察aof文件变化

redis安全认证

保护模式
protected-mode  yes/no (保护模式,是否只允许本地访问)
127.0.0.1:6379> CONFIG GET protected-mode
1) "protected-mode"
2) "yes"
bind 指定ip地址监听
127.0.0.1:6379> CONFIG GET bind
1) "bind"
2) "127.0.0.1 172.16.190.129" 如果本地使用则只配置127
requirepass {password}
127.0.0.1:6379> CONFIG SET requirepass "123456"
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "123456"
127.0.0.1:6379> get k1111  ## 没有密码认证不能执行命令
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> get k1111
(nil)
取消密码认证
#配置文件中注释相关行即可

主从复制

主从介绍

在分布式系统中解决单点问题,通常把数据复制多个副本到其他机器,满足故障恢复和负载均衡等要求;

复制功能是高可用的redis基础,哨兵和集群都是复制的基础上实现高可用的。

实施过程
1、创建对应目录将单节点编译文件拷贝到从节点
mkdir /opt/redis_cluster/redis_6379/{conf,logs,pid} -p
mkdir /data/redis_cluster/redis_6379 -p
mkdir /opt/redis_cluster/redis -p
scp -r /opt/redis_cluster/redis/* db03:/opt/redis_cluster/redis
make install 
2、增加防火墙策略
firewall-cmd --add-port=6379/tcp --permanent
firewall-cmd --reload
3、修改配置文件
cat > /opt/redis_cluster/redis_6379/conf/redis_6379.conf <<EOF  
### 以守护进程模式启动 
daemonize yes
### 绑定的主机地址
bind $(hostname -i)  
### 监听端口
port 6379
### pid 文件和 log 文件的保存地址
pidfile /opt/redis_cluster/redis_6379/pid/redis_6379.pid 
logfile /opt/redis_cluster/redis_6379/logs/redis_6379.log 
### 设置数据库的数量,默认数据库为 0
databases 16
### 指定本地持久化文件的文件名,默认是 dump.rdb
dbfilename redis_6379.rdb
### 本地数据库的目录
dir /data/redis_cluster/redis_6379
EOF
4、确认redis各节点服务启动,验证单节点是否可用
5、从节点输入SLAVEOF db01 6379 即可复制主节点的数据
#info replication 查看主从复制状态
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:db01
master_port:6379
master_link_status:up
master_last_io_seconds_ago:4
master_sync_in_progress:0
slave_read_repl_offset:10359
slave_repl_offset:10359
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:018cf29ebea94cdb190f45111ca60c929ac9e030
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:10359
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:43
repl_backlog_histlen:10317
6、主节点插入数据从节点读取验证
redis主从故障恢复
1、主备验证完成后关闭主节点进程,模仿故障发生(先备份rdb数据)
[root@db01 redis_6379]# redis-cli
127.0.0.1:6379> bgsave
Background saving started
2、关闭进程后查看复制状态信息
127.0.0.1:6379> info replication
# Replication
role:slave
master_host:db01
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
3、手动关闭主从复制
db03:6379> SLAVEOF no one
OK
4、再次备份从节点数据并在剩余的节点中找出主节点,将从节点提升为主节点
db02:6379> SLAVEOF db03 6379
OK
5、插入数据模拟业务恢复,并验证从节点数据是否复制过去
for i in {1..1000};  do redis-cli -h db03 set w_${i} v_${i}; echo "${i} is ok"; done
6、启动db01进程,并加入从节点复制数据
db01:6379> SLAVEOF db03 6379
db01:6379> get w_1101    #最新数据验证获取成功
"v_1101"
7、关闭db02、db01、db03复制,恢复到单机版本,在db02和db03节点执行命令将db01 设置为主
db01:6379> SLAVEOF no one
OK
db02:6379> SLAVEOF db01 6379
OK
db01:6379> info replication
# Replication
role:master  --显示db01为主,有两个从节点
connected_slaves:2
slave0:ip=172.16.190.128,port=6379,state=online,offset=56315,lag=0
slave1:ip=172.16.190.130,port=6379,state=online,offset=56315,lag=1
master_failover_state:no-failover
master_replid:07d47c052ae0fed9ef1bfd64f925b5b603950b14
master_replid2:f0cf44ff24ce12b3b559d1d91b0fcc1587a45b21
master_repl_offset:56315
second_repl_offset:56288
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:48473
repl_backlog_histlen:7843
断开复制主要流程:
1.断开与主节点复制关系
2.从节点晋升为主节点
从节点断开复制后不会抛弃原有数据,只是无法再获取主节点上的数据变化.
通过 slaveof 命令还可以实现切主操作,所谓切主是指把当前从节点对主节点的复制切换到另一个主节点. 执行 slaveof {newMasterIp} {newMasterPort}命令即可.
切主操作流程如下:
1.断开与旧主节点的复制关系
2.与新主节点建立复制关系
3.删除从节点当前所有数据
4.对新主节点进行复制操作
提示: 线上操作一定要小心,因为切主后会清空之前所有的数据.

哨兵(Sentinel)

哨兵介绍

redis的主从模式下,主节点出现故障不能提供服务,需要人工干预,将从节点晋升为主节点,还需要修改客户端的配置(连接ip等),哨兵主要解决redis主从需要人工干预的问题。

###哨兵的缺点
1、配置复杂2、中断时间长3、资源利用率低4、依赖于redis数据节点5、主库压力比较大,性能有瓶颈

 

Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance)该系统执行以下三个任务:

1、监控
Sentinel 会不断地定期检查你的主服务器和从服务器是否运作正常。
2、提醒
当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
3、自动故障迁移
当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从 服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失 效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器

目录规划
角色ip端口
Master 192.168.190.129 6379
Sentinel-01 192.168.190.129 26379
Master 192.168.190.128 6379
Sentinel-02 192.168.190.128 26379
Master 192.168.190.130 6379
Sentinel-03 192.168.190.130 26379
配置思路

哨兵是继续主从复制,所以先要配置好主从复制,具体步骤如下:

1、先配置和创建好1台服务器的节点和哨兵

2、使用传输命令发送到另外两台机器

3、修改另外两台机器的ip地址

实施过程
1、启动db01、db02、db03的redis节点,在db02、db03上执行主从复制的命令,并通过info replication命令查看主从状态
2、在各节点上执行以下命令创建哨兵的目录和配置文件,注意各节点的bind ip配置
mkdir -p /data/redis_cluster/redis_26379
mkdir -p /opt/redis_cluster/redis_26379/{conf,pid,logs}
cat > /opt/redis_cluster/redis_26379/conf/redis_26379.conf<<EOF 
bind 172.16.190.129 
port 26379
##守护进程模式启动
daemonize yes
logfile /opt/redis_cluster/redis_26379/logs/redis_26379.log 
dir /data/redis_cluster/redis_26379
#mymaster 是主节点别名 节点的ip 和端口  2是判断主节点失败,需要两个sentinel 节点同意
sentinel monitor mymaster 172.16.190.129 6379 2
#断线超时时间,超过这个时间就认为是断线
sentinel down-after-milliseconds mymaster 3000 
#向新主节点发起复制操作的从节点个数,多个从同时传输会导致主节点服务器压力上升,写1则顺序复制,写总节点数则同时向主复制
sentinel parallel-syncs mymaster 1
#故障转移超时则判定为失败,设置值需要考虑网络环境、rdb备份文件大小
sentinel failover-timeout mymaster 18000
EOF
yum -y install rsync  #安装文件传输命令
启动哨兵,3台机器都操作
# redis-sentinel /opt/redis_cluster/redis_26379/conf/redis_26379.conf
[root@db01 ~]# ps -ef|grep redis
root   1633   1  0 09:49 ?    00:00:11 redis-server 127.0.0.1:6379
#26379端口服务变成了哨兵节点
root   4050   1  0 11:03 ?    00:00:00 redis-sentinel 172.16.190.129:26379 [sentinel]
[root@db01 conf]# more redis_26379.conf
#取消了sentinel down-after-milliseconds mymaster 3000默认配置。新增了纪元相关参数
bind 172.16.190.129
port 26379
daemonize yes
logfile "/opt/redis_cluster/redis_26379/logs/redis_26379.log"
dir "/data/redis_cluster/redis_26379"
sentinel monitor mymaster 172.16.190.129 6379 2
sentinel down-after-milliseconds mymaster 3000
sentinel failover-timeout mymaster 1800
# Generated by CONFIG REWRITE
protected-mode no
pidfile "/var/run/redis.pid"
user default on nopass ~* &* +@all
sentinel myid 93d33bce801f09b3172d22e7eb60c1a1e819e03d
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel current-epoch 0
sentinel known-replica mymaster 172.16.190.128 6379
sentinel known-sentinel mymaster 172.16.190.128 26379 86a2a69e6fd008214d42ace1fe
7dcef956d6196d
数据持续写入 观察日志变化,验证数据读取
故障模拟

1、停掉某个节点,观察其他节点日志变化

1、启动db01
2、启动哨兵
3、设置权重,db01大于其他节点
4、重新发起选举 redis-cli -h db01 -p 26379 Sentinelfailover mymaster
5、观察主从复制是否正常 #config get slaveof 
6、恢复db01权重,下次公平选举

 

redis cluster

1、槽位分配slot
2、16384个槽位
3、每一个槽位都必须分配到位,有一个没有分配,整个集群都不可用
4、序号顺序不一定要连续,最重要的是每个节点的槽位梳理要大致相同,允许2%的误差
5、集群通讯端口为配置文件里的port加10000,比如6380的通讯端口就是16380
6、故障转移切换全自动,不需要人工干预
7、集群配置文件动态更新,不要手动修改
8、程序连接redis集群需要插件支持,插件版本要一致
9、集群内消息传递是同步的
10、集群内的所有一发现的节点配置文件是自动更新的
11、hash分配算法是足够随机和足够平均的 足够稳定
目录规划
# redis 安装目录 
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}
# redis 数据目录 
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb 
# redis 运维脚本
/root/scripts/redis_shell.sh

拓扑图
 

 

手动搭建部署集群

部署一套服务器上的2个集群节点 ,发送完成后修改其他服务器的配置ip地址

 

##db01操作
mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid} 
mkdir –p /data/redis_cluster/redis_{6380,6381}
cat >/opt/redis_cluster/redis_6380/conf/redis_6380.conf<<EOF 
bind 172.16.190.129
port 6380
daemonize yes
pidfile "/opt/redis_cluster/redis_6380/pid/redis_6380.pid" 
logfile "/opt/redis_cluster/redis_6380/logs/redis_6380.log" 
dbfilename "redis_6380.rdb"
dir "/data/redis_cluster/redis_6380/"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
EOF
​
cp /opt/redis_cluster/redis_6380/conf/redis_6380.conf /opt/redis_cluster/redis_6381/conf/redis_6381.conf
sed -i 's#6380#6381#g' /opt/redis_cluster/redis_6381/conf/redis_6381.conf
rsync -avz /opt/redis_cluster/redis_638* db02:/opt/redis_cluster/
rsync -avz /opt/redis_cluster/redis_638* db03:/opt/redis_cluster/
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
###db02 操作
find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#129#128#g"
mkdir -p /data/redis_cluster/redis_{6380,6381}
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
###db03 操作
find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "/bind/s#129#130#g"
mkdir -p /data/redis_cluster/redis_{6380,6381}
redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf

所有节点都启动后进程会有cluster标注,登录cluster nodes 查看每个节点只有自己,没有发现其他节点的信息,通过节点发现将其他节点的id自动写到集群配置文件内,redis除了原有的配置文件,又添加了一份配置文件,当集群信息发生变化,集群节点下线、故障转移等操作redis会自动记录在配置文件,不要手动修改集群的配置文件。

[root@db03 redis_cluster]# ps -ef|grep redis
root       2625      1  0 15:19 ?        00:00:00 redis-server 172.16.190.130:6381 [cluster]
root       2631      1  0 15:19 ?        00:00:00 redis-server 172.16.190.130:6380 [cluster]
[root@db03 redis_cluster]# redis-cli -h db03 -p 6380
db03:6380> CLUSTER nodes
d93ddcc484b2bef8462a7163436b95dcdcc20a35 :6380@16380 myself,master - 0 0 0 connected
[root@db03 ~]# sh redis_shell.sh login 6380  #登录集群内任意一台执行节点发现命令
172.16.190.130:6380> CLUSTER MEET 172.16.190.129 6381  #使用meet命令跟节点地址 发现对应节点
OK
172.16.190.130:6380> CLUSTER MEET 172.16.190.129 6380
OK
172.16.190.130:6380> CLUSTER MEET 172.16.190.128 6380
OK
172.16.190.130:6380> CLUSTER MEET 172.16.190.128 6381
OK
172.16.190.130:6380> CLUSTER MEET 172.16.190.130 6381
OK
172.16.190.130:6380>  CLUSTER NODES  #查看集群节点信息
97d428a549976784f0b1e4a18895f611d7bb56d1 172.16.190.128:6381@16381 master - 0 1642666748131 4 connected
……

查看集群配置文件是否写入节点信息

[root@db02 redis_cluster]# cat redis_6381/nodes_6381.conf  --节点配置文件存储在数据目录
122d0aa0329a16ce11d62460ab57162f777761a4 172.16.190.129:6380@16380 master - 0 1642666710257 2 connected
46272fa2df81f4dac2f0c1ac54d68f6727baae69 172.16.190.128:6380@16380 master - 0 1642666709245 ……
redis集群通讯过程

分布式存储中需要提供维护节点元数据信息,元数据包括:节点负责哪些数据、是否出现故障灯状态信息;redis集群采用Gossip(流言)协议,协议工作原理就是节点不断交换信息。

1、集群中的每一个节点都会单独开辟一个tcp通道,用户节点之间彼此通信,通信端口在基础端口上佳1w
2、每个机电在固定周期内通过特定规则选择结构节点发送ping消息
3、接手到ping消息的节点用pong消息作为响应,集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能只知道部分节点,只要这些节点彼此可以正常通信,最终会形成一致状态,当节点出现故障、新节点加入、主从角色变化等,通过ping/pong达到部门消息的目的。
gossip协议常见消息分为:
ping: 用于检测节点是否在线及节点信息交换
pong:接手到ping、meet信息是给相应节点发送确认信息,也可以向集群发起广播自身费pong消息来通知整个集群对状态进行更新
meet:用于通知新节点加入
fail:当判定节点下线后通过广播向集群内发送fail消息,其他节点收到fail消息后也会更新对应节点状态未下线。

 

 

手动槽位分配

节点互相发现后需要分配槽位,并且所有槽位分配完毕后集群才可以使用,如果有一个槽位没有分配则整个集群不可用

[root@db03 ~]# sh redis_shell.sh login 6380
172.16.190.130:6380> set r3 1
(error) CLUSTERDOWN Hash slot not served   
172.16.190.130:6380> CLUSTER info   #查看集群状态
cluster_state:fail        #
cluster_slots_assigned:0
……
redis-cli -h db01 -p 6380 cluster addslots {0..5461}
redis-cli -h db02 -p 6380 cluster addslots {5462..10922}
redis-cli -h db03 -p 6380 cluster addslots {10923..16383}
[root@db03 ~]# sh redis_shell.sh login 6380
172.16.190.130:6380> CLUSTER info 
cluster_state:ok   #状态恢复
​
172.16.190.128:6380> CLUSTER nodes  #集群节点信息
46272fa2df81f4dac2f0c1ac54d68f6727baae69 172.16.190.128:6380@16380 myself,master - 0 1642678322000 3 connected 5462-10922
……
###节点信息解释
格式:<id> <ip:port> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
​
id: 节点ID,是一个40字节的随机字符串,这个值在节点启动的时候创建,并且永远不会改变(除非使用CLUSTER RESET HARD命令)。
ip:port: 客户端与节点通信使用的地址.
flags: 逗号分割的标记位,可能的值有: myself, master, slave, fail?, fail, handshake, noaddr, noflags. 下一部分将详细介绍这些标记.
master: 如果节点是slave,并且已知master节点,则这里列出master节点ID,否则的话这里列出”-“。
ping-sent: 最近一次发送ping的时间,这个时间是一个unix毫秒时间戳,0代表没有发送过.
pong-recv: 最近一次收到pong的时间,使用unix时间戳表示.
config-epoch: 节点的epoch值(or of the current master if the node is a slave)。每当节点发生失败切换时,都会创建一个新的,独特的,递增的epoch。如果多个节点竞争同一个哈希槽时,epoch值更高的节点会抢夺到。
link-state: node-to-node集群总线使用的链接的状态,我们使用这个链接与集群中其他节点进行通信.值可以是 connected 和 disconnected.
slot: 哈希槽值或者一个哈希槽范围. 从第9个参数开始,后面最多可能有16384个 数(limit never reached)。代表当前节点可以提供服务的所有哈希槽值。如果只是一个值,那就是只有一个槽会被使用。如果是一个范围,这个值表示为起始槽-结束槽,节点将处理包括起始槽和结束槽在内的所有哈希槽。
#集群信息解释
172.16.190.130:6381> CLUSTER info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:6
cluster_stats_messages_ping_sent:16902
cluster_stats_messages_pong_sent:17202
cluster_stats_messages_fail_sent:4
cluster_stats_messages_auth-req_sent:5
cluster_stats_messages_sent:34113
cluster_stats_messages_ping_received:17197
cluster_stats_messages_pong_received:16897
cluster_stats_messages_fail_received:6
cluster_stats_messages_auth-req_received:1
cluster_stats_messages_auth-ack_received:2
cluster_stats_messages_received:34103
###########
cluster_state: ok状态表示集群可以正常接受查询请求。fail 状态表示,至少有一个哈希槽没有被绑定(说明有哈希槽没有被绑定到任意一个节点),或者在错误的状态(节点可以提供服务但是带有FAIL 标记),或者该节点无法联系到多数master节点。.
cluster_slots_assigned: 已分配到集群节点的哈希槽数量(不是没有被绑定的数量)。16384个哈希槽全部被分配到集群节点是集群正常运行的必要条件.
cluster_slots_ok: 哈希槽状态不是FAIL 和 PFAIL 的数量.
cluster_slots_pfail: 哈希槽状态是 PFAIL的数量。只要哈希槽状态没有被升级到FAIL状态,这些哈希槽仍然可以被正常处理。PFAIL状态表示我们当前不能和节点进行交互,但这种状态只是临时的错误状态。
cluster_slots_fail: 哈希槽状态是FAIL的数量。如果值不是0,那么集群节点将无法提供查询服务,除非cluster-require-full-coverage被设置为no .
cluster_known_nodes: 集群中节点数量,包括处于握手状态还没有成为集群正式成员的节点.
cluster_size: 至少包含一个哈希槽且能够提供服务的master节点数量.
cluster_current_epoch: 集群本地Current Epoch变量的值。这个值在节点故障转移过程时有用,它总是递增和唯一的。
cluster_my_epoch: 当前正在使用的节点的Config Epoch值. 这个是关联在本节点的版本值.
cluster_stats_messages_sent: 通过node-to-node二进制总线发送的消息数量.
cluster_stats_messages_received: 通过node-to-node二进制总线接收的消息数量.

 

集群高可用配置

为了防止一台机器故障整个集群不可用,启用对应从节点保障主节点故障时集群可用

###复制节点时避免本机主复制本机从,要复制其他机器的从节点
###从节点执行命令,表述自己要复制的节点id
redis-cli -h db01 -p 6381 CLUSTER REPLICATE 要复制的主节点id
redis-cli -h db01 -p 6381 CLUSTER REPLICATE 122d0aa0329a16ce11d62460ab57162f777761a4
redis-cli -h db02 -p 6381 CLUSTER REPLICATE 46272fa2df81f4dac2f0c1ac54d68f6727baae69
redis-cli -h db03 -p 6381 CLUSTER REPLICATE d93ddcc484b2bef8462a7163436b95dcdcc20a35
[root@db03 ~]# redis-cli -h db01 -p 6380 set t1 c 
(error) MOVED 8943 172.16.190.128:6380  #提示要在另外一台机器上插入数据,因为这个分片在168上
redis cluster ask路由

集群模式下redis在接收键值前会先计算键值对应的槽,如果是节点本身则处理,不是则恢复moved重定向错误,通知客户端请求正确的节点,这个过程成为mover重定向;

使用-c选项解决redis路由的问题
cat input_key.sh
#!/bin/bash
for i in $(seq 1 1000)
do
  redis-cli -c -h db01 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok" 
done
[root@db03 ~]# redis-cli -h db01 -c -p 6380
db01:6380> get k_1
"v_1"
db01:6380> get k_100
-> Redirected to slot [5541] located at 172.16.190.128:6380  #重定向到插槽[*]位于服务器
"v_100"     #给了回复但也给了值
故障模拟转移

通过关闭单节点进程,查看其他节点日志变化及将节点从从节点恢复为主节点;

1、ps -ef|grep redis #查询进程id ,kill掉db03主节点
2、sh redis_shell.sh login 6381  #登录db03从节点,准备查询集群状态
3、172.16.190.130:6381> CLUSTER info
cluster_state:ok      #杀掉进程后集群显示正常
4、172.16.190.130:6381> CLUSTER nodes
97d428a549976784f0b1e4a18895f611d7bb56d1 172.16.190.128:6381@16381 slave  46272fa2df81f4dac2f0c1ac54d68f6727baae69 0 1642749435000 3 connected #172.16.190.128:6381
​
46272fa2df81f4dac2f0c1ac54d68f6727baae69 172.16.190.128:6380@16380 master - 0 1642749434000 3 connected 5462-10922  #172.16.190.128:6380
​
6dcfd0d894189d2c02fbda110e63aeeb85209595 172.16.190.130:6381@16381 myself,master - 0 1642749435000 6 connected 10923-16383  #172.16.190.130:6381(原来的从) 
​
d93ddcc484b2bef8462a7163436b95dcdcc20a35 172.16.190.130:6380@16380 slave,fail #状态异常 6dcfd0d894189d2c02fbda110e63aeeb85209595 1642749385493 1642749380000 6 disconnected
#172.16.190.130:6380
9f6e5453529bca33ce19b09c0d9771b52801af5d 172.16.190.129:6381@16381 slave  122d0aa0329a16ce11d62460ab57162f777761a4 0 1642749435225 2 connected  #172.16.190.129:6381@16381
​
122d0aa0329a16ce11d62460ab57162f777761a4 172.16.190.129:6380@16380 master - 0 1642749436240 2 connected 0-5461
#172.16.190.129:6380
4、 redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf #启动db02,观察集群状态
5、集群和节点状态正常,将6380切换为主
6、172.16.190.130:6380> CLUSTER FAILOVER
OK
172.16.190.130:6380> CLUSTER NODES
6dcfd0d894189d2c02fbda110e63aeeb85209595 172.16.190.130:6381@16381 master - 0 1642753513000 6 connected 10923-16383
d93ddcc484b2bef8462a7163436b95dcdcc20a35 172.16.190.130:6380@16380 myself,slave 6dcfd0d894189d2c02fbda110e63aeeb85209595 0 1642753514000 6 connected
……
172.16.190.130:6380> CLUSTER FAILOVER #想切换谁为主就在谁的节点和端口上执行
OK
172.16.190.130:6380> CLUSTER NODES
6dcfd0d894189d2c02fbda110e63aeeb85209595 172.16.190.130:6381@16381 slave d93ddcc484b2bef8462a7163436b95dcdcc20a35 0 1642753618153 8 connected
d93ddcc484b2bef8462a7163436b95dcdcc20a35 172.16.190.130:6380@16380 myself,master - 0 1642753616000 8 connected 10923-16383

 

错误锦集

故障描述:下班后所有虚拟机全部关闭,第二天通过通过命令启动集群,通过CLUSTER info查看集群状态未fail,节点状态如下:

redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
172.16.190.128:6380>CLUSTER NODES   #节点状态fail
d93ddcc484b2bef8462a7163436b95dcdcc20a35 172.16.190.130:6380@16380 master,fail? - 1642729827554 1642729825606 0 connected 10923-16383
9f6e5453529bca33ce19b09c0d9771b52801af5d 172.16.190.129:6381@16381 slave,fail? 
……
172.16.190.128:6380> CLUSTER info
cluster_state:fail      #集群状态未fail
cluster_slots_assigned:16384
cluster_slots_ok:5461
cluster_slots_pfail:10923
cluster_slots_fail:0
……
172.16.190.128:6380> set y1 1     #数据插入显示集群未启动
(error) CLUSTERDOWN The cluster is down
####
redis-cli --cluster check 172.16.190.128:6380  #通过集群检查修复命令尝试修复集群
Could not connect to Redis at 172.16.190.129:6381: Connection timed out                                             Could not connect to Redis at 172.16.190.130:6381: No route to host #提示连接失败
Could not connect to Redis at 172.16.190.130:6380: No route to host
Could not connect to Redis at 172.16.190.129:6380: No route to host
172.16.190.128:6380 (46272fa2...) -> 327 keys | 5461 slots | 1 slaves.
[OK] 327 keys in 1 masters.
0.02 keys per slot on average.
>>> Performing Cluster Check (using node 172.16.190.128:6380)#进行集群检查
M: 46272fa2df81f4dac2f0c1ac54d68f6727baae69 172.16.190.128:6380
   slots:[5462-10922] (5461 slots) master   #主,槽位
additional replica(s)
S: 97d428a549976784f0b1e4a18895f611d7bb56d1 172.16.190.128:6381 #从,槽位
   slots: (0 slots) slave
   replicates 46272fa2df81f4dac2f0c1ac54d68f6727baae69  #复制节点数据
[OK] All nodes agree about slots configuration. #所有节点同意
>>> Check for open slots... #检查空槽位
>>> Check slots coverage... #检查槽位覆盖
[ERR] Not all 16384 slots are covered by nodes. #不是所有的槽位都被覆盖
​
####通过路由问题想到是防火墙策略未开放,除本机外的集群节点未检查,调整防火墙再次执行命令后集群状态正常
###不需要所有节点都执行检查命令 单节点执行即可    
使用工具搭建部署redis cluster

手动搭建可以了解过程和细节,但配置较多,多节点时工作量较大,官方提供了redis-trib.rb工具,redis-trib.rb 是采用 Ruby 实现的 redis 集群管理工具,内部通过 Cluster 相关命令帮我们简化集群 创建、检查、槽迁移和均衡等常见运维操作,使用前要安装 ruby 依赖环境。

安装命令:

#所有节点执行
yum makecache fast
yum install rubygems
gem sources --remove https://rubygems.org/
gem sources -a http://mirrors.aliyun.com/rubygems/ 
gem update –system
gem install redis -v 3.3.5
pkill redis
rm -rf /data/redis_cluster/redis_6380/*
rm -rf /data/redis_cluster/redis_6381/*
sh redis_shell.sh start 6380
sh redis_shell.sh start 6381
#db01执行
cd /opt/redis_cluster/redis/src/
redis-cli --cluster create 172.16.190.128:6381 172.16.190.130:6381 172.16.190.129:6381 172.16.190.128:6380 172.16.190.130:6380 172.16.190.129:6380 --cluster-replicas 1
#检查集群完整性
redis-cli --cluster check 172.16.190.129:6380
#####
请补充主从节点命令
错误锦集
[root@db01 src]# ./redis-trib.rb create --replicas 1 172.16.190.128:6381 172.16.190.130:6381 172.16.190.129:6381 172.16.190.128:6380 172.16.190.130:6380 172.16.190.129:6380
###该命令已被放弃
WARNING: redis-trib.rb is not longer available! #警告:redis-trib。Rb不再可用!
You should use redis-cli instead. 你应该使用redis-cli。
All commands and features belonging to redis-trib.rb have been moved
to redis-cli.#为了使用它们,你应该使用——cluster调用redis-cli
In order to use them you should call redis-cli with the --cluster 
option followed by the subcommand name, arguments and options.#选项后面跟着子命令名、参数和选项。
Use the following syntax: #使用以下语法:
redis-cli --cluster SUBCOMMAND [ARGUMENTS] [OPTIONS]
Example: 举例 
redis-cli --cluster create 172.16.190.128:6381 172.16.190.130:6381 172.16.190.129:6381 172.16.190.128:6380 172.16.190.130:6380 172.16.190.129:6380 --cluster-replicas 1
To get help about all subcommands, type: redis-cli --cluster help  #帮助命令
工具扩容节点

Redis 集群的扩容操作可分为以下几个步骤 1)准备新节点 2)加入集群 3)迁移槽和数据

扩容流程图:

db01上新建节点
mkdir -p /opt/redis_cluster/redis_{6390,6391}/{conf,logs,pid} 
mkdir -p /data/redis_cluster/redis_{6390,6391}
cd /opt/redis_cluster/
cp redis_6380/conf/redis_6380.conf redis_6390/conf/redis_6390.conf 
cp redis_6380/conf/redis_6380.conf redis_6391/conf/redis_6391.conf 
sed -i 's#6380#6390#g' redis_6390/conf/redis_6390.conf
sed -i 's#6380#6391#g' redis_6391/conf/redis_6391.conf
启动节点
bash redis_shell.sh start 6390 
bash redis_shell.sh start 6391
发现节点
redis-cli -c -h db01 -p 6380 cluster meet 10.0.0.51 6390 
redis-cli -c -h db01 -p 6380 cluster meet 10.0.0.51 6391
在 db01 上使用工具扩容
cd /opt/redis_cluster/redis/src/ 
./redis-trib.rb reshard 10.0.0.51:6380

 

 

redis集群命令

集群(cluster)
CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
节点(node)
CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。 CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。
CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
槽(slot)
CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节 点,那么先让另一个节点删除该槽>,然后再进行指派。
CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。 CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。 
CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
键(key)
CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。
CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。

 

redis运维工具

运维脚本
#!/bin/bash
USAG(){
echo "sh $0 {start|stop|restart|login|ps|tail} PORT"
}
if [ "$#" = 1 ]
then
    REDIS_PORT='6379'
elif
  [ "$#" = 2 -a -z "$(echo "$2"|sed 's#[0-9]##g')" ]
then
    REDIS_PORT="$2"
else
  USAG
  exit 0
fi
​
REDIS_IP=$(hostname -I|awk '{print $1}')
PATH_DIR=/opt/redis_cluster/redis_${REDIS_PORT}/
PATH_CONF=/opt/redis_cluster/redis_${REDIS_PORT}/conf/redis_${REDIS_PORT}.conf
PATH_LOG=/opt/redis_cluster/redis_${REDIS_PORT}/logs/redis_${REDIS_PORT}.log
CMD_START(){
  redis-server ${PATH_CONF}
}
CMD_SHUTDOWN(){
  redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT} shutdown
}
CMD_LOGIN(){
  redis-cli -c -h ${REDIS_IP} -p ${REDIS_PORT}
}
​
CMD_PS(){
    ps -ef|grep redis
}
CMD_TAIL(){
    tail -f ${PATH_LOG}
}
case $1 in
    start)
        CMD_START
        CMD_PS
        ;;
    stop)
        CMD_SHUTDOWN
  CMD_PS
  ;;
  restart)
        CMD_START
        CMD_SHUTDOWN
        CMD_PS
        ;;
    login)
        CMD_LOGIN
        ;;
     ps)
        CMD_PS
        ;;
      tail)
      CMD_TAIL
      ;;
        *)
      USAG
esac
数据导入导出工具
cd /opt/redis_cluster/
git clone https://github.com/vipshop/redis-migrate-tool.git cd redis-migrate-tool/
autoreconf -fvi
./configure
make && make install
[root@db01 ~]# cat redis_6379_to_6380.conf 
[source]
type: single
servers:
- 10.0.0.51:6379
[target]
type: redis cluster
servers:
- 10.0.0.51:6380
[common]
listen: 0.0.0.0:8888
source_safe: true
生成测试数据
[root@db01 ~]# cat input_key.sh
#!/bin/bash
for i in $(seq 1 1000)
do
redis-cli -c -h db01 -p 6379 set k_${i} v_${i} && echo "set k_${i} is ok"
done
redis-migrate-tool -c redis_6379_to_6380.conf
redis-migrate-tool -c redis_6379_to_6380.conf -C redis_check
分析键值大小
yum install python-pip gcc python-devel
cd /opt/
git clone https://github.com/sripathikrishnan/redis-rdb-tools
cd redis-rdb-tools
python setup.py install
cd /data/redis_cluster/redis_6380/
rdb -c memory redis_6380.rdb -f redis_6380.rdb.csv
分析rdb并导出
awk -F ',' '{print $4,$2,$3,$1}' redis_6380.rdb.csv |sort > 6380.txt
监控过期键
需求背景
因为开发重复提交,导致电商网站优惠卷过期时间失效
问题分析
如果一个键已经设置了过期时间,这时候在 set 这个键,过期时间就会取消 解决思路
如何在不影响机器性能的前提下批量获取需要监控键过期时间
1.Keys* 查出来匹配的键名。然后循环读取ttl时间
2.scan * 范围查询键名。然后循环读取 ttl 时间
Keys 重操作,会影响服务器性能,除非是不提供服务的从节点
Scan 负担小,但是需要去多次才能取完,需要写脚本
cat 01get_key.sh
#!/bin/bash
key_num=0
> key_name.log
for line in $(cat key_list.txt)
do
  while true
do
    scan_num=$(redis-cli -h 192.168.47.75 -p 6380 SCAN ${key_num} match ${line}\* count
1000|awk 'NR==1{print $0}')
    key_name=$(redis-cli -h 192.168.47.75 -p 6380 SCAN ${key_num} match ${line}\* count
1000|awk 'NR>1{print $0}')
    echo ${key_name}|xargs -n 1 >> key_name.log 
    ((key_num=scan_num))
    if [ ${key_num} == 0 ]
        then
        break 
        fi
    done 
done

 

 



这篇关于redis学习笔记-2的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程