这是我参与「第五届⻘训营 」笔记创作活动的第21天。
这篇笔记记录下redis的对于项目的必要性,以及一些redis的常见使用场景。
redis的使用必要性
随着传统数据库中数据表的愈发复杂,数据量的增大,数据库的读写压力不断增加,查询的效率大大降低。而redis与传统数据库不同的是,redis的数据是存在内存中,所以读写速度很快。
如果将冷热数据分离,让热数据(经常被读取的数据)放置在redis缓存中,冷数据还在传统数据库,读写效率会大大增加。
redis常见使用案例
1. 连续签到
利用redis中key的expire功能,对key设置过期时间,每次进行签到,更新key的过期时间(往后推);如果没有进行签到,删除key,直到下次签到再加回去。
// addContinuesDays 为用户签到续期
func addContinuesDays(ctx context.Context, userID int64) {
key := fmt.Sprintf(continuesCheckKey, userID)
// 1. 连续签到数+1
err := RedisClient.Incr(ctx, key).Err()
if err != nil {
fmt.Errorf("用户[%d]连续签到失败", userID)
} else {
expAt := beginningOfDay().Add(48 * time.Hour)
// 2. 设置签到记录在后天的0点到期
if err := RedisClient.ExpireAt(ctx, key, expAt).Err(); err != nil {
panic(err)
} else {
// 3. 打印用户续签后的连续签到天数
day, err := getUserCheckInDays(ctx, userID)
if err != nil {
panic(err)
}
fmt.Printf("用户[%d]连续签到:%d(天), 过期时间:%s", userID, day, expAt.Format("2006-01-02 15:04:05"))
}
}
}
2. 消息通知
利用redis的list数据结构,作为消息队列。
举例场景为用户订阅文章,文章更新,将更新后的文章推送到ES,用户就可以搜索到最新的文章数据。
3. 计数
利用redis中hash结构,可以储存用户的多项计数需求。
如统计一个博客用户发布的所有文章的各项数据,如文章点赞数、文章被阅读数、收藏量等,这些多次查询会大大减慢系统响应时间,这时候可以利用hash进行结构存储。
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)。
4. 排行榜
使用Sorted Set数据结构进行存储,和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。
举例: 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 SortedSet 结构进行存储。
5. 分布式锁
可以使用redis的setnx实现,利用了两个特性
Redis:是单线程执行命令
setnx.只有未设置过才能执行成功 SetNX Redis SET key value [expiration] NX command.
Ex02 只是体验SetNX的特性,不是高可用的分布式锁实现 该实现存在的问题:
- (1) 业务超时解锁,导致并发问题。业务执行时间超过锁超时时间
- (2) redis主备切换临界点问题。主备切换后,A持有的锁还未同步到新的主节点时,B可在新主节点获取锁,导致并发问题。
- (3) redis集群脑裂,导致出现多个主节点