应用架构设计的三个类型

前段时间在论坛回答两个问题:事务和事件,这两个概念涉及到业务和技术架构的区分问题,合适的架构解决合适的业务,就像不同运输工具装载不同的运输物一样,人用客车装载,货物用卡车装载。

通过长期业务实践,我们会发现业务中隐约有一些通用共同的东西,如果我们能够总结出这些通用的业务功能应该使用什么技术架构解决,也就是解决了大部分软件系统的共性问题,可以避免初学者范方向性基本错误,特别是当前云计算环境下的编程,云计算那些强大的技术服务应该适用怎样的业务,只有这些问题搞清楚了,才能更好地使用云计算。

从我个人经验来看,业务中通用的东西提炼出来,分为三种模型:串行 星形和并行,见文后附图:

1.串行:这实际代表事务处理,每次只能存在一个处理过程,在这个过程中调用多个函数,这是一个不可逆的过程,讲究前后顺序时序,每个环节都会产生结果数据。

2.星形:这实际代表一种操作共同数据的模型,比串行要灵活一些,允许多个过程操作一个数据,雅称称:并发计算concurrency computing

3.并行,这比星形更加自由,每个过程都独立于另外一个过程,互相不干扰,雅称并行计算Parallel Computing。

上面三个模型中都涉及两个基本元素:动态过程和静态数据,三个模型实际是这两个元素不同的组合结果,而过程和数据从哲学上讲可以说是抽象时空的两个基本要素,那么我们也许可以假定这三个模型已经涵括大部分需要软件实现的现实中业务系统。

再回到事件和事务两个概念,很显然,串行模型特点和事务特点非常吻合,因此,如果遇到业务中强调事务实现的,如交易事务等等应该是用严格的串行模型实现。

而事件概念一般是突发的,无法人为控制,如某地发生XX大事件,所以,事件发生的特点肯定是发散或同时的,很显然,星形模型和并行模型特点和事件特点吻合。

既然这三个模型是业务和技术的接口模型,也就是说,业务人员和技术人员对这三个模型各有各的理解,通过这三个模型他们能够找到沟通点,也能找到业务功能对应的技术实现途径。

再从“同步”和“异步”来看三个模型,串行模型无疑属于“同步”;而另外两种模型无疑是异步的,或者可以说,不严格要求是同步,而通常异步能够带来高效率和高性能,因此,可以认为是“异步”的。

最后再从“有状态stateful”和“无状态stateless”角度来看这三个模型,串行和星形属于有态的,而并行属于无态,这里状态实际就是静态数据,有态表示不同过程需要共享同一个静态数据,从基本常识来看,为获得高性能,这种静态资源争夺必然会降低性能,因此,如果限制静态数据为不可变的,那么就无需使用多线程锁进行独占式修改访问,应此也会提升性能。


[该贴被banq于2012-05-16 17:28修改过]


前面提到谈论事务讨论见:问个比较初级的问题,通用业务逻辑提取

谈论事件:领域框架事件驱动的时序问题

以前我们常说程序=算法+数据,如果用过程+数据就更加贴切,算法代表一种动态过程,但是算法一词过于计算机专业化,没有通用意义,所以用“过程”替代比较直观。

在云计算环境下,云计算主要解决Scalable性能拓展问题,无疑我们的应用非串行化,Scalable指标就越好,云计算通过自动伸缩扩展并发计算和并行计算这两个模型,也就是我们所说的星形和并行,可以大大提升我们软件系统的处理能力。

当然,从CAP定理,一致性 可用性和分区性也可以分析这三个模型,无疑串行是一致性最高的,可用性好,无法分区切分;而星形和并行则灵活些。


下面谈一下初学者的问题,对于初学者来说,他们可能自己没有意识到自己大部分在进行串行模型,也就是事务模型的编程。

过去,计算机主要用于精确计算,大部分进行财务系统或金融系统的信息处理,因此传统关系数据库是缺省的事务编程模型,每次开启一个数据库连接实际开启一个专用锁,保证当前线程是独占资源,虽然应用在JavaEE .NET等多线程环境,只是相当于从串行过渡到星形模型,当访问量增加时会产生性能瓶颈。

