常见面试题汇总1

1.如何设计直播间百万并发弹幕系统?

1.1> 系统架构

               ┌────────────────────┐
               │    直播业务后台     │
               └────────▲───────────┘
                        │
                鉴权/限流/封号/内容策略
                        │
 ┌────────┐      ┌──────┴──────┐        ┌────────────┐
 │ 观众A   │◀────▶│ WebSocket网关│◀──────▶ Redis Pub/Sub │
 │ 观众B   │      └──────▲──────┘        └────▲───────┘
 │ 观众C   │             │                   │
 └────────┘      推送分发层              推流广播层
                 (百万长连接)            (按直播间维度分片)

                        │
                        ▼
                 弹幕存储写入服务(Kafka)
                        │
                        ▼
                 内容审核 + 数据入库

1.2  WebSocket 网关(长连接服务)

每个客户端与服务端建立一个 WebSocket 长连接。

网关层做:用户认证、维持心跳、限流、消息路由。

可使用高性能框架如:Go:gnet、gws

单台机器可支撑 10~20 万连接;配合负载均衡(如 LVS)轻松支撑百万连接。

1.3 弹幕广播

观众发送弹幕

WebSocket 网关接收

写入 Kafka topic(用于异步存储 + 内容审核)

通过 Redis Pub/Sub(或自研推流服务)推送至同直播间所有用户

1.4 消息推送优化

优化点 说明
直播间分片 每个直播间一个广播频道 live_room:123,推送范围精准
热点弹幕合并 “666”、“牛逼” 被多用户发送时,合并为一条弹幕显示“666 x82”
弹幕压缩协议 使用 msgpack / protobuf 编码,节省带宽与反序列化成本
静默用户不推送 长时间无操作或挂后台的用户暂时暂停推送节流

1.5 内容审核 & 消息入库

发弹幕 → 立即异步发送到 Kafka 进行日志采集、内容审核。

1.6 难点优化

问题 解决方案
弹幕太多渲染卡顿 前端轨道限流 + 粒度动态调整(B 站也有“节流弹幕”策略)
高并发压力大 弹幕写入异步(Kafka),广播走内存(Redis)
网络波动 WebSocket 客户端自动重连,带 offset 恢复弹幕
弹幕刷屏 / 灌水 UID/IP 限速 + 抽样上报 + 黑名单封禁

1.7 总结

WebSocket 长连接网关 支持百万连接。

实时弹幕不查库,全走 Redis Pub/Sub 或自研推流服务。

异步内容审核,不影响实时性。

直播间分片广播,精准推送、减少带宽。

前端限流+合并渲染,提升客户端流畅度。

弹性扩展架构,支撑随直播爆发的百万级增长。

2.实现24小时内短视频播放量Top 200的实时榜单,数据量级3亿用户+100万作品,要求延迟<1分钟,如何设计?

2.1 架构设计

[客户端播放] → [Kafka] → [Flink 计算] → [Redis 实时榜单] ← [前端查询]

滚动窗口 + 状态计算

2.2 客户端埋点 -> 写入kafka

客户端上报播放行为: 包括 user_id、video_id、播放时间戳等

上报到 Kafka 各个分区: Kafka 支持高并发写入,作为流式入口

2.3 实时计算 Flink/spark streaming

1> 核心实现逻辑

2.3.1 使用 滑动窗口(滑动时间窗口 Sliding Window)

窗口大小:24小时

滑动间隔:30秒或1分钟

2.3.2 基于 video_id 做聚合:每个 video_id 的播放量(过去24小时)

2.3.3 排序取 Top 200:

Flink 内部可用 KeyedProcessFunction + Windowed Stream 实现排序逻辑

也可以将分区 TopK 合并再全局 TopK(两层排序)

2> 滚动窗口 实现细节

使用 Flink 的 Event Time + Watermark 保证事件时间排序

避免乱序数据影响精度

2.4 存储状态查询 redis zset 存储实时榜单

实时 Top200 榜单写入 Redis: ZADD rank <video_id>

