微服务概念介绍

概述

微服务micro service是和单体应用相对应的一个概念。我们不妨先来回顾单体应用程序是怎样的一种行为。在微服务提出之前,世界上流行的应用程序大多都是单体应用程序。何为单体应用程序,个人认为其实这更多的是从服务端应用程序架构角度的一个概念。

单体应用程序意味着所有的代码都是在一个项目当中的,这些代码是统一打包部署发布出去的,在一个进程当中运行。

微服务,可以理解为将原来单体应用中的不同模块划分成不同的相对更小的应用程序。解耦合,模块化在此时发生。 

本质上就是一种分而治之的思想。从思想层面来说并没有任何全新的东西。当应用程序越来越复杂,可以说这是一条必经之路。即便是单体应用程序,在整个应用程序内部,不同的功能模块,也是放在不同的包当中的,相关的逻辑也是组织在一起的。

只是微服务将这些模块几乎完全的隔离开了,不仅这些代码分开了,他们的打包,部署,运维,测试甚至数据库都是隔离的。这些微服务之间的交互就通过彼此暴露的api进行。

什么是微服务

微服务也被称为微服务架构,是一种可将应用程序构造为一组服务的架构方式,这些服务的特点是:

  • 高度可维护和可测试
  • 松耦合
  • 可独立部署
  • 围绕业务模块进行组织
  • 由一个小团队拥有

微服务的优劣

微服务的优点和缺点和它的特点以及架构方式密不可分。微服务带来的好处非常多,主要包含:

  1. 从需求角度来说:每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求
  2. 从团队管理的角度来说:微服务能够被小团队单独开发。因此团队更好管理,可以采用敏捷开发的模式。
  3. 从部署和开发角度来说:微服务是松耦合的,无论是在开发阶段或部署阶段都是独立的。单个服务代码量不会很多,开发启动起来就会很快。维护成本也更低。此外由于工程量小,这也消除了对技术栈的长期承诺。 开发新服务时,可以选择新技术堆栈。 同样,当对现有服务进行重大更改时,您可以使用新技术堆栈将其重写。
  4. 从技术选择角度来说:微服务允许选用技术十分灵活,整个项目无需强制要求使用一样的技术栈。
  5. 从测试角度来说:由于代码相对较少,因此微服务可以进行较快的单元测试和api测试,这样利于实现CI持续集成和CD持续交付。

微服务架构模式具有许多重要的好处。首先,它解决了复杂性问题。它将原本是巨大的整体应用程序分解为一组服务。虽然功能总数不变,但该应用程序已分为可管理的块或服务。每个服务都有以RPC或消息驱动的API形式定义的边界。微服务架构模式强制执行一定程度的模块化,实际上,使用单一代码库很难实现。因此,单个服务的开发速度更快,并且更易于理解和维护。

其次,该体系结构使每个服务可以由专注于该服务的团队独立开发。开发人员可以自由选择任何有意义的技术,只要该服务遵守API合同即可。当然,大多数组织都希望避免完全无政府状态并限制技术选择。但是,这种自由意味着开发人员不再有义务使用新项目开始时已经存在的可能过时的技术。编写新服务时,他们可以选择使用当前技术。此外,由于服务相对较小,因此使用当前技术重写旧服务变得可行。

第三,微服务架构模式使每个微服务可以独立部署。开发人员无需协调其服务本地更改的部署。这些更改只要经过测试就可以部署。 UI团队可以例如执行A / B测试并快速迭代UI更改。微服务架构模式使连续部署成为可能。

最后,微服务架构模式使每个服务都可以独立扩展。您可以仅部署满足其容量和可用性约束的每个服务的实例数。此外,您可以使用最符合服务资源要求的硬件。例如,您可以在EC2 Compute Optimized实例上部署CPU密集型图像处理服务,并在EC2 Memory Optimized实例上部署内存数据库服务。

 

