经典软件架构模式(完)

如何选择架构模式

上面我们探讨了6种经典的架构模式,那么在实践中,我们到底应该如何选择呢?在次我们可以用一个案例来初步的讨论。

我们的案例是开发一个大型网站的发布(CMS)系统。大家知道,现在的门户网站,每天的访问量都是上亿次PV的;同时网站每天也要发布数以百计的新闻和专题。这些新闻除了简单的放上网站以外,互相直接的内容关系,还是网站编辑们组织栏目,整理专题所需要的。因为我们的网站是由大大小小很多经过分类的文章链接组成的。而CMS就是一套专门用来发布、管理网站文章内容的系统。

这个系统的主要使用者有2个,对于网站访问者来说,他们看到是编辑人员的工作成果:一个经过良好组织(通过超链接)的网站,里面包含了很多页面。对于网站编辑者来说,这个系统要提供他们的工作界面,包括工作人员自己的帐号权限管理、内容组织编辑等软件功能界面。

面对这样的一个需求,我们首先要做需求的细化:

1. 编辑功能

a) 新建、修改、删除文章

b) 对各级文章模版进行修改

c) 制作各种专题页面和嵌入式链接专区

2. 用户需求

a) 快速响应用户的点击

b) 当新文章发布后,快速更新首页、专题页面等链接区块

c) 承载海量用户并发访问

以上两个需求抽象总结来说:

1. 要应对编辑复杂的交互操作

2. 要应对快速的高性能数据发送

在需求确定了之后,我们就要进入模式的选项。我们可以先按利于功能开发和适用服务器端(交互操作少)还是适用于客户端(交互操作多)两个维度来整理一下已知的架构模式。

我们可以看到,分层模式是最基本的模式,其他的5种模式多少都算是分层模式的一种变种。所以他处于模式分类的中心地位。而MVC和微核模式由于方便在运行时提供复杂的模块交互,所以更多用于客户端方向。而REST/SOA/管道和过滤器则更倾向于特定的模块处理接口(请求-应答),所以更适合于服务器端。

在功能性和性能(非功能需求)上看,REST由于实现层大部分是HTTP协议承载,所以一般性能较差,好处是很方便开发功能。而MVC模式的实现代码也因为需要复杂的事件机制甚至依赖语言的反射机制,所以性能也不能算非常好。相比之下,微核模式能更接近基本底层代码,其性能表现要好的多。而SOA模式因为可以组合大量的系统提供高吞吐量,所以也在可用性、承载量上有更好的表现。

最后,我们来比较下SOA和“管道与过滤器”这两者。SOA对于服务的描述更适合与开发复杂的逻辑,而“管道和过滤器”由于功能语义更底层,所以更方便能以最有效的实现方法来处理数据。所以SOA强于功能处理,而“管道与过滤器”则偏重性能(承载量)。

不过我们这个案例的需求非常明显,分层模式的功能太弱了,应该有更好的选择。由于我们需要有“复杂的交互的操作”,所以MVC模式应该是值得考虑的一个。由于同时也有“高性能数据发送”的需求,而且“用户读文章”的功能非常单一,所以“管道和过滤器”模式也应该使用,而无需去使用针对复杂功能的SOA模式。

通过以上的论证,我们可以明确一个观念:万能的模式一定是无能的模式;模式的限制越多,能提供的特性也越强。

需求分析结论

  • 价值取向
    • 万能即无能
    • 限制越多,功能越强
  • 需求及变化
    • 范围一:编辑使用,逻辑多变
      • 内容页、栏目页、专题页
      • 相关文章、每页推荐、模板升级
      • PC浏览器、手机浏览器、手机APP
    • 范围二:浏览者使用,性能要求高
      • 高可用、高承载
      • 只读、非实时

最后,我们在建立方案之前,还应该参考一下业界的实现,以比较和印证我们的分析。

  • StoryServer
    • Tcl语言模板——无法二次开发工具
    • 自带cache系统——不好分布
    • 按CPU收费——费用高
  • Zope
    • Python语言模板
    • 自带数据库、Web服务器——性能差
  • Midgard
    • PHP语言模板——灵活性差
    • 安装在Apache上——部署复杂,性能差

可以看出,参考产品中,在以上两个需求都满足的很好的确实不多。所以我们应该提供高性能、高可用性,同时也是维护使用简单的发布系统。现在,我们分两个层面来描述我们的系统架构设计:

1. 整体系统架构

我们把整个系统分为两个过滤器,一个是用来生成内容的“内容管理器子系统”,另外一个是“内容缓冲器”子系统。文章内容从编辑人员处通过“内容管理器”输入和处理,然后发布到“内容缓冲器”系统中,由它提供高性能、分布式的内容发布功能。我们可以综合使用内存缓冲更新方法和文件静态存储方法等一系列手段,尽量的提高内容缓冲器的性能。由于内容缓冲器的写入很少,而读取量很大,针对这个特性,我们的分布集群也很好做。

2. 内容管理器子系统架构

