微服务概览

微服务概览

1. 单体架构

Web应用程序发展的早期,大部分web工程是将所有的功能模块(service side)打包到一起并放在一个web容器中运行,很多企业的Java应用程序打包为war包。其他语言(Ruby,Python或者C++)写的程序也有类似的问题。

让我们假设您正在构建一个电子商务应用程序,该应用程序接收来自客户的订单,验证库存和可用信用,并运送它们。该应用程序包含几个组件,包括实现用户界面的StoreFrontUI,以及用于检查信用,维护库存和装运订单的一些后端服务。

该应用程序部署为单个整体应用程序。例如,Java Web应用程序由单个WAR文件组成,该文件在Web容器(如Tomcat)上运行。Rails应用程序包含使用例如Apache / Nginx上的Phusion Passenger或Tomcat上的JRuby部署的单个目录层次结构。您可以在负载均衡器后面运行应用程序的多个实例,以便扩展和提高可用性。

image-20210211235030552

个人觉得如果是在创业初期而且开发的人力资源不足的情况下,采用这种单体的架构是在情理之中的,毕竟这是你熟悉的代码,不过随着时间的推移,问题开始慢慢显现,代码越垒越多,维护的成本越来越高,需求也是越来越复杂,牵一发而动全身,有的时候甚至没有办法扩展。如果你将这个应用交给你的帮手,我觉得你的帮手可能也不会在短时间内就能看明白你的代码,应用无法扩展,可靠性低下,这些都是单体架构应用的顽疾。终于到了最后,敏捷性开发和部署都变的无法完成了。到了这一步就要考虑换架构了。没错误,我要说的就是微服务。

2. 微服务

微服务首先要做的第一件事情就是拆解单体架构,化繁为简,分而治之。

image-20210211235916336

这是我听毛剑讲微服务架构的时候说的,在B站从单体巨石架构演进为微服务架构的演示图。这张架构图明确的一点就是微服务的核心思想就是-化繁为简,分而治之

1. 微服务起源

你是不是经常听到别人在讲 SOA(面向服务的架构模式)它和微服务又是什么关系?

SOA你可以把微服务想成是 SOA 的一种实践。微服务架构有如下几个特点:

• 小即是美:小的服务代码少,bug 也少,易测试,易维护,也更容易不断迭代完善的精致进而美妙。

• 单一职责:一个服务也只需要做好一件事,专注才能做好。

• 尽可能早地创建原型:尽可能早的提供服务 API,建立服务契约,达成服务间沟通的一致性约定,至于实现和完善可以慢慢再做。

• 可移植性比效率更重要:服务间的轻量级交互协议在效率和可移植性二者间,首要依然考虑兼容性和移植性。

You should instead think of Microservices as a specific approach for SOA in the same way that XP or Scrum are specific approaches for Agile software development.
--来自《Building Microservices》
你应该将微服务看作SOA的一种特定方法,就像XP或Scrum是敏捷软件开发的特定方法一样。

img

如图,左边是典型的单体架构,右边则是微服务架构,两边对比还是比较明显的,左侧单体架构只有一个db,右侧微服务每一个微服务都独享一个db。左侧单体服务的数据链路比较单一,只有一条而到了右侧的微服务每一个服务一条连接。

2. 微服务定义

围绕业务功能构建的,服务关注单一业务,服务间采用轻量级的通信机制,可以全自动独立部署,可以使用不同的编程语言和数据存储技术。微服务架构通过业务拆分实现服务组件化,通过组件组合快速开发系统,业务单一的服务组件又可以独立部署,使得整个系统变得清晰灵活:

• 原子服务

尽可能的关注单一业务,换句话说就是一个划分出来的微服务只做一件事情。划分的边界就不好说了,这真的是要依照具体的业务来确定的。

• 独立进程

每一个划分出来的微服务都是一个单独的进程。在操作系统里都是一个单独的应用。

• 隔离部署

这里说的隔离部署其实和上一个独立进程关系是比较密切的,随着容器编排技术的日益成熟,从原来的Docker到Docker Swarm再到后来的K8s,利用namespace和cgroup技术时间进程级别的隔离从而是有效的推进了微服务架构的发展。