设置定期过期,保持榜单更新

每次榜单变更触发更新:ZREVRANGE rank 0 199 WITHSCORES

2.5 技术选型总结

模块 技术 说明
数据采集 Kafka 高吞吐数据流管道
实时计算 Flink 滑动窗口+聚合+TopK
存储缓存 Redis SortedSet 高速实时查询
历史数据 HBase / ClickHouse 支持历史回查
可视化接口 Nginx + API Server 提供榜单查询接口

2.6 结构图

图片

3.双机房容灾下,如何保证数据库主从切换时数据一致性?若切换后出现数据重复/丢失如何修复?

3.1 架构选型对比

架构类型 一致性等级 主从切换代价 是否易丢数据
异步复制(MySQL 默认) 最弱 只写主库 不等从库同步, 就返回结果 速度快,但有数据丢失风险 ✅ 有丢失风险
半同步复制(semi-sync) 中等 写成功要同步至少一个从库 才返回结果 ⛔️ 减少丢失风险
强同步复制(双写确认) 强一致 慢 等待全部从库同步成功 最后返回结果 ❌ 几乎无丢失风险(但影响写性能)
多主架构(例如 Galera Cluster) 自带同步冲突解决机制 ❌ 数据冲突需设计

3.2 如何保证数据的一致性

3.2.1 半同步复制

1> 启用 rpl_semi_sync_master_enabled = 1

2> 要求写操作在返回客户端成功前,必须至少一个从库确认写入

3.2.2 全局幂等

3.2.3 主从延迟监控:切换前强制确认 binlog 已同步

3.2.4 使用 GTID(全局事务 ID)追踪同步进度

3.3 数据丢失/重复 如何修复

1> 代码层面 利用唯一主键/业务幂等字段,直接忽略重复写

2> 主库写成功但从库未同步 → 切换过去后业务查询不到这条数据

修复方式 说明
Binlog 恢复 读取主库 binlog,将未同步事务重新 replay 到新主库
Kafka/Log Replay 如果业务数据通过 MQ 也发出(如双写 Kafka + DB),可回放事件
业务补偿机制 如订单支付失败 → 由 MQ 定时补偿(超时未到账就回查)
人为修补 最不推荐,但可查日志找回关键业务数据并手动写回

3.4 总结

主从切换想要数据一致,一定要靠:半同步复制 + 应用幂等 + binlog 可追溯 + 业务补偿机制,多层协同来保证。只靠数据库本身是远远不够的。

层级 建议
数据库复制 使用半同步 + GTID + 延迟监控
应用层 幂等设计(全局唯一ID / 幂等校验字段)
切换策略 需监控同步延迟,选举切换脚本确保 binlog flush 完成
异常修复 保留 binlog、MQ、操作日志,具备回放/补偿能力
多活架构(如双主) 加分布式协调机制,避免并发写冲突,强制全局幂等

4.Redis集群支撑10万QPS点赞请求,如何解决热点Key?若Redis仍扛不住,如何降级?

4.1 热key拆分

将一个1个热key 拆分为多个 sub key 然后定时汇总这些sub key即可

假设视频 video:1234 是热点,原先是:
INCR video:1234:like_count

改为 多个子 Key:
slot = hash(user_id) % 10
INCR video:1234:like_count:slot_3

然后定时汇总这10个 Slot 的值即可:
SUM(video:1234:like_count:slot_0 ~ slot_9)

4.2 业务侧 预处理

点赞请求往往是幂等 + 可延迟写,可在应用层做缓冲,解决方案如下:

1> 应用服务器本地维护一个计数器(比如内存Map)

2> 每隔 100ms/1s 将该 Key 的点赞量 flush 到 Redis

3> 或者每累计到 100 次就 flush 一次

4.3 引入MQ 缓冲写入

1> MQ 收到点赞请求,顺序排队

2> 后台消费者异步批量写入 Redis

3> 可控制 Redis 写入速率、防止突刺

4> 缺点是无法立即反馈点赞数,但一般点赞场景允许几秒延迟

