redis
介绍
简介
- 完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库
优势
-
支持数据的持久化
- 可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用
-
性能极高
- 读的速度是110000次/s,写的速度是81000次/s
-
丰富的数据类型
- 支持二进制案例的Strings, Lists, Hashes, Sets及Ordered Sets数据类型操作
-
原子性
- 所有操作都是原子性的,要么成功执行要么失败完全不执行
-
丰富的特性
- 支持publish/subscribe, 通知, key 过期等等特性
-
支持数据的备份
- 即master-slave模式的数据备份
作用
- MySQL缓存,从架构上提升系统性能,减少磁盘I/O
端口
- 6379
安装配置
依赖包
- yum -y install gcc gcc-c++ make
编译安装
- tar xf redis-4.0.10.tar.gz -C /usr/local/
- cd /usr/local/redis-4.0.10/
- make
编译问题
-
jemalloc/jemalloc.h:No such file or directory
- make MALLOC=libc
-
/deps/hiredis/libhiredis.a: No such file or directory
-
/deps/lua/src/liblua.a: No such file or directory
软连接
- ln -s /usr/local/redis-4.0.10/src/redis-server /usr/bin/redis-server
- ln -s /usr/local/redis-4.0.10/src/redis-cli /usr/bin/redis-cli
启动服务
- redis-server /usr/local/redis-4.0.10/redis.conf &
- 配置文件必须接在启动命令的第一个参数才能生效
客户端登录
-
redis-cli
- ping,响应pong则正常
- -p 指定端口
- -a 指定密码
配置文件
vim /usr/local/redis-4.0.10/redis.conf
bind 127.0.0.1 1.1.1.21
- 默认只监听本地端口,添加本机IP则可以远程连接
port 6379
- 默认端口
timeout 300
- 客户端闲置多长时间后关闭连接,0表示关闭功能
daemonize yes
- redis默认不是作为守护进程运行,改成yes则默认在后台运行
loglevel warning
- 默认记录告警级别为notice,可改成warning
logfile “/usr/local/redis-4.0.10/logs/redis.log”
- 默认不记录日志,可指定保存路径,需提前创建目录
databases 16
- 数据库的数量,默认数据库为0(0-15)。使用SELECT 命令在连接上指定数据库id
save
save 900 1 #900秒内1次改变则做快照
- 快照频次,数据的持久化方式之一
dbfilename dump.rdb
- 快照文件名,自动读取
dir ./
- 快照保存路径
requirepass 123456
- 设置Redis连接密码,默认不开启。连接时通过AUTH 命令提供密码
- 不设置密码则只允许本地登录
protected-mode yes
- 保护模式,只允许本机登录
appendonly no
- aof模式,写操作追加到文件中,数据持久化方式。默认关闭
vm.overcommit_memory = 1
- 内存不足时可能会启动失败,默认为0,改为1可避免
include /path/to/local.conf
- 指定包含其它的配置文件
数据类型
string(字符串)
-
介绍
- redis最基本的类型,一个key对应一个value,最大512MB。类似于变量
- 是二进制安全的,可以包含任何数据。比如jpg图片或者序列化的对象
-
命令
-
SET key value
- 设置指定 key 的值
-
GET key
- 获取指定 key 的值
-
GETRANGE key start end
- 截取key中字符串。第一个0, 最后一个-1
-
GETSET key value
- 将key的值设为value,并返回key的旧值(old value)
-
GETBIT key offset
- 对 key 所储存的字符串值,获取指定偏移量上的位(bit)
-
SETBIT key offset value
- 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
-
SETRANGE key offset value
- 从偏移量offset开始,用value覆写key的值
-
MGET key1 [key2…]
- 获取所有(一个或多个)给定 key 的值
-
MSET key value [key value …]
- 同时设置一个或多个key-value对
-
SETEX key seconds value
- 设置临时键值,过期时间为seconds
-
PSETEX key milliseconds value
- 和SETEX命令相似,单位毫秒
-
SETNX key value
- key不存在则赋值value,存在则不处理
-
MSETNX key value [key value …]
- 所有key不存在时,同时设置多个键值
-
STRLEN key
- 返回key所储存的字符串值的长度
-
INCR key
- key值加一(整数加) 。自增
-
INCRBY key increment
- key值加increment(整数加)
-
INCRBYFLOAT key increment
- key值加increment(小数加)
-
DECR key
- key值减一(整数减)
-
DECRBY key decrement
- key值减decrement(整数减)
-
APPEND key value
- 字符串拼接,value拼到key值后面
-
hash(哈希)
-
介绍
- 键值对的集合。一个键中可以有多组域值对filed-value
- 是一个string类型的field和value的映射表,特别适合用于存储对象
- 每个hash可以存储2^32 -1个键值对
-
命令
-
HSET key field value
- 将哈希表key中的字段field的值设为value
-
HSETNX key field value
- 只有在字段field不存在时,设置哈希表字段的值
-
HMSET key field1 value1 [field2 value2 ]
- 同时将多个field-value(域-值)对设置到哈希表key中
-
HKEYS key
- 获取所有哈希表中的字段
-
HVALS key
- 获取哈希表中所有值
-
HLEN key
- 获取哈希表中字段的数量
-
HMGET key field1 [field2]
- 获取所有给定字段的值
-
HDEL key field1 [field2]
- 删除一个或多个哈希表字段
-
HEXISTS key field
- 查看哈希表 key 中,指定的字段是否存在
-
HGET key field
- 获取存储在哈希表中指定字段的值
-
HGETALL key
- 获取在哈希表中指定 key 的所有字段和值
-
HINCRBY key field increment
- 键中指定字段值加increment
-
HINCRBYFLOAT key field increment
- 键中指定字段浮点值加increment
-
HSCAN key cursor [MATCH pattern] [COUNT count]
- 迭代哈希表中的键值对
-
list(列表)
-
介绍
- 简单的字符串列表,按照插入顺序排序,可以在头部或尾部插入
- 一个列表最多可以包含2^32 - 1个元素 (4294967295)
-
命令
-
BLPOP key1 [key2 ] timeout
- 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
-
BRPOP key1 [key2 ] timeout
- 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
-
BRPOPLPUSH source destination timeout
- 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止
-
LINDEX key index
- 通过索引获取列表中的元素
-
LINSERT key BEFORE|AFTER pivot value
- 在列表的元素前或者后插入元素
-
LLEN key
- 获取列表长度
-
LPOP key
- 移出并获取列表的第一个元素
-
LPUSH key value1 [value2]
- 将一个或多个值插入到列表头部
-
LPUSHX key value
- 将一个值插入到已存在的列表头部
-
LRANGE key start stop
- 获取列表指定范围内的元素
-
LREM key count value
- 移除列表元素
-
LSET key index value
- 通过索引设置列表元素的值
-
LTRIM key start stop
- 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
-
RPOP key
- 移除并获取列表最后一个元素
-
RPOPLPUSH source destination
- 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
-
RPUSH key value1 [value2]
- 在列表中添加一个或多个值
-
RPUSHX key value
- 为已存在的列表添加值
-
set(无序集合)
-
介绍
- string类型的无序集合,集合内元素具有唯一性,最多2^32 - 1个元素
-
命令
-
SADD key member1 [member2]
- 向集合添加一个或多个成员
-
SCARD key
- 获取集合的成员数
-
SDIFF key1 [key2]
- 返回给定所有集合的差集
-
子主题 15
- SDIFFSTORE destination key1 [key2] #返回给定所有集合的差集并存储在 destination 中
-
SINTER key1 [key2]
- 返回给定所有集合的交集
-
SINTERSTORE destination key1 [key2]
- 返回给定所有集合的交集并存储在 destination 中
-
SISMEMBER key member
- 判断 member 元素是否是集合 key 的成员
-
SMEMBERS key
- 返回集合中的所有成员
-
SMOVE source destination member
- 将 member 元素从 source 集合移动到 destination 集合
-
SPOP key
- 移除并返回集合中的一个随机元素
-
SRANDMEMBER key [count]
- 返回集合中一个或多个随机数
-
SREM key member1 [member2]
- 移除集合中一个或多个成员
-
SUNION key1 [key2]
- 返回所有给定集合的并集
-
SUNIONSTORE destination key1 [key2]
- 所有给定集合的并集存储在 destination 集合中
-
SSCAN key cursor [MATCH pattern] [COUNT count]
- 迭代集合中的元素
-
zset(有序集合)
-
介绍
- sorted set,string类型元素的集合,不允许重复的成员
- 每个元素关联一个double类型的分数,通过分数来为集合中的成员进行从小到大的排序
- 分数(score)可以重复,相同分数排序时按插入顺序
-
命令
-
ZADD key score1 member1 [score2 member2]
- 向有序集合添加一个或多个成员,或者更新已存在成员的分数
-
ZCARD key
- 获取有序集合的成员数
-
ZCOUNT key min max
- 计算在有序集合中指定区间分数的成员数
-
ZINCRBY key increment member
- 有序集合中对指定成员的分数加上增量 increment
-
ZINTERSTORE destination numkeys key [key …]
- 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
-
ZLEXCOUNT key min max
- 在有序集合中计算指定字典区间内成员数量
-
ZRANGEBYLEX key min max [LIMIT offset count]
- 通过字典区间返回有序集合的成员
-
ZRANGE key start stop [WITHSCORES]
- 通过索引区间返回有序集合成指定区间内的成员
-
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]
- 通过分数返回有序集合指定区间内的成员
-
ZRANK key member
- 返回有序集合中指定成员的索引
-
ZREM key member [member …]
- 移除有序集合中的一个或多个成员
-
ZREMRANGEBYLEX key min max
- 移除有序集合中给定的字典区间的所有成员
-
ZREMRANGEBYRANK key start stop
- 移除有序集合中给定的排名区间的所有成员
-
ZREMRANGEBYSCORE key min max
- 移除有序集合中给定的分数区间的所有成员
-
ZREVRANGE key start stop [WITHSCORES]
- 返回有序集中指定区间内的成员,通过索引,分数从高到底
-
ZREVRANGEBYSCORE key max min [WITHSCORES]
- 返回有序集中指定分数区间内的成员,分数从高到低排序
-
ZREVRANK key member
- 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
-
ZSCORE key member
- 返回有序集中,成员的分数值
-
ZUNIONSTORE destination numkeys key [key …]
- 计算给定的一个或多个有序集的并集,并存储在新的 key 中
-
ZSCAN key cursor [MATCH pattern] [COUNT count]
- 迭代有序集合中的元素(包括元素成员和元素分值)
-
redis事务
介绍
-
Redis 事务可以一次执行多个命令
-
事务是一个单独的隔离操作
- 事务中的所有命令都会序列化、按顺序地执行
-
事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
-
事务是一个原子操作
- 事务中的命令要么全部被执行,要么全部都不执行
三个阶段
-
开始事务
- MULTI
-
命令入队
- 顺序写入命令
-
执行事务
- EXEC
redis服务器命令
设置密码
-
临时
- CONFIG SET requirepass 123
-
永久
- CONFIG SET requirepass 123
CONFIG REWRITE - 修改配置文件
- CONFIG SET requirepass 123
查看密码配置
- CONFIG GET requirepass
验证密码
- AUTH 123
查看所有配置
- CONFIG GET *
查看服务器信息
- INFO
切换数据库
- SELECT 1
CONFIG GET parameter
- 获取指定配置参数的值
CONFIG SET parameter value
- 修改 redis 配置参数,无需重启
CONFIG REWRITE
- 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写
BGREWRITEAOF
- 异步执行一个 AOF(AppendOnly File) 文件重写操作
BGSAVE
- 在后台异步保存当前数据库的数据到磁盘
CLIENT KILL [ip:port] [ID client-id]
- 关闭客户端连接
CLIENT LIST
- 获取连接到服务器的客户端连接列表
CLIENT GETNAME
- 获取连接的名称
CLIENT PAUSE timeout
- 在指定时间内终止运行来自客户端的命令
CLIENT SETNAME connection-name
- 设置当前连接的名称
CLUSTER SLOTS
- 获取集群节点的映射数组
COMMAND
- 获取 Redis 命令详情数组
COMMAND COUNT
- 获取 Redis 命令总数
COMMAND GETKEYS
- 获取给定命令的所有键
TIME
- 返回当前服务器时间
COMMAND INFO command-name [command-name …]
- 获取指定 Redis 命令描述的数组
CONFIG RESETSTAT
- 重置 INFO 命令中的某些统计数据
DBSIZE
- 返回当前数据库的 key 的数量
DEBUG OBJECT key
- 获取 key 的调试信息
DEBUG SEGFAULT
- 让 Redis 服务崩溃
FLUSHALL
- 删除所有数据库的所有key
FLUSHDB
- 删除当前数据库的所有key
INFO [section]
- 获取 Redis 服务器的各种信息和统计数值
LASTSAVE
- 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示
MONITOR
- 实时打印出 Redis 服务器接收到的命令,调试用
ROLE
- 返回主从实例所属的角色
SAVE
- 异步保存数据到硬盘
SHUTDOWN [NOSAVE] [SAVE]
- 异步保存数据到硬盘,并关闭服务器
SLAVEOF host port
- 将当前服务器转变为指定服务器的从属服务器(slave server)
SLOWLOG subcommand [argument]
- 管理 redis 的慢日志
SYNC
- 用于复制功能(replication)的内部命令
多实例
创建实例目录
- cd /usr/local/redis-4.0.10
- mkdir 6379 6380 6381
创建实例配置文件
- cp redis.conf 6379/
修改各实例的配置
-
端口,pid文件,log文件,数据目录
-
6379/redis.conf
- port 6379
pidfile “/var/run/redis_6379.pid”
logfile “/usr/local/redis-4.0.10/6379/redis.log”
dir “/usr/local/redis-4.0.10/6379”
- port 6379
-
6380/redis.conf
- sed ‘s/6379/6380/’ 6379/redis.conf > 6380/redis.conf
-
6381/redis.conf
- sed ‘s/6379/6381/’ 6379/redis.conf > 6381/redis.conf
利用实例配置文件启动实例
- redis-server /usr/local/redis-4.0.10/6379/redis.conf
- redis-server /usr/local/redis-4.0.10/6380/redis.conf
- redis-server /usr/local/redis-4.0.10/6381/redis.conf
数据缓存验证
实验
- 使用redis做mysql数据库缓存
目的
- 观察redis用作数据库缓存的效果,了解在工作中如何使用redis
实现效果
- 如果访问时与数据库通信则在终端中显示过程,否则不会在终端显示
配置java环境
- tar xf jdk-8u181-linux-x64.tar.gz -C /usr/local
- ln -s /usr/local/jdk1.8.0_181/ /usr/local/java
-
vim /etc/profile.d/java.sh
export JAVA_HOME=/usr/local/java
export PATH=
J
A
V
A
H
O
M
E
/
b
i
n
:
JAVA_HOME/bin:
JAVAHOME/bin:PATH
- . /etc/profile.d/java.sh
- java -version
数据库配置
-
创建库
- create database shopping;
-
授权用户
- grant all on shopping.* to java@localhost identified by ‘123’;
项目配置
-
解压
- tar xf java-redis-mysql.tar
-
导入数据
- cat java-redis-mysql/java/user.sql |mysql -ujava -p123 -D shopping
-
修改配置文件
- 修改文件中MySQL及redis的用户名、密码、访问地址(本机则不用改)
-
修改项目脚本
- vim /root/java-redis-mysql/java/bin/startup.sh
src=readlink -f $0
#获取链接文件的目标路径
prefix=dirname $src
#获取文件所在的目录
cd $prefix
java -jar …/springboot.jar --spring.config.location=…/application.yml - 原脚本中使用相对路径,若在其他地方运行或安装在其他目录则会运行失败
- vim /root/java-redis-mysql/java/bin/startup.sh
启动项目
- /root/java-redis-mysql/java/bin/startup.sh
访问测试
-
启动成功后,开启另外一个终端
-
curl 127.0.0.1:8080/user/3
- 第一次访问,因缓存中没有相应数据,会直接访问到数据库,应用上有信息输出
-
curl 127.0.0.1:8080/user/3
- 第二次访问,能正常获取信息,应用上没有任何信息输出,说明访问了缓存
-
curl 127.0.0.1:8080/user/5
查看redis数据
- redis-cli
-
keys *
-
get user#3
数据持久化
RDB
-
方式
- Redis Data Base 按照一定的时间间隔对数据集创建基于时间点的快照
-
优点
- RDB是Redis数据集的基于时间点的紧凑的副本,非常适合于备份场景
- 与AOF相比RDB在数据集较大时能够以更快的速度恢复
-
缺点
- 可能造成丢失的数据更多
- 需经常调用fork()函数以开辟子进程来实现持久化,性能不足时调用耗时长
-
设置
- 默认情况下Redis在磁盘上创建二进制格式的命名为dump.rdb的数据快照
- save
save 900 1 #900秒内1次改变则做快照
AOF
-
方式
- Append Only File 记录Server收到的写操作到日志文件,在Server重启时通过回放这些写操作来重建数据集
-
优点
- Redis持久化更可靠,三种fsync策略供选择
- AOF日志是append only方式产生的日志,可以使用redis-check-aof工具快速进行修复数据
- 当AOF日志逐渐变大后,Redis可在后台自动的重写AOF日志
- AOF日志的格式易于理解易于解析
-
缺点
- 同样的数据集AOF文件要比RDB文件大很多
- 根据使用的fsync方式不同AOF可能比RDB慢很多
- 一些特定的命令可能存在bug从而导致重载AOF日志时不能重建出完全一样的数据集
-
设置
-
appendonly no 改成 appendonly yes
-
appendfilename “appendonly.aof”
- 默认AOF文件名
-
appendfsync everysec
- 每秒调用一次fsync刷新数据到磁盘
-
no-appendfsync-on-rewrite no
- 当进程中BGSAVE或BGREWRIREAOF命令正在执行时不阻止主进程中的fsync()调用。当存在延迟问题时需调整为yes
-
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb- 当AOF增长率为100%且达到了64MB时开始自动重写AOF
-
-
fsync调用模式
-
no
- 全由操作系统决定刷数据的时机。最快但最不安全
-
everysec
- 默认值, 每秒一次刷新。足够快,最多丢失一秒的数据
-
always
- 每执行一次写操作便刷一次数据到磁盘。最慢但最安全
-
选择
- 取决于具体的应用场景,通常,两种方式可同时使用
Redis 4.0混合持久化
-
配置(需先开启AOF)
-
AOF重写前先将内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件
-
于是在Redis重启的时候,可以先加载RDB的内容,然后再重放增量AOF日志就可以完全替代之前的AOF全量文件重放,因此重启效率大幅得到提升
主从复制
介绍
-
单台redis问题
-
从结构上,单个Redis服务器会发生单点故障,且负载压力大
-
从容量上,单个Redis服务器内存容量有限,且服务器的内存容量不能全部用于redis
-
解决方案
- 主从、集群
-
-
Redis主从复制
- 支持多个数据库之间的数据同步
- 主数据库(Master)可以进行读写操作,当发生写操作的时候自动将数据同步到从数据库
- 从数据库(Slave)一般是只读的,并接收主数据库同步过来的数据
- 一个主数据库可以有多个从数据库,而一个从数据库只能有一个主数据库
- 主数据库主要进行写操作,从数据库负责读操作
原理
-
复制初始化
(全量复制)- 当一个从数据库启动时,会向主数据库发送sync命令
- 主数据库接收到sync命令后会开始在后台保存快照(行rdb操作)并将保存期间接收到的命令缓存起来
- 当快照完成后,主库会将快照文件和所有缓存的命令发送给从数据库
- 从数据库收到后,会载入快照文件并执行收到的缓存的命令
-
复制同步
(增量复制)- 全量复制后后,主数据库每收到写命令时就会将命令同步给从数据库,从而保证主从数据库数据一致
配置
-
主服务器
- bind 0.0.0.0
requirepass 123
- bind 0.0.0.0
-
从服务器
- bind 0.0.0.0
slaveof 1.1.1.21 6379
masterauth 123
- bind 0.0.0.0
-
启动测试
-
查看主从复制信息
- info replication
哨兵
(sentinel)
-
官方文档
- https://redis.io/topics/sentinel
-
作用
-
监控(Monitoring)
- 哨兵会不断地检查你的Master和Slave是否运作正常
-
提醒(Notification)
- 当被监控的某个Redis节点出现问题时, 通过API向管理员或其他应用程序发送通知
-
自动故障迁移
(Automatic failover)- 当一个Master不能正常工作时,将其中一个Slave升级为新的Master, 并让其他Slave改为从新的Master复制数据
- 原Master恢复正常工作后,会自动变成新Master的Slave
- Master和Slave服务器切换后,Master的redis.conf、Slave的redis.conf和sentinel.conf的配置文件的内容都会发生相应的改变
-
-
工作方式
- 每个Sentinel进程每秒一次向Master、Slave及其他Sentinel发送一个PING命令
- 如果一个实例(instance)距上次有效回复PING的时间超过down-after-milliseconds值, 则会被Sentinel标记为主观下线(SDOWN)
- 如果Master被标记为SDOWN,则正在监视这个Master的所有Sentinel要以每秒一次的频率确认Master的确进入了主观下线状态
- 当在指定的时间范围内,确认Master进入了SDOWN的Sentinel数量达到配置文件指定的值,Master则会被标记为客观下线(ODOWN)
- 一般情况, 每个Sentinel会以每10秒一次的频率向集群中的所有Master、Slave发送INFO命令
- 当Master被Sentinel标记为ODOWN时,Sentinel向所有 Slave发送 INFO 命令的频率会从 10 秒一次改为每秒一次
- 若没有足够数量的Sentinel同意Master下线, Master的客观下线状态就会被移除。
若Master重新向Sentinel发送PING命令返回有效回复,Master的主观下线状态就会被移除
-
缺陷
-
数据丢失
-
异步复制导致
- 数据还没复制到slave,master就宕机
-
脑裂导致
- master因网络问题无法与slave连接,当仍在运行。哨兵判断其为宕机,切换新的master,此时就有两个master,称之为脑裂
- 脑裂时client仍向旧master写入,当其恢复时作为slave会清空数据
-
规避
- min-slaves-to-write 1 #至少有一个slave
min-slaves-max-lag 10 #复制延时超过10s则master拒绝写入
- min-slaves-to-write 1 #至少有一个slave
-
-
不能横向扩容
- 集群解决
-
-
实验
bind 0.0.0.0 #4.0中不能监听127.0.0.1,否则哨兵无法通信
port 26379
daemonize yes
logfile “/var/log/sentinel_26379.log”
sentinel monitor mymaster 1.1.1.21 6379 2 #定为ODOWN所需的sentinel数
sentinel auth-pass mymaster 123 #设置master和slaves验证密码
sentinel down-after-milliseconds mymaster 5000 #SDOWN超时时间(ms)
sentinel parallel-syncs mymaster 1 #故障转移时与新master同步的slave数
sentinel failover-timeout mymaster 10000 #failover操作限定时间
- 启动哨兵(所有)
- cd /usr/local/redis-4.0.10/
- ./src/redis-sentinel sentinel.conf &
- 测试
- 停掉master,观察master是否切换
- 重启原master,观察主从状态
- 日志
- 新增哨兵
- +sentinel sentinel 2b445220f3e35ed75f5ba9802b03f364610fc49b 1.1.1.24 26379 @ mymaster 1.1.1.21 6379
- 判定sdown
- +sdown master mymaster 1.1.1.21 6379
- 判定odown
- +odown master mymaster 1.1.1.21 6379 #quorum 3/2
- 故障迁移
- +config-update-from sentinel fc43a362d6bcca2f10e05113df73af5bd9ab2562 1.1.1.25 26379 @ mymaster 1.1.1.21 6379
- +switch-master mymaster 1.1.1.21 6379 1.1.1.25 6379
- +slave slave 1.1.1.11:6379 1.1.1.11 6379 @ mymaster 1.1.1.25 6379
+slave slave 1.1.1.24:6379 1.1.1.24 6379 @ mymaster 1.1.1.25 6379
+slave slave 1.1.1.21:6379 1.1.1.21 6379 @ mymaster 1.1.1.25 6379
- 移除sdown
- -sdown slave 1.1.1.21:6379 1.1.1.21 6379 @ mymaster 1.1.1.25 6379
集群cluster
介绍
-
官方文档
- https://redis.io/docs/manual/scaling/
-
Redis Cluster
- 数据会在多个Redis节点之间自动分片
- 当集群中的一部分节点失效或者无法进行通讯时, 仍然可以继续提供服务
- 不支持需要同时处理多个键的Redis命令
redis-cluster设计
- 无中心结构,每个节点保存数据和整个集群状态
- 客户端与redis节点直连,不需要中间proxy层。连接集群中任意可用节点即可
- 所有redis节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽
- redis-cluster把所有物理节点映射到[0-16383]slot上,cluster负责维护node <-> slot <-> value
- Redis集群预设16384个槽,当需要向集群写入数据时,根据CRC16(key) % 16384的值,将key放入该值对应的槽中
Redis-Cluster节点分配
-
假设A,B,C三个节点,它们可以是一台机器上的三个端口,也可以是三台不同的服务器
-
采用哈希槽(hash slot)的方式来分配16384个slot
-
承担slot
- A覆盖0-5460
- B覆盖5461-10922
- C覆盖10923-16383
-
存取数据
- 假设存入foo=‘bar’,按照算法得到哈希槽为12182,则把foo存入C节点
- client连接任意节点获取foo值,用相同算法,内部跳转到C节点上获取数据
-
新增主节点
-
若新增节点D,redis-cluster从各个节点的前面各拿取一部分slot到D上
-
承担slot
- A覆盖1365-5460
- B覆盖6827-10922
- C覆盖12288-16383
- D覆盖0-1364,5461-6826,10923-12287
-
Redis-Cluster主从模式
- 为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点
- 主节点提供数据存取,从节点数据备份。当主节点宕机后顶替成为主节点
容错机制-投票
- 若半数以上master节点与故障节点通信超过cluster-node-timeout时间,认为该节点故障,自动触发故障转移操作.故障节点对应的从节点自动升级为主节点
- 如果集群任意master挂掉,且当前master没有slave,集群进入fail状态
集群部署
-
实验规划
- 使用不同端口启动多实例:7000、7000、7000、7000、7000、7000
-
配置多实例
- bind 127.0.0.1
protected-mode yes
port 7000
daemonize yes
#requirepass passwd #禁用密码
pidfile /var/run/redis_7000.pid
logfile “/usr/local/redis/7000/redis.log”
dir /usr/local/redis/7000
appendonly yes
cluster-enabled yes
cluster-config-file nodes-7000.conf
- bind 127.0.0.1
-
安装ruby(2.2.2以上)
- yum install -y zlib-devel
- tar xf ruby-3.0.0.tar.gz
- cd ruby-3.0.0
- ./configure
- make && make install
- ruby -v
-
安装rubygems
- tar xf rubygems-3.2.5.tgz
- cd rubygems-3.2.5
- ruby setup.rb
-
替换gem源为国内源
- gem source -a http://mirrors.aliyun.com/rubygems/ -r https://rubygems.org/
-
安装redis支持
- gem install redis -v 4.1.0
-
创建集群
-
ln -s /usr/local/redis-4.0.10/src/redis-* /usr/bin
-
redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
- yes
-
-
集群测试
-
客户端连接到集群的任意主节点
- redis-cli -c -p 7000
-
set school qfedu
-
get school
-
集群状态查看
- redis-trib.rb check 127.0.0.1:7000
-
集群节点查看
- redis-cli -p 7001 cluster nodes | grep master
-
故障转移
- redis-cli -p 7002 debug segfault
- redis-cli -p 7000 cluster nodes|grep master
-
扩容
-
创建启动实例7006、7007
-
加主节点
- redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7001
新增 已有
- redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7001
-
加从节点
- redis-trib.rb add-node --slave --master-id d57b089d9dd85abc2a0f1c3c29c40e8189941965 127.0.0.1:7007 127.0.0.1:7001
-
重新分片
-
手动
- redis-trib.rb reshard 127.0.0.1:7001
-
自动
- redis-trib.rb rebalance --use-empty-masters 127.0.0.1:7001
-
-
-
删除节点
-
正常状态
- redis-trib.rb del-node 127.0.0.1:7006 733e4f9e95106fed95a0bd075ec9daa5c2e36be6
-
fail状态
- redis-cli -p 7000 cluster forget 733e4f9e95106fed95a0bd075ec9daa5c2e36be6
- 每个正常节点上执行一次
-
-
-
常见问题处理
-
https://www.cnblogs.com/gered/p/11793451.html
-
1
-
报错
- redis-trib.rb check 127.0.0.1:7000
…
[ERR] Not all 16384 slots are covered by nodes
- redis-trib.rb check 127.0.0.1:7000
-
原因
- 删除了主节点但未移除slot导致不够16384个
-
解决
- redis-trib.rb fix 127.0.0.1:7000
- redis-trib.rb check 127.0.0.1:7000
- 如果slots分布不均匀重新分配slots
-
-
2
-
报错
- ERR Slot 4981 is already busy
-
原因
- 创建集群时实例上有数据时
-
解决
- 找出有数据的节点执行flushall及cluster reset指令清除数据
-
-
3
-
安装报错
- gem install redis -v 4.1.0
- ruby setup.rb
-
解决
- 先安装zlib-devel,再重新执行
-
-