缺点则有:

  1. 部署维护要求比较高:单体应用就一个war包,微服务在一个系统中会有很多的服务,每个服务都对应一个包,维护起来就会复杂一些。在实际环境中,部署和管理由许多不同服务组成的系统也存在操作复杂性
  2. 技术复杂性提高:微服务就会带来一系列的问题,事务问题,Session一致性问题,锁问题,分布式复杂性等。同时虽然单个微服务的测试更加方便,但是应用程序整体的测试以及应用程序相互之间依赖的测试就更加难。contract约定测试在这方面可以提供帮助。此外,还有下面这些技术上的问题:
    • 开发人员必须实现服务间通信机制并处理部分故障
    • 实施跨多个服务的请求更加困难
    • 测试服务之间的交互更加困难
    • 实施跨多个服务的请求需要团队之间的仔细协调(更高的维护成本)
    • 开发人员工具/ IDE面向构建整体应用程序,不为开发分布式应用程序提供明确支持。
  3. 增加内存消耗。微服务架构用N x M服务实例替换了N个整体应用程序实例。如果每个服务都在其自己的JVM中运行(这通常是隔离实例所必需的),则JVM运行时的开销是M倍。此外,如果每个服务都在自己的VM上运行,就像Netflix一样,则开销会更高。

像其他所有技术一样,微服务架构也有缺点。缺点之一是名称本身。微服务一词过分强调服务规模。实际上,有些开发人员主张构建极细粒度的10-100 LOC服务。小型服务虽然更可取,但重要的是要记住,它们是达到目的的一种手段,而不是主要目标。微服务的目标是充分分解应用程序,以促进敏捷应用程序的开发和部署。

微服务的另一个主要缺点是由于微服务应用程序是分布式系统这一事实而导致的复杂性。开发人员需要选择并实现基于消息传递或RPC的进程间通信机制。此外,由于请求的目的地可能很慢或不可用,它们还必须编写代码来处理部分失败。尽管这都不是火箭科学,但是它比单片应用程序复杂得多,在单片应用程序中,模块通过语言级方法/过程调用相互调用。

微服务的另一个挑战是分区数据库体系结构。更新多个业务实体的业务交易相当普遍。由于只有一个数据库,因此在单一应用程序中实现这类事务很简单。但是,在基于微服务的应用程序中,您需要更新不同服务拥有的多个数据库。通常,不仅由于CAP定理,也不选择使用分布式事务。当今许多高度可扩展的NoSQL数据库和消息传递代理完全不支持它们。您最终不得不使用最终的基于一致性的方法,这对开发人员而言更具挑战性。

测试微服务应用程序也要复杂得多。例如,对于像Spring Boot这样的现代框架,编写一个测试类来启动一个整体Web应用程序并测试其REST API是很简单的。相反,针对服务的类似测试类将需要启动该服务及其依赖的任何服务(或至少为这些服务配置存根)。再一次,这不是火箭科学,但重要的是不要低估这样做的复杂性。

微服务架构模式的另一个主要挑战是实现跨多个服务的更改。例如,假设您正在实现一个需要更改服务A,B和C的案例,其中A依赖于B,B依赖于C。在单片应用程序中,您只需更改相应的模块,集成更改,一口气部署它们。相反,在微服务架构模式中,您需要仔细计划和协调对每个服务的更改的推出。例如,您需要先更新服务C,然后再更新服务B,最后再更新服务A。幸运的是,大多数更改通常只影响一项服务,而需要协调的多服务更改相对较少。

部署基于微服务的应用程序也要复杂得多。单一应用程序可以简单地部署在传统负载均衡器后面的一组相同服务器上。每个应用程序实例都配置有基础结构服务(例如数据库和消息代理)的位置(主机和端口)。相反,微服务应用程序通常包含大量服务。例如,根据Adrian Cockcroft [编辑– Hailo被MyTaxi收购],Hailo有160种不同的服务,而Netflix有600多种。每个服务将具有多个运行时实例。还有许多需要配置,部署,扩展和监视的活动部件。另外,您还需要实现服务发现机制(在后面的文章中讨论),该服务使服务能够发现其需要与之通信的任何其他服务的位置(主机和端口)。传统的基于故障单和手动操作的方法无法扩展到这种复杂程度。因此,成功部署微服务应用程序需要开发人员更好地控制部署方法以及高度自动化。

