如果微服务架构落地实践(上)中的5点都让你膝盖中箭,那么根据个人的经验,综合解决微服务实施难点的第一步就是:

1.以始为终,构建一个独立的敏捷微服务团队

我们对微服务的期待就是:可以独立开发,独立部署,并且去中心化管理。那么我们就需要先构造一支“可独立开发、独立部署、并且去中心化管理”的团队。这个团队为了达到这个目标,会采取各种办法(如:DevOps, 全功能团队)解决阻碍实现“独立开发、独立部署、去中心化管理”的问题。而根据康威定理,系统架构会慢慢向去中心化方向发展。

一定要意识到,这个过程会打破大型系统自上而下的既有流程,并采用更有生产力的方式构建新的组织架构。你所要做的就是充分信任团队,把它看作一个微型的技术管理创新。不要用老的方式控制团队的运作,这会打击团队的士气。

管理建议:

a. 让微服务团队完全脱离之前的工作,专心于微服务的工作中。如果分心同时做几件事,每件事都不会做到最好。

b. 给微服务团队一些特权,为了满足“全功能微服务团队”的诉求,特事特办。

c. 如果团队在执行过程中出现了依赖阻碍了进度,则需要吧依赖标出来。代码中的依赖容易看见,但组织中的流程依赖很难发现。

d. 为了避免团队对外部的“依赖惯性”,让团队自己想办法在内部解决依赖。

e. 组织流程的改变也是很重要的微服务架构产物,而不仅仅是微服务代码或者基础设施。

技术建议:

a. 为微服务创建一个全新的代码库,而不要从原先的代码库上克隆或复制,避免和原团队开发依赖。

b. 建设一个独立的持续交付流水线,最好是通过“流水线即代码”技术(如:Jenkinsfile)来自动生成流水线。

2. 构建微服务的“电梯演讲”

成立了微服务团队之后,接下来就是要选择第一个实现的微服务。但这个微服务应该多大,边界在哪里是个问题。这不需要严格的设计和反复的论证,只要发现当前痛点或者想要完成一个假设就足够上路了。让整个过程变轻,而不是变重。

我的建议是通过“微服务电梯演讲”的方式来定义微服务。格式可以是:(xxx微服务)用来在(xxx痛点场景)的情况下解决(某个问题),从而实现了(xxx效果),提升了(xxx价值)。例如:

订单查询微服务 用来在 订单查询数量快速 的情况下解决 访问数量迅速升高导致应用整体性能下降的问题, 从而实现了订单查询请求的分离,提升了其他功能的性能

当构造了微服务的电梯演讲,团队就可以以此为原则启动了。当碰到与现有系统冲突的问题,替换几个词有助于你做决策(语言一定程度上也是有魔力的)。例如把“拆分”换成“移除”,“从现有系统中拆分出订单查询功能”转变为“从现有系统中移除订单查询功能”。思维方式就从一个团队负责两个系统变成了两个团队负责两个系统。例如把“集成”换成“调用”,则“用户注册和用户登陆需要集成”转变为“用户登陆服务需要调用用户注册服务的信息”。思维上就把两个系统的关系明确了,从而确定了微服务之间的关系和沟通方式。

管理建议:

a. 把微服务电梯演讲挂在墙上,让团队成员铭记于心。这会强化组织对微服务边界的认识。

b. 随着团队的反思和学习,电梯演讲有可能变更,但一定要让团队形成共识和一致的意见。

c. 不要期望一次就划分正确,划分是一个持续权衡取舍的过程。

技术建议:

a. 明确了微服务的职责和边界之后再去看代码,否则容易被代码的复杂度影响。

b. 领域驱动设计(DDD)可以帮助你更好的划分微服务。领域驱动设计很好的遵循了“关注点分离(Seperation of concerns, SOC)”的原则,提出了成熟的,清晰的分层架构。

c. 不会领域驱动设计(DDD)也没有关系。简单的使用“关注点分离原则”也可以帮助你达到这一点。例如,从接口分离出流量较大的接口独立部署,把读数据库和写数据库的API分开独立部署,把静态访问和动态访问分离等等。

3. 以最小的代价发布第一个微服务

要注意两个关键点:一个是“最小代价”,另一个是“发布(Release)”。正如前文所述,微服务架构本身就决定了微服务一定是低成本低风险的渐进式演进。而最大的成本在于:

a. 级别、职责分工明确的组织沟通结构。

b. “长时间、慢反馈”的行动习惯。

c. 先进且学习成本较高的技术栈。

因此,“最小代价”包括以下三个方面:

a. 最精简的独立敏捷全功能团队

b. 最快的时间

c. 代价最小的技术栈。