4.4 redis 降级策略

4.4.1 只允许读 不允许写

1> 暂时禁止点赞写入,只允许读取现有点赞数(或延迟反馈)

2> 写入可以进入 MQ,延迟处理,或写入日志后补

4.4.2 客户端本地缓存兜底

1> 用户点击点赞后,立即更新本地缓存反馈「已点赞」

2> 前端不依赖 Redis 的实时返回

3> 前端定时 flush 到 Redis

4.4.3 限流

1> 控制点赞请求频率,比如单用户/设备/视频限速

2> 1秒内最多点赞1次;3s内最多点赞3次等

4.5 总结

要解决点赞请求 Redis 扛不住的问题,必须分层解决热点 Key 拆分 + 客户端预聚合 + MQ 异步削峰 + 降级兜底缓存,才能在 10 万 QPS 的压力下保持系统稳定。

优化项 说明
Key 拆分数 10 ~ 100 个 SubKey 效果明显
Redis 设置热点Key TTL 避免内存常驻膨胀
分布式锁 对排行榜、视频统计等操作加入锁避免并发写错乱
使用 Lua 脚本 原子操作点赞 + 去重行为,如 INCRBY + SET

5.MySQL索引失效的十大场景?联合索引 (a,b,c) 在 WHERE b=? AND c=? 时是否生效?为什么?

结论:联合索引生效必须满足最左前缀匹配原则。缺失左侧列时,后续列的索引能力将严重受限或完全失效。

序号 失效场景 示例 关键原因 备注
1 违反最左匹配原则 联合索引 (a,b,c) 下查询 WHERE b=? AND c=? B+树按索引顺序构建,缺失最左列无法定位起始位置 最常见原因
2 索引列进行运算/函数操作 WHERE YEAR(date_col)=2023 索引存储原始值,计算后无法匹配索引树 包括表达式(如 col*2>100)
3 隐式类型转换 索引列 varchar,查询 WHERE str_col=123 MySQL自动转换类型(如字符串转数字),等效于对列用函数 需确保查询值与列类型严格一致
4 使用!=<>操作符 WHERE status != 'active' 非等值查询需扫描大量索引项,优化器可能认为全表扫描更快 高筛选率时可能仍用索引
5 OR****连接非索引列条件 WHERE indexed_col=10 OR non_indexed_col=20 只要 OR 任一条件涉及无索引列,优化器通常放弃索引 可改写为 UNION 分治查询
6 LIKE%****开头 WHERE name LIKE '%abc' 前缀不确定导致无法利用索引有序性 LIKE 'abc%' 可用索引
7 范围查询后的列失效 索引 (a,b,c) 下 WHERE a=10 AND b>20 AND c=30 范围查询(b>20)使后续列(c)在索引中无序 仅范围查询前的列及范围列本身生效
8 IS NULL/IS NOT NULL WHERE age IS NULL 取决于数据分布。若NULL占比高,优化器可能选择全表扫描 非绝对失效,需看统计信息
9 未利用覆盖索引(非直接失效) SELECT * 但查询列未被索引覆盖 需要回表查询完整数据行,当回表代价高时,优化器可能放弃索引 用 SELECT 索引列 可避免回表提升性能

6.短视频评论表设计:需支持分页查询、子评论嵌套、热度排序,如何优化存储与查询性能?

6.1 分页查询:将评论分为主评论表 和 子评论表来分表实现分页查询

6.2 子评论嵌套:要限制 子评论嵌套的深度 加载评论时 采用 懒加载 + 条数限制的方式 来限制每一次用户点击 展示的条数

6.3 热度排序 借助 redis zset 按照点赞+追评 的条数 来实现热门排序

设计方案 分表设计(主评论/子评论分开)
表结构 video_comment_main + video_comment_reply
分页效率 主评论表体积小,分页查询非常快
子评论查询 子评论表专门索引 root_id,查询更快
热点评论写入冲突 热点子评论写入只影响 reply 表
热门评论缓存 主表缓存简单清晰(Sorted Set)
适合场景 数据量大、高并发、复杂业务

