返回 登录
0

如何完美使用微服务

阅读2602

通常来说,下面我要讲的大部分应用微服务的方法都适用于SOA架构。但是,微服务架构中使用这些方法的效果会更好,好处也更多。下面我会简单介绍一些使用微服务的方法,之后我们会在谈到其应用时再做具体说明。

容器

同时处理很多项微服务可能会十分复杂,因为每个微服务的编程语言可能不一样,可能需要不同的应用服务器(最好是轻量级的服务器),也可能使用不同的库。但如果我们将每个服务都当做容器来包装,那么这些问题都会迎刃而解。我们只需要运行容器(例如用Docker运行容器),其他需要的东西统统都在容器内部了。

容器本身是自给自足的,其内部包含我们需要的所有东西(除了内核kernel),此外各个容器单独运行并不可改变。而自给自足则意味着容器通常具有以下几个部分。

运行时间库(运行应用时所需的JDK、Python或其他库)

应用服务器(Tomcat、nginx等)

数据库(最好是轻量级的)

工件(JAR、WAR、静态文件等)

图片描述

容器内部自给自足的微服务

部署服务最简单的方式就是通过完全自给自足的容器实现,但这又会带来一些扩展方面的问题。如果我们想在集群中的多个节点对某个容器进行扩展,那么我们就需要保证嵌入在这些容器中的数据库信息是同步的,或者它们的数据卷(data volume)位于同一个共享驱动器(shared drive)上。同步信息一般会带来额外的复杂性,而共享数据卷可能会影响系统的性能。

另外一种方法就是将数据库放在一个独立的容器中,尽可能实现自给自足。此时,每一个服务就会有两个容器,一个负责应用,另一个负责数据库。两个容器互相连接(最好是通过代理服务连接)。虽然这种方法略微增加了部署的复杂性,但其使得拓展变得十分自由。根据性能测试的结果或者访问请求(traffic)的增加量,我们可以部署多个应用容器的实例或者数据库实例。当出现拓展需求时,不论是应用还是数据,我们都完全可以顺利进行扩展。

图片描述

此外,由于容器的自给自足和不可变性,我们在不同的环境中使用容器(开发、测试、生产等),结果都会保持一致。容器的特性和微服务创建小型应用得方法相结合,我们就可以轻而易举的部署并扩展容器,同时也极大的降低了风险,而这些都是其他方法做不到的。

在处理保留系统时,人们通常还会采用第三种组合方法。即使我们决定从巨石应用逐渐转变为微服务,数据库也往往在最后进行重构,这种转换方法肯定不是最佳的。对大型企业来说,数据是最有价值的资产。如果只是重新编写程序还好,但如果决定了要重构数据,那么相应的风险就会很高,所以管理层往往对这种提议持保留态度。此时,我们可能就会选择共享数据库(可能没有容器),但这种选择一定程度上与我们使用微服务的初衷相矛盾。

最好的方法就是在共享数据库时确保每一种模式或每一组图表只能被一个服务所使用。其他服务如果也需要相同的数据,那么就需要通过该服务分配的API接口来实现。这种方法中,我们并没有实现明显的分离(毕竟物理隔离才是最明显的隔离方式),至少我们应该控制访问数据子集的服务,同时明确这些服务以及数据的关联。事实上,这种想法和水平层次的想法很类似。

但在实践时,随着巨石应用的体量不断变大(层次数量不断增加),人们往往会忽视这种方法。垂直分离(即使是共享数据库)能够帮助我们实现很清晰的有界上下文,确保每个服务各司其职。

图片描述

每个容器都是完全自给自足的,但其使用的数据子集来源于同一个共享数据库。每一个数据子集只能由特定的某个容器使用。

代理微服务或API网关

大型企业的前端可能需要调用数十个甚至数百个HTTP请求(例如亚马逊公司)。调用请求的时间往往比收到响应数据的时间还长,此时代理微服务可能就派上用场了。代理微服务的目的是调用不同的微服务,并最终返回一个聚合数据(aggregated data)。代理微服务不包含任何逻辑,只会把不同的响应数据聚合在一起,并向用户返回一个最终的整合数据结果。

反向代理

微服务的API接口绝对不能直接暴露。如果没有相应的编排,用户和微服务之间的依赖就会很大,而这可能会使微服务本应带来的优势荡然无存。轻量级的服务器可以完美的实现反向代理任务,只需极小的花费就能够方便的进行使用,例如nginx、Apache Tomcat和HAProxy等。

最小化方法(minimalist approach)

微服务应当只包含其真正需要的东西,例如程序包(package)、库和框架等。与巨石应用的方法截然不同,微服务的体量越小越好。以前我们可能会使用类似JBoss这样的JEE服务器,JBoss中包含了所有的工具,但我们能用到的可能只有一部分而已。对微服务来说,其体量越小,使用时的效果会越好。如果我们拥有数百个微服务,但每个微服务都有一整套JBoss服务器,那么就完全违背了微服务的使用原则。相比之下,Apahce Tomcat是更好的选择。我个人则倾向使用更小的方法,例如用Spray作为一个轻量级的RESTful API服务器。总之,去粗取精,拿掉多余的东西,只留下你需要的。

