一、数据库分类
关系型: mysql oracle sqlserver db2 postgresql
非关系型:redis mongo ES
二、Redis重要特性
1.速度快
c语言写的
代码优雅
单线程架构
2.支持多种数据结构
字符串,哈希,列表,集合,有序集合
3.丰富的功能
天然计数器
健过期功能
消息队列
4.支持客户端语言多
php,java,python
5.数据持久化
所有的数据都运行在内存中
支持2种格式持久化数据AOF RDB AOF&RDB
6.自带多种高可用架构
主从
哨兵
集群
三、redis应用场景
1.缓存-键过期时间
把session会话存在redis,过期删除
缓存用户信息,缓存Mysql部分数据,用户先访问redis,redis没有再访问mysql,然后回写给redis
商城优惠卷过期时间
2.排行榜-列表&有序集合
热度/点击数排行榜
直播间礼物积分排行
3.计数器-天然支持计数器
帖子浏览数
视频播放数
评论数
点赞/踩
4.社交网络-集合
粉丝
共同好友
兴趣爱好
标签
5.消息队列-发布订阅
配合ELK缓存收集来的日志
1.准备安装和数据目录
[root@redis ~]# mkdir -p /data/soft
[root@redis ~]# mkdir -p /opt/redis_cluster/redis_6379/{conf,logs,pid}
2.下载redis安装包
[root@redis ~]# cd /data/soft/
[root@redis soft]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz
3.解压redis到/opt/redis_cluster/
[root@redis soft]# tar xf redis-5.0.7.tar.gz -C /opt/redis_cluster/
[root@redis soft]# ln -s /opt/redis_cluster/redis-5.0.7/ /opt//redis_cluster/redis
4.切换目录安装redis
[root@redis soft]# cd /opt/redis_cluster/redis
[root@redis redis]# make && make install
在这里我出现一个错误:
[root@redis redis]# make && make install
cd src && make all
make[1]: Entering directory `/opt/redis_cluster/redis-5.0.7/src'
CC Makefile.dep
make[1]: Leaving directory `/opt/redis_cluster/redis-5.0.7/src'
make[1]: Entering directory `/opt/redis_cluster/redis-5.0.7/src'
CC adlist.o
In file included from adlist.c:34:0:
zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such file or directory
#include <jemalloc/jemalloc.h>
^
compilation terminated.
make[1]: *** [adlist.o] Error 1
make[1]: Leaving directory `/opt/redis_cluster/redis-5.0.7/src'
make: *** [all] Error 2
解决办法:
[root@redis redis]# make MALLOC=libc
5.编写配置文件
[root@redis redis]# vim /opt/redis_cluster/redis_6379/conf/6379.conf
添加:
bind 127.0.0.1 192.168.1.20
port 6379
daemonize yes
pidfile /opt/redis_cluster/redis_6379/pid/redis_6379.pid
logfile /opt/redis_cluster/redis_6379/logs/redis_6379.log
databases 16
dbfilename redis.rdb
dir /opt/redis_cluster/redis_6379
6.启动当前redis服务
[root@redis redis]# redis-server /opt/redis_cluster/redis_6379/conf/6379.conf
1.全局命令
KEYS * #列出所有键值名,但在企业环境禁止使用
DBSIZE #查看有多少键值数
EXISTS #查看键值是否存在
EXPIRE k2 20 #设置K2过期时间为20秒,20秒后k2自动取消
PERSIST k2 #取消k2的过期时间
TTL k2 #查看k2的生命周期
TYPE #查看数据类型
2.字符串类型:string
SET k3 3 #创建键值
GET k3 #查看键值
DEL k2 #删除键值
INCR k3 #键值k3为整数,递增加1
INCRBY k3 10 #递增k3的量值10
MSET k4 v4 k5 v5 k6 v6 k7 v7 #批量创建键值
MGET k4 k5 k6 k7 #批量查看键值
3.列表:list
RPUSH list1 1 2 3 4 #创建列表list1,值为1 2 3 4
RPUSH list1 5 6 7 8 #在list1右侧添加5 6 7 8
LPUSH list1 0 #在list1左侧添加0
LRANGE list1 0 -1 #查看list1所有值
RPOP list1 #删除右侧最后一个值
LPOP list1 #删除左侧第一个值
LTRIM list1 0 2 #仅保留前3位,其他值删除
4.哈希:hash
HMSET user:1000 username zhangsan age 17 job it #创建hash键值user:1000
HGET user:1000 username #查看键值中username参数
HGET user:1000 age #查看键值中age参数
HGET user:1000 job #查看键值中job参数
HMSET user:1000 tel 18866668888 #添加值tel
5.集合:set
SADD set1 1 2 3 #创建集合set1
SMEMBERS set1 #查看集合set1
SADD set1 1 4 #为集合set1添加值1 4 ,但集合特性是去除重复,所以1无法再添加
SREM set1 1 4 #删除集合的值1 4
sadd set2 1 4 5 #创建第二个集合set2
SDIFF set1 set2 #求差集
SINTER set1 set2 #求合集(交集)
SUNION set1 set2 #求并集
1.redis持久化:
RDB:生成时间点快照,保存于硬盘
优点:速度快,适合做备份,能做主从复制,单开子进程进行rdb操作不影响主业务
缺点:会有部分数据丢失
AOF: 记录所有写操作命令,通过再次执行这些命令还原数据
优点:最大程度保证数据不丢失
缺点:日志记录量太大
2.RDB配置:
redis-cli 登录redis
bgsave rdb保存命令
vim /opt/redis_cluster/redis_6379/conf/6379.conf
添加:
save 900 1 #在900秒(15分钟)内,如果至少有1个key发生变化,则dump内存快照。
save 300 10 #在300秒(5分钟)内,如果至少有10个key发生变化,则dump内存快照。
save 60 10000 #在60秒(1分钟)内,如果至少有10000个key发生变化,则dump内存快照
3.AOF配置
vim /opt/redis_cluster/redis_6379/conf/6379.conf
添加:
appendonly yes #启用AOF持久化
appendfilename "redis.aof" #指定AOF文件名
appendfsync everysec #每秒同步一次
4.重启redis
redis-cli shutdown
redis-server /opt/redis_cluster/redis_6379/conf/6379.conf
为解决单点故障把数据复制到一个或多个副本副本服务器(从服务器),实现故障恢复和负载均衡
环境:
主服务器:192.168.1.20
从服务器:192.168.1.21
1.开启第二台服务器,安装redis
(1)把第一台服务器的redis安装目录,scp到第二台服务器上
[root@redis ~]# scp -rp /opt/redis_cluster/ [email protected]:/opt/
(2)在第二台服务器上,make install安装redis
[root@redis-2 ~]# cd /opt/redis_cluster/redis
[root@redis-2 ~]# make install
[root@redis-2 ~]# vim /opt/redis_cluster/redis_6379/conf/6379.conf
添加:
bind 127.0.0.1 192.168.1.21
slaveof 192.168.1.20 6379
(3)启动服务
[root@redis-2 ~]# redis-server /opt/redis_cluster/redis_6379/conf/6379.conf
(4)主服务器上新建键值,测试从服务器自动同步
主
[root@redis ~]# redis-cli
127.0.0.1:6379> set k1 1
OK
127.0.0.1:6379> keys *
1) "k1"
从
[root@redis-2 redis]# redis-cli
127.0.0.1:6379> keys *
1) "k1"
(5)从服务器在同步过程中,只能复制主数据库的数据,不能手动添加修改数据;
[root@redis-2 redis]# redis-cli
127.0.0.1:6379> set k2 2
(error) READONLY You can't write against a read only replica.
如果从服务器非要修改数据,需要断开同步:
[root@redis-2 redis]# redis-cli slaveof no one
OK
[root@redis-2 redis]# redis-cli
127.0.0.1:6379> set k2 2
OK
1.redis集群
Redis Cluster 是 redis的分布式解决方案,在3.0版本正式推出
当遇到单机、内存、并发、流量等瓶颈时,可以采用Cluster架构方案达到负载均衡目的。
Redis Cluster之前的分布式方案有两种:
1)客户端分区方案:
优点分区逻辑可控,缺点是需要自己处理数据路由,高可用和故障转移等。
2)代理方案:
优点是简化客户端分布式逻辑和升级维护便利,缺点加重架构部署和性能消耗。
官方提供的 Redis Cluster集群方案,很好的解决了集群方面的问题
2.数据分布
分布式数据库首先要解决把整个数据库集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整体数据的一个子集,需要关注的是数据分片规则,Redis Cluster采用哈希分片规则。
3 目录规划
redis安装目录
/opt/redis_cluster/redis_{PORT}/{conf,logs,pid}
redis数据目录
/data/redis_cluster/redis_{PORT}/redis_{PORT}.rdb
redis运维脚本
/root/scripts/redis_shell.sh
4.集群拓扑
redis1 192.168.1.20
redis2 192.168.1.21
redis3 192.168.1.22
5.手动搭建部署集群
思路:
先部署一台服务器上的2个集群节点,
把文件发送到其他主机修改IP地址,启动服务
实现命令:
(1)redis1操作
[root@redis01 ~]# mkdir -p /opt/redis_cluster/redis_{6380,6381}/{conf,logs,pid}
[root@redis01 ~]# mkdir -p /data/redis_cluster/redis_{6380,6381}
下载redis安装包
[root@redis01 ~]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz
解压redis及软链接
[root@redis01 ~]# tar xf redis-5.0.7.tar.gz -C /opt/redis_cluster/
[root@redis01 ~]# ln -s /opt/redis_cluster/redis-5.0.7/ /opt/redis_cluster/redis
安装redis
[root@redis01 ~]# cd /opt/redis_cluster/redis
[root@redis01 redis]# make && make install
编写配置文件
[root@redis01 ~]# vim /opt/redis_cluster/redis_6380/conf/redis_6380.conf
添加:
bind 192.168.1.20
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"
cluster-enabled yes
cluster-config-file nodes_6380.conf
cluster-node-timeout 15000
[root@redis01 ~]# cd /opt/redis_cluster/
[root@redis01 redis_cluster]# ls
redis redis-5.0.7 redis_6380 redis_6381
[root@redis01 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6381/conf/redis_6381.conf
[root@redis01 redis_cluster]# sed -i 's#6380#6381#g' redis_6381/conf/redis_6381.conf
[root@redis01 redis_cluster]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis01 redis_cluster]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
[root@redis01 redis_cluster]# netstat -anput | grep redis
tcp 0 0 192.168.1.20:6380 0.0.0.0:* LISTEN 18646/redis-server
tcp 0 0 192.168.1.20:6381 0.0.0.0:* LISTEN 18653/redis-server
tcp 0 0 192.168.1.20:16380 0.0.0.0:* LISTEN 18646/redis-server
tcp 0 0 192.168.1.20:16381 0.0.0.0:* LISTEN 18653/redis-server
(2)复制redis1的安装和数据目录到redis2、redis3
[root@redis01 redis_cluster]# ssh-keygen -t rsa
[root@redis01 redis_cluster]# ssh-copy-id [email protected]
[root@redis01 redis_cluster]# ssh-copy-id [email protected]
[root@redis01 redis_cluster]# scp -rp /opt/redis_cluster/ [email protected]:/opt/
[root@redis01 redis_cluster]# scp -rp /opt/redis_cluster/ [email protected]:/opt/
(3)redis2操作
[root@redis02 ~]# cd /opt/redis_cluster/redis
[root@redis02 redis]# make install
[root@redis02 redis]# find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "s#20#21#g"
[root@redis02 redis]# mkdir -p /data/redis_cluster/redis_{6380,6381}
[root@redis02 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis02 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
[root@redis02 redis]# netstat -anput | grep redis
tcp 0 0 192.168.1.21:6380 0.0.0.0:* LISTEN 7668/redis-server 1
tcp 0 0 192.168.1.21:6381 0.0.0.0:* LISTEN 7673/redis-server 1
tcp 0 0 192.168.1.21:16380 0.0.0.0:* LISTEN 7668/redis-server 1
tcp 0 0 192.168.1.21:16381 0.0.0.0:* LISTEN 7673/redis-server 1
(4)redis3操作
[root@redis03 ~]# cd /opt/redis_cluster/redis
[root@redis03 redis]# make install
[root@redis03 redis]# find /opt/redis_cluster/redis_638* -type f -name "*.conf"|xargs sed -i "s#20#22#g"
[root@redis03 redis]# mkdir -p /data/redis_cluster/redis_{6380,6381}
[root@redis03 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis03 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
[root@redis03 redis]# netstat -anput | grep redis
tcp 0 0 192.168.1.22:6380 0.0.0.0:* LISTEN 7648/redis-server 1
tcp 0 0 192.168.1.22:6381 0.0.0.0:* LISTEN 7653/redis-server 1
tcp 0 0 192.168.1.22:16380 0.0.0.0:* LISTEN 7648/redis-server 1
tcp 0 0 192.168.1.22:16381 0.0.0.0:* LISTEN 7653/redis-server 1
当把所有节点都启动后查看进程会有cluster的字样
但是登录后执行CLUSTER NODES命令会发现只有每个节点自己的ID,目前集群内的节点
还没有互相发现,所以搭建redis集群我们第一步要做的就是让集群内的节点互相发现.
在执行节点发现命令之前我们先查看一下集群的数据目录会发现有生成集群的配置文件
查看后发现只有自己的节点内容,等节点全部发现后会把所发现的节点ID写入这个文件
集群模式的Redis除了原有的配置文件之外又加了一份集群配置文件.当集群内节点
信息发生变化,如添加节点,节点下线,故障转移等.节点会自动保存集群状态到配置文件.
需要注意的是,Redis自动维护集群配置文件,不需要手动修改,防止节点重启时产生错乱.
节点发现使用命令: CLUSTER MEET {IP} {PORT}
提示:在集群内任意一台机器执行此命令就可以
[root@redis01 ~]# vim redis_shell.sh
#!/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
[root@redis01 ~]# chmod +x redis_shell.sh
[root@redis01 ~]# sh redis_shell.sh login 6380
192.168.1.20:6380> cluster meet 192.168.1.20 6381
OK
192.168.1.20:6380> cluster meet 192.168.1.21 6381
OK
192.168.1.20:6380> cluster meet 192.168.1.22 6381
OK
192.168.1.20:6380> cluster meet 192.168.1.21 6380
OK
192.168.1.20:6380> cluster meet 192.168.1.22 6380
OK
192.168.1.20:6380> cluster nodes
e078c92b339e5bda45e19d61f3c3eaa57e845943 192.168.1.22:6380@16380 master - 0 1615229770000 0 connected
12d50615be0600d221889dd55615f754a903c431 192.168.1.20:6380@16380 myself,master - 0 1615229769000 1 connected
26d009e70d978a51cf3b12cb212d5d7697b7545d 192.168.1.21:6380@16380 master - 0 1615229768593 5 connected
c169cefef90e71aa2f4bc177183f6ac118e33fcd 192.168.1.20:6381@16381 master - 0 1615229770000 4 connected
0464a04a58cfc9611cf40d7e013e949965b14ae9 192.168.1.21:6381@16381 master - 0 1615229769600 2 connected
027b0b6705f5dd2b5d66b94e38433facccaf2d84 192.168.1.22:6381@16381 master - 0 1615229770608 3 connected
节点都发现完毕后我们再次查看集群配置文件
可以看到,发现到的节点的ID也被写入到了集群的配置文件里
在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责哪些数据,是否出现故障灯状态信息,
redis 集群采用 Gossip(流言)协议,Gossip 协议工作原理就是节点彼此不断交换信息,一段时间后所有的节点都会知道集群完整信息,这种方式类似流言传播。
通信过程:
1)集群中的每一个节点都会单独开辟一个 Tcp 通道,用于节点之间彼此通信,防火墙放行(端口号+10000)
.
2)每个节点在固定周期内通过特定规则选择结构节点发送 ping 消息
3)接收到 ping 消息的节点用 pong 消息作为响应。集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终他们会打成一致的状态,当节点出现故障,新节点加入,主从角色变化等,它能够给不断的ping/pong消息,从而达到同步目的。
通讯消息类型:
Gossip:
Gossip 协议职责就是信息交换,信息交换的载体就是节点间彼此发送Gossip 消息。
常见 Gossip 消息分为:ping、 pong、 meet、 fail 等
meet:
meet 消息:用于通知新节点加入,消息发送者通知接受者加入到当前集群,meet 消息通信正常完成后,接收节点会加入到集群中并进行ping、 pong 消息交换
ping:
ping 消息:集群内交换最频繁的消息,集群内每个节点每秒想多个其他节点发送 ping 消息,用于检测节点是否在线和交换彼此信息。
pong:
Pong 消息:当接收到 ping,meet 消息时,作为相应消息回复给发送方确认消息正常通信,节点也可以向集群内广播自身的 pong 消息来通知整个集群对自身状态进行更新。
fail:
fail 消息:当节点判定集群内另一个节点下线时,回向集群内广播一个fail 消息,其他节点收到 fail 消息之后把对应节点更新为下线状态。
虽然节点之间已经互相发现了,但是此时集群还是不可用的状态,因为并没有给节点分配槽位,而且必须是所有的槽位都分配完毕后整个集群才是可用的状态.反之,也就是说只要有一个槽位没有分配,那么整个集群就是不可用的.
测试命令:
192.168.1.20:6380> set k1 v1
(error) CLUSTERDOWN Hash slot not served
192.168.1.20:6380> cluster info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_ping_sent:459
cluster_stats_messages_pong_sent:476
cluster_stats_messages_meet_sent:5
cluster_stats_messages_sent:940
cluster_stats_messages_ping_received:476
cluster_stats_messages_pong_received:464
cluster_stats_messages_received:940
前面说了,我们虽然有6个节点,但是真正负责数据写入的只有3个节点,其他3个节点只是作为主节点的从节点,也就是说,只需要分配期中三个节点的槽位就可以了
分配槽位的方法:
分配槽位需要在每个主节点上来配置,此时有2种方法执行:
1)分别登录到每个主节点的客户端来执行命令
2)在其中一台机器上用redis客户端远程登录到其他机器的主节点上执行命令
每个节点执行命令:
[root@redis01 ~]# redis-cli -h 192.168.1.20 -p 6380 cluster addslots {0..5461}
OK
[root@redis01 ~]# redis-cli -h 192.168.1.21 -p 6380 cluster addslots {5462..10922}
OK
[root@redis01 ~]# redis-cli -h 192.168.1.22 -p 6380 cluster addslots {10923..16383}
OK
虽然这时候集群是可用的了,但是整个集群只要有一台机器坏掉了,那么整个集群都是不可用的.
所以这时候需要用到其他三个节点分别作为现在三个主节点的从节点,以应对集群主节点故障时可以进行自动切换以保证集群持续可用.
注意:
1.不要让复制节点复制本机器的主节点, 因为如果那样的话机器挂了集群还是不可用状态, 所以复制节点要复制其他服务器的主节点.
2.使用redis-trid工具自动分配的时候会出现复制节点和主节点在同一台机器上的情况,需要注意
这一次我们采用在一台机器上使用redis客户端远程操作集群其他节点
注意:
1.需要执行命令的是每个服务器的从节点
2.注意主从的ID不要搞混了.
执行命令:
[root@redis01 ~]# sh redis_shell.sh login 6380
192.168.1.20:6380> cluster nodes
e078c92b339e5bda45e19d61f3c3eaa57e845943 192.168.1.22:6380@16380 master - 0 1615230652000 0 connected 10923-16383
12d50615be0600d221889dd55615f754a903c431 192.168.1.20:6380@16380 myself,master - 0 1615230651000 1 connected 0-5461
26d009e70d978a51cf3b12cb212d5d7697b7545d 192.168.1.21:6380@16380 master - 0 1615230652884 5 connected 5462-10922
c169cefef90e71aa2f4bc177183f6ac118e33fcd 192.168.1.20:6381@16381 master - 0 1615230651000 4 connected
0464a04a58cfc9611cf40d7e013e949965b14ae9 192.168.1.21:6381@16381 master - 0 1615230652000 2 connected
027b0b6705f5dd2b5d66b94e38433facccaf2d84 192.168.1.22:6381@16381 master - 0 1615230651874 3 connected
[root@redis01 ~]# redis-cli -h 192.168.1.20 -p 6381 cluster replicate 26d009e70d978a51cf3b12cb212d5d7697b7545d (第二台主机6380的id)
OK
[root@redis01 ~]# redis-cli -h 192.168.1.21 -p 6381 cluster replicate e078c92b339e5bda45e19d61f3c3eaa57e845943 (第三台主机6380的id)
OK
[root@redis01 ~]# redis-cli -h 192.168.1.22 -p 6381 cluster replicate 12d50615be0600d221889dd55615f754a903c431 (第一台主机6380的id)
OK
我们使用常规插入redis数据的方式往集群里写入数据看看会发生什么
[root@redis01 ~]# redis-cli -h 192.168.1.20 -p 6380 set k1 v1
(error) MOVED 12706 192.168.1.22:6380
结果提示error, 但是给出了集群另一个节点的地址
那么这条数据到底有没有set写入呢? 我们登录这两个节点分别查看
[root@redis01 ~]# redis-cli -h 192.168.1.22 -p 6380 get k1
(nil)
结果没有,这是因为使用集群后由于数据被分片了,所以并不是说在那台机器上写入数据就会在哪台机器的节点上写入,
集群的数据写入和读取就涉及到了另外一个概念,ASK路由
在集群模式下,Redis接受任何键相关命令时首先会计算键对应的槽,再根据槽找出所对应的节点
如果节点是自身,则处理键命令;
否则回复MOVED重定向错误,通知客户端请求正确的节点,这个过程称为Mover重定向.
知道了ask路由后,我们使用-c选项批量插入一些数据
[root@redis01 ~]# vim input_key.sh
#!/bin/bash
for i in $(seq 1 1000)
do
redis-cli -c -h 192.168.1.20 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
done
[root@redis01 ~]# sh input_key.sh
写入后我们同样使用-c选项来读取刚才插入的键值,然后查看下redis会不会帮我们路由到正确的节点上
[root@redis01 ~]# redis-cli -c -h 192.168.1.20 -p 6380
192.168.1.20:6380> get k_1
"v_1"
192.168.1.20:6380> get k_100
-> Redirected to slot [5541] located at 192.168.1.21:6380
"v_100"
192.168.1.21:6380> get k_1000
-> Redirected to slot [79] located at 192.168.1.20:6380
"v_1000"
至此,我们已经手动的把一个redis高可用的集群部署完毕了, 但是还没有模拟过故障。
这里我们就模拟故障,停掉期中一台主机的redis节点,然后查看一下集群的变化
我们使用暴力的kill -9(真实环境禁止使用,建议使用kill或pkill)杀掉 redis2上的redis集群节点,然后观察节点状态
理想情况应该是redis1上的6381从节点升级为主节点
在redis1上查看集群节点状态
虽然我们已经测试了故障切换的功能,但是节点修复后还是需要重新上线所以这里测试节点重新上线后的操作
重新启动redis2的6380,然后观察日志
观察redis1上的日志
这时假如我们想让修复后的节点重新上线,可以在想变成主库的从库执行CLUSTER FAILOVER命令
这里我们在redis2的6380上执行
操作命令:
中止redis2的服务:
[root@redis02 redis]# pkill redis-server
[root@redis01 ~]# sh redis_shell.sh login 6380
192.168.1.20:6380> cluster nodes
e078c92b339e5bda45e19d61f3c3eaa57e845943 192.168.1.22:6380@16380 master - 0 1615231880000 0 connected 10923-16383
12d50615be0600d221889dd55615f754a903c431 192.168.1.20:6380@16380 myself,master - 0 1615231880000 1 connected 0-5461
26d009e70d978a51cf3b12cb212d5d7697b7545d 192.168.1.21:6380@16380 master,fail - 1615231815591 1615231814381 5 disconnected
c169cefef90e71aa2f4bc177183f6ac118e33fcd 192.168.1.20:6381@16381 master - 0 1615231881081 6 connected 5462-10922
0464a04a58cfc9611cf40d7e013e949965b14ae9 192.168.1.21:6381@16381 slave,fail e078c92b339e5bda45e19d61f3c3eaa57e845943 1615231815591 1615231813371 2 disconnected
027b0b6705f5dd2b5d66b94e38433facccaf2d84 192.168.1.22:6381@16381 slave 12d50615be0600d221889dd55615f754a903c431 0 1615231880071 3 connected
查看日志:
[root@redis01 ~]# sh redis_shell.sh tail 6380
再启动redis2的服务
[root@redis02 redis]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis02 redis]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
redis2重回master:
[root@redis01 ~]# redis-cli -h 192.168.1.21 -p 6380 cluster failover
OK
[root@redis01 ~]# sh redis_shell.sh login 6380
192.168.1.20:6380> cluster nodes
e078c92b339e5bda45e19d61f3c3eaa57e845943 192.168.1.22:6380@16380 master - 0 1615232369884 0 connected 10923-16383
12d50615be0600d221889dd55615f754a903c431 192.168.1.20:6380@16380 myself,master - 0 1615232368000 1 connected 0-5461
26d009e70d978a51cf3b12cb212d5d7697b7545d 192.168.1.21:6380@16380 master - 0 1615232368000 7 connected 5462-10922
c169cefef90e71aa2f4bc177183f6ac118e33fcd 192.168.1.20:6381@16381 slave 26d009e70d978a51cf3b12cb212d5d7697b7545d 0 1615232368875 7 connected
0464a04a58cfc9611cf40d7e013e949965b14ae9 192.168.1.21:6381@16381 slave e078c92b339e5bda45e19d61f3c3eaa57e845943 0 1615232368000 2 connected
027b0b6705f5dd2b5d66b94e38433facccaf2d84 192.168.1.22:6381@16381 slave 12d50615be0600d221889dd55615f754a903c431 0 1615232367000 3 connected
手动搭建集群便于理解集群创建的流程和细节,不过手动搭建集群需要很多步骤,当集群节点众多时,必然会加大搭建集群的复杂度和运维成本,因此官方提供了 redis-trib.rb的工具方便我们快速搭建集群。redis-trib.rb是采用 Ruby 实现的 redis 集群管理工具,内部通过 Cluster相
关命令帮我们简化集群创建、检查、槽迁移和均衡等常见运维操作,使用前要安装 ruby 依赖环境
前提准备:
停掉所有的节点,然后清空数据,恢复成一个全新的集群,所有机器执行命令
redis01
[root@redis01 ~]# pkill redis
[root@redis01 ~]# rm -rf /data/redis_cluster/redis_6380/*
[root@redis01 ~]# rm -rf /data/redis_cluster/redis_6381/*
redis02
[root@redis02 ~]# pkill redis
[root@redis02 ~]# rm -rf /data/redis_cluster/redis_6380/*
[root@redis02 ~]# rm -rf /data/redis_cluster/redis_6381/*
redis03
[root@redis03 ~]# pkill redis
[root@redis03 ~]# rm -rf /data/redis_cluster/redis_6380/*
[root@redis03 ~]# rm -rf /data/redis_cluster/redis_6381/*
全部清空之后启动所有的节点,所有机器执行
[root@redis01 ~]# redis-server /opt/redis_cluster/redis_6380/conf/redis_6380.conf
[root@redis01 ~]# redis-server /opt/redis_cluster/redis_6381/conf/redis_6381.conf
检查集群完整性
[root@redis01 ~]# ./redis-trib.rb check 192.168.1.20:6380
(2)或直接使用redis-cli命令*****
创建群集:
[root@redis01 ~]# redis-cli --cluster create --cluster-replicas 1 192.168.1.20:6380 192.168.1.21:6380 192.168.1.22:6380 192.168.1.20:6381 192.168.1.21:6381 192.168.1.22:6381
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.1.21:6381 to 192.168.1.20:6380
Adding replica 192.168.1.22:6381 to 192.168.1.21:6380
Adding replica 192.168.1.20:6381 to 192.168.1.22:6380
M: 693e607d9b74b95f0b12a393ca6eb47ea3cb7d22 192.168.1.20:6380
slots:[0-5460] (5461 slots) master
M: d61af1f93a1ef578ec028107f31ad3664b3fed48 192.168.1.21:6380
slots:[5461-10922] (5462 slots) master
M: 41775731c12898cfb013bc5743de80fcbaa03485 192.168.1.22:6380
slots:[10923-16383] (5461 slots) master
S: 19022abbaa30a2439cf4980f32c74cb557257fa9 192.168.1.20:6381
replicates 41775731c12898cfb013bc5743de80fcbaa03485
S: a5748f4927ae568a92bbeed799b7777fa89c2dbc 192.168.1.21:6381
replicates 693e607d9b74b95f0b12a393ca6eb47ea3cb7d22
S: 3098f51106137ca378f8307202b2d594f7236aa4 192.168.1.22:6381
replicates d61af1f93a1ef578ec028107f31ad3664b3fed48
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 192.168.1.20:6380)
M: 693e607d9b74b95f0b12a393ca6eb47ea3cb7d22 192.168.1.20:6380
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: a5748f4927ae568a92bbeed799b7777fa89c2dbc 192.168.1.21:6381
slots: (0 slots) slave
replicates 693e607d9b74b95f0b12a393ca6eb47ea3cb7d22
M: d61af1f93a1ef578ec028107f31ad3664b3fed48 192.168.1.21:6380
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
S: 19022abbaa30a2439cf4980f32c74cb557257fa9 192.168.1.20:6381
slots: (0 slots) slave
replicates 41775731c12898cfb013bc5743de80fcbaa03485
S: 3098f51106137ca378f8307202b2d594f7236aa4 192.168.1.22:6381
slots: (0 slots) slave
replicates d61af1f93a1ef578ec028107f31ad3664b3fed48
M: 41775731c12898cfb013bc5743de80fcbaa03485 192.168.1.22:6380
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
检查完整性:
[root@redis01 ~]# redis-cli --cluster check 192.168.1.20:6380
Redis集群的扩容操作可分为以下几个步骤
1)准备新节点
2)加入集群
3)迁移槽和数据
我们在redis1上创建2个新节点
[root@redis01 ~]# mkdir -p /opt/redis_cluster/redis_{6390,6391}/{conf,logs,pid}
[root@redis01 ~]# mkdir -p /data/redis_cluster/redis_{6390,6391}
[root@redis01 ~]# cd /opt/redis_cluster/
[root@redis01 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6390/conf/redis_6390.conf
[root@redis01 redis_cluster]# cp redis_6380/conf/redis_6380.conf redis_6391/conf/redis_6391.conf
[root@redis01 redis_cluster]# sed -i 's#6380#6390#g' redis_6390/conf/redis_6390.conf
[root@redis01 redis_cluster]# sed -i 's#6380#6391#g' redis_6391/conf/redis_6391.conf
启动节点
[root@redis01 ~]# bash redis_shell.sh start 6390
[root@redis01 ~]# bash redis_shell.sh start 6391
发现节点
[root@redis01 redis]# redis-cli -c -h redis01 -p 6380 cluster meet 192.168.1.20 6390
OK
[root@redis01 redis]# redis-cli -c -h redis01 -p 6380 cluster meet 192.168.1.20 6391
OK
在redis1上使用工具扩容:注意新版本使用步骤(2)
(1)旧版本3…
cd /opt/redis_cluster/redis/src/
./redis-trib.rb add-node 192.168.1.20:6390 192.168.1.20:6380
./redis-trib.rb add-node 192.168.1.20:6390 192.168.1.20:6380
./redis-trib.rb reshard 192.168.1.20:6380
(2)或直接使用哦redis-cli命令完成
[root@redis01 redis]# redis-cli --cluster add-node 192.168.1.20:6390 192.168.1.20:6380
[root@redis01 redis]# redis-cli --cluster add-node 192.168.1.20:6391 192.168.1.20:6380
[root@redis01 ~]# redis-cli --cluster reshard 192.168.1.20:6380
打印出进群每个节点信息后,reshard命令需要确认迁移的槽数量,这里我们输入4096个:
How many slots do you want to move (from 1 to 16384)? 4096
输入6390的节点ID作为目标节点,也就是要扩容的节点,目标节点只能指定一个
What is the receiving node ID? 6390的ID号
之后输入源节点的ID,这里分别输入每个主节点的6380的ID最后输入done,或者直接输入all
Source node #1:all
迁移完成后命令会自动退出,这时候我们查看一下集群的状态
./redis-trib.rb rebalance 192.168.1.20:6380 #旧版本
或
redis-cli --cluster rebalance 192.168.1.20:6380 #新版本
流程说明
1).首先需要确定下线节点是否有负责的槽,
如果是,需要把槽迁移到其他节点,保证节点下线后整个集群槽节点映射的完整性.
2).当下线节点不再负责槽或者本身是从节点时,
就可以通知集群内其他节点忘记下线节点,当所有的节点忘记该节点后可以正常关闭.
这里我们准备将刚才新添加的节点下线,也就是6390和6391
收缩和扩容迁移的方向相反,6390变为源节点,其他节点变为目标节点,源节点把自己负责的4096个槽均匀的迁移到其他节点上,.
由于redis-trib…rb reshard命令只能有一个目标节点,因此需要执行3次reshard命令,分别迁移1365,1365,1366个槽.
操作命令:
[root@redis01 ~]# cd /opt/redis_cluster/redis/src/
[root@redis01 src]# ./redis-trib.rb reshard 192.168.1.20:6380
How many slots do you want to move (from 1 to 16384)? 1365
输入6380的id
输入6390的id
done
忘记节点
由于我们的集群是做了高可用的,所以当主节点下线的时候从节点也会顶上,所以最好我们先下线从节点,然后在下线主节点
[root@redis01 ~]# cd /opt/redis_cluster/redis/src/
[root@redis01 src]# ./redis-trib.rb del-node 192.168.1.20:6391 ID
[root@redis01 src]# ./redis-trib.rb del-node 192.168.1.20:6390 ID
集群(cluster)
CLUSTER INFO 打印集群的信息
CLUSTER NODES 列出集群当前已知的所有节点(node),以及这些节点的相关信息。
节点(node)
CLUSTER MEET 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
CLUSTER FORGET
CLUSTER REPLICATE
CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。
槽(slot)
CLUSTER ADDSLOTS [slot …] 将一个或多个槽(slot)指派(assign)给当前节点。
CLUSTER DELSLOTS [slot …] 移除一个或多个槽对当前节点的指派。
CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
CLUSTER SETSLOT NODE
CLUSTER SETSLOT MIGRATING
CLUSTER SETSLOT IMPORTING
CLUSTER SETSLOT STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。
键 (key)
CLUSTER KEYSLOT 计算键 key 应该被放置在哪个槽上。
CLUSTER COUNTKEYSINSLOT 返回槽 slot 目前包含的键值对数量。CLUSTER GETKEYSINSLOT 返回 count 个 slot 槽中的键。
数据导入导出工具
需求背景
刚切换到redis集群的时候肯定会面临数据导入的问题,所以这里推荐使用redis-migrate-tool工具来导入单节点数据到集群里
官方地址:
http://www.oschina.net/p/redis-migrate-tool
安装工具
[root@redis01 ~]# cd /opt/redis_cluster/
[root@redis01 redis_cluster]# yum -y install epel-release
[root@redis01 redis_cluster]# yum -y install git
[root@redis01 redis_cluster]# git clone https://github.com/vipshop/redis-migrate-tool.git
[root@redis01 redis_cluster]# cd redis-migrate-tool/
[root@redis01 redis-migrate-tool]# yum -y install install autoconf automake libtool
[root@redis01 redis-migrate-tool]# autoreconf -fvi
[root@redis01 redis-migrate-tool]# ./configure
[root@redis01 redis-migrate-tool]# make && make install
创建配置文件
[root@redis01 redis-migrate-tool]# vim redis_6379_to_6380.conf
[source]
type: single
servers:
- 192.168.1.20:6379
[target]
type: redis cluster
servers:
- 192.168.1.20:6380
[common]
listen: 0.0.0.0:8888
source_safe: true
生成测试数据
[root@redis01 ~]# cat input_key.sh
#!/bin/bash
for i in $(seq 1 1000)
do
redis-cli -c -h redis01 -p 6380 set k_${i} v_${i} && echo "set k_${i} is ok"
done
执行导入命令
[root@redis1 ~]# redis-migrate-tool -c redis_6379_to_6380.conf
数据校验
[root@redis1 ~]# redis-migrate-tool -c redis_6379_to_6380.conf -C redis_check
需求背景
redis的内存使用太大键值太多,不知道哪些键值占用的容量比较大,而且在线分析会影响性能.
安装工具
[root@redis01 ~]# yum -y install python-pip gcc python-devel
[root@redis01 ~]# cd /opt/
[root@redis01 opt]# git clone https://github.com/sripathikrishnan/redis-rdb-tools
[root@redis01 opt]# cd redis-rdb-tools
[root@redis01 redis-rdb-tools]# python setup.py install
使用方法
[root@redis01 redis-rdb-tools]# cd /data/redis_cluster/redis_6380/
[root@redis01 redis_6380]# rdb -c memory redis_6380.rdb -f redis_6380.rdb.csv
分析rdb并导出
[root@redis01 redis_6380]# awk -F ',' '{print $4,$2,$3,$1}' redis_6380.rdb.csv |sort > 6380.txt
需求背景
因为开发重复提交,导致电商网站优惠卷过期时间失效
问题分析
如果一个键已经设置了过期时间,这时候在set这个键,过期时间就会取消
解决思路
如何在不影响机器性能的前提下批量获取需要监控键过期时间
1.Keys * 查出来匹配的键名。然后循环读取ttl时间
2.scan * 范围查询键名。然后循环读取ttl时间
Keys 重操作,会影响服务器性能,除非是不提供服务的从节点
Scan 负担小,但是需要去多次才能取完,需要写脚本
脚本内容:
[root@redis01 ~]# vim 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.1.20 -p 6380 SCAN ${key_num} match ${line}\* count 1000|awk 'NR==1{print $0}')
key_name=$(redis-cli -h 192.168.1.20 -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