09 Microservices Guide
最后更新于
最后更新于
微服务的架构出现已经很久很久了,微服务架构就是一种将单个应用程序转换为一组小服务的方法,每个小服务都在自己的进程中运行,并使用轻量级的交互方式(如HTTP)进行通信。
服务的划分是根据具体的业务来的,并且可以通过完全自动化的部署机制独立部署。虽然大家都在谈论微服务,但是什么时候应该使用微服务,使用微服务需要注意哪些问题对于很多人来说仍然是一个模糊的概念。本文将会和大家一起探讨一下微服务相关的一些问题。
在最开始的程序体系中,通常都是单体服务。对于单体服务来说,所有的服务都在一个进程中。企业应用程序通常由三个主要部分构建: 客户端用户界面(由 HTML 页面和在用户机器上的浏览器中运行的 javascript 组成),数据库(由插入到公共的、通常是关系的数据库管理中的许多表组成系统)和服务器端应用程序。
服务器端应用程序将处理 HTTP 请求、执行域逻辑、从数据库检索和更新数据,以及选择和填充要发送到浏览器的 HTML 视图。这个服务器端应用程序是一个整体,也就是一个单独的进程。对系统的任何更改都需要重新构建和部署服务器端应用程序的最新版本。
对于单体服务来说,所有的处理请求逻辑都在单个进程中运行,为了结构化和代码编写规范,通常会使用编程语言的基本功能将应用程序划分为类、函数和命名空间等。
虽然单体服务也可以通过负载均衡器后面运行多个实例来水平扩展应用,但是随着服务器端业务越来越复杂,对于服务的每一次很小的变动都会导致对于整体服务的重新构建和部署。并且随着时间的推移,通常很难保持良好的模块化结构,和对现有架构进行扩展。同时因为单体服务在一个进程中运行,如果该进程出现运行时问题,会导致所有的服务不可用,稳定性不够。
俗话说得好,鸡蛋不能放在一个篮子里面。
于是把巨大的单体服务拆分成为一个个的微服务就是现在系统架构的热潮。
微服务架构就是将单体的应用程序拆分为一个个的服务,这些服务可以独立部署和扩展,并且服务之间有牢固的模块边界,服务之间主要通过HTTP协议进行交互。因为服务之间是无内部耦合的,所以我们可以甚至使用不同的编程语言来实现不同的服务。提高了程序的灵活性。
微服务有些什么特征呢?什么样的服务才能被称为是微服务呢?
社会很复杂,单纯的是人。实际工程上的问题,不会向书本上学到的知识那样,有一个明确定义。事实上,出了学校之后,这个世界上的事情已经不是非黑即白了。
比如,我们上学时候学到的圆的定义,它清晰的告诉我们,什么是圆。而对于微服务来说,则并没有这样的定义。
因为微服务是在不断的实践中总结摸索出来的一种架构。虽然不同的人对微服务有不同的理解,但是他们应该都具有下面几个共同的特征。
自从软件变得复杂之后,为了更好的进行软件开发和后续的扩展,软件逐渐开始组件化。所谓组件就是一个个的可以独立替换和升级的部件。
现代程序中有很多可以称之为组件的东西,比如java中的依赖jar包,python中的依赖包等。
这些lib可以在运行时链接到程序中,以内存中的函数进行运行。
有了链接的lib,为什么我们还需要将这些组件服务化,以单独的进程来运行呢?
使用服务作为组件(而不是库)的一个主要原因是服务是可独立部署的。如果您的应用程序 由单个进程中的多个库组成,则对任何单个组件的更改都会导致必须重新部署整个应用程序。
但是,如果该应用程序分解为多个服务,那么对于该服务的变更,只需要重新部署该服务即可。虽然这不是绝对的,因为有些服务的变化会导致对应的调用接口的变化,所以也需要对应的服务来进行修改和适配。但是一个好的微服务架构的目标是通过服务契约中的内聚服务边界和演化机制来最小化这些变动。
使用服务作为组件的另一个好处是更明确的组件接口。大多数语言没有定义显式发布接口的良好机制,从而导致组件之间的耦合过于紧密。通过使用显式远程调用机制,服务可以更容易的进行定义。
使用服务也有他的缺点,因为服务之间是通过远程调用的,远程调用比进程内调用更昂贵,所以服务之间的调用通常是更加粗粒度的调用,所以我们在界定服务的时候,需要划分明确的职责分配。
根据康威定律:组织沟通方式决定系统设计。
通常来说,对于大型的系统可以分为UI团队,服务逻辑团队和数据库团队。但是这样的组织方式就会导致一个团队的改动需要其他团队也进行改动来配合。
所以在微服务中,组织应该是安装具体的业务来划分,这样能够保证组织的灵活性。
对于单体服务而言,依赖的lib是通过内部函数的调用来实现的,它的好处就是速度快,但是如果将单体服务转换成微服务,就需要考虑到服务之间的相互调用问题。
常见的服务之间的调用方式有哪些呢?
最常见的就是HTTP/HTTPS协议之间的调用,这种方式的好处就是协议简单通用,兼容性的成本较低。
如果是跨语言的,通常会用Thrift之类的RPC远程调用协议,这种方式的好处就是会比HTTP调用要快,但是调用起来比较复杂。需要构建特定的客户端。
上面讲的是同步调用,如果是异步的话,还可以使用MQ机制,MQ的作用一是可以削峰,二是可以解耦。
对于微服务来说,并不要求所有的微服务都采用同一种语言,同一种架构方式来进行。通常来说了保证系统和代码的可维护性,一般来说是要求所有的服务都使用同样的编程语言和架构。
但是对于特别的部分,比如对性能要求特别高这样的需求,那么可以尝试考虑一个不同的编程语言。
总的来说,就是每个微服务的团队对他们自己的服务负责,只需要保证对外的服务和接口的正确性即可。
对于单体应用来说, 所有的数据都放在一个数据库中。如果对微服务进行了去中心化管理,那么相应的数据库属于各个微服务组,所以在理论上微服务的数据也应该是去中心化部署的。
但是这样多个数据库照成的后果就是各个数据库中数据的一致性。在单体应用中,这个问题可以通过数据库事务来解决。但是对于微服务来说,分布式事务是不可行的,或者说代价太大。一般来说对于微服务来说,我们需要保证数据的最终一致性。
通过补偿机制来进行数据的校验和修复。
自动化部署的目标就是持续交付,对于微服务来说,多个服务的自动化是必不可少的。通过自动化编译,自动化测试,自动化集成和自动化部署,可以大大的减轻开发团队和运维团队的任务。提升开发效率。
使用服务作为组件的结果是,应用程序需要设计成可以容忍服务失败。 任何服务调用都可能因网络或者其他的原因导致不可用而失败,所以必须尽可能优雅地对此做出响应。
于单体服务相比,这需要引入额外的复杂性来处理它,所以可以看做是微服务的一个缺点。开发团队需要尽量多做异常测试,以保证在极端的环境中程序的正确性。
由于服务随时可能出现故障,因此能够快速检测故障并在可能的情况下自动恢复服务非常重要。微服务应用程序非常重视应用程序的实时监控,检查架构元素(数据库每秒收到多少请求)和业务相关指标(例如每分钟收到多少订单)。语义监控可以提供错误的早期预警系统,让开发团队跟进和调查。 监控对于快速发现不良的紧急行为并加以修复至关重要。
我们希望看到针对每个单独服务的复杂监控和日志记录设置,例如显示启动/关闭状态的仪表板以及各种运营和业务相关指标,还包括有关断路器状态、当前吞吐量和延迟的详细信息等。
讲了这么多微服务的特征,微服务虽然有他的灵活性的优点,但是如何划分微服务的边界,和对微服务的监控是一个很复杂的问题,所以到底要不要使用微服务还留给读者自己思考。
最后,问大家一个问题,在现实的项目中,有很多人希望把现有的单体服务拆分成为微服务,但是各个微服务还是共享着同一个数据库,也就是说这些微服务之间还存在着数据交叉。那么这种微服务算不算是真正的微服务呢?