编程进阶网 编程进阶网
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机的原理
  • 操作系统原理
  • 网络协议原理
  • 数据库的原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 技能之旅
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Kotlin精通
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 在线工具
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 加解密
  • 时间日期
  • 网络工具
  • 颜色设计
  • 二维码
  • 开发实用
  • 计算机的原理
  • 操作系统原理
  • 网络协议原理
  • 数据库的原理
  • 序卷导读
  • 数据本质
  • 运行模型
  • 并发设计
  • 内存真相
  • 交互系统
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 技能之旅
  • 体系建设
  • 代码品质
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 性能优化
  • 数据结构导论
  • 线性结构详解
  • 树哈希结构论
  • 容器设计实战
  • 经典算法思想
  • 工程案例剖析
  • 算法题库精练
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++编程技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript案例
  • JavaScript高级
  • Kotlin精通
  • Android库解读
  • Android专栏
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • 毛选解读
  • 自我精进
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • 业务思考

    • README
    • 01.业务连续评估实战
    • 02.质量连续评估实战
    • 03.运营连续评估实战
    • 04.成本效率评估实战
    • 技术团队效能评估
    • 06.从救火到防火实战
      • 1. 案例引入
        • 1.1 凌晨三点的电话
        • 1.2 顺藤摸到根因
        • 1.3 我们要回答什么
      • 2. 稳定性全景图
        • 2.1 三层设防模型
        • 2.2 为什么这么切
      • 3. 业务连续三把锁
        • 3.1 稳定测试先弄坏
        • 3.2 容灾演练打疫苗
        • 3.3 发布流水线防赌
      • 4. 举一反三批量治理
        • 4.1 单点到面扫描
        • 4.2 安全基线文档化
        • 4.3 杠杆效应量化
      • 5. 人因风险四防线
        • 5.1 人比系统更危险
        • 5.2 四道防线设计
        • 5.3 一次性治理 20+ 风险项
      • 6. 四级监控体系
        • 6.1 底层到业务四层
        • 6.2 告警减肥:87→23
      • 7. 质量连续性举证法
        • 7.1 三级数据表达法
        • 7.2 归因链数字逻辑
      • 8. 反模式
        • 8.1 只修不防
        • 8.2 不举一反三
        • 8.3 数据无归因
        • 8.4 告警铺天盖地
      • 9. 稳定性自检清单
        • 9.1 十二条自检
      • 10. 综合案例串讲
        • 10.1 小林 12 个月翻盘全貌
        • 10.2 述职现场还原
        • 10.3 设计哲学回扣
        • 10.4 稳定性体系速查
    • 07.降本提效团队实战
  • 产品思考

  • 软实力

  • 开发流程

  • Git应用

  • 技术模版

  • 技术规范

  • markdown

  • mermaid

  • license

  • 博客部署

  • 技术招聘

  • 八股文

  • 技术
  • 业务思考
杨充
2016-07-13
目录

06.从救火到防火实战

# 06.从救火到防火实战

支付系统每周宕机一次——小林用 12 个月,把业务连续性、运营连续性、质量连续性三套方法论打穿成一个完整的稳定性体系。

# 目录介绍

  • 1. 案例引入
    • 1.1 凌晨三点的电话
    • 1.2 顺藤摸到根因
    • 1.3 我们要回答什么
  • 2. 稳定性全景图
    • 2.1 三层设防模型
    • 2.2 为什么这么切
  • 3. 业务连续三把锁
    • 3.1 稳定测试先弄坏
    • 3.2 容灾演练打疫苗
    • 3.3 发布流水线防赌
  • 4. 举一反三批量治理
    • 4.1 单点到面扫描
    • 4.2 安全基线文档化
    • 4.3 杠杆效应量化
  • 5. 人因风险四防线
    • 5.1 人比系统更危险
    • 5.2 四道防线设计
    • 5.3 一次性治理 20+ 风险项
  • 6. 四级监控体系
    • 6.1 底层到业务四层
    • 6.2 告警减肥:87→23
  • 7. 质量连续性举证法
    • 7.1 三级数据表达法
    • 7.2 归因链数字逻辑
  • 8. 反模式
    • 8.1 只修不防
    • 8.2 不举一反三
    • 8.3 数据无归因
    • 8.4 告警铺天盖地
  • 9. 稳定性自检清单
    • 9.1 十二条自检
  • 10. 综合案例串讲
    • 10.1 小林 12 个月翻盘全貌
    • 10.2 述职现场还原
    • 10.3 设计哲学回扣
    • 10.4 稳定性体系速查

