微服务 to 变 or not to 变?

巨兽型可变服务器

本文讲的是微服务 to 变 or not to 变?,今天,在创建和部署应用的时候,最常用的方式就是可变服务器。我们会创建一个web服务器,该服务器上具有完整的应用,每次有新的版本发布时我们就会对服务器进行更新。服务器中具体的改动包括配置改动(属性文件、XML文件、数据库表等)、代码工件(JAR、WAR、DLL、静态文件等)、数据库模式和数据。因为每当有新版本时我们就会对服务器进行相应的改动,因此这种服务器叫做可变服务器。
对于可变服务器来说,我们不清楚开发、测试和生产环境是否相同,甚至是生产中的不同节点也可能会产生不利的差异问题。代码、配置文件或静态文件在某些实例中是否全部完成升级更新也未可知。

可变服务器是一种巨兽服务器,它包含了我们需要的所有东西,构成了一个简单的实例,后端、前端、API接口等等都包括在内。此外,这种服务器会不断成长。一段时间后可能没有人知道生产中某一部分的配置详情,而要想准确复制(新生产节点、测试环境等等)就只能复制整个虚拟机,然后开始进行配置(IP、主机文件、数据库连接等)。我们不断的在服务器中添加新东西,渐渐地就会失去对服务器的把控。过一段时间,当初设计完美惊艳的架构就会面目全非。

新添加的层次、新耦合的代码、还有源源不断的修补程序(补丁),最终你会迷失在迷宫一样的代码中。一开始还很美丽的小项目变成了一头丑陋的巨兽。你满怀希望的项目,到最后也成为了大家茶余饭后的笑话。对于这样的项目,人们可能会说最好的处理方式就是扔到一旁重新来过。但事已至此,巨兽一旦形成就难以重新开始了,已经投入了太多资源,重新开始将会耗费大量时间,而且会产生很多风险。所以巨石架构可能还会持续相当长的一段时间。

可变部署看起来简单,实则不然。它将所有东西都耦合在一起,试图把复杂性隐藏,但这也使各个实例之间更容易产生差异。
发布新版本应用时,何时重启这样的服务器很关键。因为在重启时,服务器通常都是不工作的,而这不仅会造成经济上的损失,还会丧失客户的信任。在今天的商业世界里,我们应当提供全天候运行的服务。此外,新版本发布时通常也意味着研发小组需要在夜间加班工作。面对这样的情况,持续部署看起来遥若星辰,可望而不可及。
测试同样也存在问题。不论我们在研发和测试环境中进行了多少次测试,只有我们将软件部署在生产环境中,让测试员和用户都能够使用,才开始真正意义上的第一次生产测试。
另外,这种服务器几乎无法实现快速回滚。因为服务器的可变性,所以不存在之前版本的“快照”。除非我们为整个虚拟机创建一个快照,但这又会产生很多新问题。
如果采用可变服务器,那么我们之前所描述到的需求是不可能全部满足的。由于服务器无法实现零宕机和快速回滚,我们也无法对其进行持续(频繁)部署。可变服务器的特性也决定了我们不可能实现全自动化(有风险),这样就延缓了我们的研发速度。
如果不能经常部署,那么我们只能不断的积累各种改变,而这些最终都会在发布的时候才暴露问题,很容易就会导致研发的失败。
为了解决这些问题,我们应该采用不可变部署方式,同时部署中应当包括小型、独立且自给自足性的应用。我们的目标很明确,零宕机时间、回滚能力、自动化以及快速功能。此外,我们还应当在用户接触软件前就在生产环境中对发布版本进行测试。

不可变服务器和反向代理

每一种“传统”的部署方式中,对系统的改动都会呈现在服务器上,从而增加了风险。而如果我们采用不可变部署方式,那么就可以立竿见影,获得成效。由于我们不需要考虑应用(应用是不可变的),因此环境的准备工作将变得极为简单。当我们在生产服务器上部署一个新的镜像文件或容器时,我们很清楚该文件或容器就是我们一直在开发和测试的东西。

不可变部署减少了未知的风险,我们知道每一个部署的实例和其他实例都是相同的。与可变部署不同,当程序包不可变而且包含了所有东西(应用服务器、配置文件和工件)的时候,我们就可以高枕无忧了。这些东西打包作为整体在部署流程中进行处理,我们只需要确保这些不可变的程序包顺利到达终端服务器就好。不可变部署消除了可变部署带来的不一致性,我们在其他环境中进行测试的程序包和最终到达服务器的程序包是完全相同的。

反向代理可用来实现零宕机。不可变服务器和反向代理可以通过下面这种简单的方式结合使用。

首先我们启动一个反向代理,指向已经完成的完全自给自足的不可变应用程序包。这个程序包可以是虚拟机,也可以是容器。这个不可变的镜像显而易见有别于可变应用。此外,还会有一个代理服务,服务器并不会直接暴露,代理服务会将所有访问(traffic)发送(route)到最终的目标位置。

