Redis服务基础

一、概述

1.数据库分类

  • RDBMS:Oracle、MySQL、PG、MS-SQL

  • NoSQL:Redis、MongoDB、ElasticSearch

MongoDB适用于地理位置应用以及大数据存储平台;少量市场份额被Hbase所抢占

Elasticsearch适用于搜索类应用

  • NewSQL:PolarDB、TiDB

2.缓存技术

Redis:基于key-value存储模式,将数据存储在内存的缓存数据库; 支持多种数据类型(string/hash/list/set/sortset等);在实际应用中,一般采用单机多实例的工作模式。

Redis单实例一般支持1000-2000个并发用户,超过这个范围,Redis性能将会下降。

数据库 优点 缺点 应用场景
Memcached 高性能读写,单一数据类型,支持客户端式分布式集群,一致性Hash、多核结构、多线程读写性能高。 无持久化、节点故障可能出现缓存穿透、分布式需要客户端实现、跨机房数据同步苦难,架构扩容复杂度高 适合大量用户访问,每个用户少量操作的环境
Reids 高性能读写、多数据类型支持、支持数据持久化、支持高可用架构、支持自定义虚拟内存、支持分布式分片集群 多线程读写较Memcached慢 适合少量用户访问,每个用户大量操作的环境
Tair 高性能读写、支持三种存储引擎(ddb/rdb/ldb),支持高可用、支持分布式分片集群 单机情况下,读写性能较其他两种产品较慢

3.缓存故障

缓存穿透

  • 定义:访问一个不存在的KEY,缓存无法生效,请求会穿透Redis直达DB;流量较大时,会造成DB挂掉。
  • 解决方案:采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的KEY,不存在的KEY会被直接过滤;访问KEY未在DB查询到值时,也会讲空值写进缓存,但可以设置较短的过期时间。

缓存雪崩

  • 定义:大量的KEY设置了相同的过期时间,导致缓存在同一时刻全部失效,造成瞬时DB请求量过大,压力骤增,引起雪崩。
  • 解决方案:可以给缓存设置过期时间加上一个随机值,使得每个KEY的过期时间分离开,不会集中在同一时刻全部失效。

缓存击穿

  • 定义:一个存在的KEY,在缓存过期的一刻,同时有大量请求,这些请求都会击穿Redis直达DB,造成瞬时DB请求量大,压力骤增。
  • 解决方案:在访问KEY之前,采用SETNX(set if not exists)来设置另一个短期KEY锁住当前KEY的访问,访问结束后再删除该短期key

4.Redis功能介绍

  • 数据类型丰富
  • 支持持久化
  • 多种内存分配及回收策略
  • 支持事务
  • 消息队列、消息订阅
  • 支持高可用
  • 支持分布式分片集群

二、Redis的安装与基础管理

1.安装

Reids官方网站

step0 下载Redis安装包

Reids下载地址

wget 下载地址
[root@db01 ~]# cd /tmp/
[root@db01 /tmp]# ll
total 0
srwxrwxrwx 1 mysql mysql 0 Sep  2 13:04 mysql.sock
[root@db01 /tmp]# wget http://download.redis.io/releases/redis-3.2.13.tar.gz
--2019-11-29 09:01:35--  http://download.redis.io/releases/redis-3.2.13.tar.gz
Resolving download.redis.io (download.redis.io)... 109.74.203.151
Connecting to download.redis.io (download.redis.io)|109.74.203.151|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1552067 (1.5M) [application/x-gzip]
Saving to: ‘redis-3.2.13.tar.gz’

100%[==============================================================>] 1,552,067    837KB/s   in 1.8s   

2019-11-29 09:01:37 (837 KB/s) - ‘redis-3.2.13.tar.gz’ saved [1552067/1552067]

[root@db01 /tmp]# ls
mysql.sock  redis-3.2.13.tar.gz

step1 解压Redis安装包

tar xf 安装包
[root@db01 /tmp]# tar xf redis-3.2.13.tar.gz -C /application/
[root@db01 /tmp]# cd /application/
[root@db01 /application]# ls 
mysql  mysql8  redis-3.2.13

step2 制作软连接

ln -s 安装目录 redis
[root@db01 /application]# ln -s redis-3.2.13/ redis
[root@db01 /application]# ll -d redis*
lrwxrwxrwx 1 root root  13 Nov 29 09:03 redis -> redis-3.2.13/
drwxrwxr-x 6 root root 309 Mar 19  2019 redis-3.2.13

step3 设定环境变量

cat >>/etc/profile<<'EOF'
export PATH=/目录/redis/src:$PATH
EOF
. /etc profile
[root@db01 ~]# tail -1 /etc/profile
export PATH=/application/redis/src:$PATH
[root@db01 ~]# . /etc/profile

step4 安装Redis

cd /目录/redis
make
[root@db01 ~]# cd /application/redis
[root@db01 /application/redis]# ls
00-RELEASENOTES  INSTALL     runtest           tests
BUGS             Makefile    runtest-cluster   utils
CONTRIBUTING     MANIFESTO   runtest-sentinel
COPYING          README.md   sentinel.conf
deps             redis.conf  src
[root@db01 /application/redis]# make
......
Hint: It's a good idea to run 'make test' ;)

