遗留系统演进

1、概述 本文主要分三部分,第一部分简要阐述“演进式架构”和“适应度函数”的概念,其中部分内容节选自《演进式架构》一书;第二部分通过以 etcd 和 kubernetes 为例说明演进式架构思想如何影响开源项目的演进;第三部分通过对第二部分的思考总结,进而推演出在公司软件产品的开发过程中,我们该如何借助“演进式架构”的思想更好地迭代现有软件产品。
2、概念 演进式架构

软件行业曾经有这样一个共识,架构一旦确定,“日后很难改变”。演进式架构将支持增量式变更作为第一原则。由于历来变更都是很难预测的,改造的成本也极其昂贵,所以演进式架构听上去很吸引人。如果真的可以在架构层次做到演进式地变更,那么变更就会更容易、成本更低,也能发生在开发实践、发布实践和整体敏捷度等多个地方。
遗留系统演进
文章图片

大泥球架构 — 来自一个不愿透漏名字的项目
适应度函数引导演进式架构
完美的系统? 自有软件系统以来,诞生了无数的优秀的系统改善了我们的生活,有些系统甚至已经被持续使用过了数十年。
然而,有没有系统自打诞生之初就是完美的呢,答案肯定是没有的。例如下图展示了 Linux 自 1991 年以来所进行的迭代版本的 timeline,甚至已经有上百个版本。
遗留系统演进
文章图片

软件系统的进化永远是一个权衡的结果。
经典物理学 vs 控制论 以往在构建软件系统时人们总是尝试在项目计划初期,尝试制定一个接近“完美”的计划,然后在很长一段时间内遵循这个计划,埋头苦干,直到最初的计划完成。
这个过程就像是在发射一颗迫击炮弹或是其他无主动动力系统的炮弹:在发射炮弹之前,通过计算发射起点和终点的相对距离、海拔,如果精确一点再加上风速,根据牛顿运动学定律算出一个初始角度,点燃炮弹。炮弹升空后,一切就听天由命了。如果中途风速变了,或是目标物临时移动了一下,炮弹都会打偏。对应这套基于经典物理学的导弹系统来说,距离越远,偏差一定也越大。
遗留系统演进
文章图片

现代化战争中使用的精确制导导弹则使用的是完全不同的策略。导弹自身携带动力系统和技术系统,实时计算反馈当前速度、位置与目标的距离,然后动态调整角度和速度,最终精确打击目标。这套基于控制论的方式将导弹的精确度
遗留系统演进
文章图片

由此尝试在软件领域引入控制论中这套实时计算反馈的方法,即适应度函数(系统函数)的概念,通过不断对系统关注指标进行量化测试来精确的控制
遗留系统演进
文章图片

影响软件项目的衡量指标可能有很多,如代码质量、性能、稳定性、复杂度、开发效率、安全性、可扩展性、可审计性等等。这些每一个指标都可以有对应的适应度函数。
总体大于部分之和,片面的去过于关注某一个维度的适应度函数并不能带来很好的收益。项目经理或架构师需要结合各个维度的适应度函数制定一个全系统适应度函数,来为后续架构决策作为指导。
适应度函数不拘泥于特定形式,它可能是自动的,如单测覆盖率、系统性能测试,也可能是需要手动评估的,如系统复杂度等,但它一定是需要可量化的。下图给出一个全局适应度函数的示例。每个指标满分为 5 分,最低分为 0 分。
遗留系统演进
文章图片

从图中可以大致评估出该系统在数据安全性、高性能等方面比较优异,但在易用性、可审计性等方面较弱。系统演进方向一定是补足评分较弱的方向,但依据系统定位不同,也不是所有评分较低的项目都需要补齐。假设该图是为某银行开发的内部管理系统,那么相比提升系统响应时间和易用性,可审计性的要求优先级一定更高一些,因此下个阶段的开发目标可能是先提升系统可审计性。由此可总结出适应度函数的两个主要作用:
  • 评估系统现状
  • 制定下个开发周期的任务优先级和总体目标。
