redis使用
2020-10-17 本文已影响0人
laowangv2
一、支持的数据类型
- String
- Hash
- List
- Set
- Zset
- Bitmap
字符串实现 - Hyperloglog
近似的基数计数 - Geospatial index
二、数据结构设计
1. 对象、类型、编码
- 对象
是redis中key、value实际使用的对象结构:
typedef struct redisObject {
// 类型
unsigned type:4;
// 编码
unsigned encoding:4;
// 指向底层实现数据结构的指针
void *ptr;
// ...
} robj;
-
类型
是数据类型:
type -
编码
是底层数据结构:
encode -
类型与编码的对应关系
type and encode -
底层数据结构
参考《redis设计与实现》
三、应用场景
1. 缓存
缓存一致性
- 更新还是删除缓存?
更新的话无论先更新缓存还是先更新数据库都会有ABBA的问题,缓存总是旧的
(A更新缓存 -> B更新缓存 -> B更新数据库 -> A更新数据库) 或
(A更新数据库 -> B更新数据库 -> B更新缓存 -> A更新缓存 - 先删缓存还是先更新数据库?
先删缓存,有可能删掉之后,另一个线程来访问,miss之后去数据库取到旧值更新缓存,然后才更新数据库
先更新数据库,只是删除缓存之前这一点点时间读到旧值,影响较小
过期时间
可以通过expire等命令设置过期时间,也可以通过setex在set的同时原子地设置过期时间
过期策略
- 定时删除
定时器,到时主动删除。内存友好,cpu不友好。 - 惰性删除
访问时判断是否过期,过期则删除,返回nil。cpu友好,内存不友好。 - 定期删除
定时扫描,删除部分过期的key。折中方案。
redis使用惰性+定期。
淘汰策略
当内存使用达限后,启用淘汰策略。
- noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)
- allkeys-lru:从所有key中使用LRU算法进行淘汰
- volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰
- allkeys-random:从所有key中随机淘汰数据
- volatile-random:从设置了过期时间的key中随机淘汰
- volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的越优先被淘汰
volatile相关的策略没有可以淘汰的键时,处理同noeviction
big key问题
- 删除大key
直接del复杂度O(n),会导致长时间阻塞。解决方案:分批删 or unlink(4.0之后),unlink实现时先把key删掉,空间慢慢释放
缓存过期的注意事项
-
缓存穿透
大量访问不存在的数据,穿透缓存直达数据库,直至数据库不堪负重
解决方法
- 如果数据量不大可以直接增加空值缓存,过期时间小一点以节省内存
- 布隆过滤器
-
缓存雪崩
缓存集中失效或者宕机,大量请求直达数据库
解决方法
- 缓存集群高可用
- 过期时间上增加一个小的随机值
-
缓存击穿
热点数据失效,大量请求打到数据库。和雪崩的区别是,击穿是热点key,雪崩是大量的key,不一定是热点。共同点是大量请求打到数据库。
解决方法
- 热点key永不过期
- 加锁,只有拿到锁的线程去读取db,更新缓存,其他线程阻塞
2. 分布式锁
-
加锁
SET resource_name my_random_value NX PX 30000
- 解锁
# lua
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
-
redission
redis客户端之一,封装了上面的操作,可以像操作java锁一样使用 -
问题
set命令加锁的单点挂掉,并且没来得及同步给slave,那么锁就失效了。为此推出了redlock算法,不过这个算法也不完美,参见redlock神仙打架事件
3. 布隆过滤器
-
用处
用于判断key可能存在和一定不存在,常用于- 解决缓存穿透
- 垃圾邮件过滤
- 大数据量去重
-
原理
一个长数组+多个哈希函数 -
用法
需要Redis版本支持插件,并安装RedisBloom
BF.RESERVE {key} {error_rate} {capacity} [EXPANSION expansion] [NONSCALING]
详见 RedisBloom Bloom Filter Command Documentation
4. 位图
- 命令如下,offset最大512M,2^32
SETBIT key offset value
GETBIT key offset
BITCOUNT key [start] [end]
BITPOS key bit [start] [end] # 返回位图中第一个值为 bit 的二进制位的位置
BITOP operation destkey key [key …] # 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上
-
BITFIELD
参见
- 常见用途
- 活跃用户
- 签到
- 分片技巧
例如,10w位分一片,100001分在100001/100000 = 1第二片,offset = 100001%100000 = 1
四、其他
pipeline和事务
- pipeline
多个命令打包发送,客户端行为,对服务器而言和一个一个收到没有区别。
集群模式下可以使用redission支持pipeline,或者自己开发获取key对应的slot。 - 事务
- A
入队错误,所有都不会执行。执行错误,不会回滚,剩下的继续执行。算满足吧 - C
入队错误,不执行,满足一致性。执行错误,继续执行,满足一致性。服务器停机,要么没有持久化,空白;要么根据持久化恢复,都满足一致性 - I
单线程,天然满足 - D
取决于刷盘策略
- A
参考
Redis的内存淘汰策略
缓存失效的经典问题
5 分钟搞懂布隆过滤器,亿级数据过滤算法你值得拥有!
Redis(5)——亿级数据过滤和布隆过滤器
Redis 应用场景汇总
不懂缓存一致性,易把代码写成Bug