导读

系统架构是一个系统的灵魂,然而一个好的架构(或者更确切的说,一个合适的系统架构)不是一蹴而就,一下子就能完全设计出来的,而是随着系统发展,逐步演进的。本文将介绍明源云研发协同平台的架构从0到1,逐步随着业务发展一步一步迭代演进的过程。

背景

随着公司的ToB业务发展,开发团队规模不断扩大,需要交付的业务也不断增长,在这个过程中,交付的效率和质量出现了不同程度的问题,虽然也有QA团队制定的流程规范以及一些相应的保障措施,但是在交付压力下,效果不那么尽如人意。在此背景下,研发协同产品被提上日程,最初的目的就是为了提升整个交付链条的效率和质量。研发协同平台提供从“需求->开发->构建->代码质量->测试→发布”的全链路的一站式服务,基于敏捷研发、持续集成、持续交付、DevOps等研发理念,主要是为开发团队赋能,提升交付效率和质量。

技术选型

技术选型是一个项目的基础,一旦技术选型出现问题,后期要换用其他技术栈,代价是非常大。一般情况下,技术选型会遵循以下几个原则:

  • 选择熟悉的技术 - 一个新项目最好不要使用超过 30% 的新技术,对于不谁的技术,不可能控制使用过程中出现的风险。而且从团队建设上,任何一位技术 Leader,如果不能得到下属的技术尊重,必将受到惩罚。当然也不能完全不用新技术,完全不用,势必会走向走向另一个极端,裹足不前,失去技术前进的机会。总的来说,选择熟悉的技术,保持稳定性,同时适当引入新技术,保持技术先进性。
  • 选择成熟活跃的技术 - 选择成熟的技术,可以避免踩不必要的坑,碰到问题,也可以找到丰富的资料,也可以得到更多的社区支持。当然这是针对应用场景而言,也有一些团队专门就是做新技术预研,专门去踩坑,看是否有应用新技术的可行性。技术不光是考虑成熟度,还要考虑技术活跃度,活跃度在某个角度也间接说明了技术的应用广度,同时也能得到更多的支持。
  • 选择前进的技术 - 选择一个技术的最低标准是,技术的生命周期必须显著长于项目的生命周期。为什么需要确保所选择的技术不断前进?因为当前技术发展是非常快速的,技术的前进不仅仅取决于它本身,也和大环境发展密切相关。例如早期的delphi, silverlight, 现在都已被淘汰,如果不幸选择了类似这样的技术栈,对项目的伤害是巨大的,甚至可能直接导致项目无法进行下去。总的来说,好的技术栈要永远跑在用户需求前面。

基于以上的技术选型原则,研发协同平台的技术选型如下:

  • 应用技术选型:.Net Core, ABP, EF Core,SQL Server
    选型理由:团队开发人员都是.NET开放背景,.Net Core 2.0已发布,已经比较成熟稳定,相较于.Net Framework,不仅跨平台,而且开源,社区活跃度相当高。ABP是一个开源的.NET/.NET Core的基于DDD的快速应用开发框架,社区活跃度高,版本迭代快,一直在向前。最重要的一点,是这些技术栈都有团队成员有成功的实施经验。
  • CI/CD工具链技术选型
    需求管理 - JIRA
    代码托管- Gitlab, sourcetree
    持续集成 - Jenkins, webpack, grunt
    持续部署 - docker
    质量服务 - sonarqube, dotcover, nuint, xunit, jmeter,selenium
    选型理由:团队除了在docker上的应用经验有所不足外,其他的技术都是非常成熟的。docker技术,团队虽然也有一定的技术基础和应用经验,但没有像研发协同这种大规模的生产应用,并且要同时支持windows和linux容器。研发协同平台的产品特性决定了,会有大量开发团队的测试环境运行在平台下,docker是最符合产品需求的技术。所以即使有风险,也必须选择docker,同时也是必须啃下的骨头。

单体架构

在项目初期,为了产品快速上线、快速验证,架构是比较简单直接的,就是单体架构,如下图:
研发协同平台架构演进-LMLPHP

