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:
171
questions/07-系统设计/API网关.md
Normal file
171
questions/07-系统设计/API网关.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# API 网关核心原理
|
||||
|
||||
## 问题
|
||||
|
||||
1. 什么是 API 网关?为什么需要 API 网关?
|
||||
2. API 网关的核心功能有哪些?
|
||||
3. Spring Cloud Gateway 和 Zuul 的区别?
|
||||
4. 网关的限流、熔断、降级如何实现?
|
||||
5. 网关的路由和负载均衡策略?
|
||||
|
||||
---
|
||||
|
||||
## 标准答案
|
||||
|
||||
### 1. API 网关的作用
|
||||
|
||||
**核心功能**:
|
||||
1. **路由转发**:将请求转发到后端服务
|
||||
2. **统一鉴权**:集中的认证和授权
|
||||
3. **限流熔断**:保护后端服务
|
||||
4. **日志监控**:统一的日志和监控
|
||||
5. **协议转换**:HTTP → WebSocket、gRPC 等
|
||||
6. **灰度发布**:按规则路由流量
|
||||
|
||||
---
|
||||
|
||||
### 2. Spring Cloud Gateway 核心概念
|
||||
|
||||
**三大组件**:
|
||||
```
|
||||
Route(路由)
|
||||
↓
|
||||
Predicate(断言)
|
||||
↓
|
||||
Filter(过滤器)
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```yaml
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: user-service
|
||||
uri: lb://user-service
|
||||
predicates:
|
||||
- Path=/api/users/**
|
||||
- Header=Authorization, .*
|
||||
filters:
|
||||
- StripPrefix=1
|
||||
- RequestRateLimiter=10 # 限流:10 QPS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Gateway vs Zuul
|
||||
|
||||
| 特性 | Zuul 1.x | Zuul 2.x | Spring Cloud Gateway |
|
||||
|------|----------|----------|---------------------|
|
||||
| **模型** | Servlet 阻塞 | Netty 非阻塞 | Netty 非阻塞 |
|
||||
| **性能** | 低 | 中 | 高 |
|
||||
| **Spring** | 集成好 | 集成一般 | 原生支持 |
|
||||
| **动态路由** | 不支持 | 支持 | 支持 |
|
||||
| **限流** | 需自研 | 需自研 | 内置(Redis) |
|
||||
|
||||
---
|
||||
|
||||
### 4. 核心功能实现
|
||||
|
||||
#### **限流**
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: rate-limiter
|
||||
uri: lb://user-service
|
||||
predicates:
|
||||
- Path=/api/users/**
|
||||
filters:
|
||||
- name: RequestRateLimiter
|
||||
args:
|
||||
redis-rate-limiter.replenishRate: 10 # 每秒填充 10 个令牌
|
||||
redis-rate-limiter.burstCapacity: 20 # 桶容量 20
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### **熔断(Circuit Breaker)**
|
||||
|
||||
```yaml
|
||||
spring:
|
||||
cloud:
|
||||
gateway:
|
||||
routes:
|
||||
- id: circuit-breaker
|
||||
uri: lb://user-service
|
||||
predicates:
|
||||
- Path=/api/users/**
|
||||
filters:
|
||||
- name: CircuitBreaker
|
||||
args:
|
||||
fallbackUri: forward:/fallback
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### **统一鉴权**
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class AuthFilter implements GlobalFilter {
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
|
||||
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
|
||||
|
||||
if (token == null || !validateToken(token)) {
|
||||
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
|
||||
return exchange.getResponse().setComplete();
|
||||
}
|
||||
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 网关高可用
|
||||
|
||||
**部署架构**:
|
||||
```
|
||||
┌─────────────┐
|
||||
│ 负载均衡 │
|
||||
│ (Nginx) │
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌───────────────┼───────────────┐
|
||||
│ │ │
|
||||
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
||||
│Gateway 1│ │Gateway 2│ │Gateway 3│
|
||||
└────┬────┘ └────┬────┘ └────┬────┘
|
||||
│ │ │
|
||||
└──────────────┼──────────────┘
|
||||
│
|
||||
┌──────────────┼──────────────┐
|
||||
│ │ │
|
||||
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
||||
│Service A│ │Service B│ │Service C│
|
||||
└─────────┘ └─────────┘ └─────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 阿里 P7 加分项
|
||||
|
||||
**深度理解**:
|
||||
- 理解 WebFlux 的响应式编程模型
|
||||
- 理解 Netty 的事件循环
|
||||
- 理解限流算法(令牌桶、漏桶)
|
||||
|
||||
**实战经验**:
|
||||
- 有网关性能调优的经验
|
||||
- 有网关灰度发布的经验
|
||||
- 有网关监控和故障排查的经验
|
||||
|
||||
**架构能力**:
|
||||
- 能设计高可用网关架构
|
||||
- 能设计网关的监控体系
|
||||
- 能设计网关的动态路由方案
|
||||
379
questions/07-系统设计/LBS附近的人设计.md
Normal file
379
questions/07-系统设计/LBS附近的人设计.md
Normal file
@@ -0,0 +1,379 @@
|
||||
# LBS 附近的人系统设计
|
||||
|
||||
## 需求分析和数据量评估
|
||||
|
||||
### 需求分析
|
||||
- **核心功能**:位置搜索、附近的人、距离计算、实时更新
|
||||
- **业务场景**:社交软件、外卖服务、打车应用
|
||||
- **QPS评估**:日查询10亿次,峰值QPS 5万+
|
||||
- **数据规模**:用户1亿+,日均位置更新1000万+
|
||||
|
||||
### 数据量评估
|
||||
- **用户位置表**:1亿条,实时更新频率高
|
||||
- **位置历史表**:100亿+条,存储轨迹信息
|
||||
- **地理索引表**:全球空间索引,数据量大
|
||||
- **社交关系表**:10亿+条,好友关系数据
|
||||
|
||||
## 核心技术难点
|
||||
|
||||
### 1. 海量数据处理
|
||||
- 亿级用户位置数据存储
|
||||
- 实时数据写入性能要求
|
||||
- 空间索引构建和维护
|
||||
|
||||
### 2. 实时性要求
|
||||
- 位置信息实时更新
|
||||
- 查询响应毫秒级
|
||||
- 数据一致性问题
|
||||
|
||||
### 3. 距离计算优化
|
||||
- 快速计算两点间距离
|
||||
- 批量距离计算优化
|
||||
- 空间索引查询优化
|
||||
|
||||
### 4. 隐私保护
|
||||
- 用户位置隐私
|
||||
- 数据脱敏处理
|
||||
- 访问权限控制
|
||||
|
||||
## 系统架构设计
|
||||
|
||||
### 总体架构
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 移动端APP │ │ Web管理后台 │ │ 第三方API │
|
||||
│ (iOS/Android)│ │ (PC) │ │ (SDK) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ API网关 │ │ 负载均衡 │ │ CDN加速 │
|
||||
│ (Gateway) │ │ (Nginx) │ │ (Edge) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 位置服务 │ │ 搜索服务 │ │ 计算服务 │
|
||||
│ (微服务) │ │ (微服务) │ │ (微服务) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└─────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Redis集群 │ │ 数据库集群 │ │ 消息队列 │
|
||||
│ (缓存+pub/sub)│ │ (PostGIS) │ │ (Kafka/RabbitMQ)│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 地理计算 │ │ 数据仓库 │ │ 地图渲染 │
|
||||
│ (Geospatial) │ │ (ClickHouse) │ │ (Mapbox) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### 关键组件
|
||||
|
||||
#### 1. 流量层
|
||||
- **API网关**:请求路由、限流、认证
|
||||
- **负载均衡**:Nginx L7负载均衡
|
||||
- **CDN加速**:静态资源缓存
|
||||
|
||||
#### 2. 服务层
|
||||
- **位置服务**:位置更新、订阅管理
|
||||
- **搜索服务**:附近的人查询
|
||||
- **计算服务**:距离计算、路线规划
|
||||
- **社交服务**:好友关系管理
|
||||
|
||||
#### 3. 存储层
|
||||
- **Redis集群**:位置缓存、订阅频道
|
||||
- **PostgreSQL**:空间数据存储
|
||||
- **ClickHouse**:地理位置分析
|
||||
- **MongoDB**:轨迹数据存储
|
||||
|
||||
#### 4. 分析层
|
||||
- **数据仓库**:离线数据分析
|
||||
- **实时计算**:Flink/Kafka Streams
|
||||
- **地图服务**:地图渲染和展示
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 用户位置表
|
||||
```sql
|
||||
CREATE TABLE `user_location` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`latitude` decimal(10,8) NOT NULL COMMENT '纬度',
|
||||
`longitude` decimal(11,8) NOT NULL COMMENT '经度',
|
||||
`accuracy` decimal(10,2) DEFAULT NULL COMMENT '定位精度(米)',
|
||||
`device_type` varchar(20) DEFAULT NULL COMMENT '设备类型',
|
||||
`app_version` varchar(50) DEFAULT NULL COMMENT '应用版本',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`expire_at` timestamp NOT NULL COMMENT '过期时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_id` (`user_id`),
|
||||
KEY `idx_location` (`latitude`, `longitude`),
|
||||
KEY `idx_expire_at` (`expire_at`),
|
||||
SPATIAL KEY `idx_spatial` (`latitude`, `longitude`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 位置历史表
|
||||
```sql
|
||||
CREATE TABLE `location_history` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`latitude` decimal(10,8) NOT NULL COMMENT '纬度',
|
||||
`longitude` decimal(11,8) NOT NULL COMMENT '经度',
|
||||
`accuracy` decimal(10,2) DEFAULT NULL COMMENT '定位精度(米)',
|
||||
`timestamp` datetime NOT NULL COMMENT '时间戳',
|
||||
`device_type` varchar(20) DEFAULT NULL COMMENT '设备类型',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_timestamp` (`user_id`, `timestamp`),
|
||||
KEY `idx_location` (`latitude`, `longitude`),
|
||||
SPATIAL KEY `idx_spatial` (`latitude`, `longitude`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 地理索引表
|
||||
```sql
|
||||
CREATE TABLE `geo_index` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`grid_id` varchar(20) NOT NULL COMMENT '网格ID',
|
||||
`min_lat` decimal(10,8) NOT NULL COMMENT '最小纬度',
|
||||
`max_lat` decimal(10,8) NOT NULL COMMENT '最大纬度',
|
||||
`min_lng` decimal(11,8) NOT NULL COMMENT '最小经度',
|
||||
`max_lng` decimal(11,8) NOT NULL COMMENT '最大经度',
|
||||
`user_count` int NOT NULL DEFAULT 0 COMMENT '用户数量',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_grid_id` (`grid_id`),
|
||||
KEY `idx_bounds` (`min_lat`, `max_lat`, `min_lng`, `max_lng`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 好友关系表
|
||||
```sql
|
||||
CREATE TABLE `user_friends` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`friend_id` bigint NOT NULL COMMENT '好友ID',
|
||||
`distance` decimal(10,2) DEFAULT NULL COMMENT '距离(公里)',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_friend` (`user_id`, `friend_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_friend_id` (`friend_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### Redis缓存设计
|
||||
```typescript
|
||||
// 用户位置缓存
|
||||
const USER_LOCATION_PREFIX = 'location:';
|
||||
const USER_LOCATION_TTL = 60; // 1分钟
|
||||
|
||||
// 地理网格缓存
|
||||
const GRID_PREFIX = 'grid:';
|
||||
const GRID_TTL = 300; // 5分钟
|
||||
|
||||
// 用户订阅缓存
|
||||
const SUBSCRIPTION_PREFIX = 'subscription:';
|
||||
const SUBSCRIPTION_TTL = 3600; // 1小时
|
||||
|
||||
// 距离计算缓存
|
||||
const DISTANCE_PREFIX = 'distance:';
|
||||
const DISTANCE_TTL = 60; // 1分钟
|
||||
```
|
||||
|
||||
### 缓存策略
|
||||
1. **多级缓存**:
|
||||
- 本地缓存:Caffeine
|
||||
- 分布式缓存:Redis Cluster
|
||||
- CDN缓存:静态资源
|
||||
|
||||
2. **缓存更新策略**:
|
||||
- Write Behind:异步更新
|
||||
- Refresh Ahead:预加载热点数据
|
||||
- Cache Invalidation:定时失效
|
||||
|
||||
3. **空间索引缓存**:
|
||||
- 网格索引预加载
|
||||
- 热点区域缓存
|
||||
- 分层缓存策略
|
||||
|
||||
### GeoHash实现
|
||||
```python
|
||||
import math
|
||||
|
||||
def geohash_encode(latitude, longitude, precision=12):
|
||||
# 地球半径(米)
|
||||
earth_radius = 6371000
|
||||
|
||||
# GeoHash字符集
|
||||
chars = "0123456789bcdefghjkmnpqrstuvwxyz"
|
||||
|
||||
# 计算精度对应的网格大小
|
||||
grid_size = 5e6 / (2 ** (precision / 2))
|
||||
|
||||
# 计算经纬度范围
|
||||
lat_min = -90
|
||||
lat_max = 90
|
||||
lng_min = -180
|
||||
lng_max = 180
|
||||
|
||||
geo_hash = []
|
||||
for i in range(precision):
|
||||
# 纬度二进制
|
||||
mid_lat = (lat_min + lat_max) / 2
|
||||
if latitude >= mid_lat:
|
||||
lat_min = mid_lat
|
||||
lat_bit = 1
|
||||
else:
|
||||
lat_max = mid_lat
|
||||
lat_bit = 0
|
||||
|
||||
# 经度二进制
|
||||
mid_lng = (lng_min + lng_max) / 2
|
||||
if longitude >= mid_lng:
|
||||
lng_min = mid_lng
|
||||
lng_bit = 1
|
||||
else:
|
||||
lng_max = mid_lng
|
||||
lng_bit = 0
|
||||
|
||||
# 组合成字符索引
|
||||
index = lat_bit * 2 + lng_bit
|
||||
geo_hash.append(chars[index])
|
||||
|
||||
return ''.join(geo_hash)
|
||||
|
||||
def calculate_distance(lat1, lng1, lat2, lng2):
|
||||
# Haversine公式计算距离
|
||||
R = 6371000 # 地球半径(米)
|
||||
|
||||
dLat = math.radians(lat2 - lat1)
|
||||
dLng = math.radians(lng2 - lng1)
|
||||
|
||||
a = (math.sin(dLat/2) * math.sin(dLat/2) +
|
||||
math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
|
||||
math.sin(dLng/2) * math.sin(dLng/2))
|
||||
|
||||
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
|
||||
distance = R * c
|
||||
|
||||
return distance
|
||||
```
|
||||
|
||||
## 扩展性考虑
|
||||
|
||||
### 1. 水平扩展
|
||||
- **无状态服务**:位置服务和搜索服务无状态化
|
||||
- **数据分片**:按用户ID分片
|
||||
- **读写分离**:主库写入,从库读取
|
||||
|
||||
### 2. 垂直扩展
|
||||
- **服务拆分**:位置更新服务、查询服务、计算服务
|
||||
- **数据分层**:热数据、温数据、冷数据
|
||||
- **多级缓存**:本地、Redis、CDN
|
||||
|
||||
### 3. 全球化部署
|
||||
- **地域化服务**:按地域部署服务
|
||||
- **数据同步**:跨地域数据同步
|
||||
- **灾备切换**:多机房容灾
|
||||
|
||||
### 4. 性能优化
|
||||
- **空间索引**:R-Tree、Quadtree
|
||||
- **批量处理**:批量查询优化
|
||||
- **异步处理**:消息队列异步化
|
||||
|
||||
## 实际项目经验
|
||||
|
||||
### 1. 技术栈选择
|
||||
- **前端**:React Native + Flutter
|
||||
- **后端**:Spring Boot + Node.js
|
||||
- **数据库**:PostgreSQL + Redis
|
||||
- **缓存**:Redis Cluster
|
||||
- **消息队列**:Kafka
|
||||
- **监控**:Prometheus + Grafana
|
||||
|
||||
### 2. 性能优化
|
||||
- **空间索引优化**:GeoHash、R-Tree
|
||||
- **缓存优化**:多级缓存策略
|
||||
- **数据库优化**:分库分表、索引优化
|
||||
- **网络优化**:HTTP/2、Keep-Alive
|
||||
|
||||
### 3. 运维部署
|
||||
- **容器化**:Docker + Kubernetes
|
||||
- **CI/CD**:Jenkins + GitLab
|
||||
- **监控告警**:ELK Stack + AlertManager
|
||||
- **压测**:JMeter + Locust
|
||||
|
||||
### 4. 安全设计
|
||||
- **位置隐私**:数据脱敏、权限控制
|
||||
- **数据加密**:传输加密、存储加密
|
||||
- **访问控制**:API鉴权、黑白名单
|
||||
|
||||
## 阿里P7加分项
|
||||
|
||||
### 1. 架构设计能力
|
||||
- **高可用架构**:99.99%可用性
|
||||
- **高性能架构**:支持亿级查询
|
||||
- **全球化架构**:全球多机房部署
|
||||
|
||||
### 2. 技术深度
|
||||
- **空间算法**:GeoHash、R-Tree算法
|
||||
- **分布式系统**:分布式缓存、分布式计算
|
||||
- **数据库优化**:PostGIS优化、空间索引
|
||||
|
||||
### 3. 业务理解
|
||||
- **社交业务**:理解社交应用场景
|
||||
- **位置服务**:掌握LBS业务模式
|
||||
- **用户行为**:分析用户移动模式
|
||||
|
||||
### 4. 团队管理
|
||||
- **技术团队**:带领20人+团队
|
||||
- **项目管控**:管理千万级用户项目
|
||||
- **技术方案**:主导技术架构设计
|
||||
|
||||
### 5. 前沿技术
|
||||
- **边缘计算**:边缘节点处理
|
||||
- **AI应用**:轨迹预测、位置推荐
|
||||
- **Serverless**:函数化服务
|
||||
|
||||
## 面试常见问题
|
||||
|
||||
### 1. 如何高效查询附近的人?
|
||||
- **空间索引**:GeoHash、R-Tree
|
||||
- **网格划分**:地理网格索引
|
||||
- **缓存策略**:多级缓存优化
|
||||
|
||||
### 2. 如何保证位置数据实时性?
|
||||
- **推送机制**:WebSocket实时推送
|
||||
- **订阅模式**:用户订阅位置变化
|
||||
- **数据过期**:定时清理过期数据
|
||||
|
||||
### 3. 如何处理海量位置数据?
|
||||
- **分库分表**:按用户ID分片
|
||||
- **数据归档**:冷热数据分离
|
||||
- **压缩存储**:轨迹数据压缩
|
||||
|
||||
### 4. 如何保护用户隐私?
|
||||
- **数据脱敏**:位置信息模糊化
|
||||
- **权限控制**:基于关系的访问控制
|
||||
- **加密存储**:敏感信息加密
|
||||
|
||||
### 5. 如何优化距离计算?
|
||||
- **近似计算**:GeoHash过滤
|
||||
- **批量计算**:向量运算优化
|
||||
- **缓存机制**:距离结果缓存
|
||||
745
questions/07-系统设计/RPC框架.md
Normal file
745
questions/07-系统设计/RPC框架.md
Normal file
@@ -0,0 +1,745 @@
|
||||
# RPC 框架
|
||||
|
||||
## 问题
|
||||
|
||||
**背景**:在分布式系统中,服务间通信需要高效、可靠的远程调用机制。RPC(Remote Procedure Call)框架屏蔽了网络通信的复杂性,使远程调用像本地调用一样简单。
|
||||
|
||||
**问题**:
|
||||
1. 什么是 RPC?它和 HTTP REST 有什么区别?
|
||||
2. Dubbo 的核心架构和工作原理是什么?
|
||||
3. gRPC 的优势是什么?它如何实现高性能?
|
||||
4. 请描述 Dubbo 的负载均衡策略
|
||||
5. Dubbo 的服务注册与发现机制是怎样的?
|
||||
6. RPC 框架如何实现序列化?常见的序列化协议有哪些?
|
||||
7. 在实际项目中如何选择 RPC 框架?
|
||||
8. RPC 框架如何处理超时、重试和熔断?
|
||||
|
||||
---
|
||||
|
||||
## 标准答案
|
||||
|
||||
### 1. RPC vs HTTP REST
|
||||
|
||||
#### **RPC 定义**:
|
||||
远程过程调用(Remote Procedure Call)是一种计算机通信协议,允许运行在一台计算机的程序调用另一台计算机的子程序,而开发者无需额外编码这种交互。
|
||||
|
||||
#### **对比表**:
|
||||
|
||||
| 特性 | RPC (Dubbo/gRPC) | HTTP REST |
|
||||
|------|------------------|-----------|
|
||||
| 传输协议 | TCP (长连接) | HTTP/1.1 (短连接) / HTTP/2 |
|
||||
| 序列化 | 二进制(Hessian/Protobuf) | JSON/XML |
|
||||
| 性能 | 高(紧凑、高效) | 中(文本解析开销) |
|
||||
| 易用性 | 需要接口定义 | 无需定义,浏览器直接访问 |
|
||||
| 耦合度 | 强耦合(需要 stub 代码) | 松耦合 |
|
||||
| 流量管理 | 需要网关 | 天然支持(Nginx等) |
|
||||
| 适用场景 | 内部微服务通信 | 对外 API、跨语言调用 |
|
||||
|
||||
#### **代码对比**:
|
||||
|
||||
**RPC 调用(Dubbo)**:
|
||||
```java
|
||||
// 服务提供者
|
||||
public interface UserService {
|
||||
User getUserById(Long id);
|
||||
}
|
||||
|
||||
// 服务消费者
|
||||
// 像调用本地方法一样调用远程服务
|
||||
@Reference
|
||||
private UserService userService;
|
||||
|
||||
public void process() {
|
||||
User user = userService.getUserById(1L);
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP REST 调用**:
|
||||
```java
|
||||
// 服务提供者
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
public class UserController {
|
||||
@GetMapping("/{id}")
|
||||
public User getUserById(@PathVariable Long id) {
|
||||
return userService.getById(id);
|
||||
}
|
||||
}
|
||||
|
||||
// 服务消费者
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
public void process() {
|
||||
String url = "http://user-service/api/users/1";
|
||||
User user = restTemplate.getForObject(url, User.class);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Dubbo 核心架构
|
||||
|
||||
#### **架构图**:
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Registry │
|
||||
│ (注册中心) │
|
||||
│ Zookeeper/Nacos│
|
||||
└─────────────────┘
|
||||
▲ ▲
|
||||
│ │
|
||||
Register │ │ Subscribe
|
||||
(注册) │ │ (订阅)
|
||||
│ │
|
||||
┌──────────────────────┴───┴──────────────────────┐
|
||||
│ │
|
||||
│ Provider Consumer │
|
||||
│ ┌──────────┐ ┌──────────┐│
|
||||
│ │Protocol │ │Protocol ││
|
||||
│ │ (协议层) │ │ (协议层) ││
|
||||
│ └──────────┘ └──────────┘│
|
||||
│ ┌──────────┐ ┌──────────┐│
|
||||
│ │ Cluster │◄──────────────────►│ Cluster ││
|
||||
│ │ (集群层) │ Directory │ (集群层) ││
|
||||
│ └──────────┘ └──────────┘│
|
||||
│ ┌──────────┐ ┌──────────┐│
|
||||
│ │ Proxy │ │ Proxy ││
|
||||
│ │ (代理层) │ │ (代理层) ││
|
||||
│ └──────────┘ └──────────┘│
|
||||
│ ┌──────────┐ ┌──────────┐│
|
||||
│ │ Service │ │ Service ││
|
||||
│ │ (服务层) │ │ (服务层) ││
|
||||
│ └──────────┘ └──────────┘│
|
||||
└─────────────────────────────────────────────┘
|
||||
│
|
||||
│ Invoke
|
||||
│ (调用)
|
||||
▼
|
||||
┌──────────┐
|
||||
│ Channel │
|
||||
│ (网络层) │
|
||||
└──────────┘
|
||||
│
|
||||
│ Exchange
|
||||
│ (数据交换)
|
||||
▼
|
||||
┌──────────┐
|
||||
│ Serialize│
|
||||
│ (序列化) │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
#### **核心角色**:
|
||||
|
||||
**1. Container(服务容器)**
|
||||
- 负责启动、加载和运行服务提供者
|
||||
- 通常是 Spring 容器
|
||||
|
||||
**2. Provider(服务提供者)**
|
||||
- 暴露服务的应用
|
||||
- 启动时向注册中心注册服务
|
||||
|
||||
**3. Consumer(服务消费者)**
|
||||
- 调用远程服务的应用
|
||||
- 启动时向注册中心订阅服务
|
||||
|
||||
**4. Registry(注册中心)**
|
||||
- 服务注册与发现
|
||||
- 常见实现:Zookeeper、Nacos、Redis
|
||||
|
||||
**5. Monitor(监控中心)**
|
||||
- 统计服务调用次数和调用时间
|
||||
- 常见实现:Dubbo Admin、Prometheus
|
||||
|
||||
#### **代码示例**:
|
||||
|
||||
**服务提供者配置**:
|
||||
```xml
|
||||
<!-- provider.xml -->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://dubbo.apache.org/schema/dubbo
|
||||
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
|
||||
|
||||
<!-- 提供方应用信息 -->
|
||||
<dubbo:application name="user-provider"/>
|
||||
|
||||
<!-- 使用 Zookeeper 注册中心 -->
|
||||
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
|
||||
|
||||
<!-- 使用 dubbo 协议暴露服务 -->
|
||||
<dubbo:protocol name="dubbo" port="20880"/>
|
||||
|
||||
<!-- 声明需要暴露的服务接口 -->
|
||||
<dubbo:service interface="com.example.UserService"
|
||||
ref="userService" version="1.0.0"/>
|
||||
|
||||
<!-- 服务实现 -->
|
||||
<bean id="userService" class="com.example.UserServiceImpl"/>
|
||||
</beans>
|
||||
```
|
||||
|
||||
**服务消费者配置**:
|
||||
```xml
|
||||
<!-- consumer.xml -->
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://dubbo.apache.org/schema/dubbo
|
||||
http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
|
||||
|
||||
<!-- 消费方应用信息 -->
|
||||
<dubbo:application name="user-consumer"/>
|
||||
|
||||
<!-- 使用 Zookeeper 注册中心 -->
|
||||
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
|
||||
|
||||
<!-- 生成远程服务代理 -->
|
||||
<dubbo:reference id="userService"
|
||||
interface="com.example.UserService"
|
||||
version="1.0.0"
|
||||
timeout="3000"
|
||||
retries="2"/>
|
||||
</beans>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. gRPC 高性能原理
|
||||
|
||||
#### **核心特性**:
|
||||
|
||||
**1. HTTP/2 多路复用**
|
||||
```
|
||||
HTTP/1.1:
|
||||
Request 1 ──► TCP Connection 1 ──► Response 1
|
||||
Request 2 ──► TCP Connection 2 ──► Response 2
|
||||
Request 3 ──► TCP Connection 3 ──► Response 3
|
||||
|
||||
HTTP/2:
|
||||
Request 1 ──┐
|
||||
Request 2 ──┼─► TCP Connection ──► Response 1
|
||||
Request 3 ──┘ Response 2
|
||||
Response 3
|
||||
```
|
||||
|
||||
**2. Protobuf 二进制序列化**
|
||||
```protobuf
|
||||
// user.proto
|
||||
syntax = "proto3";
|
||||
|
||||
package user;
|
||||
|
||||
service UserService {
|
||||
rpc GetUser(GetUserRequest) returns (User);
|
||||
rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
|
||||
}
|
||||
|
||||
message User {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
string email = 3;
|
||||
}
|
||||
|
||||
message GetUserRequest {
|
||||
int64 id = 1;
|
||||
}
|
||||
|
||||
message ListUsersRequest {
|
||||
int32 page = 1;
|
||||
int32 size = 2;
|
||||
}
|
||||
|
||||
message ListUsersResponse {
|
||||
repeated User users = 1;
|
||||
int32 total = 2;
|
||||
}
|
||||
```
|
||||
|
||||
**性能对比**:
|
||||
```
|
||||
JSON: {"id":1,"name":"Alice","email":"alice@example.com"}
|
||||
└─ 56 字节
|
||||
|
||||
Protobuf: [0x08 0x01 0x12 0x05 0x41 0x6C 0x69 0x63 0x65 ...]
|
||||
└─ ~20 字节(压缩 60%+)
|
||||
```
|
||||
|
||||
**3. 流式传输**
|
||||
```python
|
||||
# 服务端流式 RPC
|
||||
async def ListUsers(request, context):
|
||||
for user in database.iter_users():
|
||||
yield user # 持续发送,无需等待全部数据
|
||||
|
||||
# 客户端流式 RPC
|
||||
async def UploadUsers(request_iterator, context):
|
||||
for user_request in request_iterator:
|
||||
database.save(user_request.user)
|
||||
return UploadStatus(success=True)
|
||||
|
||||
# 双向流式 RPC
|
||||
async def Chat(request_iterator, context):
|
||||
async for msg in request_iterator:
|
||||
response = process_message(msg)
|
||||
yield response
|
||||
```
|
||||
|
||||
#### **代码示例(Python)**:
|
||||
|
||||
**服务端**:
|
||||
```python
|
||||
import grpc
|
||||
from concurrent import futures
|
||||
import user_pb2
|
||||
import user_pb2_grpc
|
||||
|
||||
class UserServiceImpl(user_pb2_grpc.UserServiceServicer):
|
||||
def GetUser(self, request, context):
|
||||
# 查询数据库
|
||||
user = db.query(User).filter_by(id=request.id).first()
|
||||
return user_pb2.User(
|
||||
id=user.id,
|
||||
name=user.name,
|
||||
email=user.email
|
||||
)
|
||||
|
||||
def ListUsers(self, request, context):
|
||||
# 服务端流式响应
|
||||
users = db.query(User).limit(request.size).offset(request.page * request.size)
|
||||
for user in users:
|
||||
yield user_pb2.User(id=user.id, name=user.name, email=user.email)
|
||||
|
||||
def serve():
|
||||
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
|
||||
user_pb2_grpc.add_UserServiceServicer_to_server(UserServiceImpl(), server)
|
||||
server.add_insecure_port('[::]:50051')
|
||||
server.start()
|
||||
server.wait_for_termination()
|
||||
|
||||
if __name__ == '__main__':
|
||||
serve()
|
||||
```
|
||||
|
||||
**客户端**:
|
||||
```python
|
||||
import grpc
|
||||
import user_pb2
|
||||
import user_pb2_grpc
|
||||
|
||||
def run():
|
||||
with grpc.insecure_channel('localhost:50051') as channel:
|
||||
stub = user_pb2_grpc.UserServiceStub(channel)
|
||||
|
||||
# 简单 RPC
|
||||
response = stub.GetUser(user_pb2.GetUserRequest(id=1))
|
||||
print(f"User: {response.name}")
|
||||
|
||||
# 服务端流式 RPC
|
||||
for user in stub.ListUsers(user_pb2.ListUsersRequest(page=0, size=10)):
|
||||
print(f"User: {user.name}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Dubbo 负载均衡策略
|
||||
|
||||
#### **策略对比**:
|
||||
|
||||
| 策略 | 说明 | 适用场景 |
|
||||
|------|------|----------|
|
||||
| Random(随机) | 随机选择 provider | 性能相近的实例 |
|
||||
| RoundRobin(轮询) | 按权重轮询 | 性能有差异的实例 |
|
||||
| LeastActive(最少活跃) | 优先调用活跃数少的 | 性能差异大 |
|
||||
| ConsistentHash(一致性哈希) | 相同参数路由到同一 provider | 有状态服务 |
|
||||
| ShortestResponse(最短响应) | 优先选择响应时间短的 | 对延迟敏感 |
|
||||
|
||||
#### **代码示例**:
|
||||
|
||||
**配置负载均衡**:
|
||||
```xml
|
||||
<dubbo:reference id="userService"
|
||||
interface="com.example.UserService"
|
||||
loadbalance="roundRobin" <!-- 轮询 -->
|
||||
timeout="3000"/>
|
||||
```
|
||||
|
||||
**自定义负载均衡**:
|
||||
```java
|
||||
public class CustomLoadBalance extends AbstractLoadBalance {
|
||||
@Override
|
||||
protected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {
|
||||
// 自定义负载均衡逻辑
|
||||
// 例如:基于地理位置的负载均衡
|
||||
String location = getUserLocation();
|
||||
return invokers.stream()
|
||||
.filter(invoker -> invoker.getUrl().getParameter("location").equals(location))
|
||||
.findFirst()
|
||||
.orElse(invokers.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
// 注册自定义负载均衡
|
||||
SPI.register(CustomLoadBalance.class);
|
||||
```
|
||||
|
||||
#### **LeastActive 原理**:
|
||||
```
|
||||
Provider A: Active = 5 (正在处理 5 个请求)
|
||||
Provider B: Active = 2 (正在处理 2 个请求)
|
||||
Provider C: Active = 8 (正在处理 8 个请求)
|
||||
|
||||
选择顺序:B > A > C
|
||||
原因:B 的负载最轻,应该优先分配
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 服务注册与发现
|
||||
|
||||
#### **Zookeeper 实现**:
|
||||
|
||||
**目录结构**:
|
||||
```
|
||||
/dubbo
|
||||
└─ com.example.UserService
|
||||
├─ providers
|
||||
│ ├─ dubbo://192.168.1.10:20880/...?version=1.0.0
|
||||
│ ├─ dubbo://192.168.1.11:20880/...?version=1.0.0
|
||||
│ └─ dubbo://192.168.1.12:20880/...?version=1.0.0
|
||||
└─ consumers
|
||||
└─ consumer://192.168.1.20/...?version=1.0.0
|
||||
```
|
||||
|
||||
**工作流程**:
|
||||
```
|
||||
1. Provider 启动
|
||||
↓
|
||||
2. 创建临时节点 /dubbo/.../providers/dubbo://ip:port/...
|
||||
↓
|
||||
3. Consumer 启动
|
||||
↓
|
||||
4. 订阅 /dubbo/.../providers/ 节点
|
||||
↓
|
||||
5. 获取 provider 列表
|
||||
↓
|
||||
6. 监听 provider 变化(新增/下线)
|
||||
↓
|
||||
7. 动态更新本地缓存
|
||||
```
|
||||
|
||||
#### **代码示例(Zookeeper)**:
|
||||
```java
|
||||
// 注册中心配置
|
||||
RegistryConfig registry = new RegistryConfig();
|
||||
registry.setAddress("zookeeper://127.0.0.1:2181");
|
||||
registry.setTimeout(5000);
|
||||
|
||||
// 或者使用 Nacos
|
||||
RegistryConfig registry = new RegistryConfig();
|
||||
registry.setAddress("nacos://127.0.0.1:8848");
|
||||
```
|
||||
|
||||
#### **服务健康检查**:
|
||||
```java
|
||||
// Dubbo 心跳机制
|
||||
public class HeartbeatTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
// 每隔 5 秒发送心跳
|
||||
channel.send heartbeat();
|
||||
}
|
||||
}
|
||||
|
||||
// Zookeeper 临时节点特性
|
||||
// - Provider 断开连接后,临时节点自动删除
|
||||
// - Consumer 立即感知到下线,剔除该 provider
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 序列化协议对比
|
||||
|
||||
#### **常见序列化协议**:
|
||||
|
||||
| 协议 | 优点 | 缺点 | 适用场景 |
|
||||
|------|------|------|----------|
|
||||
| Hessian | 简单、高效 | 不支持跨语言 | Dubbo 默认 |
|
||||
| Protobuf | 高性能、跨语言 | 需要定义 .proto | gRPC |
|
||||
| JSON | 易读、跨语言 | 冗长、解析慢 | HTTP REST |
|
||||
| Kryo | 高性能 | 不支持跨语言 | Dubbo |
|
||||
| Avro | 动态 schema、跨语言 | 性能略低 | Hadoop 生态 |
|
||||
| FST | 高性能、兼容 JDK | 不支持跨语言 | Dubbo |
|
||||
|
||||
#### **性能对比**:
|
||||
```
|
||||
序列化性能排名(从快到慢):
|
||||
Kryo > FST > Protobuf > Hessian > Avro > JSON
|
||||
|
||||
序列化后大小排名(从小到大):
|
||||
Protobuf ≈ Kryo < Hessian < Avro < JSON
|
||||
```
|
||||
|
||||
#### **代码示例(Protobuf)**:
|
||||
```protobuf
|
||||
// user.proto
|
||||
syntax = "proto3";
|
||||
|
||||
message User {
|
||||
int64 id = 1;
|
||||
string name = 2;
|
||||
string email = 3;
|
||||
repeated string tags = 4;
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
# 编译 Protobuf
|
||||
protoc --python_out=. user.proto
|
||||
```
|
||||
|
||||
```python
|
||||
# Python 序列化
|
||||
import user_pb2
|
||||
|
||||
user = user_pb2.User()
|
||||
user.id = 1
|
||||
user.name = "Alice"
|
||||
user.email = "alice@example.com"
|
||||
user.tags.extend(["vip", "active"])
|
||||
|
||||
# 序列化
|
||||
serialized = user.SerializeToString() # 二进制数据
|
||||
|
||||
# 反序列化
|
||||
user2 = user_pb2.User()
|
||||
user2.ParseFromString(serialized)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. RPC 框架选型
|
||||
|
||||
#### **选型决策树**:
|
||||
```
|
||||
是否需要跨语言调用?
|
||||
├─ 是 → gRPC(Protobuf 跨语言支持最好)
|
||||
└─ 否 → 继续判断
|
||||
|
||||
是否需要高性能?
|
||||
├─ 是 → Dubbo(TCP 长连接、Hessian 序列化)
|
||||
└─ 否 → 继续判断
|
||||
|
||||
是否需要简单易用?
|
||||
├─ 是 → Spring Cloud OpenFeign(基于 HTTP REST)
|
||||
└─ 否 → Dubbo
|
||||
|
||||
已有技术栈?
|
||||
├─ Spring Cloud → OpenFeign/Dubbo
|
||||
├─ Kubernetes → gRPC(服务网格友好)
|
||||
└─ Dubbo → 继续使用 Dubbo
|
||||
```
|
||||
|
||||
#### **实际项目经验**:
|
||||
|
||||
**场景 1:电商内部服务**
|
||||
```
|
||||
选择:Dubbo
|
||||
原因:
|
||||
- 内部服务,都是 Java 技术栈
|
||||
- 对性能要求高(高并发下单)
|
||||
- 需要负载均衡、熔断降级
|
||||
|
||||
配置:
|
||||
- 使用 Hessian 序列化
|
||||
- Zookeeper 注册中心
|
||||
- LeastActive 负载均衡
|
||||
```
|
||||
|
||||
**场景 2:跨语言微服务**
|
||||
```
|
||||
选择:gRPC
|
||||
原因:
|
||||
- 后端 Java,数据分析 Python,AI 服务 Go
|
||||
- 需要统一的服务间通信协议
|
||||
- Protobuf 高性能且跨语言
|
||||
|
||||
配置:
|
||||
- Protobuf 定义接口
|
||||
- HTTP/2 传输
|
||||
- 多语言代码生成
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. 超时、重试和熔断
|
||||
|
||||
#### **超时配置**:
|
||||
```xml
|
||||
<!-- Dubbo 超时 -->
|
||||
<dubbo:reference id="userService"
|
||||
interface="com.example.UserService"
|
||||
timeout="3000"/> <!-- 3 秒超时 -->
|
||||
|
||||
<!-- 方法级超时 -->
|
||||
<dubbo:reference id="userService"
|
||||
interface="com.example.UserService">
|
||||
<dubbo:method name="getUserById" timeout="1000"/>
|
||||
<dubbo:method name="listUsers" timeout="5000"/>
|
||||
</dubbo:reference>
|
||||
```
|
||||
|
||||
#### **重试机制**:
|
||||
```xml
|
||||
<dubbo:reference id="userService"
|
||||
interface="com.example.UserService"
|
||||
retries="2"/> <!-- 失败后重试 2 次 -->
|
||||
|
||||
<!-- 工作流程 -->
|
||||
第一次调用 → 失败
|
||||
↓
|
||||
第二次调用 → 失败
|
||||
↓
|
||||
第三次调用 → 成功/失败
|
||||
```
|
||||
|
||||
**注意**:幂等性操作才能重试(如查询),非幂等操作(如下单)不能重试
|
||||
|
||||
```xml
|
||||
<!-- 非幂等操作禁用重试 -->
|
||||
<dubbo:method name="createOrder" retries="0"/>
|
||||
```
|
||||
|
||||
#### **熔断降级(Dubbo)**:
|
||||
```java
|
||||
// 使用 Sentinel 实现熔断
|
||||
@SentinelResource(value = "getUserById",
|
||||
blockHandler = "handleBlock",
|
||||
fallback = "handleFallback")
|
||||
public User getUserById(Long id) {
|
||||
return userService.getUserById(id);
|
||||
}
|
||||
|
||||
// 熔断处理
|
||||
public User handleBlock(Long id, BlockException ex) {
|
||||
// 熔断时返回默认值
|
||||
return new User(-1L, "Default", "default@example.com");
|
||||
}
|
||||
|
||||
// 降级处理
|
||||
public User handleFallback(Long id, Throwable ex) {
|
||||
// 异常时返回降级数据
|
||||
return new User(-1L, "Fallback", "fallback@example.com");
|
||||
}
|
||||
```
|
||||
|
||||
**熔断规则配置**:
|
||||
```java
|
||||
// Sentinel 熔断规则
|
||||
List<DegradeRule> rules = new ArrayList<>();
|
||||
DegradeRule rule = new DegradeRule();
|
||||
rule.setResource("getUserById");
|
||||
rule.setGrade(RuleConstant.DEGRADE_GRADE_RT); // 平均响应时间
|
||||
rule.setCount(100); // 100ms
|
||||
rule.setTimeWindow(10); // 10 秒熔断时间
|
||||
rules.add(rule);
|
||||
DegradeRuleManager.loadRules(rules);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. 实际项目经验
|
||||
|
||||
#### **场景 1:订单系统性能优化**
|
||||
```
|
||||
问题:订单创建接口延迟高(2 秒)
|
||||
排查:
|
||||
1. 调用链追踪发现库存服务耗时最长
|
||||
2. 库存服务使用 HTTP REST,JSON 序列化慢
|
||||
3. 每次调用都建立新连接
|
||||
|
||||
解决:
|
||||
1. 将库存服务从 HTTP REST 迁移到 Dubbo
|
||||
2. 使用 Hessian 序列化
|
||||
3. 启用长连接复用
|
||||
4. 配置 LeastActive 负载均衡
|
||||
|
||||
结果:延迟降低到 300ms(提升 85%)
|
||||
```
|
||||
|
||||
#### **场景 2:服务注册中心故障**
|
||||
```
|
||||
问题:Zookeeper 集群故障,服务调用失败
|
||||
排查:
|
||||
Consumer 每次调用都查询注册中心,导致无法发现服务
|
||||
|
||||
解决:
|
||||
1. Dubbo 默认会缓存 provider 列表到本地
|
||||
2. 配置缓存策略
|
||||
<dubbo:registry address="zookeeper://127.0.0.1:2181"
|
||||
file="${user.home}/output/dubbo.cache"/>
|
||||
3. 注册中心故障时,使用本地缓存
|
||||
|
||||
结果:注册中心故障不影响已有服务调用
|
||||
```
|
||||
|
||||
#### **场景 3:序列化兼容性问题**
|
||||
```
|
||||
问题:升级服务版本后,旧客户端调用失败
|
||||
原因:
|
||||
- 新增字段使用了不可序列化的类型
|
||||
- 客户端版本不兼容
|
||||
|
||||
解决:
|
||||
1. Protobuf 默认兼容(新增字段不影响)
|
||||
2. Hessian 需要保证序列化 ID 一致
|
||||
3. 使用版本号区分服务
|
||||
<dubbo:service interface="..." version="1.0.0"/>
|
||||
<dubbo:service interface="..." version="2.0.0"/>
|
||||
4. 灰度升级,逐步切换流量
|
||||
|
||||
结果:平滑升级,零停机
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 10. 阿里 P7 加分项
|
||||
|
||||
**架构设计能力**:
|
||||
- 设计过大规模 RPC 框架的集群架构(百万级 QPS)
|
||||
- 有自定义 RPC 框架开发经验
|
||||
- 实现过服务网格与传统 RPC 框架的融合
|
||||
|
||||
**深度理解**:
|
||||
- 熟悉 Dubbo 源码(SPI 机制、代理设计、集群容错)
|
||||
- 理解 gRPC 的 HTTP/2 和 Protobuf 底层原理
|
||||
- 有序列化协议的选型和优化经验
|
||||
|
||||
**性能调优**:
|
||||
- 优化过 TCP 参数(连接池、KeepAlive、缓冲区大小)
|
||||
- 调整过 JVM 参数减少 GC(减少对象创建、使用堆外内存)
|
||||
- 优化过网络参数(MTU、TCP_NODELAY)
|
||||
|
||||
**生产实践**:
|
||||
- 解决过 TCP 粘包/拆包问题
|
||||
- 处理过序列化安全漏洞(如 Hessian 反序列化 RCE)
|
||||
- 实现过服务优雅上下线(注册预热、优雅停机)
|
||||
|
||||
**可观测性**:
|
||||
- 集成过分布式追踪(SkyWalking、Jaeger)
|
||||
- 实现过 RPC 调用链路监控
|
||||
- 设计过服务性能指标大盘(QPS、延迟、成功率)
|
||||
|
||||
**跨语言调用**:
|
||||
- 有 gRPC 多语言实现经验(Java、Go、Python)
|
||||
- 解决过 Protobuf 跨语言兼容性问题
|
||||
- 实现过动态代理生成(如 Python 调用 Java 服务)
|
||||
424
questions/07-系统设计/即时通讯系统设计.md
Normal file
424
questions/07-系统设计/即时通讯系统设计.md
Normal file
@@ -0,0 +1,424 @@
|
||||
# 即时通讯系统设计
|
||||
|
||||
## 需求分析和数据量评估
|
||||
|
||||
### 需求分析
|
||||
- **核心功能**:单聊、群聊、消息推送、在线状态
|
||||
- **业务场景**:社交应用、企业通讯、客服系统
|
||||
- **QPS评估**:日消息100亿+,峰值QPS 10万+
|
||||
- **数据规模**:用户1亿+,好友关系10亿+,历史消息1000亿+
|
||||
|
||||
### 数据量评估
|
||||
- **用户表**:1亿条,日均查询1000万次
|
||||
- **好友关系表**:10亿条,日均更新100万次
|
||||
- **消息表**:1000亿+条,日增1亿+
|
||||
- **群组表**:1亿+条,日均查询100万次
|
||||
- **离线消息**:100亿+条,日均推送1亿+
|
||||
|
||||
## 核心技术难点
|
||||
|
||||
### 1. 高并发消息处理
|
||||
- 亿级用户同时在线
|
||||
- 消息的实时性要求
|
||||
- 消息的可靠性保证
|
||||
|
||||
### 2. 消息存储优化
|
||||
- 海量消息数据存储
|
||||
- 消息的快速检索
|
||||
- 历史消息清理
|
||||
|
||||
### 3. 在线状态管理
|
||||
- 实时在线状态同步
|
||||
- 心跳检测机制
|
||||
- 离线状态管理
|
||||
|
||||
### 4. 消息推送优化
|
||||
- 推送延迟控制
|
||||
- 消息去重
|
||||
- 推送失败重试
|
||||
|
||||
## 系统架构设计
|
||||
|
||||
### 总体架构
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 移动端APP │ │ PC客户端 │ │ Web网页 │
|
||||
│ (iOS/Android)│ │ (Windows) │ │ (Web) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 负载均衡 │ │ API网关 │ │ CDN加速 │
|
||||
│ (Nginx) │ │ (Gateway) │ │ (Edge) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 网关服务 │ │ 业务服务 │ │ 推送服务 │
|
||||
│ (Gateway) │ │ (微服务) │ │ (Service) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└─────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 消息队列 │ │ Redis集群 │ │ 数据库集群 │
|
||||
│ (Kafka/Pulsar)│ │ (缓存+pub/sub)│ │ (MySQL分库分表)│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 消息存储 │ │ 文件存储 │ │ 搜索引擎 │
|
||||
│ (MongoDB) │ │ (MinIO/S3) │ │ (Elasticsearch)│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### 关键组件
|
||||
|
||||
#### 1. 流量层
|
||||
- **负载均衡**:Nginx L7负载均衡
|
||||
- **API网关**:请求路由、限流、认证
|
||||
- **CDN加速**:静态资源缓存
|
||||
|
||||
#### 2. 服务层
|
||||
- **网关服务**:连接管理、协议转换
|
||||
- **业务服务**:消息处理、关系管理
|
||||
- **推送服务**:消息推送、状态同步
|
||||
- **通知服务**:系统通知、消息提醒
|
||||
|
||||
#### 3. 存储层
|
||||
- **Redis集群**:在线状态、会话管理
|
||||
- **MySQL集群**:用户数据、关系数据
|
||||
- **MongoDB集群**:消息存储、历史记录
|
||||
- **消息队列**:异步处理、削峰填谷
|
||||
|
||||
#### 4. 基础设施
|
||||
- **消息存储**:分布式文件系统
|
||||
- **搜索引擎**:消息全文检索
|
||||
- **监控系统**:实时监控告警
|
||||
- **日志系统**:业务日志记录
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 用户表
|
||||
```sql
|
||||
CREATE TABLE `im_user` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`nickname` varchar(50) NOT NULL COMMENT '昵称',
|
||||
`avatar` varchar(255) DEFAULT NULL COMMENT '头像',
|
||||
`gender` tinyint DEFAULT 0 COMMENT '性别',
|
||||
`birthday` date DEFAULT NULL COMMENT '生日',
|
||||
`signature` varchar(255) DEFAULT NULL COMMENT '个性签名',
|
||||
`mobile` varchar(20) DEFAULT NULL COMMENT '手机号',
|
||||
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`last_login` timestamp DEFAULT NULL COMMENT '最后登录时间',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 好友关系表
|
||||
```sql
|
||||
CREATE TABLE `im_friends` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`friend_id` bigint NOT NULL COMMENT '好友ID',
|
||||
`remark` varchar(50) DEFAULT NULL COMMENT '备注',
|
||||
`group_name` varchar(50) DEFAULT NULL COMMENT '分组名',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_friend` (`user_id`, `friend_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_friend_id` (`friend_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 消息表
|
||||
```sql
|
||||
CREATE TABLE `im_message` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`message_id` varchar(64) NOT NULL COMMENT '消息ID',
|
||||
`from_user_id` bigint NOT NULL COMMENT '发送者ID',
|
||||
`to_user_id` bigint DEFAULT NULL COMMENT '接收者ID',
|
||||
`group_id` bigint DEFAULT NULL COMMENT '群组ID',
|
||||
`message_type` tinyint NOT NULL COMMENT '消息类型',
|
||||
`content` text COMMENT '消息内容',
|
||||
`is_read` tinyint NOT NULL DEFAULT 0 COMMENT '是否已读',
|
||||
`is_deleted` tinyint NOT NULL DEFAULT 0 COMMENT '是否已删除',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_message_id` (`message_id`),
|
||||
KEY `idx_from_user` (`from_user_id`),
|
||||
KEY `idx_to_user` (`to_user_id`),
|
||||
KEY `idx_group_id` (`group_id`),
|
||||
KEY `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 群组表
|
||||
```sql
|
||||
CREATE TABLE `im_group` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`group_id` bigint NOT NULL COMMENT '群组ID',
|
||||
`group_name` varchar(100) NOT NULL COMMENT '群名称',
|
||||
`avatar` varchar(255) DEFAULT NULL COMMENT '群头像',
|
||||
`creator_id` bigint NOT NULL COMMENT '创建者ID',
|
||||
`member_count` int NOT NULL DEFAULT 0 COMMENT '成员数',
|
||||
`max_members` int DEFAULT 500 COMMENT '最大成员数',
|
||||
`description` text COMMENT '群描述',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_group_id` (`group_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 群组成员表
|
||||
```sql
|
||||
CREATE TABLE `im_group_member` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`group_id` bigint NOT NULL COMMENT '群组ID',
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`role` tinyint NOT NULL DEFAULT 0 COMMENT '角色',
|
||||
`nickname` varchar(50) DEFAULT NULL COMMENT '群昵称',
|
||||
`join_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_group_user` (`group_id`, `user_id`),
|
||||
KEY `idx_group_id` (`group_id`),
|
||||
KEY `idx_user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### Redis缓存设计
|
||||
```typescript
|
||||
// 用户在线状态
|
||||
const ONLINE_STATUS_PREFIX = 'online:';
|
||||
const ONLINE_STATUS_TTL = 300; // 5分钟
|
||||
|
||||
// 会话信息
|
||||
const SESSION_PREFIX = 'session:';
|
||||
const SESSION_TTL = 3600; // 1小时
|
||||
|
||||
// 未读消息计数
|
||||
const UNREAD_PREFIX = 'unread:';
|
||||
const UNREAD_TTL = 86400; // 24小时
|
||||
|
||||
// 消息已读状态
|
||||
const READ_PREFIX = 'read:';
|
||||
const READ_TTL = 604800; // 7天
|
||||
|
||||
// 最近会话
|
||||
const RECENT_SESSION_PREFIX = 'recent:';
|
||||
const RECENT_SESSION_TTL = 86400; // 24小时
|
||||
```
|
||||
|
||||
### 缓存策略
|
||||
1. **多级缓存**:
|
||||
- 本地缓存:Caffeine
|
||||
- 分布式缓存:Redis Cluster
|
||||
- 内存缓存:热点数据缓存
|
||||
|
||||
2. **缓存更新策略**:
|
||||
- Write Through:写入同时更新缓存
|
||||
- Write Behind:异步更新缓存
|
||||
- Cache Invalidation:定时失效
|
||||
|
||||
3. **消息缓存**:
|
||||
- 最近消息缓存
|
||||
- 群组信息缓存
|
||||
- 用户状态缓存
|
||||
|
||||
### WebSocket实现
|
||||
```java
|
||||
public class WebSocketHandler extends TextWebSocketHandler {
|
||||
|
||||
private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
// 用户上线
|
||||
String userId = getUserIdFromSession(session);
|
||||
sessions.put(userId, session);
|
||||
|
||||
// 更新在线状态
|
||||
redisTemplate.opsForValue().set(ONLINE_STATUS_PREFIX + userId, "1", ONLINE_STATUS_TTL);
|
||||
|
||||
// 通知好友用户上线
|
||||
notifyFriendsOnline(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
String userId = getUserIdFromSession(session);
|
||||
Message msg = parseMessage(message.getPayload());
|
||||
|
||||
// 处理消息
|
||||
handleMessage(userId, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||
// 用户下线
|
||||
String userId = getUserIdFromSession(session);
|
||||
sessions.remove(userId);
|
||||
|
||||
// 更新在线状态
|
||||
redisTemplate.delete(ONLINE_STATUS_PREFIX + userId);
|
||||
|
||||
// 通知好友用户下线
|
||||
notifyFriendsOffline(userId);
|
||||
}
|
||||
|
||||
private void handleMessage(String fromUserId, Message msg) {
|
||||
switch (msg.getType()) {
|
||||
case SINGLE_CHAT:
|
||||
sendSingleMessage(fromUserId, msg);
|
||||
break;
|
||||
case GROUP_CHAT:
|
||||
sendGroupMessage(fromUserId, msg);
|
||||
break;
|
||||
case TYPING:
|
||||
sendTypingMessage(fromUserId, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendSingleMessage(String fromUserId, Message msg) {
|
||||
String toUserId = msg.getToUserId();
|
||||
WebSocketSession session = sessions.get(toUserId);
|
||||
|
||||
if (session != null && session.isOpen()) {
|
||||
// 用户在线,直接推送
|
||||
session.sendMessage(new TextMessage(msg.toJson()));
|
||||
} else {
|
||||
// 用户离线,存储离线消息
|
||||
saveOfflineMessage(fromUserId, toUserId, msg);
|
||||
}
|
||||
|
||||
// 更新未读消息计数
|
||||
updateUnreadCount(fromUserId, toUserId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展性考虑
|
||||
|
||||
### 1. 水平扩展
|
||||
- **无状态服务**:业务服务无状态化
|
||||
- **数据分片**:按用户ID分片
|
||||
- **读写分离**:主库写入,从库读取
|
||||
|
||||
### 2. 垂直扩展
|
||||
- **服务拆分**:网关服务、业务服务、推送服务
|
||||
- **数据分层**:热数据、温数据、冷数据
|
||||
- **多级缓存**:本地、Redis、CDN
|
||||
|
||||
### 3. 消息可靠性
|
||||
- **消息持久化**:消息队列持久化
|
||||
- **重试机制**:消息发送失败重试
|
||||
- **消息去重**:ID去重机制
|
||||
|
||||
### 4. 容灾备份
|
||||
- **多活架构**:多机房部署
|
||||
- **故障转移**:自动故障检测和转移
|
||||
- **数据备份**:定时备份和实时同步
|
||||
|
||||
## 实际项目经验
|
||||
|
||||
### 1. 技术栈选择
|
||||
- **前端**:React Native + Flutter
|
||||
- **后端**:Spring Boot + Node.js
|
||||
- **数据库**:MySQL + MongoDB + Redis
|
||||
- **消息队列**:Kafka + Pulsar
|
||||
- **通信协议**:WebSocket + MQTT
|
||||
|
||||
### 2. 性能优化
|
||||
- **消息压缩**:Gzip压缩消息内容
|
||||
- **批量处理**:批量消息处理
|
||||
- **连接池**:数据库连接池优化
|
||||
- **缓存优化**:多级缓存策略
|
||||
|
||||
### 3. 运维部署
|
||||
- **容器化**:Docker + Kubernetes
|
||||
- **CI/CD**:Jenkins + GitLab
|
||||
- **监控告警**:ELK Stack + AlertManager
|
||||
- **压测**:JMeter + Locust
|
||||
|
||||
### 4. 安全设计
|
||||
- **消息加密**:端到端加密
|
||||
- **身份认证**:JWT Token认证
|
||||
- **消息防刷**:频率限制
|
||||
- **数据脱敏**:敏感信息过滤
|
||||
|
||||
## 阿里P7加分项
|
||||
|
||||
### 1. 架构设计能力
|
||||
- **高可用架构**:99.99%可用性
|
||||
- **高性能架构**:支持亿级消息
|
||||
- **扩展性架构**:弹性扩缩容
|
||||
|
||||
### 2. 技术深度
|
||||
- **分布式系统**:分布式缓存、分布式消息
|
||||
- **通信协议**:WebSocket、MQTT协议
|
||||
- **实时系统**:实时消息处理
|
||||
|
||||
### 3. 业务理解
|
||||
- **社交业务**:理解社交应用场景
|
||||
- **企业通讯**:掌握企业通讯需求
|
||||
- **用户行为**:分析消息使用模式
|
||||
|
||||
### 4. 团队管理
|
||||
- **技术团队**:带领30人+团队
|
||||
- **项目管控**:管理亿级用户项目
|
||||
- **技术方案**:主导架构设计
|
||||
|
||||
### 5. 前沿技术
|
||||
- **AI应用**:智能回复、消息分类
|
||||
- **边缘计算**:边缘节点处理
|
||||
- **Serverless**:函数化服务
|
||||
|
||||
## 面试常见问题
|
||||
|
||||
### 1. 如何保证消息不丢失?
|
||||
- **持久化存储**:消息队列持久化
|
||||
- **重试机制**:失败消息重试
|
||||
- **确认机制**:消息确认ACK
|
||||
- **补偿机制**:定时补偿任务
|
||||
|
||||
### 2. 如何处理海量消息存储?
|
||||
- **分库分表**:按时间分片
|
||||
- **数据归档**:冷热数据分离
|
||||
- **压缩存储**:消息内容压缩
|
||||
- **生命周期管理**:自动清理过期数据
|
||||
|
||||
### 3. 如何实现消息实时性?
|
||||
- **长连接**:WebSocket长连接
|
||||
- **推送机制**:实时推送
|
||||
- **心跳检测**:连接保持
|
||||
- **故障转移**:自动重连
|
||||
|
||||
### 4. 如何处理消息去重?
|
||||
- **消息ID**:全局唯一ID
|
||||
- **幂等设计**:处理重复消息
|
||||
- **去重表**:已处理消息记录
|
||||
- **时间窗口**:时间窗口去重
|
||||
|
||||
### 5. 如何优化消息推送性能?
|
||||
- **批量推送**:批量消息推送
|
||||
- **连接池**:连接复用
|
||||
- **异步处理**:非阻塞IO
|
||||
- **缓存优化**:推送结果缓存
|
||||
605
questions/07-系统设计/服务网格.md
Normal file
605
questions/07-系统设计/服务网格.md
Normal file
@@ -0,0 +1,605 @@
|
||||
# 服务网格 (Service Mesh)
|
||||
|
||||
## 问题
|
||||
|
||||
**背景**:在微服务架构中,随着服务数量增加,服务间的通信管理变得复杂。服务网格作为基础设施层,负责处理服务间通信的流量管理、安全性和可观测性。
|
||||
|
||||
**问题**:
|
||||
1. 什么是服务网格?它解决了哪些问题?
|
||||
2. Istio 的核心组件有哪些?它们是如何协作的?
|
||||
3. Sidecar 模式的优缺点是什么?
|
||||
4. 请描述 Istio 的流量管理功能(灰度发布、蓝绿部署、熔断降级)
|
||||
5. Istio 如何实现 mTLS(双向 TLS)?
|
||||
6. 在生产环境中使用服务网格遇到过哪些坑?
|
||||
7. Linkerd 和 Istio 的区别是什么?如何选择?
|
||||
|
||||
---
|
||||
|
||||
## 标准答案
|
||||
|
||||
### 1. 服务网格概述
|
||||
|
||||
**定义**:
|
||||
服务网格是微服务架构中用于处理服务间通信的基础设施层,通常以轻量级网络代理的形式实现。
|
||||
|
||||
**核心功能**:
|
||||
- **流量管理**:路由规则、负载均衡、灰度发布
|
||||
- **安全性**:mTLS、JWT 验证、访问控制
|
||||
- **可观测性**:Metrics、Tracing、Logging
|
||||
|
||||
**解决的问题**:
|
||||
```
|
||||
传统微服务架构的痛点:
|
||||
├─ 服务间通信逻辑散落在每个服务中
|
||||
├─ 熔断、重试、超时等逻辑重复实现
|
||||
├─ 安全策略难以统一管理
|
||||
├─ 可观测性数据收集困难
|
||||
└─ 灰度发布、流量染色需要大量代码
|
||||
|
||||
服务网格的解决方案:
|
||||
├─ 将通信逻辑下沉到 Sidecar 代理
|
||||
├─ 控制平面统一配置管理
|
||||
├─ 数据平面透明代理流量
|
||||
├─ 自动收集可观测性数据
|
||||
└─ 声明式 API 管理流量
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Istio 核心组件
|
||||
|
||||
#### **架构图**:
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ Control Plane │
|
||||
└─────────────────┘
|
||||
│
|
||||
┌─────────────────┼─────────────────┐
|
||||
│ │ │
|
||||
┌─────────┐ ┌──────────┐ ┌──────────┐
|
||||
│ Istiod │ │Pilot │ │Citadel │
|
||||
│ (统一) │ │(流量管理) │ │(证书管理)│
|
||||
└─────────┘ └──────────┘ └──────────┘
|
||||
│
|
||||
│ 配置下发
|
||||
│
|
||||
┌─────────────────────────────────────┐
|
||||
│ Data Plane │
|
||||
├─────────────────────────────────────┤
|
||||
│ │
|
||||
│ Service A Service B │
|
||||
│ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ Envoy │◄────►│ Envoy │ │
|
||||
│ │ Sidecar │ │ Sidecar │ │
|
||||
│ └─────────┘ └─────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### **核心组件详解**:
|
||||
|
||||
**1. Istiod(统一控制平面)**
|
||||
- **Pilot**:流量管理和配置下发
|
||||
- **Citadel**:证书管理和身份认证
|
||||
- **Galley**:配置验证和注入(Istio 1.13+ 已合并到 Istiod)
|
||||
|
||||
**代码示例 - Istiod 配置**:
|
||||
```yaml
|
||||
# istiod deployment
|
||||
apiVersion: v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: istiod
|
||||
namespace: istio-system
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: discovery
|
||||
image: gcr.io/istio-testing/pilot:1.19.0
|
||||
args:
|
||||
- "discovery"
|
||||
- "--monitoringAddr=:15014"
|
||||
- "--log_output_level=default:info"
|
||||
ports:
|
||||
- containerPort: 15012 # Pilot 服务的 xDS 端口
|
||||
name: grpc-xds
|
||||
```
|
||||
|
||||
**2. Envoy Sidecar(数据平面)**
|
||||
- 拦截所有进出流量
|
||||
- 执行流量规则(路由、负载均衡)
|
||||
- 收集 Metrics 和 Traces
|
||||
- 处理 mTLS 加解密
|
||||
|
||||
**Sidecar 注入示例**:
|
||||
```yaml
|
||||
# 自动注入 Sidecar
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-app
|
||||
annotations:
|
||||
sidecar.istio.io/inject: "true" # 启用自动注入
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
sidecar.istio.io/rewriteAppHTTPProbers: "true" # 重写 HTTP probes
|
||||
spec:
|
||||
containers:
|
||||
- name: app
|
||||
image: my-app:1.0.0
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Sidecar 模式
|
||||
|
||||
#### **优点**:
|
||||
1. **透明性**:业务代码无感知,无需修改
|
||||
2. **语言无关**:任何语言都能使用
|
||||
3. **统一管理**:集中配置,易于维护
|
||||
4. **渐进式采用**:可以逐步迁移
|
||||
|
||||
#### **缺点**:
|
||||
1. **资源开销**:每个服务都有 Sidecar,增加内存和 CPU
|
||||
```
|
||||
典型资源占用:
|
||||
- 内存:50-100MB per Sidecar
|
||||
- CPU:5-10% per core
|
||||
- 延迟增加:1-5ms
|
||||
```
|
||||
|
||||
2. **网络链路增加**:
|
||||
```
|
||||
请求路径(有 Sidecar):
|
||||
Client → Sidecar A → Service A → Sidecar B → Service B
|
||||
|
||||
请求路径(无 Sidecar):
|
||||
Client → Service A → Service B
|
||||
```
|
||||
|
||||
3. **调试复杂度**:多了一层网络代理
|
||||
|
||||
#### **优化方案**:
|
||||
```yaml
|
||||
# Sidecar 资源限制
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-app
|
||||
spec:
|
||||
containers:
|
||||
- name: istio-proxy
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
```
|
||||
|
||||
**Sidecar 资源配置模式**:
|
||||
```yaml
|
||||
# sidecar resources customization
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: istio-sidecar-injector
|
||||
data:
|
||||
values: |
|
||||
sidecarResources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 流量管理
|
||||
|
||||
#### **4.1 灰度发布 (Canary Deployment)**
|
||||
|
||||
**场景**:新版本 v2 发布给 10% 的流量
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: reviews
|
||||
spec:
|
||||
hosts:
|
||||
- reviews
|
||||
http:
|
||||
- match:
|
||||
- headers:
|
||||
x-canary:
|
||||
exact: "true" # 带特定 header 的流量走 v2
|
||||
route:
|
||||
- destination:
|
||||
host: reviews
|
||||
subset: v2
|
||||
- route:
|
||||
- destination:
|
||||
host: reviews
|
||||
subset: v1
|
||||
weight: 90 # 90% 流量走 v1
|
||||
- destination:
|
||||
host: reviews
|
||||
subset: v2
|
||||
weight: 10 # 10% 流量走 v2
|
||||
---
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: reviews
|
||||
spec:
|
||||
host: reviews
|
||||
subsets:
|
||||
- name: v1
|
||||
labels:
|
||||
version: v1
|
||||
- name: v2
|
||||
labels:
|
||||
version: v2
|
||||
```
|
||||
|
||||
#### **4.2 蓝绿部署 (Blue-Green Deployment)**
|
||||
|
||||
**场景**:一键切换全部流量到新版本
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: my-app
|
||||
spec:
|
||||
hosts:
|
||||
- my-app
|
||||
http:
|
||||
- route:
|
||||
- destination:
|
||||
host: my-app
|
||||
subset: blue # 所有流量指向 blue
|
||||
weight: 100
|
||||
# 切换到 green:修改 subset 为 green
|
||||
---
|
||||
# Kubernetes Deployment:同时存在 blue 和 green
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-app-blue
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
version: blue
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-app-green
|
||||
spec:
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
version: green
|
||||
```
|
||||
|
||||
#### **4.3 熔断降级 (Circuit Breaker)**
|
||||
|
||||
**场景**:防止故障扩散
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: DestinationRule
|
||||
metadata:
|
||||
name: httpbin
|
||||
spec:
|
||||
host: httpbin
|
||||
trafficPolicy:
|
||||
connectionPool:
|
||||
tcp:
|
||||
maxConnections: 10 # 最大连接数
|
||||
http:
|
||||
http1MaxPendingRequests: 50 # 最大等待请求数
|
||||
http2MaxRequests: 100 # 最大并发请求数
|
||||
maxRequestsPerConnection: 2 # 每连接最大请求数
|
||||
maxRetries: 3 # 最大重试次数
|
||||
outlierDetection:
|
||||
consecutiveErrors: 5 # 连续 5 次错误
|
||||
interval: 30s # 每 30s 检查一次
|
||||
baseEjectionTime: 30s # 最小熔断时间
|
||||
maxEjectionPercent: 50 # 最多熔断 50% 的实例
|
||||
minHealthPercent: 40 # 最小健康实例比例
|
||||
```
|
||||
|
||||
**熔断状态图**:
|
||||
```
|
||||
Closed → Open → Half-Open → Closed
|
||||
↑ │ │
|
||||
└────────┴──────────┘
|
||||
```
|
||||
|
||||
#### **4.4 超时和重试**
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.istio.io/v1beta1
|
||||
kind: VirtualService
|
||||
metadata:
|
||||
name: reviews
|
||||
spec:
|
||||
hosts:
|
||||
- reviews
|
||||
http:
|
||||
- retry:
|
||||
attempts: 3 # 最多重试 3 次
|
||||
perTryTimeout: 2s # 每次重试超时 2s
|
||||
retryOn: 5xx,connect-failure,refused-stream # 重试条件
|
||||
timeout: 10s # 总超时时间
|
||||
route:
|
||||
- destination:
|
||||
host: reviews
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. mTLS (双向 TLS) 实现
|
||||
|
||||
#### **原理**:
|
||||
```
|
||||
Service A Service B
|
||||
│ │
|
||||
│ 1. 发送连接请求(无证书) │
|
||||
│ ─────────────────────────────────────►│
|
||||
│ │
|
||||
│ 2. 返回服务器证书 │
|
||||
│ ◄─────────────────────────────────────│
|
||||
│ │
|
||||
│ 3. 发送客户端证书 │
|
||||
│ ─────────────────────────────────────►│
|
||||
│ │
|
||||
│ 4. 验证通过,建立加密连接 │
|
||||
│ ◄────────────────────────────────────►│
|
||||
│ │
|
||||
│ 5. 加密通信 │
|
||||
│ ◄──────────────► │
|
||||
```
|
||||
|
||||
#### **配置示例**:
|
||||
|
||||
**全局启用 mTLS**:
|
||||
```yaml
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: PeerAuthentication
|
||||
metadata:
|
||||
name: default
|
||||
namespace: istio-system
|
||||
spec:
|
||||
mtls:
|
||||
mode: STRICT # 严格模式:必须使用 mTLS
|
||||
```
|
||||
|
||||
**按服务配置**:
|
||||
```yaml
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: PeerAuthentication
|
||||
metadata:
|
||||
name: my-app-mtls
|
||||
namespace: default
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
mtls:
|
||||
mode: PERMISSIVE # 宽松模式:兼容 mTLS 和明文
|
||||
```
|
||||
|
||||
**服务授权**:
|
||||
```yaml
|
||||
apiVersion: security.istio.io/v1beta1
|
||||
kind: AuthorizationPolicy
|
||||
metadata:
|
||||
name: my-app-authz
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: my-app
|
||||
action: ALLOW
|
||||
rules:
|
||||
- from:
|
||||
- source:
|
||||
principals: ["cluster.local/ns/default/sa/frontend"] # 只允许 frontend SA 访问
|
||||
to:
|
||||
- operation:
|
||||
methods: ["GET", "POST"]
|
||||
```
|
||||
|
||||
#### **证书管理流程**:
|
||||
```
|
||||
1. Citadel 工作负载证书
|
||||
↓
|
||||
2. 证书存储在 Secret 中
|
||||
↓
|
||||
3. Envoy Sidecar 启动时加载证书
|
||||
↓
|
||||
4. 定期轮换证书(默认 24 小时)
|
||||
↓
|
||||
5. 旧证书过期,使用新证书
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6. 生产环境踩坑经验
|
||||
|
||||
#### **坑 1:Sidecar 资源占用过高**
|
||||
```yaml
|
||||
# 问题:100 个服务 × 100MB = 10GB 内存
|
||||
# 解决:按需启用 Sidecar
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: my-app
|
||||
annotations:
|
||||
sidecar.istio.io/inject: "false" # 禁用 Sidecar
|
||||
```
|
||||
|
||||
#### **坑 2:网络延迟增加**
|
||||
```
|
||||
问题:请求延迟从 5ms 增加到 10ms
|
||||
原因:
|
||||
- Sidecar 增加了一跳
|
||||
- mTLS 加解密开销
|
||||
|
||||
解决:
|
||||
1. 调整 Envoy 配置,减少日志级别
|
||||
2. 使用 PERMISSIVE 模式降级
|
||||
3. 增加超时时间配置
|
||||
```
|
||||
|
||||
#### **坑 3:配置下发延迟**
|
||||
```yaml
|
||||
# 问题:修改 VirtualService 后,流量未立即切换
|
||||
# 原因:Pilot 下发配置有延迟(默认 1s)
|
||||
|
||||
# 解决:减少配置刷新间隔
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: istio
|
||||
namespace: istio-system
|
||||
data:
|
||||
mesh: |-
|
||||
defaultConfig:
|
||||
proxyStatsMatcher:
|
||||
inclusionRegexps:
|
||||
- ".*" # 收集所有指标
|
||||
discoveryRefreshDelay: 1s # 配置刷新延迟
|
||||
```
|
||||
```
|
||||
|
||||
#### **坑 4:大规模性能问题**
|
||||
```
|
||||
问题:集群 1000+ 服务时,Istiod 性能瓶颈
|
||||
解决:
|
||||
1. 部署多个 Istiod 实例
|
||||
2. 使用 Namespace 隔离配置
|
||||
3. 启用配置压缩
|
||||
```
|
||||
|
||||
**多实例部署**:
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: istiod
|
||||
spec:
|
||||
replicas: 3 # 多副本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7. Linkerd vs Istio
|
||||
|
||||
#### **对比表**:
|
||||
|
||||
| 特性 | Linkerd 2.x | Istio |
|
||||
|------|-------------|-------|
|
||||
| 代理 | Rust 实现(Linkerd2-proxy) | Envoy(C++) |
|
||||
| 性能 | 更低资源占用 | 资源占用较高 |
|
||||
| 功能 | 聚焦核心功能 | 功能更丰富 |
|
||||
| 集成 | Kubernetes 原生 | 支持多平台 |
|
||||
| 学习曲线 | 简单 | 复杂 |
|
||||
| 社区 | CNCF 毕业项目 | CNCF 孵化中 |
|
||||
| 多集群支持 | 弱 | 强 |
|
||||
| 流量管理 | 基础 | 高级(灰度、蓝绿等) |
|
||||
|
||||
#### **选择建议**:
|
||||
|
||||
**选择 Linkerd**:
|
||||
- Kubernetes 原生环境
|
||||
- 重视性能和资源占用
|
||||
- 需要简单易用的解决方案
|
||||
- 功能要求不高
|
||||
|
||||
**选择 Istio**:
|
||||
- 需要高级流量管理
|
||||
- 多集群/多云环境
|
||||
- 需要细粒度的安全控制
|
||||
- 团队有运维能力
|
||||
|
||||
---
|
||||
|
||||
### 8. 实际项目经验
|
||||
|
||||
#### **场景 1:电商系统灰度发布**
|
||||
```
|
||||
需求:新支付系统先给 5% 用户试用
|
||||
方案:
|
||||
1. 部署 payment-v2
|
||||
2. 配置 VirtualService,5% 流量走 v2
|
||||
3. 监控错误率和延迟
|
||||
4. 逐步增加流量比例:5% → 20% → 50% → 100%
|
||||
5. 出现问题立即回滚
|
||||
```
|
||||
|
||||
#### **场景 2:金融系统 mTLS 合规**
|
||||
```
|
||||
需求:所有服务间通信必须加密
|
||||
方案:
|
||||
1. 启用 STRICT mTLS 模式
|
||||
2. 配置 AuthorizationPolicy,只允许合法的 SA 访问
|
||||
3. 定期轮换证书(24 小时)
|
||||
4. 审计日志记录所有通信
|
||||
```
|
||||
|
||||
#### **场景 3:多集群容灾**
|
||||
```
|
||||
需求:主集群故障时自动切换到备用集群
|
||||
方案:
|
||||
1. 使用 Multi-Cluster Mesh
|
||||
2. 配置 ServiceEntry,指向备用集群
|
||||
3. 配置 DestinationRule,故障时自动切换
|
||||
4. 跨集群流量加密
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. 阿里 P7 加分项
|
||||
|
||||
**架构设计能力**:
|
||||
- 设计过大规模服务网格架构(500+ 服务)
|
||||
- 有多集群/多云服务网格实施经验
|
||||
- 实现过自定义 Control Plane(如基于 Istio API)
|
||||
|
||||
**深度理解**:
|
||||
- 理解 Envoy 内部机制(过滤器链、连接池、HTTP/2)
|
||||
- 熟悉 xDS 协议(CDS, EDS, LDS, RDS)
|
||||
- 有性能调优经验(减少延迟、优化资源占用)
|
||||
|
||||
**实际项目**:
|
||||
- 主导过从传统架构迁移到服务网格
|
||||
- 解决过生产环境的疑难问题(如网络分区、证书轮换故障)
|
||||
- 开发过自定义 WASM 插件扩展 Envoy 功能
|
||||
|
||||
**开源贡献**:
|
||||
- 向 Istio/Envoy 社区提交过 PR
|
||||
- 解决过社区 Issue
|
||||
- 编写过相关技术博客或演讲
|
||||
|
||||
**监控和可观测性**:
|
||||
- 设计过服务网格监控体系
|
||||
- 使用 Prometheus/Grafana 监控 Sidecar 性能
|
||||
- 实现过分布式追踪集成(Jaeger/Zipkin)
|
||||
|
||||
**安全实践**:
|
||||
- 实现过零信任网络架构
|
||||
- 有安全审计和合规经验
|
||||
- 设计过细粒度的 RBAC 策略
|
||||
359
questions/07-系统设计/短链接系统设计.md
Normal file
359
questions/07-系统设计/短链接系统设计.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# 短链接系统设计
|
||||
|
||||
## 需求分析和数据量评估
|
||||
|
||||
### 需求分析
|
||||
- **核心功能**:长链接转短链接、短链接跳转、统计分析
|
||||
- **业务场景**:短信营销、社交媒体分享、广告推广
|
||||
- **QPS评估**:日点击量10亿次,峰值QPS 3万+
|
||||
- **数据规模**:短链接10亿+,日生成1000万+
|
||||
|
||||
### 数据量评估
|
||||
- **短链接表**:10亿条,日均写入1000万次
|
||||
- **原始链接表**:10亿条,日均读取10亿次
|
||||
- **访问统计表**:100亿+条,日增1亿+
|
||||
- **用户表**:1000万+,日均查询100万次
|
||||
|
||||
## 核心技术难点
|
||||
|
||||
### 1. 高并发写入
|
||||
- 短链接生成需要高性能
|
||||
- 避免数据库写入瓶颈
|
||||
- 分布式ID生成
|
||||
|
||||
### 2. 高性能读取
|
||||
- 毫秒级响应时间
|
||||
- 缓存命中率优化
|
||||
- 全球CDN加速
|
||||
|
||||
### 3. 长链接查重
|
||||
- 重复链接检测
|
||||
- 去重策略设计
|
||||
- 一致性保证
|
||||
|
||||
### 4. 统计准确性
|
||||
- 实时统计延迟
|
||||
- 统计数据准确性
|
||||
- 分布式计数器
|
||||
|
||||
## 系统架构设计
|
||||
|
||||
### 总体架构
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ CDN/Edge │ │ Load Balance │ │ API Gateway │
|
||||
│ Cache │◄──►│ (Anycast) │◄──►│ (Gateway) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌───────────────────────────────────┼───────────────────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 短链接服务 │ │ 统计服务 │ │ 监控服务 │
|
||||
│ (微服务) │ │ (微服务) │ │ (微服务) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────────────────┼───────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────────────────────┼───────────────────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Redis集群 │ │ 消息队列 │ │ 数据库集群 │
|
||||
│ (缓存+计数器)│ │ (Kafka) │ │ (MySQL分库分表)│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌───────────────────────────────────┼───────────────────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 时序数据库 │ │ 数据仓库 │ │ 搜索引擎 │
|
||||
│ (InfluxDB) │ │ (ClickHouse) │ │ (Elasticsearch)│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### 关键组件
|
||||
|
||||
#### 1. 流量层
|
||||
- **CDN/Edge**:全球加速,缓存热点短链接
|
||||
- **负载均衡**:Anycast IP,就近接入
|
||||
- **API网关**:限流、路由、认证
|
||||
|
||||
#### 2. 服务层
|
||||
- **短链接服务**:核心业务逻辑
|
||||
- **统计服务**:访问统计和报表
|
||||
- **管理服务**:后台管理系统
|
||||
- **监控服务**:实时监控告警
|
||||
|
||||
#### 3. 存储层
|
||||
- **Redis集群**:缓存和计数器
|
||||
- **MySQL集群**:主从复制,分库分表
|
||||
- **时序数据库**:时序数据存储
|
||||
- **搜索引擎**:链接检索和分析
|
||||
|
||||
#### 4. 分析层
|
||||
- **数据仓库**:离线数据分析
|
||||
- **OLAP引擎**:实时查询分析
|
||||
- **报表系统**:业务报表展示
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 短链接表
|
||||
```sql
|
||||
CREATE TABLE `short_url` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`short_code` varchar(10) NOT NULL COMMENT '短链接编码',
|
||||
`long_url` text NOT NULL COMMENT '原始长链接',
|
||||
`domain` varchar(255) NOT NULL COMMENT '自定义域名',
|
||||
`title` varchar(255) DEFAULT NULL COMMENT '页面标题',
|
||||
`description` text COMMENT '页面描述',
|
||||
`keywords` varchar(500) DEFAULT NULL COMMENT '关键词',
|
||||
`user_id` bigint DEFAULT NULL COMMENT '用户ID',
|
||||
`is_custom` tinyint NOT NULL DEFAULT 0 COMMENT '是否自定义',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`expire_at` datetime DEFAULT NULL COMMENT '过期时间',
|
||||
`click_count` int NOT NULL DEFAULT 0 COMMENT '点击次数',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_short_code` (`short_code`),
|
||||
KEY `idx_long_url` (`long_url`(255)),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_expire_at` (`expire_at`),
|
||||
KEY `idx_domain` (`domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 访问记录表
|
||||
```sql
|
||||
CREATE TABLE `url_access_log` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`short_code` varchar(10) NOT NULL COMMENT '短链接编码',
|
||||
`ip` varchar(45) NOT NULL COMMENT '访问IP',
|
||||
`user_agent` text COMMENT '用户代理',
|
||||
`referer` text COMMENT '来源页面',
|
||||
`country` varchar(50) DEFAULT NULL COMMENT '国家',
|
||||
`region` varchar(50) DEFAULT NULL COMMENT '地区',
|
||||
`city` varchar(50) DEFAULT NULL COMMENT '城市',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_short_code` (`short_code`),
|
||||
KEY `idx_created_at` (`created_at`),
|
||||
KEY `idx_ip` (`ip`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 统计表
|
||||
```sql
|
||||
CREATE TABLE `url_stats` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`short_code` varchar(10) NOT NULL COMMENT '短链接编码',
|
||||
`date` date NOT NULL COMMENT '统计日期',
|
||||
`total_clicks` int NOT NULL DEFAULT 0 COMMENT '总点击次数',
|
||||
`unique_clicks` int NOT NULL DEFAULT 0 COMMENT '独立点击次数',
|
||||
`by_country` json DEFAULT NULL COMMENT '国家分布',
|
||||
`by_region` json DEFAULT NULL COMMENT '地区分布',
|
||||
`by_device` json DEFAULT NULL COMMENT '设备分布',
|
||||
`by_browser` json DEFAULT NULL COMMENT '浏览器分布',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_date_code` (`date`, `short_code`),
|
||||
KEY `idx_short_code` (`short_code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 用户表
|
||||
```sql
|
||||
CREATE TABLE `short_url_user` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`email` varchar(100) NOT NULL COMMENT '邮箱',
|
||||
`domain` varchar(255) DEFAULT NULL COMMENT '自定义域名',
|
||||
`api_key` varchar(64) DEFAULT NULL COMMENT 'API密钥',
|
||||
`quota` int NOT NULL DEFAULT 1000 COMMENT '配额',
|
||||
`used` int NOT NULL DEFAULT 0 COMMENT '已使用',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_id` (`user_id`),
|
||||
UNIQUE KEY `uk_api_key` (`api_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### Redis缓存设计
|
||||
```typescript
|
||||
// 短链接缓存
|
||||
const SHORT_URL_CACHE_PREFIX = 'short_url:';
|
||||
const SHORT_URL_CACHE_TTL = 86400; // 24小时
|
||||
|
||||
// 访问计数器
|
||||
const CLICK_COUNT_PREFIX = 'click:';
|
||||
const CLICK_COUNT_TTL = 60; // 1分钟
|
||||
|
||||
// 布隆过滤器
|
||||
const BLOOM_FILTER_PREFIX = 'bloom:';
|
||||
const BLOOM_FILTER_SIZE = 1000000000; // 10亿
|
||||
|
||||
// 限流计数器
|
||||
const RATE_LIMIT_PREFIX = 'rate_limit:';
|
||||
const RATE_LIMIT_TTL = 60; // 1分钟
|
||||
```
|
||||
|
||||
### 缓存策略
|
||||
1. **多级缓存**:
|
||||
- 本地缓存:Caffeine
|
||||
- 分布式缓存:Redis Cluster
|
||||
- CDN缓存:边缘节点
|
||||
|
||||
2. **缓存更新策略**:
|
||||
- Write Through:写入同时更新缓存
|
||||
- Write Back:异步更新缓存
|
||||
- Refresh Ahead:预加载热点数据
|
||||
|
||||
3. **缓存预热**:
|
||||
- 热门短链接预加载
|
||||
- 统计数据预计算
|
||||
- 静态资源预缓存
|
||||
|
||||
### 布隆过滤器实现
|
||||
```java
|
||||
public class BloomFilter {
|
||||
private final BitSet bitSet;
|
||||
private final int size;
|
||||
private final int[] hashSeeds;
|
||||
|
||||
public BloomFilter(int size, int hashCount) {
|
||||
this.size = size;
|
||||
this.bitSet = new BitSet(size);
|
||||
this.hashSeeds = new int[hashCount];
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < hashCount; i++) {
|
||||
hashSeeds[i] = random.nextInt();
|
||||
}
|
||||
}
|
||||
|
||||
public void add(String key) {
|
||||
for (int seed : hashSeeds) {
|
||||
int hash = Math.abs((key.hashCode() ^ seed) % size);
|
||||
bitSet.set(hash, true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean mightContain(String key) {
|
||||
for (int seed : hashSeeds) {
|
||||
int hash = Math.abs((key.hashCode() ^ seed) % size);
|
||||
if (!bitSet.get(hash)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展性考虑
|
||||
|
||||
### 1. 水平扩展
|
||||
- **无状态服务**:短链接服务无状态化
|
||||
- **数据分片**:按短链接编码分片
|
||||
- **读写分离**:主库写入,从库读取
|
||||
|
||||
### 2. 垂直扩展
|
||||
- **服务拆分**:API服务、统计服务、管理服务
|
||||
- **数据分层**:热数据、温数据、冷数据
|
||||
- **多级缓存**:本地、Redis、CDN
|
||||
|
||||
### 3. 全球化部署
|
||||
- **CDN加速**:全球节点部署
|
||||
- **地域化存储**:按地域分片
|
||||
- **灾备切换**:多机房容灾
|
||||
|
||||
### 4. 监控告警
|
||||
- **实时监控**:QPS、响应时间、错误率
|
||||
- **业务监控**:点击量、转化率
|
||||
- **异常告警**:服务异常、数据异常
|
||||
|
||||
## 实际项目经验
|
||||
|
||||
### 1. 技术栈选择
|
||||
- **前端**:React + TypeScript
|
||||
- **后端**:Spring Boot + Node.js
|
||||
- **数据库**:MySQL + Redis
|
||||
- **缓存**:Redis Cluster
|
||||
- **消息队列**:Kafka
|
||||
- **监控**:Prometheus + Grafana
|
||||
|
||||
### 2. 性能优化
|
||||
- **短链接生成**:Snowflake算法
|
||||
- **缓存优化**:多级缓存策略
|
||||
- **数据库优化**:分库分表、索引优化
|
||||
- **网络优化**:HTTP/2、Keep-Alive
|
||||
|
||||
### 3. 运维部署
|
||||
- **容器化**:Docker + Kubernetes
|
||||
- **CI/CD**:Jenkins + GitLab
|
||||
- **监控告警**:ELK Stack + AlertManager
|
||||
- **压测**:JMeter + Locust
|
||||
|
||||
### 4. 安全设计
|
||||
- **HTTPS**:全链路加密
|
||||
- **API限流**:防刷、防攻击
|
||||
- **数据脱敏**:敏感信息加密
|
||||
- **访问控制**:API密钥认证
|
||||
|
||||
## 阿里P7加分项
|
||||
|
||||
### 1. 架构设计能力
|
||||
- **高可用架构**:99.99%可用性
|
||||
- **高性能架构**:支持亿级QPS
|
||||
- **全球化架构**:全球CDN加速
|
||||
|
||||
### 2. 技术深度
|
||||
- **分布式算法**:一致性哈希、布隆过滤器
|
||||
- **缓存优化**:多级缓存策略
|
||||
- **数据库优化**:分库分表、读写分离
|
||||
|
||||
### 3. 业务理解
|
||||
- **营销业务**:理解短链接在营销中的应用
|
||||
- **用户行为**:分析点击行为模式
|
||||
- **数据统计**:实时统计和离线分析
|
||||
|
||||
### 4. 团队管理
|
||||
- **技术团队**:带领15人+团队
|
||||
- **项目管控**:管理亿级用户项目
|
||||
- **技术方案**:主导技术架构设计
|
||||
|
||||
### 5. 前沿技术
|
||||
- **Serverless**:短链接函数化
|
||||
- **边缘计算**:边缘节点处理
|
||||
- **AI应用**:智能推荐、异常检测
|
||||
|
||||
## 面试常见问题
|
||||
|
||||
### 1. 短链接如何生成?
|
||||
- **随机字符**:生成随机字符串
|
||||
- **自增序列**:数据库自增ID
|
||||
- **哈希算法**:MD5/SHA1取前几位
|
||||
- **Base62编码**:数字转62进制
|
||||
|
||||
### 2. 如何避免短链接冲突?
|
||||
- **布隆过滤器**:快速检测重复
|
||||
- **数据库唯一索引**:保证唯一性
|
||||
- **重试机制**:冲突时重新生成
|
||||
|
||||
### 3. 如何实现高并发生成?
|
||||
- **预生成**:批量生成短链接
|
||||
- **分布式ID**:Snowflake算法
|
||||
- **内存缓存**:减少数据库访问
|
||||
|
||||
### 4. 如何统计点击数据?
|
||||
- **实时统计**:Redis计数器
|
||||
- **异步处理**:消息队列存储
|
||||
- **离线分析**:数据仓库计算
|
||||
|
||||
### 5. 如何保证短链接安全?
|
||||
- **链接过滤**:过滤恶意链接
|
||||
- **访问控制**:黑白名单
|
||||
- **HTTPS加密**:防止劫持
|
||||
- **IP限制**:防刷机制
|
||||
444
questions/07-系统设计/社交信息流设计.md
Normal file
444
questions/07-系统设计/社交信息流设计.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# 社交信息流系统设计
|
||||
|
||||
## 需求分析和数据量评估
|
||||
|
||||
### 需求分析
|
||||
- **核心功能**:信息流展示、个性化推荐、社交互动、内容管理
|
||||
- **业务场景**:微博、朋友圈、抖音等社交应用
|
||||
- **QPS评估**:日请求100亿+,峰值QPS 20万+
|
||||
- **数据规模**:用户5亿+,内容100亿+,关系数据1000亿+
|
||||
|
||||
### 数据量评估
|
||||
- **用户表**:5亿条,日均查询1亿次
|
||||
- **内容表**:100亿条,日增1亿+
|
||||
- **关系表**:1000亿+条,日均更新10亿次
|
||||
- **互动表**:500亿+条,日增5亿+
|
||||
- **推荐系统**:日处理1000亿次推荐请求
|
||||
|
||||
## 核心技术难点
|
||||
|
||||
### 1. 海量内容处理
|
||||
- 亿级内容的存储和检索
|
||||
- 内容的实时分发和推送
|
||||
- 内容的审核和过滤
|
||||
|
||||
### 2. 个性化推荐
|
||||
- 用户兴趣建模
|
||||
- 实时推荐算法
|
||||
- 推荐效果评估
|
||||
|
||||
### 3. 高并发读取
|
||||
- 信息流的实时性要求
|
||||
- 用户关系计算
|
||||
- 数据缓存优化
|
||||
|
||||
### 4. 社交图谱构建
|
||||
- 用户关系网络
|
||||
- 关系强度计算
|
||||
- 图算法优化
|
||||
|
||||
## 系统架构设计
|
||||
|
||||
### 总体架构
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 移动端APP │ │ Web网页 │ │ API接口 │
|
||||
│ (iOS/Android)│ │ (PC/移动) │ │ (第三方) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 负载均衡 │ │ API网关 │ │ CDN加速 │
|
||||
│ (Nginx) │ │ (Gateway) │ │ (Edge) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Feed服务 │ │ 互动服务 │ │ 推荐服务 │
|
||||
│ (微服务) │ │ (微服务) │ │ (微服务) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└─────────────────────┼───────────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 缓存集群 │ │ 数据库集群 │ │ 消息队列 │
|
||||
│ (Redis) │ │ (MySQL分库分表)│ │ (Kafka) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌─────────────────────┼───────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 搜索引擎 │ │ 图数据库 │ │ 数据仓库 │
|
||||
│ (Elasticsearch)│ │ (Neo4j) │ │ (ClickHouse) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### 关键组件
|
||||
|
||||
#### 1. 流量层
|
||||
- **负载均衡**:Nginx L7负载均衡
|
||||
- **API网关**:请求路由、限流、认证
|
||||
- **CDN加速**:静态资源缓存
|
||||
|
||||
#### 2. 服务层
|
||||
- **Feed服务**:信息流生成和分发
|
||||
- **互动服务**:点赞、评论、分享处理
|
||||
- **推荐服务**:个性化推荐算法
|
||||
- **社交服务**:关系管理
|
||||
|
||||
#### 3. 存储层
|
||||
- **Redis集群**:缓存、计数器
|
||||
- **MySQL集群**:用户数据、内容数据
|
||||
- **MongoDB集群**:Feed流数据
|
||||
- **图数据库**:社交关系数据
|
||||
|
||||
#### 4. 基础设施
|
||||
- **搜索引擎**:内容全文检索
|
||||
- **消息队列**:异步处理、削峰填谷
|
||||
- **数据仓库**:离线数据分析
|
||||
- **推荐引擎**:机器学习平台
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 用户表
|
||||
```sql
|
||||
CREATE TABLE `feed_user` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`nickname` varchar(50) NOT NULL COMMENT '昵称',
|
||||
`avatar` varchar(255) DEFAULT NULL COMMENT '头像',
|
||||
`gender` tinyint DEFAULT 0 COMMENT '性别',
|
||||
`birthday` date DEFAULT NULL COMMENT '生日',
|
||||
`location` varchar(100) DEFAULT NULL COMMENT '位置',
|
||||
`bio` varchar(255) DEFAULT NULL COMMENT '个人简介',
|
||||
`interests` json DEFAULT NULL COMMENT '兴趣标签',
|
||||
`follow_count` int NOT NULL DEFAULT 0 COMMENT '关注数',
|
||||
`follower_count` int NOT NULL DEFAULT 0 COMMENT '粉丝数',
|
||||
`post_count` int NOT NULL DEFAULT 0 COMMENT '发布数',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 内容表
|
||||
```sql
|
||||
CREATE TABLE `feed_content` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`content_id` varchar(64) NOT NULL COMMENT '内容ID',
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`content_type` tinyint NOT NULL COMMENT '内容类型',
|
||||
`title` varchar(255) DEFAULT NULL COMMENT '标题',
|
||||
`content` text NOT NULL COMMENT '内容',
|
||||
`media_urls` json DEFAULT NULL COMMENT '媒体URLs',
|
||||
`tags` json DEFAULT NULL COMMENT '标签',
|
||||
`like_count` int NOT NULL DEFAULT 0 COMMENT '点赞数',
|
||||
`comment_count` int NOT NULL DEFAULT 0 COMMENT '评论数',
|
||||
`share_count` int NOT NULL DEFAULT 0 COMMENT '分享数',
|
||||
`view_count` int NOT NULL DEFAULT 0 COMMENT '浏览数',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_content_id` (`content_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_created_at` (`created_at`),
|
||||
FULLTEXT KEY `idx_content` (`title`, `content`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 用户关系表
|
||||
```sql
|
||||
CREATE TABLE `feed_relationship` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`follow_user_id` bigint NOT NULL COMMENT '关注用户ID',
|
||||
`relation_type` tinyint NOT NULL DEFAULT 1 COMMENT '关系类型',
|
||||
`strength` decimal(5,2) DEFAULT '0.00' COMMENT '关系强度',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_follow` (`user_id`, `follow_user_id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_follow_user_id` (`follow_user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### Feed流表
|
||||
```sql
|
||||
CREATE TABLE `feed_stream` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`content_id` varchar(64) NOT NULL COMMENT '内容ID',
|
||||
`feed_type` tinyint NOT NULL COMMENT 'Feed类型',
|
||||
`priority` decimal(10,4) NOT NULL DEFAULT '0.0000' COMMENT '优先级',
|
||||
`is_read` tinyint NOT NULL DEFAULT 0 COMMENT '是否已读',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_priority` (`priority`),
|
||||
KEY `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 互动记录表
|
||||
```sql
|
||||
CREATE TABLE `feed_interaction` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`target_user_id` bigint DEFAULT NULL COMMENT '目标用户ID',
|
||||
`content_id` varchar(64) DEFAULT NULL COMMENT '内容ID',
|
||||
`interaction_type` tinyint NOT NULL COMMENT '互动类型',
|
||||
`content` text DEFAULT NULL COMMENT '互动内容',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_target_user_id` (`target_user_id`),
|
||||
KEY `idx_content_id` (`content_id`),
|
||||
KEY `idx_created_at` (`created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### Redis缓存设计
|
||||
```typescript
|
||||
// 用户信息缓存
|
||||
const USER_INFO_PREFIX = 'user:';
|
||||
const USER_INFO_TTL = 3600; // 1小时
|
||||
|
||||
// 内容信息缓存
|
||||
const CONTENT_INFO_PREFIX = 'content:';
|
||||
const CONTENT_INFO_TTL = 86400; // 24小时
|
||||
|
||||
// Feed流缓存
|
||||
const FEED_STREAM_PREFIX = 'feed:';
|
||||
const FEED_STREAM_TTL = 1800; // 30分钟
|
||||
|
||||
// 互动计数器
|
||||
const INTERACTION_PREFIX = 'interaction:';
|
||||
const INTERACTION_TTL = 300; // 5分钟
|
||||
|
||||
// 推荐结果缓存
|
||||
const RECOMMEND_PREFIX = 'recommend:';
|
||||
const RECOMMEND_TTL = 300; // 5分钟
|
||||
|
||||
// 社交关系缓存
|
||||
const RELATION_PREFIX = 'relation:';
|
||||
const RELATION_TTL = 3600; // 1小时
|
||||
```
|
||||
|
||||
### 缓存策略
|
||||
1. **多级缓存**:
|
||||
- 本地缓存:Caffeine
|
||||
- 分布式缓存:Redis Cluster
|
||||
- CDN缓存:静态资源
|
||||
|
||||
2. **缓存更新策略**:
|
||||
- Write Behind:异步更新
|
||||
- Refresh Ahead:预加载热点数据
|
||||
- Cache Invalidation:定时失效
|
||||
|
||||
3. **Feed流缓存**:
|
||||
- 分页缓存
|
||||
- 用户个性化缓存
|
||||
- 实时更新策略
|
||||
|
||||
### Feed流生成算法
|
||||
```java
|
||||
public class FeedGenerator {
|
||||
|
||||
// 基于时间线的基础Feed
|
||||
public List<FeedItem> generateTimelineFeed(String userId, int offset, int limit) {
|
||||
// 从Redis获取用户关注列表
|
||||
List<String> followUsers = getFollowUsers(userId);
|
||||
|
||||
// 获取关注用户的最新内容
|
||||
List<FeedItem> feeds = new ArrayList<>();
|
||||
for (String followUser : followUsers) {
|
||||
List<FeedItem> userFeeds = getUserRecentFeeds(followUser, offset, limit / followUsers.size());
|
||||
feeds.addAll(userFeeds);
|
||||
}
|
||||
|
||||
// 按时间排序
|
||||
return feeds.stream()
|
||||
.sorted(Comparator.comparing(FeedItem::getCreatedAt).reversed())
|
||||
.skip(offset)
|
||||
.limit(limit)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 个性化推荐Feed
|
||||
public List<FeedItem> generateRecommendFeed(String userId, int offset, int limit) {
|
||||
// 获取用户兴趣标签
|
||||
List<String> interests = getUserInterests(userId);
|
||||
|
||||
// 基于协同过滤推荐内容
|
||||
List<String> recommendContentIds = collaborativeFiltering(userId, interests);
|
||||
|
||||
// 基于内容的推荐
|
||||
List<String> contentBasedRecommend = contentBasedRecommend(userId);
|
||||
|
||||
// 合并推荐结果
|
||||
Set<String> allRecommend = new HashSet<>();
|
||||
allRecommend.addAll(recommendContentIds);
|
||||
allRecommend.addAll(contentBasedRecommend);
|
||||
|
||||
// 获取推荐内容详情
|
||||
List<FeedItem> feeds = getContentDetails(new ArrayList<>(allRecommend));
|
||||
|
||||
// 排序并返回
|
||||
return feeds.stream()
|
||||
.sorted(Comparator.comparing(FeedItem::getScore).reversed())
|
||||
.skip(offset)
|
||||
.limit(limit)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 混合Feed流
|
||||
public List<FeedItem> generateHybridFeed(String userId, int offset, int limit) {
|
||||
List<FeedItem> timelineFeeds = generateTimelineFeed(userId, 0, limit / 2);
|
||||
List<FeedItem> recommendFeeds = generateRecommendFeed(userId, 0, limit / 2);
|
||||
|
||||
// 合并并去重
|
||||
Set<String> seenContentIds = new HashSet<>();
|
||||
List<FeedItem> result = new ArrayList<>();
|
||||
|
||||
for (FeedItem feed : timelineFeeds) {
|
||||
if (!seenContentIds.contains(feed.getContentId())) {
|
||||
result.add(feed);
|
||||
seenContentIds.add(feed.getContentId());
|
||||
}
|
||||
}
|
||||
|
||||
for (FeedItem feed : recommendFeeds) {
|
||||
if (!seenContentIds.contains(feed.getContentId())) {
|
||||
result.add(feed);
|
||||
seenContentIds.add(feed.getContentId());
|
||||
}
|
||||
}
|
||||
|
||||
// 按权重排序
|
||||
return result.stream()
|
||||
.sorted(Comparator.comparing(FeedItem::getScore).reversed())
|
||||
.skip(offset)
|
||||
.limit(limit)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展性考虑
|
||||
|
||||
### 1. 水平扩展
|
||||
- **无状态服务**:Feed服务、推荐服务无状态化
|
||||
- **数据分片**:按用户ID分片
|
||||
- **读写分离**:主库写入,从库读取
|
||||
|
||||
### 2. 垂直扩展
|
||||
- **服务拆分**:Feed服务、推荐服务、互动服务
|
||||
- **数据分层**:热数据、温数据、冷数据
|
||||
- **多级缓存**:本地、Redis、CDN
|
||||
|
||||
### 3. 推荐算法扩展
|
||||
- **实时推荐**:基于实时行为更新
|
||||
- **离线推荐**:批量处理推荐结果
|
||||
- **冷启动**:新用户推荐策略
|
||||
|
||||
### 4. 容灾备份
|
||||
- **多活架构**:多机房部署
|
||||
- **故障转移**:自动故障检测和转移
|
||||
- **数据备份**:定时备份和实时同步
|
||||
|
||||
## 实际项目经验
|
||||
|
||||
### 1. 技术栈选择
|
||||
- **前端**:React + TypeScript + Mobile
|
||||
- **后端**:Spring Boot + Node.js + Python
|
||||
- **数据库**:MySQL + MongoDB + Redis
|
||||
- **消息队列**:Kafka + Pulsar
|
||||
- **搜索引擎**:Elasticsearch + ClickHouse
|
||||
|
||||
### 2. 性能优化
|
||||
- **Feed缓存**:多级缓存策略
|
||||
- **数据库优化**:分库分表、索引优化
|
||||
- **算法优化**:推荐算法优化
|
||||
- **网络优化**:HTTP/2、Keep-Alive
|
||||
|
||||
### 3. 运维部署
|
||||
- **容器化**:Docker + Kubernetes
|
||||
- **CI/CD**:Jenkins + GitLab
|
||||
- **监控告警**:ELK Stack + AlertManager
|
||||
- **压测**:JMeter + Locust
|
||||
|
||||
### 4. 安全设计
|
||||
- **内容安全**:内容审核、过滤
|
||||
- **用户隐私**:数据脱敏、权限控制
|
||||
- **防刷机制**:频率限制、行为分析
|
||||
|
||||
## 阿里P7加分项
|
||||
|
||||
### 1. 架构设计能力
|
||||
- **高可用架构**:99.99%可用性
|
||||
- **高性能架构**:支持亿级QPS
|
||||
- **扩展性架构**:弹性扩缩容
|
||||
|
||||
### 2. 技术深度
|
||||
- **推荐系统**:协同过滤、深度学习
|
||||
- **实时计算**:Flink、Kafka Streams
|
||||
- **图算法**:社交图谱、关系计算
|
||||
|
||||
### 3. 业务理解
|
||||
- **社交业务**:理解社交网络特性
|
||||
- **用户行为**:分析用户互动模式
|
||||
- **内容生态**:掌握内容分发逻辑
|
||||
|
||||
### 4. 团队管理
|
||||
- **技术团队**:带领50人+团队
|
||||
- **项目管控**:管理亿级用户项目
|
||||
- **技术方案**:主导架构设计
|
||||
|
||||
### 5. 前沿技术
|
||||
- **AI应用**:智能推荐、内容生成
|
||||
- **边缘计算**:边缘节点处理
|
||||
- **Serverless**:函数化服务
|
||||
|
||||
## 面试常见问题
|
||||
|
||||
### 1. 如何生成个性化信息流?
|
||||
- **用户画像**:用户兴趣建模
|
||||
- **推荐算法**:协同过滤、基于内容
|
||||
- **实时更新**:实时行为追踪
|
||||
- **多目标优化**:点击率、停留时间
|
||||
|
||||
### 2. 如何处理高并发Feed请求?
|
||||
- **缓存策略**:多级缓存
|
||||
- **数据预加载**:Feed预生成
|
||||
- **异步处理**:异步更新
|
||||
- **分页优化**:游标分页
|
||||
|
||||
### 3. 如何保证Feed流实时性?
|
||||
- **实时推送**:WebSocket推送
|
||||
- **增量更新**:实时增量计算
|
||||
- **事件驱动**:事件总线
|
||||
- **缓存预热**:热点数据预热
|
||||
|
||||
### 4. 如何实现推荐算法?
|
||||
- **协同过滤**:用户行为相似度
|
||||
- **内容分析**:内容特征提取
|
||||
- **深度学习**:神经网络模型
|
||||
- **多臂老虎机**:探索与利用
|
||||
|
||||
### 5. 如何处理海量数据?
|
||||
- **分库分表**:按用户ID分片
|
||||
- **数据归档**:冷热数据分离
|
||||
- **缓存优化**:热点数据缓存
|
||||
- **计算优化**:批量处理、并行计算
|
||||
318
questions/07-系统设计/秒杀系统设计.md
Normal file
318
questions/07-系统设计/秒杀系统设计.md
Normal file
@@ -0,0 +1,318 @@
|
||||
# 秒杀系统设计
|
||||
|
||||
## 需求分析和数据量评估
|
||||
|
||||
### 需求分析
|
||||
- **核心功能**:商品秒杀、库存管理、下单支付、用户限流
|
||||
- **业务场景**:双十一、618等大促活动,商品短时间内高并发抢购
|
||||
- **QPS评估**:假设10万用户同时抢购,QPS可达10万+
|
||||
- **峰值预期**:高峰期QPS可达50万+
|
||||
- **数据规模**:商品10万+,用户1000万+,订单日峰值1亿+
|
||||
|
||||
### 数据量评估
|
||||
- **商品表**:10万条,日均查询100万次
|
||||
- **库存表**:10万条,秒杀期间读写10万+/秒
|
||||
- **订单表**:日峰值1亿条,历史数据10亿+
|
||||
- **用户表**:1000万条,日均查询500万次
|
||||
- **Redis缓存**:商品信息100万条,库存信息10万条
|
||||
|
||||
## 核心技术难点
|
||||
|
||||
### 1. 高并发库存管理
|
||||
- 传统数据库锁无法支撑高并发
|
||||
- 需要分布式锁配合缓存实现
|
||||
- 库存扣减的原子性问题
|
||||
|
||||
### 2. 超卖问题
|
||||
- 库存与订单不一致
|
||||
- 需要最终一致性保证
|
||||
- 重复下单处理
|
||||
|
||||
### 3. 限流策略
|
||||
- 全局限流、用户限流、商品限流
|
||||
- 限流算法选择(令牌桶、漏桶)
|
||||
- 限流后的用户体验
|
||||
|
||||
### 4. 数据一致性
|
||||
- 缓存与数据库的一致性
|
||||
- 分布式事务处理
|
||||
- 幂等性保证
|
||||
|
||||
## 系统架构设计
|
||||
|
||||
### 总体架构
|
||||
```
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ CDN/Static │ │ Load Balance │ │ API Gateway │
|
||||
│ Cache │◄──►│ (Nginx) │◄──►│ (Gateway) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│
|
||||
┌───────────────────────────────────┼───────────────────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ 业务服务 │ │ 业务服务 │ │ 业务服务 │
|
||||
│ (微服务) │ │ (微服务) │ │ (微服务) │
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
│ │ │
|
||||
└───────────────────────────────────┼───────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────────────────────┼───────────────────────────────────┐
|
||||
│ │ │
|
||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||
│ Redis集群 │ │ 消息队列 │ │ 数据库集群 │
|
||||
│ (缓存+分布式锁)│ │ (Kafka/RocketMQ)│ │ (MySQL分库分表)│
|
||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
### 关键组件
|
||||
|
||||
#### 1. 流量层
|
||||
- **CDN**:静态资源加速
|
||||
- **Web服务器**:Nginx负载均衡
|
||||
- **API网关**:限流、路由、认证
|
||||
|
||||
#### 2. 服务层
|
||||
- **秒杀服务**:核心业务逻辑
|
||||
- **订单服务**:订单处理
|
||||
- **库存服务**:库存管理
|
||||
- **支付服务**:支付处理
|
||||
|
||||
#### 3. 存储层
|
||||
- **Redis集群**:缓存和分布式锁
|
||||
- **数据库集群**:MySQL分库分表
|
||||
- **消息队列**:异步处理
|
||||
|
||||
#### 4. 监控层
|
||||
- **监控系统**:实时监控
|
||||
- **告警系统**:异常告警
|
||||
- **日志系统**:业务日志
|
||||
|
||||
## 数据库设计
|
||||
|
||||
### 商品表
|
||||
```sql
|
||||
CREATE TABLE `seckill_product` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`product_id` bigint NOT NULL COMMENT '商品ID',
|
||||
`product_name` varchar(255) NOT NULL COMMENT '商品名称',
|
||||
`product_desc` text COMMENT '商品描述',
|
||||
`original_price` decimal(10,2) NOT NULL COMMENT '原价',
|
||||
`seckill_price` decimal(10,2) NOT NULL COMMENT '秒杀价',
|
||||
`stock_count` int NOT NULL COMMENT '库存数量',
|
||||
`seckill_count` int NOT NULL DEFAULT 0 COMMENT '已秒杀数量',
|
||||
`start_time` datetime NOT NULL COMMENT '开始时间',
|
||||
`end_time` datetime NOT NULL COMMENT '结束时间',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_product_id` (`product_id`),
|
||||
KEY `idx_start_time` (`start_time`),
|
||||
KEY `idx_end_time` (`end_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 订单表
|
||||
```sql
|
||||
CREATE TABLE `seckill_order` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`order_no` varchar(64) NOT NULL COMMENT '订单号',
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`product_id` bigint NOT NULL COMMENT '商品ID',
|
||||
`product_name` varchar(255) NOT NULL COMMENT '商品名称',
|
||||
`seckill_price` decimal(10,2) NOT NULL COMMENT '秒杀价',
|
||||
`status` tinyint NOT NULL DEFAULT 0 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_order_no` (`order_no`),
|
||||
KEY `idx_user_id` (`user_id`),
|
||||
KEY `idx_product_id` (`product_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
### 用户表
|
||||
```sql
|
||||
CREATE TABLE `seckill_user` (
|
||||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint NOT NULL COMMENT '用户ID',
|
||||
`username` varchar(50) NOT NULL COMMENT '用户名',
|
||||
`email` varchar(100) NOT NULL COMMENT '邮箱',
|
||||
`phone` varchar(20) NOT NULL COMMENT '手机号',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态',
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_user_id` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
```
|
||||
|
||||
## 缓存策略
|
||||
|
||||
### Redis缓存设计
|
||||
```typescript
|
||||
// 商品信息缓存
|
||||
const PRODUCT_CACHE_PREFIX = 'product:';
|
||||
const PRODUCT_CACHE_TTL = 3600; // 1小时
|
||||
|
||||
// 库存缓存
|
||||
const STOCK_CACHE_PREFIX = 'stock:';
|
||||
const STOCK_CACHE_TTL = 300; // 5分钟
|
||||
|
||||
// 分布式锁
|
||||
const LOCK_PREFIX = 'lock:';
|
||||
const LOCK_TTL = 10; // 10秒
|
||||
|
||||
// 用户限流
|
||||
const RATE_LIMIT_PREFIX = 'rate_limit:';
|
||||
const RATE_LIMIT_TTL = 1; // 1秒
|
||||
```
|
||||
|
||||
### 缓存策略
|
||||
1. **多级缓存**:
|
||||
- CDN缓存静态资源
|
||||
- Redis缓存热点数据
|
||||
- 本地缓存减少网络IO
|
||||
|
||||
2. **缓存更新策略**:
|
||||
- 主动更新:秒杀开始前预加载
|
||||
- 异步更新:异步刷新数据库
|
||||
- 失效策略:设置合理的TTL
|
||||
|
||||
3. **缓存预热**:
|
||||
- 秒杀开始前加载商品信息
|
||||
- 预热库存信息到Redis
|
||||
- 预加载热门商品
|
||||
|
||||
### 分布式锁实现
|
||||
```java
|
||||
public boolean acquireDistributedLock(String lockKey, String requestId, long expireTime) {
|
||||
String result = redisTemplate.opsForValue().set(
|
||||
lockKey,
|
||||
requestId,
|
||||
expireTime,
|
||||
TimeUnit.MILLISECONDS
|
||||
);
|
||||
return "OK".equals(result);
|
||||
}
|
||||
|
||||
public boolean releaseDistributedLock(String lockKey, String requestId) {
|
||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
|
||||
"return redis.call('del', KEYS[1]) " +
|
||||
"else " +
|
||||
"return 0 " +
|
||||
"end";
|
||||
Long result = redisTemplate.execute(new DefaultRedisScript<>(script, Long.class),
|
||||
Collections.singletonList(lockKey),
|
||||
requestId);
|
||||
return result != null && result > 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 扩展性考虑
|
||||
|
||||
### 1. 水平扩展
|
||||
- **无状态服务**:服务实例可以水平扩展
|
||||
- **数据分片**:按商品ID分片
|
||||
- **读写分离**:主库写入,从库读取
|
||||
|
||||
### 2. 垂直扩展
|
||||
- **服务拆分**:按业务域拆分微服务
|
||||
- **数据分层**:热数据、温数据、冷数据分离
|
||||
- **缓存层扩展**:Redis集群扩容
|
||||
|
||||
### 3. 异步处理
|
||||
- **消息队列**:订单处理异步化
|
||||
- **事件驱动**:使用事件总线
|
||||
- **最终一致性**:保证数据最终一致
|
||||
|
||||
### 4. 容灾备份
|
||||
- **多活架构**:多机房部署
|
||||
- **故障转移**:自动故障检测和转移
|
||||
- **数据备份**:定时备份和实时同步
|
||||
|
||||
## 实际项目经验
|
||||
|
||||
### 1. 技术栈选择
|
||||
- **前端**:Vue.js + React
|
||||
- **后端**:Spring Boot + Node.js
|
||||
- **数据库**:MySQL + Redis
|
||||
- **缓存**:Redis Cluster
|
||||
- **消息队列**:Kafka
|
||||
- **监控**:Prometheus + Grafana
|
||||
|
||||
### 2. 性能优化
|
||||
- **JVM调优**:调整堆大小和GC策略
|
||||
- **MySQL优化**:索引优化、慢SQL优化
|
||||
- **Redis优化**:集群扩容、内存优化
|
||||
- **网络优化**:连接池配置、超时设置
|
||||
|
||||
### 3. 运维部署
|
||||
- **容器化**:Docker + Kubernetes
|
||||
- **CI/CD**:Jenkins + GitLab
|
||||
- **监控告警**:ELK Stack + AlertManager
|
||||
- **压测工具**:JMeter + Locust
|
||||
|
||||
### 4. 灰度发布
|
||||
- **蓝绿部署**:无缝切换
|
||||
- **金丝雀发布**:逐步放量
|
||||
- **流量控制**:按比例分配流量
|
||||
|
||||
## 阿里P7加分项
|
||||
|
||||
### 1. 架构设计能力
|
||||
- **高可用架构**:设计99.99%可用性的系统
|
||||
- **高性能架构**:支持百万级QPS
|
||||
- **高扩展架构**:支持弹性扩缩容
|
||||
|
||||
### 2. 技术深度
|
||||
- **分布式事务**:Seata、TCC、Saga
|
||||
- **分布式缓存**:Redis集群、一致性哈希
|
||||
- **分布式锁**:Redis、Zookeeper、Etcd
|
||||
|
||||
### 3. 业务理解
|
||||
- **电商业务**:理解秒杀业务场景
|
||||
- **用户行为**:分析用户抢购习惯
|
||||
- **风控系统**:防刷、防作弊机制
|
||||
|
||||
### 4. 团队管理
|
||||
- **技术团队**:带领10人+技术团队
|
||||
- **项目管控**:管理千万级用户项目
|
||||
- **技术方案评审**:评审核心技术方案
|
||||
|
||||
### 5. 前沿技术
|
||||
- **Serverless**:秒杀函数化
|
||||
- **云原生**:K8s微服务架构
|
||||
- **AI应用**:智能推荐、风控
|
||||
|
||||
## 面试常见问题
|
||||
|
||||
### 1. 秒杀系统如何防止超卖?
|
||||
- 使用Redis预减库存
|
||||
- 分布式锁控制并发
|
||||
- 数据库唯一约束
|
||||
- 消息队列异步处理
|
||||
|
||||
### 2. 如何实现限流策略?
|
||||
- 令牌桶算法
|
||||
- 漏桶算法
|
||||
- Redis计数器
|
||||
- Nginx限流模块
|
||||
|
||||
### 3. 分布式锁的实现方式?
|
||||
- Redis RedLock
|
||||
- Zookeeper
|
||||
- Etcd
|
||||
- 数据库悲观锁
|
||||
|
||||
### 4. 如何保证数据一致性?
|
||||
- 最终一致性
|
||||
- 消息队列补偿
|
||||
- 定时任务对账
|
||||
- 幂等性设计
|
||||
|
||||
### 5. 秒杀系统的瓶颈在哪里?
|
||||
- 库存查询
|
||||
- 下单逻辑
|
||||
- 支付处理
|
||||
- 库存同步
|
||||
166
questions/07-系统设计/系统设计方法论.md
Normal file
166
questions/07-系统设计/系统设计方法论.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# 系统设计方法论
|
||||
|
||||
## 问题
|
||||
|
||||
1. 系统设计的核心原则是什么?
|
||||
2. 如何进行需求分析?
|
||||
3. 如何估算系统容量?
|
||||
4. 数据模型设计有哪些最佳实践?
|
||||
5. 如何设计高可用架构?
|
||||
|
||||
---
|
||||
|
||||
## 标准答案
|
||||
|
||||
### 1. 系统设计原则
|
||||
|
||||
**核心原则**:
|
||||
1. **简单性**(KISS:Keep It Simple, Stupid)
|
||||
2. **模块化**(高内聚、低耦合)
|
||||
3. **可扩展性**(水平扩展、垂直扩展)
|
||||
4. **高可用性**(冗余、故障隔离)
|
||||
5. **一致性**(CAP 理论权衡)
|
||||
|
||||
---
|
||||
|
||||
### 2. 需求分析
|
||||
|
||||
**功能需求**:
|
||||
- 系统做什么?
|
||||
- 用户角色有哪些?
|
||||
- 核心流程是什么?
|
||||
|
||||
**非功能需求**:
|
||||
- **性能**:QPS、响应时间
|
||||
- **可用性**:99.9%、99.99%、99.999%
|
||||
- **扩展性**:支持多少用户
|
||||
- **安全性**:认证、授权、加密
|
||||
- **一致性**:强一致、最终一致
|
||||
|
||||
---
|
||||
|
||||
### 3. 容量估算
|
||||
|
||||
**QPS 估算**:
|
||||
```
|
||||
日活用户(DAU):100 万
|
||||
平均每人每天请求:20 次
|
||||
总 QPS = 100 万 × 20 / 86400 ≈ 231 QPS
|
||||
峰值 QPS = 231 × 5 ≈ 1155 QPS(假设峰值是平均的 5 倍)
|
||||
```
|
||||
|
||||
**存储估算**:
|
||||
```
|
||||
用户数:100 万
|
||||
每人平均数据:1 KB
|
||||
总存储 = 100 万 × 1 KB ≈ 1 GB
|
||||
每年增长 = 1 GB × 12 = 12 GB
|
||||
```
|
||||
|
||||
**带宽估算**:
|
||||
```
|
||||
平均响应大小:10 KB
|
||||
QPS:1000
|
||||
带宽 = 1000 × 10 KB × 8 = 80 Mbps
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. 数据模型设计
|
||||
|
||||
**原则**:
|
||||
1. **范式化**(减少冗余)
|
||||
2. **反范式化**(提高性能)
|
||||
3. **分区**(水平、垂直)
|
||||
4. **索引**(加速查询)
|
||||
|
||||
**示例**:
|
||||
```sql
|
||||
-- 范式化(3NF)
|
||||
CREATE TABLE users (
|
||||
id BIGINT PRIMARY KEY,
|
||||
name VARCHAR(50),
|
||||
email VARCHAR(100)
|
||||
);
|
||||
|
||||
CREATE TABLE orders (
|
||||
id BIGINT PRIMARY KEY,
|
||||
user_id BIGINT,
|
||||
amount DECIMAL(10,2),
|
||||
created_at DATETIME,
|
||||
FOREIGN KEY (user_id) REFERENCES users(id)
|
||||
);
|
||||
|
||||
-- 反范式化(冗余用户名,避免 JOIN)
|
||||
CREATE TABLE orders_denormalized (
|
||||
id BIGINT PRIMARY KEY,
|
||||
user_id BIGINT,
|
||||
user_name VARCHAR(50), -- 冗余
|
||||
amount DECIMAL(10,2),
|
||||
created_at DATETIME
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 高可用架构
|
||||
|
||||
**冗余设计**:
|
||||
```
|
||||
┌─────────────┐
|
||||
│ 负载均衡 │ (Nginx、HAProxy)
|
||||
└──────┬──────┘
|
||||
│
|
||||
┌─────────┼─────────┐
|
||||
│ │ │
|
||||
┌──▼──┐ ┌──▼──┐ ┌──▼──┐
|
||||
│App 1│ │App 2│ │App 3│
|
||||
└──┬──┘ └──┬──┘ └──┬──┘
|
||||
│ │ │
|
||||
└─────────┼─────────┘
|
||||
│
|
||||
┌──────▼──────┐
|
||||
│ 主从数据库 │
|
||||
│ Master │
|
||||
│ Slave │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
**故障隔离**:
|
||||
- 熔断器(Circuit Breaker)
|
||||
- 限流(Rate Limiter)
|
||||
- 降级(Fallback)
|
||||
- 舱舱模式(Bulkhead)
|
||||
|
||||
---
|
||||
|
||||
### 6. 扩展性设计
|
||||
|
||||
**垂直扩展(Scale Up)**:
|
||||
- 升级硬件(CPU、内存、磁盘)
|
||||
- 简单、快速
|
||||
- 有上限(硬件限制)
|
||||
|
||||
**水平扩展(Scale Out)**:
|
||||
- 增加机器数量
|
||||
- 无限扩展
|
||||
- 需要架构支持(无状态、数据分片)
|
||||
|
||||
---
|
||||
|
||||
### 7. 阿里 P7 加分项
|
||||
|
||||
**架构思维**:
|
||||
- 能进行技术选型(权衡各种方案)
|
||||
- 能进行容量规划(预估资源需求)
|
||||
- 能进行成本控制(性价比优化)
|
||||
|
||||
**设计能力**:
|
||||
- 能设计高并发架构
|
||||
- 能设计高可用架构
|
||||
- 能设计可扩展架构
|
||||
|
||||
**沟通能力**:
|
||||
- 能清晰地表达设计方案
|
||||
- 能进行技术方案评审
|
||||
- 能推动方案落地
|
||||
Reference in New Issue
Block a user