经典软件架构模式(三)

REST模式

让我们回到服务器端开发。一直以来,互联网服务就以数据互通为最重要的业务特性。我们来看看一个微博系统的案例。

【此案例并非完全真实情况,有一定提炼修改成分】

微博作为一个非常常用的“用户制造内容”服务,一直都是各种互联网网站最喜欢的项目之一。微博本身的功能抽象并不复杂:发微博、读微博、发评论、看评论。但是需要微博数据的外部系统却很多,比如微博自己就有WEB平台、手机平台、Pad平台,在各种合作厂商那里,又要提供可以发微博晒产品、真人秀、炫耀成就……等等。可以说微博是一个结合大量其他应用系统的信息中心。初期的产品设计,可能会比较简单:

在这个模型里面,我们一般把功能分层两组,一组是本系统的服务器,如WEB平台和手机平台。另外一组是开放给第三方的接口服务器。我们希望这样能分流负载,并且隔离不同平台的故障。但是,随着业务的发展,策划有可能对最简单的微博功能,要求增加一下活动,比如“集赞抽奖”之类的,那么我们就要增加一些专门的“游戏活动”服务器。但是为了让第三方也能参加,自然就要部署多套,而且其中功能可能还有一些不同。——这就造成了积累下来的业务逻辑重复代码增多的问题。

随着第三方的接入商越来越多,除了会剧烈增加第三方TCP接口服务器的负载外,还有针对外部厂商的开发语言提供越来越多格式的API,这些维护工作量往往会占据掉开发团队大量的开发时间。有没有一种一蹴而就的方法呢?答案是有的。在互联网数据共享和互联的服务里面,一种叫REST的模型迅速超越了古老的corba RPC方案,战胜了JAVA专用的RMI技术,也干掉了各种WebService方案(包括SOAP),登上了最流行互联网接口的宝座。因此当我们改成使用REST模型的方案后,我们终于可以集中精力在微博系统本身的业务功能开发上了。

由于我们把微博的功能都集中到REST功能服务器上,我们可以把各种用户界面相关的代码独立出去,集中精力做好核心功能逻辑。同时由于所有的请求都集中到REST服务器上,在此的负载均衡和故障维护都变得统一。也无需维护多份相关的逻辑代码了。由于REST是一种跨语言的标准协议(基于HTTP),所以各种语言都有开源的REST API,这样就无需另外开发很多语言的API。为了提高外部业务的性能,还可以专门构造一个缓存系统,减少对主题功能服务器的压力。

REST模式是在Roy Thomas Fielding于2000年的博士论文提出。这篇论文的名字叫《架构风格与基于网络的软件架构设计》,在论文中,作者详细的回顾了架构模式的发展例程,并且以互联网服务为案例,逐步推演出REST架构模式,论证了其合理性和必然性。这篇论文本身就是一片对于架构模式的很好的说明(当然包括了本文前面介绍的几种模式),并且在互联网的环境下,提出了新的解决方案。这个模式的出现,说明了软件架构模式并非一层不变,而是在持续发展中的新兴科学。

“最通用的接口”——最常用于互联网公共接口 。现在的主要实现方案,一般使用HTTP协议和URI标准。

l 适应:资源型公开服务。一般互联网服务都可以抽象成“对一个由URI指定的资源”进行“增删查改”操作的模型。这种模式和按照REST定义的HTTP命令字天衣无缝的结合在一起。并且这些“资源”还可以利用缓存,来提高其性能。

l 不适应:大量临时状态服务。由于REST模式规定了“资源”必须是无状态的、可缓存的,否则就会造成大量的性能问题。因为我们如果以HTTP协议去实现这个模式,短连接和大量文本协议字的解析,在没有缓存支持下运行,将会很消耗服务器性能。况且,资源状态变化过于频繁,必定造成接口调用的频繁,这也会消耗大量网络连接。

l 方法论:以业务资源为核心设计。我们需要把我们的业务功能,抽象成可以用“资源”描述的模型,才能很好的使用REST模式。而不是简单的把URI作为某种类似“命令字”的方式来使用,那是一般的Web Service。一般我们可以把本服务的核心数据,作为“资源”来描述,然后围绕这些不同种类的资源来设计接口。以微博服务为例,微博文和评论就是这种“资源”。