此外,很多微服务“爱好者”由于害怕失败,因此将微服务始终放在实验室里。要用于面对失败,在生产环境中面临真实的问题,但要采取一些规避风险的措施。

管理建议:

a. 尽量让现有微服务团队自己学习解决问题,成为全功能团队。如无必要,绝不增添新的人手。

b. 扯破嗓子不如甩开膀子,先动起来,在行动中解决问题。

c. 先考虑最后如何发布,根据发布流程倒推。

技术建议:

a. 根据当前技术采用的情况选择代价较小的技术栈。

b. 采用动态特性开关(Feature Toggle),在发布后可以在生产环境动态的控制微服务的启用,降低失败风险。

c. 如果采用了动态特性开关,一定要预设删除特性开关和对应旧代码的时间期限,一般不超过两个月。否则后面大量的动态特性开关会带来管理成本的提升和代码的凌乱。

d. 由于团队比较小,功能比较单一,不建议采用分支构建微服务,而应该采用单主干方式开发。

4.  取得快速胜利(Quick wins),演示(Showcase)驱动开发

刚开始机型微服务改造的时候一定会是一个试错的过程。如果目标定的太大,会让团队倍感压力,从而士气低落。而制定每日的短期目标,赢得快速胜利,则会不断激励团都的士气。通过设定当前结束的产出来确定今天需要做什么是一个非常有效的方法。

每日演示(Daily Showcase)就是一种推进产出的方法。每天向团队分享今天的工作内容,使小组能够共同学习。并且以当天或者明天的Showcase为目标。每个人Showcase的内容不超过20分钟。一天的Showcase时间不超过一个小时。可以早上Showcase,也可以下班后Showcase。

常见的快速胜利目标如下:

a. 构造第一条微服务流水线

b. 上线第一个微服务Helloworld

c. 构造第一个微服务自动化测试

而以下目标不适合作为快速胜利的目标:

a. 构造微服务DevOps平台

b. 完成整个产品的微服务架构拆分

c. 构造微服务自动化运维体系

管理建议:

a. 要防止团队画大饼,完成好每日和每周的工作目标即可。微服务开发本身就没有很长周期。

b. 强迫团队有所产出,这样才能用关键产出驱动开发。产出不一定是代码或者基础设施,一篇总结,或者学习的分享文章,设置踩过的坑或者遇到的问题都可以展示,目的是要打造自治学习的团队。

c. 贵在坚持,不要计划太远。超过一个月,就要对目标是不是范围太大进行反思。

d.以天为单位拆分任务,超过一天的必须要拆分。无法在一天完成的工作需要拆分出阶段性产出。

e. 如果能够结对,并且每天能够交换结对,showcase不必要。

f. 可视化所有任务,用敏捷看板来管理任务是了解现状的最好方式。

技术建议:

a. 除了让第一个Helloworld尽快发布到生产环境,其他不要想太多。

b. 完成HelloWorld的发布,然后要考虑如何对发布流程进行改进,而不是上线业务。

5. 代码未动, DevOps先行

微服务解耦的本质是把代码内部的复杂性通过一些工具转化为外部复杂性。把代码内部的复杂性分散到各个微服务中以降低整体复杂性和架构风险。在这个过程中,会大量采用DevOps技术和工具。也可以说,微服务是DevOps文化和技术走到极致的必然结果。

以J2EE的应用为例,以前Web Server+ App Server + Middle Ware+ Database的传统架构被代码更少,更多基础设施的工具所取代。因为基础设施相对于代码来说更加稳定,更加有利于扩展。

如果把微服务的技术架构比作“搭台唱戏”:那么首先需要建立好微服务交付和运行的平台,然后让微服务上台“唱戏”。这个平台一开始不需要很完善,只需要满足生产上线的必要要求即可。而在很多企业里,这个部分是由Ops团队在交付流程末尾把关的。因此,把最后一道关卡的确认工作放到最前面考虑也可以减少后期的返工和不必要的成本。

以前,软件的开发和测试过程是分开的。然而,随着DevOps运动的兴起和各种自动化运维工具的兴起,分开的必要性大不如前,只要有足够的自动化测试做质量保证,就可以很快的将微服务快速部署和发布到生产环境上。最开始的时候,哪怕发布一个Hello World程序,都表明微服务的持续交付和运行的平台已经搭建好了。微服务的交付流程已经打通,这一点是重中之重。从技术交付产物来说,DevOps主要交付两点:a. 持续交付流水线; b. 微服务运行平台 。为了保证微服务交付的高效,需要把这两者通过自动化的方式有机结合起来,而不是各自为政,让开发和运维的矛盾编程自动化的开发和运维矛盾。

此外,DevOps指的不光是一系列技术,更是一种工作方式。从团队工作方式来说,DevOps要做到:

