otto.de是德国的一家 上购物 站,本篇前半部分主要介绍了几个系统架构以及它们的优缺点,后半部分主要讲解otto.de的微服务架构。
在我们开始开发otto.de 上商店时,我们选择了分布式垂直架构。之前的工作经验告诉我们,一体化架构(monolithic architecture)不能够满足不断增长的需求。爆发式增长的数据,持续提高的负载和对系统的扩展,所有的这些强迫我们去重新思考 站的架构。
这篇文章将会描述我们的解决办法,还有我们这么做的原因。
一体化(Monoliths)
在项目刚开始的时候,团队通常会考虑使用什么编程语言和合适的架构。当谈到服务端应用时,Java和Spring框架,Ruby on rails或者类似的框架通常会成为团队的选择。
选择了语言和框架后,经过一段时间的开发,一个简单的应用诞生了。与此同时,一体式架构(macro-architecture)毫无争议的成为了团队的选择。但是,这种架构的缺点也渐渐地浮出了水面:
它导致了重量级微架构(a heavyweight Micro Architecture)
负载均衡限制了应用的可扩展性
系统的可维护性受到影响,尤其是那些大型应用
零停机部署(Zero downtime deployment)变得非常的困难,尤其是那些有状态的应用(stateful application)
多个团队开发效率低,并且需要额外的协调
我们可以根据业务域来分解系统。举个例子来说,在otto.de我们就讲 上商城分解成了11个不同的垂直模块:后勤办公室,产品,订单等等。
每一个垂直模块属于一个单一团队,它们有独立的前端,后端和数据存储。在模块之间共享代码是严令禁止的。当然,在特殊的情况下,如果我们需要分享代码,我们会建立一个开源的项目来解决该问题。
因此,每个垂直模块是一个独立自主的系统,就像Stefan Tikov在Substainable Architecture中提到的那样。
分布式计算
一个垂直模块依旧可能成为一个相对大型的一体化应用,因此我们需要继续对垂直模块进行拆分。一种方法是将一个垂直模块分解成更多的垂直模块,另外一种方法是通过分布式计算将系统分解成多个模块,不同的是这些模块运行在他们自己的进程中,并且通过REST来传递信息。
因为我们暂时没有利用到分片这个概念,在这篇文章就不再详细描述了。
负载均衡
每当服务器承受不了巨大的负载压力时,负载均衡就会容重登场。通过对一个应用拷贝多次,同时利用负载均衡器将负载分解来缓解压力。
当你没有相应的需求时,组合的结果会变得有点太复杂。幸运地是,开发者并不需要在一开始的时候就制定庞大的计划,相反,他们可以循序渐进,一步步朝着目标架构前进。
举个例子来说,在otto.de,架构一开始是4个垂直模块加上负载均衡,在过去的三年里,产生了更多的垂直模块。在此期间,某些模块变得非常的巨大笨重。因此,我们引入了微服务架构,同时通过扩展垂直模块来建立分布式计算。
微服务(Microservices)
微服务最近变得非常的流行。微服务是一种架构风格,它能够根据业务域将系统分解成多个细粒度,独立的模块。
在这种情况下,微服务可以是一个小的垂直模块,或者是分布式计算机构中的一个服务。与传统方法的不同之处在于应用的大小:一个微服务仅仅实现了一个业务域中的几个功能,它结构清晰,一个开发者能够很轻松的掌握它。
一个微服务非常的小,因此多个微服务能够运行在单一的服务器上。我们对“Fat JARs”有丰富的经验,通常能通过执行java –jar 来执行它们。如果需要的话,也能开启一个Jetty或者类似的服务器。
为了简化不同微服务的部署和操作问题,每一个服务器运行在独立的Docker容器中。
REST和微服务架构是一个很好的组合,它适合于构建大型的系统。一个微服务可以负责提供REST资源,超媒体(hypermedia)可以用来解决服务发现的问题,在涉及到接口的版本控制,服务部署独立性的情况下,媒体类型(media type)有很大的帮助。
总而言之,微服务架构有许多的好处,比如说:
在微服务架构下进行开发是非常有趣的:每几周或者几个月,你就可能开始一个新的开发项目。
由于微服务非常小,微服务架构不需要重量级框架和过多的模板代码。
他们能够被独立的部署。因此持续交付或者持续部署变得非常的简单。
微服务架构能够支持多个独立的团体同时开发。
开发者能够为每一个服务选择最恰当的开发语言。不用担心对项目产生影响,开发者可以尝试新的语言或者框架。但是需要注意,这并不意味这你能够随意行使这项权利。
因为微服务足够小,只需消耗较少的资源就能将他们替换成新的项目。
这种架构的可扩展性相比于一体化架构显得非常的好,每一个服务都能被独立的扩展。
微服务架构遵守敏捷开发的原则。一个不能完全满足用户的新特性不仅可以被迅速的创建,而且还能够被快速的销毁。
宏架构和微架构(Macro- and Micro-Architecture)
在微服务架构中,哪一部分将难以改变部模块的扩展已经不再是关键问题,最难以改变的事情是有关微服务架构的决定,比如说如何将微服务整合到系统的方法,或者模块间传输信息协议的选择。
因此,otto.de严格区分了微架构(micro-architecture)和宏架构(macro-architecture)。微架构都是关于垂直架构或者微服务架构的内部结构,并且全部交由各自的团队全权处理。
但是,明确宏架构的大体方向是有价值的:
垂直分解:系统被分割成多个垂直模块,每一个模块完全属于一个特定的团队。模块与模块之间的信息传递禁止在用户请求的过程中进行,而必须在后台执行。
RESTful架构:不同服务之间的信息传递和整合只通过REST来执行。
零分享架构:服务间不会通过共享可变状态(mutable state)来进行信息交换或者分享信息。没有HTTP sessions,没有中央数据存储中心,没有共享代码。但是多个服务的实例之间有可能共享一个数据库。
数据管理:对于每一个数据节点,只有一个系统负责管理。其他的系统只能通过REST API读取数据,然后将需要的数据拷贝回自己的数据库。
我们的架构已经熬过了一轮软件开发周期,与此同时,我们开始标准化微服务使用的方式。
集成
目前为止,我已经详细说明了许多有关系统分解的内容。但是,用户体验是我们的系统的最终目标,我们希望我们的应用保持一致性,感觉就像是一个整体。
因此,问题来了:我们如何能够集成一个分布式的系统,同时让用户意识不到我们架构的分布特性。
超链接
对于前端集成,最简单的办法就是使用超链接。
每一个服务负责不同的页面,页面的导航通过链接来实现。
AJAX
使用AJAX的目的也很明显,它能够通过Javascript重新加载页面的不同内容,并且将他们整合在特定的页面。
主要注意的是,服务之间涉及到的依赖非常的小,服务互相之间需要对使用的URL和媒体类型(media type)保持一致性。

