1. redis 为什么这么快

- 基于内存来存储数据的，所以读写访问速度可以做到特别快
- 单线程的，可以避免多线程上下文切换带来的开销，同时加入了多路 IO 复用
- 内置了优化过的数据类型，性能高

3. 分布式缓存常见的技术选型方案



4. 为什么使用 redis/缓存

- 高性能，频繁访问的数据，访问数据更快
- 高并发，加大 QPS 访问量

5. redis 的应用场景

- 分布式锁
- 限流，通过 redis 加 Lua 脚本实现，令牌桶
- 消息队列
- 延时队列
- 分布式 Session
- 复杂业务场景，通过 bitmap 统计用户活跃量，通过或 soted set 实现排行榜

6. 常见缓存读写分类策略
7. 如何实现分布式锁

set NX key value，del NX key value

8. redis 数据结构

- String
- List
- Set
- Zset
- Hash
- HyperLogLogs
- Bitmap
- GeoSptial

10. String 的应用场景

String 是一种二进制安全的数据结构，可以用来存储任何类型数据，字符串，浮点数，图片（base 64 或地址），序列化

11. String 还是 Hash 存储对象更好

String 性能上比 Hash 节省内存，并且在存储多层嵌套的整个对象通过序列化也很方便，Hash 则是可以单独修改或者添加部分字段信息，如果是经常修改对象中的部分信息，就使用 Hash，否则用String

12. String 的底层实现

C 语言字符串是以\\0 结尾的字符数组，但是 redis 自己编写了 SDC（简单动态字符串）作为底层实现

13. 购物车使用 String 还是 Hash

使用 Hash，用户修改时就只是修改内部的 key 和 value 值即可

14. 如何实现排行榜

使用 Zset 实现

15. Set 的使用场景

存储不能重复的数据，例如网站的 UV 统计，点赞的统计
计算交集并集差集，共同好友
需要随机获取数据中的元素的场景，抽奖，随机点名

16. 使用 Set 实现抽奖系统

添加元素，随机移除并获取其中一个（不重复），随机获取一个元素（可重复）

17. 使用 Bitmap 统计活跃用户

将用户 ID 作为 offset，如果用户活跃过，就将该 bit 位设为 1

18. 使用 HyperLogLog 统计页面 UV

添加一个或多个元素到 HyperLogLog 中，
获取一个或多个 HyperLogLog 的唯一计数

19. [[Redis 持久化机制]]

20. Redis 线程模型

Redis 在 6.0 引入多线程来提供网络请求处理 IO 的性能，Redis 中的事件处理模型基于 Reacotor 模型，对应其中的文件时间处理器，这个是单线程运行的，Redis 利用 IO 多路复用程序来监听来自客户端的大量链接，无需创建多余的线程来监听，降低资源消耗

21. Redis 6.0 之前为什么不使用多线程，6.0 为何应用多线程

为了提高网络 IO 的读写性能，Redis 瓶颈主要在于**内存**和**网络**

22. Redis 后台线程

三个后台线程：
- `close_file`
- `aof_fsync`
- `lazy_free`

23. Rdis 缓存过期时间，如何判断数据是否过期，过期数据删除策略

redis 内存有限，因此要给缓存设置一定的过期时间，防止 OOM，同时可以实现某些需要一定时间后过期的业务，
通过一个过期字典（一个 hash 表）来保存数据过期的时间，过期字典的 key 指向 redis 中的 key，value 是一个 long 类型的整数，存储时间戳

**过期数据删除策略**
- **惰性删除**：只有在数据取出时判断是否过期，对 cpu 友好
- **定期删除**：定期取出一批的 key 删除过期的 key，通过限制删除操作执行时长和频率来减少对 CPU 的影响，对内存友好
---
redis 使用的是定期删除+惰性删除的方式

24. 内存淘汰机制

- **volatile-lru**：从已设置过期时间的数据集中挑选最少使用的进行删除
- **volatile-ttl**：从已设置过期时间的数据集中挑选将要过期的删除
- **volatile-random**：从已设置过期时间的数据集中随机选择数据删除
- **allkeys-lru**：内存不足时，移除最近最少使用的 key
- **allkeys-random**：从数据中随机选择数据淘汰
- **no-eviction**：禁止删除，新写入的操作报错
- **volatile-lfu**：从已设置过期时间的数据集中挑选最不经常使用的数据删除
- **allkeys-lfu**：从键空间中移除最不经常使用的数据

25. 什么是 Rdis 事务

redis 事务将多个命令打包后顺序执行，通过 `MULTI` `EXEC` `DISCARD` `WATCH` 命令实现

26. Redis 事务支持原子性吗，支持持久性吗

不支持，运行错误时也不支持回滚，除了出现错误的命令其他命令都会执行，无法保证持久性

27. 如何解决 Redis 事务缺陷

利用 Lua 脚本来批量执行，一段 Lua 脚本可以看成一条命令，执行过程中不会有其他命令执行，但是出错的命令之后的命令也不会执行

28. Redis 性能优化
	1. 使用批量操作减少网络传输
		一个 redis 命令执行分为以下四部
		- 发送命令
		- 命令排队
		- 命令执行
		- 返回结果
		1 和 4 的耗时为 RTT，就时网络延时，通过批量操作可以减少网络传输次数，减少网络开销  
	1. pipeline
		`MGET`，`HMGET`，`SADD`，原生支持批量操作
	1. 通过pipeline 	
	1. Lua 脚本
30. 大量 key 集中过期问题

- 给 key 设置随机过期时间
- 设置 lazy-free（惰性删除/延迟释放）

31. bigkey 分析及处理

String 类型超过 10kb，复合类型超过 5000 个元素，
使用 redis 的--bigkey 获取，借助开源工具分析，借助公有云的 Redis 分析服务

- 分割 BigKey
- 手动清理
- 采用合适的数据结构（HyperLogLog 统计页面 UV）
- 开启 lazy-free

32. hotkey 危害及处理

频繁访问的 key，
使用--hotkey，使用 `MONITOR`，使用开源项目京东 hotkey，根据业务提前预估，业务代码中记录，借助公有云分析

- 读写分离
- 使用 Redis Cluster
- 二级缓存，将 hotkey 存放一份到 JVM 本地内存中（使用Caffeine）

33. 慢查询命令

设置慢查询时间，通过查询慢查询日志获取

34. 内存碎片

不可用的内存空间
- redis 存储数据时申请的空间大于实际需要空间
- 频繁修改 redis 中的数据

通过 redis 的内存整理功能清理碎片

35. 生产问题
	
	1. 缓存穿透

		请求的 key 时不存在于缓存，也不存在于数据库中，从而大量请求到数据库中查找，
		- 缓存无效 key
		- 布隆过滤器

	  1. 缓存击穿
	  
		请求热点数据，但是热点 key过期，请求大量到数据库，
			- 设置热点key永不过期
			- 热点数据提前预热
			- 请求数据到达数据库前获取互斥锁，保证只有一个请求到达数据库

	 1. 缓存雪崩

		缓存在同一时间大量失效，大量请求到达数据库，或者是服务器宕机
			- 设置不同失效时间，随机失效
			- 缓存永不失效
			- 二级缓存
			- 采用 redis 集群
			- 限流

36. 如何保证缓存数据和数据库一致性

**旁路缓存模式**
更新完 DB 后直接删除cache

37. [[Redis 集群]]


38. 为什么要使用分布式缓存


39. 常见的缓存更新策略


40. 如何实现自动化故障转移


41. 缓存数据量太大怎么办