综合架构题

共 19 题
📑 题目列表 19 题
#
★★★

1. 设计一个千万级 QPS 的短链生成系统,ID 生成、缓存、持久化、统计?

如何设计一个千万级 QPS 的短链生成系统?ID 生成、缓存、持久化、统计如何设计?

  • 短链接 ID 的生成与编码
  • 高并发读写的缓存与持久化
  • 统计与重定向

短链系统核心是"长链→短链"映射与"短链→长链"重定向。ID 生成:用全局唯一 ID(如雪花算法 Snowflake、Redis 自增、发号器)生成递增 ID,再编码为短码(如 Base62 压缩长度),保证唯一且不可预测(可加随机盐)。缓存:热点短链映射高并发读,用 Redis 缓存(短码→长链),采用 Cache-Aside 或本地缓存(多级缓存)降低 DB 压力,写时先写缓存再异步落库。持久化:用关系库(如 MySQL)存映射表(短码、长链、创建时间、过期时间),主键/索引短码;写入可异步批量落库防热点。重定向:重定向请求先查缓存,未命中查库并回填缓存,返回 302/301 跳转。统计:记录访问日志(IP、时间、UA),通过消息队列收集,异步聚合到统计表/列存,支持点击量统计。千万级 QPS 需分布式缓存集群、读写分离与水平分库。

短链系统本质是"高并发读 + 一次写":ID 生成保证唯一、缓存扛读、异步落库扛写、日志队列做统计;缓存命中率是性能关键。