# 1. 案例引入

# 1.1 凌晨三点的电话

小林,Java 四年经验,2024 年 Q1 被 Leader 紧急调去接手公司的核心支付系统。原负责人离职,代码交接文档只有一句"跑得动就别改"。

周一 09:00  小林第一天。Leader: "支付交给你了,上个月崩了两次。"
            小林打开监控大盘: QPS 峰值 3000, 4台 8C16G 云服务器
            单测覆盖率 12%, 灰度发布: 无
            小林在 TODO 清单写: "这周别出事"

周三 03:14  钉钉告警: 支付接口错误率 30% → 50% → 80%
     03:18  值班同学: "Redis 连接超时!"
     03:25  重启 Redis,错误率下降但未恢复
     03:32  小林被电话叫醒: "你负责的支付挂了! 商家在投诉!"
     03:40  小林登录: Redis 连接池全部耗尽。上游营销服务突增 QPS
            → 支付缓存 key 集中过期 → DB 查询激增 → 连接池打满
     03:48  临时扩容 + 缓存过期时间加随机偏移
     04:12  恢复。故障持续 58 分钟, 1,260 笔交易失败

事后复盘(5 Why):

  1. 为什么支付挂了? → Redis 连接池耗尽。
  2. 为什么连接池耗尽? → 缓存 key 集中过期,DB 查询穿透。
  3. 为什么集中过期? → 所有 key 用相同 TTL,没加随机偏移。
  4. 为什么没提前发现? → 没有缓存雪崩的监控/演练/预案。
  5. 为什么没有预案? → 没人做过稳定性评估,系统靠运气跑。

Leader 在复盘会上只说了一句:「修完这个 bug,我要看到你拿出一套方案——怎么保证下个月、下下个月不再有这种半夜电话。」

# 1.2 顺藤摸到根因

小林的真实问题不是 Redis 连接池,而是三个更深层的问题:

修复 Redis 连接池 → 下次可能是 DB 连接池
修复缓存雪崩 → 下次可能是线程池 OOM
修复这个 bug → 下个 bug 不知道什么时候来

根因 = 没有稳定性体系。每次都是在"灭眼前的火",而不是"防止下一场火"。

# 1.3 我们要回答什么

本章要回答三个问题——这三个问题对应的正是小林接下来 12 个月的三个战役:

问题 对应能力 核心动作
怎么让系统不挂、挂了能快速恢复? 业务连续性 稳定测试 + 容灾演练 + 发布流水线
怎么让日常运营不踩同样的坑? 运营连续性 举一反三 + 批量治理 + 人因防线
怎么证明质量确实在变好? 质量连续性 数据归因链 + 方法论推广

读完本章,你会拿到一套**"从救火到防火"的完整动作库**。

# 2. 稳定性全景图

# 2.1 三层设防模型

小林梳理出的模型——不是三套独立的 checklist,而是一个从外到内、环环相扣的防御体系:

第一层:业务连续性(系统不挂)
├── 稳定性测试:模拟所有"可能让它挂"的场景
├── 容灾演练:验证"挂了之后"能不能恢复
└── 发布流水线:让每次上线都有守门员

第二层:运营连续性(不踩同样的坑)
├── 举一反三:修一个 bug → 扫描全部门同类隐患
├── 批量治理:从修 1 个到治理 20+ 个
└── 人因防线:让"人"的操作不会变成灾难

第三层:质量连续性(用数据证明)
├── 趋势数据:质量问题在变好还是变差
├── 归因链:每一项改善能追溯到具体措施
└── 方法论扩散:从自己用到推广到其他团队

# 2.2 为什么这么切

疑惑:为什么三层而不是一步到位?

论证:小林接手第一周如果直接去"写质量报告",生产环境还天天崩——报告就是废纸。反之,系统稳了但永远在处理紧急故障,没有时间做体系化治理——稳定不可持续。

结论:先止血(第一层),再建制(第二层),最后自证(第三层)。这是"救火→防火"的唯一可行路径。

# 3. 业务连续三把锁

# 3.1 稳定测试先弄坏

修完 Redis 缓存雪崩后,小林做的第一件事不是改架构,而是列了一张清单——把所有"以为没问题"的地方测一遍:

