14 - 复杂系统设计与大厂高并发场景题篇

核心定位:高并发流式 AI 对话架构、海量文档异步处理流水线、多租户强隔离、大模型多级容灾熔断、分布式长任务调度与探针流计算。


Q1: 系统设计题:请设计一个面向政企的「高并发、低延迟流式 AI 问答平台」,需要支撑 10,000+ 并发在线用户同时进行 SSE 交互,请给出端到端的架构设计。

回答(求职者口吻)
面对万级并发的长连接流式场景,核心设计原则是“网关长短连接解耦、应用层轻量无状态、下游异步化流水线”

  1. 接入层与负载均衡(Ingress / Envoy)
    - 使用 Envoy / Nginx 开启 HTTP/2 与 SSE 代理,调优 worker_rlimit_nofile 1000000,关闭代理缓冲区(proxy_buffering off)。
    - 基于 Hash 环或最少连接(Least Request)算法将流量负载分发至 Go 业务 Pod 集群。
  2. 业务应用层(Go Stateless API Cluster)
    - 部署 10~20 个轻量 Go 容器副本(每个副本承载 500~1000 个 SSE 连接,内存开销极小)。
    - 每个用户请求派生轻量 Goroutine,通过带缓冲的 Channel 接收下游 Token 并即时 Flush。
  3. 大模型代理与网关池(LLM Gateway & Pooling)
    - 设立专用的 LLM 代理网关,聚合上游多个大模型供应商 API 实例(或私有化多卡 vLLM 集群)。
    - 实现自适应动态权重负载均衡:依据各模型实例的当前并发度、首字延迟(TTFT)与健康状态动态分发,避免单点过载。
  4. 会话与缓存层(Redis Cluster)
    - 历史多轮会话上下文全部缓存在 Redis 中,会话读取走从库集群,单次请求检索延迟控制在 5ms 以内。
  5. 异步存证与监控
    - 问答结束事件异步投递至 Kafka,由日志服务消费后批量写入 MySQL / ES,彻底移除核心流式主链路上的数据库写瓶颈。

Q2: 场景设计题:请设计一个「百万级政务公文与法规文档的异步解析与 RAG 向量化管道」,要求支持断点续传、失败重试、防止 OOM,并能在 1 小时内完成全量入库。

回答(求职者口吻)
该场景属于典型的大规模分布式批处理与计算密集型数据管道

  1. 分布式任务拆解与流水线化(Map-Reduce 式分治)
    - 文档发现与元数据切分(Producer):扫描百万公文,按 100 篇为一个 Batch 生成子任务,投递至 Kafka doc_pipeline_topic
    - 流水线三阶段解耦
    • OCR 与版面分析阶段(CPU/GPU Worker):利用多节点容器并行提取结构化文本与表格;
    • 语义分块与元数据增强阶段(Compute Worker):按条款与章节分块,打上租户与权限标签;
    • Batch Embedding 与向量入库阶段(GPU Worker):批量调用 Embedding 服务(如每批 128 条),并发写入向量数据库。
  2. 内存控制与防 OOM(Streaming Processing)
    - Worker 严禁将整本大 PDF 一次性加载到内存。基于文件流(Stream)按页读取与切片,完成一页即释放该页的图片内存,单 Worker 内存稳定在 200MB 以内。
  3. 断点续传与幂等性保证
    - 记录文档粒度与分块粒度的两级状态机:doc_statuschunk_status
    - 每个 Chunk 记录全局唯一 Hash。若某个 Worker 崩溃,重试机制根据已落库的 Chunk Hash 自动跳过已处理页,仅对未完成部分继续执行,保障零重复计算。
  4. 吞吐量测算与横向扩容
    - 百万文档若产生 5000 万 Chunk,1 小时完成需达到 $14,000\text{ Chunks/s}$。部署 16 节点的 GPU Embedding 集群(支持动态 Batching),配合向量库(Milvus/Infinity)的分布式 Partition 并发 Bulk Insert,完全可达成吞吐目标。

Q3: 架构设计题:如果让你设计一个「多租户、细粒度数据权限隔离的知识库系统」,底层存储如何选型与分库分表?如何防止跨租户数据越权与向量污染?

