Skip to content
On this page

架构实战经验

← 返回专题记录

高性能架构

冷热分离

根据业务状态,对适合的业务表做冷热分离。终态数据不常使用,只读不写。接受冷热数据分开查询,无同时读取数据需求。无复杂查询要求和快速响应要求。

1. 判断冷热

  • 时间维度
  • 状态维度
  • 组合状态

2. 触发分离

  • 状态转移时(代码侵入,监听数据库)
  • 定时扫描(跟时间相关)

3. 如何分离

  • 判断(判断 + 持久化)
  • 转移冷库(状态迁移,覆盖遗漏,幂等唯一不重复)
  • 删除热库

一致性(最终一致性,容错):

  • 添加重试
  • 幂等

数据量:

  • 分批处理
  • 状态转移触发不需要考虑

并发性:

  • 多线程加速
  • 数据隔离
  • 先锁定数据,锁超时,再 update

4. 如何使用

  • 入口区分

5. 历史数据迁移

  • 分批迁移方案,只需要执行一次历史数据标记,就可以启动老数据迁移。
  • 状态转移触发,则需要对所有历史数据的最终态做一次迁移,可能需要停机。

6. 后续冷库优化

  • 修改成 OLAP 数据库,支持简单条件查询
  • HBase
  • Doris

读写分离

主要解决高并发的问题。

查询分离

写效率尚可,解决查询慢、关联表多、历史数据多、所有数据任何时候都可能被修改和查询。

1. 触发

  • 写入时触发,有代码入侵
  • 写入时触发,异步发起更新,有代码入侵
  • 监控数据库,日志触发,业务复杂时难以穷举

2. 实现查询分离

  1. 数据更新 need_update
  2. 发送 MQ
  3. 消费者获取 MQ
  4. 查询 need_update=true
  5. 将查询的数据更新到查询库
  6. 更新 need_update=false
  7. 回调告知消费完成

采用 MQ 触发查询更新(解耦,异步):

  • 入库线程限制
  • 自动重试
  • 并发场景

MQ 带来的问题:

  • 选型
  • MQ 宕机
  • 消息重复投递
  • 消息丢失问题

