1.分布式系统下如何实现服务限流
- 核心算法:
- 固定窗口:将时间划分为固定窗口(如 1 秒),统计窗口内请求数,超过阈值则限流。实现简单但存在临界值突发流量问题。
- 滑动窗口:将固定窗口拆分为多个小窗口,滑动计算请求数,缓解临界问题,但实现复杂度较高。
- 漏桶算法:控制请求处理速率恒定,平滑流量,但无法应对突发流量。
- 令牌桶算法:按固定速率生成令牌,请求需获取令牌才能处理,支持突发流量且灵活,是主流选择。
- 实现方式:
- 单机限流:如 Guava 的RateLimiter(基于令牌桶)、Nginx 的limit_req模块。
- 分布式限流:基于 Redis 实现(如用INCR统计请求数,结合过期时间模拟窗口;或用 Lua 脚本实现令牌桶),保证集群限流一致性。
- 应用场景:根据业务需求选择算法(如秒杀场景用令牌桶应对突发流量),并在网关层、服务层多维度限流。
2. 订单未支付过期自动关单方案
定时任务 | 实现简单、成本低 | 时间精度低、增加数据库压力 | 数据量小、对时间不敏感 | |
JDK 延迟队列(DelayQueue) | 不依赖第三方组件 | 可能 OOM、数据易丢失 | 小数据量、非核心场景 | |
Redis 过期监听 | 高性能 | 存在延迟、消息可能丢失 | 较少用在生产环境 | |
Redisson 分布式延迟队列 | 使用简单、原子性强 | 依赖 Redis | 需分布式支持的场景 | |
RocketMQ 延迟消息 | 解耦系统、吞吐量高 | 引入 MQ 增加复杂度(消息丢失等) | 需高吞吐量、解耦场景 | |
RabbitMQ 死信队列 | 支持高可用 | 可能因队头消息导致阻塞 | 需高可用但可接受轻微阻塞场景 |
3. 秒杀系统设计
3.1 架构原则 “4 要 1 不要”
- 数据要少(减少传输与处理数据)、请求要少(合并 CSS/JS 等)、路径要短(减少中间节点)、依赖要少(区分强弱依赖)、不要有单点(服务无状态化)。
3.2 核心优化策略
- 动静分离:拆分静态数据(如商品标题)与动态数据(如库存),静态数据缓存至 CDN、浏览器,提升访问效率。
- 热点处理:识别静态热点(报名筛选)与动态热点(实时上报),通过缓存、限制、隔离(业务 / 系统 / 数据隔离)优化。
- 流量削峰:用消息队列缓冲、答题延缓请求、分层过滤(CDN→前台→后台→数据库)减少无效请求。
- 减库存设计:可选 “下单减库存”(防超卖)、“付款减库存”(可能超卖)、“预扣库存”(保留时间 + 自动释放),需保证数据一致性(如数据库字段设为无符号整数)。
4. 高并发系统设计(QPS 提升 10 倍)
- 硬件与架构:水平扩容、微服务拆分(降低耦合)。
- 通信优化:用 Dubbo 等 RPC 框架(性能是 Feign 的 10 倍),自带负载均衡、熔断降级。
- 中间件支撑:消息队列(削峰解耦)、三级缓存(本地缓存 + 分布式缓存 + 数据库)。
- 数据库优化:读写分离、分库分表(按用户 ID / 业务分片)。
- 高可用策略:熔断(隔离故障服务)、限流(控制请求量)、降级(弱依赖失效时保障核心流程)、预案与核对机制。
5. 其他核心系统设计要点
- 会员系统:ES 双中心主备集群(高可用)+ Redis 缓存(性能)+ MySQL 分库分表(存储),解决高并发查询与数据一致性。
- 优惠券系统:分库分表应对存储瓶颈,拆分子库存解决热点问题,本地缓存优化模板获取,支撑 10 万级 QPS。
- 短 URL 生成器:预生成短 URL(Base64 编码),用 HDFS 存储、Redis 缓存,支持百亿级规模与数万并发。
- 分布式链路跟踪:通过 TraceID 串联请求链路,记录各环节日志,用 ELK 栈分析,定位性能瓶颈。
6. 关键技术问题解决方案
- 库存超卖:用 Redis 原子操作(decr)、令牌桶(预生成库存令牌)、自旋锁或 CAS 乐观锁控制并发修改。
- 数据库选择:高并发场景不推荐关系数据库(B + 树索引 IO 成本高),可选用 LSM 树或列存储数据库。
- 同城多活:用 Otter 工具基于 binlog 同步数据,支持双机房故障自动切换,保障数据一致性。
7. 架构设计原则
- 分层设计:隔离关注点(表现层、逻辑层、数据层),便于复用与扩展。
- 动静分离:静态数据缓存至 CDN / 本地,动态数据按需加载,减少服务端压力。
- 限流熔断:通过令牌桶 / 漏桶算法限流,熔断故障依赖,保障系统在流量峰值下的可用性。
8. 短 URL 生成器设计
- 核心需求:将长 URL 转换为短 URL(如http://1.cn/ScW4dt),支持百亿级规模管理和数万级并发吞吐量,需解决无冲突、高并发访问及海量存储问题。
- 实现方案:
- 短 URL 生成:采用预生成策略,通过随机数生成 6 个字符的短 URL(Base64 编码),利用布隆过滤器检查冲突,预生成 144 亿条(含 20% 冗余)存储于 HDFS。
- 架构设计:用户请求经负载均衡到短 URL 服务器,生成短 URL 时从预加载服务器的内存中获取,同时将映射关系存入 HBase;访问短 URL 时优先查 Redis 缓存,未命中则查 HBase 并更新缓存。
- 过期处理:每月清理过期(2 年)短 URL,回收资源并重写入预生成文件。
9. 支持万亿 GB 网盘系统(DBox)设计
- 核心功能:文件上传下载(支持断点续传)、文件共享、秒传、限流(向付费用户倾斜资源)。
- 关键技术:
- 存储架构:元数据(用户信息、文件属性等)存于分库分表的 MySQL,文件内容切分为 4MB 块存储于 Ceph 对象存储,实现元数据与内容分离管理。
- 秒传实现:通过文件 MD5、前 256KB MD5 及文件长度三重校验,若文件已存在则仅建立关联,不重复上传。
- 限流策略:根据用户类型(免费 / VIP)限制并发连接数、线程数及传输速率,保障付费用户体验。
10. 支持 3 千万用户同时在线的短视频系统(QuickTok)设计
- 核心挑战:应对高并发访问的带宽压力(总带宽 88Tb)及海量存储(年新增 5200PB)。
- 架构设计:
- 上传流程:用户上传视频经负载均衡到上传微服务,暂存文件后触发消息队列,视频处理器进行合规审查、转码等操作,最终存入 HDFS 和 CDN。
- 播放优化:采用 CDN 分发,对粉丝超 10 万的大 V 视频主动推送至粉丝活跃区域的 CDN 节点,仅推送部分片段(基于完播率),降低带宽压力。
- 缩略图推荐:结合大数据和机器学习,生成吸引用户的缩略图,通过实时推荐和离线训练优化点击率。
11. 基于 LBS 的交友系统(Liao)地理空间邻近算法
- 核心需求:为 10 亿用户快速匹配邻近用户,需高效计算用户间距离。
- 算法选择:
- 排除方案:SQL 邻近算法(效率低)、地理网格算法(精度不足)、动态网格算法(实现复杂)。
- 最终方案:GeoHash 算法,将经纬度编码为 5 个字符(网格约 25km²),存储于 Hash 表(key 为 GeoHash 值,value 为用户 ID 列表)。查询时先匹配当前网格用户,不足时扩展至周边 8 个网格,计算实际距离后返回结果。
12. 搜索引擎(Bingoo)设计
- 核心功能:全网内容爬取、索引构建、快速检索及结果排序。
- 关键组件:
- 分布式爬虫:爬取网页存储于 HDFS,压缩后按固定格式(含 docID、URL、内容)存储。
- 索引构建:生成 “docID→单词列表” 正排索引,再转换为 “单词→docID 列表” 倒排索引,通过 64 个索引桶并行处理提升效率。
- 排序算法:采用 PageRank 算法,根据网页链接关系打分,结合用户搜索词相关性排序,确保结果准确性。
13. 微博系统(Weitter)应对热点事件的突发访问压力
- 核心功能:发微博、关注好友、刷微博(支持 10 万 QPS),需处理大 V 热点消息引发的高并发。
- 优化策略:
- 推拉结合的信息流模式:在线用户采用推模式(实时更新好友微博列表),离线用户采用拉模式(登录时重建列表),平衡读写压力。
- 缓存设计:缓存 7 天内微博(约 700G),大 V 用户 48 小时内微博本地缓存,减少数据库访问。
- 数据库分片:按用户 ID 分片,避免大 V 数据集中导致的热点问题,限制用户日发微博上限(50 条)。
14. 限流器(Diana)设计
- 核心功能:部署于网关,对超限流规则的请求返回 503 响应,支持全局限流、账号 / 设备 / 资源限流。
- 限流算法:
- 固定窗口:简单但可能短时间放过两倍请求,适合非核心场景。
- 滑动窗口:拆分时间片滑动计算,避免固定窗口缺陷,精度更高。
- 漏桶算法:控制请求处理速率,但会浪费空闲资源,适合特殊场景。
- 令牌桶算法:默认算法,可在系统空闲时累积令牌,高效利用资源,支持突发流量。
15. 敏感数据加解密平台(Venus)设计
- 核心需求:保障敏感数据(手机号、密码等)存储和传输安全,解决密钥分散、版本管理混乱等问题。
- 安全策略:
- 密钥管理:密钥分片存储于异构服务器(文件服务器 + 数据库),需多角色协同才能获取完整密钥,避免泄露。
- 加解密流程:应用通过 SDK 调用服务,SDK 缓存密钥和算法,首次调用需从服务端获取,保障性能和可靠性。
- 版本控制:支持多版本密钥,加密时嵌入版本信息,解密时根据版本获取对应密钥,避免密钥升级导致的数据不可解。
16. 支持 5 亿用户的网约车系统(Udi)设计
- 核心规模:日活乘客 5 千万、司机 2 千万,日订单 6 千万,需处理长连接和实时派单。
- 关键模块:
- 长连接管理:司机 App 通过 TCP 长连接每秒上传位置,由 TCP 管理服务器分配连接节点,用 Redis 记录连接关系,确保消息准确推送。
- 派单算法:基于 Redis GeoHash 计算乘客附近司机,结合地理系统规划路径,聚合 3 秒内订单批量派单,最小化整体等待时间。
- 订单状态模型:覆盖 “创单→派单中→已派单→行程中→待支付→已完成” 全生命周期,确保流程无遗漏。
17. 双十一预约抢购系统设计
- 核心阶段:商品预约、等待抢购、商品抢购、订单支付。
- 技术方案:
- 预约阶段:用 Redis 分布式锁控制资格发放,避免超量。
- 等待阶段:页面静态化并缓存于 CDN,对动态接口限流(如 Nginx 模块),应对流量突增。
- 抢购阶段:消息队列削峰,Redis 预扣库存,订单表分库分表,避免数据库压力过大。
- 支付阶段:支付回调后异步更新订单状态,用本地消息表确保积分累计等非核心流程的最终一致性。
18. 千万级流量架构设计
- 前端优化:减少请求(合并 CSS/JS、图片)、页面静态化(CDN 缓存)、边缘计算(CDN 节点提供计算能力)。
- 后端优化:
- 网络层面:专线和 CDN 优化,减少延迟。
- 架构层面:动静分离、集群部署、数据隔离、服务拆分、异步驱动(消息队列)。
- 性能保障:明确指标(如 100 万并发内 TP99=2s)、限流保护、快速扩容(3 分钟内完成)、全流程性能优化。
19. 支持 10 万 QPS 的 RPC 框架设计
- 性能优化:
- 网络传输:采用多路 I/O 复用模型(如 epoll),开启 tcp_nodelay 关闭 Nagle 算法,减少延迟。
- 序列化方式:优先选择 Protobuf/Thrift(性能高、跨语言),JSON 适合低要求场景。
- 调用流程:客户端序列化请求→网络传输→服务端反序列化并调用→返回结果,优化每个环节的耗时。
20. 蓝绿发布实现
- 核心目标:微服务不停机升级,降低部署风险。
- 实现思路:部署两套环境(蓝绿),蓝环境为当前版本,绿环境部署新版本。升级时将流量逐步切至绿环境,验证无误后全量切换,故障时可快速回滚至蓝环境,确保服务连续性。
21. 如何根据应用场景选择合适的消息中间件?
- 应用场景:核心为异步解耦(如用户注册后异步赠送积分、优惠券,降低模块耦合)和削峰填谷(如外卖订单创建时,通过消息队列缓冲瞬时流量,保护下游系统)。
- 技术选型:
- RabbitMQ:支持优先级队列等功能,但消息堆积能力较弱,适合中小规模场景,团队技术栈为 Golang 时优先考虑。
- RocketMQ:性能优秀,支持消息重试、过滤、轨迹等功能,适合核心业务场景,Java 技术栈优先考虑。
- Kafka:高吞吐量,擅长日志、大数据流式计算场景,适合数据量极大的场景。
- 选型需结合性能、扩展性、团队技术栈及功能需求,避免过度依赖单一中间件特性。
22. 如何提升 RocketMQ 顺序消费性能?
- 顺序消费原理:基于队列级别的顺序保证,通过加锁(Broker 端队列锁、消费端 MessageQueue 和 ProcessQueue 锁)实现,但并发度受队列数量限制。
- 设计缺陷:多次加锁导致并发性能低。
- 优化方案:
- 关联顺序性:区分不同业务的顺序需求(如同一用户的操作需顺序,不同用户可并发)。
- 线程模型优化:按消息 Key 的哈希值路由到不同消费线程,同一 Key 的消息串行处理,不同 Key 并行,提升并发度。
- 核心是通过细化锁粒度,在保证业务顺序的前提下提高并行处理能力。
23. 使用分布式调度框架该考虑哪些问题?
- 核心场景:保证分布式事务一致性(如用户注册后消息发送与数据库操作的一致性)。
- 解决方案:采用 “本地消息表 + 定时任务”,通过 ElasticJob 实现定时调度:
- 本地消息表记录待发送消息,确保数据库操作与消息记录在同一事务。
- 定时任务通过分片机制拉取待处理消息,发送到 MQ 并更新消息状态。
- 支持流式任务,通过循环拉取处理数据,提升实时性;处理失败时通过重试机制补偿。
- 关键要点:任务分片、故障转移、流式处理及消息重试策略。
24. 同城多活方案中如何实现机房之间的数据同步?
- 核心数据中心设计:主库集中在一个机房,通过主从同步至备份机房,适合机房距离≤50 公里场景,但存在主从延迟、故障切换复杂等问题。
- Otter 工具:基于 Canal 监控 MySQL 的 Row Binlog,实现跨机房双向同步:
- 解决数据冲突(行冲突通过时间戳,字段冲突通过合并或回源查询)。
- 支持多机房拓扑(星形、级联),但推荐同城双活,避免跨城市高延迟。
- 注意事项:使用 SnowFlake 算法避免主键冲突,表结构变更需兼容,双向同步表无默认值且必须有主键。
25. 微服务架构下如何进行系统拆分?
- 拆分思路:
- 从上到下梳理业务流程,按阶段(如计划排期、生产交付、售后)划分领域。
- 从下到上分析数据依赖,按实体职责拆分(如订单与排期分离),避免数据交叉频繁。
- 服务抽象:
- 被动抽象法:提取公共逻辑为公共服务,适合初期项目。
- 动态辅助表:通过辅助表存储业务特性数据,贴近业务但隔离性差。
- 强制标准接口:底层服务仅提供标准功能,业务个性部分由上层实现,降低耦合。
- 原则:确保拆分后模块职责单一,数据依赖清晰,便于维护和扩展。
26. 如何解决高并发下库存抢购超卖少买问题?
- 常见方案:
- 原子操作:使用 Redis 的decr等原子命令,避免超卖,失败时需补偿库存。
- 令牌库存:用 Redis 的 List 存储令牌,用户抢库存时获取令牌,避免负数问题。
- 多库存秒杀:拆分库存到多个 Key,随机扣减;库存不足时需判断是否允许部分购买。
- 锁机制:自旋互斥锁(适合多步操作)、CAS 乐观锁(争抢少时效率高)、Redis Lua 脚本(保证多操作原子性)。
- 核心:减少锁争抢,利用原子操作或分布式锁保证库存一致性。
27. 高并发下数据写入为何不推荐关系数据库?
- 关系数据库限制:基于 B+Tree 索引,树深度随数据量增加导致 IO 增多,写入性能下降;主从架构下主库压力集中,不适合高并发写入。
- 替代方案:
- LSM Tree:如 RocksDB,通过内存暂存 + 顺序写磁盘,合并小文件减少 IO,适合写多读少场景。
- 列存储数据库:按列存储,适合数据分析场景,减少无效 IO,压缩效率高。
- HTAP:融合 OLAP 和 OLTP,同一数据支持行 / 列存储,自动选择引擎优化查询。
- 结论:关系数据库适合事务性操作,高并发写入需结合 LSM Tree 或列存储等方案。
28. 如何设计分布式链路跟踪系统?
- 核心组件:基于 ELK 栈(Filebeat 收集、Kafka 传输、Elasticsearch 存储、Kibana 分析)。
- 关键设计:
- TraceID:标识单次请求,贯穿整个调用链路。
- RPCID/SpanID:RPCID(层级计数器)或 SpanID(链式依赖)记录调用关系,串联日志。
- 日志规范:JSON 格式,包含类型(请求、数据库操作、错误等)、时间戳、耗时等字段,支持 Metrics 统计。
- 埋点 SDK:通过 AOP 或侵入式埋点,记录调用链路信息,确保日志全量且格式统一。
- 优势:全量日志跟踪,支持问题排查、性能分析及调用关系可视化。
29. 如何优化架构缓解流量压力提升并发性能?
- 可预估用户量场景:如游戏房间,通过调度服务分配集群,限制单服房间数,精准控制资源。
- 不可预估用户量场景:如直播互动:
- 聊天:合并重复消息,通过队列缓冲,批量拉取降低压力。
- 答题:客户端延迟请求,预加载题目,异步提交结果。
- 点赞:客户端合并操作,服务端通过多层汇总(本地缓存→二级缓存→核心缓存)分散压力。
- 打赏 / 购物:按用户 ID 分片,通过代理服务动态扩容,支持热迁移切片。
- 服务降级:通过队列缓冲或限流,牺牲部分实时性保证系统稳定。
30. 复杂架构为何需要分层设计?
- 分层优势:
- 简化设计:不同团队专注某一层(如表现层、逻辑层),降低复杂度。
- 复用性高:提取通用层(如 Manager 层)供多系统使用。
- 便于扩展:针对瓶颈层(如 CPU 密集的逻辑层)单独扩容,降低成本。
- 分层实践:参考阿里架构,分为终端显示层、开放接口层、Web 层、Service 层、Manager 层、DAO 层,各层职责清晰,通过 Manager 层封装通用能力,Service 层编排业务逻辑,实现高内聚低耦合。
31. 分布式事务常见解决方案及适用场景
- 核心问题:保证跨服务操作的数据一致性(如下单时扣库存与创建订单需同时成功或失败)。
- 解决方案:
- 2PC(两阶段提交):分准备和提交阶段,强一致性但性能差,适合银行等对一致性要求极高的场景。
- TCC(Try-Confirm-Cancel):业务层拆分三个操作,灵活性高但开发成本高,适合核心业务(如支付)。
- 本地消息表:通过本地事务记录消息,定时同步至 MQ,最终一致性,适合非核心场景(如积分发放)。
- SAGA 模式:长事务拆分为短事务链,失败时逆向补偿,适合长流程业务(如订单履约)。
- 选择原则:优先最终一致性方案降低复杂度,核心场景按需选择强一致性方案。
32. 缓存三大问题(雪崩、穿透、击穿)及解决办法
- 缓存雪崩:大量缓存同时失效,请求直达数据库。
解决:过期时间加随机值避免同时失效;多级缓存(本地缓存 + 分布式缓存);熔断降级保护数据库。 - 缓存穿透:查询不存在的数据,缓存无命中,频繁访问数据库。
解决:布隆过滤器过滤无效请求;缓存空值(短期过期);接口层校验拦截。 - 缓存击穿:热点 Key 突然失效,大量请求冲击数据库。
解决:互斥锁(如 Redis 的 SETNX)控制并发重建缓存;热点数据设置永不过期;异步后台更新缓存。
33. JVM 性能优化核心要点
- 内存模型:区分堆(新生代、老年代)、方法区、直接内存,避免 OOM(如新生代过小导致频繁 GC,老年代溢出)。
- 垃圾回收:
- 年轻代用 Minor GC(复制算法),老年代用 Major GC(标记 – 清除 / 整理)。
- 选合适收集器:G1 适合大堆场景,ZGC/Shenandoah 适合低延迟需求。
- 调优参数:
- 堆大小:-Xms=-Xmx避免动态扩容;新生代占比 1/3~1/2。
- 收集器参数:-XX:+UseG1GC启用 G1,-XX:MaxGCPauseMillis控制延迟。
- 问题排查:用 jstack 分析线程阻塞,jmap 查看内存快照,Arthas 实时诊断线上问题。
34. 并发编程关键技术及实践
- 线程池:核心参数(核心线程数、最大线程数、队列、拒绝策略)需匹配业务(CPU 密集型:线程数≈核数;IO 密集型:线程数≈2 * 核数)。
- 线程安全:
- 同步机制:synchronized(自动释放锁)、ReentrantLock(可中断、超时)。
- 可见性:volatile 禁止指令重排,保证多线程数据可见。
- 原子类:AtomicInteger 等通过 CAS 避免锁竞争。
- 并发容器:
- ConcurrentHashMap(分段锁→CAS 优化,线程安全)。
- CopyOnWriteArrayList(读写分离,适合读多写少)。
- 锁优化:偏向锁→轻量级锁→重量级锁的升级机制,减少锁竞争(如缩小同步代码块范围)。
35. 微服务治理核心组件及作用
- 服务注册发现:Nacos/Eureka 管理服务地址,支持动态扩缩容,避免硬编码。
- 配置中心:Nacos/Apollo 集中管理配置,动态推送更新(如开关、限流阈值),无需重启服务。
- 熔断降级:Sentinel/Hystrix 监控服务健康,故障时熔断避免级联失败,降级返回兜底数据。
- API 网关:Spring Cloud Gateway 路由请求、鉴权、限流、日志收集,统一入口简化调用。
- 链路追踪:Sleuth+Zipkin 追踪跨服务调用,定位性能瓶颈和异常节点。
36. 分布式 ID 生成方案及选型
- 核心需求:保证全局唯一、趋势递增(利于数据库索引)、高可用、高性能。
- 常见方案:
- UUID/GUID:简单易用,但无序且占空间大,不适合作为数据库主键。
- 数据库自增 ID:单机可行,分布式场景下需分库分表配合自增步长,易引发 ID 冲突。
- 雪花算法(Snowflake):64 位 ID,包含时间戳、机器 ID、序列号,支持分布式且趋势递增,需保证机器 ID 唯一。
- Redis 自增:利用INCR命令生成,性能高但依赖 Redis 可用性,需做好持久化。
- 选型建议:高并发场景优先选雪花算法,简单场景可用 Redis 自增,避免 UUID 作为主键。
37. 分库分表后如何解决跨库事务问题
- 挑战:传统单机事务无法覆盖多库表操作,易出现数据不一致。
- 解决方案:
- 最终一致性方案:基于本地消息表 + 定时任务,通过消息队列异步补偿,适合非核心业务。
- TCC 模式:Try(预留资源)、Confirm(确认提交)、Cancel(取消释放),业务侵入性高,适合核心场景(如支付)。
- SAGA 模式:将长事务拆分为短事务链,失败时执行逆向补偿操作,适合流程型业务。
- 注意事项:优先保证核心业务数据一致性,非核心业务可接受最终一致性以降低复杂度。
38. 如何设计高可用的 Redis 集群
- 架构选型:
- 主从复制:主库写入,从库只读,解决单节点读压力,但主库故障需手动切换。
- 哨兵模式(Sentinel):自动监控主从节点,主库故障时自动切换从库为主库,提升可用性。
- Redis Cluster:分片存储数据,每个分片有主从节点,支持水平扩容,适合大规模数据场景。
- 关键优化:
- 避免大 Key(如超过 100KB),防止阻塞集群。
- 合理设置内存淘汰策略(如allkeys-lru),防止 OOM。
- 开启 AOF+RDB 混合持久化,兼顾数据安全性和恢复速度。
39. 如何优化 MySQL 查询性能
- 索引优化:
- 建立合适索引(如主键索引、联合索引),避免索引失效(如使用!=、函数操作索引列)。
- 联合索引遵循 “最左前缀原则”,合理安排字段顺序。
- SQL 优化:
- 避免SELECT *,只查询必要字段。
- 减少子查询,改用 JOIN;避免OR,改用UNION。
- 大表分页用WHERE id > 上一页最大ID替代LIMIT offset, rows。
- 架构优化:
- 读写分离:主库写入,从库读取,分散压力。
- 分库分表:按业务维度(如用户 ID)拆分,降低单表数据量。
- 缓存热点数据:将高频查询结果放入 Redis,减少数据库访问。
40. 微服务接口设计原则
- 单一职责:一个接口只处理一个业务场景(如 “创建订单” 和 “查询订单” 分离),避免接口臃肿。
- 幂等性:通过唯一标识(如订单号)保证重复调用结果一致,防止重复提交(如支付接口)。
- 版本控制:接口 URL 包含版本号(如/api/v1/order),便于迭代兼容旧版本。
- 限流降级:接口层设置限流规则(如 QPS 阈值),异常时返回降级响应(如默认数据)。
- 清晰的错误码:自定义错误码(如 10001 代表参数错误),便于问题排查和前端处理。
41. 如何设计分布式锁
- 核心要求:互斥性、安全性(避免死锁)、可用性、公平性。
- 实现方案:
- Redis 分布式锁:使用SET key value NX PX命令加锁,Lua 脚本解锁,需设置过期时间防止死锁,集群场景需考虑 RedLock 算法。
- ZooKeeper 分布式锁:基于临时节点,节点创建成功即获锁,会话过期自动释放,天然避免死锁,性能略低于 Redis。
- 注意事项:加锁后需验证锁持有者身份,避免误释放;长时间任务需定时续期锁(如 “看门狗” 机制)。
42. 如何应对大促场景下的数据库压力
- 事前准备:
- 扩容数据库实例,增加从库数量分担读压力。
- 预热缓存,将热点数据(如商品信息)提前加载到 Redis。
- 分库分表扩容,拆分大表降低单表压力。
- 事中优化:
- 读写分离,强制热点读走缓存。
- 限制非核心业务访问(如关闭评论、推荐等非交易功能)。
- 使用队列异步处理非实时操作(如订单日志、统计数据)。
- 事后处理:
- 监控数据库慢查询,及时优化 SQL。
- 复盘流量峰值,调整扩容策略和缓存方案。
43. 如何设计一个延迟队列
- 应用场景:订单超时未支付自动关闭、定时任务(如到期提醒)。
- 实现方案:
- JDK DelayQueue:基于内存,简单易用但不适合分布式场景,数据易丢失。
- Redis zset:将延迟任务作为 zset 成员,score 为过期时间戳,定时扫描到期任务,适合中小规模场景。
- 消息队列延迟消息:如 RocketMQ 的延迟级别、RabbitMQ 的死信队列,可靠性高,适合分布式系统。
- 选型建议:分布式场景优先用消息队列延迟消息,简单场景可用 Redis zset。
44. 如何保证缓存与数据库数据一致性
- 更新策略:
- Cache Aside Pattern:更新数据库后删除缓存,读数据时先查缓存,未命中则查库并回写缓存,避免缓存脏数据。
- 读写锁:更新时加写锁,防止并发读写导致的数据不一致。
- 异常处理:
- 缓存删除失败时,通过定时任务对比数据库与缓存数据,修复不一致。
- 对热点数据设置较短过期时间,加速脏数据淘汰。
- 核心原则:优先保证数据库数据正确,缓存作为辅助,允许短暂不一致但需最终一致。
评论前必须登录!
注册