单体架构实现了主要的核心功能,提供了一站式的从需求->代码管理->开发->持续集成的服务。整体架构就是展示层->应用服务->数据层,其中缓存,后台作业,调度,邮件,日志,权限控制等都是以功能模块的形式内嵌在应用服务中,对于在CI过程使用到的工具栈,也是直接调用第三方的服务。另外因为CI过程一般都是长时任务,对于在展示层显示CI的过程状态,也是采用了简单的轮询机制来处理。
单体架构快速了实现了产品的核心功能,可以提供给种子用户快速验证,但随着验证反馈->快速迭代,一旦产品提供给大范围的用户使用,这种架构也就不在满足需求了,它的主要问题如下:

  • 业务服务和基础功能服务耦合在一起,一方面影响业务服务的扩展,另一方面基础服务是公共的,除了为RDC平台提供服务,在技术上也需要为其它产品提供服务
  • 业务服务中有不少长耗时的任务,这些都影响了业务服务的横向扩展,长耗时任务也必须从业务服务解耦
  • 轮询机制的状态刷新需要改进,同时应用服务和基础服务拆分后,也需要机制保障通信,缺少消息服务中间件
  • 不管是从稳定性还是可用性考虑,服务都必须可扩展
  • 一旦大范围使用,Jenkins单点,docker单点服务,都不足以应对,一定要集群

面对上述问题,平台的架构也必须升级来满足业务业务发展的需求,而演进的主要方式则是服务化、集群化

架构演进的五条原则

既然要对架构进行升级重构,那么有没有一些基本的准则,指导我们避免一些坑呢?基于此,我们尝试总结了架构演进的五条原则:

  • 确定当前的架构现状:每次架构演进,一定是针对当前架构的,所以必须非常清楚当前的架构现状和问题。清楚现状,明白目标,才能逐步改进,向目标前进。
  • 确定重构的目的和必要性:架构重构的原因是什么?是为了满足业务需要还是只是觉得架构比较落伍?除了架构重构之外,是否有别的备选方案,是否一定要进行架构重构?
  • 定义“重构完成”的标准:为每一次架构演进定义清晰的重构目标和成功标尺。
  • 渐进式重构:尽量将重构过程进行分解,每次都进行小的改进,尽快展示成果并得到反馈,在迭代中逐步完善。
  • 远离虚的东西:例如使用热门的技术,使用不成熟的技术。架构重构要脚踏实地,根据实际需要以及团队的技术背景,合理的选择重构方案。

我们每次对架构的重构,都是按照这些原则来进行的。

向集群架构演进

单体架构有不少问题,但是否一定需要进行架构重构呢?在重构前,我们需要回答架构演进原则提出的问题:

  • 确定当前的架构现状:所有服务集中在一起运行。
  • 确定重构的目的和必要性:随着产品的逐步推广,使用用户增多,使用频率,单体架构在应对业务量上涨上已经越来越吃力,同时,可用性也成为了高风险点。
  • 定义“重构完成”的标准:让架构支撑服务化,集群化。
  • 渐进式重构:以迭代的方式,按优化级逐步重构。例如,jenkins集群化,docker集群化,基础服务解耦服务化,一步一步,每一步都可以看到效果,得到反馈。
  • 远离虚的东西:并没有引入多少新的东西,主要是解耦,服务化,集群,增加消息服务中间件。

除了原有的架构重构外,在产品层面, 整个交付链条延伸到了C/D环节,这里和其他DevOps平台一个很不一样的点就是,在研发协同平台上交付的产品是ERP产品,ERP产品是运行在大量客户的不同环境下的,它不是交付一个SaaS产品,一个云服务产品。ERP产品要持续交付给大量的不同客户,而这里的客户环境又各不相同,要做到稳定,持续的交付是有相当大的难度和挑战的,在架构设计上必须充分考虑C/D的稳定性和持续性。

基于以上的需求,我们将单体架构重构为集群架构,并增加了C/D的架构设计,架构图如下:
研发协同平台架构演进-LMLPHP

集群架构有如下特点:

  • 解耦了基础服务与业务服务,各个服务的职责更清晰,也更单一
  • 基础功能服务化,复用基础服务能力
  • 使用Azure文件云服务,提高文件服务的可靠性和可用性
  • 新增消息服务,解耦各组件之间的通信
  • 构建服务集群,提高服务的可靠性和可用性
  • 构建Jenkins集群,提高平台的持续集成能力
  • 构建docker服务集群,提高平台持续部署,持续提供稳定运行环境的能力

实现了集群架构以后,服务的能力,稳定性和可靠性都上了一个台阶,但是随着用户的使用越来越深入,平台提供的服务越来越多,集群架构的问题也逐步开始显现:

  • 平台提供的服务能力越来越多,业务越来越复杂
  • 服务虽然集群化,但是业务服务能力还是单一对外,某个服务功能出现问题,会影响到服务整体对外提供的能力。可行的途径是进行服务拆分,不过服务拆分,复杂度也会增加,服务的运维成本以及治理问题也是需要综合考虑的
  • docker容器采用自开发的集群分配策略,缺少编排能力
  • 平台服务要提供集成与被集成的能力,与其他的CI服务集成,与测试平台集成
  • 平台要与其他产品打通 - 与运维产品打通,获取客户运维数据,做到DevOps闭环,通过反馈和运维数据反向推动产品持续迭代改进
  • 平台要对外开放,面向生态合作伙伴提供服务能力,对外开放,第一步就是要让用户能进来,这就涉及到整个用户中心体系的建立,用户管理、统一身份认证等。
  • 虽然集群架构已大大提高了可靠性和可用性,但是随着服务的深入使用和用户规模的不断增长,对可靠性和可用性的要求也越来越高,对平台服务以及服务资源的运维也变得越来越重要和紧迫