测试类型 验证内容 首次测试发现的隐患
缓存失效 Redis 全部 key 同时过期 核心接口 P99 从 50ms 飙到 8s
连接池满 DB/Redis/HTTP 连接池打满 支付回调线程池无界队列→OOM
依赖超时 下游服务随机增加 5s 延迟 2 个接口没有设置超时,无限等待
磁盘满 日志/临时文件写满磁盘 Nginx 日志无轮转策略

结论:"我以为它没问题"是所有线上故障的第一句遗言。稳定测试是把这句话提前说出来的唯一方式。

# 3.2 容灾演练打疫苗

疑惑:测试没测出来的怎么办?

论证:小林设计了第一次容灾演练——模拟单台 Redis 宕机:

演练步骤 预期 实际结果 暴露问题
① kill Redis 主 Sentinel 自动切换 切换耗时 12 秒 切换期间 32 个请求返回 500
② 验证新主 新主正常 数据完整 应用连接池没 evict 失效连接,继续往旧主发请求
③ 验证恢复 切换后恢复 5 秒后恢复 客户端超时 30s,远大于切换时间

修复:缩短 Redis 超时 30s→3s、开启连接池 idle 检测、集成熔断器降级到本地缓存。

容灾演练 = 给系统打疫苗:用小剂量可控的故障,验证免疫能力。小林每月一次,从"手心出汗"到"从容记录"。

# 3.3 发布流水线防赌

疑惑:过去的发布——Jenkins 打个包→丢服务器→群公告"上了"→等 10 分钟看监控。怎么让它变成可防可控?

论证:小林设计了三段式发布流水线:

代码合并 → 编译构建 → 单测(覆盖率≥60%卡点)
    → 集成测试 → 接口自动化(核心接口 100%)
    → 预发布 → 全链路压测 → 灰度 5% → 灰度 50% → 全量
卡点 拦截条件 首次拦截
单测覆盖率 新增代码 < 60% 3 次
集成测试 核心接口失败 2 次
全链路压测 P99 > 基线 × 1.5 1 次:新 SQL 没走索引
灰度 5% 错误率 > 0.1% 0 次(压测阶段已拦截)

结论:发布回滚率从 30% 降到 0%——不是运气好了,是每个阶段都有守门员。

# 4. 举一反三批量治理

# 4.1 单点到面扫描

疑惑:修完一个缓存雪崩就够了?同类问题有没有存在于其他 30+ 个服务里?

论证:小林以 Redis 缓存雪崩为起点,对全部门共性风险做了扫描:

扫描维度 范围 隐患 整改
缓存雪崩 全部 30+ 服务 8 个服务集中过期 统一加 TTL 随机偏移 ±30%
连接池配置 全部服务 5 个无界队列 / 30s 超时 统一:有界队列 + 3s 超时
单点依赖 核心链路 3 个服务依赖单 Redis 改哨兵模式 + 故障转移
降级策略 全部服务 12 个服务无降级 核心链路全配备

结论:修一个 bug 只值 4 小时,但举一反三的扫描能释放 100 个小时的隐性风险。

# 4.2 安全基线文档化

小林把共性问题和修复方案凝练成《支付系统稳定性安全基线》,5 条 check item:

# 基线规则 违反后果
1 所有外部依赖必须设置超时(≤ 5s) 无超时 = 雪崩
2 所有缓存 key 必须加 TTL 随机偏移(±30%) 集中过期 = 缓存雪崩
3 所有连接池必须为有界队列 + evict 检测 无界队列 = OOM
4 核心链路必须有降级策略(熔断/限流/缓存兜底) 无降级 = 依赖挂了你也挂
5 新服务上线前必须通过稳定性测试 checklist 未测试 = 定时炸弹

这份基线后来被推广到公司其他 5 个业务线——一份文档的杠杆效应。

# 4.3 杠杆效应量化

方式 修复故障数 投入工时 每条修复成本
单点修复 1 个 4h 4h/个
批量治理 20+ 个 16h 0.8h/个

结论:举一反三不是"多做点",而是用 4 倍的精力换 20 倍的效果。

# 5. 人因风险四防线

# 5.1 人比系统更危险

稳定了两个月后,又出事故了——不是代码,是人。

运维同学把接口超时从 3s 改为 10s
直接在配置中心改成 10000——没 Code Review,没灰度
5 分钟后线程池耗尽:下游 3 个服务同时超时 10s
故障 22 分钟, 影响 892 笔交易

根因:系统稳了,但人可以直接改生产配置——没有安全边界。

# 5.2 四道防线设计

