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:
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过滤
|
||||
- **批量计算**:向量运算优化
|
||||
- **缓存机制**:距离结果缓存
|
||||
Reference in New Issue
Block a user