一种自动化方法是使用现成的PaaS,例如Cloud Foundry。 PaaS为开发人员提供了一种轻松的方法来部署和管理其微服务。它使他们免受诸如采购和配置IT资源之类的问题的困扰。同时,配置PaaS的系统和网络专业人员可以确保遵守最佳做法和公司政策。自动化微服务部署的另一种方法是开发本质上属于您自己的PaaS。一个典型的起点是将群集解决方案(例如Kubernetes)与Docker等技术结合使用。

 

在微服务概念被提出之前,人们习惯于开发单体应用程序。因此为与微服务进行对比,我们不妨来试着构建一个单体应用程序。下面我们通过Nginx官网的介绍来看一下microservice和单体应用程序

构建单体应用程序Monolithic Application

假设我们要构建一个全新的出租车叫车应用程序,旨在与Uber和Hailo竞争。 在进行一些初步的会议和需求收集之后,我们可以手动创建一个新项目,也可以使用Rails,Spring Boot,Play或Maven附带的生成器来创建一个新项目。 此新应用程序将具有模块化的六角形体系结构,如下图所示:

Modular, but still monolithic, architecture used as basis for sample microservices application

应用程序的核心是业务逻辑,该业务逻辑由service,domain object和event等模块实现。围绕中间核心的是与外部世界接口的适配器adapters。适配器的示例包括数据库访问组件,生成和使用消息的消息传递组件以及公开API或实现UI的Web组件。

尽管具有逻辑模块化的体系结构,但该应用程序却作为一个整体打包和部署。实际的打包格式取决于应用程序的语言和框架。例如,许多Java应用程序打包为WAR文件,并部署在诸如Tomcat或Jetty之类的应用程序服务器上。其他也有一些Java应用程序打包为独立的可执行JAR。同样,Rails和Node.js应用程序打包为目录层次结构。

用这种风格编写的应用程序非常普遍。由于我们的IDE和其他工具专注于构建单个应用程序,因此它们易于开发。这些类型的应用程序也易于测试。您可以通过简单地启动应用程序并使用Selenium测试UI来实施端到端测试。整体应用程序也易于部署。只需要将打包的应用程序复制到服务器即可。您还可以通过在负载平衡器后面运行多个副本来扩展应用程序。在项目的早期阶段,它运作良好。

单体应用程序的地狱

但是,这种简单的方法有很大的局限性。会取得成功的应用程序具有随着时间的流逝变得越来越庞大的趋势。在每次需要完成一些业绩的时期,开发团队都会开发更多的功能,这就意味着要添加许多行代码。几年后,您的小型,简单应用程序将成长为巨大的整体。举一个极端的例子,我最近采访了一位开发人员,他正在编写一种工具来分析其数百万行代码(LOC)应用程序中数千个JAR之间的依赖关系。我敢肯定,经过多年的开发,众多的开发人员共同努力创造了这种mosnster一样的应用程序。(以博主的亲身经历来看,博主曾在公司做过一个项目历史长达15年以上,代码多达400万行以上的单体应用程序,当客户变多的时候会出现许多问题)

一旦您的应用程序变成了一个庞大,复杂的整体,您的开发组织就可能陷入困境。进行敏捷开发和交付的任何尝试都会失败。一个主要问题是应用程序极其复杂。对于任何一个开发人员来说,它太大了,根本无法完全理解。结果,修复错误和正确实现新功能变得困难且耗时。而且,这往往是螺旋式下降。如果代码库难以理解,则将无法正确进行更改。最后,您将得到一个巨大的,难以理解的大泥球。

应用程序的绝对大小也会减慢开发速度。应用程序越大,启动时间越长(同样深有体会)。例如,在最近的一项调查中,一些开发人员报告启动时间长达12分钟。我还听说了一些需要花费40分钟才能启动的应用程序的轶事。如果开发人员必须定期重新启动应用程序服务器,那么他们一整天的时间都将花在等待周围,从而降低他们的生产力。

