架构原则——一致性原则

     一致性是所有质量原则的根基。好的架构应该是直接的,人们掌握了部分系统后就可以推测出其他部分。

【基本】

      编码风格为制定包括对命名、格式、目录结构等诸多风格要求的软件系统编码规范。

      编码风格一致,利于团队模式下代码编写和阅读。

【高级

      架构风格为一组原则的集合,是为系统家族提供抽象框架的粗粒度模式。

      架构风格可以改善设计,促进重用,为常见的问题提供可靠的解决方案。

【说明】

      架构风格可能是对一些架构模式的运用,然而在运用模式之前,首先需要分辨系统的类别。例如系统如果是业务复杂的企业应用,那么就领域层而言,就应该选择领域模型(Domain Model),通过有效地利用对象、组件和服务保证系统的可重用性与可扩展性。而一旦选择了领域模型,那么在通常情况下,就不应该在同一个系统的其他模块中采用事务脚本(Transaction Script)模式。否则,我们就违背了风格的一致性。

   当然,架构风格的选择会因为关注点的不同,产生不同的解决方案。例如,从部署的角度来看,我们可能需要选择分布式部署的物理架构;而对于同一个系统而言,由于需要考虑消息的传递,我们又可能选择消息总线的方式。这与风格的一致性并不矛盾。我们只需保证在同一个关注面上,保持一致的风格即可。

【举例】

1. 风格形式一致性带来的简单美

      保持系统架构在形式上的一致性,常常是架构师的有意为之,其目的是希望保持架构的简单性。最能体现形式一致性的一个原则是“惯例优于配置”。这里所谓的“惯例”,可以理解为框架对实现的一些约束。我们可以根据事先制订的默认规则,通过反射技术完成对象的创建,对象的协作,甚至是应用程序的组装。“惯例优于配置”的关键,就在于它规定了形式上的一致性。以Ruby on Rails为例,通过事先确立Model、View和Controller的目录结构与命名规范,强迫开发人员对系统进行MVC的划分,并严格遵守框架制订的规范。在程序运行时,Rails会将分离的部分组装在一起。组装的过程默认按照命名约定与惯例进行,在一般情况下就不需要任何外部的元数据配置信息。下图是Rails的MVC架构: 

 

  当客户端向服务端发出请求后,Dispatcher会对请求的url进行解析,并判断应该将请求发送到应用程序的哪个部分,以及如何解析这一请求。在寻找到正确的controller与action之后,就可以通过该action来处理请求。action可以查阅请求中携带的数据,可以与模型交互,也可以调用别的action。最后,action会为视图准备充分的信息,视图则将所需的信息展现给用户。因为在形式上能够保持一致性,框架就变得简单,参与的各个组件能够做到各司其职,职责清晰,意图明确。

  这种形式的一致性基于一种朴素的思想,就是有限的约束比完全的开放更容易实施和遵循。正如社会总要有一套被人广泛认同的规则,来约束每位公民的行为,否则整个世界就会乱了套。形式一致性的本质在于概念的完整性,而它的基础则在于约定。架构的复杂性在于我们无法为混沌的系统做出正确的决策,如果能够为我们所要解决的场景抽象出整体的概念,就能够最大程度地对模型进行简化,从而给出一致性的约定。Rails利用现有的MVC模式,通过约定与惯例在形式上的一致性,实现了Web架构的简化。

2.解决方案一致让一致性可持续

        首要在进行系统架构之前,我们必须根据系统与团队的情况,制定被团队成员广泛接受的架构原则。例如,我们可以为系统制订分层指导原则。对于领域层,我们遵循DDD的要求,为领域模型确定实体、值对象、聚合根、服务、工厂与资源库之间的明确划分,并明确地指出它们应该具备的特征。我们要求应用服务层不应包含任何业务逻辑,只负责UI与领域层之间的消息传递,并可调用基础设施中公共模块的数据验证、缓存和安全等功能。我们要求应用服务层不应保留业务对象的状态,仅仅负责协调应用的活动,并要求所有公开在外的应用服务均定义为接口。除此之外,团队成员之间的协作与沟通,以及必要的架构评审与代码走查,都能够在一定程度上避免解决方案的不一致。

3.数据一致性约束

        数据一致性约束的是一个用户写入并提交数据之后,其他用户去读这条记录的时候,要么看到的是事务开始之前的状态,要么就是事务结束后的状态,而在这两个状态之间的事务状态则不会被其他人看到。例如,A要给B100元,那么,要么结果是B有100元,要么是A有100元,而A减少了100元,但B还没加上这100块的这个中间状态则不能够被其他人看到。

        做到这个一致性的一般性做法就是把数据加锁,让某个数据只能被某个进程或线程访问就行了。但这样也有个代价就是锁住数据的时间越长,系统的并发程度越低,系统的tps也就越低了。尤其在分布式场景下,维持锁的延迟在加入了网络这个因素后,变得非常巨大,以至于很难接受。

        因此在互联网行业中,大家普遍使用的方式是“最终一致”,也就是,三种状态都有可能出现,但A减少了100元,B却没加上100元这个状态,因为速度非常快,只有毫秒级,并且对用户没有太多的不良影响,所以就认为是允许了。

        用户可见的状态,从原来的两个状态,变成了三个状态。

        然而需要注意的是,最终一致并不意味着弱一致,也就是说,B“最终”必须能够拿到这笔钱,能够拿到,就是“最终”一致,在异常状态下不能够拿到,那就是“弱”一致。

posted on 2014-12-04 13:51  bitepeng  阅读(3093)  评论(0编辑  收藏  举报

导航