资源服务器(Asset Server)
当然,图片在不同页面的显示也需要保持一致性。除此之外,分布式的服务需要对他们各自的Javascript库和版本保持一致。
为了保持一致性,在我们的系统中,静态资源,比如说CSS,JS和图片都是通过一个中央资源服务器来进行传输。
在垂直架构,共享资源的部署和版本控制是一个完全不同的话题,这需要一篇独立的文章来详细解释。在这里我们不做过多解释,我们只需要记住,共享资源的同时保持服务独立是具有非常大的挑战性。
Edge-Side Includes
有一种不太知名的方法,它能整合不同服务的资源到同一个站点。这种方法我们称之为Server-Side Includes或者是Edge-Side Includes。大多数的Web服务器或者反向代理都只支持这个功能。
这项技术非常的简单:一个服务插入插入一条带有URL的包含语句(include statement)。然后这个URL会被web服务器或者反向代理解析,代理根据URL获取到一个响应,然后用这个响应代替页面中的包含语句。
在我们的商城中,每一个页面都包含了来自搜索&导航服务(SAN)的导航信息:
…
…
反向代理(我们使用了Varnish)解析了页面,然后将URL分解出来,SAN根据URL提供相应的HTML片段。
然后Varnish代理用这个HTML片段取代包含语句,并将重新生成的页面发送回用户。
在这种方式下,用户根本意识不到页面是由多个来自不同服务的片段组成的。
数据拷贝(Data Replication)
以上提到的技术仅仅解决了前端集成问题,现在我们来谈谈服务端集成。不同的服务之间需要共同的数据,但是他们又不能共享同一个数据库,因此我们想了一些办法来处理这个问题。
数据拷贝就是一个办法。比如说,其他的服务需要关于产品的数据,它们就会定期的向负责产品数据的垂直模块(Product)请求数据,这样产品数据的更新能够很迅速的被其他服务检测到。
我们没有使用任何的消息队列来向客户端推送(push)数据。相反的,每当服务需要更新数据时,它们会轮询(poll)Atom Feed。
值得一提的是,某些不好的事情必须牺牲服务的可用性来避免,我们在开发过程中不得不面对这个矛盾。
没有远程服务调用(NO Remote Service Calls)
理论上来说,在某些情况下,我们可以避免数据的拷贝,这样服务就能够同步使用其他的服务了。一个购物篮并不需要保存额外的产品信息,相反它可以直接向产品模块请求数据。
我们并没有这么做,为什么呢/p>
当一个系统的主要功能依赖于其它系统时,系统的可测试性受到影响。
一个缓慢的服务会影响到其它系统的请求,当请求越多,雪球越滚越大,最终影响到了整个系统的可用性。
系统的可扩展性受到了限制。
独立的服务部署变得非常的困难。
我们长期和垂直架构打交道,我们非常明确的知道,在早期的时候,严格的界限会使得微服务的开发,测试,迁移变得更加独立,方便。
经验教训
按照以上罗列的办法,经过三年的工作后,我们变得经验丰富。
回顾往事,如果我早点做这些事情,我们的一体化系统会变得更加的精细。现在,otto.de的未来属于微服务。
文章知识点与官方知识档案匹配,可进一步学习相关知识云原生入门技能树首页概览8588 人正在系统学习中
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!