Organized 50 interview questions into 12 categories: - 01-分布式系统 (9 files): 分布式事务, 分布式锁, 一致性哈希, CAP理论, etc. - 02-数据库 (2 files): MySQL索引优化, MyBatis核心原理 - 03-缓存 (5 files): Redis数据结构, 缓存问题, LRU算法, etc. - 04-消息队列 (1 file): RocketMQ/Kafka - 05-并发编程 (4 files): 线程池, 设计模式, 限流策略, etc. - 06-JVM (1 file): JVM和垃圾回收 - 07-系统设计 (8 files): 秒杀系统, 短链接, IM, Feed流, etc. - 08-算法与数据结构 (4 files): B+树, 红黑树, 跳表, 时间轮 - 09-网络与安全 (3 files): TCP/IP, 加密安全, 性能优化 - 10-中间件 (4 files): Spring Boot, Nacos, Dubbo, Nginx - 11-运维 (4 files): Kubernetes, CI/CD, Docker, 可观测性 - 12-面试技巧 (1 file): 面试技巧和职业规划 All files renamed to Chinese for better accessibility and organized into categorized folders for easier navigation. Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
4.5 KiB
4.5 KiB
Redis 数据结构
问题
- Redis 有哪些数据结构?底层实现是什么?
- String 类型的应用场景?
- Hash 和 String 的区别?
- List 的应用场景?
- Set 和 ZSet 的区别?
- Bitmap、HyperLogLog、GEO 的应用?
标准答案
1. Redis 数据类型
| 类型 | 底层实现 | 应用场景 |
|---|---|---|
| String | SDS | 缓存、计数器、分布式锁 |
| Hash | 压缩列表/哈希表 | 对象存储、购物车 |
| List | 双向链表/压缩列表 | 消息队列、最新列表 |
| Set | 哈希表/整数集合 | 标签、共同关注 |
| ZSet | 跳表/哈希表 | 排行榜、延时队列 |
| Bitmap | String(位操作) | 签到、在线用户 |
| HyperLogLog | String(基数统计) | UV 统计 |
| GEO | ZSet(经纬度编码) | 附近的人 |
2. String(SDS - Simple Dynamic String)
结构:
struct sdshdr {
int len; // 已使用长度
int free; // 剩余空间
char buf[]; // 字节数组
};
优势:
- O(1) 获取长度
- 防止缓冲区溢出
- 减少内存分配次数
应用:
# 缓存
SET user:1001 '{"id":1001,"name":"Alice"}'
GET user:1001
# 计数器
INCR view_count:1001
DECR stock:1001
# 分布式锁
SET lock:order:1001 "uuid" NX PX 30000
3. Hash
结构:
HSET user:1001 name "Alice" age 25 email "alice@example.com"
HGET user:1001 name
HGETALL user:1001
底层:
- 字段少(< 512):压缩列表(ziplist)
- 字段多(≥ 512):哈希表(hashtable)
应用:
// 对象存储(推荐 Hash,而非 String)
redisTemplate.opsForHash().putAll("user:1001", Map.of(
"name", "Alice",
"age", "25"
));
// 购物车
redisTemplate.opsForHash().put("cart:1001", "product:1001", "2");
4. List
结构:
LPUSH list:msgs "msg1" "msg2" "msg3" # 左侧插入
RPOP list:msgs # 右侧弹出
底层:
- 元素少(< 512):压缩列表(ziplist)
- 元素多(≥ 512):双向链表(linkedlist)
- Redis 3.2+:quicklist(ziplist + linkedlist)
应用:
# 消息队列
LPUSH queue:email '{"to":"alice@example.com","subject":"Hello"}'
RPOP queue:email
# 最新列表
LPUSH timeline:1001 "post1" "post2"
LRANGE timeline:1001 0 9 # 最新 10 条
5. Set vs ZSet
Set(无序集合):
SADD tags:article:1001 "java" "redis" "mysql"
SMEMBERS tags:article:1001
SISMEMBER tags:article:1001 "java"
SINTER tags:user:1001 tags:article:1001 # 交集
底层:
- 元素少(< 512):整数集合(intset)
- 元素多(≥ 512):哈希表(hashtable)
ZSet(有序集合):
ZADD rank:score 100 "player1" 200 "player2" 150 "player3"
ZREVRANGE rank:score 0 9 WITHSCORES # Top 10
ZRANK rank:score "player1" # 排名
ZSCORE rank:score "player1" # 分数
底层:
- 元素少(< 128):压缩列表(ziplist)
- 元素多(≥ 128):跳表(skiplist) + 哈希表(hashtable)
6. Bitmap
原理:用 bit 位表示状态(0 或 1)
# 签到
SETBIT sign:2024:02:28:1001 0 1 # 用户 1001 在第 0 天签到
SETBIT sign:2024:02:28:1001 4 1 # 用户 1001 在第 4 天签到
# 统计签到天数
BITCOUNT sign:2024:02:28:1001
# 用户 1001 和 1002 共同签到的天数
BITOP AND result sign:2024:02:28:1001 sign:2024:02:28:1002
BITCOUNT result
7. HyperLogLog
用途:基数统计(不重复元素个数)
优点:内存占用极小(12 KB)
PFADD uv:2024:02:28 user:1001 user:1002 user:1003
PFCOUNT uv:2024:02:28 # 3
# 合并多个 HyperLogLog
PFMERGE uv:2024:02:01-28 uv:2024:02:01 uv:2024:02:02 ...
误差率:< 1%
8. GEO(地理位置)
# 添加位置
GEOADD locations:users 116.404 39.915 "user:1001" # 北京
# 查找附近的人(5 km 内)
GEORADIUS locations:users 116.404 39.915 5 km
# 计算距离
GEODIST locations:users user:1001 user:1002
底层:ZSet(经纬度编码为 score)
9. 阿里 P7 加分项
深度理解:
- 理解 SDS 和 C 字符串的区别
- 理解跳表的实现原理
- 理解压缩列表的优缺点
实战经验:
- 有选择合适数据类型的经验
- 有大数据量下的优化经验
- 有 Redis 内存优化的经验
架构能力:
- 能设计基于 Redis 的业务方案
- 能设计 Redis 集群方案
- 能设计 Redis 监控体系