对于初学者的知识结构如下:算法+数据结构 ==> 事务模型(串行模型)。

所以,引入“事件”概念,会让初学者视野拓展开来,原来除了事务,还有事件模型啊,而串行 星形 并行可以说完全丰富了初学者的知识结构,特别当他面对云计算环境,那些消息 NoSQL等等如何使用时,从这三个模型完全可以辅助他入手。

过程和数据是串行 星形 并行的两个基本元素,事务和事件是这三个类型的通俗表达。

我们也可以用这套分类标准来看现在面向对象和面向函数区别,以便我们何时使用何种技术。

Java .NET等传统面向对象的对象缺省是一种带有边界的数据结构,我们开始代码时总是首先建立一个Class类作为对象;所以,他们在过程表达上要弱,这时只能通过架构上的“服务Service”概念引入来强化,这就是SOA架构,如果说DDD领域驱动设计侧重静态数据结构,那么SOA侧重动态过程的服务,这两者结合才能表达一个完整的业务系统。

而面向函数语言如Scala等,包括Javascript,开始代码时总是首先建立一个function函数作为对象,所以,他们的特点是侧重动态过程,无疑,用Scala来表达SOA的服务是最合适的,表达事件也是最合适的,这也是为什么我们接触Javacript时,会发现有事件这个概念,他们都属于同一个边界的,同一个本家。

再说开去,无论怎么复杂的架构标准,都离不开动态过程和静态数据这两个基本要素,因为他们都要落地,只有借助这两个要素,才能落地成串行 星形和并行三个架构实现。

比如电信联盟行业对其业务支撑系统,俗称BOSS有一个标准,所谓BOSS就是对我们通常电信电话上网彩信等套餐进行跟踪自动计费的一个系统,去电信厅开通某个业务,操作员操作的都是BOSS系统。

电信联盟的BOSS标准称为NGOSS,其又分为两个部分:动态流程的eTom和静态数据的SID模型,所以,研究eTom和SID的文档就有几百页,你可能迷失于大量显式语言设计中,疑惑这样的设计能够落地成为代码?实际它也是分为过程和数据两个部分,肯定能够落地的。

另外看到一些媒体专门列举了一些著名架构师都写代码的例子,架构师有两种侧重,侧重技术的,甚至可以去发明纯技术语言,但是侧重业务设计规划的,和自己行业有关,比如电信行业 保险行业等等,你不能指望他去发明技术语言,但是可以设计出类似NGOSS这样行业业务语言。

无论是Java Scala这些技术语言,还是eTom/SID这些业务语言,都是一种语言,都遵循过程和数据的动静结合原理,都能落袋到三种架构类型,这些类型都遵循不同的逻辑规范,串行是不可逆,也就是非幂等过程,而并行是完全幂等过程,而星形则是两者都有可能,取决于你需要选择。见:蒯因与引用透明
[该贴被banq于2012-05-17 07:46修改过]

星形和并行代表了并发并行新的计算模型,从这篇文章为什么JVM能够击败Node.js?对Javascript Ruby Python Groovy比较来看,可以说这几种语言对星形和并行支持很弱,再结合传统关系数据库使用,还是一种串行的事务模型,这也就是现在大多数程序员的知识结构。

比较图转载如下:

多谢banq,确实有所领悟
串行和并行两种方式产生冲突时应该怎么处理呢?

2012-05-17 13:53 "@liyao0409"的内容
串行和并行两种方式产生冲突时应该怎么处理呢? ...

用业务俗语表达,串行处理事务,并行处理事件,这个问题是否变成:这些请求到底是事务请求,还是一般事件?

事务是一种务必需要完成的工作,比如公司事务,家庭事务,国家事务,既然务必完整完成,那就必须投入更多资源确保完整完成,很显然,串行方式可以确保专一,心无旁骛,但效率低。

事件是不受人控制的发生一件一件事情,是一种时间点的概念,比如公司发生事件,家庭发生事件,国家发生事件。因为事件是无法事先规划控制的,因此,响应这些事件的处理过程就有可能无法投入更多资源确保完整务必完成,质量无法保证,追求效率第一,把这个事件平息了是第一考虑的。