最小化的策略同样也适用于操作系统方面(OS)。如果我们正在用Docker容器部署微服务,那么CoreOS可能要比Red Hat和Ubuntu系统更合适。去掉多余的东西能够让我们更好的利用各种资源。但是,选择OS其实没有那么简单,我们之后会谈到。

配置管理

随着微服务数量的不断增加,对配置管理(CM)的需求越来越多。如果没有Puppet、Chef或者Ansible这样的工具,部署微服务可能会成为一场噩梦。事实上,不论是不是微服务,不论简化部署的方法有多简单,我们都需要使用CM工具。

跨功能研发小组

虽然没有规则说明,但研发团队最好是在开发具有多功能特性的应用时采用微服务方法。从设计之初到最终的部署和维护,应当有一个小组负责整个过程。由于微服务体量很小,因此不可能让各个小组分别负责某个微服务研发的每个阶段(例如架构/设计、开发、测试、部署和维护小组)。所以我们应当让一个小组负责某个微服务的整个生命周期。很多时候,一个小组可能负责多项微服务,但多个小组不应该负责同一个微服务。

API版本控制(versioning)

版本控制应当适用于任何API,对微服务也一样。如果有某些改动打破了API的格式,那么就应当针对该改动单独发布另外一个版本。不论是公共接口还是其他内部服务使用的接口,我们不清楚谁在使用这些接口,因此必须要保证向下兼容,或者至少要给用户足够的时间去适应。

结语

微服务的概念很早就出现了,我们来看下面这个例子:

1 ps aux | grep jav[a] | awk ‘{print $2}’ | xargs kill

上面是Unix/Linux中使用的一行命令(pipes)。它包含了四个程序,每个程序都会产生一个输入(stdin)和/或一个输出(stdout)。每个程序的目标都很明确,实现的功能也是唯一或者很少的。虽然每个程序本身很简单,但当它们合起来成为一行命令时,这行命令就可以完成十分复杂的操作。今天,大部分的Unix/Linux程序中都使用类似的方法。

在上述的例子中,我们运行ps aux来检索所有正在运行的进程,并将结果传递命令中的下一个程序,也就是grep jav[a]。grep jav[a]将范围缩小到Java进程,然后再将此结果传递到下一个程序,即awk ‘{print $2}’。而这一程序做的事情就更多了,它能对上一步的结果进行过滤并筛选出进程ID中的第二列数据(the second column that happens tobe the process ID)。最后xargs kill接收到来自awk的结果,并杀死已经筛选出来符合ID条件的进程。

那些不了解Unix/Linux的人可能认为上述事例中的命令在执行时会出现错误(杀错进程)。但真正使用Linux命令的人会发现,这种方法十分灵活且高效。“大”程序需要考虑到每一个可能的用例,而我们所使用的小程序则不然,这些数量巨大的小程序可以根据任务不同按照我们的需要进行任意组合。这是一种至简之道。每个程序都很小,而且都可以完成一个非常具体的目标。最重要的是,这些小程序都会接收到定义明确的输入,同时生成完整的输出结果。

据我所知,Unix是目前还在使用中的最古老的一种微服务,他拥有很多小型、具体,且易于理解的服务,这些服务的接口定义非常规范。

虽然微服务的概念很早就出现了,但直到最近它才开始逐渐流行。因为微服务需要其他一些东西的帮助才能完全发挥作用,而这些东西都在不断完善和成熟的过程中。微服务的流行得益于一些概念的产生,包括领域驱动设计(DDD)、持续交付、容器、小型自主团队、可扩展系统等等。只有当这些东西聚合到一个框架中时,微服务的作用才能真正体现出来。

微服务被用来创建一些复杂的系统,这些系统由小型且自治的服务构成,而这些服务通过各自的API接口进行数据交换,同时有相应的有界上下文明确它们的范围。一定程度来说,微服务就是面向对象编程方法所期待的东西。当你听到软件行业领袖谈到某些想法,尤其是涉及到面向对象的编程,以及如何实现这些想法时,他们所描述的东西就是今天微服务的样子。下面就是我引述的其中描述微服务的一些言论:

最重要的是“消息传递”。在创建大型的可扩展的系统时,关键的是如何设计各个模块之间的信息交换,而不是系统内部属性和行为是什么。
–Alan Kay

把同类的东西聚集起来,把不同的东西分离开来。
–Robert C.Martin

在使用微服务的时候,我们都倾向于让它们做一件事情或者仅实现一个功能。这样就能为不同的任务选择各自最佳的工具。例如,我们可以用最适合某个需求的编程语言开发某个微服务。只要提前明确定义了各个小组的API接口,再加上各微服务之间存在物理隔离,那么微服务就真正实现了松耦合,也具有了很高的独立性。此外,微服务的分散化特性使得我们的测试和持续交付或持续部署的速度大大加快。

当微服务再与新兴的软件工具相结合,尤其像Docker这样的工具结合时,我们就能看到微服务真正的闪光点,各种问题都会迎刃而解,微服务的开发和部署工作也会变得更加简单。

再次声明,本书所提到的东西只是一些建议,并不一定适用于所有案例。没有哪一种技术能够解决所有的问题,微服务也不例外。所以我们并不是说所有应用都应该采用微服务的方式,而是试图通过微服务解决一些十分具体的问题。

普元云计算专区:http://primeton.csdn.net/m/zone/primeton/index#

普元公众号:

图片描述

评论