经典软件架构模式(三)

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 条评论
登录 后参与评论

相关文章

来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2567
来自专栏java 成神之路

使用 NIO 实现 echo 服务器

4617
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2707
来自专栏Golang语言社区

【Golang语言社区】GO1.9 map并发安全测试

var m sync.Map //全局 func maintest() { // 第一个 YongHuomap := make(map[st...

4708
来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.2K7
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3125
来自专栏落花落雨不落叶

canvas画简单电路图

61411
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

5446
来自专栏我和未来有约会

Silverlight第三方控件专题

这里我收集整理了目前网上silverlight第三方控件的专题,若果有所遗漏请告知我一下。 名称 简介 截图 telerik 商 RadC...

4025
来自专栏我和未来有约会

Kit 3D 更新

Kit3D is a 3D graphics engine written for Microsoft Silverlight. Kit3D was inita...

2526

扫码关注云+社区