防线 设计 效果
① 变更规范 所有变更走审批流;高风险变更双人审批 配置变更 100% 审批覆盖
② 变更室操作 重大变更必须在大屏前操作,另一人实时盯监控 操作错误秒级发现
③ 白屏化工具 常用运维操作封装为 Web 界面,内置影响面检查 + 自动回滚 SSH 操作比例从 60%→15%
④ 环境隔离 研发/测试/预发/生产四层隔离;预发与生产共享配置中心 变更先过预发再进生产

实施后:变更引致的 P0/P1 故障从月均 1.5 次 → 0 次。

# 5.3 一次性治理 20+ 风险项

疑惑:除了配置变更,还有哪些"人可触达的风险"?

论证:小林提炼出一个模型——任何可以改的数字 = 潜在的风险点:

风险类型 扫描范围 发现隐患 治理方案
配置类 所有 timeout/queueSize/maxConn 20+ 项无安全边界 统一配置模板 + 上下限
权限类 生产环境 SSH/DB 权限 8 人持有 root 权限最小化 + 操作审计
脚本类 运维脚本/定时任务 5 个无输入校验 参数白名单 + dry-run
架构类 单点/无降级/无双活 同 §4 已治理 ——

结论:人因风险的本质是**"能做"和"不能做"之间没有隔离带**。四道防线就是这条隔离带的四个钢筋。

# 6. 四级监控体系

# 6.1 底层到业务四层

第四层:业务监控
├── 支付成功率 / 金额趋势 / 商户投诉数
└── 成功率 < 99.5% → P0 告警

第三层:应用监控
├── 接口 QPS / P99 / 错误率 / 线程池 / 连接池
└── 错误率 > 0.1% → P1 告警

第二层:中间件监控
├── Redis/MySQL/MQ 的连接数 / QPS / 慢查询 / 主从延迟
└── 慢查询 > 100ms → 告警

第一层:基础设施监控
├── CPU / 内存 / 磁盘 / 网络 / 进程存活
└── CPU > 80% → 告警

# 6.2 告警减肥:87→23

疑惑:告警多不好吗?

论证:告警疲劳比漏告警更危险。当你每天收到 87 条告警,你就不再看了。

结论:小林把 87 条告警砍到 23 条,原则是——每条告警背后必须对应一个明确的 action。没有 action 的告警 = 关掉。

# 7. 质量连续性举证法

# 7.1 三级数据表达法

疑惑:系统稳了。但怎么证明"稳了"是自己的功劳而不是运气?

论证:年终述职季,Leader 问小林"你这 12 个月做成了什么"。小林对比了三种表达方式:

级别 表达 说服力 示例
弱 "线上问题变少了" ⭐ 主观感受,无数据
中 "P0/P1 从月均 1.5→0" ⭐⭐⭐ 有数据,无归因
强 "P0/P1 归零,归因于:①稳定测试修 8 个隐患 ②灰度拦截 3 次 ③演练验证切换" ⭐⭐⭐⭐⭐ 数据 + 归因 + 方法论

结论:数据不说谎,但你得帮它说话——从"数字下降"到"因为我做了 X/Y/Z 所以下降"才是完整的证据链。

# 7.2 归因链数字逻辑

小林逐项建立了因果:

P0/P1 故障 1.5次/月 → 0次/月
├── 归因①: 稳定性测试(发现 + 修复 8 个隐患)
├── 归因②: 容灾演练(验证切换机制,修连接池)
├── 归因③: 发布流水线(单测 + 灰度拦住 3 次高危变更)
└── 归因④: 人因治理(四道防线杜绝配置事故)

支付成功率 99.82% → 99.98%
├── 归因①: 缓存雪崩治理(TTL 偏移 + 降级)
├── 归因②: 连接池规范(有界队列 + 3s 超时)
└── 归因③: 共 35 项隐患全量修复

# 8. 反模式

# 8.1 只修不防

症状:报警 → 修 bug → 发布 → 下个报警。永远在救火。

危害:修得越快,Leader 越觉得你"适合修 bug"——你被锁死在救火员的角色里。

修复:每修完一个 bug,立即做三件事:①写进复盘文档 ②扫描同类风险 ③更新安全基线。

# 8.2 不举一反三

症状:修完 Redis 连接池,MySQL 连接池也炸了——"上次修的不是这个"。

危害:同一个根因换一张皮,你永远追不上。

修复:任何隐患修复后,问自己:同样的风险模式在哪些其他服务/组件上也存在?

# 8.3 数据无归因

症状:述职时说"线上故障少了""系统比以前稳了"——没有任何归因。