建议:

  • 数据标识来触发,而不是通过 id(need_update
  • 批量查询,批量更新标识,保证幂等性操作
  • 先锁定数据,锁超时,再 update,解决并发问题
  • 时序性问题:
    1. 业务 id 作为 key,保证相同业务顺序执行
    2. 引入 update_time 或版本号,如果发现版本号或者 update_time 倒退,就再次触发同步

3. 存储

  • ES:侧重全文检索、相关度排序。数据需要整理成一整条数据。
  • Doris:侧重 SQL 适配,OLAP
  • MongoDB:文档非结构化

4. 使用

  • 查询数据可能存在延迟

5. 历史数据

  • 修改 need_update=true
  • 分批渐进式处理

拆分存储

选型

  • 数据库分区
  • NoSQL
  • NewSQL
  • 分库分表

MongoDB

文档数据库,非约束关系型数据库,没有事务,稳定性需要结合场景评估。

NewSQL

  • OLTP:TiDB、PolarDB、OceanBase
  • HTAP:Doris、TiDB + TiFlash、ClickHouse
  • 冷数据新范式:S3/OSS + Trino/Dremio,AnalyticDB for MySQL

分库分表

  1. 组装动态 SQL
  2. 数据库路由
  3. 结果合并

技术模式:

  • 代理模式
  • 客户端模式

分片涉及要点

  1. 分片主键,根据业务需求选择字段
  2. 分片策略
    • 范围分片
    • Hash 分片
    • 混合分片(先范围再 hash)
  3. 业务代码如何修改
    • 对微服务影响更小,建议拆分微服务
    • 读数据考虑避免跨库跨表
  4. 历史数据迁移
    • 存量直接迁移,增量监听数据库日志
    • 验证数据全量
  5. 未来扩容方案

秒杀设计

多级分流

1. 接入层

  • 客户端缓存
  • 强制缓存和协商缓存
  • 动静分离
  • 静态资源 CDN 缓存
  • 网关做限流、熔断、降级、黑白名单
  • 流量做负载均衡:LVS、Nginx、HAProxy、Keepalived
  • 传输链路优化:
    • keep-alive
    • 多路复用
    • 即时压缩
    • 快速 UDP 连接

2. 应用层

  • 核心业务拆分成微服务,不互相影响
  • 核心业务做无状态,便于快速弹性伸缩
  • 异步化,流量削峰,MQ
  • 服务端缓存
    • 缓存属性
    • 缓存风险

3. 持久层

  • 拆分存储
  • 读写分离

业务超卖

  1. 前置拦截

    • 进一步请求准入控制
    • 做限流
    • 推荐令牌桶
  2. 锁机制

    • Redis + Lua
    • 乐观锁
    • 悲观锁
  3. 最终一致性

    • 事务消息
    • 对账补偿
  4. 下单锁定,支付锁定,下单锁定超时释放

缓存场景

查询优化

写入优化

写缓冲

  • 预约场景
  • WAL 的思想引入缓冲层
  • 日志收集埋点场景

高可用架构

限流熔断

  • 原理:限流在入口处拦截过载流量;熔断在调用端切断故障下游,防止雪崩。
  • 关键点:限流保护自己,熔断保护下游和整体链路。

冗余 Failover

  • 原理:任何组件都至少部署两个以上节点,消除单点故障(SPOF)。
  • 关键点:配合 Keepalived 或 Sentinel 实现故障自动转移。

去中心化

  • 原理:移除中心化管理节点(Master),采用 P2P 或 Gossip 协议,避免 Master 成为瓶颈或单点。
  • 关键点:如 Redis Cluster、Cassandra、Blockchain,节点地位对等。

高可扩展

微服务架构

  • 原理:将单体应用按业务领域拆分为独立部署服务,实现开发、部署、扩容的解耦。
  • 关键点:服务粒度控制,避免分布式事务带来的复杂性。

事件驱动架构

  • 原理:生产者和消费者通过中间件交互,互不感知,实现逻辑解耦和流量削峰。
  • 关键点:消息的可靠投递和幂等性处理。

无状态设计

  • 原理:服务节点不存储会话状态(Session),状态外置(Redis/JWT),使节点可随意扩展。
  • 关键点:JWT 换取空间换时间,Redis Session 换取时间换空间。

混合方案

  1. Access Token (JWT) + Refresh Token (存 Redis)
  2. JWT 携带最小化信息 + 局部查库

微内核 + 插件


Spring Cloud + k8s 缺点

  1. 认知负担、学习成本
  2. 资源消耗更大,采用代理的话调试困难,开发体验差
  3. 平台耦合,耦合 k8s 这一套
  4. k8s 拓展功能并不丰富,四层代理的基础在服务治理上并不强大,ELK 也适配不好

Elasticsearch 数据持久化流程

Elasticsearch 通过 内存缓冲 + 事务日志(Translog)+ 定期刷盘 实现高性能与数据可靠性的平衡。

持久化步骤

  1. 写入 Translog
  2. 写入内存缓冲区(Indexing Buffer)
  3. Refresh(默认每 1 秒)
  4. Flush(定期或触发条件满足时)
  5. Merge(后台自动)

可调参数

  • index.translog.durability
  • index.translog.sync_interval
  • index.translog.flush_threshold_size
  • index.refresh_interval
  • indices.memory.index_buffer_size
  • index.translog.flush_threshold_period

建议:生产环境保持 translog.durability=request 以确保数据安全;批量导入时临时关闭 refresh 提升性能。

深度分页问题

  • max_result_window
  • Search After
  • Scroll API
  • 业务层优化

常见策略:

  • 禁止深度翻页
  • 改用“加载更多”
  • 预聚合 / 分桶
  • 异步导出