a. 要让Dev和Ops共同参与决策、设计、实现和维护

b. 团队完全独立自主,打破对现有流程的依赖。

c. 不断追求改进,让团队形成改进的团队文化。

管理建议:

a. 给团队继续前进的最大动力,就是新程序快速投入生产。

b. 如果你的组织是Dev 和 Ops分离的组织,先咨询下Ops工程师的意见。最好是能够给微服务团队配备一名Ops工程师。

c. 如果不具备实施DevOps的条件,微服务架构就要从运维侧,而不是开发侧进行。

技术建议:

a. 微服务平台一开始可以很简单,可以在以后慢慢增强和扩展。但一定要部署到生产环境里使用。

b. 如果想使用现成的微服务平台可以参考Spring Cloud。

c. 微服务运行平台可以通过反向代理和生产环境并行运行。

d. 采用灰度发布技术在生产环境中逐步提升微服务的使用占比。

e. 基础设施即代码是DevOps的核心实践,可以帮助开发人员快速构建与生产环境相似的开发环境,减少环境的不一致性。可以采用Docker, Ansible, Vagrant等工具来完成。

f. 基础设施对微服务应该是透明的。微服务不应该也没必要知道运行环境的细节。只要能够正常启动并执行任务就完成了它的任务。因此,基础设施代码和微服务业务代码要分开,且微服务不应该高速平台自己如何部署。

g. 服务注册和发现是微服务架构的核心部分,Consul和Eureka是这方面的佼佼者。

h. 部署(Deploy)和发布(Release)要分开。

6. 除了代码提交和发布,微服务平台一切都应当自动化

在完成了微服务的基础设施和交付流程之后,就可以开始实现微服务的业务了。这时候需要依据电梯演讲划分出来的微服务进行业务逻辑开发。在以DevOps的方式工作一段时间后,团队应该养成自动化的习惯,如果没有,就应该检查一下自己的自动化程度。最佳的自动化状态就是出来代码提交和发布,在这之间的每一个流程和环节都应该由自动化的手段来完成。

当然,也有不能自动化的部分。根据我的经验,不能自动化的原因主要来自于流程管理的制度要求,而非技术困难。这往往是组织没有依据微服务进行流程变革导致的。这时候需要检讨不能自动化的部分是不是有存在的必要。

另一方面,虽然自动化可以大幅度缩短微服务交付时间,提升微服务交付效率。但自动化的同时需要考虑安全因素和风险,不能顾此失彼。对于生产来说,可用性和安全性是最重要的部分。通常,可实现自动化的关键流程有:

a. 自动化功能测试(UI/集成/单元/回归)

b. 自动化构建

c. 自动化部署

d. 自动化性能测试

e. 自动化安全扫描

管理建议:

a. 鼓励团队成员自发进行自动化的改进,这会给未来微服务批量开发带来很多好处。

b. 不要一开始就追求全面的自动化,自动化需要花费一定的时间。根据团队的进度视情况适度进行。

技术建议:

a. 采用TDD(Test-Driven Development)的方式不光可以提升质量,也可以完成测试的自动化。

b. 注意自动化的安全隐患,机密信息需要独立管理。

c. 关键步骤需要准备自动手动两种方式,必要时可以干预自动过程。

d. 采用git的hook技术,在代码push之前就可以完成测试和静态检查,提升CI的成功率。

7. 总结并复制成功经验,建立微服务交付的节奏

当完成了第一个微服务,不要急于开始进行下一个微服务的开发。而是需要进行一次关于可复制经验的总结,识别微服务开发中的经验教训并总结成可复制的经验和产出。以下是一些需要总结出来的关键产出。

a. 微服务开发到发布的端到端流程规范。

b. 微服务开发的技术质量规范。

c. 团队合作中坚持的最佳实践。

d. 常见技术问题总结。

有了以上关键产出,就可以对微服务团队进行扩张。这时候有了微服务开发的老司机,带着刚加入的同事一起开发,风险相对会低很多。

管理建议:

a. 刚开始的时候可以每周进行一个回顾会议,团队需要快速的反馈和调整。

b. 不要急于扩展团队,要在成功经验稳定并形成模式之后再快速扩充。

c. 避免微服务良好的开发氛围被稀释,刚开始的时候扩充团队可以慢一点,新老成员配比不要超过1:1。

d. 虽然微服务平台趋于稳定,但在微服务没有上规模之前,不要让团队缺少Ops成员。

e. 注重知识的传承和人才的培养。

技术建议:

a. 不要急于在微服务规模不大时形成微服务模板,否则会限制微服务未来的开发和扩展。

b. 在微服务不成规模的时候不要放松对微服务平台的改进。

1