危害:评审人不知道"稳了"是你的功劳还是运气。一次大促没出事可能是流量不够大。

修复:每条质量数据的背后必须有归因链——数据 + 措施 + 因果逻辑。

# 8.4 告警铺天盖地

症状:87 条告警规则、每个异常都通知、钉钉群 24 小时响。

危害:告警疲劳 → 关静音 → 真故障没人看。

修复:砍到每条告警都有 action。没有 action 的告警 = 噪音。

# 9. 稳定性自检清单

# 9.1 十二条自检

接一个存量系统(或年终自评),逐条打勾。任何一条打不了勾 = 风险敞口:

业务连续性 (4 条):
□ 1. 对系统做过稳定性测试(缓存失效/连接池满/依赖超时/磁盘满)
□ 2. 每季度至少完成一次容灾演练并形成复盘报告
□ 3. 发布流水线有卡点(单测 ≥60% + 集成测试 + 灰度)
□ 4. 核心链路全部有降级策略(熔断/限流/缓存兜底)

运营连续性 (4 条):
□ 5. 风险扫描不局限当前模块——对全部门同类服务做过 check
□ 6. 有安全基线文档,且推广到至少 1 个其他团队
□ 7. 人因防线覆盖了配置变更/权限/脚本/环境
□ 8. 告警规则每条有 action(总数 ≤ 30 条)

质量连续性 (4 条):
□ 9. 有质量趋势数据(P0/P1/成功率/发布回滚率)且留存 6 个月以上
□ 10. 每一项改善有归因链(数据 + 措施 + 因果)
□ 11. 方法论有文档沉淀(安全基线/演练 SOP/审批流程)
□ 12. 至少做过一次内部分享或外部推广

# 10. 综合案例串讲

# 10.1 小林 12 个月翻盘全貌

维度 Q1(接手时) Q4(12个月后) 变化
P0/P1 故障 月均 1.5 次 连续 3 个月 0 次 清零
变更引致故障 月均 1.5 次 0 次 清零
支付成功率 99.82% 99.98% +0.16%
发布回滚率 30% 0% 清零
单测覆盖率 12% 68% +56%
告警规则 87 条 23 条 -74%
容灾演练 0 次 每月 1 次 常态化
安全基线 0 条 5 条(推广 5 个业务线) 从 0 到 1

# 10.2 述职现场还原

Leader:「来说说你这 12 个月做成了什么。」

小林(打开第一页):

支付系统 P0/P1 故障从月均 1.5 次降至连续 3 个月 0 次。归因于: ① 稳定性测试发现并修复 8 个隐患 ② 容灾演练验证切换机制,3 轮共发现 4 个关键缺陷 ③ 发布流水线在灰度阶段拦截 3 次高危变更 ④ 人因风险治理——四道防线让变更引致故障归零

方法论输出:《稳定性安全基线》已推广至公司 5 个业务线。

Leader:「这是我今年看到的述职里,最能清晰证明'做了什么、为什么有效、怎么复制'的报告。」

# 10.3 设计哲学回扣

小林 12 个月的三条心得:

  1. 先止血,再建体系:系统还崩着就别写文档,先把监控搭起来、最大隐患修掉
  2. 用一次事故,救一百次未来:每修一个 bug,问"同类的在哪儿"
  3. 数据不说谎,但你需要帮它说话:数字 + 归因 + 方法论 = 完整的证据链

# 10.4 稳定性体系速查

维度 核心动作 关键产出 一句话
业务连续性 稳定测试 + 容灾演练 + 发布流水线 P0→0, 回滚率→0 让它不挂
运营连续性 举一反三 + 批量治理 + 人因防线 20+ 项统一治理 不让同因再挂
质量连续性 趋势数据 + 归因链 + 方法论推广 成功率+0.16%, 5 线推广 证明它更稳了

下一集预告:小林拿着报销单报销云资源时,Leader 拍了一张成本账单在桌上:「系统稳了是好事——但上季度成本涨了 40%,业务只涨了 10%。另外你的团队 6 个人,最近代码合并冲突越来越频繁……你觉得问题出在哪?」

小林的新战役:从能跑,到跑得快。

上次更新: 2026/07/13, 14:25:52
技术团队效能评估
07.降本提效团队实战

← 技术团队效能评估 07.降本提效团队实战→

最近更新
01
11.数据库的原理总结
07-12
02
11.操作系统原理总结
07-10
03
7.资深程序员软能力
07-10
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 鄂ICP备2024073355号-1 | 鄂ICP备2024073355号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式