• 去中心化服务治理

随着主体对客体的相互作用的深入和认知机能的不断平衡、认知结构的不断完善,个体能从自我中心状态中解除出来,我们称之为去中心化
--皮亚杰

怎么理解去中心化服务治理。比如说当平台的决策者倡导建设API网关,所有外部服务和内部服务都由统一的API网关进行管理。在项目初期,中心化的API网关统一了所有API的入口,这看起来很规范,但从技术角度来看限制了API的多样化。随着业务的发展,API网关开始暴露问题,每个用户请求经过机房时只要有服务之间的交互,则都会从API网关进行路由,服务上量以后,由于内部服务之间的交互都会叠加在API网关的调用上,所以在很大程度上放大了API网关的调用TPS,API网关很快就遇到了性能瓶颈。

上面这个案例是典型的微服务的反模式,微服务倡导去中心化的治理,不推荐每个微服务都使用相同的标准和技术来开发和使用服务。

在微服务架构下可以使用C++开发一个服务,来对接Java开发的另外一个服务,对于异构系统之间的交互标准,通常可以使用工具来补偿。开发者可以开发共用的工具,并分享给异构系统的开发者使用,来解决异构系统不一致的问题,例如:Thrift远程调用框架使用中间语言(IDL)来定义接口,中间语言是独立于任何语言的,并提供了工具来生成中间语言,以及在中间语言与具体语言之间的代码转换。或者是后来的GRPC框架。

微服务架构倡导去中心化的服务管理和治理,尽量不设置中心化的管理服务,最差也需要在中心化的管理服务宕机时有替代方案和设计。在支付平台服务化建设中,如果第1层SOA服务化采用Dubbo框架进行定制化,如果Dubbo服务化出现了大面积的崩溃,则服务化体系会切换到点对点的hessian远程调用,这被称为服务化降级,降级后点对点的hessian远程调用时没有中心化节点,整体上符合微服务的原理。

缺点:

• 基础设施的建设、复杂度高

img

由原来的单体的服务经过微服务化的拆解,拆解出了成百上千个微服务,从宏观上来看,整体架构的复杂度变高了,服务于服务之间的依赖相比之前变得异常的复杂,当你的服务出了问题之后你就需要去定位问题在哪儿,面对这成百上千个服务,排障的工作就变得异常的复杂。比如说你的服务需要上测试环境去测试,测试人员去测试的时候发现了问题,但是测试人员是无法定位出问题出在哪里的,有可能是你的服务确实有问题,甚至说你的服务的上下游服务有问题,最后导致了测试人员测试的时候测试出了问题。所以总结下来就是,服务的架构变的复杂之后测试和联调,排障都会造成很大的难度。

3. 微服务的不足

Fred Brooks 在30年前写道,“there are no silver bullets”。但凡事有利就有弊,微服务也不是万能的。

• 微服务应用是分布式系统,由此会带来固有的复杂性。开发者不得不使用 RPC 或者消息传递,来实现进程间通信;此外,必须要写代码来处理消息传递中速度过慢或者服务不可用等局部失效问题。

• 分区的数据库架构,同时更新多个业务主体的事务很普遍。这种事务对于单体式应用来说很容易,因为只有一个数据库。在微服务架构应用中,需要更新不同服务所使用的不同的数据库,从而对开发者提出了更高的要求和挑战。

• 测试一个基于微服务架构的应用也是很复杂的任务。

• 服务模块间的依赖,应用的升级有可能会波及多个服务模块的修改。

• 对运维基础设施的挑战比较大。

img

这是一张表示两个维度,一个是单体架构,一个微服务架构下,基建复杂度和生产力关系的图。从这张图得出的结论就是,没有绝对完美的架构设计,任何架构都存在弊端,架构师需要按照实际的业务场景去权衡。

4. 组件服务化

传统实现组件的方式是通过库(library),库是和应用一起运行在进程中,库的局部变化意味着整个应用的重新部署。 通过服务来实现组件,意味着将应用拆散为一系列的服务运行在不同的进程中,那么单一服务的局部变化只需重新部署对应的服务进程。我们用 Go 实施一个微服务:

img

img