大型,复杂的整体应用程序的另一个问题是,会带来持续部署(CD)的障碍。如今,SaaS应用程序的最新技术是每天将变更推送到生产中多次。对于复杂的整体而言,这极其困难,因为您必须重新部署整个应用程序才能更新其中的任何一部分。我前面提到的漫长的启动时间也无济于事。另外,由于通常不会很好地了解更改的影响,因此您可能必须进行大量的手动测试。因此,几乎不可能进行连续部署。

当不同的模块具有冲突的资源需求时,单体应用程序也可能难以扩展。例如,一个模块可能实现CPU密集型图像处理逻辑,并且理想情况下将部署在Amazon EC2 Compute Optimized实例中。另一个模块可能是内存数据库,最适合EC2内存优化的实例。但是,由于这些模块是一起部署的,因此您必须在硬件选择上进行折中。

整体应用的另一个问题是可靠性。由于所有模块都在同一个进程中运行,因此任何模块中的错误(例如内存泄漏)都可能导致整个进程中断。而且,由于该应用程序的所有实例都是相同的,因此该错误将影响整个应用程序的可用性。

最后但并非最不重要的一点是,单片应用程序使采用新框架和语言变得极为困难。例如,假设您有200万行使用XYZ框架编写的代码。重写整个应用程序以使用较新的ABC框架将非常昂贵(无论是时间还是成本),即使该框架要好得多。结果,采用新技术存在巨大的障碍。在项目开始时,您会遇到各种技术选择,而您会陷入困境。

总结一下:您有一个成功的业务关键型应用程序,已经成长为开发人员无法理解的庞然大物。它是使用过时的,非生产性的技术编写的,这使得雇用有才能的开发人员很困难。该应用程序难以扩展且不可靠。结果就是,不可能进行敏捷的开发和交付。

微服务–解决复杂性

许多组织,例如Amazon,eBay和Netflix,都采用了现在称为微服务架构的模式来解决此问题。 与其构建一个单一的,单体应用程序,不如将应用程序拆分为一组较小的,相互连接的服务。

服务通常实现一组不同的特征或功能,例如订单管理,客户管理等。每个微服务都是一个微型应用程序,具有自己的六边形体系结构,该体系结构由业务逻辑和各种adapter组成。 某些微服务会暴露其他微服务或应用程序客户端需要使用的API。 其他微服务可能实现Web UI。 在运行时,每个实例通常是云VM或Docker容器。

例如,下图显示了先前描述的叫车系统的可能分解。

现在,应用程序的每个功能区域都由其自己的微服务实现。此外,该Web应用程序被分为一组简单的Web应用程序(例如,在我们的出租车叫车示例中,一个用于乘客,一个用于驾驶员)。这使得为​​特定用户,设备或特殊用例部署不同的体验变得更加容易。

每个后端服务公开一套REST API,大多数服务使用其他服务提供的API。例如,驾驶员管理使用通知服务器来通知可用的驾驶员潜在的行程。 UI服务调用其他服务以呈现网页。服务还可以使用基于消息机制的异步通信。

某些REST API也公开给驾驶员和乘客使用的移动应用程序。但是,这些应用无法直接访问后端服务。相反,通信是通过称为API网关API gateway的中介进行的。 API gateway负责负载平衡,缓存,访问控制,API计量和monitor等任务,并且可以使用NGINX有效地实现。

 

在运行时,行程管理服务由多个服务实例组成。每个服务实例都是一个Docker容器。为了实现高度可用,这些容器在多个Cloud VM上运行。服务实例的前面是一个负载均衡器,例如NGINX,它在实例之间分配请求。负载平衡器还可能处理其他问题,例如缓存,访问控制,API计量和监视。

微服务架构模式极大地影响了应用程序与数据库之间的关系。每个服务都具有自己的数据库架构,而不是与其他服务共享单个数据库架构。一方面,这种方法与企业范围的数据模型的思想相矛盾。而且,它通常会导致某些数据重复。但是,如果您想从微服务中受益,则每个服务都具有数据库架构是必不可少的,因为这样可以确保松散耦合。下图显示了示例应用程序的数据库体系结构。

