DevOps 实践:数据迁移、持续部署与系统架构优化
1. 数据迁移
数据库变更通常无法回滚,否则可能会有数据丢失的风险,因此数据迁移需要特别小心。数据迁移类似于增量发布,分为三个步骤:
1.
部署兼容新旧模式的代码
:同时部署数据迁移代码。
2.
运行数据迁移代码
:在部署成功后,可以手动启动或作为部署脚本的一部分自动启动。
3.
移除旧模式代码并重新部署
:迁移完成后,手动移除理解旧模式的代码,然后再次部署。
这种将数据迁移与部署分离的方法,能让每次部署失败后都可回滚,且不会丢失数据。迁移仅在新代码在生产环境中被证明稳定后进行。虽然比在部署期间迁移数据稍复杂,但更安全,还能实现零停机部署。
对于涉及大量数据的迁移,由于迁移期间生产系统需要保持可用,因此需要特别注意。编写迁移代码时应采用增量方式,可能还需要使用速率限制器来优化性能,并同时使用新旧两种模式。例如,从一个表向另一个表移动数据时,读取和更新数据时可以同时查看两个表,但只向新表插入数据。
迁移完成后,要及时清理过时的代码。如果迁移需要较长时间,可在团队任务计划中添加提醒;对于非常长时间的迁移,可在团队日历中添加提醒或在可视化计划中安排“完成数据迁移”的任务。
这种三步迁移过程适用于任何外部状态的更改,除数据库外,还包括配置设置、基础设施变更和第三方服务变更。涉及外部状态时要格外小心,因为错误很难撤销,通常小而频繁的更改比大而不频繁的更改更好。
2. 持续部署
要实现持续部署,团队需要采用严格的持续集成方法。每天需要进行多次集成,并每次都创建一个已知良好、可部署的构建。“可部署”意味着未完成的功能对用户不可见,代码无需手动测试。此外,部署过程需要完全自动化,并且要有自动检测部署失败的方法。
持续部署只有在部署对用户不可见时才有意义,通常适用于后端系统和基于 Web 的前端。桌面和移动前端、嵌入式系统等通常不太适合持续部署。
当团队进行持续部署时,会有以下表现:
- 部署到生产环境变得轻松无压力。
- 部署问题出现时,容易解决。
- 部署不太可能导致生产问题,即使出现问题也通常能快速修复。
持续部署的典型替代方案是面向发布的部署,即只有在有可发布的内容时才进行部署。实际上,一旦满足前提条件,持续部署比面向发布的部署更安全、更可靠。
团队不必直接从面向发布的部署切换到持续部署,可以逐步进行。先编写一个完全自动化的部署脚本,然后在持续集成过程中自动部署到暂存环境,最后过渡到持续部署。
持续部署的核心思想是最小化正在进行的工作并加速反馈循环。任何能加速反馈循环和减少部署时间的方法都是正确的方向。此外,也可以寻找加速发布想法反馈循环的方法。
3. 进化式系统架构
我们构建基础设施时应满足当前需求,同时不牺牲未来发展。简单性是敏捷开发的核心,在团队进行进化式设计时尤为明显:从最简单的设计开始,通过增量设计添加更多功能,并通过反思设计不断改进代码。
系统架构指构成已部署系统的组件,包括团队构建的应用程序和服务、它们的交互方式、网络网关和负载均衡器,甚至第三方服务。我们可以从简单架构开始,逐步进化。不过,系统架构的进化速度较慢,相关行业经验不如进化式设计丰富,需要根据实际情况判断如何和何时应用。
需要注意的是,系统架构和应用程序架构是有区别的。应用程序架构是代码的设计,包括如何调用系统中其他组件的决策;而系统架构涉及创建和使用哪些组件以及它们之间的高层关系。
4. “你真的需要它吗”
软件行业有很多大公司解决重大问题的成功案例,如 Google 的全球数据库复制、Netflix 迁移到云端、Amazon 推动服务化等。但这些公司解决的问题可能并非我们所面临的问题,在达到它们的规模之前,不要盲目模仿。
以 Stack Overflow 为例,这个热门的编程问答网站每月提供 13 亿页面服务,每个页面的渲染时间不到 19 毫秒。它的系统架构如下表所示:
| 组件 | 数量 | 峰值性能 | CPU 利用率 |
| — | — | — | — |
| HAProxy 负载均衡器 | 2(1 个活动,1 个故障转移) | 4,500 请求/秒 | 18% |
| IIS 网络服务器 | 9 | 450 请求/秒 | 12% |
| Redis 缓存 | 2(1 个主,1 个副本) | 60,000 操作/秒 | 2% |
| SQL Server 数据库服务器(Stack Overflow) | 2(1 个活动,1 个备用) | 11,000 查询/秒 | 15% |
| SQL Server 数据库服务器(其他 Stack Exchange 站点) | 2(1 个活动,1 个备用) | 12,800 查询/秒 | 14% |
| 标签引擎和 ElasticSearch 服务器 | 3 | 自定义标签引擎:3,644 请求/分钟;ElasticSearch:3400 万次搜索/天 | 自定义标签引擎:3%;ElasticSearch:7% |
| SQL Server 数据库服务器(HTTP 请求日志) | 1 | - | - |
| LogStash 服务器 | 6 | - | - |
截至 2016 年,Stack Overflow 每天部署网站 5 - 10 次,完整部署约需 8 分钟。除本地化和数据库迁移外,部署过程就是遍历服务器,将其从 HAProxy 轮询中移除,复制文件,然后再放回轮询。其主要应用是一个单租户单体应用,为所有问答网站提供服务。
这是一种不太时髦的系统架构,没有容器、微服务、自动扩展,甚至没有云,只是一些强大的机架式服务器、少量应用程序和文件复制部署方式,但简单直接、稳定可靠。人们采用复杂架构的常见原因之一是“扩展”,但 Stack Overflow 是世界上流量最高的 50 个网站之一,我们的架构是否真的需要比它更复杂呢?
5. 追求简单架构
不要盲目复制任何架构,而应着眼于需要解决的问题,寻找能解决问题的最简单架构。可以通过以下思想实验来思考:
1.
从理想世界开始
:假设组件代码编写完美但非即时完成,网络完全可靠但仍有延迟,每个节点都有无限资源。此时,考虑组件边界应如何划分。可能因安全、监管和延迟等原因将组件隔离到不同服务器或地理位置,区分客户端和服务器端处理,并使用第三方组件节省时间和精力。
2.
引入不完美的组件和网络
:去掉组件和网络完美的假设,考虑组件可能失败、网络可能中断的情况。此时需要冗余机制,以及处理复制和故障转移的组件。思考如何以最简单的方式满足这些需求,是否可以使用第三方工具或服务来降低复杂性。例如,使用云服务提供商可以避免担心冗余电源和发电机的问题。
3.
限制资源
:去掉无限资源的假设,可能需要多个节点来处理负载,以及负载均衡组件。可能需要将 CPU 密集型操作分离成单独的组件,并引入队列来处理。还可能需要共享缓存和填充缓存的方法。但要注意,是在推测未来负载,还是基于实际使用和趋势解决实际问题。是否可以通过使用更强大的硬件或等待解决未来负载来简化架构。
4.
考虑人员和团队
:去掉理想的编码假设,思考谁来编写每个组件的代码,他们如何相互协调。是否需要拆分组件以方便跨团队沟通或限制单个组件的复杂性,以及如何简化这些约束。
6. 控制架构复杂性
有些架构复杂性是必要的,如负载均衡和组件故障处理,这是无法消除的本质复杂性。但有些复杂性是偶然的,例如为了便于人员管理而将大组件拆分成多个小组件,这并非解决问题的必要部分,可以通过以下方法减少:
-
进化式设计
:很多人拆分组件是为了避免“大泥球”问题,但实际上将大组件拆分成多个小组件往往会增加整体复杂性。虽然单个组件更容易理解,但组件间的交互会变差,错误跟踪和重构更困难,分布式事务也应尽量避免。使用进化式设计可以创建大组件而不变成“大泥球”。
-
自律
:团队拆分组件的另一个原因是提供隔离。当一个组件负责多种类型的数据时,容易将数据纠缠在一起,导致后续难以重构。但数据并非必须纠缠在一起,通过设计可以在单个组件内创建隔离的模块,甚至每个模块可以使用单独的数据库。如果不通过网络调用强制隔离,团队需要具备自律能力。集体代码所有权、结对编程或团队编程以及积极的工作氛围都有帮助,反思设计可以纠正可能出现的错误。
-
快速部署
:大组件通常难以部署,主要问题往往不在于部署本身,而在于部署前的构建和测试。如果组件需要手动测试,问题会更严重。可以通过创建零摩擦的构建、引入测试驱动开发和持续集成以及创建快速可靠的测试来解决这个问题。如果构建和测试速度快,就不必为了方便部署而拆分组件。
-
垂直扩展
:根据康威定律,组织倾向于按照组织结构来设计系统。许多组织默认采用水平扩展,导致有很多小而孤立的团队,需要相应的小组件。垂直扩展可以让团队在相同组件上共同工作,使架构设计更符合要解决的问题,而不是为了匹配团队结构。
7. 系统架构重构
可以对系统架构进行多种重构,以下是一些常见的重构方式:
1.
多仓库组件 → 单仓库组件
:如果团队的组件分布在多个仓库中,可以将它们合并到一个仓库,并提取出通用类型和实用工具的共享代码。
2.
组件 → 微巨石
:如果团队拥有多个组件,可以将它们合并为一个组件,同时保持基本架构不变。将它们隔离在不同的目录树中,并使用顶级接口文件来转换序列化负载和组件数据结构。用函数调用代替组件间的网络调用,但在其他方面保持架构不变,包括使用原始数据类型而非对象或自定义类型。这种进程内组件称为微巨石,它提供了组件的隔离性,但没有操作复杂性。不过,微巨石重构的验证还不充分,仅在一些小问题上进行过尝试。
3.
微巨石 → 模块
:如果不需要强隔离性,可以移除顶级接口文件和序列化/反序列化,直接正常调用微巨石的代码,结果就是一个模块。由模块组成的组件通常称为模块化单体,但模块适用于任何大小的组件。
4.
模块 → 新模块
:如果模块之间有很多交叉依赖,可以通过重构模块的职责来简化。这实际上是应用程序架构的问题,但它可以是更大系统重构的中间步骤。
5.
大泥球 → 模块
:如果大组件变得混乱不堪,可以使用进化式设计逐步将其转换为模块,在过程中解开和隔离数据。
6.
模块 → 微巨石
:如果需要强隔离性,或者考虑将大组件拆分成多个小组件,可以将模块转换为微巨石。引入顶级接口文件并序列化复杂函数参数,将微巨石视为单独的组件,调用者应通过顶级接口文件调用,并将调用抽象在基础设施包装器后面。
7.
微巨石 → 组件
:如果微巨石适合作为网络组件使用,将其转换为组件相对简单,只需将顶级 API 文件转换为服务器,并让调用者使用网络调用。如果在调用时使用了基础设施包装器,这个过程会更简单。
总之,在 DevOps 实践中,数据迁移、持续部署和系统架构优化都有各自的要点和方法。通过合理的数据迁移策略、有效的持续部署流程和优化的系统架构设计,可以提高软件的开发和部署效率,降低风险,更好地满足业务需求。
DevOps 实践:数据迁移、持续部署与系统架构优化(下半部分)
8. 系统架构重构的案例分析
为了更好地理解系统架构重构的实际应用,我们来看一个具体案例。有一个团队在一家知名大公司工作,由于自上而下的架构要求,3 名程序员需要维护 21 个独立的服务,每个服务对应一个实体。这种架构带来了诸多问题,于是团队进行了一系列重构:
-
合并仓库
:原本每个服务存放在单独的 git 仓库中,团队获得许可将这些服务合并到一个单一的单仓库(monorepo)中。这样做消除了重复的序列化/反序列化代码,极大地简化了重构过程。以前一个更改可能需要在 16 个仓库中进行 16 次提交,现在只需要一次。
-
组件合并
:考虑到团队服务的 CPU 需求较低,且有组织范围内的服务定位器,团队将这些服务合并为一个组件,同时保持端点不变。这使得他们可以减少虚拟机(VM)的部署数量,降低云成本;用函数调用代替网络调用,加快响应时间;简化端到端测试,使部署更加容易和快速。
-
内部服务库化
:团队大约一半的服务仅在内部使用,每个服务都有一定的样板代码和开销。将这些内部服务转换为库可以消除这些开销,同时也减少了一些缓慢的端到端测试。
通过这些重构,团队如果获得许可,就可以显著降低成本和开发摩擦,提高系统的整体效率。
9. 系统架构重构的流程总结
为了更清晰地展示系统架构重构的过程,我们可以用以下 mermaid 流程图表示:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([开始]):::startend --> B{评估当前架构}:::decision
B -->|多仓库组件| C(合并为单仓库组件):::process
B -->|多个组件| D(合并为微巨石):::process
B -->|微巨石| E{是否需要强隔离?}:::decision
E -->|是| F(转换为组件):::process
E -->|否| G(转换为模块):::process
B -->|模块| H{是否有交叉依赖?}:::decision
H -->|是| I(重构模块职责):::process
B -->|大泥球组件| J(转换为模块):::process
C --> K(持续优化):::process
D --> K
F --> K
G --> K
I --> K
J --> K
K --> L([结束]):::startend
这个流程图展示了从评估当前架构到最终持续优化的整个过程,根据不同的架构情况选择不同的重构路径。
10. 系统架构重构的注意事项
在进行系统架构重构时,还需要注意以下几点:
-
风险评估
:重构过程中可能会引入新的问题,如兼容性问题、性能下降等。在开始重构之前,要对可能的风险进行充分评估,并制定相应的应对措施。
-
逐步推进
:不要一次性进行大规模的重构,而是采用逐步推进的方式。可以先在小范围进行试点,验证重构的可行性和效果,然后再逐步扩大范围。
-
沟通协作
:系统架构重构涉及多个团队和人员,需要进行充分的沟通和协作。确保所有相关人员都理解重构的目标、过程和影响,避免出现误解和冲突。
11. 持续部署与系统架构的协同
持续部署和系统架构是相互影响、相互促进的关系。一个简单、灵活的系统架构更有利于实现持续部署,而持续部署的实践也可以推动系统架构的优化。
-
架构支持持续部署
:系统架构应该设计成易于部署和更新的形式。例如,采用模块化设计,使得每个模块可以独立部署和测试;使用容器化技术,提高部署的一致性和可重复性。
-
持续部署反馈架构优化
:持续部署过程中收集的反馈信息,如部署失败率、性能指标等,可以帮助我们发现系统架构中存在的问题,从而进行针对性的优化。
以下是持续部署与系统架构协同的关系表格:
| 方面 | 系统架构对持续部署的影响 | 持续部署对系统架构的影响 |
| — | — | — |
| 部署效率 | 简单架构部署更快,减少部署时间 | 反馈架构瓶颈,促使优化架构提高部署效率 |
| 可靠性 | 稳定架构降低部署失败率 | 发现架构薄弱点,加强架构可靠性 |
| 可维护性 | 模块化架构便于维护和更新 | 推动架构模块化,提高可维护性 |
12. 总结与展望
在 DevOps 的实践中,数据迁移、持续部署和系统架构优化是三个关键的方面。数据迁移需要谨慎处理,采用分步骤的方法确保数据安全和系统稳定;持续部署可以提高开发和部署效率,但需要满足一定的前提条件;系统架构应该追求简单,控制复杂性,并通过重构不断优化。
未来,随着技术的不断发展,DevOps 的实践也将不断演进。例如,人工智能和机器学习技术可能会应用到持续部署和系统架构优化中,实现自动化的决策和优化。同时,随着云计算和容器技术的普及,系统架构将更加灵活和可扩展。我们需要不断学习和探索,以适应这些变化,提高软件开发和运维的水平。
总之,通过合理运用这些方法和策略,我们可以构建更加高效、稳定和可靠的软件系统,满足不断变化的业务需求。
DevOps实践:数据迁移与架构优化
超级会员免费看
171万+

被折叠的 条评论
为什么被折叠?