-- 短链映射表
CREATE TABLE short_url (
  code     VARCHAR(16) PRIMARY KEY,   -- 短码
  long_url VARCHAR(2048) NOT NULL,
  expire_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_long ON short_url(long_url);
#
★★★

2. 审计日志的写入与查询,Append-only、压缩、分区的设计?

审计日志的写入与查询如何设计?Append-only、压缩、分区如何配合?

  • 审计日志的写入模式(Append-only)
  • 压缩与分区的设计
  • 审计日志的查询

审计日志具有"只写不删、按时间追加、事后查询"的特征,设计应围绕 Append-only。写入:日志只追加(append-only),不更新、不删除,保证不可篡改与审计完整性;写入用批量/异步批量提升吞吐,避免频繁小事务。存储:按时间分区(如按月/按日分区表),便于按时间的归档、清理与查询裁剪;对历史分区可压缩(如列式压缩、归档到冷存储)降低存储成本,同时保持可查询。查询:审计查询多按"用户+时间+操作"过滤,需建合适索引(时间、用户、操作类型);对历史数据可走分区裁剪或归档库。设计上还应考虑:每条日志带不可变的时间戳与操作者、写前写后值(before/after)、满足合规保留期,并提供幂等与防篡改(如哈希链)。核心是"写快、省存储、可查、不可改"。

审计日志的本质是"不可变性+高速追加+按时间管理":Append-only 保不可篡改、分区与压缩控成本、索引保查询;设计要兼顾写入吞吐与事后审计。

-- 按时间分区的审计日志表
CREATE TABLE audit_log (
  id BIGSERIAL,
  user_id BIGINT,
  action TEXT,
  target TEXT,
  before_data JSONB,
  after_data JSONB,
  created_at TIMESTAMPTZ DEFAULT now()
) PARTITION BY RANGE (created_at);

-- 查询:按用户与时间过滤,利用分区裁剪
SELECT * FROM audit_log
WHERE user_id = 1001 AND created_at >= '2026-01-01';
#
★★★

3. 支付系统的对账,T+1 对账、资金安全、幂等设计?

支付系统的对账如何设计?T+1 对账、资金安全、幂等如何保证?

  • 支付对账的流程
  • 资金安全与幂等
  • 差异处理

支付系统对账是保障资金安全的关键。T+1 对账:次日用内部交易流水与银行/渠道流水做总额与明细核对,核对金额、笔数、状态,发现差异(多账、少账、状态不一致)。资金安全:对账发现"我记了账、渠道没入账"或"渠道入账、我没记账"等差异,需定位并补偿(如退款、挂账、人工处理),确保资金不流失、账实相符。幂等设计:对账与补偿处理必须幂等——同一笔对账结果重复处理不产生重复动作(如用"交易号+渠道号"做唯一键,重复补偿直接忽略),避免重复退款/重复入账。实现上:对账任务定时拉取双方流水、按唯一键 join 比对、生成差异清单、走补偿流程并记录审计。为保证幂等,支付核心操作(下单、扣款、退款)都带唯一业务号,数据库建唯一约束。

支付对账的核心是"以渠道数据为准核对自身账务,发现差异并幂等补偿",资金安全靠对账兜底、幂等靠唯一键防重;三者缺一不可。

-- 幂等:以唯一业务号做唯一约束,防止重复处理
CREATE UNIQUE INDEX uk_ref ON payment(merchant_ref, channel_ref);

-- 对账:按参考号比对,找出状态不一致或缺失的记录
SELECT p.order_id, p.status AS our_status, c.status AS chan_status
FROM payment p
LEFT JOIN channel_txn c ON c.ref = p.merchant_ref
WHERE p.biz_date = '2026-08-02'
  AND (c.ref IS NULL OR c.status <> p.status);
#
★★★

4. 秒杀场景的库存扣减,行锁、乐观锁、Redis 预扣减、消息队列削峰的取舍?

秒杀场景的库存扣减如何设计?行锁、乐观锁、Redis 预扣减、消息队列削峰的取舍是什么?

  • 库存扣减的并发方案
  • 行锁、乐观锁、Redis 预扣减、消息队列削峰
  • 各方案的取舍

秒杀的核心是"高并发下准确扣减有限库存"。行锁(悲观锁):UPDATE ... WHERE id=? AND stock>0 依赖行锁,简单可靠,但高并发下锁等待严重、吞吐低。乐观锁:UPDATE ... WHERE stock >= X 或带版本号重试,减少锁等待,但并发失败重试多。Redis 预扣减:先用 Redis 原子操作(Lua 脚本 DECRBY 保证原子)预扣库存,扛住瞬时流量,成功者再异步落库,Redis 吞吐极高,但需处理 Redis 与 DB 的一致性(回调、失败补偿)。消息队列削峰:把请求先入队异步处理,系统按自身能力消费,平滑流量尖峰,避免数据库被瞬时打爆。取舍:纯行锁简单但撑不住高并发;乐观锁适合冲突不高的场景;秒杀场景主流是"Redis 预扣减 + 消息队列削峰 + 数据库最终扣减",即 Redis 挡流量、MQ 削峰、DB 兜底一致。需配合防止超卖(Redis 原子扣减、DB 再校验)与幂等。

秒杀库存扣减的核心是"高并发原子扣减":Redis 预扣+MQ 削峰+DB 兜底是主流组合,行锁/乐观锁适合中低并发;关键是防止超卖与保证最终一致。

-- Redis Lua:原子扣减库存,防止超卖
if redis.call('GET', KEYS[1]) > 0 then
  return redis.call('DECRBY', KEYS[1], ARGV[1])
else
  return -1
end
#
★★★

5. 设计千万级用户的 Feed 流存储,推拉结合、缓存、分库与一致性

如何设计千万级用户的 Feed 流存储?推拉结合、缓存、分库与一致性如何设计?

  • Feed 流的推、拉、推拉结合模式
  • 缓存与分库
  • 一致性

Feed 流(信息流)存储的核心是"发布写入与粉丝读取"的权衡。推模式(Push):作者发布时把内容推送到每个粉丝的收件箱(写放大),粉丝读时 O(1) 读自己的时间线,读取快但写放大严重(大 V 粉丝多时不可行)。拉模式(Pull):粉丝读时拉取关注人的最新内容再合并排序(读放大),写简单但读延迟高、压力大。推拉结合:普通用户用推模式(把内容推给粉丝收件箱),大 V 用拉模式(粉丝读时实时拉取大 V 内容合并),平衡读写。存储:收件箱用 Redis(ZSet 存时间线)或 KV 缓存,粉丝读先读缓存;内容详情存数据库(分库分表,按作者/时间分片)。分库:按用户 ID 分库,避免单点热点(大 V 内容分片)。一致性:推模式中粉丝收件箱与作者内容需一致,采用"先写内容库、再异步推收件箱"的最终一致,配合补偿(拉取兜底)。缓存用多级缓存(本地+Redis)扛热点。

Feed 流设计核心是"读写放大权衡":推拉结合是最优解(小 V 推、大 V 拉),缓存扛热点读、分库分片扛写入、异步保证最终一致。

#
★★★

6. 设计一个亿级日活的点赞与收藏系统,如何用 Redis 聚合计数、异步落库与最终对账,保证计数与明细的一致性?

如何设计一个亿级日活的点赞与收藏系统?如何用 Redis 聚合计数、异步落库与最终对账保证计数与明细一致?

  • 点赞/收藏的计数与明细
  • Redis 聚合计数与异步落库
  • 最终对账与一致性

点赞/收藏系统需同时维护"计数"(点赞数)与"明细"(谁点了赞),且高并发写入。设计:Redis 聚合计数——点赞/收藏实时写 Redis(计数用 INCR 原子累加,明细用 Set 或 Hash 存 user_id),保证低延迟与高并发;异步落库——把 Redis 的增量事件(点赞/取消)通过消息队列异步批处理写库,明细落 MySQL 持久化,避免高频写库压力。最终对账——定期或触发式对账,用 Redis 计数与数据库明细重算核对,发现不一致(如异步丢失、重复)则补偿修正,保证计数与明细收敛一致。一致性上,读计数走 Redis(快),写后异步落库(最终一致),对账兜底。还要处理取消点赞(Redis 减、Set 移除、DB 删除)与幂等。热点内容(爆款)需防热点,用本地缓存或分片。

点赞系统的核心是"Redis 扛实时计数+MQ 异步落库+对账兜底":Redis 提供低延迟与原子性,异步落库防写库压力,对账保证最终一致,兼顾性能与一致性。

-- Redis Lua:点赞时原子incr并对明细Set去重
redis.call('INCR', KEYS[1])                       -- 计数
redis.call('SADD', KEYS[2], ARGV[1])              -- 明细
return 1
#
★★★

7. 设计一个附近的人 LBS 系统,GeoHash、Redis GEO 与数据库空间索引在精度、范围查询与写入成本上的取舍?

如何设计附近的人 LBS 系统?GeoHash、Redis GEO 与数据库空间索引在精度、范围查询与写入成本上的取舍是什么?

  • LBS 系统存储方案
  • GeoHash、Redis GEO、数据库空间索引
  • 精度、范围查询、写入成本的取舍

附近的人 LBS 系统需按经纬度查询"范围内的用户"。GeoHash:用可排序的字符串编码经纬度,前缀越短范围越大,可模糊查询(前缀匹配),但边界邻近点可能被分到不同前缀、精度受编码长度限制,且不是按真实距离排序,需辅助过滤。Redis GEO:用 Redis 的 GEO 数据结构(ZSet 存储 geohash 编码的成员),支持 GEORADIUS 按距离查询与排序,内存级性能、查询快、写入简单,但数据量大时内存成本高、持久化受限。数据库空间索引:关系库用空间索引(如 PostGIS 的 GIST、MySQL 的 SPATIAL)存经纬度,支持空间范围查询,持久化可靠、可过滤,但查询性能低于 Redis、写入涉及索引更新成本。取舍:Redis GEO 性能最好、适合高并发实时查询但内存贵;数据库空间索引持久化、成本低但查询慢;GeoHash 是通用编码、可与缓存/DB 结合。一般方案:GeoHash 做粗粒度分区分桶 + Redis 缓存热点 + 数据库持久化兜底,按距离过滤。

三者权衡是"性能、成本、精度":Redis GEO 快但贵、空间索引持久但慢、GeoHash 灵活但需辅助过滤;高并发系统常组合使用。

#
★★

8. 如何设计数据库主库宕机切换(failover)演练,检测与选主流程、脑裂防护(fencing、quorum、STONITH)、切换后的数据一致性校验与旧主降级回收?

如何设计数据库主库宕机切换(failover)演练?检测与选主、脑裂防护、切换后一致性校验与旧主回收如何设计?

  • 主库宕机检测与选主
  • 脑裂防护(fencing、quorum、STONITH)
  • 切换后一致性校验与旧主回收

主库宕机切换演练要覆盖检测、选主、脑裂防护、一致性校验与回收。检测与选主:通过心跳/健康检查检测主库不可用,超时后触发选举(如用 etcd、ZooKeeper 或集群共识协议选新主,从候选从库中选数据最新者)。脑裂防护:防止出现"两个主"并存,需用 fencing(隔离旧主,使其无法对外服务)、quorum(多数派共识,少数派不选主)、STONITH(Shoot The Other Node In The Head,强制断电/隔离旧主)等技术,确保旧主被可靠隔离。切换后一致性校验:新主接收读写前,校验数据一致性(对比新旧主数据差异、检查异步复制是否追平、识别未同步的 binlog/WAL),必要时回放或标记差异。旧主降级回收:旧主恢复后不能直接当主,需降级为从库、重新与主库同步(重建复制),校验一致后再加入集群,避免旧主携带旧数据覆盖新主。演练需验证全程 RPO/RTO 达标。

failover 演练的关键是"可靠选主 + 防脑裂 + 一致性收敛 + 旧主安全回收";脑裂防护(fencing/quorum/STONITH)是避免双主损坏数据的关键。

#
★★

9. 区域级故障下如何设计跨地域灾备切换演练,DNS/全局流量调度切换、备库禁写与追平确认、RPO 评估与切回(failback)方案?

区域级故障下如何设计跨地域灾备切换演练?DNS/流量调度、备库禁写与追平、RPO 评估与切回如何设计?

  • 跨地域灾备的流量调度
  • 备库禁写与追平确认
  • RPO 评估与 failback

跨地域灾备切换演练应对区域级故障。流量调度:用 DNS/全局负载均衡(GSLB)把用户流量从故障区切换到备区,需验证 DNS 切换的生效与回源,避免缓存导致流量仍打到故障区。备库禁写与追平:切换前备区数据库先"禁写"(只读),等主备数据追平(确认异步复制追平、RPO 达到可接受),再开放读写,避免切换后数据丢失或账目不一致。RPO 评估:量化跨地域异步复制在故障瞬间丢失的数据量(因网延迟 RPO 通常非零),演练时实测并确认在业务容忍范围内。切回(failback):原区恢复后,把流量切回,需先反向同步(把备区新数据同步回原区)、校验一致、再切换流量,并处理"切回窗口"的数据不中断。演练要验证每个环节的 RTO/RPO 并形成可复用的切换手册。

跨地域灾备的核心是"流量切换 + 数据追平 + 一致校验 + 安全切回";RPO 取决于异步复制延迟,演练需实测并确认在容忍内,failback 要防数据回写覆盖。

#
★★

10. 如何设计定期备份恢复演练以实测验证 RTO/RPO 达标(恢复沙箱、计时、数据校验)?演练如何自动化与常态化?

如何设计定期备份恢复演练以实测验证 RTO/RPO 达标?如何自动化与常态化?

  • 备份恢复演练的目的
  • 恢复沙箱、计时、数据校验
  • 自动化与常态化

备份恢复演练用于实测验证"备份可恢复、RTO/RPO 达标"。恢复沙箱:在隔离的沙箱环境(非生产)从备份恢复数据库,避免影响生产;计时:从发起恢复到可对外服务的耗时,即为实测 RTO;数据校验:恢复后校验数据完整性(行数、校验和、关键数据比对、恢复时间点是否符合 RPO),确认备份可用且数据一致。自动化与常态化:把演练脚本化/自动化(编排恢复、校验、报告),按周期(如每月/每季)自动执行,无需人工干预;演练结果纳入监控与告警,RTO/RPO 不达标自动告警并触发改进;演练数据与报告归档,以满足合规审计。演练还应覆盖全量备份、增量备份与时间点恢复(PITR)等不同备份类型。核心是"经常演练、自动化验证、指标可量化"。

备份恢复演练的本质是"以演练实测验证备份可靠性与恢复能力",沙箱隔离+计时+校验测 RTO/RPO,自动化让演练常态化、可量化、可审计。

#
★★

11. CDC/复制链路中断后如何设计数据回补与对账方案(断点续传、全量/增量比对、差异补偿写入与幂等)?

CDC/复制链路中断后如何设计数据回补与对账方案?断点续传、全量/增量比对、差异补偿与幂等如何设计?

  • 复制链路中断的恢复
  • 断点续传、全量/增量比对
  • 差异补偿与幂等

CDC/复制链路中断后需回补数据并保证一致。断点续传:CDC(如 Debezium)用 binlog/日志位点(offset/LSN)记录消费位置,中断后从断点续传,避免重复或丢失;需持久化位点并支持从位点恢复。全量/增量比对:若中断期间数据大量变化或位点丢失,先做全量比对(源与目标库按主键比对差异),再用增量比对(时间窗口内比对新增/变更),定位差异。差异补偿写入:对差异数据按比对结果补写(插入缺失、更新变更、删除多余),并保证幂等——补偿写入以唯一键/业务号去重,重复执行不产生重复,避免重复插入或重复更新。设计上:回补前目标库进入"只读追平"状态,回补后校验(行数、校验和)确认一致,再恢复双向/正常复制。整个流程需可观测、可中断恢复。

复制链路回补的核心是"位点续传免重免漏 + 全量/增量比对定位 + 幂等补偿收敛";幂等是防止重复补偿导致脏数据的关键。

#
★★

12. 设计一个全球部署的 SaaS 数据库,多租户、跨地域、合规?

如何设计一个全球部署的 SaaS 数据库?多租户、跨地域、合规如何设计?

  • 多租户的数据模型
  • 跨地域部署与数据就近
  • 合规(数据主权、隐私)

全球 SaaS 数据库设计需兼顾多租户、跨地域与合规。多租户:三种模式——每租户独立库/实例(隔离好、成本高)、共享库每租户独立 schema(隔离较好)、共享表按租户 ID 隔离(成本低、需行级隔离);需设计租户 ID 字段与隔离策略,保证数据不串租户,并考虑租户隔离下的性能与索引。跨地域:按地域就近部署(数据本地化),全局用全球分布数据库(如 Spanner、CockroachDB)或"区域主数据+跨区同步",通过 GSLB 路由到最近区域,降低延迟;需处理跨区读写一致性(多数场景用区域本地读写+异步同步)。合规:遵循数据主权(数据存储在用户所在区域)、GDPR/个保法(删除权、数据本地化、跨境传输合规),多租户隔离需满足合规审计。设计需在"隔离、性能、成本、合规"间权衡,并支持按地域配置数据留存与合规策略。

全球 SaaS 数据库的核心权衡是"多租户隔离 vs 成本"、"就近访问 vs 跨区一致"、"区域部署 vs 合规";需按租户与地域维度设计隔离与数据治理。

#
★★

13. 设计一个分布式 IM 系统的消息存储,消息顺序、漫游、消息可靠性?

如何设计分布式 IM 系统的消息存储?消息顺序、漫游、消息可靠性如何保证?

  • IM 消息存储的模型
  • 消息顺序与漫游
  • 消息可靠性

分布式 IM 系统的消息存储需解决顺序、漫游与可靠性。消息顺序:同一会话内消息需有序,常用"会话内单调递增序号"(如会话级 seq 或消息 ID 单调分配),发送方按序分配、接收方按序展示,跨设备/多端靠 seq 排序;序号分配可用 Redis 自增或消息队列。漫游:用户换设备/多端登录要能拉取历史消息,消息需持久化到服务端(按会话存储),支持按会话+时间分页拉取;多端通过同步游标/增量拉取保证一致。消息可靠性:消息不能丢(存储先落库/落日志再确认,用可靠消息队列传输)、不能重(消息 ID 去重幂等)、送达可靠(ACK 重试、离线消息补发)。模型:消息表(会话、发送者、seq、内容、时间)按会话/用户分片,配合 Redis 存未读与在线状态。设计上存储用"分发+持久化"分离,保证高性能与可靠性。

IM 存储核心是"会话内有序(seq)+ 服务端持久化实现漫游 + 落库/去重/ACK 保可靠";重点是 seq 的单调分配与消息的幂等去重。

-- IM 消息表(按会话定位)
CREATE TABLE message (
  session_id BIGINT,
  seq        BIGINT,
  sender_id  BIGINT,
  content    TEXT,
  created_at TIMESTAMPTZ,
  PRIMARY KEY (session_id, seq)
);
#
★★

14. 设计一个电商订单系统的数据库 Schema,订单、库存、支付、物流的关系建模与一致性约束?

如何设计一个电商订单系统的数据库 Schema?订单、库存、支付、物流的关系建模与一致性约束如何设计?

  • 电商核心实体建模
  • 订单、库存、支付、物流的关系
  • 一致性约束

电商订单系统核心实体:订单(order)、订单项(order_item)、用户(user)、商品(product)、库存(stock)、支付(payment)、物流(shipment)。关系建模:订单-用户多对一;订单-订单项一对多(订单明细含商品、数量、单价、金额);订单-支付一对多(可多次支付、退款);订单-物流一对多(一次发货可拆多包裹)。一致性约束:订单总金额 = 各订单项金额之和,可用数据库约束或应用层校验;库存扣减与订单创建需原子(事务或预扣库存),防止超卖;支付状态与订单状态联动(支付成功才可发货);金额用 DECIMAL 存储避免浮点误差;外键与唯一约束(订单号唯一、支付流水唯一)保证数据完整。设计上:订单表主表+明细表,金额字段用 DECIMAL,状态机(待支付/已支付/已发货/已完成/已取消)用状态字段+约束保证合法流转;库存与订单解耦(预占库存、扣减库存、释放库存)。

电商订单建模核心是"实体关系清晰 + 金额精确 + 状态机受控 + 库存扣减原子";数据库层面用外键、唯一约束、DECIMAL 与事务保证一致性。

CREATE TABLE orders (
  id BIGSERIAL PRIMARY KEY,
  user_id BIGINT NOT NULL,
  order_no VARCHAR(32) UNIQUE NOT NULL,
  total_amount DECIMAL(12,2) NOT NULL,
  status SMALLINT NOT NULL DEFAULT 0,
  created_at TIMESTAMPTZ DEFAULT now()
);

CREATE TABLE order_item (
  id BIGSERIAL PRIMARY KEY,
  order_id BIGINT NOT NULL REFERENCES orders(id),
  product_id BIGINT NOT NULL,
  quantity INT NOT NULL,
  price DECIMAL(12,2) NOT NULL
);
#
★★

15. 实时排行榜的数据库设计(Redis ZSET 缓存 + 定期落库 + 对账)

实时排行榜的数据库设计是什么?Redis ZSET 缓存、定期落库与对账如何配合?

  • 排行榜的数据结构
  • Redis ZSET 与落库
  • 对账与一致性

实时排行榜需高并发计分与实时排名查询。设计:Redis ZSET 缓存——用 ZSet 存"成员→分数",支持 ZINCRBY 原子加分、ZREVRANGE 取 TOP N、ZRANK 查排名,内存级性能,实时性好;分数变化直接在 ZSet 更新。定期落库——把 Redis 的分数增量(或定时快照)异步批量落库(MySQL),持久化排名数据,防止重启/内存丢失;可按周期(如每 5 分钟)把 ZSet 全量或增量写库。对账——定期用 Redis ZSet 与数据库持久化数据对账,校验分数一致,发现差异(如落库丢失、重复)则补偿修正,保证 Redis 与 DB 收敛一致。处理:加分幂等(事件去重)、排行榜按上一个周期滚动(如日榜/周榜用不同 key)、冷热数据(热榜用 Redis、历史榜落库查询)。核心是"Redis 扛实时、DB 保持久、对账保一致"。

排行榜设计的核心是"Redis ZSet 实时计分 + 异步落库持久化 + 对账兜底";用不同 key 区分周期榜单,幂等加分防重复。

-- Redis Lua:原子加分
redis.call('ZINCRBY', KEYS[1], ARGV[1], ARGV[2])
return 1
#
★★

16. 设计订单超时未支付自动取消,延迟队列(Redis ZSET 时间轮)与数据库定时扫描两种方案的精度、吞吐与恢复机制如何权衡?

设计订单超时未支付自动取消,延迟队列与数据库定时扫描两种方案如何权衡?

  • 延迟队列(Redis ZSET 时间轮)
  • 数据库定时扫描
  • 精度、吞吐、恢复机制的权衡

订单超时未支付自动取消有两条主流路线。Redis ZSET 延迟队列(时间轮):把订单到期时间作为 score 存入 ZSet,用定时任务轮询 ZRANGEBYSCORE 取到期订单处理,精度高(分钟/秒级)、吞吐高(Redis 内存操作)、可支撑大量订单;缺点是数据在 Redis,若 Redis 丢失需重建,且需要把处理结果写回 DB 状态。数据库定时扫描:定时任务扫订单表未支付订单,按创建时间过滤,比较到期时间取超时订单置为已取消;实现简单、依赖 DB 持久、恢复性好(DB 顶事件),但精度受扫描频率限制(如每分钟扫一次)、吞吐受 DB 扫描成本限制(订单量大时扫描慢)。权衡:精度与吞吐要求高时用 Redis 延迟队列(配合 DB 兜底);订单量小、实现简单、强持久化时用 DB 定时扫描。恢复机制:Redis 方案需支持从 DB 重建未处理订单(启动时扫描 DB 未支付订单重新入队);DB 扫描方案天然可恢复,但需处理扫描间隙与重复扫描幂等。

权衡核心是"精度/吞吐 vs 简单/持久":Redis 延迟队列精度高但需设计恢复,DB 扫描简单可靠但精度与吞吐受限;生产常用延迟队列+DB 兜底。

#

17. 设计一个可观测性平台的数据存储,Metrics、Logs、Traces?

如何设计一个可观测性平台的数据存储?Metrics、Logs、Traces 如何存储?

  • 可观测性三大数据(Metrics、Logs、Traces)
  • 各自的存储方案
  • 数据量巨大下的设计

可观测性平台存储三类数据。Metrics(指标):时序数据(如 CPU、延迟、QPS),数据量小但写入频繁,用时序数据库(Prometheus、InfluxDB、TimescaleDB)存储,按时间压缩、聚合与降采样,支持告警与仪表盘。Logs(日志):文本/结构化日志,数据量大、非结构化,用日志存储(Elasticsearch、ClickHouse、Loki)存储,支持全文检索与过滤,按时间分区与生命周期管理(保留期后归档/删除)。Traces(链路):分布式调用链(span),记录请求在微服务间的调用,用 trace 存储(Jaeger、Tempo、SkyWalking),按 trace ID 关联 span,支持调用链分析。设计上:三类数据量大,需分布式存储、按时间分区、索引优化、采样与压缩;日志与 trace 常关联(trace ID 关联日志),用于故障定位。可观测性存储需高吞吐写入、可扩展与长生命周期管理,通常组合多种专门存储。

可观测性存储按数据类型选专用引擎:Metrics 用时序库、Logs 用检索/日志库、Traces 用链路库;关键是大数据量的写入优化、索引与生命周期管理,并做三类数据关联。

#

18. 设计数据库读写分离的监控与自动切换(延迟告警、从库摘除)

如何设计数据库读写分离的监控与自动切换?延迟告警、从库摘除如何设计?

  • 读写分离的监控
  • 延迟告警与从库摘除
  • 主从切换与一致性

读写分离的监控与自动切换核心是"感知从库健康并保障一致性"。监控:监控主从复制延迟(主库 binlog 位点 vs 从库位点)、从库存活、从库查询延迟与错误率,采集到监控系统。延迟告警:当复制延迟超过阈值(如 5 秒)告警,因为延迟会导致读不到最新数据(读写一致性问题);设置分级阈值(警告/严重)。从库摘除:当某从库延迟过高、故障或监控异常时,把该从库从读流量负载中摘除(从负载均衡/连接池下线),避免读到过期数据或因故障拖垮请求;恢复后重新加入。自动切换:主库故障时触发主从切换(选新主、更新路由),从库故障只摘除不影响主链路;切换需保证数据一致性。读一致性:对强一致的读可走主库或"读从库+确认延迟等因素"。设计上:读写分离需在应用层/中间件做读写路由,监控中心下发摘除/恢复指令。

读写分离的核心是"监控从库健康与复制延迟",延迟告警触发摘除,保证读不到过期数据;主故障切主、从故障摘除,保障可用与一致。

#

19. 设计用户签到系统,连续签到天数、补签与月度统计如何用 Redis 与数据库建模?并发防重与跨天边界如何处理?

如何设计用户签到系统?连续签到天数、补签与月度统计如何用 Redis 与数据库建模?并发防重与跨天边界如何处理?

  • 签到数据的 Redis 与数据库建模
  • 连续签到、补签、月度统计
  • 并发防重与跨天边界

用户签到系统需处理连续签到、补签与月度统计。建模:Redis 用 Bitmap(SETBIT 按 date 存签到标记)或 Set 存签到日期,支持 O(1) 判断是否签到、统计月度签到天数;数据库用签到表(user_id、sign_date、连续天数)持久化,供统计与历史。连续签到天数:用 Redis 位运算(从今天往前数连续为 1 的位数)或按日期判断是否连续,计算连续天数;补签:补签后更新对应日期标记与连续天数。月度统计:用 Redis Bitmap 的 BITCOUNT 统计当月签到天数,或查询 DB 聚合。并发防重:同一用户同一日重复签到需防重,用 Redis SETNX(key=user:date)原子判断,已签到则拒绝,保证一天只签一次。跨天边界:需定义"天"的边界(如按自然日或按用户时区),用统一日期键(如 yyyy-MM-dd)避免时区混乱;跨天时连续天数计算以日期连续性为准。设计上:Redis 挡实时判断与防重、DB 持久化兜底,定期对账。

签到系统核心是"Redis 快速判断与防重 + DB 持久化":Bitmap 高效统计、SETNX 防同一天重复、统一日期键处理跨天,连续天数靠日期连续性计算。

-- Redis Lua:防重签到(同一天只签一次)
if redis.call('SETNX', KEYS[1], 1) == 1 then
  redis.call('SETBIT', KEYS[2], 0, 1)  -- 标记当日签到
  return 1
end
return 0