这个JAVA的ESB出来之后,就把SOA给搞臭了,那些搞软件工程学术研究的就索性换了一个词就变成微服务。其实本质还是一样的。

• kit :一个微服务的基础库(框架) 。

• service :业务代码 + kit依赖+第三方依赖组成的业务微服务

• rpc + message queue:轻量级通讯

本质上等同于,多个微服务组合(compose)完成了一个完整的用户场景(usecase)。

5. 按业务组织服务

1. 烟囱式交付模型

img

这是一张传统的工作模式,从上到下,UI交给中间件团队再交给DBA再交给测试最后给运维,大家各干各的,完全是一个烟囱式的模型。烟囱式的结构描述的是一个职能范围。大家只干自己本职内的工作,其他的就不管了,滑稽的现象就是后端开发团队写完了代码之后直接把代码交给给运维部署,稀里糊涂把代码二进制bin run起来之后就说上线成功了。按照我的理解软件开发是一个系统性的工程,特别是针对一些大项目,大家都各司其职,按照这种烟囱式的组织架构去开发,一层一层的往下丢,到最后真的出现了问题都不知道是哪一步的问题。我推崇一个理念,就是You build it and you fix it.自己开发的代码就自己最清楚其中的逻辑,和烟囱式的组织结构不同的就是,后者是直接对业务场景负责,也就是直接对结果负责。开发人员比测试人员其实是更熟悉代码,测试人员不知道代码的结构,最多只能做一个黑盒测试,测试的case都需要自己去做维护。开发人员对服务负责,就意味着你需要对所有的一切都负责,对代码的测试,代码的bug,监控,部署等等。测试和运维要干的事情就是提供一系列的平台和工具,方便配合开发人员做代码的测试和运维,现在的devops不就是一个全新的工种嘛。😝

img

2. 康威定律

不知道大家有没有去了解过康威定律

Conway’s law 最初来自于Conway在1967年发表的论文
《How Do Committees Invent?》,之后在《人月神话》
这本书中引用了论文的结论,并命名为康威定律(Conway’s law)得以推广

Conway’s law: Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations. - Melvin Conway(1967)
设计系统的组织其产生的设计等价于组织间的沟通结构。

反向理解起来也是成立的。

Conway’s law reversed:You won’t be able to successfully establish an efficient organizational structure that is not supported by your system architecture design.
如果系统架构不支持,你无法建立一个高效的组织。

Mike Amundsen 归纳了如下四个核心观点:

  • 第一定律
Communication dictates the design
组织沟通方式会通过系统设计表达出来	

对于复杂的,需要协作完成的系统开发,沟通是必须要持续提升的问题。
每个团队由5-10人组成(沟通成本 = n(n-1)/2 - 《人月神话》),在团队内部进行频繁的、细粒度的沟通。对于团队外部,定义好接口,契约,只进行粗粒度的沟通。这样可以降低沟通成本,同时也符合高内聚,低耦合原则(代码和人员管理有些时候真是相通的)。

  • 第二定律
  There is never enough time to do something right, but there is always enough time to do it over
  时间再多一件事情也不可能做的完美,但总有时间做完一件事情

这就是我们在用kanban管理迭代时几乎都有一列是BAU(Business As Usual ),其中会包括一些日常修复的Bug Story。敏捷开发中将迭代引入,做到持续交付,快速验证,迅速反馈,持续改进。

  • 第三定律
    There is a homomorphism from the linear graph of a system to the linear graph of its design organization
    线型系统和线型组织架构间有潜在的异质同态特性
大白话就是,你想要架构成为什么样,就将团队分成怎样的结构。比如前后端分离的团队,架构就是基于前后端分离。在基于微服务设计的团队里,一个很好的理念是**自管理**。团队内部对于自己所负责的模块高度负责,进行端对端的开发以及运维。
  • 第四定律
      The structures of large systems tend to disintegrate during development, qualitatively more so than with small systems
      大的系统组织总是比小系统更倾向于分解
  合久必分,分久必合,团队以及架构都是在不断优化的。一个团队随着人员的增加,沟通以及管理成本一定会增加。

