1. 对于一个系统的接口层应该如何设计
数据校验与安全认证
严格校验入参(类型、长度、格式、合法取值),防止 SQL 注入和非法业务逻辑。
强制使用 HTTPS,采用 JWT 或 OAuth2.0 进行身份鉴权,并对敏感信息进行脱敏处理。
异步处理与可观测性
针对耗时长的非核心接口(如发送邮件、统计),采用 消息队列(MQ) 削峰填谷,立即返回“处理中”。
完备的日志(TraceId)和监控指标(QPS、RT、错误率),确保出问题时能快速定位。
应对接口泄漏与大量恶意请求
限流
接口层应当在网关层实现限流,在网关层设置阈值,过滤掉超额流量。
多维度限流: 不要只针对全局,要针对 IP、用户ID、API 路径 进行多重限制。
常用算法: 令牌桶(Token Bucket): 允许一定程度的突发流量。
漏桶(Leaky Bucket): 强制平滑流量,由于请求流出速率恒定,适合保护后续数据库。
黑白名单与封禁
动态黑名单: 配合监控系统,如果某个 IP 在短时间内触发了大量的 404 或限流错误,自动将其加入 Redis 黑名单封禁一段时间。
WAF(Web 应用防火墙): 在接入层(如 Nginx/Cloudflare)阻断常见的攻击向量。
接口隐藏与动态化
URL 签名: 请求必须携带由私钥生成的 Signature,即使 URL 泄漏,攻击者无法伪造签名也无法调用。
接口动态化: 针对抢购等高危接口,URL 后缀可以加上由后端下发的随机 Hash 值,且具有时效性。
幂等性设计(用户重复点击、网络抖动)
前端防抖
点击按钮后置灰(Loading 状态),防止用户物理层面的连续点击。但这只是辅助,不能作为唯一手段。
后端幂等令牌
获取 Token: 进入页面时,前端向后端申请一个唯一的 UUID(Token)。
携带提交: 提交表单时在 Header 中携带此 Token。
校验逻辑:后端使用 Redis 的 SETNX 命令:SET key value NX EX 3600。
如果设置成功,说明是第一次请求,正常执行业务。
如果设置失败,说明是重复请求,直接返回“请勿重复提交”。
应对接口雪崩
如果后端业务逻辑执行慢,大量请求积压在接口层,会导致整个连接池耗尽。
超时控制(Timeout): 设置合理的接口超时时间(如 3s),防止慢请求拖死线程池。
熔断与降级(Circuit Breaker): 如果某个下游服务(如积分服务)持续报错,接口层应开启熔断,直接返回友好提示或默认值,不再调用下游。
隔离策略(Bulkhead): 为核心业务接口分配独立的线程池,防止非核心接口的流量爆发影响核心业务。
2. 如何设计一个百万级QPS的接口
流量削峰与分层过滤
在百万级流量下,保护后端核心资源(如数据库)是第一优先级。
多级限流: * 接入层: 在 Nginx 或云网关(API Gateway)利用漏桶或令牌桶算法,丢弃非正常频率的请求。
应用层: 使用 Sentinel 或 Hystrix 对具体的接口、方法进行集群限流。
黑白名单与风控: 尽早拦截无效流量(如机器人、爬虫)。
请求合并: 将短时间内的大量同类读请求,在网关层合并为一个请求去访问底层服务,减少网络开销。
合理设计缓存(数据下沉)
百万 QPS 下,任何请求直接打到数据库都会瞬间造成系统崩溃。
多级缓存:
本地缓存: 使用 Caffeine 或 Guava Cache 缓存极热点数据,避免 Redis 的网络 IO 瓶颈。
分布式缓存: Redis 集群需采用分片(Sharding)架构,并配合多副本读写分离。
解决热点 Key 与缓存击穿:
热点探测: 实时监控高频访问 Key,动态将其推送到本地内存。
缓存预热: 流量洪峰到达前,提前加载数据。
数据压缩: 尽量缩减缓存 Value 的大小(如使用 Protobuf 替代 JSON),节省带宽。
极速接入层与弹性架构
单机承载能力有限,必须通过水平扩展和优化底层协议来应对流量。
无状态化: 保证应用节点不存储 Session 等状态,以便随时进行秒级水平扩容。
高性能网关: 采用 OpenResty、Go 或基于 Netty 的 Java 网关,利用非阻塞 IO 处理海量连接。
负载均衡策略: 使用四层负载均衡(LVS/DPDK)配合七层负载均衡(Nginx),分担解析压力。
长连接维护: 适当调大连接池,减少 TCP 三次握手的开销。
异步化与解耦
对于非强一致性的操作,必须遵循“先响应,后处理”的原则。
消息队列(MQ): * 将写操作(如发券、日志、积分增加)投递到 Kafka 或 RocketMQ,实现流量平滑。
顺序与幂等: 确保消息消费的幂等性,防止重复执行。
异步编程: Java 内部使用 CompletableFuture 或 Reactor 模型,避免主线程在 IO 等待上浪费时间。
存储引擎优化
即使有了缓存,存储层也需要做最后的兜底准备。
读写分离与分库分表: 通过分片将压力分散到多个数据库节点。
批量写入: 数据库写操作尽量采用
Batch Insert减少磁盘 IO 次数。冷热隔离: 将近期活跃数据与历史数据分开存储,提升查询效率。
NoSQL 选型: 如果场景允许,优先使用 MongoDB、Cassandra 或 Elasticsearch 等擅长横向扩展的数据库。