Files
interview/questions/design-lbs.md
yasinshaw 71e3497bfd feat: add comprehensive system design interview questions
- design-seckill.md: 秒杀系统设计
- design-shorturl.md: 短链接系统设计
- design-lbs.md: LBS附近的人系统设计
- design-im.md: 即时通讯系统设计
- design-feed.md: 社交信息流系统设计

Each document includes:
- Requirements analysis and data volume assessment
- Technical challenges
- System architecture design
- Database design
- Caching strategies
- Scalability considerations
- Practical project experience
- Alibaba P7 level additional points

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-28 23:43:36 +08:00

14 KiB
Raw Blame History

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
  • 地图服务:地图渲染和展示

数据库设计

用户位置表

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;

位置历史表

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;

地理索引表

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;

好友关系表

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缓存设计

// 用户位置缓存
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实现

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/CDJenkins + 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过滤
  • 批量计算:向量运算优化
  • 缓存机制:距离结果缓存