Database architecture in sample microservices application for ride service

每个服务都有其自己的数据库。此外,服务可以使用最适合其需求的一种数据库,即多语言持久性体系结构。例如,“驾驶员管理”(该驾驶员发现与潜在乘客接近的驾驶员)必须使用支持有效地理位置查询的数据库。

从表面上看,微服务架构模式类似于SOA。使用这两种方法,体系结构都由一组服务组成。但是,考虑微服务架构模式的一种方法是,它无需商业化和可察觉的Web服务规范(WS‑ *)和企业服务总线(ESB)的SOA。基于微服务的应用程序倾向于使用诸如REST之类的更简单,轻便的协议,而不是WS- *。他们还非常避免使用ESB,而是在微服务本身中实现类似于ESB的功能。微服务架构模式还拒绝了SOA的其他部分,例如规范架构的概念。

 

怎么解决微服务的问题?

对于devops的问题:

这要求相关人员必须具备devops的能力。所谓devops,就是打包,部署,运行,监控我们的微服务等工作。为什么微服务需要强调这些问题,因为相对於单体应用只需要打包部署单个包而言,对于每个拆分后的微服务进行编译、打包、部署必将是原来工作量的数倍,如果不采用自动化工具,这些工作将会消耗大量的时间和精力也做不好,从这个角度来说,使用自动化工具是必须的。

并且由于多个微服务采用框架各异,那么微服务部署所依赖的基础环境,必将异常复杂繁琐。

可以说DevOps是微服务实施的充分必要条件

对于事务一致性问题,首先必须提出的一点是:你的需求里到底需不需要事务一致性?如果没有,这个问题就不需要考虑。如果有,这个问题才存在。

微服务中的事务一致性问题可能会面临下面这些调整:

首先,对于微服务架构来说,数据访问更加复杂,数据库是微服务私有的,唯一可访问的方式就是通过该微服务的API。这种数据访问方式的好处是使得微服务之间松耦合,并且彼此之间独立非常容易进行性能扩展。

其次,不同的微服务经常使用不同的数据库。应用会产生各种不同类型的数据,关系型数据库并不一定是最佳选择。例如,某个产生和查询字符串的应用采用Elasticsearch的字符搜索引擎;某个产生社交图片数据的应用可以采用图数据库,例如,Neo4j;基于微服务的应用一般都使用SQL和NoSQL结合的模式。但是这些非关系型数据大多数并不支持事务。可见在微服务架构中已经不能选择分布式事务了。

依据CAP理论,必须在可用性(availability)和一致性(consistency)之间做出选择。如果选择提供一致性需要付出在满足一致性之前阻塞其他并发访问的代价。这可能持续一个不确定的时间,尤其是在系统已经表现出高延迟时或者网络故障导致失去连接时。

依据目前的成功经验,可用性一般是更好的选择,但是在服务和数据库之间维护数据一致性是非常根本的需求,因此微服务架构中应选择满足最终一致性。

目前使用比较多的方案是
结合MQ消息中间件实现的可靠消息最终一致性。可靠消息最终一致性,需要业务系统结合MQ消息中间件实现,在实现过程中需要保证消息的成功发送及成功消费。即需要通过业务系统控制MQ的消息状态。

关于微服务的事务问题,更详细的内容暂时可以参考这篇博客:微服务架构下的事务一致性保证

总结

构建复杂的应用程序本质上是一件困难的事情。 单体架构仅对简单,轻量级的应用有意义。 如果将其用于复杂的应用程序,将陷入痛苦的世界。 尽管存在缺点和实现挑战,但微服务架构模式是复杂,不断发展的应用程序的更好选择。

总的来说,对于任何一种技术而言都不是绝对盲目推崇的,适合的才最好,微服务自然有很多好处,但是在实际的项目中依然需要结合实际需求和情况进行实践。但是总的来说,软件项目的趋势是在朝这个方向前进的。越来越多的公司和项目都在采用这种架构模式了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章