refactor: rename files to Chinese and organize by category
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>
This commit is contained in:
215
questions/03-缓存/Redis数据结构.md
Normal file
215
questions/03-缓存/Redis数据结构.md
Normal file
@@ -0,0 +1,215 @@
|
||||
# Redis 数据结构
|
||||
|
||||
## 问题
|
||||
|
||||
1. Redis 有哪些数据结构?底层实现是什么?
|
||||
2. String 类型的应用场景?
|
||||
3. Hash 和 String 的区别?
|
||||
4. List 的应用场景?
|
||||
5. Set 和 ZSet 的区别?
|
||||
6. Bitmap、HyperLogLog、GEO 的应用?
|
||||
|
||||
---
|
||||
|
||||
## 标准答案
|
||||
|
||||
### 1. Redis 数据类型
|
||||
|
||||
| 类型 | 底层实现 | 应用场景 |
|
||||
|------|---------|----------|
|
||||
| **String** | SDS | 缓存、计数器、分布式锁 |
|
||||
| **Hash** | 压缩列表/哈希表 | 对象存储、购物车 |
|
||||
| **List** | 双向链表/压缩列表 | 消息队列、最新列表 |
|
||||
| **Set** | 哈希表/整数集合 | 标签、共同关注 |
|
||||
| **ZSet** | 跳表/哈希表 | 排行榜、延时队列 |
|
||||
| **Bitmap** | String(位操作) | 签到、在线用户 |
|
||||
| **HyperLogLog** | String(基数统计) | UV 统计 |
|
||||
| **GEO** | ZSet(经纬度编码) | 附近的人 |
|
||||
|
||||
---
|
||||
|
||||
### 2. String(SDS - Simple Dynamic String)
|
||||
|
||||
**结构**:
|
||||
```c
|
||||
struct sdshdr {
|
||||
int len; // 已使用长度
|
||||
int free; // 剩余空间
|
||||
char buf[]; // 字节数组
|
||||
};
|
||||
```
|
||||
|
||||
**优势**:
|
||||
- O(1) 获取长度
|
||||
- 防止缓冲区溢出
|
||||
- 减少内存分配次数
|
||||
|
||||
**应用**:
|
||||
```bash
|
||||
# 缓存
|
||||
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
|
||||
|
||||
**结构**:
|
||||
```bash
|
||||
HSET user:1001 name "Alice" age 25 email "alice@example.com"
|
||||
HGET user:1001 name
|
||||
HGETALL user:1001
|
||||
```
|
||||
|
||||
**底层**:
|
||||
- 字段少(< 512):压缩列表(ziplist)
|
||||
- 字段多(≥ 512):哈希表(hashtable)
|
||||
|
||||
**应用**:
|
||||
```java
|
||||
// 对象存储(推荐 Hash,而非 String)
|
||||
redisTemplate.opsForHash().putAll("user:1001", Map.of(
|
||||
"name", "Alice",
|
||||
"age", "25"
|
||||
));
|
||||
|
||||
// 购物车
|
||||
redisTemplate.opsForHash().put("cart:1001", "product:1001", "2");
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. List
|
||||
|
||||
**结构**:
|
||||
```bash
|
||||
LPUSH list:msgs "msg1" "msg2" "msg3" # 左侧插入
|
||||
RPOP list:msgs # 右侧弹出
|
||||
```
|
||||
|
||||
**底层**:
|
||||
- 元素少(< 512):压缩列表(ziplist)
|
||||
- 元素多(≥ 512):双向链表(linkedlist)
|
||||
- Redis 3.2+:quicklist(ziplist + linkedlist)
|
||||
|
||||
**应用**:
|
||||
```bash
|
||||
# 消息队列
|
||||
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(无序集合)**:
|
||||
```bash
|
||||
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(有序集合)**:
|
||||
```bash
|
||||
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)
|
||||
|
||||
```bash
|
||||
# 签到
|
||||
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)
|
||||
|
||||
```bash
|
||||
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(地理位置)
|
||||
|
||||
```bash
|
||||
# 添加位置
|
||||
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 监控体系
|
||||
Reference in New Issue
Block a user