Redis - 五种数据类型以及基本操作
Redis 与其他 key - value
缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
五种数据类型
在Redis中有五种数据类型:
String
:字符串Hash
:哈希List
:列表Set
:集合zset(Sorted Set)
:有序集合
一、String(字符串)
- string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。
- string 类型是二进制安全的。redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。
- string 类型是 Redis 最基本的数据类型,
string 类型的值最大能存储 512MB
。
1.基本操作
- 添加 / 修改数据:
set key value
- 获取数据:
get key
- 删除数据:
del key
- 添加 / 修改多个数据:
mset key value key1 value1
- 获取多个数据:
mget key key1
- 追加信息到原始数据后边(不存在时则添加):
append key value
# 示例
> set test "testString"
OK
> get test
"testString"
> del test
(integer) 1
> mset test1 "value1" test2 "value2"
OK
> mget test1 test2
1) "value1"
2) "value2"
> append test1 "111"
9
> mget test1
1) "value1111"
2.增减操作
- 设置数值增加指定范围的值
- 默认每次加1:
incr key
- 每次新增value:
incrby key value
- 默认每次加1:
- 设置数据减少指定范围的值
- 默认每次减1:
decr key
- 每次减少value:
decrby key value
- 默认每次减1:
> incr testCount
(integer) 1
> get testCount
"1"
> incrby testCount 3
(integer) 4
> get testCount
"4"
> decr testCount
(integer) 3
> get testCount
"3"
> decrby testCount 4
(integer) -1
> get testCount
"-1"
3.时效操作
- 设置过期时间:
setex key seconds value
> setex testExpire 10 "value"
OK
> get testExpire
"value"
# 10s后再get,已经失效
> get testExpire
(nil)
二、Hash(哈希)
- Redis hash 是一个键值(key=>value)对集合。
- Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
1.基本操作
- 添加 / 修改数据:
hset key field value
- 获取数据
hget key field
hgetall key
- 删除数据:
hdel key field field1
- 添加 / 修改多个数据:
hmset key field value field1 value1
- 获取多个数据:
hmget key field field1
- 获取表中字段数量:
hlen key
- 获取表中是否存在某个字段:
hexists key field
> hset testHash name ywb
1
> hset testHash age 20
1
> hget testHash name
"ywb"
> hget testHash age
"20"
> hgetall testHash
1) "name"
2) "ywb"
3) "age"
4) "20"
> hset testHash name ywbb
0
> hget testHash name
"ywbb"
> hmset testHash name ywbbb age 22
OK
> hgetall testHash
1) "name"
2) "ywbbb"
3) "age"
4) "22"
> hlen testHash
2
> hexists testHash name
(integer) 1
> hexists testHash sex
(integer) 0
> hmget testHash name
1) "ywbbb"
> hmget testHash name age
1) "ywbbb"
2) "22"
> hmget testHash name age sex
1) "ywbbb"
2) "22"
3) (nil)
2.扩展操作
- 获取hash表中所有的字段key:
hkeys key
- 获取hash表中所有的字段值:
hvals key
- 设置指定字段的数值增加指定范围的值:
hincrby key field increment
hincrbyfloat key field increment
> hkeys testHash
1) "name"
2) "age"
> hvals testHash
1) "ywbbb"
2) "22"
> hincrby testHash age 2
(integer) 24
> hget testHash age
"24"
三、List(列表)
- 数据存储需求:存储多个数据,并对数据进行存储空间的顺序进行区分
- 需要的数据结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
1.基本操作
- 添加 / 修改数据
lpush key value value1
rpush key value value1
- 获取数据
lrange key start end
lindex key index
llen key
- 删除数据
rpop key
lpop key
> lpush testList val1 val2
(integer) 2
> llen testList
(integer) 2
> lindex testList 1
"val1"
> lindex testList 2
(nil)
> lindex testList 0
"val2"
> lrange testList 0 0
1) "val2"
> lrange testList 0 1
1) "val2"
2) "val1"
> lpop testList
"val2"
2.扩展操作
- 在规定时间内获取并移除数据
blpop key1 key2 timeout
brpop key1 key2 timeout
四、Set(集合)
- 新的存储需求:存储大量的数据,在查询方便提供更高的效率
- 需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
- set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值是不允许重复的
1.基本操作
- 添加 / 修改数据:
sadd key member member1
- 获取数据:
smembers key
- 删除数据:
srem key member1
- 获取集合数据总量:
scard key
- 判断集合中是否包含指定数据:
sismember key member
> sadd testSet a b c d
(integer) 4
> srem testSet a
1
> smembers testSet
1) "b"
2) "c"
3) "d"
> scard testSet
3
> sismember testSet a
(integer) 0
> sismember testSet b
(integer) 1
2.扩展操作(随机取数,交、并、差集)
- 随机获取集合中指定数量的数据:
srandmember key count
- 随机获取集合中某个数据并将改数据集移除集合:
spop key
> srandmember testSet 2
1) "b"
2) "c"
> srandmember testSet 2
1) "c"
2) "d"
> srandmember testSet 2
1) "c"
2) "d"
> srandmember testSet 2
1) "b"
2) "d"
> spop testSet
"c"
- 俩个集合的
交、并、差集
sinter key key1
sunion key key1
sdiff key key1
> sadd set1 a b c d
(integer) 4
> sadd set2 a b c e f
(integer) 5
> sinter set1 set2
1) "b"
2) "a"
3) "c"
> sunion set1 set2
1) "b"
2) "a"
3) "c"
4) "e"
5) "d"
6) "f"
# sdiff相当于左连接的差集
> sdiff set1 set2
1) "d"
> sdiff set2 set1
1) "f"
2) "e"
- 俩个集合的
交、并、差集并存储到指定集合
中sinterstore destination key1 key2
sunionstore destination key1 key2
sdiffstore destination key1 key2
> sinterstore setInter set2 set1
3
> smembers setInter
1) "a"
2) "b"
3) "c"
> sunionstore setUnion set2 set1
6
> smembers setUnion
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"
6) "f"
> sdiffstore setDiff set2 set1
2
> smembers setDiff
1) "f"
2) "e"
五、ZSet(Sorted Set 有序集合)
- 在之前的四个类型中都不支持排序的,下来咱们看的sorted_set类型是既支持存储大数据,也支持排序功能
1.基本操作
- 添加数据:
zadd key score member
- 获取数据
zrange key start stop
zrevrange key start stop
- 删除数据:
zrem key member
> zadd zset1 10 setVal1
(integer) 1
> zadd zset1 9 setVal2
(integer) 1
> zadd zset1 10 setVal3
(integer) 1
> zrange zset1 0 -1
1) "setVal2"
2) "setVal1"
3) "setVal3"
> zrange zset1 0 -1 withscores
1) "setVal2"
2) 9.0
3) "setVal1"
4) 10.0
5) "setVal3"
6) 10.0
> zrevrange zset1 0 -1 withscores
1) "setVal3"
2) 10.0
3) "setVal1"
4) 10.0
5) "setVal2"
6) 9.0
> zrem zset1 setVal1
1
2.扩展操作
- 按条件获取数据:
zrangebyscore key min max
zrevrangescore key max min
- 条件删除数据:
zremrangebyrank key start stop
zremrangebyscore key min max
- 获取集合数据总量:
zcard key
zcount key min max
> zrangebyscore test 2 3
1) "val2"
2) "val3"
> zrevrangebyscore test 3 2
1) "val3"
2) "val2"
> zremrangebyrank test 0 1
(integer) 2
> zremrangebyscore test 0 1
0
> zcard test
3
> zcount test 1 3
3
- 集合交、并操作:
zinterstore destination numkeys key
zunionstore destination numkeys key
- (这个指令就不做演示了,可以自己查看文档。跟set有点类似,只不过会把所有交集的和给加起来。然后这里边有个numkeys这个参数是一共几个key进行计算 后边的key就需要几个)
- 获取数据对应的索引:
zrank key member
zrevrank key member
- socre值获取与修改:
zscore key member
zincrby key increment member
缓存穿透、缓存雪崩、缓存击穿的区别和解决方案
1.缓存穿透(缓存中无,DB中也无)
访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。
- 解决方案
- (1)采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
- (2)拦截器,id<=0的直接拦截。
- (3)从cache和db都取不到,可以将key-value写为key-null,设置较短过期时间,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击。
- (4)利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试
- (5)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。
2.缓存击穿(缓存中无,但是DB中有)
一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。
- 解决方案
- (1)设置热点数据永远不过期。
- (2)加互斥锁。
3.缓存雪崩(同一时间缓存大量失效,造成瞬时DB请求量大甚至down机)
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
- 解决方案
- (1)缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
- (2)如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中。
- (3)设置热点数据永远不过期。
- (4)使用互斥锁,但是该方案吞吐量明显下降了。
- (5)双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点:
- 从缓存A读数据,有则直接返回
- A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程。
- 更新线程同时更新缓存A和缓存B。