随着RESTful、云计算、DevOps、持续交付等概念的深入人心,微服务(Microservices)逐渐成为系统架构的一个代名词。那么微服务是否是业界期待已久的企业架构解决方案?在对遗留系统进行微服务的改造过程中存在怎样的困难和挑战,应该注意些什么?在该分享中,王磊将通过实际的案例,跟大家探讨使用微服务改造遗留系统的实践之路。
· 什么是微服务
· 微服务的诞生背景
· 遗留系统的微服务改造策略
· 微服务改造之路
背景
首先,请大家思考什么是系统架构设计?
一直以来,系统架构设计是IT领域经久不衰的话题之一,是每个系统构建过程中极其关键的一部分,它决定了系统是否能够被正确、有效的构建。大家也一直在探索,寻找更优秀的架构设计方式来构建系统。
那什么是系统的架构设计?对于这个问题,我相信每个朋友都会有不同的定义,实际上,也并没有一个标准的答案来解释什么是架构设计。
基于我过去的经验和工作方式,我认为系统架构设计的本质,是在应用系统内部找到这样一个动态平衡:平衡业务、技术、团队的同时,考虑系统灵活性、可扩展性以及可维护性等因素,并将应用系统划分成不同的部分,使这些部分彼此之间相互分工、相互协作,从而为用户提供某种特定的价值的方式。
随着RESTful、云计算、DevOps、持续交付等概念的深入人心,微服务架构逐渐成为系统架构的一个代名词。
什么是微服务架构
2015年,微服务架构这个词,以相当高的频率出现在各种演讲、文章、会议、社区上。这里,我就和大家快速回顾一下,老马(Martin Folwer)对微服务的定义中认为,微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。 每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。 另外,对具体的服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。
总结成一句话就是微服务是围绕业务构建的细粒度的分布式系统。
微服务的诞生背景
2015年,微服务突然火了,为什么?
其实微服务架构并不是什么技术创新,而是IT发展到现阶段对技术架构的要求。
这个要求包括快速和业务对齐(alignbusiness)、快速理解和抽象业务(DDD)、快速开发(Lean、Agile)、快速反馈和交付(CI、CD、DevOps)。
所以我认为微服务并不是技术,而是将化整为零(或称分治)思想换了一种说法,无论是把一个大型系统分割成多个小而自治的系统,还是把一个大型团队分成多个团队,或是把一个复杂的项目分成多个交付阶段都是这种思想的运用。
当然,任何新事物的诞生,总会有一个推动因素。微服务的诞生也并非偶然。它是互联网高速发展,技术日新月异的变化以及传统架构无法适应快速变化等多重因素的推动下所诞生的产物。
基于个人的理解,我将微服务的诞生因素总结为如下几点:
1、互联网行业的快速发展
过去的十年中,互联网对我们的生活产生了翻天覆地的变化,越来越多的传统行业公司也开始依赖互联网技术打造其核心竞争优势。
在这种情况下,如何从系统架构的角度出发,构建灵活、易扩展的系统,快速应对需求的变化;同时,随着用户量的增加,如何保证系统的可伸缩性、高可用性,成为系统架构面临的挑战。
2、单块架构系统面临的挑战
随着用户需求个性化、产品生命周期变短、市场需求不稳定等因素的出现,单块架构系统面临着越来越多的挑战。如何找到一种更有效的、更灵活、适应需求的系统架构方式,成为大家关注的焦点。
3、敏捷、精益方法、持续交付的深入人心
在IT行业发展的过去十年,敏捷、精益、持续交付等价值观、方法论的提出以及实践,让很多组织意识到应变市场变化、提高响应力的重要性,应该构建软件交付周期的闭环(分析、开发、测试、部署、运维、监控、运营),而不仅仅是提高开发阶段的效率。
精益创业(Lean Startup)帮助组织分析并建立最小可实行产品(MinimumViableProduct),通过迭代持续改进敏捷方法帮助组织消除浪费,通过反馈不断找到正确的方向。
持续交付则帮助组织构建更快、更可靠、可频繁发布的交付机制并构建产品交付闭环。
大部分组织已经基本上形成了一套可实施的交付体系。包括持续集成、自动化测试、数据管理、自动化部署机制等。
这时候,大泥球式的单块架构,会逐渐成为影响交付周期进一步优化的瓶颈,因此如何找到灵活性高、扩展性好的架构方式,也成为进一步优化交付周期面临的挑战。
4、Docker等容器虚拟化技术的快速发展
同传统的虚拟化技术相比,基于容器技术的Docker,不需要复杂的Hypervisor机制支持,具有更高的虚拟化性能和效率。
同时容器可以很容易的运行在任意的装有DockerEngine的系统上,使得开发人员能够用更低的成本将应用程序部署在不同平台上。
5、DevOps文化
DevOps文化的推行打破了传统开发与运维之间的壁垒,帮助组织形成开发、运维紧密配合的、全功能化的高效团队,并尽早降低软件交付最后一公里的风险。
遗留系统的微服务改造策略
聊完什么是微服务架构以及其诞生背景,接下来我们来谈谈如何改造遗留系统。
在过去的10多年间,大部分工作时间我都在和遗留系统打交道。我相信很多朋友也是工作在已经运转多年的遗留系统上。
对于这类系统,当谈论使用微服务对其进行改造时,我认为要谨记一点:
改造不是重做。
在改造的过程中,要始终以保证系统为用户提供的业务价值可用作为首要目标。从这个点出发,基于我的经验,对微服务改造的策略总结为如下五个步骤:
1、范围定义
对于遗留系统而言,通常业务运转时间较长(譬如5~8年以上,甚至更长),因此涉及的功能繁杂,代码中存在大量无效或者过时的需求,缺陷修复成本较高。
另外,系统在演进的过程中,也会持续为用户提供新的功能和价值。因此,划分出清晰的范围非常重要。
实际上,范围定义主要包括两部分:
1) 明确业务改造范围
所谓改造范围,就是确定我们常说的业务试点。通常,作为初次尝试微服务实践的组织,建议选取业务范围影响较小、非关键功能的试点,这样做也是为了确保在不影响核心业务的情况下快速尝试并获得反馈。
2) 明确成员责任范围
明确成员责任范围,确定由谁来改造,确保改造的目标清晰。
实际上,对于产品而言,遗留系统的维护和更新,包括缺陷定位、缺陷修复、数据更新、功能实现、测试、交付给运维团队等,通常已经让团队的工作处于高负荷状态。因此,需要确定成员,全身心的投入,以微服务改造作为短期目标。
2、功能剥离
有了明确的业务范围,成员也有了清晰的责任,接下来就需要将部分功能点进行剥离。
所谓剥离,就是将选中的功能从原有的系统中拆分出来,并构建成独立的服务。在这个阶段,主要包括两点:
1)将功能从原有系统拆分出来,并构建新服务
一提到拆分,很多朋友会纠结,“系统复杂,如何拆分微服务才好?怎么样的拆分才合理?”。其实,从我个人的观点来看,这时候还不是纠结服务到底怎么划分合理的时候。为什么?
a)好的架构是动态演变和迭代出来的,业务在不断改变,技术和工具也在不会的升级换代,没有完美的架构,只有无限逼近完美的动态平衡,所以先小范围、低成本动起来,在运转中找平衡点。
b)微服务的复杂度在于分布式系统本身,以及其生态系统(开发、测试、部署、运维、监控、告警)的搭建。
c)团队文化的形成是一个相对漫长的过程,如果花很大力气关注服务怎么拆,而没有聚焦在生态系统的搭建以及团队文化的形成上,实际上是舍本逐末。即便拆分出了不同的服务,在落地的时候也会遇到诸多问题。所以,找一个功能点先拆,然后搭建持续交付流水线,快速试错,建立好有效的反馈闭环机制,再不断寻找动态平衡,拆分出更细的服务或者将不合理的服务合并。
2)在原有的系统前端,使用代理机制,并使用遗留系统和新服务组合为用户提供价值
这一步,目的是使用组合的系统(遗留系统+新的服务)为用户提供价值。
对于Web系统,通常可以在前端使用直接请求新的服务。也可以在后端使用转发请求,获取新服务提供的数据。
如下图所示:
3、数据解耦
在以前的遗留系统构建过程中,通常使用数据库作为集成点,不同功能/系统之间通过数据库完成数据交换。对于某些系统,还大量使用存储过程完成业务逻辑,开发的时候看似效率高,但几年下来,DBA成了IT团队最懂业务的人,维护成为瓶颈。
而实际上,业务的数据是业务固有的组成部分,应当随着业务的变化而变化。业务拆分出来,数据也应该拆分出来。从而保证访问数据只能通过统一的相关业务API完成。便于在将来的业务和架构演进中,有效的对数据维护、管理和升级。
4、数据同步
数据同步,是一个价值体现的过渡过程。
一方面,遗留系统的改造中存在的各种各样的挑战和我们今天认为的不合理(当时的场景也许是合理的)。另一方面,对于大部分遗留的系统,都会使用数据库作为集成点(开发成本低),导致某业务功能的数据与其他功能有着千丝万缕的联系,数据的变化容易对其他功能造成影响。
因此对于大型的遗留系统,很难在短期的时间内(3~6个月)完成全系统的改造。需要一个相对漫长,循序渐进的过程来完成改造。
譬如,在电商系统中,商家的后台管理系统中的产品、价格的更新,会发布到面向用户的电商搜索系统中以及其他系统中。如果我们将系统中的产品相关拆分成独立服务,则必须也要拆分数据发布机制,否则的话容易造成数据不一致。但拆分数据发布机制,又需要分析清楚不同数据之间的影响和依赖,需要更大的成本,短期内不易完成。
这时候,如果将新服务的数据同步回原有的数据库,采用这样一个折中的的过程,既能保障新的服务和数据被独立,又不影响原有的遗留系统功能。
说白了,这其实也是在保证系统为用户提供的业务价值不被破坏。
有了之前的尝试,接下来就是通过不断的迭代,完成功能剥离,数据解耦、数据同步,从而将更多的功能拆分成独立的服务。
如上就是我对于遗留系统改造的策略。
遗留系统改造实践
接下来,我和大家分享一个我所经历的遗留系统改造的案例。首先,让我们看看这个系统的背景和一些数据。
客户背景
某区域最大的房产门户,业务涉及个人房产、商业房产、土地交易、买卖租赁、业务运行在7个国家。
8年前基于第三方平台二次开发的业务支撑系统,随着企业的高速发展,维护成本增加,新需求交付周期长,系统逐渐成为阻碍企业高速发展的瓶颈。
业务痛点
对于每10万元额度的合同,从销售团队准备材料、与客户签单、递交给合同部门,再到合同生效大概需要3.5人天。当时年销售额为4亿,随着业务量的快速增长,签订合同的人力成本在66人年,这还是不考虑管理、沟通等成本,因此成本急剧增加。
系统概览
系统为典型的三层单块架构,主从数据库运行在数据中心的虚拟机上。开发和运维团队属于两个独立部门,部署时需要提交文档,记录部署流程、细节以及潜在风险,然后提交审批,获取批准后由运维团队排期并完成部署。
相关数据
a) 400K行代码
系统涉及订单、用户、产品、价格、合同、多国业务支撑等
b) 11名团队成员
以开发和测试为主,每2周交付一个版本给运维部门,以修复缺陷为主,也会有新特性需求。
c) 30% 单元测试覆盖率
系统功能繁杂,二次开发封装了很多库,单元测试覆盖率低。
无效功能的代码长期不清理,核心人员离职或者换岗,因此,大部分功能用集成和功能测试来验证。
d) 50分钟持续集成
持续集成的大部分时间都用来运行集成/功能测试,同时创建很多任务,用于检测不同系统间的数据一致性。
e) 3天部署
交付版本给运维部门后,需要相关人员审批,授权后排期进行部署,从提交到部署生效,通常需要2~3天。
基于之前定义的改造策略,我们的改造过程大致如下所示:
范围定义:
· 将合同相关部分作为改造的业务范围
· 将团队中3人+外部引入的2人作为微服务改造团队
功能剥离:
· 首先剥离合同签署部分,提供在线签署合同系统(H5+JS)
· 提供合同签署后的存储服务,记录用户在线签署的合同
数据解耦
· 将用户在线签署的合同数据独立存储
数据同步
· 在夜间负载较低的时候,将签署的合同数据同步回原有的遗留系统中
不断迭代,陆续完成后续的服务
· 实现合同服务,并构建前后端分离的H5+JS应用,为合同部门提供合同管理后台
· 定义合同pdf生成器,完成pdf的存储和下载
· 定义合同中相关数据的服务接口,譬如产品服务,用户服务。便于用户挑选产品组合以及获取积分信息
经过近半年多后,改造的架构如下所示:
可以看到,合同签署的业务已经被拆分出来,同时合同签署的数据也被独立出来,但由于原有遗留系统的复杂度以及数据相关依赖,我们需要将合同的签署数据同步到遗留系统的数据库中。
当然,这只是我的个案中用到,大家可以在改造的过程中,结合具体的业务场景中,考虑是否需要这样的数据同步机制。
对于当前这个例子,如果不做数据的同步,则需要更长的时间分析并解耦合同数据同原有遗留系统的依赖,因此也可以看出,同步是为了帮助我们尽快的使改造后的服务体现价值。
理论上,经过不断地迭代,逐渐完成业务功能解耦,新服务构建。那么遗留系统就会被替换掉。
改造要点
在改造的整个过程中,我认为如下几个实践是非常重要的:
基础设施自动化
原有的部署发生在数据中心,因此流程上相对复杂,而且存在一定弊端(譬如审批和协作上,起不到实质作用)。对于改造后的服务而言,我们使用更多的自动化方式代替复杂的审批流程。通过使用AWS作为基础设施,团队能够更自主的对基础设施进行管理。如资源创建、销毁、更新等。随着服务的增多,基础设施自动化帮助我们节省了大量的时间。当然,从组织层面,也成立了专门的小组研究AWS以及相关的DevOps配套工具。
目前,国内外有很多优秀的云平台,可以方便的为用户提供基础设施的自动化机制。
微服务生态系统
微服务的生态系统是指微服务实施过程相关的协作部分,涉及部分较多,譬如测试机制、持续集成、自动化部署、细粒度监控、日志聚合、告警、持续交付,以及大家非常关注的服务注册、服务发现机制等。
这部分的灵活性比较大,因为目前如上说的每一个领域都有很多优秀的工具。譬如日志聚合目前业界的方案通常为ELK、AWS的部署使用CloudFormation更灵活,监控的方案如Zabbix、NewRelic、CloudWatch等,成熟的监控工具都具有告警功能,PagerDuty也提供更专业的告警服务。服务注册和发现有Eureka,Consul,Zookeeper。大家可以在各自的团队中自由发挥。
开发框架的演进
开发框架是团队在构建微服务的过程中,不断总结,梳理出的快速开发微服务的相关工具和框架。
我们基于Ruby构建了快速开发框架,主要包括四部分,如下图所示:
1) 开发模板
使用Grape作为Web框架,HAL作为API通信规约,RSpec作为测试框架。同时,还定义了一组Rake任务,譬如运行测试,查看测试报告,将当前的服务生成RPM/AMI镜像等。
除此之外,该模板也提供了一组通用的URL,帮助使用者查看微服务的版本、配置信息以及检测是否健康运行等。譬如/diagnostic/config, /health, /version, /heartbeat
2) 代码生成工具
通过指定不同参数,代码生成工具能创建具有数据库访问能力,或者是包含异步队列处理的微服务应用。同时,也可以标记该服务是数据消费者还是数据生产者,帮助理解多个微服务之间的联系
3) 持续集成模板
基于持续集成服务器Bamboo,创建了模板工程,并定义主要的阶段:
验证:运行单元测试,契约测试
构建:构建基于AMI的部署包
部署:基于指定版本的AMI,快速部署到验收环境或者产品环境上。
利用这样的持续集成模板工程,花费很少的时间,就可以针对新建的微服务应用,快速配置其对应的持续集成环境。
4) 基于Asgard的部署工具
Asgard是由Netflix开发的基于Web的AWS云部署和管理工具。基于Asgard,我们实现了命令行部署工具,部署时通过一条命令,提供服务名称、版本号,就可自动完成资源的创建、部署、流量切换、删除旧的应用等操作。譬如:
deploy [ServiceName] [ServiceVersion]
团队运维自管理
这一部分是关于团队的文化管理。也是对DevOPS的延伸,我们称为TMI(Team Managed Infrastructure)。
目的是将分析、开发、测试以及资源创建、销毁、自动化部署的权利交给团队,由团队按需完成部署(加上看板的流程管理,而非Scrum的固定迭代,可以做到一天部署多次)。
当然,这个环节非常依赖于成熟的监控以及告警机制,当出现问题时,能够有效的通知到责任人,快速反馈,快速修复。团队内部也会定期轮换Pager(出问题救火的人),培养团队以服务可用作为大家的共同目标,培养产品观念,而非项目观念。
再回顾一下这个图:
最后,和大家分享一下,我个人在微服务实施过程中总结的4句方针:
1. 由大到小,由粗到细
2. 关注运维,关注监控
3. 快速反馈,快速修复
4. 循序渐进,增量实现
--------------本期结束---------------
【作者介绍】
王磊,曾任职西安尚度元科技CTO、前ThoughtWorks首席咨询师。国内较早倡导和实践微服务的先行者,多次受邀在大型技术会议主题分享“微服务架构”,并著有《微服务架构与实践》一书。王磊有超过10年以上的软件行业经验,从企业应用、互联网应用、微服务平台架构设计开发到自动化构建、持续集成、持续交付以及DevOps的转型实施等有较丰富的实践经验。他同时是开源软件的爱好者、贡献者及GDCR西安组织者,译有《Ruby Gems开发实战》一书。现任职于华为。