微服务架构的概念,现在对于大家应该都不陌生,无论使用 Apache Dubbo、还是 Spring Cloud,都可以去尝试微服务,把复杂而庞大的业务系统拆分成一些更小粒度且独立部署的 Rest 服务。但是这个过程,具体应该怎么做?现有的条件下到底要不要做微服务?服务拆分成什么粒度才是合适的?遗留的老系统需要如何考虑重构改造?有哪些坑需要我们注意?系统怎么在分布式服务下实现数据的一致性和服务的高可用可伸缩?拆分的过程中系统数量增多,测试、部署、运维、监控,又应该如何处理?
本文将从这些问题的深度分析出发,阐述微服务架构落地的一些设计原则和利弊取舍,结合微服务架构过程的很多最佳实践经验,希望给读者带来一定的启发和思考,避免在实际应用过程中走弯路,能够多快好省的落地实现微服务架构。内容涉及:
- 微服务架构的发展过程简介
- 微服务架构的特点与常见特性
- 微服务架构的常见技术与简单示例
- 微服务架构存在的一些问题
- 如何合理拆分微服务
- 遗留系统应该如何改造
- 怎么考虑拆分后的数据一致性
- 系统和服务的高可用可伸缩如何实现
- 拆分过程的测试和部署如何处理
- 拆分后的运维和监控如何处理
第一部分:微服务深度解析
微服务架构的发展过程简介
微服务架构发展的五个关键时间节点
- “微服务”这个概念最早是在 2011 年 5 月威尼斯的一个软件架构会议上讨论并提出的,用于描述一些作为通用架构风格的设计原则。
- 2012 年 3 月在波兰克拉科夫举行的 33rd Degree Conference 大会上,Thoughtworks 首席咨询师 James Lewis 做了题为《Microservices - Java, the Unix Way》的演讲(http://2012.33degree.org/talk/show/67),这次演讲里 James 讨论了微服务的一些原则和特征,例如单一服务职责、康威定律、自动扩展、DDD 等等。
- “微服务架构”则是由 Fred George 在 2012 年的一次技术大会上所提出(http://oredev.org/oredev2012/2012/sessions/micro-service-architecture.html),在大会的演讲中他讲解了如何分拆服务以及如何利用 MQ 来进行服务间的解耦,这就是最早的微服务架构雏形。
- 而后由 Martin Fowler 发扬光大并且在 2014 年发表了一篇著名的微服务文章(https://martinfowler.com/articles/microservices.html),这篇文章深入全面的讲解了什么是微服务架构。随后,微服务架构逐渐成为一种非常流行的架构模式,一大批的技术框架和文章涌现出来,越来越多的公司借鉴和使用微服务架构相关的技术。
- 2016 年 4 月,Lightbend 公司的创始人兼 CTO、Akka 的作者 Jonas Bonér,发布了一本小册子《响应式微服务架构》,讨论了基于响应式原理的微服务架构,以及如何将其用于构建可扩展,可应对故障的隔离服务,并与其他服务结合以形成一个紧密的整体。
特别值得一提的是,在微服务架构发展的过程中,还有两位技术大牛的影响不可忽视:
- Chris Richardson:《POJOS IN ACTION》与《微服务架构的设计模式》的作者,也是著名开源项目 cloudfoundry 和 eventuate 的创始人,他做了大量的微服务架构相关的方法和实践的探索,这里有其大量的演讲材料和视频:https://chrisrichardson.cn/resource/。
- Sam Newman,Martin Fowler 和 James Lewis 的 Thoughtworks 前同事,《Building Microservices》和《Monolith To Microservices》这两本的作者,前一本中文版叫《微服务设计》,同时也是 2014 年著名的推特论战《单体应用 vs 微服务应用》的主角之一(另外两人分别是 Netflix 的 Adrian Cockcroft 和 Etsy 的 John Allspaw ,具体参见 https://www.csdn.net/article/2014-08-06/2821078)。
微服务架构的发展趋势
软件架构的发展趋势,简单的说可以分为这几个阶段(详细介绍可以参见我的上一个文章《软件架构发展历程分享》或者《高可用可伸缩微服务架构:基于 Dubbo、Spring Cloud 和 ServiceMesh》一书):
- 单体架构:最简单的架构风格,所有的代码在一起,部署到单个进程,例如打包成一个 war 或者 jar,就是通常说的“大泥球”。
- 垂直架构:随着业务的发展,系统变得复杂,通过结构化思考,大家发现对于大规模协同开发,有效的控制手段就是对系统进行抽象和分层,例如场景的 MVC 方式。
- 面向服务架构(SOA):面向服务架构从建设企业 IT 生态系统的角度思考架构问题,关注点是各个系统提供可以集成的业务服务能力,而且通常由 ESB 之类的集中化技术实现。
- 微服务架构(MSA):微服务架构风格,将系统设计为一组低耦合的微服务,每个服务独立的部署运行,服务间一般采用 REST 等方式通信,同时采用自动化的测试运维等技术降低服务拆分后的复杂度。
我们可以从 Google 的趋势图看到,从 2014 年起,微服务架构架构的热度就直线上升,成为最热门的技术之一。从国内的情况来看,一方面;另一方面,一直到现在,每年的 QCon 大会都会有微服务架构版本,跟大家分享最新的微服务架构知识和实践经验。
什么是微服务架构
按 Martin Fowler 和 James Lewis 的定义,微服务架构风格是通过实现一系列微小的服务的方式,开发一个独立应用系统的方法,每个服务运行在自己的进程内,通过轻量级的机制与其他服务通信,通常是 HTTP 资源 API 的方式。这些服务都是围绕业务能力来构建,通过全自动部署工具来实现独立部署。这些服务,其可以使用不同的编程语言和不同的数据存储技术,并保持最小化集中管理。
具体包含如下特征:
- 组件以服务形式来提供:微服务也是面向服务的,提倡用可以独立部署的服务来作为组装业务能力的组件,而不是类库的形式。这样需要明确定义组件间的接口和通信协议。微服务架构的一个目的是通过合理的边界划分和演化机制来减少变更带来的影响。
- 围绕业务功能进行组织:根据康威定律,“设计系统的组织,其产生的设计等同于组织之内、组织之间的沟通结构”。微服务更倾向于围绕业务功能对服务结构进行划分、拆解。这样的服务,是针对业务领域有着关完整实现的软件,它包含使用接口、持久存储、以及对象的交互。因此团队应该是跨职能的,包含完整的开发技术:用户体验、数据库、以及项目管理。
- 产品不是项目:传统的开发模式,我们一般称为项目心态,就是以乙方心态给甲方做项目。一旦项目开发完成,软件将移交给维护/实施部门,或者是乙方交给甲方,然后开发团队就可以解散掉了。而微服务要求开发团队对软件产品的整个生命周期负责。这要求开发者每天都关注软件产品的运行情况,并与用户联系的更紧密,这也就是我们说的产品心态。产品心态下的软件质量要明显好于项目心态。Amazon 的理念就是“You build, you run it”,这也正是 DevOps 的文化理念。
- 强化终端及弱化通道:微服务的应用致力松耦合和高内聚,所以更倾向于 REST,而不是复杂的协议(如 WS 或者 BPEL 或者集中式框架),或者采用轻量级消息总线(如 RabbitMQ 或 ZeroMQ 等)来发布消息。
- 分散治理:这是跟传统的集中式管理很大区别的地方。微服务把单体式框架中的组件,拆分成不同的服务,在构建它们时将会有更多的选择。分散治理也意味着责任的下放,每个团队对自己的业务服务负责,如果你维护一个 7x24 小时的不间断服务,那么你就必须 24 小时随时 OnCall,哪怕晚上 3 点起来处理问题,就是 AWS 的模式。
- 分散数据管理:当单体式的应用使用单一逻辑数据库对数据持久化时,企业通常选择在应用的范围内使用一个数据库。微服务让每个服务管理自己的数据库:无论是相同数据库的不同实例,或者是不同的数据库系统。这一点,我们后面会详细说明。
- 基础设施自动化:云计算,特别是 AWS、Azure、Aliyun 等的发展,减少了构建、发布、运维微服务的复杂性。微服务的团队更加依赖于基础设施的自动化。其实不管是运维,测试也是一样。
- 容错性设计:任务服务都可能因为供应商或者底层硬件或网络的不可靠而故障。微服务应为每个应用的服务及数据中心提供日常故障检测和恢复,收集各项系统状态指标和业务指标、日志信息进行监控,并提供预警报警能力。面向失败的设计,后面也会再讨论。
- 改进设计:组件的关键特性是可替代性和可升级性,由于设计会不断更改,微服务所提供的服务应该能够替换或者报废,而不是要长久的发展的,每种设计也一样都有自己的阶段使命和生命周期。这样如果客户需要兼容性,版本控制是一种好的手段。
Chris Richardson 则简化了这种说法,认为微服务是一种架构风格,通过一组服务的方式构造系统,同时需要满足如下条件:
- 高可维护性和测试性
- 松耦合性
- 可独立部署
- 围绕业务能力进行组织
- 一个小团队对其完全负责 微服务架构能够快速、频繁和可靠地发布大型的复杂应用系统,也能够使得组织可以进化出自己的技术栈。
Peter Lawyer 说,微服务很多地方特别像是 Mike Gancarz 总结的 Unix 哲学:
- 小即是美(Small is beautiful)
- 让程序只做好一件事(Make each program do one thing well)
- 尽可能早地建立原型(Build a prototype as soon as possible)
- 可移植性比效率更重要(Choose portability over efficiency)
- 尽可能地榨取软件的全部价值 Use software leverage to your advantage.
微服务架构就是 Unix 哲学在分布式系统里的应用。微服务架构的哲学本质上等于 Unix 哲学里的“让程序只做好一件事”:
- 服务都很小,细粒度地执行单个功能。
- 组织文化应拥抱自动化部署和测试。这减轻了管理和运维的负担。
- 文化和设计原则应拥抱失败和错误,类似于抗脆弱系统。
- 每个服务都是弹性的,回弹性的,可组合的,最小化的和完整的(弹性和回弹性参见响应式微服务)。
从这里我们可以得出一个结论,一个微服务架构的系统需要满足一系列的条件和原则,而不仅仅是说使用了某个微服务的技术框架就是微服务架构。微服务这个词目前也过于流行以致于有些泛滥了。很多技术组件或者框架,例如可以用来暴露服务,可以用来自动化部署,可以用来管理配置等等,它们都可以用来作为微服务架构设计时的某个组成部分。但是单独用一个,并不代表我们实现了微服务设计,而只能说明我们借鉴了一些微服务的思想。另一方面,我们在做微服务的时候,也不用把市面上所有的微服务组件都拿来用。就像是我们写个业务系统不会用到 JDK 的所有 API,画一幅画之前我们买了一盒 24 支的水彩笔,实际上我们可能做一幅作品最终只用到了 5-6 个颜色的水彩笔。
微服务架构的特点、优势和常见技术
微服务的四个特点和六个能力
微服务架构首先是一个分布式的架构,其次我们要暴露和提供业务服务能力,然后我们需要考虑围绕这些业务能力的各种非功能性的能力。这些分散在各处的服务本身需要被管理起来,并且对服务的调用方透明,这样就有了服务的注册发现的功能需求。
同样地,每个服务可能部署了多台机器多个实例,所以,我们需要有路由和寻址的能力,做负载均衡,提升系统的扩展能力。有了这么多对外提供的不同服务接口,我们一样需要有一种机制对他们进行统一的接入控制,并把一些非业务的策略做到这个接入层,比如权限相关的,这就是服务网关。同时我们发现随着业务的发展和一些特定的运营活动,比如秒杀大促,流量会出现十倍以上的激增,这时候我们就需要考虑系统容量,服务间的强弱依赖关系,做服务降级、熔断,系统过载保护等措施。
微服务的优势
这个图 x 轴是系统复杂度,y 轴是开发的生产力,我们可以看到:
- 在系统复杂度很低的时候,单体的生产力要高一点,这是因为拆分微服务,管理这些服务的成本增加了
- 当复杂度开始增加,单体的生产力快速的降低,而微服务则不太受影响,这是因为复杂度大了,单体牵一发而动全身,各种耦合和相互影响太多
- 随着复杂度越来越高,微服务的低耦合开始减低了生产力的衰变,而单体架构的生产力则会降到一个非常低的水平
也就是说微服务应用在复杂度低的情况下,生产力反而比单体系统低。在复杂度高的地方,情况恰恰相反。
随着复杂度升高,单体架构的生产力快速下降,而微服务相对平稳,所以,复杂度越高的业务系统,越适合使用微服务架构。
搞清楚了微服务架构与单体架构的生产力的区别以后,我们再来看看微服务有哪些优势,我总结了一下有以下几点:
- 服务简单:因为微小,所以简单,从一个大泥球,变成了很多个小而美的颗粒,每个小颗粒职责单一,边界明确,可以通过简单组装完成大的功能,自然就比之前的大泥球好处理得多。
- 灵活扩展:单体的情况下,只能通过增加机器,再部署多套单体系统做成集群,前面加负载均衡来扩展;微服务以后,我们会发现用户服务压力不大不用扩展,订单服务压力大的时候多部署两台就可以了,这样我们就把扩展的方式从全部优化到局部。
- 便于维护:如果一个系统有 100 个业务功能,依赖关系相互耦合到一起,那么这就是维护的恶梦,这样的系统没有任何免疫力,修改任何一个功能,都可能会导致整个系统崩溃。微服务就简单得多了,每个服务自己出现问题,其他服务不会直接受到影响。同时维护具体某个服务的人员,也不需要一上来就学习全部的业务知识,比如用户服务模块的维护人员,只需要先学习用户服务的业务就可以上手工作了。
- 独立演进:变成微服务以后,各个独立系统的内部设计和实现细节都被隔离开,相互之间不受影响,只要服务间的接口不变,大家就可以各自独立的发展自己的系统,完成升级、重构、功能增强等等。
- 混合开发:各服务独立开发的另外一个好处就是,各个独立系统可以使用自己的技术栈和研发模式,包括开发语言和工具、数据库存储和中间件等技术,这样有助于试验和引入更先进和创新的技术,从一些个边缘服务开始尝试,技术、工具、中间件、研发模式,孵化成熟以后,可以大范围推广,实现技术和研发能力的持续更新换代,让研发组织保持长期的优势和活力,充分获得技术发展的红利。
- 持续交付:微服务比单体系统简单明确,这样就便于我们利用自动化测试和自动化部署来加速功能的迭代,配合 CI/CD 等基础设施,实现业务功能的持续交付,保障研发能够紧跟业务发展变化的节奏。
常见的微服务技术框架
在互联网出行业务中,用户通过 API 网关访问系统的乘客、司机、出行三个 REST 服务,这三个服务再通过 REST 访问计费、支付和通知三个服务。看起来很简单,也好理解,但是实际的业务系统里,设计和实现一般会是这样:
- 服务框架:我们可以选择用 Spring Cloud 或者 Apache Dubbo,包括新兴的 Spring Cloud Alibaba,还有华为贡献的 Apache ServiceComb,蚂蚁金服的 SOFAStack ,Oracle 的 Helidon,Redhat 的 Quarkus,基于 Scala 语言和 Akka 的 Lagom,基于 Grails 语言的 Micronaut,基于 Python 语言的 Nameko,基于 Golang 语言的 go-micro,支持多语言混编的响应式微服务框架 Vert.X,腾讯开源的 Tars,百度开源的 Apache BRPC(孵化中),微博的简化版 Dubbo 框架 Motan 等等。
- 配置中心:Apollo,Nacos,disconf,Spring Cloud Config,或者 Etcd、ZK、Redis 自己封装
- 服务注册发现:Eureka,Consul,或者 Etcd、ZK、Redis 自己封装
- 服务网关:Zuul/Zuul2,Spring Cloud Gateway,nginx 系列的 Open Resty 和 Kong,基于 Golang 的 fagongzi Gateway 等
- 容错限流:Hystrix,Sentinel,Resilience4j,或者直接用 Kong 自带的插件
- 消息处理:Kafka、RabbitMQ、RocketMQ,以及 Pulsar,可以使用 Sping Messaging 或者 Spring Cloud Stream 来简化处理
- 链路监控与日志:开源的链路技术有 CAT、Pinpoint、Skywalking、Zipkin、Jaeger 等,也可以考虑用商业的 APM(比如听云 APM、OneAPM、App Dynamic 等),日志可以用 ELK
- 认证与授权:比如要支持 OAuth2、LDAP,传统的自定义 BRAC 等,可以选择 Spring Security 或者 Apache Shiro 等