Redis的实用技巧 | ⻘训营笔记

76 阅读3分钟

这是我参与「第五届⻘训营 」笔记创作活动的第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集群脑裂,导致出现多个主节点