背景
笔主曾多次在找工作的时候看到有要求熟悉Redis的原理等,但苦于课内仅学习过MySQL相关的知识,对Redis知之甚少。此次正好借助字节青训营的机会可以对Redis有个初步的了解,并以此记录下学习的笔记。
Redis是什么
Redis是为了解决MySQL中,因为数据量大量增长而带来的读写数据压力问题。在设计Redis的时候提出将数据分为热数据和冷数据两种类型,热数据即经常会被访问到的数据,冷数据则相反。因为使用热数据的频率较高,所以将热数据存储到内存中,即MySQL中;将冷数据存储到Redis中。
Redis的特点&用途
- 数据结构多样性: Redis 支持多种数据结构,包括字符串、哈希表、列表、集合、有序集合、位图、地理空间索引等。这使得开发者可以根据具体应用场景选择合适的数据结构来存储数据。
- 内存存储: Redis 将数据保存在内存中,因此具有非常高的读写性能。它适用于需要快速读写操作的应用,例如缓存、实时计数等。
- 持久化: Redis 支持数据持久化到磁盘,以确保数据在重启后不会丢失。它提供了两种持久化方式:RDB(快照)和AOF(日志追加)。
- 发布订阅: Redis 允许客户端订阅一个或多个频道,以便在特定事件发生时接收通知。这在实现实时消息传递、事件触发等场景中非常有用。
- 事务支持: Redis 支持事务,可以将多个命令打包成一个事务进行原子性执行。这在需要保持数据一致性的操作中很有用。
- 高可用性: Redis 提供了主从复制功能,允许创建多个副本以提高可用性和数据冗余。此外,Sentinel 和 Cluster 是用于在分布式环境中管理多个 Redis 实例的工具。
- 性能优化: Redis 在内部使用了多种技术,如单线程、非阻塞 I/O 等,以优化性能。它还提供了对 Lua 脚本的支持,允许开发者在服务器端执行自定义脚本。
- 地理空间功能: Redis 支持地理空间索引和查询,适用于需要处理地理位置信息的应用,如位置服务。
- 多语言支持: Redis 提供多种编程语言的客户端库,使得开发者可以使用不同的编程语言与 Redis 进行交互。
Redis应用案例
在课程中详细讲解了六个案例,分别是:连续签到、消息通知、计数、排行榜、限流和分布式锁,下面以连续签到为例。
// 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"))
}
}
}
这段代码实现了增加用户连续签到天数的功能
Redis注意事项
尽量避免使用大key
缺点: 读取成本高 容易导致慢查询 主从复制异常、任务阻塞,从而导致无法响应请求
避免慢查询场景
慢查询发生的原因 (1) 批量操作一次性传入过多的k-v值 (2) 使用zset,因为其大部分命令都是O(log(n)) (3) 操作的单个value过大,超过10KB