如何实现高QPS接口的,从哪几个方面考虑?
1 个回答
永远喜欢简单而真诚的人。李青莲# 1) 架构与接口形态(少做事) * **无状态、水平扩展**:实例可横向扩。会话放外部(JWT/Redis)。 * **读写分离 / CQRS**:写入走异步(MQ/任务),读用副本/缓存。 * **幂等与最终一致**:让重试安全,便于限流/失败恢复。 * **减少往返**:合并接口、批量 API、服务端聚合(BFF)。 # 2) 缓存优先(把大头挡在前面) * **多级缓存**:浏览器/网关/CDN → 本地 Caffeine → Redis。热点加 **本地短 TTL**。 * **缓存击穿/雪崩**:随机过期、互斥重建(single flight)、降级兜底。 * **结果缓存/预计算**:榜单、聚合结果提前算好;版本化键(key with version)。 # 3) 数据与查询(避重活) * **只取必要字段**;避免 N+1;**批量**`IN`/多键查。 * **索引与分页**:联合覆盖索引+**keyset** 分页(`id/create_time < ?`),少用 `OFFSET`。 * **读路径**:只扫热数据(分区/归档);能上 ES/ClickHouse 的别让 MySQL 挖矿。 # 4) I/O 与并发模型(快完成 + 并行) * **连接复用**:HTTP/2、keep-alive、连接池(Hikari/OkHttp)。 * **协议**:内部走 gRPC/二进制,压缩(zstd/lz4)权衡 CPU。 * **并发编排**:I/O 密集用并发/虚拟线程(JDK21+);CPU 密集控线程≈核数。 * **限批/合并**:写路径攒批(队列+linger),读路径请求合并(batching/coalescing)。 **线程池模板(有界+背压)** ```java ExecutorService pool = new ThreadPoolExecutor( 8, 16, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000), r -> { Thread t = new Thread(r, "api-"); t.setDaemon(false); return t; }, new ThreadPoolExecutor.CallerRunsPolicy() // 饱和时让调用线程承担 -> 自然限流 ); ``` **Hikari 连接池要点**:`maximumPoolSize` 以库能承受为上限;`connectionTimeout` 1\~3s;开启 `leakDetectionThreshold`。 # 5) 保护与韧性(可退让) * **限流/配额**:令牌桶(按租户/接口),峰值平滑;爆量直接 429 + 退避。 * **超时预算**:外呼设超时,**端到端预算**(例如 200ms 内完成)。 * **重试策略**:仅对幂等、可重试错误(5xx/网络),指数退避+抖动,设置最大重试。 * **熔断/隔离**:舱壁(线程池/信号量隔离)、熔断半开、降级兜底(缓存旧值/静态页)。 # 6) 代码与 JVM(减分配、减锁、减 GC) * **对象复用/零拷贝**:少装箱、少临时 `String` 拼接;使用 `StringBuilder`/缓冲区。 * **无锁/少锁**:优先无锁容器或读写锁;热点路径避免 `synchronized`。 * **GC 策略**:G1(JDK11+);`Xms=Xmx`,容器下用 `-XX:MaxRAMPercentage`;监控 P99 GC 暂停。 * **序列化**:JSON 开启 afterburner/fastjson2;需要极致就 ProtoBuf。 # 7) 可观测与容量(量化而治) * **RED 三观**:Rate、Errors、Duration(P95/P99);区分冷/热命中。 * **依赖监控**:下游 QPS、RT、错误率、连接池/线程池使用率、限流命中。 * **容量模型**:压测(k6/JMeter),按 3× 峰值;通过 **小步扩容+灰度** 验证。 # 8) 典型落地“组合拳” * 首页/搜索:CDN + 边缘缓存 → 服务端本地缓存 + Redis → ES 查询(keyset)→ 超时降级旧缓存。 * 下单写路径:网关限流 → 异步下单(MQ)→ 幂等键 → 库侧批量落盘/分区表。 * 导出/报表:异步任务 + 流式分页写文件(CSV.GZ)→ OSS 下载(避免同步接口背压)。 # 9) 常见坑 * 无界队列 + 无限制线程/连接 → 瞬间 OOM/雪崩。 * 全用 `OFFSET` 分页、LIKE 前导 `%` → 数据量一大就废。 * 把并发度写死在代码,不可灰度调参。 * 只看平均值不看 P99,忽略尾延迟。 ## 面试用 60 秒版本 > 我做高 QPS,会从**架构、缓存、查询、并发、保护、可观测**六方面入手:接口无状态、可水平扩;前置多级缓存并处理击穿;数据库用覆盖索引+keyset 分页,避免 OFFSET;I/O 密集用并发/虚拟线程,连接池与线程池都有界并带背压;配限流、超时、重试、熔断、降级;全链路监控 P95/P99、错误率与池使用率,并通过压测确定容量。通常这套下来,QPS 可线性提升,同时把 P99 控在目标范围内。发布于 2025-08-14 07:41 •IP属地 云南举报评论收藏
公众号进入网站体验更佳