不同类型的项目、产品关注的指标可能不尽相同,以下简要列出开源项目和商业软件产品所关注的一些指标。
开源项目的适应度函数相关指标
  • 功能完整性
  • 稳定性
  • 可扩展性
  • 安全性
  • 高性能
  • 伸缩性
  • 受欢迎度
  • 易用性
商业软件产品的适应度函数相关指标
  • 功能完整性
  • 稳定性
  • 可扩展性
  • 可观测性
  • 高性能
  • 安全性
  • 易用性
  • 研发 ROI
  • 创新性
  • 产品销量
    3、开源项目的演进
每个适应度函数都应该是可量化的,但受篇幅限制,不在此展开讲每个指标的适应度函数的具体计算方法,只讲系统演进变化和全局适应度函数的关系。
ETCD 演进
诞生 2013.8
ETCD —> Distributed etc,分布式配置管理系统,类比单机的 linux etc
CoreOS 团队需要一个协调服务来存储服务配置信息、提供分布式锁等能力供其分布式容器管理系统使用。
为什么造轮子 需求分析:
  • 支持 watch 方便使用方及时收到通知响应
  • 部署运维简单:因为设计之初假定分布式系统不稳定,所以该分布式系统应支持频繁增删节点
  • 高可用与一致性 (CP)
  • 使用方式简单通用,不与语言绑定
  • 仅存储元数据因此无需支持太大数据量(MB 至 GB 级别即可)
方案对比
zookeeper:
  • 功能性需求满足
  • 调用复杂
  • 部署复杂,当时无法不重启的情况下增删节点
自研:
参考已有方案,对症下药。
  • http 长连接 watch
  • raft 保证 CP 和容灾
  • REST API 简单
  • 数据结构使用内存树,满足需求,暂不考虑持久化问题
roadmap 遗留系统演进
文章图片

v1 keyword: it works
使用 golang 实现了基于 REST 的配置基本的 CRUD 功能,直观易用。
满足 CoreOS 基本的需求,在内部开始使用。
遗留系统演进
文章图片

第一个版本在易用性方面较为优秀,高性能方面对于单机应用来说基本合格,一方面为技术栈特点决定,另一方面因为功能也还比较简单。但其它各方面都还比较弱,未实现完整的 RAFT 导致伸缩性还无法实现、暂无安全校验。
v2 keyword: 填坑
因为要在大规模生产集群使用,在 v1 开发完不久后,coreOS 团队着重对目前较弱的功能完整性、安全性等影响生产环境采用 etcd 的功能进行了大幅完善,具体完善的内容可参考如下脑图。
遗留系统演进
文章图片

这其中几个核心点:
  • 高可用
  • 读一致性
  • 目录结构
因为 v2 满足了 kubernetes 对元数据存储的需求(Go 语言编写、etcd 高可用、Watch 机制、CAS、TTL 等特性),被 kubernetes 社区广泛使用,导致项目受欢迎程度大幅提升。
遗留系统演进
文章图片

v2 版本的 etcd 系统全局适应度函数如上图所示,除了性能和稳定性、扩展性外,均有了较高的评分。至此, etcd 已经孵化成了一个较成功的开源项,后续需在稳定性、性能方面投入更多精力。由于拓展性并不是较重要的系统目标,所以暂未进行相关升级迭代。
v3 keyword: 性能优化,稳定性,提示用户体验
“不被使用的系统永远不会有 bug,也不会被吐槽。”
“项目被吐槽是好事,因为说明有人在用。”
随着 Kubernetes 项目不断发展,v2 版本的瓶颈和缺陷逐渐暴露,遇到了若干性能和稳定性问题,Kubernetes 社区呼吁支持新的存储、批评 etcd 不可靠的声音开始不断出现。
这个阶段完成的核心功能如下:
  • gprc
  • 取消目录结构
  • 分页