面对上述问题,需要对服务进行拆分,治理,提供服务和资源的运维、监控能力,而都需要架构

向微服务架构演进

在进行微服务架构重构之前,我们同样需要回答架构演进原则提出的问题:

  • 确定重构的目的和必要性 - 随着产品的持续迭代,业务复杂度越来越大,服务的使用也越来越深入,用户规模也在不停的增长,对整体服务的可靠性,可用性提出了新的挑战
  • 定义“重构完成”的界限 - 微服务化,容器云平台
  • 渐进式重构 - 以迭代的方式,按优化级逐步重构。例如服务的运维,监控,日志服务,服务的拆分,治理,容器云平台这些都是独立可逐步改进的
  • 确定当前的架构状态 - 集群架构中已经详细的描述
  • 远离虚的东西 - 新引入的技术点都有成熟可借鉴的方案,例如k8s,ELK,grafana, IdentityServer4,Ocelot,Consul

但是这里有一点是要特别强调的,尽管新引入的技术都有成熟可借鉴的方案,但是对团队而言,有不少是没有成功的生产环境实施经验的,这里是冒了一定的风险,但又是不得不去做和突破的事情。
重构后的微服务架构图,如下:
研发协同平台架构演进-LMLPHP

微服务架构的特点如下:

  • 提炼CI引擎,丰富集成能力
  • 服务按领域拆分,提供服务治理能力
  • 服务运维能力,提供监控、告警、统计分析
  • 提供日志服务,便于错误分析和运营分析
  • 提供统一的容器云服务, 提供高可用、可伸缩的容器应用管理

各个应用层在微服务架构下的职责:

  • 运行环境层:提供基础设施服务,包括服务器,IT安全配置以及容器云平台。未来所有的服务都会运行在容器云平台上,当前只有少数的服务在容器云平台上试运行,随着不断的改进、成熟,未来会逐步将服务迁移到容器云平台上
  • 数据存储层:提供数据存储能力,对于不同的数据类型,提供了不同的存储方式。 Sql Server用于应用数据的存储,redis用于缓存数据的存储,ES集群用于日志的存储,Azure文件用于文档的存储
  • 基础服务层:提供基础公共服务能力,除了为研发协同平台本身提供基础服务,也面向其他产品提供基础服务能力。
    日志服务(ELK)提供日志采集,存储,分析和展示服务;
    消息服务(MQTT)提供组件间的通信能力;
    文件服务(Azure文件)为应用提供统一的上传、存储、下载的服务;邮件服务提供邮件发送服务;
    任务调度和后台作业(Quaz+Hangfire)提供了长耗时任务队列的调度和处理服务;
    身份认证服务(IdentityServer4)面向开放提供了统一的身份认证能力。
  • 应用服务层:研发协同业务服务,主要包含基础服务,产品服务,持续集成服务、质量服务和持续交付服务。当前应用服务还没有微服务化,还处于服务拆分阶段,按领域拆分,按文件结构组织,一旦微服务框架就绪,则按领域服务一个一个拆分,逐步切换。
  • API接口层:API网关为服务消费端提供了统一的服务入口。除了网关,实现微服务框架,还必须实现服务治理:服务的注册、发现、负载、容错、降级、监控与日志。
  • 展示层:展示层是应用服务的消费者,通过API网关来使用应用服务。
  • 运维监控:运维监控服务(App.Metric+telegraf+InfluxDB+Grafana)当前主要实现了服务器资源监控以及业务服务的监控(流量、请求、错误等),以及分析图表的展示,并根据一定的预警规则,即使预警异常。

微服务架构是我们今年技术规划要实现的目标,其中一部分已经落地,一部分正在进行,也有一些还未开始,随着产品业务的发展,伴随着架构也是在不断摸索、重构、演进、向前。

写在最后

从来没有一个完美的架构能够一直支撑业务的发展,架构是动态的、变化的,随着业务的发展不断演进的,不同的阶段需要不同的架构 。研发协同平台的架构也是经历了单体架构->集群架构->微服务架构几个阶段,而且每一次架构重构周期都比较长,只要架构的模式思路定下来,保持快速的敏捷演进,不停向前,结合反馈和实际应用情况,不断改进,就可以比较稳定的实现架构重构。

07-15 10:24