回答(求职者口吻)
在企业级多租户知识库中,“逻辑隔离的敏捷性”与“物理隔离的安全性”必须根据客户密级做分级设计

  1. 数据模型分级隔离策略
    - 普通租户(共享实例 + 字段隔离)
    • MySQL 表中强制包含 tenant_idorg_id。所有 SQL 操作强制经过 ORM 租户插件(如 GORM Scope 自动注入 WHERE tenant_id = ?),从框架层杜绝开发人员漏写条件。
    • 高密涉密租户(独立 Schema / 独立 Database 隔离)
    • 为核心重点委办局分配专属 MySQL 数据库实例与专属 MinIO 存储桶。
  2. 向量数据库隔离设计(防向量污染)
    - 物理 Collection 隔离:每个租户对应独立的 Vector Collection / Namespace。向量检索完全在租户自身的 Collection 内部进行,物理上杜绝跨租户相似度召回。
    - 细粒度数据权限过滤(Payload Pre-Filtering)
    • 在向量的 Payload 元数据中存储允许访问的 org_pathmin_security_levelrole_whitelist
    • 检索时,强制由后端安全上下文生成 Filter DSL 注入向量查询引擎。
  3. 双重越权防御拦截网
    - 检索结果返回后,Go 业务层进行二次安全校验(Post-Validation):逐一核对命中 Chunk 的所属组织是否在当前用户的有效访问权限树内,防止底层向量引擎因 Bug 返回脏数据。

Q4: 高可用设计题:当后端依赖的大模型 API 突发限流(429)或响应延迟从 1s 飙升至 10s 时,你如何设计多级缓存、熔断降级与负载均衡策略?

回答(求职者口吻)
针对大模型 API 这一外部强依赖的不可控性,我们构建了“主动限流 + 多模型动态路由 + 熔断降级 + 语义缓存”的四级防护网:

  1. 第一级:语义缓存命中(Semantic Caching - GPTCache / Redis)
    - 针对常见的高频咨询问题(如“办理身份证需要什么材料”),计算 Query 的 Embedding 并与 Redis 缓存中的高频问题库做余弦相似度匹配。
    - 若相似度 $> 0.96$,直接返回已缓存的高质量标准答案,直接跳过大模型调用,阻断流量下流,毫秒级响应。
  2. 第二级:令牌桶与并发主动平滑(Proactive Rate Limiting)
    - 在调用大模型前,基于 Redis 维护与供应商 TPM/RPM 对齐的本地令牌桶,当并发请求即将超限时,在网关层平滑排队,防止触发上游 429 报错。
  3. 第三级:多供应商动态权重路由与故障逃生(Failover Routing)
    - 接入多家供应商模型(如 DeepSeek-V3 官方、火山引擎代理、阿里云百炼代理、私有化备用节点)。
    - 维护健康评分:当主通道连续出现 3 次 429 或 P99 延迟超过 5s 时,自动将主通道权重调为 0,秒级无缝将新请求切换至备用模型通道。
  4. 第四级:熔断降级与兜底回答(Circuit Breaker)
    - 基于 Sentinel-Go 实现断路器。当全链路大模型彻底不可用时触发熔断,直接提取 RAG 检索到的前 3 条核心政策法规文本原文,以结构化公文卡片形式直接呈现给用户,并提示“AI 深度总结繁忙,已为您呈现官方依据原文”。

Q5: 性能设计题:大模型流式输出涉及长时间维持大量 HTTP 长连接(SSE),如何在 Linux 内核、网关层与 Go 应用层进行全链路连接调优与内存控制?

