文章目录
Redis
一、Resid操作命令
-
redis 默认为 16 个库
-
在 redis.conf 文件可配置,该文件很重要,后续很多操作都是这个配置文件
-
redis 默认自动使用 0 号库
1.1启动
- redis安装目录下src文件中
./reids.server /opt/redis.conf
1.2沟通命令
ping
#返回PONG,表示运行正常
127.0.0.1:6379> ping
PONG
1.3查看当前数据库中 key 的数目
dbsize
#查看0号库
127.0.0.1:6379> dbsize
(integer) 2
#查看5号库
127.0.0.1:6379> select 5
OK
127.0.0.1:6379[5]> dbsize
(integer) 0
1.4切换库
select db
#默认0号
#查看5号
127.0.0.1:6379> select 5
OK
1.5删除当前库的数据
flushdb
#删除当前库的数据
127.0.0.1:6379[5]> flushdb
OK
1.6退出连接
exit
二、Redis Key命令
2.1、keys 查看key值
-
语法:keys pattern
-
作用:查找所有符合模式 pattern 的 key. pattern 可以使用通配符。通配符:
*:表示 0-多个字符 ,例如:keys * 查询所有的 key。
?:表示单个字符,例如:wo?d , 匹配 word , wood
-
显示所有key(不推荐使用)
redis是单线程,如果数据量较大,查询时间长,消耗资源
127.0.0.1:6379> keys * 1) "k1" 2) "k2" 3) "world" 4) "weles" 5) "woos"
-
使用通配符
127.0.0.1:6379> keys k* 1) "k1" 2) "k2" 127.0.0.1:6379> keys w* 1) "world" 2) "weles" 3) "woos"
127.0.0.1:6379> keys wo?s 1) "woos"
2.2、exists 判断是否存在
-
语法:exists key [key…]
-
作用:判断 key 是否存在
-
返回值:整数,存在 key 返回 1,其他返回 0. 使用多个 key,返回存在的 key 的数量。
-
判断key是否存在
127.0.0.1:6379> exists k1 (integer) 1 127.0.0.1:6379> exists k1 k2 k3 (integer) 2
2.3、expire 设置存活时间
-
语法:expire key seconds
-
作用:设置 key 的生存时间,超过时间,key 自动删除。单位是秒。返回值:设置成功返回数字 1, 其他情况是 0
-
设置时间
127.0.0.1:6379> keys * #查看全部 1) "k2" 2) "world" 3) "weles" 4) "woos" 127.0.0.1:6379> expire k2 10 #设置k2存活10秒 (integer) 1 127.0.0.1:6379> ttl k2 #查看K2存活时间 (integer) 5 127.0.0.1:6379> exists k2 #查看k2是否存在 (integer) 0
-
在设置验证码时可以使用,定时清理缓存等等
2.4、ttl 查看存活时间
-
语法:ttl key
-
作用:以秒为单位,返回 key 的剩余生存时间(ttl: time to live) 返回值:
- -1 :没有设置 key 的生存时间, key 永不过期
- -2 :key 不存在
- 数字:key 的剩余时间,秒为单位
-
查看时间
127.0.0.1:6379> ttl k2 #查看K2存活时间 (integer) 5 127.0.0.1:6379> ttl k3 (integer) -2 127.0.0.1:6379> ttl k1 (integer) -1
2.5、type 查看value数据类型
-
语法:type key
-
作用:查看 key 所存储值的数据类型返回值:字符串表示的数据类型
- none (key 不存在)
- string (字符串)
- list (列表)
- set (集合)
- zset (有序集)
- hash (哈希表)
-
查看key数据类型
127.0.0.1:6379> type k1 string #不存在 127.0.0.1:6379> type k3 none
2.6、del 删除key
-
语法:del key [key…]
-
作用:删除存在的 key ,不存在的 key 忽略。返回值:数字,删除的 key 的数量。
-
删除key
127.0.0.1:6379> del k1 #删除存在的值 (integer) 1 127.0.0.1:6379> del k3 #删除不存在的值 (integer) 0
三、Redis数据类型
3.1、String 字符串类型
-
字符串类型是 Redis 中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON 化的对象甚至是一张图片。最大 512M。
127.0.0.1:6379> set student 高靖奇 OK 127.0.0.1:6379> type student string
3.1.1基本命令
(1)set get 插入 获取
-
set:将字符串值 value 设置到 key 中
-
语法:set key value
-
get:获取 key 中设置的字符串值
-
语法: get key
-
向已经存在的 key 设置新的 value,会覆盖原来的值
#插入数据 127.0.0.1:6379> set k1 v2 OK 127.0.0.1:6379> set k2 v2 OK 127.0.0.1:6379> set k3 v3 OK #查看所有数据 127.0.0.1:6379> keys * 1) "k3" 2) "k1" 3) "k2" #获取所有数据 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> get k2 "v2" 127.0.0.1:6379> get k3 "v3" #修改k1 127.0.0.1:6379> set k1 vvvv1 OK 127.0.0.1:6379> get k1 "vvvv1" #查看不存在的值,nil == null 127.0.0.1:6379> get k4 (nil)
(2)incr decr i++ i–
-
incr:将 key 中储存的数字值加 1,如果 key 不存在,则 key 的值先被初始化为 0 再执行incr 操作
-
语法:incr key 类似于i++
-
decr:将 key 中储存的数字值减1,如果 key 不存在,则 key 的值先被初始化为 0 再执行 decr 操作
-
语法:decr key 类似于i–
-
只能对数字类型的数据操作,其他字符会报错
-
做全局计数器
#操作存在的值 #incr 127.0.0.1:6379> set k1 10 OK 127.0.0.1:6379> incr k1 (integer) 11 127.0.0.1:6379> incr k1 (integer) 12 127.0.0.1:6379> incr k1 (integer) 13 #decr 127.0.0.1:6379> decr k1 (integer) 12 127.0.0.1:6379> decr k1 (integer) 11 127.0.0.1:6379> decr k1 (integer) 10 #操作不存在的值,先创建,从0开始加1或减1 127.0.0.1:6379> keys * 1) "k3" 2) "k1" 3) "k2" #incr 127.0.0.1:6379> incr k4 (integer) 1 127.0.0.1:6379> incr k4 (integer) 2 #decr 127.0.0.1:6379> decr k4 (integer) -1 127.0.0.1:6379> decr k4 (integer) -2
(3)append 拼接
-
如果 key 存在, 则将 value 追加到 key 原来旧值的末尾如果 key 不存在, 则将 key 设置值为 value
-
语法:append key value
-
返回值:追加字符串之后的总长度
#操作存在的值 127.0.0.1:6379> append k1 hello (integer) 7 127.0.0.1:6379> get k1 "10hello" #操作不存在的值,创建一个key, 127.0.0.1:6379> append k5 hello (integer) 5 127.0.0.1:6379> get k5 "hello"
3.1.2常用命令
(1) strlen 查看value长度
-
返回 key 所储存的字符串值的长度返回值,如果key存在,返回字符串值的长度,key不存在,返回0
-
语法:strlen key
#操作存在的值 127.0.0.1:6379> strlen k1 (integer) 7 #操作不存在的值 127.0.0.1:6379> strlen k6 (integer) 0
(2)getrange 截取
-
获取 key 中字符串值从 start 开始 到 end 结束 的子字符串,包括 start 和 end, 负数表示从字符串的末尾开始, -1 表示最后一个字符
-
语法:getrange key start end
-
返回值:截取的子字符串
#截取2-5的字符 127.0.0.1:6379> get k1 "10hello" 127.0.0.1:6379> getrange k1 2 5 "hell" #从尾部截取,start,end是负数,最后一位是-1 127.0.0.1:6379> getrange k1 -6 -1 "0hello" #超出范围截取,end为字符串末尾 127.0.0.1:6379> getrange k1 2 100 "hello"
(3)setrange 覆盖
-
用 value 覆盖(替换)key 的存储的值从 offset 开始,不存在的 key 做空白字符串。
-
语法:setrange key offset value
-
返回值:修改后的字符串的长度
#替换给定的字符串 127.0.0.1:6379> get k1 "10hello" 127.0.0.1:6379> setrange k1 2 gjq (integer) 7 127.0.0.1:6379> get k1 "10gjqlo" #设置不存在的key #如果不从0开始,前面会有“\x00”做占位符 127.0.0.1:6379> get k6 (nil) 127.0.0.1:6379> setrange k6 2 gjq (integer) 5 127.0.0.1:6379> get k6 "\x00\x00gjq" 127.0.0.1:6379> setrange k6 0 gjq (integer) 5 127.0.0.1:6379> get k6 "gjqjq"
(4)mset 批量插入
-
同时设置一个或多个 key-value 对返回值: OK
-
mset key value [key value…]
#一次设置多个 key, value 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 OK 127.0.0.1:6379> keys k* 1) "k3" 2) "k1" 3) "k2"
(5)mget 批量获取
-
获取所有(一个或多个)给定 key 的值返回值:包含所有 key 的列表
-
语法:mget key [key …]
#获取存在的值 127.0.0.1:6379> mget k1 k2 k3 1) "v1" 2) "v2" 3) "v3" #获取不存在的值 127.0.0.1:6379> mget k1 k4 1) "v1" 2) (nil)
3.2、hash 哈希数据类型
-
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
-
常用于存储Java对象的
-
Java演示
Map<String,String> data = new HashMap(); //在redis hash中 username等表示field 张三等表示value data.put("username","张三"); data.put("age","23"); data.put("nomber","1901040101"); //redis hash 类型 //student就是redis hash中的key,data是value Map<String,Map<String,String>> map = new HashMap(); map.put("student",data);
3.2.1基本命令
(1)hest 插入
-
将哈希表 key 中的域 field 的值设为 value ,同时也能将多个 field-value (域-值)设置到哈希表 key 中,如果 key 不存在,则新建 hash 表,执行赋值,如果有 field ,则覆盖值。
-
如果 field 是 hash 表中新 field,且设置值成功,返回 1,如果 field 已经存在,旧值覆盖新值,返回 0
-
语法:hset key field value / hset key field value [field value…]
#插入单个数据 127.0.0.1:6379> hset student 1913041429 gjq (integer) 1 127.0.0.1:6379> hset student 1913041415 czy (integer) 1 127.0.0.1:6379> hset student 1913041422 hyn (integer) 1 127.0.0.1:6379> hset student 1913041441 lhr (integer) 1 127.0.0.1:6379> hset student 1913041448 zx (integer) 1 #插入多个数据 127.0.0.1:6379> hset student 1913041436 bzk 1913041329 zlq 1913041422 ysa (integer) 2 #更新存在的 127.0.0.1:6379> hset student 1913041429 gaojingqi (integer) 0 127.0.0.1:6379> hget student 1913041429 "gaojingqi"
(2)hget 获取
-
获取哈希表 key 中给定域 field 的值
-
field 域的值,如果 key 不存在或者 field 不存在返回 nil
-
语法:hget key field
#获取存在的值 127.0.0.1:6379> hget student 1913041429 "gaojingqi" #获取不存在的值 127.0.0.1:6379> hget student 1913041436 (nil)
(3)hmget 批量获取
-
获取哈希表 key 中一个或多个给定域的值
-
返回和 field 顺序对应的值,如果 field 不存在,返回 nil
-
语法:hmget key field [field…]
#获取多个field的值 #显示值的顺序和hmget后面field顺序一直 127.0.0.1:6379> hmget student 1913041429 1913041415 1913041422 1913041411 1) "gaojingqi" 2) "czy" 3) "ysa" 4) (nil)
(4)hgetall 获取全部
-
获取哈希表 key 中所有的域和值
-
以列表形式返回 hash 中域和域的值 ,key 不存在,返回空 hash
-
语法:hgetall key
#获取所有值 127.0.0.1:6379> hgetall student 1) "1913041429" #域的名称 2) "gaojingqi" #域对应的值 3) "1913041415" 4) "czy" 5) "1913041422" 6) "ysa" 7) "1913041441" 8) "lhr" 9) "1913041448" 10) "zx" 11) "1913041436" 12) "bzk" 13) "1913041329" 14) "zlq"
(5)hdel 批量删除
-
删除哈希表 key 中的一个或多个指定域 field,不存在 field 直接忽略返回值:成功删除的 field 的数量
-
语法:hdel key field [field…]
#删除指定的field 127.0.0.1:6379> hdel student 1913041329 1913041436 (integer) 2 127.0.0.1:6379> hgetall student 1) "1913041429" 2) "gaojingqi" 3) "1913041415" 4) "czy" 5) "1913041422" 6) "ysa" 7) "1913041441" 8) "lhr" 9) "1913041448" 10) "zx"
3.2.2常用命令
(1)hkeys 获取所有key
-
查看哈希表 key 中的所有 field 域
-
包含所有 field 的列表,key 不存在返回空列表
-
语法:hkeys key
#获取student的所有学号 127.0.0.1:6379> hkeys student 1) "1913041429" 2) "1913041415" 3) "1913041422" 4) "1913041441" 5) "1913041448"
(2)hvals 获取所有value
-
返回哈希表 中所有域的值
-
包含哈希表所有域值的列表,key 不存在返回空列表
-
语法:hvals key
#获取student所有域的值 127.0.0.1:6379> hvals student 1) "gaojingqi" 2) "czy" 3) "ysa" 4) "lhr" 5) "zx"
(3)hexists 查看是否有值
-
查看哈希表 key 中,给定域 field 是否存在返回值:如果 field 存在,返回 1, 其他返回 0
-
语法:hexists key field
#查看key 中 field 域是否存在 127.0.0.1:6379> hexists student 1913041429 (integer) 1
3.3、list 列表类型
- Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
3.3.1基本命令
(1)lpush rpush 插入
-
lpush:将一个或多个值 value 插入到列表 key 的表头(最左边),从左边开始加入值,从左到右的顺序依次插入到表头
-
语法:lpush key value [value…]
-
rpush:将一个或多个值 value 插入到列表 key 的表尾(最右边),各个 value 值按从左到右的顺序依次插入到表尾
-
语法:rpush key value [value…]
-
返回:数字,新列表的长度
#将a b c 插入到mylist列表表头 #从左(a)往右(c)依次插入列表头 127.0.0.1:6379> lpush mylist a b c (integer) 3 127.0.0.1:6379> lrange mylist 0 4 1) "c" 2) "b" 3) "a" #插入重复的值 #不覆盖之前的值,新添加一个值 127.0.0.1:6379> lpush mylist a (integer) 4 127.0.0.1:6379> lrange mylist 0 4 1) "a" 2) "c" 3) "b" 4) "a" #将d e f 插入到mylist列表表尾 #从左(d)往右(f)依次插入列表表尾 127.0.0.1:6379> rpush mylist d e f (integer) 7 127.0.0.1:6379> lrange mylist 0 7 1) "a" 2) "c" 3) "b" 4) "a" 5) "d" 6) "e" 7) "f"
(2)lrange 获取
-
获取列表 key 中指定区间内的元素,0 表示列表的第一个元素,以 1 表示列表的第二个元素;start , stop 是列表的下标值,也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 start ,stop 超出列表的范围不会出现错误。
-
语法:lrange key start stop
#返回全部内容 127.0.0.1:6379> lrange mylist 0 7 1) "a" 2) "c" 3) "b" 4) "a" 5) "d" 6) "e" 7) "f" #查看第二个元素 127.0.0.1:6379> lrange mylist 1 1 1) "c"
(3)lindex 根据下标获取
-
获取列表 key 中下标为指定 index 的元素,列表元素不删除,只是查询。0 表示列表的第一个元素,以 1 表示列表的第二个元素;也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
-
语法:lindex key index
#获取全部 127.0.0.1:6379> lrange mylist 0 7 1) "a" 2) "c" 3) "b" 4) "a" 5) "d" 6) "e" 7) "f" #获取下标为2的元素 127.0.0.1:6379> lindex mylist 2 "b" #获取不存在的元素 127.0.0.1:6379> lindex mylist 10 (nil)
(4)llen 获取列表长度
-
获取列表 key 的长度
-
语法:llen key
#获取列表长度 127.0.0.1:6379> llen mylist (integer) 7
3.3.2常用命令
(1)lrem 删除指定的值
-
根据参数 count 的值,移除列表中与参数 value 相等的元素, count >0 ,从列表的左侧向右开始移除; count < 0 从列表的尾部开始移除;count = 0 移除表中所有与 value 相等的值。
-
语法:lrem key count value
#count > 0,从左到右删除的count个与value相等的值 #查看存在的元素 127.0.0.1:6379> lrange mylist 0 10 1) "c" 2) "b" 3) "a" 4) "a" 5) "c" 6) "b" 7) "a" 8) "d" 9) "e" 10) "f" #从左到右删除连个a 127.0.0.1:6379> lrem mylist 2 a (integer) 2 #查看删除之后的元素 127.0.0.1:6379> lrange mylist 0 10 1) "c" 2) "b" 3) "c" 4) "b" 5) "a" 6) "d" 7) "e" 8) "f" #count = 0 ,删除所有与value相等的值 #删除所有b 127.0.0.1:6379> lrem mylist 0 b (integer) 2 127.0.0.1:6379> lrange mylist 0 10 1) "c" 2) "c" 3) "a" 4) "d" 5) "e" 6) "f"
(2)lset 修改指定的值
-
将列表 key 下标为 index 的元素的值设置为 value。
-
语法:lset key index value
#获取全部 127.0.0.1:6379> lrange mylist 0 -1 1) "c" 2) "c" 3) "a" 4) "d" 5) "e" 6) "f" #修改下标为2的value为gjq 127.0.0.1:6379> lset mylist 2 gjq OK ##获取全部 127.0.0.1:6379> lrange mylist 0 -1 1) "c" 2) "c" 3) "gjq" 4) "d" 5) "e" 6) "f"
(3)linsert 插入值
-
将值 value 插入到列表 key 当中位于值 pivot 之前或之后的位置。key 不存在,pivot 不在列表中,不执行任何操作。
-
语法:linsert key BEFORE|ALFTER pivot value
#查找全部 127.0.0.1:6379> lrange mylist 0 -1 1) "c" 2) "c" 3) "gjq" 4) "d" 5) "e" 6) "f" #在gjq前插入xyy 127.0.0.1:6379> linsert mylist BEFORE gjq xyy (integer) 7 #在gjq后插入zlq 127.0.0.1:6379> linsert mylist AFTER gjq zlq (integer) 8 #查找全部 127.0.0.1:6379> lrange mylist 0 -1 1) "c" 2) "c" 3) "xyy" 4) "gjq" 5) "zlq" 6) "d" 7) "e" 8) "f"
3.4、set 集合类型
- Redis 的 Set 是 string 类型的无序集合,集合成员是唯一的,即集合中不能出现重复的数据.
3.4.1基本命令
(1)sadd 添加元素
-
将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略,不会再加入。
-
语法:sadd key member [member…]
#添加一个元素 127.0.0.1:6379> sadd class 19130401 (integer) 1 #添加已存在的元素,返回0,没有元素被添加 127.0.0.1:6379> sadd class 19130401 (integer) 0 #添加多个元素 127.0.0.1:6379> sadd class 19130402 19130403 19130404 (integer) 3
(2)smembers 查全部元素
-
获取集合 key 中的所有成员元素,不存在的 key 视为空集合
-
语法:smembers key
#获取class所有元素 127.0.0.1:6379> smembers class 1) "19130401" 2) "19130402" 3) "19130403" 4) "19130404"
(3)sismember 判断是否存在
-
判断 member 元素是否是集合 key 的成员返回值:member 是集合成员返回 1,其他返回 0
-
语法:sismember key member
#19130401存在class中 127.0.0.1:6379> sismember class 19130401 (integer) 1 #19130406不在class中 127.0.0.1:6379> sismember class 19130406 (integer) 0
(4)scard 获取元素个数
-
获取集合里面的元素个数
-
语法:scard key
#获取class中的元素个数 127.0.0.1:6379> scard class (integer) 4
(5)srem 删除
-
删除集合 key 中的一个或多个 member 元素,不存在的元素被忽略。返回值:数字,成功删除的元素个数,不包括被忽略的元素。
-
语法:srem key member [member]
#查看全部class 127.0.0.1:6379> smembers class 1) "19130401" 2) "19130402" 3) "19130403" 4) "19130404" #删除19130401 127.0.0.1:6379> srem class 19130401 (integer) 1 #查看全部class 127.0.0.1:6379> smembers class 1) "19130402" 2) "19130403" 3) "19130404" 127.0.0.1:6379>
3.4.2常用命令
(1)srandmember 随机返回元素
-
只提供 key,随机返回集合中一个元素,元素不删除,依然在集合中;提供了 count 时,count 正数, 返回包含 count 个数元素的集合, 集合元素各不相同。count 是负数,返回一个 count 绝对值的长度的集合, 集合中元素可能会重复多次。
-
语法:srandmember key [count]
#没有count随机返回一个值 127.0.0.1:6379> srandmember class "19130403" 127.0.0.1:6379> srandmember class "19130404" 127.0.0.1:6379> srandmember class "19130402" #有count且为正数,返回count个元素,最多显示全部元素 127.0.0.1:6379> srandmember class 1 1) "19130402" 127.0.0.1:6379> srandmember class 2 1) "19130403" 2) "19130402" 127.0.0.1:6379> srandmember class 3 1) "19130402" 2) "19130403" 3) "19130404" 127.0.0.1:6379> srandmember class 5 1) "19130402" 2) "19130403" 3) "19130404" #有count且为负数,返回count个元素,超出集合长度元素会重复出现 127.0.0.1:6379> srandmember class -1 1) "19130402" 127.0.0.1:6379> srandmember class -5 1) "19130402" 2) "19130402" 3) "19130404" 4) "19130403" 5) "19130404"
(2)spop 随机删除
-
随机从集合中删除一个元素, count 是删除的元素个数。
-
语法:spop key [count]
#查看全部 127.0.0.1:6379> smembers class 1) "19130401" 2) "19130402" 3) "19130403" 4) "19130404" 5) "19130405" 6) "19130406" 7) "19130407" 8) "19130408" 9) "19130409" 10) "19130410" #没有count,随机删除一个元素 127.0.0.1:6379> spop class "19130401" 127.0.0.1:6379> spop class "19130406" 127.0.0.1:6379> spop class "19130407" #查看全部 127.0.0.1:6379> smembers class 1) "19130402" 2) "19130403" 3) "19130404" 4) "19130405" 5) "19130408" 6) "19130409" 7) "19130410" #有count,删除count个元素 #c 127.0.0.1:6379> spop class 3 1) "19130403" 2) "19130409" 3) "19130410"
3.5、zset 有序集合类型
- Redis 有序集合 zset 和集合 set 一样也是 string 类型元素的集合,且不允许重复的成员。不同的是 zset 的每个元素都会关联一个分数(分数可以重复),redis 通过分数来为集合中的成员进行从小到大的排序。
3.5.1基本命令
(1)zadd 添加
-
将一个或多个 member 元素及其 score 值加入到有序集合 key 中,如果 member存在集合中,则更新值;score 可以是整数或浮点数
-
语法:zadd key score member [score member…]
#在studentscore中添加数据 127.0.0.1:6379> zadd studentscore 99.9 gjq 88 hyn 95.1 czy (integer) 3
(2)zrange zrevrange 获取元素
-
zrange:查询有序集合,指定区间的内的元素。集合成员按 score 值从小到大来排序。 start,stop 都是从 0 开始。0 是第一个元素,1 是第二个元素,依次类推。以 -1 表示最后一个成员,-2 表示倒数第二个成员。WITHSCORES 选项让 score 和 value 一同返回。
-
语法:zrange key start stop [WITHSCORES]
-
zrevrange:返回有序集 key 中,指定区间内的成员。集合成员按 score 值从小到大来排序。其它同 zrange 命令。
-
语法:zrevrange key start stop [WITHSCORES]
#查看全部数据的member值 #zrange命令 127.0.0.1:6379> zrange studentscore 0 -1 1) "hyn" 2) "czy" 3) "gjq" #zrevrange命令 27.0.0.1:6379> zrevrange studentscore 0 -1 1) "gjq" 2) "czy" 3) "hyn" #使用withscores值,查看member和score值 #zrange命令 127.0.0.1:6379> zrange studentscore 0 -1 withscores 1) "hyn" #member值 2) "88" #score值 3) "czy" 4) "95.099999999999994" 5) "gjq" 6) "99.900000000000006" #zrevrange命令 127.0.0.1:6379> zrevrange studentscore 0 -1 withscores 1) "gjq" 2) "99.900000000000006" 3) "czy" 4) "95.099999999999994" 5) "hyn" 6) "88" #显示第一个元素 127.0.0.1:6379> zrange studentscore 0 0 withscores 1) "hyn" 2) "88"
(3)zrem 删除
-
删除有序集合 key 中的一个或多个成员,不存在的成员被忽略
-
语法:zrem key member [member…]
#删除gjq czy的信息 #查看全部 127.0.0.1:6379> zrevrange studentscore 0 -1 1) "gjq" 2) "czy" 3) "hyn" #删除 127.0.0.1:6379> zrem studentscore gjq czy (integer) 2 #查看全部 127.0.0.1:6379> zrange studentscore 0 -1 1) "hyn"
(4)zcard 获取元素个数
-
获取有序集 key 的元素成员的个数
-
语法:zcard key
#获取stuentscore中有几个元素 127.0.0.1:6379> zcard studentscore (integer) 1
3.5.2常用命令
(1)zrangebyscore zrevrangebyscore 获取区间内的元素
-
zrangebyscore:获取有序集 key 中,所有 score 值介于 min 和 max 之间(默认包括等于 max 或 min )的成员,有序成员是按递增(从小到大)排序。
-
zrevrangebyscore:返回有序集 key 中,所有 score 值介于 max 和 min 之间(默认包括等于 max 或 min )的的成员。有序集成员按递减(从大到小)排列
-
min , max 可以使用 -inf ,+inf 表示最小和最大
limit 用来限制返回结果的数量和区间。
withscores 显 示 score 和 value
-
语法:zrangebyscore key min max [WITHSCORES ] [LIMIT offset count]
#查全部 127.0.0.1:6379> zrange studentscore 0 -1 withscores 1) "lhr" 2) "92" 3) "czy" 4) "95" 5) "hyn" 6) "99" 7) "zx" 8) "80" #显示92-99之间的成员(包含 92 99) 127.0.0.1:6379> zrangebyscore studentscore 92 99 withscores 1) "zx" 2) "92" 3) "zlq" 4) "95" 5) "gjq" 6) "99" #显示90-100之间的成员(不包含 92 99) 127.0.0.1:6379> zrangebyscore studentscore (92 (99 withscores 1) "zlq" 2) "95" #显示所有数据(使用 -inf +inf) 127.0.0.1:6379> zrangebyscore studentscore -inf +inf withscores 1) "lhr" 2) "92" 3) "czy" 4) "95" 5) "hyn" 6) "99" 7) "zx" 8) "80" #使用limit #查全部 127.0.0.1:6379> zrangebyscore studentscore 90 100 withscores 1) "zx" 2) "92" 3) "zlq" 4) "95" 5) "gjq" 6) "99" #查找90-100之间的成员 127.0.0.1:6379> zrangebyscore studentscore 90 100 limit 1 2 #从第一位开始,取两个元素 1) "zlq" 2) "gjq"
(2)zcount 获取区间内元素个数
-
返回有序集 key 中, score 值在 min 和 max 之间(默认包括 score 值等于 min 或 max )的成员的数量
-
语法:zcount key min max
# 查看90-100之间的成员 127.0.0.1:6379> zrangebyscore studentscore 90 100 1) "zx" 2) "zlq" 3) "gjq" #查看90-100之间的成员数量 127.0.0.1:6379> zcount studentscore 90 100 (integer) 3
四、Redis事务
- 事务是指一系列操作步骤,这一系列的操作步骤,要么完全地执行,要么完全地不执行
- Redis 中的事务(transaction)是一组命令的集合,至少是两个或两个以上的命令,redis 事务保证这些命令被执行时中间不会被任何其他操作打断。
4.1、操作命令
4.1.1 multi 事务开始
- 作用:标记一个事务的开始。事务内的多条命令会按照先后顺序被放进一个队列当中。
- 返回值:总是返回 ok
4.1.2 exec 执行命令
- 执行所有事务块内的命令
- 返回值:事务内的所有执行语句内容,事务被打断(影响)返回 nil
4.1.3 discard 取消事务
- 取消事务,放弃执行事务块内的所有命令
- 返回值:总是返回 ok
4.1.4 watch 监视key
- 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动, 那么事务将被打断。
- 返回值:总是返回 ok
- 语法:watch key [key …]
4.1.5 unwatch 取消监视
- 取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后, EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了
- 返回值:总是返回 ok
4.2、事务的实现
4.2.1正常执行事务
-
执行步骤: 首先开启事务, 其次向事务队列中加入命令,最后执行事务提交
-
事务的执行:
- multi : 用 multi 命令告诉 Redis,接下来要执行的命令你先不要执行,而是把它们暂时存起来 (开启事务)
- sadd class 19130414 第一条命令进入等待队列(命令入队)
- sadd class 19130413 第二条命令进入等待队列(命令入队)
- exce 告知 redis 执行前面发送的两条命令(提交事务
-
在执行exec命令之前,如果有一条进入队列的命令出现错误(例如:命令语法错误),整个事务都会被终止,正确的命令也不会执行
-
在执行exec命令之后,如果有命令出现错误(例如:添加的数据有问题,命令执行时产生错误),事务不会终止,正确的命令依然会被执行
-
Redis 在事务失败时不进行回滚,而是继续执行余下的命令。
-
Redis 这种设计原则是:Redis 命令只会因为错误的语法而失败(这些问题不能在入队时发现),或是命令用在了错误类型的键上面,失败的命令并不是 Redis 导致,而是由编程错误造成的,这样错误应该在开发的过程中被发现,生产环境中不应出现语法的错误。就是在程序的运行环境中不应该出现语法的错误。而 Redis 能够保证正确的命令一定会被执行。再者不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速
#正常执行事务 #开启事务,其后的命令加入队列,暂时不自信 127.0.0.1:6379> multi OK #添加一条语句 127.0.0.1:6379(TX)> sadd class 19130414 QUEUED #表示命令进入队列,等待执行 127.0.0.1:6379(TX)> sadd class 19130413 QUEUED #执行事务,队列中的命令全部开始执行,返回的数据是顺序执行每条命令的执行结果 127.0.0.1:6379(TX)> exec 1) (integer) 1 2) (integer) 1 #查看class集合 127.0.0.1:6379> smembers class 1) "19130413" 2) "19130414"
4.2.2 放弃事务
-
事务的执行
- MULTI 开启事务
- SET age 25 命令入队
- SET age 30 命令入队
- DISCARD 放弃事务,则命令队列不会被执行
#放弃执行事务 #开始事务 127.0.0.1:6379> multi OK #设置k1为a1 127.0.0.1:6379(TX)> set k1 a1 QUEUED 127.0.0.1:6379(TX)> set k2 a2 QUEUED #放弃执行事务 127.0.0.1:6379(TX)> discard OK #k1 k2 的值没有改变 127.0.0.1:6379> get k1 "v1" 127.0.0.1:6379> get k2 "v2"
4.2.3 Redis的watch机制
-
watch机制原理
-
何时取消 key 的监视(WATCH)
- WATCH 命令可以被调用多次。 对键的监视从 WATCH 执行之后开始生效, 直到调用 EXEC 为止。不管事务是否成功执行, 对所有键的监视都会被取消。
- 当客户端断开连接时, 该客户端对键的监视也会被取消
- UNWATCH 命令可以手动取消对所有键的监视
-
数据k1,A修改的时候,为k1添加watch命令,如果k1在事务A执行完之前没有被修改,那么A修改成功;如果k1在A执行完事务之前被修改,那么事务A执行失败。
#客户端A:设置k1 k2 k3 事务,但不执行 127.0.0.1:6379> multi set k1 a1 (error) ERR wrong number of arguments for 'multi' command 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set k1 a1 QUEUED 127.0.0.1:6379(TX)> set k2 a2 QUEUED 127.0.0.1:6379(TX)> set k3 a3 QUEUED 127.0.0.1:6379(TX)> exec #客户端B:修改k1的值为10 127.0.0.1:6379> set k1 10 OK #客户端A:执行事务 127.0.0.1:6379(TX)> exec (nil)
五、Redis持久化
5.1 持久化概述
- 持久化可以理解为存储,就是将数据存储到一个不会丢失的地方,如果把数据放在内存中,电脑关闭或重启数据就会丢失,所以放在内存中的数据不是持久化的,而放在磁盘就算是一种持久化。
- Redis 的数据存储在内存中,内存是瞬时的,如果 linux 宕机或重启,又或者 Redis 崩溃或重启,所有的内存数据都会丢失,为解决这个问题,Redis 提供两种机制对数据进行持久化存储,便于发生故障后能迅速恢复数据。
5.2 持久化方式
5.2.1 RDB方式
(1)什么是RDB方式:
- Redis Database(RDB),就是在指定的时间间隔内将内存中的数据集快照写入磁盘,数据恢复时将快照文件直接再读到内存。
- RDB 保存了在某个时间点的数据集(全部数据)。存储在一个二进制文件中,只有一个文件。默认是 dump.rdb。RDB 技术非常适合做备份,可以保存最近一个小时,一天,一个月的全部数据。保存数据是在单独的进程中写文件,不影响 Redis 的正常使用。RDB 恢复数据时比其他 AOF 速度快。
- RDB方式也叫内存快照
(2)实现方式:
-
RDB 方式的数据持久化,仅需在 redis.conf 文件中配置即可,默认配置是启用的。
-
在配置文件 redis.conf 中配置SNAPSHOTTING
-
配置执行 RDB 生成快照文件的时间策略。
对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个 key 改动”这一条件被满足时, 自动保存一次数据集。
配置格式:save < seconds > < changes >
save 900 1 在900s的时间内有一个key的值被改动,就备份一次
save 300 10
save 60 10000
save “” 表示关闭RDB方式
-
dbfilename:设置 RDB 的文件名,默认文件名为 dump.rdb
-
dir:指定 RDB 文件的存储位置,默认是 ./ 当前目录
-
(3)总结
- 优点:由于存储的是数据快照文件,恢复数据很方便,也比较快
- 缺点:
- 会丢失最后一次快照以后更改的数据。如果你的应用能容忍一定数据的丢失,那么使用 rdb 是不错的选择;如果你不能容忍一定数据的丢失,使用 rdb 就不是一个很好的选择。
- 由于需要经常操作磁盘,RDB 会分出一个子进程。如果你的 redis 数据库很大的话, 子进程占用比较多的时间,并且可能会影响 Redis 暂停服务一段时间(millisecond 级别),如果你的数据库超级大并且你的服务器 CPU 比较弱,有可能是会达到一秒。
5.2.2 AOF方式
(1)什么是AOF方式
- Append-only File(AOF),Redis 每次接收到一条改变数据的命令时,它将把该命令写到一个 AOF 文件中(只记录写操作,读操作不记录),当 Redis 重启时,它通过执行 AOF 文件中所有的命令来恢复数据。
(2)如何实现
- AOF 方式的数据持久化,仅需在 redis.conf 文件中配置即可配置项:
- appendonly:默认是 no,改成 yes 即开启了 aof 持久化
- appendfilename:指定 AOF 文件名,默认文件名为 appendonly.aof
- dir : 指定 RDB 和 AOF 文件存放的目录,默认是 ./
- appendfsync:配置向 aof 文件写命令数据的策略:
- no:不主动进行同步操作,而是完全交由操作系统来做(即每 30 秒一次),比较快但不是很安全。
- always:每次执行写入都会执行同步,慢一些但是比较安全。
- everysec:每秒执行一次同步操作,比较平衡,介于速度和安全之间。这是默认项。
- auto-aof-rewrite-min-size:允许重写的最小 AOF 文件大小,默认是 64M 。当 aof 文件大于 64M 时,开始整理 aop 文件, 去掉无用的操作命令。缩小 aop 文件。
(3)总结
- 可以同时使用这两种方式,redis 默认优先加载 aof 文件(aof 数据最完整);
六、Redis主从复制
- Redis 提供了复制功能来自动实现多台 redis 服务器的数据同步
- 我们可以通过部署多台 redis,并在配置文件中指定这几台 redis 之间的主从关系,主负责写入数据, 同时把写入的数据实时同步到从机器, 这种模式叫做主从复制,即master/slave。
- redis 默认 master 用于写,slave 用于读,向 slave 写数据会导致错误
6.1 主从复制实现
- 方式 1:修改配置文件,启动时,服务器读取配置文件,并自动成为指定服务器的从服务器,从而构成主从复制的关系
- 方式 2: ./redis-server --slaveof ,在启动 redis 时指定当前服务成为某个主 Redis 服务的从 Slave
(1)方式1实现步骤
- 模拟多 Reids 服务器, 在一台已经安装 Redis 的机器上,运行多个 Redis 应用模拟多个 Reids 服务器。一个 Master,两个 Slave.
-
新建三个 Redis 的配置文件
作为 Master 的 Redis 端口是 6380
作为 Slaver 的 Redis 端口分别是 6382 , 6384
#设置配置文件 root@iZ8vbis43wevef6250tlrhZ opt]# ls containerd redis redis-6.2.1.tar.gz redis6380.conf redis6382.conf redis6384.conf redis.conf [root@iZ8vbis43wevef6250tlrhZ opt]# > redis6380.conf [root@iZ8vbis43wevef6250tlrhZ opt]# cat redis6380.conf [root@iZ8vbis43wevef6250tlrhZ opt]# > redis6382.conf [root@iZ8vbis43wevef6250tlrhZ opt]# > redis6384.conf [root@iZ8vbis43wevef6250tlrhZ opt]# ll redis*.conf -rw-rw-r-- 1 root root 0 Nov 15 15:08 redis6380.conf -rw-rw-r-- 1 root root 0 Nov 15 15:09 redis6382.conf -rw-rw-r-- 1 root root 0 Nov 15 15:09 redis6384.conf -rw-rw-r-- 1 root root 92224 Nov 15 14:11 redis.conf
-
编辑Master配置文件
在redis6380.conf中加入:
include /opt/redis.conf #包含原来的配置文件内容。/opt/redis.conf 按照自己的目录设置。 daemonize yes #yes 后台启动应用,相当于 ./redis-server & , &的作用。 port 6380 #port : 自定义的端口号 pidfile /var/run/redis_6380.pid #pidfile : 自定义的文件,表示当前程序的 pid ,进程 id。 logfile 6380.log #logfile:日志文件名 dbfilename dump6380.rdb #dbfilename:持久化的 rdb 文件名
-
编辑Slave配置文件
#redis6382.conf include /opt/redis.conf daemonize yes port 6382 pidfile /var/run/redis_6382.pid logfile 6382.log dbfilename dump6382.rdb slaveof 127.0.0.1 6380 #slaveof : 表示当前 Redis 是谁的从。当前是 127.0.0.0端口 6380 这个 Master 的从。
#redis6384.conf include /opt/redis.conf daemonize yes port 6384 pidfile /var/run/redis_6384.pid logfile 6384.log dbfilename dump6384.rdb slaveof 127.0.0.1 6380
-
启动服务器,Master/Slave都启动
启动方式: ./redis-server 配置文件
#启动三个redis [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-server /opt/redis6380.conf [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-server /opt/redis6382.conf [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-server /opt/redis6384.conf #查看进程 [root@iZ8vbis43wevef6250tlrhZ src]# ps -ef | grep redis root 8783 1 0 15:41 ? 00:00:00 ./redis-server 127.0.0.1:6380 root 8801 1 0 15:41 ? 00:00:00 ./redis-server 127.0.0.1:6382 root 8816 1 0 15:41 ? 00:00:00 ./redis-server 127.0.0.1:6384 root 8868 625 0 15:41 pts/0 00:00:00 grep --color=auto redis
-
查看配置后的服务信息
命令:
(1)Redis 客户端使用指定端口连接 Redis 服务器:./redis-cli -p 端口号
(2)查看服务器信息:info replication
#登录到6380 [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-cli -p 6380 #查看6380的信息 127.0.0.1:6380> info replication # Replication role:master #角色是master connected_slaves:2 #有2个slave slave0:ip=127.0.0.1,port=6382,state=online,offset=1414,lag=1 #列举两个slave slave1:ip=127.0.0.1,port=6384,state=online,offset=1414,lag=1 master_failover_state:no-failover
#登录到6382(6384内容相同) [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-cli -p 6382 127.0.0.1:6382> info replication # Replication role:slave #角色是slave master_host:127.0.0.1 master_port:6380 #master端口号 master_link_status:up #主master的状态是可用的(up:可用,down:不可用)
-
添加数据到Master
#先执行flushall命令清除数据,避免干扰的测试数据。 #flushall命令,生产环境避免使用 127.0.0.1:6380> flushall OK 127.0.0.1:6380> set k1 v1 OK 127.0.0.1:6380> set k2 v2 OK
-
在Slave中读数据
#6382,6384可以读Master数据,但是不能写数据 #6382 127.0.0.1:6382> get k1 "v1" 127.0.0.1:6382> get k2 "v2" #6384 127.0.0.1:6384> get k1 "v1" 127.0.0.1:6384> get k2 "v2" #写数据失败 127.0.0.1:6384> set k3 v3 (error) READONLY You can't write against a read only replica.
6.2 容灾处理
- master 上(冷处理:机器挂掉了,再处理)当 Master 服务出现故障,需手动将 slave 中的一个提升为 master, 剩下的 slave 挂至新的
- 命令:
- slaveof no one,将一台 slave 服务器提升为 Master (提升某 slave 为 master)
- slaveof 127.0.0.1 6381 (将 slave 挂至新的 master 上)
(1)实现步骤
-
将主服务器关闭(模拟挂掉)
[root@iZ8vbis43wevef6250tlrhZ src]# ps -ef | grep redis root 8801 1 0 15:41 ? 00:00:09 ./redis-server 127.0.0.1:6382 root 8816 1 0 15:41 ? 00:00:10 ./redis-server 127.0.0.1:6384 root 11081 10935 0 16:01 pts/1 00:00:00 ./redis-cli -p 6382 root 12123 11963 0 16:11 pts/2 00:00:00 ./redis-cli -p 6384 root 17872 625 0 17:03 pts/0 00:00:00 grep --color=auto redis
-
选择一个 Slave 升到 Master,其它的 Slave 挂到新提升的 Master
#提升为master 127.0.0.1:6382> slaveof no one OK #查看信息 127.0.0.1:6382> info replication # Replication role:master #当前角色是master connected_slaves:0 #当前的slave是0 master_failover_state:no-failover
-
将其他slave挂到新的Master上
#将6384挂载到6382上 127.0.0.1:6384> slaveof 127.0.0.1 6382 OK #查看信息 127.0.0.1:6384> info replication # Replication role:slave master_host:127.0.0.1 master_port:6382 #master端口号 master_link_status:up
现在的主从(Master/Slave)关系:Master 是 6382 , Slave 是 6384
-
将原来是服务器添加到主从结构
6380服务器修复后,重新工作,需要把它添加到现有的Master/Slave 中
#重启服务6380 [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-server /opt/redis6380.conf [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-cli -p 6380 #查看信息 127.0.0.1:6380> info replication # Replication role:master #默认新加的服务是master connected_slaves:0 master_failover_state:no-failover #添加6380到6382 127.0.0.1:6380> slaveof 127.0.0.1 6382 OK #查看信息 127.0.0.1:6380> info replication # Replication role:slave #现在角色是slave master_host:127.0.0.1 master_port:6382 #master端口号是6382 master_link_status:up
-
查看Master信息
#查看信息 127.0.0.1:6382> info replication # Replication role:master connected_slaves:2 #有两个slave slave0:ip=127.0.0.1,port=6384,state=online,offset=7813,lag=1 slave1:ip=127.0.0.1,port=6380,state=online,offset=7813,lag=1 master_failover_state:no-failover
现在的 Master/Slaver 关系是:
Master: 6382
Slave: 6380 6384
6.3 操作命令
- 进入客户端需指定端口:./redis-cli -p 6380
- 不配置启动默认都是主 master
- info replication 查看 redis 服务器所处角色
6.4 总结
- 一个 master 可以有多个 slave
- slave 下线,读请求的处理性能下降
- master 下线,写请求无法执行
- 当 master 发生故障,需手动将其中一台 slave 使用 slaveof no one 命令提升为 master,其它 slave 执行 slaveof 命令指向这个新的master,从新的master处同步数据。
- 主从复制模式的故障转移需要手动操作,要实现自动化处理,这就需要 Sentinel 哨兵,实现故障自动转移。
七、Redis Sentinel高可用
- Sentinel 哨兵是 redis 官方提供的高可用方案,可以用它来监控多个 Redis 服务实例的运行情况。
- Redis Sentinel 是一个运行在特殊模式下的 Redis 服务器。
- Redis Sentinel 是在多个Sentinel 进程环境下互相协作工作的。
7.1 Sentinel 系统有三个主要任务
-
监控:Sentinel 不断的检查主服务和从服务器是否按照预期正常工作。
-
提醒:被监控的 Redis 出现问题时,Sentinel 会通知管理员或其他应用程序。
-
自动故障转移:监控的主 Redis 不能正常工作,Sentinel 会开始进行故障迁移操作。将一个从服务器升级新的主服务器。 让其他从服务器挂到新的主服务器。同时向客户端提供新的主服务器地址。
-
Sentinel最少为三个,必须为奇数
原因:Sentinel监控Master采用心跳机制,每隔一秒发送一次请求,当其中一台Sentinel请求无响应,会发起投票,当票数多于半数,则认为Master不能工作了,然后从slave中选取一个作为Master
-
默认端口号:26379
7.2 配置实现
1、Sentinal配置
复制三份sentienl.conf文件
[root@iZ8vbis43wevef6250tlrhZ redis]# cp sentinel.conf sentinel16380.conf
[root@iZ8vbis43wevef6250tlrhZ redis]# cp sentinel.conf sentinel16384.conf
[root@iZ8vbis43wevef6250tlrhZ redis]# cp sentinel.conf sentinel16382.conf
修改sentinl.conf文件
#sentinel16380.conf 其他两个相同
#修改port
# port <sentinel-port>
# The port that this sentinel instance will run on
port 26380
#修改监控的 master 地址
# The valid charset is A-z 0-9 and the three characters ".-_".
#固定命令行 可修改名称 master地址 master端口号 投票数量
sentinel monitor mymaster 127.0.0.1 6382 2
2、先启动Redis,再启动Sentiel
启动Redis见上所述
启动Sentiel
命令:./redis-sentinel sentinel 配置文件
[root@iZ8vbis43wevef6250tlrhZ src]# ./redis-sentinel /opt/sentinel26382.conf
7464:X 15 Nov 2021 20:23:03.111 # +monitor master mymaster 127.0.0.1 6382 quorum 2
7464:X 15 Nov 2021 20:23:03.111 * +slave slave 127.0.0.1:6384 127.0.0.1 6384 @ mymaster 127.0.0.1 6382
7464:X 15 Nov 2021 20:23:03.119 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6382
7464:X 15 Nov 2021 20:24:43.354 * +sentinel sentinel 6d6b00d7c5a2db7d1e1c08b4c4ffab266088f6c4 127.0.0.1 26384 @ mymaster 127.0.0.1 6382 #其他两个sentinel
7464:X 15 Nov 2021 20:31:43.025 * +sentinel sentinel 9935c9d14e3ce4059f1b97f87e8e06bd75ac1706 127.0.0.1 26380 @ mymaster 127.0.0.1 6382
3、停止Master服务器
#查看Master信息
#6382是主服务器
127.0.0.1:6382> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6384,state=online,offset=184320,lag=1
slave1:ip=127.0.0.1,port=6380,state=online,offset=184320,lag=1
master_failover_state:no-failover
master_replid:60452299e6e0f9f5b4852e6d37e2c75371812d37
master_replid2:1c320a0a12f9f465218f9b6a51c7eb8f08d516d6
master_repl_offset:184453
second_repl_offset:6932
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:184453
#停止服务
127.0.0.1:6382> shutdown
not connected>
4、查看Sentinel
在 Master 执行 shutdown 后, 稍微等一会 Sentinel 要进行投票计算,从可用的 Slave选举新的 Master。
查看 Sentinel 日志,三个 Sentinel 窗口的日志是一样的。
#6380成为新的Master
7464:X 15 Nov 2021 20:41:32.948 # +switch-master mymaster 127.0.0.1 6382 127.0.0.1 6380
7464:X 15 Nov 2021 20:41:32.948 * +slave slave 127.0.0.1:6384 127.0.0.1 6384 @ mymaster 127.0.0.1 6380
7464:X 15 Nov 2021 20:41:32.948 * +slave slave 127.0.0.1:6382 127.0.0.1 6382 @ mymaster 127.0.0.1 6380
7464:X 15 Nov 2021 20:42:02.978 # +sdown slave 127.0.0.1:6382 127.0.0.1 6382 @ mymaster 127.0.0.1 6380
查看6380的变化
#查看信息
127.0.0.1:6380> info replication
# Replication
role:master #成为新的master
connected_slaves:1
slave0:ip=127.0.0.1,port=6384,state=online,offset=230683,lag=0
master_failover_state:no-failover
master_replid:bf437c83106f69558dd77b79702ded638cb1ae69
master_replid2:60452299e6e0f9f5b4852e6d37e2c75371812d37
master_repl_offset:230683
second_repl_offset:195311
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:7464
repl_backlog_histlen:223220
5、重启6382服务器
#重启6382服务器
[root@iZ8vbis43wevef6250tlrhZ src]# ./redis-server /opt/redis6382.conf
[root@iZ8vbis43wevef6250tlrhZ src]# ./redis-cli -p 6382
127.0.0.1:6382>
#查看6380服务器
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6384,state=online,offset=298760,lag=1
slave1:ip=127.0.0.1,port=6382,state=online,offset=298760,lag=1 #6382重新加入Master,成为slave
7.3 监控
- Sentinel 会不断检查 Master 和 Slave 是否正常
- 如果 Sentinel 挂了,就无法监控,所以需要多个哨兵,组成 Sentinel 网络,一个健康的Sentinel 至少有 3 个 Sentinel 应用。 彼此在独立的物理机器或虚拟机。
- 监控同一个 Master 的 Sentinel 会自动连接,组成一个分布式的 Sentinel 网络,互相通信并交换彼此关于被监控服务器的信息。
- 当一个 Sentinel 认为被监控的服务器已经下线时,它会向网络中的其它 Sentinel 进行确认,判断该服务器是否真的已经下线。
- 如果下线的服务器为主服务器,那么 Sentinel 网络将对下线主服务器进行自动故障转移, 通过将下线主服务器的某个从服务器提升为新的主服务器,并让其从服务器转移到新的主服务器下,以此来让系统重新回到正常状态。
- 下线的旧主服务器重新上线,Sentinel 会让它成为从服务器,挂到新的主服务器下
7.4 总结
- 主从复制,解决了读请求的分担,从节点下线,会使得读请求能力有所下降,Master 下线,写请求无法执行。
- Sentinel 会在 Master 下线后自动执行故障转移操作,提升一台 Slave 为 Master,并让其它Slave 成为新 Master 的 Slave。
八、Redis安全设置
- 访问 Redis 默认是没有密码,任意用户都可以访问。
- 设置 Redis 的访问密码,修改 redis.conf 中这行 requirepass 密码。
- 密码要比较复杂,不容易破解,而且需要定期修改。因为 redis 速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行 150K 次的密码尝试,需要指定非常非常强大的密码来防止暴力破解。
8.1 开启访问密码设置
-
修改 redis.conf 。 找到 requirepass 行去掉注释,requirepass 空格后就是密码。
#修改前,大致在文件879行左右 # requirepass foobared #修改为123456,生产环境要设置的较为复杂 requirepass 123456
8.2访问有密码的Redis
-
访问有密码的 Redis 两种方式
- 在连接到客户端后,使用命令 auth 密码 , 命令执行成功后,可以正常使用 Redis
- 在连接客户端时使用 -a 密码。例如 ./redis-cli -h ip -p port -a password
-
方法一:
#连接成功,但操作失败 127.0.0.1:6379> keys * (error) NOAUTH Authentication required. #输入命令 auth 密码 127.0.0.1:6379> auth 123456 OK 127.0.0.1:6379> keys * 1) "k2" 2) "k1"
-
方法二(不推荐)
#提示:警告将密码明文写出来不安全 [root@iZ8vbis43wevef6250tlrhZ src]# ./redis-cli -a 123456 Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379>
8.3 绑定IP
- 修改 redis.conf 文件,把# bind 127.0.0.1 前面的注释#号去掉,然后把 127.0.0.1 改成允许访问你 redis 服务器的 ip 地址,表示只允许该 ip 进行访问。
- 多个 ip 使用空格分隔。
8.4 修改默认端口
- 修改 redis 的端口,这一点很重要,使用默认的端口很危险,redis.conf 中修改 port 6379
- 将其修改为自己指定的端口(可随意),端口 1024 是保留给操作系统使用的。用户可以使用的范围是 1024-65535
- 使用 -p 参数指定端口,例如:./redis-cli -p 新设置端口
九、SpringBoot集成Redis
-
pom.xml
<!-- Redis起步依赖 springboot会在容器中创建两个对象RedisTemplate,StringRedisTemplate --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
application.yml
spring: redis: host: localhost port: 6397 password: 123456
-
RedisController
package com.bjpowernode.controller; import com.bjpowernode.vo.Student; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @RestController public class RedisController { /** * 注入 RedisTemplate * 泛型 key, value 都是 String ,或者 Object, 不写 * RedisTemplate<String,String> * RedisTemplate<Object,Object> * RedisTemplate * * 注意:RedisTemplate对象的名称RedisTemplate */ @Resource private RedisTemplate redisTemplate; @GetMapping("/myname") public String getName(){ redisTemplate.setKeySerializer( new StringRedisSerializer()); // redisTemplate.setValueSerializer( new StringRedisSerializer()); String name=(String) redisTemplate.opsForValue().get("name"); return name; } //添加数据到Redis @PostMapping("/name/{myname}") public String addName(@PathVariable("myname") String name){ redisTemplate.opsForValue().set("name",name); return "添加了学生:"+name; } }
-
对比StringRedisTemplate和RedisTemplate
StringRedisTemplate:把k,v都是作为String类型处理,使用的是String的序列化,可读性好RedisTemplate:把k,v 经过了序列化存到redis。k,v是序列化的内容,不能直接识别,默认使用JDK的序列化,可以修改为其他的
9.1 序列化
- 序列化:把对象转化为可传输的字节序列的过程叫做序列化
- 反序列化:把字节序列化还原为对象的过程称为反序列化
9.1.1 为什么需要序列化
- 序列化最终的目的是为了对象可以跨平台存储和进行网络传输。而进行跨平台存储和网络传输的方式就是IO,而IO支持的数据格式就是字节数组。必须把对象转成字节数组的时候就制定一种规则(序列化),那么从IO流里面读出数据的时候再以这种规则把对象还原回来(反序列化)。
9.1.2 什么情况下需要序列化
- 凡是需要进行“跨平台存储”,“网络传输”的数据,都需要进行序列化
- 本质上存储和网络传输都需要经过把一个对象状态保存成一种跨平台识别的字节格式,然后其他的平台才可以通过字节信息解析还原对象信息
9.1.3 序列化方式
- 序列化知识一种拆装组装对象的规则,那么这种规则肯定也可能有多种多样
- 常见的序列化方式有:JDK(不支持跨语言),JSON,XML,Hessian,Kryo(不支持跨语言),Thrift,Protostuff
- Java的序列化:把Java对象转为bate[],二进制数据
- Json序列化:Json序列化功能将对象转换为Json格式,或从Json格式转换为对象。实体类转换为Json字符串
9.2 设置RedisTemplate序列化
-
可以设置key,也可以设置value的序列化
-
也可以同时设置key和value的序列化
@PostMapping("/Redis/addstr") public String addName(String k,String v){ //使用RedisTemplate //设置key使用String的序列化 redisTemplate.setKeySerializer(new StringRedisSerializer()); //设置value使用String的序列化 redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.opsForValue().set(k,v); return k+v; }
9.3 Json序列化
-
创建Student实体类
/** * 序列化 */ @PostMapping("/Redis/addjson") public String addJson(){ Student student = new Student(); student.setId(1001); student.setName("zs"); //设置key使用String的序列化 redisTemplate.setKeySerializer(new StringRedisSerializer()); //设置value使用String的序列化 redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer()); redisTemplate.opsForValue().set("stdent",student); return student; } /** * 反序列化 */ @PostMapping("/Redis/getjson") public String getJson(){ //设置key使用String的序列化 redisTemplate.setKeySerializer(new StringRedisSerializer()); //设置value使用String的序列化 redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer()); redisTemplate.opsForValue().get("stdent"); return student; }