所以,好像事件和事务的区别在于两个因素谁重要的问题:质量和速度效率。如果追求效能,将其作为事件看待,使用并行过程来高效处理;追求质量,不惜调集各种资源(锁 JTA需要监视线程)等,那么将其作为事务看待。

事件还有另外一个隐式意义,如果我们把“人”认为“服务器”,人以外的其他地方认为是“客户端”,事件都发生在“客户端”,而“服务器”这端响应事件的是“服务”。在“服务器”这端的“服务”内部还是可以再细分为“客户端”和“服务端”,通过这种细分,“服务”内部也是存在事件的,这样,服务这个过程概念实际上变成一个个事件点了,这样切分的好处是松耦合,避免铁板一块。

而服务如果以串行实现,恰恰是铁板一块,Scalable效能吞吐量都是很差的,唯一优点是能够确保事情完整地高质量地完成。EJB无态Bean或有态Bean缺省都是带有JTA事务,JTA事务机制确保服务是串行的,传统Spring+Hibernate等架构或其他语言+传统关系数据库结构,好像没有JTA,实际上有JDBC事务,也就是有数据库锁,还是一个串行过程而已。

我们如果在服务内部引入客户端和服务端概念,就能切分服务这一串行过程,而将一个服务切分为客户端和服务端,实际就要在服务内部切一刀,该怎么切?这是对象化方法就其作用了,对象化方法特点是封装,封装代码边界划分,边界划分实际是切一刀,小学生男女同桌,女生喜欢在中间划一条线,这一划代表两个对象(男女)封装起来。

我们在服务内部通过DDD领域驱动设计引入实体聚合根,让实体聚合根代表业务核心,它是客户端,由它发出各种事件指挥服务端,服务端是除了业务以外的技术架构,因此,在服务内部我们又切分成业务和技术两个方面。

由于我们有了这套切分方法,那么任何原来看似串行的都可以解决成并行,也就不可能存在串行和并行矛盾冲突的地方,因为并行总是可以切分串行的,除非你认为完整高质量过程不能被破坏,当然,使用并行,也不代表质量不高,但是为高质量可能付出代价高一些,当然随着中间件发展,对并行高质量支持的中间件迟早会出现。

见:OOD vs SOA
混合OO和Functional设计
[该贴被banq于2012-05-18 07:18修改过]

事件的产生是并行的,事件的处理是串行的,这样不行么?
比如领域对象的save操作,可以同时触发若干个事件,每个事件的内部处理过程使用串行处理。

2012-05-18 09:30 "@gameboyLV"的内容
事件的产生是并行的,事件的处理是串行的,这样不行么? ...

当然可以,用点线面来比喻的话,事件是点,事务是线。

事件产生于客户端,当客户端是用户浏览器时,事件的并发产生是天然的;而如果我们对服务器端的“服务”再切分为“Client”"Server"时,那我们就要保证这个"Client"产生的事件必须是并发的,采取并行模型。

事件的处理属于服务器端或"Server",这里又可以重新考量使用三个类型中任何一个模型了,用串行也可以啊。

通过以上分析,我们能够达成共识,实现相互沟通,这实际是一种架构语言。

下面这个案例展示,首先从过程和数据进行切分,分别找到过程服务、结果状态数据和结构性数据,结果状态数据是过程处理的中间结果,而结构性数据一般是实体对象,是服务的目标。

审批系统的DDD、DCI应用

函数式编程另类指南

云计算和传统分布式技术区别?
[该贴被banq于2012-05-30 10:14修改过]

2012-05-18 09:30 "@gameboyLV"的内容
事件的产生是并行的,事件的处理是串行的,这样不行么? ...

实际上,这是一种折中处理,或者说偷懒处理。我们考虑事件的时候,其实应该着重考虑处理部分,而非产生。试想把所有生产者都合起来看成一个“大生产者”,那么“大生产者”和事件串行处理器所构成的实际上是一个大串行而已。引入事件,实际上就是为了并行处理,也就是N个处理者同时处理N个事件(相当于N台电脑同时计算)。

我个人认为引入事件,就应该向离散时空思考,否则优点浪费事件了。