回答(求职者口吻)
SSE 长连接虽然轻量,但在海量并发下会对文件句柄、网络栈内存和应用协程产生复合压力:

  1. Linux 操作系统内核调优
    - fs.file-max = 2097152(调大系统全局文件句柄上限);
    - /etc/security/limits.conf 中设置进程 nofile 1048576
    - 调优 TCP 缓冲区大小以降低内存占用:
    net.ipv4.tcp_rmem = 4096 87380 4194304net.ipv4.tcp_wmem = 4096 16384 4194304(调小写缓冲区下限,一个连接仅占几 KB 内存);
    - net.core.somaxconn = 32768(增大全连接队列长度)。
  2. Nginx / Envoy 网关层调优
    - proxy_buffering off;(坚决关闭响应缓冲,避免 Nginx 在内存中拼装大响应);
    - proxy_read_timeout 300s;(延长长连接读取超时);
    - proxy_http_version 1.1; proxy_set_header Connection "";(开启与 upstream 的长连接复用)。
  3. Go 应用层内存与协程优化
    - 使用 sync.Pool 复用 SSE 序列化 Buffer 和 Token 字符串对象,避免高频 malloc 触发 GC;
    - 严格为每个流式连接设置 context.WithTimeout,监听 ctx.Done(),客户端断连即刻销毁协程与 Channel,杜绝僵尸长连接占用内存。

Q6: 场景设计题:如何设计一个可靠的「分布式长流程 Task Agent 调度与执行引擎」,保证任务在遇到节点宕机或网络中断时能够自动恢复并断点续跑?

回答(求职者口吻)
针对耗时 30 秒至数分钟的多步复杂 Agent 任务,我们设计了“基于 WAL 状态持久化的分布式状态机工作流引擎”

  1. 执行步骤 WAL 日志与状态落库(Write-Ahead State)
    - Agent 在执行每一个 Step(如“调用 RAG 检索”、“执行数据对比”)之前,先在 MySQL 中将该 Step 标记为 status = 'RUNNING',并记录入参快照;
    - 步骤执行成功后,原子更新该 Step 为 status = 'COMPLETED',并将工具返回的数据落库保存。
  2. 心跳租约与故障接管(Heartbeat Lease & Worker Failover)
    - 正在执行任务的 Worker 节点每 5 秒向 Redis 刷新该任务的心跳租约(SET agent:task:lease:{id} worker_A EX 15)。
    - 独立的集群 Watchdog(调度协调节点)定期扫描处于 RUNNING 但心跳租约已过期的异常任务,判定原 Worker 节点已宕机。
  3. 断点续跑机制(Resume from Checkpoint)
    - Watchdog 将任务重新放入执行队列;
    - 新接管的 Worker 读取该任务的历史 Step 记录,直接跳过所有已 COMPLETED 的历史步骤,直接将历史步骤的持久化输出作为输入上下文,从第一个未完成的 Step 继续向下调度,真正做到“故障无感,平滑续跑”。

Q7: 场景题:如何设计一个「政务政策实时敏感词与合规审查系统」,要求支持千万级敏感词库、毫秒级命中、低误报率,并支持流式文本的实时拦截?

回答(求职者口吻)
1. 多级过滤与漏斗架构(Filter Funnel Architecture)
- 第一级:Bloom Filter(布隆过滤器)快速初筛
- 将千万级词库构建在内存布隆过滤器中,0.1ms 快速判定“绝对无敏感词”的文本,直接放行 95% 以上的安全请求。
- 第二级:AC 自动机(Aho-Corasick 多模式匹配)深度扫描
- 将敏感词构建在 Trie 树 + Fail 指针构成的 AC 自动机中。时间复杂度仅与待检测文本长度相关 $O(N)$,与千万词库规模无关,单次扫描耗时 $< 2ms$。
2. 流式滑动窗口与分包拦截
- 针对大模型逐字吐字的场景,后端维护固定长度(最长敏感词长度)的环形缓冲区,逐字滑动推进 AC 自动机状态,命中敏感词瞬间立即切断流式下发。
3. 语义上下文消歧(解决误报率)
- 政务公文包含大量生僻专业词汇。针对命中中低风险敏感词的句子,异步调用本地轻量级 NLP 文本分类模型(BERT/RoBERTa)进行合规上下文二次判定(判定是正常公文引述还是恶意违规),有效降低误杀率。


Q8: 架构题:如何设计一个「分布式微服务接口限流与防刷系统」,支持针对租户、IP、用户、API 路径等多维度的滑动窗口与令牌桶限流?