按业务能力组织服务的意思是服务提供的能力和业务功能对应,比如:订单服务和数据访问服务,前者反应了真实的订单相关业务,后者是一种技术抽象服务不反应真实的业务。所以按微服务架构理念来划分服务时,是不应该存在数据访问服务这样一个服务的。

3. 对康威定律的思考🤔

康威定律只是Conway本人基于软件开发的经验,对于架构以及团队管理普遍现象的总结。软件行业半个世纪的发展也验证了其正确性。理解了康威定律可以帮助开发人员从另一个角度理解架构设计。事实上传统应用设计架构的分层结构正反映了不同角色的沟通结构。所以若要按微服务的方式来构建应用,也需要对应调整团队的组织架构。每个服务背后的小团队的组织是跨功能的,包含实现业务所需的全面的技能。现实中的问题是,仅仅基于康威定律,还是不能评判某个架构是否是合格的?如何提升?什么时间进行提升?等一系列问题。这些就要靠不停的学习要研究啦,没有绝对完美的架构设计,只有不停的优化和调整来适合当前的场景。

4. 毛大的总结

下面是毛剑在讲B站的工作模式:

我们的模式:大前端(移动/Web) -> 网关接入 -> 业务服务 -> 平台服务 -> 基础设施(PaaS/Saas)

开发团队对软件在生产环境的运行负全部责任

第二点恰恰好契合了 You build it and you fix it的理念。

针对业务形成一个闭环的小组,前端团队和网关团队形成一个小闭环,网关团队和后面的后端API服务团队,后端团队提供API的文档,与后端团队沟通,重要的就是API文档,也就是所谓的契约精神。测试与运维团队提供高效的测试和运维发布平台,整个流程就会变得非常的高效。

6. 去中心化

每个服务面临的业务场景不同,可以针对性的选择合适的技术解决方案。但也需要避免过度多样化,结合团队实际情况来选择取舍,要是每个服务都用不同的语言的技术栈来实现,想想维护成本真够高的。

数据去中心化

每个服务独享自身的数据存储设施(缓存,数据库等),不像传统应用共享一个缓存和数据库,这样有利于服务的独立性,隔离相关干扰。与之前单存储的架构比起来,不会因为数据的问题而导致了服务不可用,也是间接了提供了服务整体的健壮性。

治理去中心化

微服务化之后某些服务一定会成为流量热点,有一个服务一定会被下流服务所依赖的服务,举个例子,Nginx就是,所有的请求必定先经过Nginx,有人会说扩容,扩容的收益比较低,不如直连来的爽快。

技术去中心化

不单单限于一门语言去干所有的事情,选择合适的语言做合适的事情。不过不需要太多,还是要收敛一点,语言太多不是一件好事情,后面对于公司而言维护的成本就很高。

7. 基础设施自动化

无自动化不微服务,自动化包括测试和部署。单一进程的传统应用被拆分为一系列的多进程服务后,意味着开发、调试、测试、监控和部署的复杂度都会相应增大,必须要有合适的自动化基础设施来支持微服务架构模式,否则开发、运维成本将大大增加。

img

CICDGitlab + Gitlab Hooks + k8s

Testing:测试环境、单元测试、API**自动化测试

在线运行时:k8s,以及一系列 PrometheusELKConrtol Panle

8. 可用性 & 兼容性设计

著名的 Design For Failure 思想,微服务架构采用粗粒度的进程间通信,引入了额外的复杂性和需要处理的新问题,如网络延迟、消息格式、负载均衡和容错,忽略其中任何一点都属于对“分布式计算的误解”。

隔离

超时控制

负载保护

限流

降级

重试

负载均衡

一旦采用了微服务架构模式,那么在服务需要变更时我们要特别小心,服务提供者的变更可能引发服务消费者的兼容性破坏,时刻谨记保持服务契约(接口)的兼容性。

*Be conservative in what you send, be liberal in what you accept.*
--伯斯塔尔法则

发送时要保守,接收时要开放。按照伯斯塔尔法则的思想来设计和实现服务时,发送的数据要更保守,意味着最小化的传送必要的信息,接收时更开放意味着要最大限度的容忍冗余数据,保证兼容性。

posted @ 2021-02-13 12:55  ttlv  阅读(308)  评论(0编辑  收藏  举报