7.分布式唯一ID生成方案(雪花算法、Redis Incr)在跨机房场景下的优劣与改进思路?

7.1 常见的唯一ID 生成方案

方案 描述 是否依赖中心服务
雪花算法 (Snowflake) 每台机器本地生成64位ID ❌(本地生成)
Redis Incr / MySQL AutoInc 全局自增值,分配唯一ID ✅(依赖中心)
数据库段式分配(如 Leaf、Tinyid) 从中心获取一段ID段,本地消费 ✅(部分依赖)
UUID/GUID 随机字符串,不适合排序、冗长

7.2 雪花算法 VS Redis Incr

维度 雪花算法(Snowflake) Redis Incr / 全局自增 ID
唯一性 依赖机器ID与时间戳;必须配置合理的节点ID Redis 保证强一致性,自增唯一
性能(吞吐) 本地生成,高并发性能优 QPS 受 Redis 单点瓶颈影响
跨机房支持 ✅ 完全本地生成,无中心依赖 ❌ 网络抖动会影响延迟与一致性
时钟依赖 ⛔ 强依赖系统时钟;时钟回拨会造成重复ID ✅ 不依赖时间
单点风险 无,天然分布式 Redis 单点或主从同步延迟问题
ID趋势排序 ✅ 按时间大致递增 ✅ 递增
容易出错点 机器ID重复、时钟回拨 Redis 崩溃、主从不一致、漂移

7.3 跨机房部署的优化建议

7.3.1 雪花算法

问题 优化建议
多机房机器ID冲突 中心分配机器ID + 持久化
时钟回拨导致 ID 重复 ✅ 加“时钟回拨检测”机制,或使用逻辑时钟
多语言实现不一致 使用标准库(如 Twitter Snowflake 规范)
ID泄露信息(时间戳) 可自定义位设计,去掉时间戳敏感字段

7.3.2 Redis Incr

问题 优化建议
Redis 单点延迟高 ✅ 多 Redis 实例+ 分区 ID 段(如 video 用 R1,user 用 R2)
Redis 跨机房 RTT 高 ✅ 就近接入、Local Redis + 延迟同步中心 Redis
Redis 宕机/主从漂移 ✅ Redis Sentinel 或切主保障;或 Fallback 到本地段号生成器

7.4 使用场景推荐

场景 推荐方案
大型电商、直播平台(多机房高可用) ✅ 雪花算法 + 时钟回拨监控
ID 严格递增、有业务语义 ✅ 段式ID(Leaf/Tinyid) + Redis
高频写入、但不要求严格递增 ✅ 雪花ID本地生成即可
小型系统、低并发、集中部署 ✅ Redis Incr / MySQL 自增足够

8.RabbitMQ脑裂问题如何解决?延迟队列的实现方案(死信队列 vs 插件)有何取舍?

8.1 脑裂的定义 与 触发条件

模块 内容
什么是脑裂 集群发生网络分区时,多个节点都认为自己是主节点,继续处理消息,造成数据不一致
典型触发场景 镜像队列 + 多节点集群 + 网络不稳定或跨机房部署
后果 消息丢失、重复、状态不一致、无法合并数据、集群恢复复杂

8.2 镜像队列 VS Quorum Queue

特性 镜像队列(Mirrored Queue) Quorum 队列(推荐)
数据一致性 弱一致性,依赖主副本同步 强一致性,基于 Raft 协议
容易脑裂 ✅ 是 ❌ 否(自动选主、防脑裂)
数据恢复 手动恢复难 自动选主恢复
支持 RabbitMQ 版本 所有版本 3.8+ 推荐
推荐使用场景 ❌ 已被废弃 ✅ 高可用、重要业务队列

8.3 脑裂处理 配置对比

