这里写目录标题
- 一、Key
- 二、常见的数据类型
-
- [1、string (字符串)](#1、string (字符串))
-
- [1-1 常见命令](#1-1 常见命令)
- [1-2 案例](#1-2 案例)
- 2、List(列表)
-
- [2-1 常见命令](#2-1 常见命令)
- [2-2 案例](#2-2 案例)
- 3、Hash(哈希)
-
- [3-1 常见命令](#3-1 常见命令)
- [3-2 案例](#3-2 案例)
- 4、Set(集合)元素唯一不重复
-
- [4-1 常见命令](#4-1 常见命令)
- [4-2 案例](#4-2 案例)
- 5、zSet(有序集合)
-
- [5-1 常见命令](#5-1 常见命令)
- [5-2 案例](#5-2 案例)
- 三、Redis的Java客户端
- [四、 Redis持久化之RDB](#四、 Redis持久化之RDB)
- 五、Redis持久化之AOF
-
- 1、什么是AOF
- 2、AOF持久化流程
- 3、Rewrite压缩
- 4、主从复制
-
- [4.1 配置主从复制](#4.1 配置主从复制)
- [4.2 一主二仆](#4.2 一主二仆)
- 5、复制原理
-
- [4-1 薪火相传](#4-1 薪火相传)
- [4-2 反客为主](#4-2 反客为主)
- [4-3 哨兵模式](#4-3 哨兵模式)
一、Key
dbsize 查看当前数据库的 key 的数量
flushdb 清空当前库
flushall 通杀全部库
keys * 获取当前库中的所有key
select 0 选择第一个库
move key 1 将当前的数据库 key 移动到某个数据库,目标库有,则不能移动
randomkey 从当前数据库中随机返回
type key 类型
del key 删除 key
exists key 判断是否存在 key
expire key 10 为给定的key设置过期时间 单位是秒
pexpire key 1000 给定的key设置过期时间 单位:毫秒
persist key 删除key的过期时间
ttl key 查看还有多少秒过期,-1 表示永不过期,-2 表示已过期
二、常见的数据类型
1、string (字符串)
1-1 常见命令
java
SET:添加或者修改已经存在的一个String类型的键值对
GET:根据key获取String类型的value
MSET:批量添加多个String类型的键值对
MGET:根据多个key获取多个String类型的valueINCR:让一个整型的key自增1
INCRBY:让一个整型的key自增并指定步长,例如: incrby num 2让num值自增2
INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行SETEX:添加一个String类型的键值对,并且指定有效期
1-2 案例
添加、查询、追加、获取长度,判断是否存在的操作
redis
127.0.0.1:6379> set name dingdada #插入一个key为'name'值为"dingdada"的数据
OK
127.0.0.1:6379> get dingdada # 获取key为'dingdada'的数据
"dingdada"
127.0.0.1:6379> keys * #查看当前库的所有数据
1) "name"
127.0.0.1:6379> EXISTS name #判断key为'name'的数据存在不存在,存在返回1
(integer) 1
127.0.0.1:6379> EXISTS name1 #不存在返回0
(integer) 0
127.0.0.1:6379> APPEND name1 dingdada1 #追加到key为'name'的数据后拼接值为'dingdada1',不存在则新增一个,并且返回该数据的总长度
(integer) 9
text
APPEND name1 dingdada1
自增、自减操作
text
127.0.0.1:6379> set num 0 #插入一个初始值为0的数据
OK
127.0.0.1:6379> get num
"0"
127.0.0.1:6379> incr num #指定key为'num'的数据自增1,返回结果 相当于java中 i++
(integer) 1
127.0.0.1:6379> get num #一般用来做文章浏览量、点赞数、收藏数等功能
"1"
127.0.0.1:6379> incr num
(integer) 2
127.0.0.1:6379> incr num
(integer) 3
127.0.0.1:6379> get num
"3"
127.0.0.1:6379> decr num #指定key为'num'的数据自减1,返回结果 相当于java中 i--
(integer) 2
127.0.0.1:6379> decr num
(integer) 1
127.0.0.1:6379> decr num
(integer) 0
127.0.0.1:6379> decr num #可以一直减为负数~
(integer) -1
127.0.0.1:6379> decr num #一般用来做文章取消点赞、取消收藏等功能
(integer) -2
127.0.0.1:6379> decr num
(integer) -3
127.0.0.1:6379> INCRBY num 10 #后面跟上by 指定key为'num'的数据自增'参数(10)',返回结果
(integer) 7
127.0.0.1:6379> INCRBY num 10
(integer) 17
127.0.0.1:6379> DECRBY num 3 #后面跟上by 指定key为'num'的数据自减'参数(3)',返回结果
(integer) 14
127.0.0.1:6379> DECRBY num 3
(integer) 11
截取、替换字符串操作
text
#截取
127.0.0.1:6379> set key1 "hello world!"
OK
127.0.0.1:6379> get key1
"hello world!"
127.0.0.1:6379> GETRANGE key1 0 4 #截取字符串,相当于java中的subString,下标从0开始,不会改变原有数据
"hello"
127.0.0.1:6379> get key1
"hello world!"
127.0.0.1:6379> GETRANGE key1 0 -1 #0至-1相当于 get key1,效果一致,获取整条数据
"hello world!"
#替换
127.0.0.1:6379> set key2 "hello,,,world!"
OK
127.0.0.1:6379> get key2
"hello,,,world!"
127.0.0.1:6379> SETRANGE key2 5 888 #此语句跟java中replace有点类似,下标也是从0开始,但是有区别:java中是指定替换字符,Redis中是从指定位置开始替换,替换的数据根据你所需替换的长度一致,返回值是替换后的长度
(integer) 14
127.0.0.1:6379> get key2
"hello888world!"
127.0.0.1:6379> SETRANGE key2 5 67 #该处只替换了两位
(integer) 14
127.0.0.1:6379> get key2
"hello678world!"
设置过期时间、不存在设置操作
text
#设置过期时间,跟Expire的区别是前者设置已存在的key的过期时间,而setex是在创建的时候设置过期时间
127.0.0.1:6379> setex name1 15 dingdada #新建一个key为'name1',值为'dingdada',过期时间为15秒的字符串数据
OK
127.0.0.1:6379> ttl name1 #查看key为'name1'的key的过期时间
(integer) 6
127.0.0.1:6379> ttl name1
(integer) 5
127.0.0.1:6379> ttl name1
(integer) 3
127.0.0.1:6379> ttl name1
(integer) 1
127.0.0.1:6379> ttl name1
(integer) 0
127.0.0.1:6379> ttl name1 #返回为-2时证明该key已过期,即不存在
(integer) -2
#不存在设置
127.0.0.1:6379> setnx name2 dingdada2 #如果key为'name2'不存在,新增数据,返回值1证明成功
(integer) 1
127.0.0.1:6379> get name2
"dingdada2"
127.0.0.1:6379> keys *
1) "name2"
127.0.0.1:6379> setnx name2 "dingdada3" #如果key为'name2'的已存在,设置失败,返回值0,也就是说这个跟set的区别是:set会替换原有的值,而setnx不会,存在即不设置,确保了数据误操作~
(integer) 0
127.0.0.1:6379> get name2
"dingdada2"
mset、mget操作
text
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #插入多条数据
OK
127.0.0.1:6379> keys * #查询所有数据
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 #查询key为'k1','k2','k3'的数据
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> MSETNX k1 v1 k4 v4 #msetnx是一个原子性的操作,在一定程度上保证了事务!要么都成功,要么都失败!相当于if中的条件&&(与)
(integer) 0
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> MSETNX k5 v5 k4 v4 #全部成功
(integer) 1
127.0.0.1:6379> keys *
1) "k2"
2) "k4"
3) "k3"
4) "k5"
5) "k1"
添加获取对象、getset操作
java
127.0.0.1:6379> mset student:1:name dingdada student:1:age 22 #新增一个key为'student:1:name',value为'dingdada '。。等数据
OK
127.0.0.1:6379> keys * #查看所有的key
1) "student:1:age"
2) "student:1:name"
127.0.0.1:6379> mget student:1:age student:1:name #获取数据
1) "22"
2) "dingdada"
##getset操作
127.0.0.1:6379> getset name1 dingdada1 #先get再set,先获取key,如果没有,set值进去,返回的是get的值
(nil)
127.0.0.1:6379> get name1
"dingdada1"
127.0.0.1:6379> getset name1 dingdada2 ##先获取key,如果有,set(替换)最新的值进去,返回的是get的值
"dingdada1"
127.0.0.1:6379> get name1 #替换成功
"dingdada2"
mset student:1:name dingdada student:1:age 22
2、List(列表)
2-1 常见命令
java
LPUSH key element ...:向列表左侧插入一个或多个元素
LPOP key:移除并返回列表左侧的第一个元素,没有则返回nil
RPUSH key element ...:向列表右侧插入一个或多个元素
RPOP key:移除并返回列表右侧的第一个元素
LRANGE key star end:返回一段角标范围内的所有元素
BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
lpush(左插入)、lrange(查询集合)、rpush(右插入)操作
2-2 案例
java
#lpush
127.0.0.1:6379> lpush list v1 #新增一个集合
(integer) 1
127.0.0.1:6379> lpush list v2
(integer) 2
127.0.0.1:6379> lpush list v3
(integer) 3
#lrange
127.0.0.1:6379> LRANGE list 0 -1 #查询list的所有元素值
1) "v3"
2) "v2"
3) "v1"
127.0.0.1:6379> lpush list1 v1 v2 v3 v4 v5 #批量添加集合元素
(integer) 5
127.0.0.1:6379> LRANGE list1 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
###这里大家有没有注意到,先进去的会到后面,也就是我们的lpush的意思是左插入,l--left
#rpush
127.0.0.1:6379> LRANGE list 0 1 #指定查询列表中的元素,从下标零开始,1结束,两个元素
1) "v3"
2) "v2"
127.0.0.1:6379> LRANGE list 0 0 #指定查询列表中的唯一元素
1) "v3"
127.0.0.1:6379> rpush list rv0 #右插入,跟lpush相反,这里添加进去元素是在尾部!
(integer) 4
127.0.0.1:6379> lrange list 0 -1 #查看集合所有元素
1) "v3"
2) "v2"
3) "v1"
4) "rv0"
##联想:这里我们是不是可以做一个,保存的记录值(如:账号密码的记录),
每次都使用lpush,老的数据永远在后面,我们每次获取 0 0 位置的元素,是不是相当于更新了
数据操作,但是数据记录还在?想要查询记录即可获取集合所有元素!
lpop(左移除)、rpop(右移除)操作
java
#lpop
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
127.0.0.1:6379> lpop list #从头部开始移除第一个元素
"v5"
##################
#rpop
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> rpop list
"v1"
127.0.0.1:6379> LRANGE list 0 -1 #从尾部开始移除第一个元素
1) "v4"
2) "v3"
3) "v2"
lindex(查询指定下标元素)、llen(获取集合长度) 操作
java
#lindex
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
127.0.0.1:6379> lindex list 1 #获取指定下标位置集合的元素,下标从0开始计数
"v3"
127.0.0.1:6379> lindex list 0 #相当于java中的indexof
"v4"
#llen
127.0.0.1:6379> llen list #获取指定集合的元素长度,相当于java中的length或者size
(integer) 3
lrem(根据value移除指定的值)
java
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
127.0.0.1:6379> lrem list 1 v2 #移除集合list中的元素是v2的元素1个
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
127.0.0.1:6379> lrem list 0 v3 #移除集合list中的元素是v2的元素1个,这里的0和1效果是一致的
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
127.0.0.1:6379> lpush list v3 v2 v2 v2
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "v2"
2) "v2"
3) "v2"
4) "v3"
5) "v4"
127.0.0.1:6379> lrem list 3 v2 #移除集合list中元素为v2 的'3'个,这里的参数数量,如果实际中集合元素数量不达标,不会报错,全部移除后返回成功移除后的数量值
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "v3"
2) "v4"
ltrim(截取元素)、rpoplpush(移除指定集合中最后一个元素到一个新的集合中)操作
java
#ltrim
127.0.0.1:6379> lpush list v1 v2 v3 v4
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "v4"
2) "v3"
3) "v2"
4) "v1"
127.0.0.1:6379> ltrim list 1 2 #通过下标截取指定的长度,这个list已经被改变了,只剩下我们所指定截取后的元素
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "v3"
2) "v2"
################
#rpoplpush
127.0.0.1:6379> lpush list v1 v2 v3 v4 v5
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
5) "v1"
127.0.0.1:6379> rpoplpush list newlist #移除list集合中的最后一个元素到新的集合newlist中,返回值是移除的最后一个元素值
"v1"
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
127.0.0.1:6379> LRANGE newlist 0 -1 #确实存在该newlist集合并且有刚刚移除的元素,证明成功
1) "v1"
lset(更新)、linsert操作
java
#lset
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "v4"
3) "v3"
4) "v2"
127.0.0.1:6379>
127.0.0.1:6379> lset list 1 newV5 #更新list集合中下标为'1'的元素为'newV5'
OK
127.0.0.1:6379> LRANGE list 0 -1 #查看证明更新成功
1) "v5"
2) "newV5"
3) "v3"
4) "v2"
##注意点:
127.0.0.1:6379> lset list1 0 vvvv #如果指定的'集合'不存在,报错
(error) ERR no such key
127.0.0.1:6379> lset list 8 vvv #如果集合存在,但是指定的'下标'不存在,报错
(error) ERR index out of range
########################
#linsert
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "newV5"
3) "v3"
4) "v2"
127.0.0.1:6379> LINSERT list after v3 insertv3 #在集合中的'v3'元素 '(after)之后' 加上一个元素
(integer) 5
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "newV5"
3) "v3"
4) "insertv3"
5) "v2"
127.0.0.1:6379> LINSERT list before v3 insertv3 #在集合中的'v3'元素 '(before)之前' 加上一个元素
(integer) 6
127.0.0.1:6379> LRANGE list 0 -1
1) "v5"
2) "newV5"
3) "insertv3"
4) "v3"
5) "insertv3"
6) "v2"
3、Hash(哈希)
3-1 常见命令
java
HSET key field value:添加或者修改hash类型key的field的值
HGET key field:获取一个hash类型key的field的值
HMSET:批量添加多个hash类型key的field的值HMGET:批量获取多个hash类型key的field的值
HGETALL:获取一个hash类型的key中的所有的field和valueHKEYS:获取一个hash类型的key中的所有的field
HVALS:获取一个hash类型的key中的所有的value
HINCRBY:让一个hash类型key的字段值自增并指定步长
HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
3-2 案例
hset(添加hash)、hget(查询)、hgetall(查询所有)、hdel(删除hash中指定的值)、hlen(获取hash的长度)、hexists(判断key是否存在)操作
java
127.0.0.1:6379> hset myhash name dingdada age 23 #添加hash,可多个
(integer) 2
127.0.0.1:6379> hget myhash name #获取hash中key是name的值
"dingdada"
127.0.0.1:6379> hget myhash age #获取hash中key是age的值
"23"
127.0.0.1:6379> hgetall myhash #获取hash中所有的值,包含key
1) "name"
2) "dingdada"
3) "age"
4) "23"
127.0.0.1:6379> hset myhash del test #添加
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
3) "age"
4) "23"
5) "del"
6) "test"
127.0.0.1:6379> hdel myhash del age #删除指定hash中的key(可多个),key删除后对应的value也会被删除
(integer) 2
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
127.0.0.1:6379> hlen myhash #获取指定hash的长度,相当于length、size
(integer) 1
127.0.0.1:6379> HEXISTS myhash name #判断key是否存在于指定的hash,存在返回1
(integer) 1
127.0.0.1:6379> HEXISTS myhash age #判断key是否存在于指定的hash,不存在返回0
(integer) 0
hkeys(获取所有key)、hvals(获取所有value)、hincrby(给值加增量)、hsetnx(存在不添加)操作
java
127.0.0.1:6379> hset myhash age 23 high 173
(integer) 2
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
3) "age"
4) "23"
5) "high"
6) "173"
127.0.0.1:6379> hkeys myhash #获取指定hash中的所有key
1) "name"
2) "age"
3) "high"
127.0.0.1:6379> hvals myhash #获取指定hash中的所有value
1) "dingdada"
2) "23"
3) "173"
127.0.0.1:6379> hincrby myhash age 2 #让hash中age的value指定+2(自增)
(integer) 25
127.0.0.1:6379> hincrby myhash age -1 #让hash中age的value指定-1(自减)
(integer) 24
127.0.0.1:6379> hsetnx myhash nokey novalue #添加不存在就新增返回新增成功的数量(只能单个增加哦)
(integer) 1
127.0.0.1:6379> hsetnx myhash name miaotiao #添加存在则失败返回0
(integer) 0
127.0.0.1:6379> hgetall myhash
1) "name"
2) "dingdada"
3) "age"
4) "24"
5) "high"
6) "173"
7) "nokey"
8) "novalue"
4、Set(集合)元素唯一不重复
4-1 常见命令
java
SADD key member ...:向set中添加一个或多个元素
SREM key member ...:移除set中的指定元素
SCARD key:返回set中元素的个数
SISMEMBER key member:判断一个元素是否存在于set中
SMEMBERS:获取set中的所有元素
4-2 案例
sadd(添加)、smembers(查看所有元素)、sismember(判断是否存在)、scard(查看长度)、srem(移除指定元素)操作
java
#set中所有的元素都是唯一的不重复的!
127.0.0.1:6379> sadd set1 ding da mian tiao #添加set集合(可批量可单个,写法一致,不再赘述)
(integer) 4
127.0.0.1:6379> SMEMBERS set1 #查看set中所有元素
1) "mian"
2) "da"
3) "tiao"
4) "ding"
127.0.0.1:6379> SISMEMBER set1 da #判断某个值在不在set中,在返回1
(integer) 1
127.0.0.1:6379> SISMEMBER set1 da1 #不在返回0
(integer) 0
127.0.0.1:6379> SCARD set1 #查看集合的长度,相当于size、length
(integer) 4
127.0.0.1:6379> srem set1 da #移除set中指定的元素
(integer) 1
127.0.0.1:6379> SMEMBERS set1 #移除成功
1) "mian"
2) "tiao"
3) "ding"
srandmember(抽随机)操作
java
127.0.0.1:6379> sadd myset 1 2 3 4 5 6 7 #在set中添加7个元素
(integer) 7
127.0.0.1:6379> SMEMBERS myset
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
127.0.0.1:6379> SRANDMEMBER myset 1 #随机抽取myset中1个元素返回
1) "4"
127.0.0.1:6379> SRANDMEMBER myset 1 #随机抽取myset中1个元素返回
1) "1"
127.0.0.1:6379> SRANDMEMBER myset 1 #随机抽取myset中1个元素返回
1) "5"
127.0.0.1:6379> SRANDMEMBER myset #不填后参数,默认抽1个值,但是下面返回不会带序号值
"3"
127.0.0.1:6379> SRANDMEMBER myset 3 #随机抽取myset中3个元素返回
1) "1"
2) "2"
3) "3"
127.0.0.1:6379> SRANDMEMBER myset 3 #随机抽取myset中3个元素返回
1) "6"
2) "3"
3) "5"
spop(随机删除元素)、smove(移动指定元素到新的集合中)操作
java
127.0.0.1:6379> SMEMBERS myset
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
127.0.0.1:6379> spop myset #随机删除1个元素,不指定参数值即删除1个
"2"
127.0.0.1:6379> spop myset 1 #随机删除1个元素
1) "7"
127.0.0.1:6379> spop myset 2 #随机删除2个元素
1) "3"
2) "5"
127.0.0.1:6379> SMEMBERS myset #查询删除后的结果
1) "1"
2) "4"
3) "6"
127.0.0.1:6379> smove myset myset2 1 #移动指定set中的指定元素到新的set中
(integer) 1
127.0.0.1:6379> SMEMBERS myset #查询原来的set集合
1) "4"
2) "6"
127.0.0.1:6379> SMEMBERS myset2 #查询新的set集合,如果新的set存在,即往后加,如果不存在,则自动创建set并且加入进去
1) "1"
sdiff(差集)、sinter(交集)、sunion(并集)操作
java
127.0.0.1:6379> sadd myset1 1 2 3 4 5
(integer) 5
127.0.0.1:6379> sadd myset2 3 4 5 6 7
(integer) 5
127.0.0.1:6379> SMEMBERS myset1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
127.0.0.1:6379> SMEMBERS myset2
1) "3"
2) "4"
3) "5"
4) "6"
5) "7"
127.0.0.1:6379> SDIFF myset1 myset2 #查询指定的set之间的差集,可以是多个set
1) "1"
2) "2"
127.0.0.1:6379> SINTER myset1 myset2 #查询指定的set之间的交集,可以是多个set
1) "3"
2) "4"
3) "5"
127.0.0.1:6379> sunion myset1 myset2 #查询指定的set之间的并集,可以是多个set
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
5、zSet(有序集合)
5-1 常见命令
java
ZADD key score member:添加一个或多个元素到sorted set,如果已经存在则更新其score值
ZREM key member:删除sorted set中的一个指定元素
zSCORE key member:获取sorted set中的指定元素的score值
ZRANK key member:获取sorted set中的指定元素的排名
ZCARD key:获取sorted set中的元素个数
zCOUNT key min max:统计score值在给定范围内的所有元素的个数
ZINCRBY key increment member: 让sorted set中的指定元素自增,步长为指定的increment值
ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
ZDIFF、ZINTER、ZUNION:求差集、交集、并集
5-2 案例
zadd(添加)、zrange(查询)、zrangebyscore(排序小-大)、zrevrange(排序大-小)、zrangebyscore withscores(查询所有值包含key)操作
java
127.0.0.1:6379> zadd myzset 1 one 2 two 3 three #添加zset值,可多个
(integer) 3
127.0.0.1:6379> ZRANGE myzset 0 -1 #查询所有的值
1) "one"
2) "two"
3) "three"
#-inf 负无穷 +inf 正无穷
127.0.0.1:6379> ZRANGEBYSCORE myzset -inf +inf #将zset的值根据key来从小到大排序并输出
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> ZRANGEBYSCORE myzset 0 1 #只查询key<=1的值并且排序从小到大
1) "one"
127.0.0.1:6379> ZREVRANGE myzset 1 -1 #从大到小排序输出
1) "two"
2) "one"
127.0.0.1:6379> ZRANGEBYSCORE myzset -inf +inf withscores #查询指定zset的所有值,包含序号的值
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
zrem(移除元素)、zcard(查看元素个数)、zcount(查询指定区间内的元素个数)操作
java
127.0.0.1:6379> zadd myset 1 v1 2 v2 3 v3 4 v4
(integer) 4
127.0.0.1:6379> ZRANGE myset 0 -1
1) "v1"
2) "v2"
3) "v3"
4) "v4"
127.0.0.1:6379> zrem myset v3 #移除指定的元素,可多个
(integer) 1
127.0.0.1:6379> ZRANGE myset 0 -1
1) "v1"
2) "v2"
3) "v4"
127.0.0.1:6379> zcard myset #查看zset的元素个数,相当于长度,size。
(integer) 3
127.0.0.1:6379> zcount myset 0 100 #查询指定区间内的元素个数
(integer) 3
127.0.0.1:6379> zcount myset 0 2 #查询指定区间内的元素个数
(integer) 2
三、Redis的Java客户端
1、快速入门
- 创建maven工程
- 引入依赖
xml
<!--jedis-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.7.0</version>
</dependency>
<!--单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.6</version>
</dependency>
- 建立连接
java
import redis.clients.jedis.Jedis;
public class Tes {
public static void main(String[] args) {
// 1.建立连接
Jedis jedis = new Jedis("192.168.67.34", 6379);
// 2.设置密码
jedis.auth("yyl");
String PONG = jedis.ping();
System.out.println("连接成功:"+PONG);
// 在这里可以执行其他操作,例如执行Redis命令等
// 关闭连接
jedis.close();
}
}
java
import redis.clients.jedis.Jedis;
public class Redis {
public static void main(String[] args) {
// 创建 Jedis 对象,参数为 Redis 服务器的 IP 和端口号
Jedis jedis = new Jedis("192.168.67.34", 6379);
// 如果 Redis 设置了密码,需要使用以下方法进行认证,否则可以省略此步骤
jedis.auth("yyl");
try {
// 执行 Redis 命令
String result = jedis.ping();
// 输出结果
System.out.println("连接成功: " + result);
System.out.println("连接信息: " + jedis);
} finally {
// 关闭连接
jedis.close();
}
}
}
四、 Redis持久化之RDB
五、Redis持久化之AOF
1、什么是AOF
AOF(Append Only File)
以日志的形式来记录每个写操作(增量保存),
将Redis执行过的所有写指令记录下来(读操作不记录),
只许追加文件但不可以改写文件。
redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
2、AOF持久化流程
(1)客户端的请求写命令会被append追加到AOF缓冲区内;
(2)AOF缓冲区根据AOF持久化策略[always,everysec,no]将操作sync同步到磁盘的AOF文件中;
(3)AOF文件大小超过重写策略或手动重写时,会对AOF文件rewrite重写,压缩AOF文件容量;
(4)Redis服务重启时,会重新load加载AOF文件中的写操作达到数据恢复的目的;
AOF默认不开启
可以在redis.conf中配置文件名称,默认为 appendonly.aof
AOF文件的保存路径,同RDB的路径一致。
AOF和RDB同时开启,redis听谁的?
AOF和RDB同时开启,系统默认取AOF的数据(数据不会存在丢失)
开启AOF
在699行 appendonly no 把no改为yes 开启后会把信息存到appendonly.aof中
重启
redis
[root@localhost bin]# systemctl restart redis
RDB和AOF用哪个好
官方推荐两个都启用。
如果对数据不敏感,可以选单独用RDB。
不建议单独用 AOF,因为可能会出现Bug。
如果只是做纯内存缓存,可以都不用。
AOF启动/修复/恢复
AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。
-
正常恢复
修改默认的appendonly no,改为yes
将有数据的aof文件复制一份保存到对应目录
恢复:重启redis然后重新加载
-
异常恢复
修改默认的appendonly no,改为yes
如遇到AOF文件损坏,通过
/usr/redis/bin/redis-check-aof --fix 文件的位置/appendonly.aof进行恢复
备份被写坏的AOF文件
恢复:重启redis,然后重新加载
bash
[root@localhost bin]# ./redis-cli -a yyl
127.0.0.1:6379> auth yyl
OK
127.0.0.1:6379> set name yyy
OK
127.0.0.1:6379> sadd kkk l1 l2 l3 l4
(integer) 4
127.0.0.1:6379> quit
进入文件随便修改破坏文件
恢复破坏文件
bash
[root@localhost bin]# ./redis-check-aof --fix ./appendonly.aof
0x 6a: Expected \r\n, got: 690d
AOF analyzed: size=128, ok_up_to=55, diff=73
This will shrink the AOF from 128 bytes, with 73 bytes, to 55 bytes
Continue? [y/N]: y
Successfully truncated AOF
如果想修复rdb文件
使用redis-check-rdb即可
AOF同步频率设置
appendfsync always
始终同步,每次Redis的写入都会立刻记入日志;性能较差但数据完整性比较好
appendfsync everysec
每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
appendfsync no
redis不主动进行同步,把同步时机交给操作系统。
3、Rewrite压缩
- 介绍
AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制, 当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩, 只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof - 触发机制,何时重写
Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发
重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。 - auto-aof-rewrite-percentage
设置重写的基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发) - auto-aof-rewrite-min-size
设置重写的基准值,最小文件64MB。达到这个值开始重写。
例如:文件达到70MB开始重写,降到50MB,下次什么时候开始重写?100MB
系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,
如果Redis的AOF当前大小>= base_size +base_size*100% (默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写。
bash
[root@localhost bin]# vim redis.conf
在771行 auto-aof-rewrite-min-size 64mb
- 重写流程
- grewriteaof触发重写,判断是否当前有bgsave或bgrewriteaof在运行,如果有,则等待该命令结束后再继续执行。
- 主进程fork出子进程执行重写操作,保证主进程不会阻塞。
- 子进程遍历redis内存中数据到临时文件,客户端的写请求同时写入aof_buf缓冲区和aof_rewrite_buf重写缓冲区保证原AOF文件完整以及新AOF文件生成期间的新的数据修改动作不会丢失。
- 子进程写完新的AOF文件后,向主进程发信号,父进程更新统计信息。
- 主进程把aof_rewrite_buf中的数据写入到新的AOF文件。
- 使用新的AOF文件覆盖旧的AOF文件,完成AOF重写。
4、主从复制
4.1 配置主从复制
- 在根目录创建文件
bash
[root@localhost ~]# mkdir redis
- 复制redis.conf到redis文件夹下
bash
[root@localhost ~]# cd redis/
[root@localhost redis]# cp /usr/redis/bin/redis.conf /root/redis
把294行密码 去掉 # requirepass yyl
- 配置一主多从,创建三个配置文件
- redis6000.conf
- redis6001.conf
- redis6002.conf
- 文件内容
bash
include /root/redis/redis.conf
pidfile /var/run/resi_6000.pid
port 6001
dbfilename dump6001.rdb
- 重新启动
bash
systemctl restart redis
- 运行三个redis
bash
/usr/redis/bin/redis-server /root/redis/resi_6000.conf
/usr/redis/bin/redis-server /root/redis/resi_6001.conf
/usr/redis/bin/redis-server /root/redis/resi_6002.conf
- 查询运行状态
bash
[root@localhost redis]# ps -ef|grep redis
4.2 一主二仆
- 查看三台服务器的运行情况
连接客户端 :./redis-cli -p 6379
查看运行 状态:info replication
- 三台全部都是主机
配从
6379 主 6000 6001从
slaveof
成为某个实例的从服务器
在6000 上执行: slaveof 127.0.0.1 6001
在主机上写,在从机上可以读取数据
主机挂掉,重启就行,一切如初
从机重启需重设:slaveof 127.0.0.1 6379
5、复制原理
4-1 薪火相传
上一个Slave可以是下一个slave的Master,Slave同样可以接收其他 slaves的连接和同步请求,那么该slave作为了链条中下一个的master, 可以有效减轻master的写压力,去中心化降低风险。
用 slaveof
中途变更转向:会清除之前的数据,重新建立拷贝最新的
风险是一旦某个slave宕机,后面的slave都没法备份
主机挂了,从机还是从机,无法写数据了
4-2 反客为主
当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。
用 slaveof no one 将从机变为主机。
4-3 哨兵模式
反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库
自定义的/root/redis目录下新建sentinel.conf文件,名字绝不能错
配置哨兵
sentinel monitor mymaster 127.0.0.1 6379 1
其中mymaster为监控对象起的服务器名称, 1 为至少有多少个哨兵同意迁移的数量。
启动哨兵
java
/usr/redis/bin/redis-sentinel /root/redis/sentinel.conf
当主机挂掉,从机选举中产生新的主机
(大概10秒左右可以看到哨兵窗口日志,切换了新的主机)
哪个从机会被选举为主机呢?根据优先级别:replica-priority
原主机重启后会变为从机。