一旦我们决定要部署一个新版本时,我们就会通过在另外一个独立的服务器上部署单独的镜像来完成。当然,有时候我们可以将这个镜像部署在相同的服务器上,但更多时候,由于巨石应用消耗大量资源,在不影响性能的前提下我们很难在同一节点进行多次部署。
此时,我们就会有两个实例(两台服务器)。一个是老版本,一个是新版本。所有的访问均通过代理服务由老的服务器处理,这样用户就不会察觉到任何改变。因为对于用户来说,我们仍旧在运行之前的服务器和软件。此时我们就可以放心的去做新软件应用的最后测试了,最好这些测试都是自动化的,而且属于部署过程的一部分,但仍需人工检测。
例如,如果我们在前端做了修改,那么就需要在最后做一次用户体验测试。不论我们进测试类型是什么,都需要绕过代理服务针对新发布软件进行测试。做这些测试的时候,我们很清楚自己在测试的软件将来会发布并应用于硬件上,而且我们是在没有影响用户体验(用户此时在使用旧版本软件)的情况下进行的测试。甚至我们可以通过A/B测试的形式选择对一部分用户开放新版本软件。

总的来说,这个时候我们就有了两个服务器实例,一个(旧版本)给用户使用,一个(新版本)用来进行测试。

第二个实例与第一个实例平行部署
不可变应用的新版本部署在独立的节点处

一旦我们完成测试,确保新版本万无一失,那么我们只需要修改代理服务,让访问指向新版本软件即可。旧版本可暂时保留一段时间,供可能的回滚使用。但对用户来说,旧版本已经不复存在了。用户的所有请求都会指向新发布的版本。而我们在此之前已经确保新
版本可以投入使用,因此请求指向的改变并不会影响服务体验(而如果在可变部署模式中,这样做就需要重启服务器,导致服务中断,影响用户体验)。当请求路径改变时,我们需要重新加载反向代理。例如,在所有连接转变到新路径之前,nginx会维持所有旧的连接路径。

最后,当所有转变完成后,我们可以移除旧版本,我们甚至可以让新版本去做这件事。这样的话,当到了合适的时间,新版本就会自动移除旧版本并取而代之。

上述方法已经在业内使用了很长时间,我们称之为蓝绿部署。之后我们在讲到Docker打包和部署示例的时候还会提到它。

不可变微服务

我们还能做的更好。不可变部署使得我们可以轻易实现流程的自动化,反向代理实现了零宕机,新旧版本的使用也简化了回滚工作。但由于我们面对的应用仍然过于庞大,因此部署和测试工作可能会花费大量的时间。这可能就会使我们的速度降低,而且无法频繁的进行部署工作。此外,体量庞大的应用在开发、测试和部署时的复杂度也很高。如果可以的话,我们可能会将其分割成易于管理的小部分,这样不仅易于管理操作,还能简化拓展。这些小服务可以部署在同一台机器上,如果其中某个服务到达瓶颈(需要扩展),那么我们就可以在网络中对其进行拓展或复制,而这正是微服务!
在研发“巨兽”型应用时,我们往往会产生解耦的层次。前端代码和后端代码分离,业务层和数据接入层分离等等。而在微服务中,我们应当开始换个角度来看问题。我们要分离的不再是业务层和数据接入层,而是各个服务。例如,用户管理服务可以从销售服务中分离出来。另外有一点不同的是在物理表现(physical)上,传统的架构分离是在程序包和类的级别进行,但所有东西还是共同部署的;而在微服务中,各项服务是物理隔离的,可能正在开发的两个服务都不在同一台机器上。
微服务的部署方式与之前描述的方式相同。

我们部署微服务不可变镜像的方式和部署其他软件的方式相同。

所有请求都通过代理服务选择路径
微服务应用是不可变的,部署时作为容器进行部署

当我们准备发布某个微服务的新版本时,会将其与旧版本部署在一起。

当新版本微服务完成测试后,我们改变代理的路径(route)

最终,我们就可以移除旧版本微服务,开始使用新服务。

唯一明显的不同就是,由于微服务体量较小,我们不需要额外的服务器存放新版本。现在,我们终于可以实现持续的(频繁的)自动部署,提高研发速度,零宕机时间,并且可以在出现错误时进行回滚工作。

时间: 2024-10-04 17:36:16

微服务 to 变 or not to 变?的相关文章

微服务:Java EE的掘墓人

在Java问世之初,包括IBM.BEA.Oracle在内的一些巨头公司看到了Java作为一门杰出的Web编程语言可能给他们带来的巨大商机.那么如何通过一门编程语言来赚钱呢?答案就是使用这门语言构建复杂无比的服务器,让那些大公司支付一大笔费用来购买这些服务器.于是紧接着就出现了Java EE规范.JSR规范,以及WebLogic.WebSphere等服务器中间件. 在这些服务器上面部署了大型的程序包,它们运行缓慢,消耗大量的内存.基于这些容器的开发和调试对开发人员来说简直就是噩梦,作为对他们的补偿

