Redis
介绍
Redis是一个开源的,内存中数据结构存储系统,可以作为数据库,缓存和消息中间件,例如String、Hash、List、Set、SortedSet等等。
它可以作为:
- 分布式缓存
- redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
- 缓存穿透、击穿、雪崩
- 分布式锁
- 队列
Redis官网地址:
英文:https://redis.io/
中文:https://redis.com.cn/
源码:https://github.com/redis/redis
在线测试:https://try.redis.io/
Redis命令参数:http://doc.redisfans.com/
安装
Window安装:
下载地址:https://github.com/zkteco-home/redis-windows/releases
- 选择对应的版本进行下载,然后解压到本地
- 进行配置环境变量,在系统变量Path这里添加redis的安装目录,如:D:\redis\redis-windows-7.0.10
- 然后进行启动,在安装目录下执行cmd,再执行 redis-server.exe redis.conf 进行启动
- 然后可通过客户端工具查看是否启动成功
Linux安装:
我们常用都是Linux版本进行安装Redis
下载地址:https://redis.io/download/
-
前提需要安装gcc编译环境,需要64位
gcc -v # 查看版本,gcc版本需要大于4.8 yum -y install gcc-c++ # 安装c++库环境 redis -server -V # 查看redis版本
-
进行下载包,放在某个位置,进行解压
tar -zxvf redis7.0.9.tar.gz # 一般放在/opt目录下解压 cd redis7.0.9 # 进入该目录 make && make install # 在该目录下执行 cd /usr/local/bin # 默认安装的位置查看 # 一般我们安装完,进行复制一份原始的redis的配置文件 mkdir /myredis # 在跟目录创建一个myredis目录 cp redis.conf /myredis/redis7.conf # 将原始redis配置文件复制到myredis目录下
-
修改redis7.conf 配置文件,该文件作为Redis的配置文件
vim /myredis/redis7.conf 默认 daemonize no 改为 daemonize yes # 将服务作为后端启动 默认 protected-mode yes 改为 protected-mode no # 允许其他程序连接到Redis,关闭保护模式 默认 bind 127.0.0.1 改为 直接注释掉(默认bind 127.0.0.1只能本机访问)或改成本机IP地址,否则影响远程IP连接 添加 redis密码 改为 requirepass 你自己设置的密码 (生产环境需要设置)
-
进行启动
cd /usr/local/bin # 在该目录 redis-server /myredis/redis7.conf # redis-server是启动命令,后面的指定配置文件启动 ps -ef|grep redis|grep - v grep # 查看redis的进程和端口,默认是6379
-
连接服务
# 客户端进行连接 - 方式1:输入该命令会有警告 redis-cli -a 设置的密码 -p 6379 # 客户端进行连接 - 方式2: redis-cli -p 6379 # 此时会提示 NOAUTH... 提示进行输入密码 auth 设置的密码 # 输入完,也可以登陆 # 客户端进行连接 - 方式3: redis-cli -a 设置的密码 -p 6379 2>/dev/null # 连接成功后,输入ping ,如返回 pong 就代表成功 # quit 是退出客户端 # 关闭客户端连接 - 在其他redis登陆,关闭已经连接的redis的客户端,在外面执行 redis-cli -p 6379 shutdown
卸载
# 先停掉已启动redis服务
ps -ef|grep redis
redis-cli shutdown
# 删除/usr/local/lib目录下的redis文件
ls - l /usr/local/bin/redis-*
rm - rf /usr/local/bin/redis-*
# 删除确保,没有其他文件
ls - l /usr/local/bin/redis-*
Docker版本安装Redis
在Docker篇有:https://blog.csdn.net/yanshengren520/article/details/122018441?spm=1001.2014.3001.5501
Redis7新特性
最新版本:https://github.com/redis/redis/releases
十大数据类型
- String : 一个字符串value最多是512M,是二进制安全的字符串,支持序列化
- List :底层是双向链表,List最多可存40亿元素
- Hash:(哈希表)使用存对象,是键值对
- Set:(无序集合)不能有重复的
- ZSet:(有序集合)
- GEO:(地理空间)存储地理位置信息,计算2个位置距离
- HyperLogLog:(基数统计)用来做基数统计的,
- bitmap:(位图)由0和1状态表现二进制bit数组,可用于记录一周内是否打卡状态
- bitfield:(位域)一次性操作多个比特位域
- Stream:(流)主要用于消息队列,支持发布订阅
Redis(Key)操作命令
一些API命令讲解:https://redis.com.cn/commands.html
注:key的值是区分大小写的
# 查
127.0.0.1:6379> keys * # 查看当前库里所有的key
exists key名 # 判断某个key是否存在, 1代表存在,0代表不存在
type key名 # 查看你的key是什么类型
expire key名 秒数 # 给key设置过期时间,单位(描述)
ttl key名 # 查看key还有多少秒过期,单位(秒) -1代表永不过期 -2 代表已过期
# 删除
del key名 # 删除指定的key数据
unlink key名 # 非阻塞删除,先keyspace元数据删除,没真正的删除会在后续异步中操作,不会阻塞的删除
# 对数据库的操作,redis默认是有16个数据库的,默认是0号库
move key名 dbindex [0-15] # 将当前数据库的key移动到指定的数据库中 例子:move key名 3 (把key移到3号库)
select dbindex [0-15] # 切换数据库[0-15],默认为0,例子:select 3 (切换到3号库)
dbsize # 查看当前数据库key的数量,相当于SQL的 select count(key)
flushdb # 清空当前库
flushall # 清空16个数据库,谨慎使用
# 批量删除 - 通过管道进行批量删除,“***” 代表 key前缀
redis-cli -a 密码 keys "***" | xargs redis-cli del
字符串(String)
# 设置值 20秒过期 ex代表以秒为单位设置 px代表以毫秒为单位设置
set key名 value值 ex 20
# 修改key的值,如果后面加了keepttl,代表保留设置前指定的过期时间,只改value值,过期时间不重置
set key名 value值 keepttl
# 获得对应的值
get key名
# 同时设置一个或多个键值对
MSET [key1] [value1] [key2] [value2] [key3] [value3]
# 同时获取多个key的值
MGET [key1] [key2] [key3]
# 同时设置一个或多个 key-value 对 必须保证key都不存在才能成功
MSETNX [key1] [value1] [key2] [value2]
# 这个相当于对value值进行截取
GETRANGE [key] 0 -1 # 获取这个key的值的全部
GETRANGE [key] 0 2 # 获取这个key的值索引0到索引2之间的值
# 获取字符串长度和内容相加
STRLEN [key] # 获取key对应的值的长度
APPEND [key] [vale] # 添加字符串内容
# 数值增减,value值一定是数字
INCR [key] # 递增数字 +1
INCRBY [key] [increment] # 增加指定的整数 +increment
DECR [key] # 递减数字 -1
DECRBY [key] [increment] # 减少指定的整数 -increment
# 分布式锁
setnx/setex [key] [过期时间] [value] # 设置带过期时间的key,动态设置,例子:setnx k1值 10 v1值
setnx [key] [value] # 只有在 key 不存在时设置 key 的值。
# 一般是两个命令连用,写成lua脚本连用,具体在Redis高级分布式锁中使用
# getset(先get再set)
getset [key] [value] # 给定 key 的值设为 value ,并返回 key 的旧值
列表(List)
单个key,多个value,一般用在栈、队列、消息队列等场景,底层是双端链表
lpush [key] [value] ... # 从(左边)放入元素 例:lpush key1 1 2 3 4
Rpush [key] [value] ... # 从(右边)放入元素
lrange [key] 0 -1 # 从左边开始遍历列表 只能从左边遍历
lpop [key] # 最左边的出栈 也就是lrange遍历的第一个,也就是删除掉
rpop [key] # 最右边的出栈 也就是lrange遍历的最后一个
lindex [key] [index] # 通过索引值获取值
llen [key] # 获得元素个数
lrem [key] [num] [value] # 从左往右删除 num个值为 value的值
lrem [key] 0 [value] # 从左往右删除所有值为value的值
ltrim [key] [开始] [结束] # 截取指定范围的值后再赋给[key],也就是删除这个区间外的值
RPOPLPUSH [key1] [key2] # 移除列表的最后一个元素,并将该元素添加到另一个列表的第一个并返回
lset [key] [index] [value] # 将key的第 index 个索引值改为value
linsert [key] before/after [value1] [value2] # 在list某个已有值的前后再添加具体
应用场景:
用户id收藏了文章1、文章2、文章3 ,命令:lpush likearticle:用户id 文章id1 文章id2 文章id3
查询用户最近收藏3条文章; lrange likearticle:用户id 0 3 (0到3条记录)
哈希(Hash)
目前基本不用,结果像Map<String,Map<Object,Object>
hset user id 11 name z1 # 创建一个hash的key
hget user id # 获取key里其中一个值
hlen # 获取在某个key内的全部数量
hexists [key] [k1] # 看key中是否有k1这个键
hkeys [key] # 获取key里面的所有key
hvals [key] # 获取key里面的所有value
集合(Set)
单个key,多个value,无重复
SADD key member ... # 添加元素 例:sadd set1 1 2 3 3 4 ,插进去的数据是1 2 3 4
SMEMBERS key # 遍历集合中所有元素
SISMEMBER key member # 判断元素是否在集合中
SREM key member ... # 删除元素
SCARD key # 获取集合长度
SRANDMEMBER key m # 从set集合里面随机取出m个 ,如果超过最大数量就全部取出 如果写的值是负数,比如-3 ,表示需要取出3个,但是可能会有重复值 不会删除
SPOP key m # 从集合中随即弹出一个元素 出一个删一个
SMOVE key1 key2 在key1里已存在的某个值 # 将key1的已存在的某个值赋给key2
# 集合运算
SDIFF keyA keyB # A - B 属于A但不属于B的元素构成的集合
SUNION keyA keyB # A U B 属于A或者属于B的元素合并后的
SINTER keyA keyB # A ∩ B 属于A同时属于B
SINTERCARD numkeys keyA keyB [LIMIT limit] # 不返回结果集,只返回结果的基数
应用场景:
-
微信抽奖
用户1参加抽奖,命令:sadd key 用户id 显示多少人参加,命令:SCARD key 进行抽奖,命令:SRANDMEMBER key 2 (随机抽2个人,但2人不删除,可还可以参与抽奖) 命令:spop key 3 (随机抽3人,会从集合中删除掉)
-
集合运算
sadd s1 1 2 3 4 sadd s2 3 4 5 6 SDIFF s1 s2 # 求差集 得出 1 2 SDIFF s2 s1 # 求差集 得出 5 6 SINTER s1 s2 # 求交集 得出 3 4
有序集合(Zset)
有序的集合,在set的基础上加了一个score分数值,根据分数值排序
ZADD key score member [ score member ] # 添加元素 例:zadd k1 60 王者 30 飞车 20 派对
ZRANGE key start stop [WITHSCORES] # 返回元素分数从小到大的顺序 返回索引从start到stop之间的所有元素例:ZRANGE k1 0 -1 (全部) 或 ZRANGE k1 0 -1 (全部) withscores (带分数值返回)
ZREVRANGE key 0 - 1 [WITHSCORES] # 反序
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] # 获取指定分数范围的元素(min,max) 不包含 limit是返回限制,返回多少个
ZSCORE key member # 获取元素的分数
ZCARD key # 获取集合中元素的数量
ZREM key 某score下对应的value值 # 删除元素
ZINCRBY key increment member # 增加某个元素的分数
ZCOUNT key min max # 获得指定分数范围内的元素个数
ZRANK key values值 # 获得下标值
ZREVRANK key values # 逆序获得下标值、
位图(bitmap)
由 0 和 1 表示的二进制位的 bit 数组
SETBIT key offset value # 将第offset的值设为value value只能是0或1 offset 从0开始
GETBIT key offset # 获得第offset位的值
STRLEN key # 得出占多少字节 超过8位后自己按照8位一组一byte再扩容
BITCOUNT key # 得出该key里面含有几个1
BITOP and destKey key1 key2 # 对一个或多个 key 求逻辑并,并将结果保存到 destkey
BITOP or destKey key1 key2 # 对一个或多个 key 求逻辑或,并将结果保存到 destkey
BITOP XOR destKey key1 key2 # 对一个或多个 key 求逻辑异或,并将结果保存到 destkey
BITOP NOT destKey key # 对key 求逻辑非,并将结果保存到 destkey
应用场景:
# 做打卡签到场景
# 第一天打开:setbit sign:用户id1:202201 0 1
# 第二天打开:setbit sign:用户id1:202202 1 1
# 第三天打开:setbit sign:用户id1:202203 2 1
# 第六天打开:setbit sign:用户id1:202203 5 1
# 查看第三天有没有来, getbit sign:用户id1:202203 2 # 得出结果是 0
# 查看统计这个月打开几次:bitcount sign:用户id1:202203 0 30 # 得出结果是4个数
基数统计(HyperLogLog)
它本身不会存储元素本身,统计某个网站的UV,某个文章的UA,UA是(独立访客,一般是客户端的IP)
pfadd hel 1 3 5 7 # 添加元素 ,然后统计个数是:4
pfadd he2 1 3 3 4 6 7 # 添加元素 ,然后统计个数是:5
pfcount hel # 打印he1个数 ,结果是 4
pfmerge he新 he1 he1 # 添加元素,多个元素
pfcount he新 # 打印he新个数 ,结果是 6
# 适合做统计个数,并不保留结果,添加元素,添加客户端iP
地理空间(GEO)
用二维的经纬度表示,经度范围 (-180, 180],纬度范围 (-90, 90],只要我们确定一个点的经纬度就可以名取得他在地球的位置
geoadd key1 经度1 纬度1 “天安门” 经度2 纬度2 “天安门2” # 添加经纬度坐标
ZRANGE key1 0 -1 # 获取全部的value值
# 如果返回值,有中文乱码,解决:redis -cli -a 123456 – raw (在外部,Linux命令行输入)
geopos key1 天安门 天安门2 # 返回经纬度
GEOHASH key1 天安门 天安门2 # 返回经纬度坐标的(base32编码)
GEODIST key1 天安门 故宫 km # 返回两个位置之间的距离,km是单位:千米 或 m:米
GEORADIUS 以给定的经纬度为中心, 返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素
# 例子:GEORADIUS key1 114.12 39.2 10 km withcoord withhash count 10 desc
# key (现在的经纬度) 10 (km或m) withcoord(会打印hash值)withhash(返回经纬度坐标)count 10(返回10条)
GEORADIUSBYMEMBER 它这个输入范围元素 例:GEORADIUS key1 天安门 10 km ...
流(Stream)
可以做消息队列,Stream流 (Redis版的MQ消息中间件+阻塞队列),但生产案例实例少,不能等价于Kafka和RabbitMQ
# 使用List实现消息队列(点对点模式)
lpush key1 1 2 3 # 进行添加集合
lrange key 1 # 从左边查看一个 lrange key 0 -1 遍历全部数据
位域(bitfield)
将 Redis 字符串看作是一个二进制位组成的数组,这个很少使用,汇编语言。
数据持久化
-
RDB (指定时间间隔执行数据集的时间点快照)
快照文件就称为RDB文件(dump.rdb)
优点:适合大规模的数据恢复、速度比AOF快、按照业务时间定时备份
缺点:如果down机,最近一次快照数据会丢失、数据量大IO操作时间长
默认触发RDB快照:
配置文件配置、手动save或者BGSAVE 、主从复制、手动执行shutdown并没有开启AOF持久化
进行配置文件配置:
# 在redis 7 进行配置,按照 redis.conf 里配置的 (save是命令) # 3600秒 修改一次 或 100秒 修改60次 或 60秒 修改10000次,满足以上就触发保存,保存到RDB文件中 save 3600 1 300 100 60 100 # save "" # 这么配置是禁止RDB模式 # 修改文件保存地址 dir /my/dump自己文件目录 # 可通过命令查看保存地址位置:config get dir # 修改文件名称 dbfilename 自己的文件名.rdb # 进行物理恢复数据 (BGSAVE是命令) 1. 在配置文件目录下,进行备份文件(备份文件.rdb),备份到其他位置上 2. 注意:中断、退出、执行重启,系统都会自动生成rdb文件 3. 我们把(备份文件.rdb)放到配置文件目录下,清空其他rdb文件 4. 在redis客户端命令下,执行BGSAVE,会执行备份文件的恢复
-
AOF(以日志的形式来记录每个写操作)
默认是不开启,它有3种写回策略:always 同步写回、everyses 每秒写回(默认)、no 由操作系统控制
优点:更好保护数据,适合做紧急数据恢复
缺点:恢复速度慢,aof文件大于rdf文件
进行配置文件配置:
# 开启配置: appendonly yes # 修改文件保存地址,默认跟RDB一个目录下 dir /my/dump自己文件目录 # 也可以指定自己目录,这个只有redis7版本之后有,会在dir这个之后, # 例:/my/dump自己文件目录/AOF目录/xxx.aof appenddirname "AOF目录" # 修改文件名称 appendfilename "appendonly.aof" # redis7版本后会有 appendonly.aof.1.base.rdb # 1.基本文件 appendonly.aof.1.incr.aof # 2.增量文件 appendonly.aof.2.incr.aof # 2.增量文件 appendonly.aof.manifest # 3.清单文件 # 进行物理恢复数据 1. 在配置文件目录下,进行备份目录(AOF目录,它下面有多个文件),备份到其他位置上 2. 注意:中断、退出、执行重启,系统都会自动生成rdb文件,需要清空掉rdb文件 3. 我们把(备份文件.rdb)放到配置文件目录下,清空其他rdb文件和AOF目录 4. 在redis客户端命令下,进行重启,重新加载redis,就会数据恢复 # 如果AOF写操作,只写一半会出现文件异常,在AOF目录下执行 redis-check-aof --fix appendonly.aof.1.incr.aof # 异常修复命令 # 修复完,进行重启redis # 重写机制,当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时,目的:减少增量文件大小 auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb # 手动重写,在redis客户端,执行命令:bgrewriteaof # aof重写期间是否同步 no-appendfsync-on-rewrite no
-
RDB - AOF混合持久化
同时开启,如果有aof文件,先执行aof文件,不执行rdb文件,没有就只执行rdb文件;
rdb做存量,aof做当量;
# 开启混合模式 aof-use-rdb-preamble yes # yes 开启 no 禁用
-
纯缓存模式
# 关闭rdb+aof,但还可以使用save、bgsave生成rdb文件 和 bgrewriteaof生成aof文件 save "" appendonly no
事务
Redis是单线程架构,在执行事务内的指令,不可能执行其他客户端的请求处理;它在一组队列中,顺序的执行一系列指令;
特点:没有隔离性的概念、不保证原子性(可能一部分成功,一部分失败)、不能回滚、排他性(一个事务依次执行,不会被其他指令插入)
操作:
# 开启事务 MULTI
# 执行事务 EXEC
# 放弃事务 DISCARD
# 案例
MULTI # 开启事务
set key1 11 # 添加数据
set key2 22
EXEC # 提交事务
# 1 如果中间有语法错误,会直接返回结果,全部指令逻辑都不会执行
# 2 如果中间有语法没错,但没有语法错误,指的是get 不存在的值,事务会有效,会执行有效的指令
Watch 监控
相当于Redis的乐观锁,一旦执行了EXEC,监控也就会取消
watch
# 开始进行监控,先监控再开启事务,保证两key变动在同一事务内,如果有其他人先修改了k1,会返回null,执行失败,比较并交换
# 案例:
get k1
watch k1
MULTI # 提交事务
set k1 新值1 # 修改数据
set k2 新值2
get k1
get k2
EXEC # 提交事务
unwatch
# 放弃监控
# 案例:
get k1
watch k1
get k2
unwatch
管道
就是一次性发送多条命令给服务端,减少客户端与Redis服务端的通信次数;
# 批处理
# 可以把多个命令写一个txt文件中,然后执行批处理
cat cmd.txt
# 执行批处理
cat cmd.txt | redis-cli -a redis密码 -- pipe
管道与事务的区别:
事务具有原子性,管道没有;
管道是一次性将多条指令发送服务端,事务是一条一条发,并且只有提交事务才执行;
常用批量删除
# 批量删除 - 通过管道进行批量删除,“***” 代表 key前缀 (在Linux)
redis-cli -a 密码 keys "***" | xargs redis-cli del
发布订阅
消息通信模式:
- 发送者 - 发送消息
- 订阅者 - 接受消息
一般很少使用,不推荐,因必须先订阅才有发送者进行发送消息
SUBSCRIBE channel [channel] # 订阅多个频道
PUBLISH channel message # 对一个频道发布信息
PSUBSCRIBE pattern [pattern...] # 按照模式批量订阅,订阅一个或多个符合给定模式(支持*号?号之类的)的频道
PUSUB CHANNELS # 由活跃频道组成的列表
PUSUB NUMSUB channel [channel...] # 某个频道有几个订阅者
PUBSUB NUMPAT # 只统计使用PUBSCRIBE 命令执行的,返回客户端订阅的唯一模式的数量
UNSUBSCRIBE channel [channel...] # 取消订阅
PUNSUBSCRIBE pattern [pattern...] # 退订所有给定模式的频道
主从复制
master以写为主,slave以读为主
基本命令
info replication # 查看主从关系和配置信息
replicaof 主库IP 主库端口 # 从库认主库,在从库这里配置
slaveof 主库IP 主库端口 # 更换主库地址
slaveof no one # 当前从库升级为主库,停止与其他数据库的同步
# 注意:命令执行,一但redis重启就失效
配置一主两从
一个主机可以有2个从机,也可以一个主机有一个从机,这个从机下有个从机,这样目的可以减少一个主机同步的压力
主库配置:
# 配置主库,主库配置文件:
daemonize yes # 开启后台启动
注释掉 bind 127.0.0.1 # 注释掉,允许其他机器访问本机
protected-mode no # 保护模式关闭
port 6379 # 指定端口
dir /myredis/配置绝对路径 # 指定当前工作目录 dir
pidfile /var/run/redis_6379.pid # 文件进程id,默认也是这个地址,需要知道该地址
loglevel notice # redis日志级别,默认就是notice
logfile "/myredis6379.log" # 日志存放地址,默认是"",指定自己的目录
requirepass 12345 # 设置redis的密码
dbfilename dump6379.rdb # 开启rdb数据持久化模式
appendonly yes # 开启aof数据持久化模式
appendfilename appendonly.aof
# 配置从机,从机配置文件(从机配置上主机的ip、端口、密码)
redis6380.conf (slave)
replicaof 主机的ip 主机的端口 # 例:replicaof 127.1.xx 6379
masterauthc "主机的访问密码"
# 注意:不同的从机的,端口号不同,防火墙也需要关闭
# 配置完,分别重启redis
cd /usr/local/bin # 在该目录
redis-server /myredis/redis7.conf # 通过指定自己的配置文件启动
# 查看主机日志,是否配置成功
tail -f myredis6379.log
# 先看主机日志:如果看到Synchronization with replica 从机ip地址:从机端口号 succeeded (代表成功)
# 再看从机日志:如果看到Connecting to MASTER 主机ip:主机端口号 (代表从机连接到主机)
# 还可以通过 info replication # 查看主从关系和配置信息
防火墙关闭
启动: systemctl start firewalld
关闭: systemctl stop firewalld
查看状态: systemctl status firewalld
开机禁用 : systemctl disable firewalld
开机启用 : systemctl enable firewalld
添加 :firewall-cmd --zone=public --add-port=80/tcp --permanent (--permanent永久生效,没有此参数重启后失效)
重新载入: firewall-cmd --reload
查看: firewall-cmd --zone= public --query-port=80/tcp
删除: firewall-cmd --zone= public --remove-port=80/tcp --permanent
复制原理:
同步机制开启后,主机会发送给从机sync命令,首次连接,进行全量复制,随机会有心跳检测,平稳阶段,进行增量复制,每个主机对应从机都有偏移量,记住从机复制到哪里,如果从机端口,会从偏移量继续传递复制。
哨兵
用来监控后台master主机是否故障,如果故障了根据投票重新选举一个新主库,一般哨兵为3个,1个主机,2个从机。
配置哨兵
# 一般在/opt/redis目录下有sentinel.conf配置文件,哨兵的配置文件(默认的)
# 我们进行配置,/myredis/redis7.conf 这个目录下是启动redis配置文件,我们也在该目录下创建哨兵的配置文件sentinel.conf
daemonize yes # 开启后台启动
注释掉 bind 127.0.0.1 # 注释掉,允许其他机器访问本机
protected-mode no # 保护模式关闭
port 26379 # 指定端口
dir /myredis/配置绝对路径 # 指定当前工作目录 dir
pidfile /var/run/redis_sentinel26379.pid # 文件进程id,默认也是这个地址,需要知道该地址
logfile "/mysentinel26379.log" # 日志存放地址,默认是"",指定自己的目录
# sentinel monitor 主机的名字 主机的ip地址 端口号 几个哨兵认同就代表它成为主机
sentinel monitor mymaster 192.xxx 6379 2
# sentinel auth-pass 主机的名字 主机的访问密码
sentinel auth-pass mymaster 主机的访问密码
# 主观下线,默认超过30秒,心跳检测30秒内没有回复,代表主机下线了(单位:毫秒)
sentinel down-after-milliseconds mymaster 30000
# 如有3个哨兵,需要写3个哨兵的配置文件,进行分别启动,注意:从机需要都配置主机的访问密码
启动哨兵
# 启动哨兵前,需要启动1个主机和2个从机,完成一主两从的配置
redis-server /myredis/redis6379.conf
redis-server /myredis/redis6380.conf
redis-server /myredis/redis6381.conf
# 启动哨兵
cd /myredis
redis-sentinel sentinel26379.conf --sentinel
redis-sentinel sentinel26380.conf --sentinel
redis-sentinel sentinel26381.conf --sentinel
# 可在 /mysentinel26379.log 日志文件中查看哨兵的日志,观察是否配置成功
哨兵的数量最好是奇数,哨兵+主从复制,并不能保证数据不丢失。
集群
用来解决数据量过大,单个Master难以满足需求,需要多个主机和从机。集群配置,就不再需要哨兵功能,客户端连接Redis只需要连接其中一个节点就可以,进行读写。连接是通过(槽位slot)负责分配到各个节点,槽位最多是12384,但建议不超过1000个,槽点分片到不同的Redis机器中,分配到的方式有3种。
Redis集群分布式存储方法:
-
哈希取余分区
hash值取余 ,计算出哈希值,用来决定映射到哪台Redis中。缺点:不容易扩容。
-
一致性哈希算法
hash函数按照算法产生的hash值,在算法中形成一个首尾相连的圆形,每个圆形不同的区域分布不同的Redis机器,这样的好处,如果新增一台机器,方便扩容;缺点:就是算法很容易数据倾斜,不平均。
-
哈希槽分区
它是一个数组,它增加了一层哈希槽,一个集群有16384个槽,这些槽会分配给集群中的所有主节点;优点:方便扩容分派查找;Redis集群数量不可能有1000个,节点越多,心跳检测,传输数量越大。
集群配置(三主三从)
前提需要6个Redis服务主机,Redis配置文件放在/myredis/cluster目录下
步骤1:配置每台Redis配置
# 主机1配置 - 端口6381
# 进行配置:vim /myredis/cluster/redisCluster6381.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6381
logfile "/myredis/cluster/cluster6381.log"
pidfile /myredis/cluster6381.pid
dir /myredis/cluster
dbfilename dump6381.rdb
appendonly yes
appendfilename "appendonly6381.aof"
requirepass 123456
masterauth 123456
# 开启集群配置
cluster-enabled yes
# 集群配置文件
cluster-config-file nodes-6381.conf
# 集群超时连接时间
cluster-node-timeout 5000
# 主机2配置 - 端口6382
# 进行配置:vim /myredis/cluster/redisCluster6382.conf
bind 0.0.0.0
daemonize yes
protected-mode no
port 6382
logfile "/myredis/cluster/cluster6382.log"
pidfile /myredis/cluster6382.pid
dir /myredis/cluster
dbfilename dump6382.rdb
appendonly yes
appendfilename "appendonly6382.aof"
requirepass 123456
masterauth 123456
cluster-enabled yes
cluster-config-file nodes-6382.conf
cluster-node-timeout 5000
# 主机3配置 - 端口6383
# 同上,进行配置:vim /myredis/cluster/redisCluster6383.conf
cluster-enabled yes
cluster-config-file nodes-6383.conf
cluster-node-timeout 5000
# 主机4配置 - 端口6384
# 同上,进行配置:vim /myredis/cluster/redisCluster6384.conf
cluster-enabled yes
cluster-config-file nodes-6384.conf
cluster-node-timeout 5000
# 主机5配置 - 端口6385
# 同上,进行配置:vim /myredis/cluster/redisCluster6385.conf
cluster-enabled yes
cluster-config-file nodes-6385.conf
cluster-node-timeout 5000
# 主机6配置 - 端口6386
# 同上,进行配置:vim /myredis/cluster/redisCluster6386.conf
cluster-enabled yes
cluster-config-file nodes-6386.conf
cluster-node-timeout 5000
步骤2:启动每台Redis配置
redis-server /myredis/cluster/redisCluter6381.conf
..........
redis-server /myredis/cluster/redisCluter6386.conf
# 通过命令查询redis启动是否成功
ps -ef|grep redis
步骤3:使用redis-cli命令为6台机器构建集群关系启动每台Redis配置
# -cluster-replicas 1 表示为每个master创建一个slave节点
redis-cli -a (redis密码) --cluster create --cluster-replicas 1 192.IP地址.1:6381 192.IP地址.1:6382 192.IP地址.2:6383 192.IP地址.2:6384 192.IP地址.3:6385 192.IP地址.3:6386
# 中途输入yes
步骤4:检查是否成功
# 登录 其中一台redis
redis-cli -a 设置的密码 -p 6381 -c
# -c表示集群 不加的话不是按照集群启动的,对于在别的机器上的key,会报错
# 查看节点状态
cluster nodes # 查看集群的主从关系
# 输出信息,显示哪些是主机,哪些是从机,但主机和从机对应的顺序是随机的
# 查看集群信息
cluster info
# 输出信息,显示当前机器是主机还是从机,还有槽的状态,有几个节点
# 查看主从
info replication
# 输出信息,显示当前机器信息
步骤5:配置成功
# 我们可以登陆其中一台redis
redis-cli -a 设置的密码 -p 6381 -c
# 进行新建、查询
# 查看某个key是哪个槽位
cluster keyslot 键名称
步骤6:主从容错切换迁移
# 随着时间,主机6381该主机,之前是主机,如果它断了,它下面的从机会变成主机
# 当主机6381重启后,它还是从机,不再是主机
# 想要原先的master继续做master的话
CLUSTER FAILOVER # 让谁上位 就在谁的端口号下执行这个命令
步骤7:主从扩容
# 1.创建2个Redis,配置文件大致与前几台一致,新Redis机器端口为6387、6388
# 2.启动Redis,分别启动
redis-server /myredis/cluster/redisCluster6388.conf
redis-server /myredis/cluster/redisCluster6387.conf
# 3.将新增的6387节点作为master加入原集群,之前6381节点是主机
redis-cli -a redis密码 --cluster add-node 192.IP地址.4:6387 192.IP地址.1:6381
# -- 相当于新的master主机(6387)拜之前的master主机(6381)看到最后一行有ok代表成功
# 4.检查集群情况,6381
redis-cli -a redis密码 --cluster check 192.IP地址.1:6381
# 会打印出有哪些master主机,还可以看到哪些主机对应的槽号
# 5.分配槽号,默认新创建的Redis没有分配槽号
redis-cli -a redis密码 --cluster reshard 192.IP地址.1:6381
# 然后执行完该命令,中途会输入分配哪些槽号,输入4096 (总槽号是16384,如果4台:16384/4=4096)
# 然后还会再输入一个ID,ID是6387这台主机的ID,(谁来接收的主机ID)
# 然后再输入all,(代表谁分配的,all代表大家都分配一点,这里也可以指定6381这主机的ID,代表这台机器分配)
# 然后再输入yes,就配置完成
# 5.检查集群情况,6381,第二次检查
redis-cli -a redis密码 --cluster check 192.IP地址.1:6381
# 就可以重新分配后的槽号
# 6.为主节点6387分配从节点6388
redis-cli -a redis密码 --cluster add-node 192.IP地址.4:6388 192.IP地址.4:6387 --cluster-slave --cluster-master-id b86176(6387主机的ID)
# 7.查看集群最新配置
redis-cli -a 设置的密码 -p 6381 -c # 登录其中一台Redis机器
cluster nodes # 查看集群的主从关系 ,也可以看到每台机器的ID
步骤8:主从缩容
# 1.6387和6388下线,先删除从机6388节点
redis-cli -a redis密码 --cluster check 192.IP地址.4:6388 # 先得到6388、6381、6387主机的ID
redis-cli -a redis密码 --cluster del-node 192.IP地址.4:6388 4111(6388主机的ID)
# 2.检查节点,在其他Redis主机检查,6388主机已不见
redis-cli -a redis密码 --cluster check 192.IP地址.1:6381
# 3.将6387的槽号情况,重新分配,先全部都给6381主机
redis-cli -a redis密码 --cluster reshard 192.IP地址.1:6381
# 然后执行完该命令,中途会输入分配哪些槽号,输入4096 (总槽号是16384,如果4台:16384/4=4096)
# 然后还会再输入一个ID,ID是6381这台主机的ID,(谁来接收的主机ID,这4096槽号由6381主机接收)
# 然后再输入6387主机ID,(代表6387主机要删除这4096槽号)
# 然后再输入 done
# 然后再输入 yes,配置完成
# 4.检查节点,在其他Redis主机检查,6387主机已变成从机
redis-cli -a redis密码 --cluster check 192.IP地址.1:6381
# 5.删除从机6387节点
redis-cli -a redis密码 --cluster del-node 192.IP地址.4:6387 xxx(6387主机的ID)
# 6.查看集群最新配置
redis-cli -a 设置的密码 -p 6381 -c # 登录其中一台Redis机器
cluster nodes # 查看集群的主从关系 ,也可以看到每台机器的ID
注意:
在Redis配置文件中,默认是yes,代表如果配置3主3从,如果其中1主1从的机器挂掉了,整个集群是不完整的,redis默认不会对外访问,如果改为no,是对外提供,可以访问Redis
cluster- require- full- coverage yes
Spring Boot集成Redis
一般我们使用RedisTemplate 、Jedis(过时)
连接单机
# 1.引包
<!--SpringBoot与Redis整合依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
# 2.配置文件
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
# 3.Redis配置类
@Configuration
public class RedisConfig {
/**
* redis序列化的工具配置类 - 避免查看redis有乱码
* @param lettuceConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory)
{
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(lettuceConnectionFactory);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
# 4.基本使用
@Resource
private RedisTemplate redisTemplate;
// 写
redisTemplate.opsForValue().set(key, value);
// 读
String str = (String) redisTemplate.opsForValue().get(keyId);
连接集群
# 配置文件修改
spring.redis.password=123456
#获取失败,集群最大重定向次数
spring.redis.cluster.max-redirects=3
spring.redis.clusterspring.redis.cluster.nodes=192.1.max-redirects=3
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.min-idle=0
# 集群节点 - 6个
spring.redis.cluster.nodes=127.0.0.1:6381,127.0.0.1:6382,127.0.0.1:6383,127.0.0.1:6384,127.0.0.1:6385,127.0.0.1:6386
# 注意:如果其中有一台集群挂掉,会报错,因:Redis默认的是 Lettuce、
# 解决方案1:下面2个配置
# 支持集群拓扑动态感应刷新,自适应拓扑刷新是否使用所有可用的更新,默认false关闭
spring.redis.lettuce.cluster.refresh.adaptive=true
# 定时刷新
spring.redis.lettuce.cluster.refresh.period=2000
# 解决方案2:引入新包(不推荐)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>