make[1]: Leaving directory `/application/redis-3.2.13/src'

step5 启动Redis

redis-server &

Redis默认端口号6379

[root@db01 /application/redis]# redis-server &
[1] 50457
[root@db01 /application/redis]# 50457:C 29 Nov 09:10:08.758 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
......
50457:M 29 Nov 09:10:08.759 * The server is now ready to accept connections on port 6379

step6 连接Redis(测试)

redis-cli

redis-cli命令支持免交互式执行redis命令

[root@db01 /application/redis]# redis-cli 
127.0.0.1:6379> SET A 123
OK
127.0.0.1:6379> GET A
"123"

step7 关闭Redis

redis-cli shutdown
[root@db01 /application/redis]# redis-cli shutdown
50489:M 29 Nov 09:15:59.674 # User requested shutdown...
50489:M 29 Nov 09:15:59.674 * Saving the final RDB snapshot before exiting.
50489:M 29 Nov 09:15:59.674 * DB saved on disk
50489:M 29 Nov 09:15:59.674 # Redis is now ready to exit, bye bye...
[1]+  Done                    redis-server
[root@db01 /application/redis]# ss -lnt | grep 6379
127.0.0.1:6379> shutdown
50457:M 29 Nov 09:14:26.721 # User requested shutdown...
50457:M 29 Nov 09:14:26.721 * Saving the final RDB snapshot before exiting.
50457:M 29 Nov 09:14:26.722 * DB saved on disk
50457:M 29 Nov 09:14:26.722 # Redis is now ready to exit, bye bye...
not connected> exit
[1]+  Done                    redis-server

附 删除数据库

FLUSHDB
127.0.0.1:6379> KEYS *
1) "A"
127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> KEYS *
(empty list or set)

2.配置文件

每次修改完配置文件,需重启Redis服务,以让配置文件生效

基础参数

cat >redis.conf << EOF
daemonize yes
#开启守护进程模式
port 端口号 #指定服务端口(默认端口6379)
logfile 日志文件 #指定日志文件路径
EOF

#重启redis
redis-cli shutdown
redis-server 配置文件
#指定配置文件启动redis

[root@db01 /application/redis]# mkdir -p /data/redis/{logs,conf,data}
[root@db01 /application/redis]# cat /data/redis/conf/redis.conf 
daemonize yes
port 6379
logfile /data/redis/logs/redis.log
[root@db01 /application/redis]# redis-cli shutdown
50496:M 29 Nov 09:21:54.529 # User requested shutdown...
......
[root@db01 /application/redis]# redis-server /data/redis/conf/redis.conf &
[1] 50583

安全管理(保护模式)

Redis默认情况下,仅允许本地用户登录;不能远程登录

bind IP地址1 IP地址2 ... #设定redis服务监听地址
requirepass 密码 #指定登录授权密码(redis服务没有用户的概念)
[root@db01 /application/redis]# redis-cli
127.0.0.1:6379> 
[root@db01 /application/redis]# redis-cli -h 10.0.0.151 -p 6379
10.0.0.151:6379> keys *
(error) DENIED Redis......
[root@db01 /application/redis]# cd /data/redis/conf/
[root@db01 /data/redis/conf]# cat redis.conf 
daemonize yes
port 6379
logfile /data/redis/logs/redis.log
bind 10.0.0.151 127.0.0.1
requirepass 123456
[root@db01 /data/redis/conf]# redis-cli shutdown
[root@db01 /data/redis/conf]# redis-server /data/redis/conf/redis.conf &
[1] 50735
登录测试
redis-cli -h 主机IP地址 -p 端口 -a 授权密码 #登录redis
[root@db01 /data/redis/conf]# redis-cli -h 10.0.0.151 -p 6379
10.0.0.151:6379> set a 123
(error) NOAUTH Authentication required.
10.0.0.151:6379> auth 123456
OK
10.0.0.151:6379> set a 123
OK
[root@db01 /data/redis/conf]# redis-cli -h 10.0.0.151 -p 6379 -a 123456
10.0.0.151:6379> set b 456
OK

内存管理

Redis服务默认使用系统所有内存,内存管理不好会造成系统OOM(内存溢出);在实际环境中,单机多实例的Redis占用内存要少于机器物理内存的80%

CONFIG GET maxmemory #查看Redis服务可使用的最大系统内存(0代表不限制)
CONFIG SET maxmemory 字节数 #设定Redis服务可使用的最大内存(支持M/G等单位)
10.0.0.151:6379> CONFIG GET MAXMEMORY
1) "maxmemory"
2) "0"
10.0.0.151:6379> CONFIG SET maxmemory 1600000000
OK
10.0.0.151:6379> CONFIG GET MAXMEMORY
1) "maxmemory"
2) "1600000000"

持久化参数

Redis提供两种持久化方式,分别为RDB和AOF;Redis默认没有开启持久化服务。

持久化方式 工作特性 优点 缺点
RDB 基于时间点快照的redis持久化 速度较快,适用于备份和主从复制 数据保存不实时,宕机时会有数据丢失
AOF 类似于MySQL binlog 宕机时, 可以最大程度上保证数据不丢失 日志记录量级较大、速度较慢
  • 手动持久化
dir 数据目录 #指定数据文件存放目录
dbfilename 数据文件名称 #定义数据文件名称
save #手动持久化
[root@db01 /data/redis/conf]# redis-cli -a 123456 shutdown 
[root@db01 /data/redis/conf]# cat redis.conf 
daemonize yes
port 6379
dir /data/redis/data
logfile /data/redis/logs/redis.log
dbfilename dump.rdb
bind 10.0.0.151 127.0.0.1
requirepass 123456
[root@db01 /data/redis/conf]# redis-server /data/redis/conf/redis.conf &
[1] 50809
[root@db01 /data/redis/conf]# redis-cli -h 10.0.0.151 -p 6379 -a 123456
10.0.0.151:6379> set a 123
OK
10.0.0.151:6379> save
OK
[root@db01 /data/redis/conf]# ls /data/redis/data/
dump.rdb
  • RDB:可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)
dir 数据目录 #指定数据文件存放目录
dbfilename 数据文件名称 #定义数据文件名称
save n m #在n秒内累积发生m次变更就进行1次持久化

#官方建议配置
save 900 1
save 300 10
save 60 10000

[root@db01 /data/redis/conf]# redis-cli -h 10.0.0.151 -p 6379 -a 123456 shutdown
[root@db01 /data/redis/conf]# cat redis.conf 
daemonize yes
port 6379
dir /data/redis/data
logfile /data/redis/logs/redis.log
dbfilename dump.rdb
bind 10.0.0.151 127.0.0.1
requirepass 123456
save 900 1
save 300 10
save 60 10000
[root@db01 /data/redis/conf]# redis-server /data/redis/conf/redis.conf &
[1] 50924
  • AOF:记录所有redis服务中写指令,并在redis服务启动时通过重新执行这些指令还原数据集。

AOF文件中的命令全部以Redis服务协议格式保存,新执行的命令或被追加到文件的末尾。在Redis服务3.2版本(含3.2版本)以后,Redis会定期的将AOF记录中重复的写指令合并,进行自我优化。

appendonly yes #开启AOF持久化
appendfsync 工作模式 #指定AOF持久化模式
工作模式 含义
always 每次发生变更立即进行持久化
everysec 每秒进行一次持久化
no 由系统缓存决定随机进行持久化
[root@db01 /data/redis/conf]# tail -4 redis.conf 
appendonly yes
appendfsync always
appendfsync everysec
appendfsync no
RDB和AOF两种持久化方式并不冲突,但是在实际使用中一般仅使用一种,甚至在集群状态下,可不开持久化

3.配置信息

  • 查看当前配置信息
CONFIG GET *
127.0.0.1:6379> CONFIG GET *
  1) "dbfilename"
  2) "dump.rdb"
  3) "requirepass"
  4) "123456"
......
  • 查看特定配置信息
CONFIG GET 配置项
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "123456"
  • 模糊查询配置信息
CONFIG GET 关键字*
127.0.0.1:6379> CONFIG GET max*
1) "maxmemory"
2) "0"
3) "maxmemory-samples"
4) "5"
5) "maxclients"
6) "10000"
7) "maxmemory-policy"
8) "noeviction"
  • 即时修改配置信息(仅当前有效)
CONFIG SET 配置项 参数值
127.0.0.1:6379> CONFIG SET requirepass 123
OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "123"

三、数据类型

数据类型 含义 例(KEY VALUE)
String 字符串类型 name zhang
Hash 字典类型 stu id:111 name:lisi
List 列表类型 Wechat [...,day3,day2 day1]
Set 集合类型 people (lxl,jnl,bbh,cyf...)
SortSet 有序结合 num (10,8,5,2,1,...)

0.键(key)的通用操作

查看已存在键的名字

KEYS * #查看已存在所有关键字
KEYS 字符* #查看以指定字符开头的键名
KEYS 键名 #查看特定的键名

不建议在生产环境中使用KEYS *指令,容易导致Redis服务崩溃。

127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> HMSET b name zs age 18
OK
127.0.0.1:6379> LPUSH wechat "today is Monday"
(integer) 1
127.0.0.1:6379> SADD mr lxl bbh ms kj cjk lzl fk
(integer) 7
127.0.0.1:6379> ZADD music 0 yldisco 0 smlt 0 bf 0 mnlsdyl 0 zdskjt
(integer) 5
127.0.0.1:6379> keys *
1) "music"
2) "a"
3) "b"
4) "wechat"
5) "mr"

查看键对应值的数据类型

TYPE 键名
127.0.0.1:6379> TYPE music
zset
127.0.0.1:6379> TYPE a
string
127.0.0.1:6379> TYPE b
hash
127.0.0.1:6379> TYPE wechat
list
127.0.0.1:6379> TYPE mr
set

设定键的生存时间

设置存活时间的键不会被Redis进行持久化

EXPIRE 键名 秒
PEXPIRE 键名 毫秒
127.0.0.1:6379> EXPIRE a 300
(integer) 1
127.0.0.1:6379> PEXPIRE b 5000
(integer) 1

取消键的生存时间设置

PERSIST 键名
127.0.0.1:6379> PERSIST b
(integer) 1

查看键的存货时间

TTL 键名 #以秒为单位返回生存时间
PTTL 键名 #以毫秒为单位返回生存时间

-1表示永久存活

127.0.0.1:6379> TTL a
(integer) 225
127.0.0.1:6379> PTTL a
(integer) 218691
127.0.0.1:6379> TTL b
(integer) -1

删除键

DEL 键名
127.0.0.1:6379> DEL b
(integer) 1

检查键是否存在

EXISTS 键名 #存在返回值为1 不存在返回值0
127.0.0.1:6379> EXISTS b
(integer) 0
127.0.0.1:6379> EXISTS a
(integer) 1

变更键名

RENAME 键名
127.0.0.1:6379> RENAME a A
OK
127.0.0.1:6379> EXISTS a
(integer) 0

1.String

应用场景:会话共享,计数器应用。

INCR 键名 #键值自增长,若键值不存在,则初始值为0
INCRBY 键名 n #为指定键值增加n
DECRBY 键名 n #为指定键值减少n
127.0.0.1:6379> INCR a 
(integer) 1
127.0.0.1:6379> INCR a 
(integer) 2
127.0.0.1:6379> INCRBY a 98
(integer) 100
127.0.0.1:6379> DECRBY a 50
(integer) 50
127.0.0.1:6379> get a
"50"
set 键名 "键值" #为键设置新值,并覆盖原值
get 键名 #查询键值
getset 键名 "键值" #同时设置键值并取出键值
setex 键名 n "键值" #设置指定键的生存时间为n秒和键值
setnx 键名 "键值" #若键不存在,则为键设置新值
mset 键名1 "键值" 键名2 "键值" ... #批量设置键值
*append 键名 "键值" #若该键不存在,返回当前键值长度,若该键存在,返回追加键值长度
setrange 键名 n 字符 #把键值的第n+1个字节和n+2个字节替换为指定字符,超过长度部分,自动补0
strlen 键名 #获得指定键的键值长度
getrange 键名 n m #获取第n+1到第m个字节,若m超过键值长度,则截取至最后
mget 键1 键2 #批量获取键值

2.Hash

应用场景:实现后端数据库缓存。

hmset 键名 字段1 值 字段2 值 ... #设置Hash类型的键值
hgetall 键名 #查询hash类型键的所有值
hmget 键名 字段1 字段2 ... #查看hash类型键的指定字段值
127.0.0.1:6379> HMSET stu id 1 name zs age 28
OK
127.0.0.1:6379> HMSET stu id 2 name ls age 19
OK
127.0.0.1:6379> HGETALL stu
1) "id"
2) "2"
3) "name"
4) "ls"
5) "age"
6) "19"
127.0.0.1:6379> HMGET stu id name
1) "2"
2) "ls"

#手动模拟缓存MySQL数据
mysql> select concat("hmset city_",id," Name ",Name," CountryCode ",CountryCode," District ",District," Population ",Population)from world.city into outfile '/tmp/sql_temp.tmp';
Query OK, 4075 rows affected (0.04 sec)
[root@db01 /data/mysql/3306]# head -1  /tmp/sql_temp.tmp 
hmset city_5 Name Amsterdam CountryCode NLD District Noord-Holland Population 731200
[root@db01 /data/redis/conf]# cat /tmp/sql_temp.tmp | redis-cli -a 123
......
OK
127.0.0.1:6379> keys *
   1) "city_3669"
   2) "city_791"
   3) "city_3121"
......

Canal是由Alibaba公司开发的一个开源项目,其主要作用为自动同步 MySQL数据库中的数据到Redis

Canal中间件获取地址

3.List

应用场景:消息队列应用,展示最新数据的业务。

List默认以倒序的方式存储数据

LPUSH 键名 "键值" #设置List类型键值
LRANGE 键名 起始位置 结束位置 #查询列表的指定值
列表中存取首个位置为0,末尾位置为-1
127.0.0.1:6379> lpush wechat "today is Tuesday"
(integer) 2
127.0.0.1:6379> lpush wechat "today is Wednesday"
(integer) 3
127.0.0.1:6379> lpush wechat "today is Thursday"
(integer) 4
127.0.0.1:6379> lpush wechat "today is Friday"
(integer) 5
127.0.0.1:6379> LRANGE wechat 0 0
1) "today is Friday"
127.0.0.1:6379> LRANGE wechat 0 2
1) "today is Friday"
2) "today is Thursday"
3) "today is Wednesday"
127.0.0.1:6379> LRANGE wechat 0 -1
1) "today is Friday"
2) "today is Thursday"
3) "today is Wednesday"
4) "today is Tuesday"
5) "today is Monday"

4.Set

应有环境:交友类应用。

SADD 键名 键值1 键值2 键值3 ... #设置Set类型键值
SUNION 键名1 键名2 #取两个键的并集键值
SINTER 键名1 键名2 #取两个集合的交集键值
SDIFF 键名1 键名2 #取键1与键2的差集
127.0.0.1:6379> smembers mr
1) "kj"
2) "ms"
3) "lxl"
4) "bbh"
5) "lzl"
6) "fk"
7) "cjk"
127.0.0.1:6379> sadd bq zl mlh jnl ycx cyf fk cjk
(integer) 7
127.0.0.1:6379> SUNION mr bq
 1) "kj"
 2) "mlh"
 3) "lxl"
 4) "ms"
 5) "ycx"
 6) "cyf"
 7) "fk"
 8) "cjk"
 9) "jnl"
10) "bbh"
11) "lzl"
12) "zl"
127.0.0.1:6379> SINTER mr bq
1) "fk"
2) "cjk"
127.0.0.1:6379> SDIFF mr bq
1) "bbh"
2) "lxl"
3) "ms"
4) "kj"
5) "lzl"
127.0.0.1:6379> SDIFF bq mr
1) "cyf"
2) "jnl"
3) "mlh"
4) "ycx"
5) "zl"

5. SortSet

应有场景:排行版类应用。

SortSet默认按照计数从大到小排序

ZADD 键名 计数 键值 计数 键值 ... #设置SortSet类型键值
ZINCRBY 键名 计数 键值 #为指定键值增加指定计数
ZREVRANGE 键名 起始位置 结束位置 #查看该键的键值排序
#集合中存取首个位置为,末尾位置为-1
ZREVRANGE 键名 起始位置 结束位置 WITHSCORES #查看该键的键值排序及各键值计数
127.0.0.1:6379> zadd music 0 yldisco 0 smlt 0 mnlsdyl 0 bf 0 dr
(integer) 5
127.0.0.1:6379> ZINCRBY music 50 yldisco
"50"
127.0.0.1:6379> ZINCRBY music 100 dr
"100"
127.0.0.1:6379> ZINCRBY music 75  mnlsdyl
"75"
127.0.0.1:6379> ZINCRBY music 95 bf
"95"
127.0.0.1:6379> ZINCRBY music 10 smlt
"10"
127.0.0.1:6379> ZREVRANGE music 0 1
1) "dr"
2) "bf"
127.0.0.1:6379> ZREVRANGE music 0 -1 WITHSCORES
 1) "dr"
 2) "100"
 3) "bf"
 4) "95"
 5) "mnlsdyl"
 6) "75"
 7) "yldisco"
 8) "50"
 9) "smlt"
10) "10"

四、发布订阅

1. 消息模式

Redis服务支持两种消息模式,分别为消息队列和发布订阅;

Redis服务支持简易化的消息队列功能,在实际工作中很少有使用Redis的消息队列功能,一般使用RabbitMQ,Kafka等比较专业的消息队列产品。

消息队列是分布式架构中所必须的一个环节

2发布订阅

在Redis集群模式下,各Redis实例之间通过发布订阅功能实现沟通;

SUBSCRIBE 频道名称  #订阅指定频道(仅当前窗口有效)
UNSUBSCRIBE 频道名称 #取消订阅指定频道(若不加参数则取消所有订阅频道)
PUBLISH 频道名称 消息内容 #向指定信道发布消息
PSUBSCRIBE * #订阅所有频道
PSUBSCRIBE pattern #订阅符合给定模式频道
PUNSUBSCRIBE pattern #取消订阅符合指定模式频道(若不指定参数,则取消订阅所有规则)
#订阅者
[root@db01 /data/mysql/3306]# redis-cli -a 123
127.0.0.1:6379> SUBSCRIBE fm937
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "fm937"
3) (integer) 1

1) "message"
2) "fm937"
3) "Hello"
#发布者
127.0.0.1:6379> PUBLISH fm937 Hello
(integer) 1
#订阅者
[root@db01 /data/mysql/3306]# redis-cli -a 123
127.0.0.1:6379> PSUBSCRIBE *
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "*"
3) (integer) 1

1) "pmessage"
2) "*"
3) "talk_box"
4) "Hi Han"
#发布者
127.0.0.1:6379> PUBLISH talk_box "Hi Han"
(integer) 1

五、Redis事务(弱事务)

数据库的事务应具备ACID特性,但Redis服务中支持弱事务,仅能实现类似于A特性的事务

Redis默认没有事务功能,每次操作相当于完成一个事务。

1.事务控制语句

MULTI #开启一个事务
EXEC #提交一个事务
DISCARD #取消一个事务
WATCH 键名 #监控键

2.工作流程

MySQL Redis
将事务加载到内存,在内存中变更数据;当提交该事务时,将redo日志进行持久化;当回退该事务时,通过undo进行数据回滚。 将事务中的语句放入至队列中,当提交事务时,将队列中所有语句进行执行;当放弃修改时,则丢弃队列中的所有语句。
执行事务时,MySQL采用悲观锁机制 执行事务时,Redis采用乐观锁(先到先得)机制

Redis中,当事务队列中的某一语句执出错,那么也将放弃队列中的所有内容。

127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> exec
1) (integer) 0
127.0.0.1:6379> exec
1) (integer) -1
#模拟抢最后一张票
127.0.0.1:6379> set ticket 1
OK
127.0.0.1:6379> WATCH ticket
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr ticket
QUEUED
127.0.0.1:6379> exec
1) (integer) 0
127.0.0.1:6379> exec
(nil)

六、Redis主复制集(Master-ReplicaSet)

1.工作流程

step 1 从库通过slaveof命令连接主库;

step 2 从库连接到主库后发送SYNC指令给主库

step 3 主库收到SYNC指令后,立即出发BGSAVE,后台保存RDB;

step 4 主库会将RDB快照和快照期间陆续产生的新操作保存并发送给从库;

step 5 从库收到主库的RDB快照和数据后,应用RDB快照和数据;

----------到此Redis主从复制正常工作------------

step 6 只要主库发生新的操作,都会以命令传播的方式自动发送给从库;

1. 所有主从复制相关信息,都可从info信息中查到,即使重启任何节点,主从关系依然存在。
2. 当构建主从或者主从关系失效恢复时,从库会主动同步主库,其余时间都由主库主动向从库发送数据。
3.主从关系恢复时,若从库数据未发生损坏,Redis 2.8版本以前是重新同步全部主从数据;而2.8版本以后仅同步增量主从数据(pSync),达到快速恢复主从的目的。
4. 若主库不开启持久化,当主库重启时会造成主从数据丢失

2.相关命令及相关参数

slaveof 主库IP地址 主库端口 #从库启动主从复制,并指定主库。

#保证主从数据一致性参数:
min-slaves-to-write n #指定最小从库写入数量为n(指定数量的从库写入成功后,主库才会给前端应用返回写入成功信息。在实际环境中,一般设定最小从库写入数量为1)
min-slaves-max-lag m #指定从库反馈最大延时时间m秒(从库超时未响应,主库会直接向前端应用返回写入失败信息。)

3.构建主动(模拟一主两从)

step 1 构建多实例

#准备配置文件
daemonize yes
port 端口号
pidfile pid文件
loglevel 日志记录级别 #一般使用notice
logfile 日志文件
dbfilename 数据文件
dir 数据目录
bind IP地址
requirepass 本地密码
masterauth 主库密码 #指定主库访问密码
#实例一(主)
[root@db02 ~]# cat /data/redis/6380/conf/redis.conf 
daemonize yes
port 6380
dir /data/redis/6380/data
pidfile /data/redis/6380/conf/redis.pid
loglevel notice
logfile /data/redis/6380/logs/redis.log
dbfilename dump.rdb
requirepass 123
masterauth 123
min-slaves-to-write 1
min-slaves-max-lag 3
#实例二(从)
[root@db02 ~]# cat /data/redis/6381/conf/redis.conf
daemonize yes
port 6381
dir /data/redis/6381/data
pidfile /data/redis/6381/conf/redis.pid
loglevel notice
logfile /data/redis/6381/logs/redis.log
dbfilename dump.rdb
requirepass 123
masterauth 123
min-slaves-to-write 1
min-slaves-max-lag 3
#实例三(从)
[root@db02 ~]# cat /data/redis/6382/conf/redis.conf
daemonize yes
port 6382
dir /data/redis/6382/data
pidfile /data/redis/6382/conf/redis.pid
loglevel notice
logfile /data/redis/6382/logs/redis.log
dbfilename dump.rdb
requirepass 123
masterauth 123
min-slaves-to-write 1
min-slaves-max-lag 3

step 2 启动多实例

redis-server 配置文件 #以指定配置文件启动多实例
#实例一(主)
[root@db02 ~]# redis-server /data/redis/6380/conf/redis.conf &
[1] 16738
#实例二(从)
[root@db02 ~]# redis-server /data/redis/6381/conf/redis.conf &
[1] 16745
#实例三(从)
[root@db02 ~]# redis-server /data/redis/6382/conf/redis.conf &
[1] 16759

step 3 开启主从

redis-cli -p 端口 -a 密码 SLAVEOF 主库IP地址 主库端口号 #开启主从
#实例二
[root@db02 ~]# redis-cli -p 6381 -a 123 slaveof 127.0.0.1 6380
OK
#实例三
[root@db02 ~]# redis-cli -p 6382 -a 123
127.0.0.1:6382> slaveof 127.0.0.1 6380
OK

step 4 查询主从状态

redis-cli -p 端口 -a 密码 INFO REPLICATION #查看主从状态
#实例一
[root@db02 ~]# redis-cli -p 6380 -a 123 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=239,lag=1
slave1:ip=127.0.0.1,port=6382,state=online,offset=239,lag=1
master_repl_offset:239
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:238
#实例二
[root@db02 ~]# redis-cli -p 6381 -a 123 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:5
master_sync_in_progress:0
slave_repl_offset:295
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
#实例三
[root@db02 ~]# redis-cli -p 6382 -a 123 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:323
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

七、Redis-Sentinel (Redis 高可用)

Redis高可用是基于一主两从的主从复制环境工作的;在实际环境中,建议独立主机运行Redis-Sentinel,一般是1台或者3台redis-sentinel协同工作。

1、Redis-Sentinel的功能

Redis-Sentinel类似于一个带有管理功能的Redis实例

  • 监控所有Redis高可用节点
  • 可以自动选主并完成主库切换
  • 从库自动跳转指向新主库
  • 应用透明
  • 自动处理故障节点(节点故障自动踢出,节点故障恢复自动加入)

2.构建Redis高可用

step 1 准备配置文件(Redis-Sentinel)

cat >>配置文件 << EOF
port 端口号 #指定Redis-sentinel的端口号,默认端口号26379
dir 数据目录 #指定Redis-sentinel的数据目录
sentinel monitor 主库别名 主库地址 主库端口 n #Redis-sentinel监控各节点
n代表主节点客观下线投票,当有n个redis-sentinel判断主节点下线时,才跳转主节点
sentinel down-after-milliseconds 主库别名 m #监控主库心跳,当主库m毫秒后仍无法连接,则判断主库宕机,实现切换;(在实际应用环境中,一般建议设置为2000ms-3000ms)
sentinel auth-pass 主库别名 主库密码 #指定主库授权密码(为保证Redis-sentinel实现自动跳转主库,因此所有实例的密码应该统一)
EOF
[root@mha_manager /application/redis]# cat /data/redis/26380/conf/sentinel.conf 
port 26380
dir "/data/redis/26380/data"
sentinel monitor my_sentinel_1 10.0.0.153 7000 1
sentinel down-after-milliseconds my_sentinel_1 5000
sentinel auth-pass my_sentinel_1 123

step 2 启动Redis-Sentinel

redis-sentinel 配置文件 &>日志文件 &
[root@mha_manager /application/redis]# redis-sentinel /data/redis/26380/conf/sentinel.conf &>/data/redis/26380/logs/sentinel.log &
[1] 40229
[root@mha_manager /application/redis]# ss -lnt | grep 26380
LISTEN     0      128          *:26380                    *:*                  
LISTEN     0      128         :::26380                   :::* 

故障转移模拟

redis-cli -p 端口 -a 密码 shutdown
[root@db03 /application/redis]# redis-cli -p 7000 
127.0.0.1:7000> auth 123
OK
127.0.0.1:7000> shutdown
[root@db03 /application/redis]# ss -lnt 
State      Recv-Q Send-Q       Local Address:Port                      Peer Address:Port              
LISTEN     0      128                      *:22                                   *:*                  
LISTEN     0      80                      :::3306                                :::*                  
LISTEN     0      128                     :::22                                  :::*         
[root@mha_manager /application/redis]# redis-cli -h 10.0.0.155 -p 7000 -a 123 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=10.0.0.154,port=7000,state=online,offset=6170,lag=0
master_repl_offset:6170
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:6169
[root@mha_manager /application/redis]# cat /data/redis/26380/conf/sentinel.conf 
port 26380
dir "/data/redis/26380/data"
sentinel myid 843b46a6888ce78075d09b7397827e2c562867a7
sentinel deny-scripts-reconfig yes
sentinel monitor my_sentinel_1 10.0.0.155 7000 1
# Generated by CONFIG REWRITE
sentinel down-after-milliseconds my_sentinel_1 5000
sentinel auth-pass my_sentinel_1 123
sentinel config-epoch my_sentinel_1 1
sentinel leader-epoch my_sentinel_1 1
sentinel known-slave my_sentinel_1 10.0.0.153 7000
sentinel known-slave my_sentinel_1 10.0.0.154 7000
sentinel current-epoch 1

故障恢复模拟

redis-server 配置文件 &
[root@db03 /application/redis]# redis-server /data/redis/conf/redis.conf &
[1] 14870
[root@db03 /application/redis]# ss -lnt 
State      Recv-Q Send-Q       Local Address:Port                      Peer Address:Port              
LISTEN     0      128                      *:22                                   *:*                  
LISTEN     0      128              127.0.0.1:7000                                 *:*                  
LISTEN     0      128             10.0.0.153:7000                                 *:*                  
LISTEN     0      80                      :::3306                                :::*                  
LISTEN     0      128                     :::22                                  :::*                  
[1]+  Done                    redis-server /data/redis/conf/redis.conf

[root@mha_manager /application/redis]# redis-cli -h 10.0.0.153 -p 7000 -a 123 info replication
# Replication
role:slave
master_host:10.0.0.155
master_port:7000
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:26899
slave_priority:100
slave_read_only:1
connected_slaves:0
min_slaves_good_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
[root@mha_manager /application/redis]# redis-cli -h 10.0.0.155 -p 7000 -a 123 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=10.0.0.154,port=7000,state=online,offset=25191,lag=0
slave1:ip=10.0.0.153,port=7000,state=online,offset=25191,lag=0
master_repl_offset:25191
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:25190

3.特性

  • 同一redis-sentinel服务可通过指定不同配置文件多次启动,实现同一redis-sentinel监控多套主从环境;
  • 监管同一主从环境的不同redis-sentinue可通过自身订阅的特殊频道(_hello频道),实现互相通信完成协同工作;
  • 自动维护配置文件;
  • Redis-Sentinel可在代码层面实现读写分离;

4.管理命令

redis-cli -p 端口 #连接redis-sentinel服务
PING #返回PONG
SENTINEL MASTER #列出所有被监视的主服务器
SENTINEL SLAVES 主库别名 #列出给定主服务器的所有从服务器及其状态
SENTINEL GET-MASTER-ADDR-BY-NAME 主库别名 #返回给定名字的主服务器IP地址和端口号
SENTINEL RESTE 模式 #重置所有名字和给定模式相匹配的主服务器
SENTINEL FAILOVER 主库别名 #当主库故障时,不询问其他redis-sentinel,强制开始一次故障转移
SENTINEL MONITOR 主库别名 主库IP地址 端口号 n #指定redis-sentinel监听一个新的主库
SENTINEL REMOVE 主库别名 #指定redis-sentinel放弃监听该主库

八、Redis Cluster (Redis 分布式集群)

Redis集群是基于一主两从的主从复制环境工作的;

Redis-sentinel仅能实现高可用和读写分离,针对缓解读操作的压力有一定作用,但无法缓解写操作的压力;Redis-Cluster既可以缓解读操作的压力,也可以缓解写操作的压力。

1.特性

高性能

  1. 在多分片节点中,将16384个槽位均匀分布到多个分片节点中;
  2. 存储数据时,将key进行CRC16运算;然后将结果与16384取余,得出槽位值(Slot):0-16383;
  3. 根据计算得出的槽位值,找到相应的分片节点的主节点,存储到相应槽位上;
  4. 如果客户端当时连接的节点不是数据存储槽位所在节点,Redis-Cluster会将客户端连接切换至真正的存储节点上进行数据存储;

高可用

在搭建Redis-Cluster时,会为每一个分片的主节点生成一个对应的从节点,实现slaveof功能;当 主节点宕机后,Redis-Cluster可实现类似于Redis-Sentinel的自动故障转移(failover)功能。
  1. Redis会有多组分片构成;
  2. Redis-Cluster使用固定个数(16384)的slot存储数据;
  3. 每组分片分得1/n个slot个数
  4. 基于CRC16(key) % 16384计算取得槽位值,得到槽位号;

在实际环境中,承载同一分片数据的两个不同实例分配到不同的主机,防止单一主机宕机造成整个分片数据的丢失

2.构建Redis-Cluster

使用redis-trib.rb工具构建集群,集群构建完成前不要配置密码。

step 1 安装集群插件

yum install -y ruby rubygems #安装ruby环境及插件(需使用EPEL源)
gem sources -l #查看ruby仓库源
gem sources -a http://mirrors.aliyun.com/rubygems/ #添加aliyun的ruby仓库源
gem sources --remove https://rubygems.org #删除默认的ruby仓库源
gem sources -l #查看ruby仓库源
gem install redis -v 3.3.3 #安装redis驱动插件(版本3.3.3)
[root@mha_manager /data/redis/26380/conf]# yum install -y  ruby rubygems
......
Complete!
[root@mha_manager /data/redis/26380/conf]# gem sources -l
*** CURRENT SOURCES ***

https://rubygems.org/
[root@mha_manager /data/redis/26380/conf]# gem sources -a http://mirrors.aliyun.com/rubygems/
http://mirrors.aliyun.com/rubygems/ added to sources
[root@mha_manager /data/redis/26380/conf]# gem sources --remove https://rubygems.org/
https://rubygems.org/ removed from sources
[root@mha_manager /data/redis/26380/conf]# gem sources -l
*** CURRENT SOURCES ***

http://mirrors.aliyun.com/rubygems/
[root@mha_manager /data/redis/26380/conf]# gem install redis -v 3.3.3
Fetching: redis-3.3.3.gem (100%)
Successfully installed redis-3.3.3
Parsing documentation for redis-3.3.3
Installing ri documentation for redis-3.3.3
1 gem installed

step 2 准备Redis节点

#准备配置文件
daemonize yes
port 端口号
pidfile pid文件
loglevel 日志记录级别 #一般使用notice
logfile 日志文件
dbfilename 数据文件
dir 数据目录
bind IP地址
cluster-enabled yes #开启redis-cluster功能
cluster-config-file nodes.conf #指定集群配置文件
cluster-node-timeout n #主节点故障切换时间为n毫秒
appendonly yes
[root@db03 /data/redis]# cat 7001/conf/redis.conf 
daemonize yes
port 7001
pidfile /data/redis/7001/conf/redis.pid
loglevel notice
logfile  /data/redis/7001/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7001/data
bind 10.0.0.153 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
[root@db03 /data/redis]# cat 7002/conf/redis.conf 
daemonize yes
port 7002
pidfile /data/redis/7002/conf/redis.pid
loglevel notice
logfile  /data/redis/7002/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7002/data
bind 10.0.0.153 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
[root@db04 /data/redis]# cat 7003/conf/redis.conf 
daemonize yes
port 7003
pidfile /data/redis/7003/conf/redis.pid
loglevel notice
logfile  /data/redis/7003/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7003/data
bind 10.0.0.154 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
[root@db04 /data/redis]# cat 7004/conf/redis.conf 
daemonize yes
port 7004
pidfile /data/redis/7004/conf/redis.pid
loglevel notice
logfile  /data/redis/7004/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7004/data
bind 10.0.0.154 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
[root@db05 /data/redis]# cat 7005/conf/redis.conf 
daemonize yes
port 7005
pidfile /data/redis/7005/conf/redis.pid
loglevel notice
logfile  /data/redis/7005/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7005/data
bind 10.0.0.155 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
[root@db05 /data/redis]# cat 7006/conf/redis.conf 
daemonize yes
port 7006
pidfile /data/redis/7006/conf/redis.pid
loglevel notice
logfile  /data/redis/7006/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7006/data
bind 10.0.0.155 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes

step 3 启动Redis节点

redis-server 配置文件
[root@db03 /data/redis]# redis-server /data/redis/7001/conf/redis.conf
[root@db03 /data/redis]# redis-server /data/redis/7002/conf/redis.conf
[root@db03 /data/redis]# ps -ef | grep redis
root      14871      1  0 14:34 ?        00:00:05 redis-server 10.0.0.153:7000
root      15727      1  0 15:44 ?        00:00:00 redis-server 10.0.0.153:7001 [cluster]
root      15777      1  0 15:45 ?        00:00:00 redis-server 10.0.0.153:7002 [cluster]
root      15783  15574  0 15:45 pts/1    00:00:00 grep --color=auto redis
[root@db04 /data/redis]# redis-server /data/redis/7003/conf/redis.conf
[root@db04 /data/redis]# redis-server /data/redis/7004/conf/redis.conf
[root@db04 /data/redis]# ps -ef|grep redis
root      16032      1  0 14:09 ?        00:00:07 redis-server 10.0.0.154:7000
root      16983      1  0 15:47 ?        00:00:00 redis-server 10.0.0.154:7003 [cluster]
root      16987      1  0 15:47 ?        00:00:00 redis-server 10.0.0.154:7004 [cluster]
root      16991  16810  0 15:48 pts/1    00:00:00 grep --color=auto redis
[root@db05 /data/redis]# redis-server /data/redis/7005/conf/redis.conf
[root@db05 /data/redis]# redis-server /data/redis/7006/conf/redis.conf
[root@db05 /data/redis]# ps -ef | grep redis
root      14921      1  0 14:14 ?        00:00:07 redis-server 10.0.0.155:7000
root      15859      1  0 15:51 ?        00:00:00 redis-server 10.0.0.155:7005 [cluster]
root      15863      1  0 15:51 ?        00:00:00 redis-server 10.0.0.155:7006 [cluster]
root      15867  15693  0 15:51 pts/1    00:00:00 grep --color=auto redis

step 4 将节点加入集群

redis-trib.rb create --replicas n 节点IP地址:端口号 节点IP地址:端口号 ...... #创建1主n从集群
IP地址添加顺序为-主节点1:端口号 主节点2:端口号 主节点3:端口号 ...... 主节点n:端口号 从节点n:端口号 ...... 从节点2:端口号 从节点1:端口号
[root@mha_manager /data/redis/26380/conf]# redis-trib.rb create --replicas 1 10.0.0.153:7001 10.0.0.154:7003 10.0.0.155:7005 10.0.0.155:7006 10.0.0.153:7002 10.0.0.154:7004 
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
10.0.0.153:7001
10.0.0.154:7003
10.0.0.155:7005
Adding replica 10.0.0.154:7004 to 10.0.0.153:7001
Adding replica 10.0.0.153:7002 to 10.0.0.154:7003
Adding replica 10.0.0.155:7006 to 10.0.0.155:7005
M: 4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 10.0.0.153:7001
   slots:0-5460 (5461 slots) master
M: 9a78b5a9371f34771a7c364fc9aaf1141ff91890 10.0.0.154:7003
   slots:5461-10922 (5462 slots) master
M: 03bef0cb27ecf559a05810eb333fbd3466d449f7 10.0.0.155:7005
   slots:10923-16383 (5461 slots) master
S: 3af82b13742e796eda6da9fbbff973f6272eac00 10.0.0.155:7006
   replicates 03bef0cb27ecf559a05810eb333fbd3466d449f7
S: 729e4872d7096c32537c132ba018b1cec2eca277 10.0.0.153:7002
   replicates 9a78b5a9371f34771a7c364fc9aaf1141ff91890
S: b6b284542f526fd586f9b1739481db1a5448e0e7 10.0.0.154:7004
   replicates 4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
......
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

step 5 查看集群节点状态

redis-cli -h IP地址 -p 端口 cluster nodes | grep master #查看集群主节点状态
redis-cli -h IP地址 -p 端口 cluster nodes | grep slave #查看集群主节点状态
[root@mha_manager /data/redis/26380/conf]# redis-cli -h 10.0.0.153 -p 7001 cluster nodes | grep master
4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 10.0.0.153:7001 myself,master - 0 0 1 connected 0-5460
03bef0cb27ecf559a05810eb333fbd3466d449f7 10.0.0.155:7005 master - 0 1575189275882 3 connected 10923-16383
9a78b5a9371f34771a7c364fc9aaf1141ff91890 10.0.0.154:7003 master - 0 1575189276890 2 connected 5461-10922

[root@mha_manager /data/redis/26380/conf]# redis-cli -h 10.0.0.153 -p 7001 cluster nodes | grep slave
b6b284542f526fd586f9b1739481db1a5448e0e7 10.0.0.154:7004 slave 4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 0 1575189290988 6 connected
3af82b13742e796eda6da9fbbff973f6272eac00 10.0.0.155:7006 slave 03bef0cb27ecf559a05810eb333fbd3466d449f7 0 1575189289982 4 connected
729e4872d7096c32537c132ba018b1cec2eca277 10.0.0.153:7002 slave 9a78b5a9371f34771a7c364fc9aaf1141ff91890 0 1575189289982 5 connected

3.添加节点

step 1 准备节点环境

#准备配置文件
daemoneize yes
port 端口号
pidfile pid文件
loglevel 日志记录级别
logfile 日志文件
dbfilename 数据文件
dir 数据目录
bind IP地址
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout n
appendonly yes
[root@mha_manager ~]# cat /data/redis/7007/conf/redis.conf 
daemonize yes
port 7007
pidfile /data/redis/7007/conf/redis.pid
loglevel notice
logfile  /data/redis/7007/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7007/data
bind 10.0.0.150 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes
[root@mha_manager ~]# cat /data/redis/7008/conf/redis.conf 
daemonize yes
port 7008
pidfile /data/redis/7008/conf/redis.pid
loglevel notice
logfile  /data/redis/7008/logs/redis.log
dbfilename dump.rdb
dir  /data/redis/7008/data
bind 10.0.0.150 127.0.0.1
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 3000
appendonly yes

step 2 启动节点

redis-server 配置文件
[root@mha_manager ~]# redis-server /data/redis/7007/conf/redis.conf
[root@mha_manager ~]# redis-server /data/redis/7008/conf/redis.conf
[root@mha_manager ~]# ps -ef | grep redis
root      41118      1  0 15:17 ?        00:00:09 redis-sentinel 10.0.0.150:26380 [sentinel]
root      41617      1  0 16:44 ?        00:00:00 redis-server 10.0.0.150:7007 [cluster]
root      41621      1  0 16:44 ?        00:00:00 redis-server 10.0.0.150:7008 [cluster]
root      41630  41561  0 16:45 pts/3    00:00:00 grep --color=auto redis

step 3 添加主节点

redis-trib.rb add-node 新节点IP地址:端口号 集群主节点:端口号
[root@mha_manager ~]# redis-trib.rb add-node 10.0.0.150:7007 10.0.0.153:7001
......
[OK] New node added correctly.
[root@mha_manager ~]# redis-cli -h 10.0.0.153 -p 7001 cluster nodes |grep master
27e03d17a77df923cb4b3884aea2dcb427c86ac9 10.0.0.150:7007 master - 0 1575190089193 0 connected
4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 10.0.0.153:7001 myself,master - 0 0 1 connected 0-5460
03bef0cb27ecf559a05810eb333fbd3466d449f7 10.0.0.155:7005 master - 0 1575190090200 3 connected 10923-16383
9a78b5a9371f34771a7c364fc9aaf1141ff91890 10.0.0.154:7003 master - 0 1575190089193 2 connected 5461-10922

step 4 重新分片(转移Slot)

redis-trib.rb reshard 集群节点IP地址:端口号
[root@mha_manager ~]# redis-trib.rb reshard 10.0.0.153:7001
......
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 27e03d17a77df923cb4b3884aea2dcb427c86ac9                            
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:all
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes

[root@mha_manager ~]# redis-cli -h 10.0.0.153 -p 7001 cluster nodes |grep master
27e03d17a77df923cb4b3884aea2dcb427c86ac9 10.0.0.150:7007 master - 0 1575190322280 7 connected 0-1364 5461-6826 10923-12287
4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 10.0.0.153:7001 myself,master - 0 0 1 connected 1365-5460
03bef0cb27ecf559a05810eb333fbd3466d449f7 10.0.0.155:7005 master - 0 1575190321775 3 connected 12288-16383
9a78b5a9371f34771a7c364fc9aaf1141ff91890 10.0.0.154:7003 master - 0 1575190322781 2 connected 6827-10922

step 5 添加从节点

redis-trib.rb add-node --slave --master-id 主节点node-ID 从节点IP地址:端口号 集群主节点:端口号
[root@mha_manager ~]# redis-trib.rb add-node --slave --master-id 27e03d17a77df923cb4b3884aea2dcb427c86ac9 10.0.0.150:7008 10.0.0.153:7001
>>> Adding node 10.0.0.150:7008 to cluster 10.0.0.153:7001
>>> Performing Cluster Check (using node 10.0.0.153:7001)
......
>>> Configure node as replica of 10.0.0.150:7007.
[OK] New node added correctly.
[root@mha_manager ~]# redis-cli -h 10.0.0.153 -p 7001 cluster nodes 
b6b284542f526fd586f9b1739481db1a5448e0e7 10.0.0.154:7004 slave 4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 0 1575190480941 6 connected
7e1b66c261ed03b80f688389ac52fd6a90c61999 10.0.0.150:7008 slave 27e03d17a77df923cb4b3884aea2dcb427c86ac9 0 1575190480941 7 connected
27e03d17a77df923cb4b3884aea2dcb427c86ac9 10.0.0.150:7007 master - 0 1575190480941 7 connected 0-1364 5461-6826 10923-12287
......

4.删除节点

删除Master节点之前首先要使用reshared移除master全部的slot,然后再删除当前节点

step 1 将节点slot转移

redis-trib.rb reshared 集群节点IP地址:端口号
[root@mha_manager ~]# redis-trib.rb reshard 10.0.0.153:7001
......
How many slots do you want to move (from 1 to 16384)? 1365
What is the receiving node ID? 4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:27e03d17a77df923cb4b3884aea2dcb427c86ac9
Source node #2:done
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes
......
[root@mha_manager ~]# redis-trib.rb reshard 10.0.0.153:7001
......
How many slots do you want to move (from 1 to 16384)? 1365
What is the receiving node ID? 9a78b5a9371f34771a7c364fc9aaf1141ff91890
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:27e03d17a77df923cb4b3884aea2dcb427c86ac9
Source node #2:done
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes
......
[root@mha_manager ~]# redis-trib.rb reshard 10.0.0.153:7001
......
How many slots do you want to move (from 1 to 16384)? 1365
What is the receiving node ID? 03bef0cb27ecf559a05810eb333fbd3466d449f7
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:27e03d17a77df923cb4b3884aea2dcb427c86ac9
Source node #2:done
......
Do you want to proceed with the proposed reshard plan (yes/no)? yes
......
[root@mha_manager ~]# redis-cli -h 10.0.0.153 -p 7001 cluster nodes |grep master
27e03d17a77df923cb4b3884aea2dcb427c86ac9 10.0.0.150:7007 master - 0 1575190833324 7 connected
4dc2b0264aaa2aa8f6cf427cb6734ad72f45bdc9 10.0.0.153:7001 myself,master - 0 0 8 connected 0-5460
03bef0cb27ecf559a05810eb333fbd3466d449f7 10.0.0.155:7005 master - 0 1575190832821 10 connected 10923-16383
9a78b5a9371f34771a7c364fc9aaf1141ff91890 10.0.0.154:7003 master - 0 1575190832821 9 connected 5461-10922
[root@mha_manager ~]# ps -ef | grep redis
root      41118      1  0 15:17 ?        00:00:10 redis-sentinel 10.0.0.150:26380 [sentinel]
root      41617      1  0 16:44 ?        00:00:06 redis-server 10.0.0.150:7007 [cluster]
root      41621      1  0 16:44 ?        00:00:01 redis-server 10.0.0.150:7008 [cluster]
root      41695  41561  0 17:00 pts/3    00:00:00 grep --color=auto redis

step 2 删除节点

实例从集群中删除后,该实例将自动停止,关闭redis服务,如需重新启用该实例,需清空重建实例。

redis-trib.rb del-node 删除节点IP地址:端口号 node-ID
[root@mha_manager ~]# redis-trib.rb del-node 10.0.0.150:7007 27e03d17a77df923cb4b3884aea2dcb427c86ac9
>>> Removing node 27e03d17a77df923cb4b3884aea2dcb427c86ac9 from cluster 10.0.0.150:7007
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@mha_manager ~]# redis-trib.rb del-node 10.0.0.150:7008 7e1b66c261ed03b80f688389ac52fd6a90c61999
>>> Removing node 7e1b66c261ed03b80f688389ac52fd6a90c61999 from cluster 10.0.0.150:7008
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@mha_manager ~]# ps -ef | grep redis
root      41118      1  0 15:17 ?        00:00:13 redis-sentinel 10.0.0.150:26380 [sentinel]
root      41768  41561  0 17:30 pts/3    00:00:00 grep --color=auto redis

九、 基于Python的API调用

1.安装python环境

本文所使用的python版本为3.6版本;python的2.7.2以上版本才支持redis cluster。

yum install -y python36 #安装python 3.6版本
yum install -y python36-pip #安装python 3.6版本对应的pip工具
python3 -V #查看Python版本
[root@db01 /data/redis/conf]# yum install -y python36
......
Dependency Installed:
  libtirpc.x86_64 0:0.2.4-0.16.el7               python3-libs.x86_64 0:3.6.8-10.el7                     
  python3-pip.noarch 0:9.0.3-5.el7               python3-setuptools.noarch 0:39.2.0-10.el7              

Complete!
[root@db01 /data/redis/conf]# python3 -V
Python 3.6.8

2.安装API

pip3 install redis #安装单机版和redis sentinel版的redis_API
pip3 install redis-py-cluster #安装redis cluster版的redis_API
[root@db01 /data/redis/conf]# pip3 install redis redis-py-cluster
WARNING: Running pip install with root privileges is generally not a good idea. Try `pip3 install --user` instead.
Collecting redis
  Downloading https://files.pythonhosted.org/packages/32/ae/28613a62eea0d53d3db3147f8715f90da07667e99baeedf1010eb400f8c0/redis-3.3.11-py2.py3-none-any.whl (66kB)
    100% |████████████████████████████████| 71kB 461kB/s 
Collecting redis-py-cluster
  Downloading https://files.pythonhosted.org/packages/35/cb/29d44f7735af4fe9251afb6b5b173ec79c6e8f49cb6a61603e77a54ba658/redis_py_cluster-2.0.0-py2.py3-none-any.whl
Installing collected packages: redis, redis-py-cluster
Successfully installed redis-3.3.11 redis-py-cluster-2.0.0

3.单节点Redis实例调用

python3 #进入python3编辑环境
import redis #导入redis的API
r = redis.StrictRedis(host='节点IP地址', port=端口号, db=0, password='授权密码') #调用函数定义连接redis的变量
r.set('键名','键值') #调用函数定义键值
r.get('键名') #调用函数查询键值
[root@db01 /data/redis/conf]# python3
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import redis
>>> r = redis.StrictRedis(host='10.0.0.151', port=6379, db=0, password='123')
>>> r.set('Han','Aspen')
True
>>> r.get('Han')
b'Aspen'
>>> print(r.get('Han'))
b'Aspen'
[root@db01 ~]# redis-cli -h 10.0.0.151 -p 6379 -a 123 get Han
"Aspen"

4.Redis Sentinel高可用调用

python3 #进入python3编辑环境
from redis.sentinel import Sentinel #导入redis sentinel的API
sentinel = Sentinel([('sentinel-IP地址','Sentinel端口')],socket_timeout=0.1) #调用函数连接redis-sentinel
sentinel.discover_master('集群名别名') #调用函数获取主库信息
sentinel.discover_slaves('集群名别名') #调用函数获取从库信息
#配置读写分离
master = sentinel.master_for('集群名别名', socket_timeout=0.1, password='业务节点授权密码') #写节点
slave = sentinel.slave_for('集群名别名', socket_timeout=0.1, password='业务节点授权密码') #读节点
master.set('键名','键值') #测试写操作
slave.get('键名') #测试读操作
[root@mha_manager /application/redis]# python3
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from redis.sentinel import Sentinel
>>> sentinel = Sentinel([('127.0.0.1','26380')],socket_timeout=0.1)
>>> sentinel.discover_master('my_sentinel_1')
('10.0.0.155', 7000)
>>> sentinel.discover_slaves('my_sentinel_1')
[('10.0.0.153', 7000), ('10.0.0.154', 7000)]
>>> master = sentinel.master_for('my_sentinel_1',socket_timeout=0.1,password='123')
>>> slave = sentinel.slave_for('my_sentinel_1',socket_timeout=0.1,password='123')
>>> master.set('Han','Aspen')
True
>>> slave.get('Han')
b'Aspen'
>>> print(slave.get('Han'))
b'Aspen'

5.Redis Cluster集群调用

python3 #进入python3编辑环境
from rediscluster import RedisCluster #导入redis cluster的API
startup_nodes = [{"host":"集群主节点IP地址","port":"端口号"},{"host":"集群主节点IP地址","port":"端口号"},{"host":"集群主节点IP地址","port":"端口号"} ...] #设定启动节点
rc = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
rc.set('键值','键名') #设置键值
print(rc.get("键值")) #查询键值
[root@mha_manager ~]# python3
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from rediscluster import RedisCluster
>>> startup_nodes = [{"host":"10.0.0.153","port":"7001"},{"host":"10.0.0.154","port":"7003"},{"host":"10.0.0.155","port":"7005"}]
TypeError: __init__() got an unexpected keyword argument 'decode_response'
>>> rc = RedisCluster(startup_nodes=startup_nodes,decode_responses=True)
>>> rc.set('Han','Aspen')
True
>>> rc.get('Han')
'Aspen'
>>> print(rc.get('Han'))
Aspen