在内容管理器内,包含了一个网站内容的内部复杂逻辑关系,因此要提供方便的软件工具给策划人员,最好是用MVC模式来实现。在编辑对于网站页面内容需求的变化中,我们可以根据MVC的原则,不断修正和增加内容管理器的功能。而核心的数据逻辑部分,则会较少需要修改,这样可以提供给编辑人员更自由的内容创作空间。

针对上述案例,我们可以发现,一个系统并非只能用一个架构模式,而是可以复合的使用不同的架构模式。而在选择模式的过程中,我们需要建立一个核心价值观:紧紧把握业务需求,以及需求的变化。我们通过把握需求,就可以抽象出业务领域的名词作为核心概念,从而导出系统架构中模块的名称;然后我们通过对业务规则的总结,则可以未这些模块添加上行为。这样整个系统的各个模块都能严格对应上业务需求。但是,有时候我们会无法决定模块应该如何划分,比如这个功能究竟应该由A模块来独立完成,还是应该由B/C两个模块协作完成。我们就可以使用“探讨需求变化的原因”这个标准来做决定。如果这个模块的需求是预计不会变化的,那么就只用一个模块就好了;如果由于不同的原因,导致这个模块需要修改的话,那么就应该为“不同的原因”专门设计“不同的模块”。而最终我们选择模块的组织形式——架构的时候,正式根据这些需求变化造成的问题来决定。比如这些需求变化会造成性能、承载上的难题吗?这些需求变化会造成用户界面修改频繁吗?能处理好这些需求变化,正是考验一个人的软件架构能力的地方。

业界经典架构模式范例

在软件界发展的长河里,使用各种架构模式的经典案例非常多。我们可以从学习这些案例的过程中,体会和掌握架构模式的含义。

分层体系里,最出名的是TCP/IP协议,这是构造互联网的基石。TCP/IP协议通过对于不同层次的定义,从而兼容各种不同的网络硬件、操作系统、应用软件。正是因为TCP/IP协议严格遵守分层的设计,所以在底层复杂的实现下依然可以提供良好的兼容性。

网游的鼻祖MUD系统,由于采用良好的分层模型,其底层MudOS被无数个不同的游戏世界所共用。而MudLib本身的良好分层,也让构造一个虚拟世界变得简单有趣,而不是复杂艰辛。通过同一套MudLib改造出的完全不同的游戏非常常见。现在很多大型网游的架构,都是来源于MUD的这套分层架构。

Windows窗口模型是最经典的微核案例。它通过一套消息队列,让运行时的各个窗口模块可以互相调用。而Windows系统本身,则负责核心的用户输入、通信、维护消息队列等操作。这样每个窗口程序,只需要针对Windows消息做编程,就能拥有对Windows系统下各个应用、服务的使用能力。

著名的开源IDE:Eclipse,现在已经被用在各种不同语言和系统的开发上,包含了JAVA/C++/LUA/PYTHON/PHP/Android…等任何你想得到的地方。这种如此丰富的特性,又能完美的结合在一起,是由于它本身对微核模式做了一个优秀的实现:OSGi

OSGI四层实际上就是个微核:为了解决组件之间的通信,OSGi约定每个组件通过提供各自开放的服务(Services)实现相互间的协作。但如何知道哪个组件拥有哪些服务呢,OSGI规范通过服务注册表(Service Registration)来解决服务的查询、定位和调用问题。在OSGI的世界里,Bundle即可理解成为组件。

管道和过滤器的例子在软件界则更加的多,比如我们最常见的Unix Shell系统,每个进程都被赋予了stdin/stdout/stderr这样的三个“出口”,因此每个进程都可以作为一个过滤器存在,而竖线“|”符号则可以把这样多个“过滤器”直接组合成一个处理管道。

在网络服务器领域,Apache MINA是一个很流行的IO框架。这个框架的特色,就是你可以用代码构建对一个网络包的处理管道。你可以定义很多个IoFilter类的对象,然后组合起来成为一个管道,这些过滤器有些负责对消息解码,有的负责对消息鉴权,有的负责解压数据……最终消息会送到用户定义的IoHandler类型的对象那里,进行最终的业务逻辑处理。这对于需要“统一的增加某个网络处理特性”来说非常好用。比如我们需要修改网络的编码协议,比如从JSON格式换成Google ProtocolBuffer,我们只需要修改一个过滤器就好了;或者我们需要让消息变得更小,我们只需要增加一个zip算法压缩、解压的过滤器就完成了。这些特性的修改完全无需修改任何业务逻辑代码。

MVC模式中,在工具类库上支持的最彻底的莫过于苹果的iOS界面类库,他直接把整个UI类库都按MVC模式来设计。你必须要编写Controller对象,关联View对象,才能让UI模型运行起来。

在Web应用开发领域,由于基于HTML/JS的页面也是用户交互操作的范畴,所以也出现大量的使用MVC模式设计的框架。其中最经典的就是Apache Struts框架。