l 设计模式实现:

l 命令模式:一般来说我们会把一次REST调用,看成是一个命令。而REST一共有四种命令:PUT/DELETE/GET/POST,我们只需要扩展这四个基本“命令”类型,就能很方便的实现REST模式了。

SOA模式

现代互联网服务,往往都是服务器集群来支撑的。单纯的在一个进程、一个服务器内的架构,往往不能满足需求。那么针对海量服务的服务器集群,有什么样的架构模式是可以参考的呢?我们可以来看一个案例。

假设我们要做一个电子商务的系统,这个系统无疑需要展示商品、提供购买流程。同时这个系统也需要有针对供应商的订货、发货、入账等流程。除了交易处理,还需要有评价系统管理信用;统计和推荐系统增加销售量;用户帐号系统保障安全和便利等等。这些模块和功能一般比较复杂,但是一般涉及到买家和卖家两个角色,因此我们往往根据这个规则,划定了两类模块,分别实施其功能,最后通过一个数据平台来存储这些数据。

这样的系统什么看起来问题不大,但是有两个潜在的问题:

  1. 不能应对复杂的需求变化。比如需要在同样的数据上重新开一个网店,但是仅仅售卖其中一部分货品。这就可能需要拷贝代码或者复杂的代码重构工作。如果需要增加一些促销活动,可能会涉及大量代码的修改。
  2. 不能应对自动容灾和伸缩的需求。由于用户访问量可能很大,因此我们往往需要准备大量的服务器来运行这个网站。当访问量变化的时候,没有预定的架构设计,可能会被用户量的增加打个措手不及;又或者当服务器出现故障的时候,明明有可以分担任务的服务器,但是用不上,白白给用户造成故障体验。

为了解决这两个问题,我们经过一番设计,能比较好的解决。其中最简单的是还是利用前文提到的“分层模式”,把业务分解成“顶层:面对用户的流程处理”和“底层:面对业务的系统能力”两个层面。这样的分层能让复杂的需求变化大部分集中于“顶层”部分,由于可以重用“底层”的能力,这种需求变化仅仅需要编写变化相关的代码,大大减轻了开发的工作量。然后,为了解决集群系统的性能和稳定性问题,我们把顶层到底层的调用,改成:“先通过一个【中心节点】查询,再具体调用”的方式。这样我们只要把运行状态同步到中心节点上,就能实现自动的容灾和伸缩。最后我们再启用分布式的数据存储,解决最底层数据的安全性问题。

这样的模型,实际上就是SOA模式。这种模式最大的特点,是关注服务模块之间的调用:在运行期根据负载、路由策略等用户设定,来决定模块间的调用关系。这比起以前单服务器中的观察者模式,是一种升级——让多台服务器和多个进程之间,可以在运行时协作。这种模式可以很好的实施集群的负载均衡和容灾策略。对于复杂的服务期间通信问题,也通过规定的交互接口和交互流程实现了高度的简化。很多SOA模式采用RPC框架实现,跨服务器调用往往和调用本地函数一样方便。

SOA模型的标准内容,包括一个核心服务代理模块、一批服务消费者模块、一批服务提供者模块。当然消费者本身也可以提供者。这些模块都可以是集群中的分布在不同服务器上的进程。而服务提供者通过一种叫“服务合同”的接口定义数据,来发布自己提供的服务;消费者则使用这个接口定义,发起对服务的调用,从而屏蔽底层服务交互的细节。

在集群启动后,服务提供者先发布自己的服务信息到服务代码模块进程上。服务消费者在需要时,对服务代理查找所需服务,得到能提供服务的地址、接口等信息,直接对服务提供者发起服务请求。

在以Web Service框架实现的时候,一般“服务合同”由WSDL提供,具体的服务都是Web Service,具体的编码格式有一些使用SOAP格式。 WSDL可以生成各Service Broker在实践中往往提供了负载均衡、容灾扩容等运营功能。 通常“服务代理”由一个目录服务器充当,而SOAP协议则可以直接序列化、反序列化为对象。