回答(求职者口吻)
1. 多维度限流 Key 动态组合
- 定义灵活的限流维度:limit:{tenant_id}:{user_id}:{api_path}limit:ip:{client_ip}
2. 基于 Redis + Lua 脚本的高性能原子滑动窗口算法
- 采用 Redis ZSet(有序集合):
```lua
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window_size = tonumber(ARGV[2])
local max_requests = tonumber(ARGV[3])

 -- 1. 移除窗口时间戳之前的过期记录
 redis.call('ZREMRANGEBYSCORE', key, 0, now - window_size)
 -- 2. 获取当前窗口内的请求总数
 local current_requests = redis.call('ZCARD', key)
 -- 3. 判定是否超限
 if current_requests < max_requests then
     redis.call('ZADD', key, now, now)
     redis.call('EXPIRE', key, window_size)
     return 1 -- 允许通过
 else
     return 0 -- 触发限流
 end
 ```
  • 通过 Lua 脚本保证“清理-统计-添加”三步操作在 Redis 单线程内的绝对原子性,杜绝高并发竞态击穿。
    3. 两级缓存与本地内存令牌桶降级
  • 网关本地内存维护基于 Go rate.Limiter 的令牌桶作为第一道屏障,防止 Redis 本身成为瓶颈;
  • 当 Redis 抖动不可用时,限流中间件自动降级为本地单机限流模式,保障系统自愈能力。

Q9: 场景题:如果知识库中存在海量相似政策(如 2021/2022/2023/2024 年各出了一版支持政策),如何设计检索与排序策略,确保回答精准匹配最新政策且支持历史演变对比?

回答(求职者口吻)
面对版本迭代型政策的检索,关键在于“意图感知 + 元数据时间维度加权 + 结构化多版本呈现”

  1. 意图分类器感知(Intent-Aware Routing)
    - 意图 A(现状咨询 - 如“现在专精特新补贴多少”):目标锁定最新现行版本。
    • 检索层注入强过滤:status = 'ACTIVE' AND effective_date <= NOW(),或者在重排阶段对相似度相近的 Chunk,按 publish_date 引入指数时间衰减因子
      $$FinalScore = Score_{Rerank} \times e^{-\lambda \cdot (Year_{current} - Year_{doc})}$$
      确保 2024 最新政策以绝对优势排在第一。
    • 意图 B(演变对比 - 如“专精特新政策这几年有哪些变化”)
    • 系统自动识别“对比/演变”意图,取消时间衰减,按政策主题聚类召回各年份(2021~2024)的代表性版本。
  2. Prompt 多版本对比模板
    - 将不同年份的 Chunk 标注版本时间线送入大模型,指导模型输出“时间演进对比表(2021旧规 $\to$ 2024新规变动点)”,实现业务价值最大化。

Q10: 系统设计题:请设计一个「边缘网关质量探针数据实时汇聚与智能调度选路系统」,要求支撑 50,000+ 边缘节点的毫秒级网络状态上报与实时最优路径计算。

回答(求职者口吻)
这是一个典型的海量时序网络数据流式计算与低延迟控制面调度系统

  1. 高吞吐数据摄取层(Edge Ingestion Layer)
    - 5 万节点按 1 秒周期上报探针指标,产生 50,000 QPS。
    - 采用 Go 编写轻量接入网关,以 gRPC 流接收数据包,零业务计算,直接分批批量(Batch Size 500)投递至 Kafka 的 16 个 Partition 中,实现极致的吞吐与写入抗峰。
  2. 近实时流式计算层(Stream Processing Layer)
    - 计算 Worker 组消费 Kafka,内部基于内存环形滑动窗口(Ring Buffer)维护每个网关节点最近 10 秒的指标流。
    - 应用 EWMA 指数移动平均滤波消除网络抖动毛刺,计算各出口链路的加权 QoS 分数。
  3. 分布式选路决策引擎(Routing Decision Engine)
    - 当且仅当备用链路综合评分持续超过主链路 15% 门槛且冷却时间达标时,生成轻量选路变更事件(Route Delta Event)。
  4. 反向推送通道(Downlink Control Channel)
    - 变更事件通过 Redis Pub/Sub 广播至维护该网关长连接的 Go 控制器节点,通过已建立的 gRPC 双向流毫秒级下发至边缘网关内核,实现从网络变质到完成切换的全链路延迟 $< 500ms$。