策略名称 含义 是否推荐 说明
ignore 忽略脑裂,节点继续工作 ❌ 不推荐 容易造成脑裂
autoheal 自动将少数派重启与多数同步 ⚠️ 中性 有恢复风险,适合不要求强一致性的场景
pause_minority 少数派检测到分区时自动暂停自身 ✅ 推荐 安全防脑裂,常配合 Quorum Queue 使用

8.4 防止脑裂部署建议

方法 说明
使用奇数节点(3/5个) 利于多数派判断
节点部署同一局域网 减少网络分区概率
负载均衡+健康检查接入 将生产者/消费者流量指向健康节点(如 Keepalived)
使用 Quorum Queue 根本解决脑裂问题

8.5 死信队列 VS 插件

特性 死信队列 TTL + DLX 延迟插件(x-delayed-message)
是否支持动态延迟 ❌ 不支持,TTL 只能按队列设置 ✅ 支持每条消息自定义 x-delay
插件依赖 ❌ 无,RabbitMQ 原生支持 ✅ 需要安装插件
队列管理成本 高:每个延迟时间要建一个队列 低:一个延迟交换机处理所有延迟
实现复杂度 中等,需要配置 DLX 和 TTL 简单,仅声明一个延迟交换机
精度 中(TTL 到期后处理有延迟波动) 高(由内部定时器调度)
场景适用性 简单定时任务、定长延迟批量消息处理 复杂延迟业务如订单取消/消息重试等

9.如何实现“附近同城”功能?从MySQL到Redis+GEO索引的演进方案?

9.1 什么是 附近同城

功能模块 说明
输入条件 经纬度(latitude, longitude),范围(如3km)
目标输出 某点一定范围内的对象列表(人、店、动态)
排序方式 按距离排序(默认)或热度/评分等综合排序
需求特征 读多写少,实时性高,高并发,近似计算容忍度

9.2 mysql 实现附近同城

使用mysql空间函数 + 索引(如 ST_Distance_Sphere)

SELECT id, name, latitude, longitude,
  ST_Distance_Sphere(
    point(longitude, latitude),
    point(用户经度, 用户纬度)
  ) AS distance
FROM user_location
WHERE distance < 3000
ORDER BY distance
LIMIT 20;
缺点项 说明
查询慢 无法使用普通索引,计算复杂
数据量一大就崩 上万条数据以上性能严重下降
不能实时更新 更新频繁(如用户位置变化)易造成写瓶颈

9.3 Redis GEO 实现

Redis 从 3.2 起支持 GEOADD / GEORADIUS 命令,底层基于 Geohash 前缀压缩 + zset 实现适用于“同城动态”、“附近的人”等近似场景

GEOADD nearby_users:city123 116.397128 39.916527 user:123
GEORADIUS nearby_users:city123 116.39 39.91 3000 m WITHDIST COUNT 20
命令 说明
GEOADD key lon lat mem 添加用户坐标
GEORADIUS key lon lat 3000 m WITHDIST COUNT 10 查询周边用户
GEOPOS key member 获取坐标
GEODIST key m1 m2 m 计算两人之间距离
ZREM key member 用户下线时清理数据
优点 说明
zset 查询时间复杂度 O(logN),适合高并发
实时 用户上下线可快速 GEOADD/REM
精度可控 GEO 编码到米级精度
使用简单 几条命令搞定,无需额外索引或结构
缺点项 说明
不支持条件组合 只能按距离查,无法叠加标签、性别等多条件过滤
容易数据冗余 每个城市/频道要维护一个 GEO key,量大不易管理
精度有限 zset 是近似值(Geohash 编码有边界效应)

9.4 ES Geo 实现

适合需要复杂多条件过滤 + 距离排序 + 全文搜索的场景

优点 说明
支持多条件查询 性别、标签、认证状态、热度等均可加条件
排序能力强 可按距离、时间、热度等复合排序
分布式扩展好 数据量千万级也能应对
缺点项 说明
引入成本高 需要部署 ES,学习曲线相对较陡
写入延迟 用户位置频繁变化不适合强实时场景

参考命令