“云模式”——分布式业务系统。SOA是提供云服务最好的模式之一,因为云服务对于容灾和伸缩性有较高的要求,并且也需要考虑后续功能开发的便利性。

l 适应:异种系统集成。在多个不同的业务系统需要“集成”或者数据共享时,SOA模式提供了很好的伸缩性、容灾模型,以及简便的接口集成方案。

l 不适应:实时系统。由于SOA模式存在一个“查询-调用”的过程,如果对于程序响应要求很高,则不适合增加这样一个复杂的模型。SOA模式可以提供几乎无限的吞吐量,但是对于降低响应延迟却有死穴。虽然我们常常利用“缓存”中心节点数据的方式来减少服务延迟,但这也同样要付出服务器提供者状态不同步,导致请求失败的风险。

l 方法论:抽象业务逻辑为“服务”。由于SOA的核心是面对服务的,所以我们在分布式系统中,传统的面向“命令字”的思维需要扭转过来:服务是有自己的名字,规定的接口形式和固定的返回值类型的,而命令字则只有自己的类型和数据;服务是以请求-应答为标准模型的,而命令处理则只有“发送-处理”。从灵活性上来说,命令字会更好,但是从代码的可理解度来说,无疑抽象成“服务”更容易被阅读。

l 设计模式实现:

l 命令模式——尽管我们把功能抽象成服务,但是其底层实现,还是一个个的命令字往返收发实现的。使用命令模式可以很好的封装服务的底层实现。

感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。

原文发布于微信公众号 - 韩大(handa1740168)

原文发表时间:2015-12-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏云计算D1net

如何将私有云模型拓展到混合云?

私有云是进入混合云的极佳跳板。企业要从私有云模型迁移到混合云需要设定具体的目标。 当企业开始利用服务器虚拟化来提高效率和降低成本,许多公司会很快发现他们正在支持...

3016
来自专栏EAWorld

基于微服务的日志中心设计、实现与关键配置

日志向来都是运维以及开发人员最关心的问题。运维人员可以及时的通过相关日志信息发现系统隐患、系统故障并及时安排人员处理解决问题。开发人员解决问题离不开日志信息的协...

782
来自专栏SDNLAB

基于OpenFlow架构的IaaS云安全

编者按:云计算技术的服务型基础设施即服务(IaaS),以其可扩展性、高效性及弹性等特点正在成为资源利用的主导方式。在从云计算的IaaS应用获得便捷的同时,安全漏...

2373
来自专栏曾钦松的专栏

万亿级调用下的优雅:微信序列号生成器架构设计及演变 ( 上 )

微信同步机制的背后,需要一个高可用、高可靠的序列号生成器来产生同步数据用的版本号。这个序列号生成器我们称之为 seqsvr ,本文会重点介绍 seqsvr 的架...

2.1K1
来自专栏java达人

Base:Acid的替代方案

作者:DAN PRITCHETT 译者:java达人 来源:https://queue.acm.org/detail.cfm?id=1394128(点击阅读原...

3825
来自专栏木东居士的专栏

DataTalk:迟到的数据该怎样处理?

1713
来自专栏鸿的学习笔记

分布式系统下如何进行数据复制?(下)

对于single-leader的数据复制模式,并且我们选择了异步的方式对数据进行处理。假如写入数据和读取数据都出现了并发的情况,显然数据会出现短时...

310
来自专栏CSDN技术头条

那些高级运维工程师,都是怎么给公司省机器的?

随着项目用户量的快速增长,前期可能由于应用程序设计、数据库设计及架构不当,大多项目会在用户量百万、日志/流水等表过千万、乃至过亿时,出现写入卡顿、查询缓慢、各种...

872
来自专栏纯洁的微笑

构建高可用网关之容错实践

自从微服务概念以来,众多的软件架构在践行着这一优秀的设计理念。各自的系统在这一指导思想下收获了优雅的可维护性,但一方面也给接口调用提出了新的要求。比如众多的AP...

3487
来自专栏美团技术团队

常见性能优化策略的总结

本文要感谢我职级评定过程中的一位评委,他建议把之前所做的各种性能优化的案例和方案加以提炼、总结,以文档的形式沉淀下来,并在内部进行分享。力求达到如下效果: 1....

3985

扫描关注云+社区