遗留系统演进
文章图片

系统完整性、稳定性、性能进一步优化,但随着系统变得越来越复杂,系统一定会丢失一定易用性,但好在还在可接受范围内。
至此, etcd 各方面已经是一个较成熟的开源项目了。
etcd 从最的公司内部项目,到最后快速成长为拥有 3w 多 star 的成功的开源项目,每一个版本都深刻吸取了社区反馈,并抓住当时核心问题进行完善,是一个很值得借鉴的例子。
k8s 演进
诞生 https://storage.googleapis.co...
2014 from Borg borg
Birth: 2003
Arch: Cell[borg master — borglet — scheduler]
Lang: C++
核心功能:
  • Pod
  • Service
  • Label(增强),borg 中只有 task 和 job, k8s 的 label 功能能强大
    IP-per-Pod,隔离更彻底,可选不绑定宿主机 ip 和端口,降低运维复杂度
2015 v1.0 keyword:startup, cncf
自 v1.0 甚至更早版本开始, google cloud 就同步推出基于 kubernnetes 开源版本的 SaaS 服务,在生产环境验证了这套方案的可行性。
由于 Kubernetes 是 Google 内部十几年积淀后开源的项目,所以自项目 1.0 开始就有较好的功能完整性。同时,其分布式架构天然决定了它有不错的伸缩性,能支持单集群上百节点。相比于同时期的其他容器管理方案,诸如
swarm、docker-compose,kubernetes 由于其复杂性,在易用性上体验还有待提升。总体来说还是比较均衡的。
遗留系统演进
文章图片

2016 v1.2 - 1.5 keyword: enhancement、Ease of use
  • scaling
  • rollingupdate
  • automated cluster management
  • node hardware awareness
  • Helm
  • MiniKube
  • kubeadm
做了很多有助于降低系统使用复杂度、体验成本的工作,因此整体易用性得到了提升。
2017 v1.6 - v1.9 keyword: enterprise features,security
  • local storage
  • secret encryption
  • RBAC
针对大规模在企业中应用时遇到的企业级特性进行了增强。
2018 v1.10 - v.13 keyword: extensibility
  • Storage class(CSI)
  • containerd(CRI)
  • In-Cluster Service Load Balancing(IPVS)
  • TLS Bootstrapping
  • API aggregation
  • Interface 化,在可扩展性方面有了大幅提升(指达到 GA 版本,有些功能在之前版本已经有 alpha、beta 版)
2019 v1.14-v1.17 keyword: extensibility
  • CRD improvement
  • Admission Webhook improvement
  • schedule framework
  • kubeEdge
  • kubectl plugin system
持续优化可扩展性,以及整个生态的构建。
2020 v1.18-1.20 keyword: function completeness
  • ServerSide Apply
  • Topology Aware Schedule
  • hierarchical namespace
  • TLS rotation for kubelet
一些功能性补全。
遗留系统演进
文章图片

上图可以看出,2015-2020,整个 kubernetes 生态已逐步完善,成为了容器管理的事实标准。与 etcd 类似,其 roadmap 中每个版本的核心功能,都是有针对性地对上一次全局适应度评估中的弱项进行的补齐,最终成长为一个成功、成熟的开源项目。
商业软件产品的迭代
商业软件产品和开源项目的异同 一般来讲,商业软件产品的适应度函数要比开源项目的更复杂些,因为除了项目本身,还要衡量成本、市场相关的指标,可体现为如下指标:
  • 研发 ROI
  • 创新性
  • 产品销量
依据适应度函数适时对项目进行评估,能对产品现状有更好的认知,也能对未来工作有更可持续性的规划。在外界环境发生变化时,也能带领团队做出调整快速响应。
落地 【遗留系统演进】TODO 每个指标的量化,以及如何和 pipeline 结合,是个比较复杂的问题,在后续文章中展开讨论。

    推荐阅读