在这个框架里,JSP充当View模块的载体,而Servlet则是Controller的载体。Model就是用户编写的JAVA类对象。Controller和Model之间通过一个配置文件关联。而Model和View之间则直接通过JSP自定义Tag来绑定。这样只要是用户的操作,就能自动根据配置struts-config.xml转发到用户对象的方法上,而结果的更新,通过JSP的标记自动的刷新出来。

SOA系统一般用在大型的企业内部中。由于企业内部的各个部门系统很多,而且数据又需要互相关联,所以SOA模型就能很好的对这些复杂的结构进行管理。

在这个例子中,大家可以看到,业务流程系统需要大量对业务服务层进行调用,而业务服务层的每个子系统(供应商、配送、保险、银行……),都是通过“注册中心”发布的。业务流程本身会先查找,然后调用这些业务服务子系统,而无需实际与复杂的业务子系统耦合到一起。

最后关于REST的案例,这里提供全球最多人使用的facebook提供的公开业务API是最好有说服力的。

这是一个针对facebook消息读取的API,URI中的object-id部分对应着一条facebook消息,而comments则对应所有的评论资源。使用GET命令字就是拉取这些评论资源。

而对于写评论,也是同样的,以URI中的object-id对应消息,comments对应评论资源,使用PUT就是把内容添加进去了。REST的核心就是以URI作为资源的对应,使用GET/PUT等HTTP命令字做操作。

在本文最后,我想推荐一些让我得到以上知识的书,这些书都是软件架构知识的宝库。其中第一本POSA是最古老的经典,是架构模式书籍的开山之作;第二本是中国人写的架构设计的方法学,详细介绍了架构设计的整个过程,以及里面所涉及的文档格式、方法,也提到了架构模式;第三本论文总结了软件架构中的知识,推导出REST模型;第四本讲解了如何在细节上以分层架构来设计复杂的库,虽然其中内容主要针对.NET体系,但是对于任何一个想设计框架或者复杂系统架构的人来说,这里面的原则、规范、最佳实践都是可以照搬的。

  • 《面向模式的软件体系结构(POSA)》
  • 《软件架构设计》
  • 《架构风格和基于网络软件架构设计》
  • 《.NET设计规范:约定、惯用法与模式》

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

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

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

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏SDNLAB

【8点20】深入了解Facebook 的Altoona数据中心网络

Facebook最近秀了一下Altoona数据中心网络的高度模块化和可扩展性。这个社交网络巨头高调公布了数据中心网络解决方案,因为Facebook想围绕开放计算...

2955
来自专栏mwangblog

Linux简单介绍

1105
来自专栏大魏分享(微信公众号:david-share)

IT武林的一项绝学:Ansible

IT的武林 如果把IT圈当成一个武林,里面有各大门派并充斥着各种武功的话,ansile绝对是一项杀伤力极强的内功。ansible本身配置和使用极为方便,并能够以...

3295
来自专栏ThoughtWorks

2015.5 技术雷达 | 工具篇

(点击图片可以查看大图) 尽管依赖管理的概念并不新奇,在很多技术栈下它甚至已经被作为一种基础开发实践,但在PHP 社区却并非如此。Composer(getcom...

3295
来自专栏QQ会员技术团队的专栏

海量服务实践──手Q游戏春节红包项目设计与总结

1. 需求背景 1.1.红包类别 2017年的手Q春节游戏红包共有刷一刷/AR地图/扫福三种,如下图所示: ? 1.2.体验流程 虽然红包分三种,但在游戏业务...

2238
来自专栏Linux Python 加油站

揭秘Linux工程师一路走来都需要哪些技能

大公司也是从小公司一步步走过来的,而大公司之所以与小公司不同,不在于基础的技术体系不同,而是当数据量达到一定程度后,引发的质变而已。而在思考质变带来的性能问题中...

904
来自专栏UML

用例图示例:包含和扩展用例

用例提供了系统的高级视图。用例建模是与用户和其他利益相关者就系统和目标进行沟通的有效方式。用例描述了系统执行的动作序列,其为特定的actor产生可观察的值结果。...

1759
来自专栏微信公众号:Java团长

做一个完整的Java Web项目需要掌握的技能

最近自己做了几个Java Web项目,有公司的商业项目,也有个人做着玩的小项目,写篇文章记录总结一下收获,列举出在做项目的整个过程中,所需要用到的技能和知识点,...

481
来自专栏PHP技术

PHP7的优缺点及从当前版本升级到PHP7都遇见了哪些坑

优点就是快,相比5.6有一倍的提升,也有很多方便的新特性,缺点是目前相关的扩展支持还不完善,很多扩展(非官方)坑不少,万一踩到由于内核变化,很多人调试起来可能不...

3656
来自专栏非著名程序员

绝对干货:供个人开发者赚钱免费使用的一些好的API接口

不久前,我写了一篇文章,名为《科普技术贴:个人开发者的那些赚钱方式》,讲了一些个人开发者接私活和自己做软件加广告的一些科普知识。可是做软件,需要服务器,需要后台...

2439

扫描关注云+社区