微服务、SOA和API对比与分析

本文讲的是微服务.SOA和API对比与分析[编者的话]对比微服务架构和面向服务的架构(SOA)是一个敏感的话题,常常引起激烈的争论.本文将介绍这些争论的起源,并分析如何以最佳方式解决它们.然后进一步查看这些概念如何与 API 管理概念结合使用,实现更敏捷.更分散化.更具弹性的企业架构. 1 简介 在对比微服务架构和面向服务的架构(SOA)时,几乎不可能在它们彼此的关系上达成一致意见.如果应用程序编程接口(API) 再加入混战,就会让理解它们的差异变得更加困难.一些人可能会说这些概念完全不同,它们

利用微服务构建现代应用(一)

本文讲的是利用微服务构建现代应用(一),[编者的话]本文介绍了微服务如何消除传统的整体化软件架构存在的问题,微服务跟SOA的关系,微服务所利用的新技术如容器.编排框架等,以及使用微服务带来的好处. 本文是关于微服务的两篇博文中的第一篇.这篇博文介绍了微服务的背景知识,微服务所使用的新技术以及使用微服务带来的好处. 简介 随着互联网公司在高度竞争性的市场中需要快速灵活的复制其开发环境,应用程序的开发正变得越来越复杂.庞大并且整体的应用程序在过去是企业的竞争力,但是在新的情境中却使得快速部署新的服务

为什么说传统分布式事务不再适用于微服务架构

传统应用使用本地事务和分布式事务保证数据一致性,但是在微服务架构中数据都是服务私有的,需要通过服务提供的API来访问,所以分布式事务不再适用微服务架构.那么微服务架构又该如何保证数据一致性呢?本文就来谈谈这个话题. 传统分布式事务不是微服务中数据一致性的最佳选择 微服务架构中应满足数据最终一致性原则 微服务架构实现最终一致性的三种模式 对账是最后的终极防线 传统分布式事务 我们先来看下第一部分,传统使用本地事务和分布式事务保证一致性. 传统单机应用一般都会使用一个关系型数据库,好处是应用可以使用

微服务架构下的事务一致性保证

今天我给大家分享的题目是微服务架构下的事务一致性保证. 主要内容包括4部分: 传统分布式事务不是微服务中一致性的最佳选择 微服务架构中应满足数据最终一致性原则 微服务架构实现最终一致性的三种模式 对账是最后的终极防线. 我们先来看一下第一部分,传统使用本地事务和分布式事务保证一致性 传统单机应用一般都会使用一个关系型数据库,好处是应用可以使用 ACID transactions.为保证一致性我们只需要:开始一个事务,改变(插入,删除,更新)很多行,然后提交事务(如果有异常时回滚事务).更进一步,

微服务和 Docker 为什么变得如此重要呢?

[原文编者的话] 本文主要讲述Docker和微服务的发展,以及Cisco对于Docker和微服务的看法.最后还提到了Docker的libnetwork,以及Cisco的开源项目Contiv,Contiv是一种通用型网络插件,用来处理多主机系统容器集群网络的使用. 在过去的18个月里,我们见证了应用程序构建.打包.传送.部署和实例化方式的快速转变.这种变化的驱动力来源于开发人员对于简化开放方式的需求以 及着眼于以应用为中心的IT视角的转变.通过飞速发展的Docker以及基于体系结构来运行应用程序的

服务端控件绑定后台变量值无效runat="Server" <%= **** %>

一个诡异的问题.服务端控件绑定后台变量值无效. 这是一段Asp.Net代码 <div> <input type="text" name="name" runat="Server" value="<%=IMaxPage %>" /> </div> 后台代码 public partial class _Default : System.Web.UI.Page { protected

微服务的框架选择

从微服务说起 微服务架构(MSA)是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦.你可以将其看作是在架构层次而非获取服务的类上应用很多SOLID原则. 用通俗的话来讲,就是为了高度解耦软件之间的依赖性,使每个独立的模块都能够单独测试,单独运维,最大限度的提高软件的开发流程.从下图可以看一下微服务的软件生命周期. 软件从需求分析就可以适配模块,也就是说需求分析的过程就可以加入设计,从新的角度来说就是在哪个模块中进行升级开发,开发人员在开发完成后,通过持续集成,将开发的结

微服务的4大设计原则和19个解决方案

作者|郝炎峰 编辑|小智 本文将介绍微服务架构的演进.优缺点和微服务应用的设计原则,然后着重介绍作为一个"微服务应用平台"需要提供哪些能力.解决哪些问题才能更好的支撑企业应用架构. 注:本文转载自公众号 EAWorld,已获授权. 写在前面 微服务架构现在是谈到企业应用架构时必聊的话题,微服务之所以火热也是因为相对之前的应用开发方式有很多优点,如更灵活.更能适应现在需求快速变更的大环境. 微服务平台也是我目前正在参与的,还在研发过程中的平台产品,平台是以 SpringCloud 为基础