楼下的川菜馆要换新菜单,但老板没有挂出“暂停营业”的牌子,而是把隔壁空置的店面悄悄改造成了第二间厨房。老厨房继续炒着水煮鱼,新厨房里大厨慢条斯理地试做融合菜。等新菜真的调好了味,服务员才笑着把客人请进新厨房——全程没有一位食客被劝退,没有一秒出现过“店面关闭”。这就是蓝绿部署:用两套完全一致的厨房,换来一次不关门的“换菜单”。蓝环境是正在颠勺的老厨房,绿环境是蓄势待发的新厨房,流量就是那一桌接一桌的客人。客人想去哪间厨房,全凭服务员(负载均衡器)的一句话。这套策略之所以在 AI 服务和互联网公司里广受欢迎,是因为它同时解决了两个最痛的问题:新版上线不能停服,出了问题又要能瞬间回到老味道。
蓝绿部署是 AI 工程化中“安全发布”的基石,熟练掌握它,意味着你能让模型服务零停机上线、秒级回滚,生产环境的稳定性从“碰运气”变成“可设计”。
可视化演示
展示AES分组密码ECB与CBC两种工作模式的加密流程,对比相同明文分组在不同模式下的密文输出差异。
本节配有交互动效(进入视口后自动加载,约 3KB)。
ECB模式 每个明文分组独立加密,相同明文产生相同密文 无需初始向量,实现简单但安全性较低 ECB模式不适用于大规模数据加密
部署原理
楼下川菜馆换菜单的秘诀,在于老板从未让任何一间厨房“空着等”。老厨房(蓝环境)从早到晚火苗不熄,新厨房(绿环境)悄悄完成装修和试菜。两间厨房的设备、调料、锅具完全一致,唯一的差别只是墙上的菜单。软件世界里的蓝绿部署正是这种思路:同时维护两套一模一样的生产环境,蓝环境运行当前正式版本,绿环境部署待发布的新版本。新版本先在绿环境里做完整的测试与验证,蓝环境则继续服务所有线上请求。
当绿环境一切就绪,系统把流量像引座一样从蓝环境切换到绿环境。这个切换动作不是“关闭老厨房再打开新厨房”,而是服务员在门口轻轻改变引导方向。对正在用餐的客人来说,没有任何感知——没有上菜中断,没有门帘拉下。整个发布过程的核心指标只有一句话:用户无感。
正是这个设计让蓝绿部署成为零停机发布的经典答案。传统发布是先下架再上架,中间必然出现服务真空;蓝绿部署则把“发布”从一次高风险的手术,变成一次低风险的开关切换。
回到川菜馆的比喻:客人只看见服务员微微侧身,新厨房的门就已经敞开,老厨房的灯还亮着以备不时之需。这种“无感”正是所有部署策略追求的终极体验。
- 不可用总时间 $T_{\text{unavail}}$代表整个发布过程中服务无法响应用户请求的累计时间,是衡量蓝绿部署收益的核心指标。
- 求和符号 $\sum_{i=1}^{n}$把一次发布中所有流量切换动作的耗时逐项累加起来,强调发布可能包含多次小规模切换。
- 单次切换耗时 $T_{\text{switch}_i}$第 $i$ 次切换从开始到完成的耗时,在蓝绿部署中通常是秒级甚至毫秒级。
- 趋近于零 $\approx 0$因为切换不涉及服务重启或版本重新构建,不可用时间趋近于零,这是蓝绿部署最核心的价值。
架构设计
双厨房能高效运转,靠的是清晰的动线:传菜口、备料台、出菜窗各有分工。蓝绿部署的架构同样需要几个各司其职的组件互相配合。首先是负载均衡器——它就像餐厅门口的服务员,所有客人的去留都由它引导,蓝环境还是绿环境,全凭它一句话。其次是服务注册中心,相当于员工花名册:新厨房的大厨一上岗,花名册上立刻有他的名字,客人点菜时系统才知道该找谁。最后是配置管理,它像统一印刷的菜谱:两间厨房的菜谱必须一模一样,否则同一个菜名端上来的却是两种味道。
架构设计的灵魂在于“差异最小化”。蓝绿两套环境在基础设施、依赖库、中间件、配置参数上应当完全一致,唯一允许的差异是应用的二进制版本。否则就会出现经典翻车:绿环境在测试时一切正常,上线后却因为某个配置项不一致而表现异常。这种“配置漂移”是蓝绿部署的头号刺客。
因此,架构层面要做三件事:用基础设施即代码(IaC)把两套环境声明成同一条模板,确保每次创建都长出一样的骨架;把配置外置到配置中心,蓝绿环境共用同一份配置基线;通过服务注册中心管理实例列表,切换时不遗漏任何新实例,也不残留任何旧实例。
回到餐厅的比喻:老板对两家厨房的要求是“复制粘贴”——连抹布挂的位置都要一样。只有这样,新厨房试菜的成功才能原封不动地复现给所有客人。
- 配置差异 $\Delta_{\text{config}}$表示蓝绿两个环境之间所有配置项的差异总和,这个值越小,切换后的行为就越可预期。
- 差的绝对值 $| C_{\text{blue}} - C_{\text{green}} |$蓝环境配置与绿环境配置逐项求差的绝对值,避免正负抵消掩盖真实偏差。
- 趋近于零 $\to 0$目标是让差异趋近于零,使绿环境在验证阶段测得的结果,上线后依然成立。
流量切换
把客人生拉硬拽到新厨房是危险的。聪明的服务员会先请几位老熟客去试菜,确认好评后,再分批引导大部队。蓝绿部署的流量切换也讲究循序渐进。常见的切换手法有四种:第一种是 DNS 切换,把域名解析指向新环境,实现最简单但受 DNS 缓存影响,生效需要几分钟;第二种是 API 网关路由切换,网关根据路由规则直接把请求打到绿环境,秒级生效且控制力强;第三种是负载均衡权重调整,把绿环境的权重从 0 调到 10%、50%、100%,每一步都观察业务指标,这是最稳妥也最常用的方式;第四种是切换之后的验证,就像试菜后的询问——检查业务成功率、响应延迟、错误率是否正常,确认“客人真的满意”。
权重调整之所以最受欢迎,是因为它天然支持灰度。切换不是一锤子买卖,而是可以随时暂停、回退的平滑过程。当流量只切了 30% 时,即使新版本有隐藏 bug,影响面也被限制在三成用户以内,且可以随时把权重归零。
回到餐厅:服务员不会一次性把所有客人推进新厨房。他先让几位熟客试菜,再逐步增加引导比例,直到所有人都坐进新厨房——而老厨房的灯始终亮着,随时准备迎接回头的客人。
- 绿环境请求量 $\lambda_{\text{green}}$单位时间内被引导到绿环境的请求数,是衡量切换进度的直接指标。
- 绿环境权重 $w_{\text{green}}$取值范围 0 到 1,表示有多少比例的流量应分配至绿环境,0.3 即三成流量。
- 总请求量 $\lambda_{\text{total}}$系统整体接收到的请求总量,是分配的分母。
- 乘法 $\times$权重本质上是一个比例系数,通过乘法把总流量按比例拆给不同环境。
数据库迁移
两间厨房可以有两套炉灶,却不能有两个食材仓库。老厨房按“猪肉、牛肉”分类,新厨房按“红肉、白肉”分类,两边厨师同时从同一个仓库取货,必须保证记录一致。数据库是蓝绿部署中最扎手的一环,因为流量可以瞬间切换,数据却无法瞬间搬家。如果数据库 schema 发生变化,老环境用旧结构读写,新环境用新结构读写,必然有一方“看不懂”数据。
业界最成熟的应对方案是双写。应用在收到写请求时,同时写入旧库和新库,保证两边数据同步更新。但双写只是开始:还要做数据回填,把历史存量数据按新格式写入新库;再做兼容性改造,让新旧库的读写接口互相兼容;最后通过一致性校验确认两库对齐——比对记录数、计算哈希、抽样核对。只有数据层真正准备好了,流量切换才没有后顾之忧。
双写方案的一个关键洞察是:写操作的成功概率取决于两个库同时成功。如果单次写旧库成功率为 99.9%,写新库成功率也是 99.9%,那么双写整体成功率约为 99.8%,差距看似微小,但在高并发场景下会累积成可观的失败量。因此双写必须配套失败补偿机制,例如写入新库失败时先将消息打入重试队列。
回到餐厅的比喻:两间厨房的账本必须同时记下每一笔食材进出。老板每天晚上核对两本账,发现任何一笔对不上,第二天一早就会暂停新厨房的采购——数据对齐,才敢让新厨房独挑大梁。
- 整体成功率 $P_{\text{success}}$双写操作两端都成功的概率,是判断数据同步可靠性的核心指标。
- 蓝库写入概率 $P_{\text{blue\_write}}$旧数据库单次写入成功的概率,受网络、锁竞争、磁盘性能影响。
- 乘号 $\times$两个独立事件同时发生的概率使用乘法计算,体现“缺一不可”的逻辑。
- 绿库写入概率 $P_{\text{green\_write}}$新数据库单次写入成功的概率,同样受各类基础设施因素影响。
回滚流程
客人连说三道菜都咸,老板一个眼神,服务员立刻把客人领回老厨房。老厨房的灶台从没熄过火,因为蓝环境始终处于“待命”状态。这正是蓝绿部署最迷人的优点:回滚根本不需要重新部署旧版本,只需要把流量反向切回蓝环境。一次回滚,本质上就是一次切换,秒级完成。
一个完整的回滚流程应当包含五个步骤。第一步是发现异常信号,监控告警如错误率飙升、延迟突增触发熔断;第二步是暂停新流量,把绿环境的权重立即降为零;第三步是将流量切回蓝环境,恢复服务;第四步是确认服务恢复,检查核心指标回到基线水平;第五步是保留绿环境现场,用于事后复盘。若执行了数据库双写,还需要数据补偿脚本,把绿环境在存活期间产生的增量数据同步回蓝库,避免数据丢失。
回滚能够如此轻快,前提是“蓝环境从未被破坏”。这正是蓝绿部署与滚动更新的本质区别:滚动更新中旧版本已经被替换,回滚等于重新走一遍发布流程;蓝绿部署中旧版本始终在线,回滚只是一句“请客人回老厨房”。
回到餐厅:老厨房的灯一直亮着,是蓝绿部署最深的底气。客人随时可以回去,厨师随时可以重新掌勺——这种“随时可退”的安全感,让发布从惊险一跃变成从容转身。
- 回滚耗时 $T_{\text{rollback}}$从决定回滚到服务完全恢复的总时间,蓝绿部署的目标是把这项指标压到秒级。
- 等号 $=$强调回滚与切换在操作本质上是同一件事,不需要额外的部署或构建动作。
- 切换耗时 $T_{\text{switch}}$一次流量切换所需的时间,在负载均衡权重调整或网关路由变更下通常为秒级。
资源管理
两间厨房同时开火,燃气费和食材损耗让人心疼。老板的办法很朴素:新厨房只开两个灶,够试菜就行;老厨房的冷库继续共用,避免重复进货。蓝绿部署最大的代价是资源翻倍,聪明的团队会想尽办法控制这笔开销。
资源管理的第一原则是“绿环境先小后大”。部署阶段把绿环境缩容到最低副本数,验证流量和功能完全够用;切换成功后,再通过水平自动伸缩(HPA)逐步扩容到与蓝环境同等的规模。第二原则是“尽量共享无状态组件”:Redis、Kafka、对象存储这类中间件不必各建一套,蓝绿环境共用,既降低成本,又天然避免数据分叉。第三原则是“观察期结束后回收”:蓝环境需要保留一段时间(通常是 24 到 72 小时)作为回滚后盾,超过观察窗口后即可释放,把省下的资源还给集群。
这套“抠门”哲学并不影响安全性。绿环境在低配状态下同样能完成所有验证动作,因为验证关注的是逻辑正确性而非吞吐能力。等到切换完成后,再按真实流量压力动态扩容,既省了钱,又不牺牲质量。
回到餐厅:新厨房只在换菜单时“限时营业”,平时锁门省燃气;两间厨房共用一个冷库,食材不重复采购。精打细算的老板发现,双厨房的代价远没有想象中那么高。
- 总成本 $C_{\text{total}}$一次蓝绿发布周期内消耗的全部计算、存储与带宽成本。
- 蓝绿成本相加 $C_{\text{blue}} + C_{\text{green}}$两套环境同时在线,各自的资源成本需要叠加计算。
- 减去共享部分 $- C_{\text{shared}}$蓝绿共用中间件与存储时省下的成本,体现在总账上为负项。
平台集成
餐厅规模大了,老板请来一位“总调度”——中央管理系统统一管理两间厨房,服务员不再扯着嗓子喊,而是通过耳麦接收调度指令。在云原生时代,Kubernetes 就是这个总调度,服务网格则是那条耳麦线路。Kubernetes 对蓝绿部署的支持浑然天成:用两套 Deployment 分别对应蓝绿版本,通过切换 Service 的 selector 指向目标版本即可完成流量切换。更精细的做法是同时保留两个 Service,用外部负载均衡控制权重。
服务网格 Istio 则把切换升级为“可编程的优雅”。通过 VirtualService 和 DestinationRule 中的 weight 字段,可以在不修改任何应用代码的前提下,把流量以任意比例分配给蓝绿两个版本。配合 CI/CD 流水线,从代码提交到绿环境部署、冒烟验证、权重调整、全量切换、观察回滚,全流程可以编排成一条自动化管道。监控告警系统则充当“巡场经理”,一旦指标异常,立刻触发自动或人工回滚。
平台集成的终极形态是“发布即配置”:工程师只需要在管理面调整一个权重数字,流量便如潮水般改道,整个过程不触碰任何业务代码。
回到餐厅:总调度在控制面板上轻轻拨动一个滑块,客人的流向就在蓝绿两间厨房之间平滑迁移。从“人喊人”到“系统调度”,蓝绿部署真正融入了现代化的技术底座。
- 绿权重 $w_{\text{green}}$服务网格或负载均衡器分配给绿环境流量的比例,取值范围 0 到 1。
- 互补关系 $1 - w_{\text{blue}}$蓝绿权重之和等于 1,改变一侧权重,另一侧自动反方向变化。
AI 应用场景
AI模型服务零停机上线
阶段:模型部署与发布
解决的问题:传统更新线上推荐模型时需要短暂停服,造成推荐接口空窗。蓝绿部署让新模型在绿环境完成回放测试后,流量平滑切换,用户无感知。
具体案例:某电商平台的召回模型从 v3 升级到 v4。团队在绿环境部署新模型,用历史请求做离线回放,确认 AUC 提升后,通过服务网格把流量权重从 0 逐步调到 100%。上线后第二小时发现 p99 延迟略有上升,运维一键将权重归零,流量切回蓝环境,全程零数据丢失。
大模型版本快速回滚
阶段:模型版本迭代与监控
解决的问题:大模型对话服务升级新版本后,可能出现回答质量下降或有害内容抬头。蓝绿部署保障了“新版本效果不达标也能秒级回到旧版本”。
具体案例:某智能客服系统接入新的开源大模型 v2。灰度 20% 流量时,监控发现“人工介入率”从 8% 涨到 15%,平台自动触发回滚,流量全部切回 v1 环境,随后保留 v2 环境采集对话样本用于分析。
训练平台基础设施升级
阶段:基础环境迁移与验证
解决的问题:GPU 训练集群需要升级 CUDA 与分布式框架版本,直接原地升级可能导致正在运行的训练任务中断。蓝绿部署为训练平台提供了无感升级路径。
具体案例:某自动驾驶公司升级训练集群的 GPU 驱动。团队在绿环境搭建新驱动版本的集群,跑通一组基准训练任务后,将新建的训练任务全部调度到绿环境,蓝环境继续运行存量任务直至自然结束。升级全程没有中断任何训练作业。
Python 演示
import random class Environment: """蓝绿部署中的一套运行环境""" def __init__(self, name, version): self.name = name self.version = version self.replicas = 3 def status(self): return "{}: version={} replicas={}".format( self.name, self.version, self.replicas) class BlueGreenManager: """模拟蓝绿部署的完整生命周期""" def __init__(self): self.env_blue = Environment("blue", "v1.0") self.env_green = Environment("green", "v1.0") self.blue_weight = 100 self.green_weight = 0 self.rollback_count = 0 def deploy_green(self, version): self.env_green.version = version self.env_green.replicas = 1 print("绿环境部署新版本 {}".format(version)) def switch(self, green_percent): green_percent = max(0, min(100, green_percent)) self.green_weight = green_percent self.blue_weight = 100 - green_percent print("流量切换: blue={}% green={}%".format( self.blue_weight, self.green_weight)) def verify_green(self): # 模拟健康检查与冒烟测试, 15% 概率失败 return random.random() > 0.15 def full_switch(self): self.switch(100) if not self.verify_green(): self.rollback() return False self.env_green.replicas = 3 print("全量切换成功, 绿环境扩容至 3 副本") return True def rollback(self): self.switch(0) self.rollback_count += 1 print("回滚完成, 回滚次数: {}".format(self.rollback_count)) def main(): manager = BlueGreenManager() print(manager.env_blue.status()) manager.deploy_green("v2.0") print(manager.env_green.status()) manager.switch(30) manager.switch(80) manager.full_switch() print("最终回滚次数:", manager.rollback_count) if __name__ == "__main__": main()
self.env_green.replicas = 1绿环境先以最小副本部署,呼应“先小后大”的资源管理原则。self.blue_weight = 100 - green_percent蓝绿权重互补,权重总和始终为 100。manager.switch(30)渐进式切换的第一步,先让三成流量进入绿环境观察。random.random() > 0.15用随机数模拟健康检查结果,体现验证环节可能失败。self.rollback_count += 1统计回滚次数,用于度量发布策略的稳定性。manager.switch(0)回滚的实现就是反向切换,把流量全部切回蓝环境。
常见误区
误区很多初学者认为蓝绿部署只是应用层的流量切换,数据库不用管,两个环境各自连自己的库就行。结果切换后才发现数据对不上,只能灰溜溜地切回去。
正解数据库恰恰是蓝绿部署中最难的部分。新版本通常伴随 schema 变更,必须通过双写、数据回填、一致性校验来保证两库同步。就好比两间厨房可以有不同的炉灶,但不能有两个对不上账的食材仓库。流量切换是台前的表演,数据库迁移才是幕后的硬功夫。
为何常见:教程和演示往往先用无状态服务展示蓝绿切换,给人“只需要管应用”的错觉,忽略了生产系统中大量有状态服务的真实约束。
误区有人以为蓝绿回滚时要重新构建并部署蓝环境的新副本,像传统发布那样走一遍构建、上传、重启的流程,于是把回滚时间按“一次完整部署”来估算。
正解蓝绿部署的最大优势就是蓝环境始终在线,回滚只是把流量反向切换,秒级完成。正如客人不满意新菜时,服务员把客人带回老厨房即可,不需要重新开火做菜。至于数据库增量数据,用补偿脚本同步即可,不必回滚整个数据库。
为何常见:习惯了滚动更新和重新发布的人,很难立刻理解“环境从未销毁”带来的回滚快感,总把回滚与重建绑定在一起。
误区绿环境全量切换后,有些人觉得大功告成,马上释放蓝环境以节省成本。结果几小时后出现隐藏 bug,想回滚却发现已经没有“老厨房”可回。
正解切换成功不代表验证结束。业界通行做法是保留蓝环境 24 到 72 小时的观察窗口,确认没有延迟出现的问题后再释放。蓝环境是回滚的底牌,底牌不能提前亮完。即使资源紧张,也应至少保留最低副本维持可用状态。
为何常见:成本压力让人急于回收资源,但蓝绿部署的容错能力恰恰依赖“旧环境多活一会儿”。
误区有人理解“两套一致的环境”就是两台一模一样的机器、相同数量的副本,导致资源成本直接翻倍,让团队对蓝绿部署望而却步。
正解“一致”指的是配置、依赖、代码基线一致,而非副本数一致。绿环境在验证阶段完全可以低配运行,切换成功后再扩容到与蓝环境等规模。新厨房先开两个灶试菜,等客人多了再全开,并不违背“两间厨房做一样的菜”的原则。
为何常见:把“环境一致性”错误地等同于“资源等量”,忽略了部署策略中常见的降配验证与动态扩缩容实践。
面试题
Q1. 蓝绿部署的核心目标是什么?
- A.降低单个服务器的运行功耗
- B.实现应用零停机发布与快速回滚← 正确答案
- C.提升单次请求的平均响应速度
- D.减少代码仓库中的分支数量
答案:B。蓝绿部署通过维护两套环境、瞬时切换流量来实现零停机发布,同时旧环境在线保证了秒级回滚。A 是节能话题,C 是性能优化,D 是代码管理,都与蓝绿部署的核心目标无关。
Q2. 蓝绿部署中“蓝环境”通常指什么?
- A.新版本运行的备选环境
- B.当前对外服务的正式环境← 正确答案
- C.用于日常开发调试的环境
- D.保存冷数据的备份环境
答案:B。蓝环境是当前正在承接生产流量的旧版本环境,绿环境才是部署新版本的候选环境。开发环境和冷备份环境都不属于蓝绿部署中的角色定义。
Q3. 蓝绿部署中推荐的回滚方式是什么?
- A.重新部署蓝环境中的旧版本
- B.把流量从绿环境切回蓝环境← 正确答案
- C.删除绿环境中的全部资源
- D.回滚数据库到旧的备份档
答案:B。蓝环境始终在线,回滚只需将流量反向切换即可秒级完成。A 需要重新构建部署,耗时且违背蓝绿设计;C 破坏现场不利于复盘;D 是数据库操作而非应用回滚的正道。
Q4. 数据库蓝绿迁移中“双写”的含义是什么?
- A.新旧两个数据库集群同时写入← 正确答案
- B.应用代码拼接两条写入语句
- C.数据库同时发布两个新版本
- D.把一个大数据库拆为两个库
答案:A。双写是指应用在写请求到达时,同时向旧库与新库写入数据,保证两边数据同步。B 只是实现细节之一,C 和 D 与双写概念无关。
Q5. 蓝绿部署中流量切换的方式包括哪些?
- A.通过域名解析记录进行切换← 正确答案
- B.通过网关路由规则进行切换← 正确答案
- C.通过负载均衡权重进行调整← 正确答案
- D.通过修改服务器MAC地址实现
答案:ABC。DNS 切换、网关路由切换、负载均衡权重调整都是常用的流量切换手段。修改服务器 MAC 地址属于底层网络操作,无法用于蓝绿流量切换,且会造成网络中断。
Q6. 为什么蓝绿部署比滚动更新更适合快速回滚?
- A.旧版本仍在线无需重新构建部署← 正确答案
- B.蓝绿部署完全不会产生数据问题
- C.切换是一次快速的流量权重变更← 正确答案
- D.蓝绿部署过程不会产生任何报错
答案:AC。蓝绿回滚的本质是一次流量切换,旧环境一直在线,因此无需重新构建,A 正确;切换本身是快速的权重变更,C 正确。B 和 D 是绝对化表述,蓝绿部署同样可能遇到数据问题和报错。
Q7. 绿环境全量切换后,释放蓝环境前应完成哪些动作?
- A.保留观察窗口确认新环境稳定性← 正确答案
- B.确认数据补偿迁移任务已经完成← 正确答案
- C.立即删除新环境产生的全部日志
- D.保留快速回滚的应急切换方案← 正确答案
答案:ABD。释放蓝环境前应确认新环境经过观察期、数据迁移补偿完成,并保留应急回滚方案。删除日志是错误操作,日志应保留用于审计和复盘。
Q8. 服务网格中用于定义蓝绿流量路由的核心资源是什么?
- A.VirtualService流量路由对象← 正确答案
- B.Deployment控制器部署对象
- C.Namespace命名空间隔离对象
- D.ConfigMap配置挂载存储对象
答案:A。服务网格(如 Istio)通过 VirtualService 和 DestinationRule 中的权重字段控制蓝绿流量分配,A 正确。Deployment 负责实例管理,Namespace 负责隔离,ConfigMap 负责配置,均不直接定义流量路由。
Q9. 蓝绿部署中“配置漂移”会造成什么问题?
- A.造成一致性问题使切换后行为异常← 正确答案
- B.数据库读写性能反而得到明显提升
- C.环境总体成本自动下降但稳定性差
- D.流量切换速度变得越快越容易出错
答案:A。配置漂移指蓝绿环境的配置不一致,导致绿环境在验证阶段表现正常、切换后却行为异常。这印证了“差异仅限应用版本”的架构原则,与性能、成本、切换速度无关。
Q10. 双写方案中,若旧库写失败率为 p1, 新库写失败率为 p2(独立), 双写整体成功率是多少?
- A.(1-p1)(1-p2)即两边都成功概率← 正确答案
- B.(1-p1)+(1-p2)两概率叠加之和
- C.1-p1-p2整体失败概率的补数
- D.p1×p2两边失败概率的乘积
答案:A。双写需要两个库同时写入成功,单次成功概率分别为 (1-p1) 和 (1-p2),根据独立事件乘法法则,整体成功率为两者乘积,即 (1-p1)(1-p2)。B 是错误相加,C 忽略了 p1 与 p2 同时失败被重复扣减,D 计算的是两库同时失败的概率。