{
  "query": {
    "bool": {
      "filter": {
        "geo_distance": {
          "distance": "3km",
          "location": {
            "lat": 39.91,
            "lon": 116.39
          }
        }
      },
      "must": {
        "match": {
          "gender": "female"
        }
      }
    }
  },
  "sort": [
    {
      "_geo_distance": {
        "location": {
          "lat": 39.91,
          "lon": 116.39
        },
        "order": "asc",
        "unit": "m"
      }
    }
  ]
}

10.设计一个支持10万QPS的短链服务,如何保证低延迟与高可用?

10.1 核心功能

功能模块 说明
创建短链 接收原始长链接,生成短码并存储映射关系
访问短链 根据短码查询长链接并跳转
管理后台 查询短链信息、生成统计报表
统计与分析 访问次数、地域、平台等维度分析

10.2 高并发架构图

                         ┌────────────┐
                         │ LoadBalancer│
                         └─────┬──────┘
                               │
           ┌──────────────────┼──────────────────┐
           │                  │                  │
     ┌─────▼─────┐      ┌─────▼─────┐      ┌─────▼─────┐
     │  API 网关 │      │  Nginx    │      │  限流组件 │
     └─────┬─────┘      └─────┬─────┘      └─────┬─────┘
           │                  │                  │
     ┌─────▼──────────────────▼──────────────────▼─────┐
     │               应用服务层(短链服务)              │
     └─────┬──────────────┬──────────────┬─────────────┘
           │              │              │
   ┌───────▼──┐     ┌─────▼────┐    ┌────▼────┐
   │ Redis 缓存│     │MySQL主库│    │Kafka统计│
   └──────────┘     └─────────┘    └─────────┘
           │
     ┌─────▼─────┐
     │ Snowflake │ ID生成器(分布式唯一短码)
     └───────────┘

10.3 唯一短码生成

推荐组合:Snowflake + Base62 编码,结合缓存、支持高并发短链生成

方案 描述 优点 缺点
Snowflake 64位 ID,时间戳 + 机器ID + 自增序列 分布式生成、趋势递增 不支持自定义码
base62编码ID 对 Snowflake ID 做 base62 编码缩短 URL短、易分享 ID不连续,不可预测
Redis INCR + 分片 每台机器一个 key,自增生成 易控流量 单点风险、需预热
自定义词典生成 生成随机词,如 a9BcDe 个性化、有记忆点 冲突处理复杂

10.4 高并发访问 读路径优化

层级 技术 说明
CDN 阿里云CDN、Cloudflare 缓存热点短链解析,避免回源
Redis 使用缓存存储短链映射 命中率高时,QPS 支撑百万级
本地缓存 Guava/LRU 缓存热点短链映射于进程内(防击穿)
MySQL 落库存储短链映射 按 key 查询,做好分库分表,支持水平扩展

10.5 redis 设计

Key 设计 Value TTL
short: long_url 动态设置
hot_rank_zset code score 常驻缓存
short_code_exist: bool 用于去重校验

10.6 安全设计

控制点 策略建议
防刷 QPS限流/IP限频/行为风控
短链过期 支持 TTL,访问超过时间自动失效
权限控制 用户短链与系统短链分开权限(如企业/个人)
短链屏蔽 黑名单 URL 过滤 + 违规短链监控
短链伪造防止 短链映射不可预测(如 base62 +随机扰动)

10.7 总结

模块 关键设计点 优化方式
唯一ID生成 Snowflake + base62编码 多实例隔离机器ID,避免冲突
查询路径 Redis → fallback MySQL Redis预热、热点本地缓存
数据存储 分库分表 + 索引优化 根据 hash 短码分表
高可用性 多副本部署 + 异地灾备 K8s、哨兵、自动恢复
安全与限流 IP 限速、防爆破、短码校验 滑动窗口限流 + 异常行为报警
扩展能力 加入统计、登录权限、多业务支持 模块拆分服务、统计异步处理
posted @ 2025-06-23 15:21  幸福捕手  阅读(26)  评论(0)    收藏  举报