我其实曾经尝试过多次用PB开发三层。包括pB7的transport,和COM+,MTS,甚至pb11后的webservices,但是总觉得烦躁。为什么呢?transport,和COM+,MTS和webservices的概念都是一样的。就是用一种代理的思路,客户端的意思先要告诉中间层,由中间层进行数据的串行化,传给客户端,客户端再进行操作和修改,再告诉中间层去更新。理论与实践表明,其开发的难度,稳定性,和访问速度,都是跟二层直连没法比的。pb的transport和MTS的效率要高一些,因为数据返回比较简练,而webservices是xml,而xml在数据串行化上的功耗相当大,使得访问起来有点慢动作。目前我自己包括其他小型的运用项目开发者,都没法无痛地开发三层,都是在用两层进行快速开发。之前有自己评估了一下,三层的COM+开发,访问一个数据库,开发量是二层的5倍。工作量是5倍,则开发成本也就是5倍,交货期和后期维护成本也是这样的。而且所谓的三层减少客户端更新也是梦魇!只是一个美好说法,修改中间层不会修改客户端的情况很少!真怀疑鼓吹三层的人的居心!
比如我们要完成1. 普通查询(只读);2. 新录入数据; 3. 修改数据
1. 普通查询(只读): a。连接中间层,b。中间层实例化对象,查询,串行化,返回adoset或者ds的描述字串,c。客户端导入adoset或者ds描述字串,显示。
2. 新录入数据:本地插入数据,b。串行化发给中间层,c。中间层通过ds填充,d。连接数据库然后写入。并返回结果。
3. 修改数据:a。中间层读取原始数据,b。串行化发给客户端,c。客户端填充,d。客户端修改,e。客户端保存时,要发回给中间层,然后更新其状态,最后update。
可见,与二层的直连开发来说,中间的处理异常繁杂,而且要处理很多异常,又不能直接messagebox弹出,必须要返回很多错误代码,在本地提示,一个异常处理不好,客户端根本看不到错误原因。而二层的任何操作,本质上只有一个或者最多两个步骤。而且稳定性高的多。因为三层加多了数据的流通环节。
另外一个,在居于数据大批量处理的系统中,靠编程代码来逐行处理数据是不可能的。比如要统计一个商业报表,都是有传到条件等参数,然后通过procedure进行逐步统计得到,并返回符合条件的结果集。所以:在数据处理的程序中,三层显得多余!实在是多余。仅仅只是一个访问代理而已。如果仅仅鼓吹三层是减轻客户端数据处理压力的话,那也是一个笑话,因为现在的电脑配置都非常高。可以这么说,以前那些文章里提到的一些很旧的电脑在现在看,也能轻松处理一些客户端逻辑,并非一定要靠中间层。比如现在的双核电脑。我想,一般的服务器,还比不上20台普通PC吧。除非是小型机,否则运算能力是没有任何说服力的。而且服务器上也不能得到很多内存!而现在pc机的CPU和内存是绝对的大!大的吓人!而且,也不太可能配备很多中间服务器的。所以以前那种客户端很差的情况下,将计算量放在中间层的做法,在今天来看,应该是一个错误的思路了。如果50人都需要处理一个过程,导不如把基本数据取下来,由50个客户端自行处理。而且很多人认为那种HP的入门的服务器(2-N万的那种,就是服务器,其实不然),那种服务器如果不提高配置,如加CPU,加内存,它的基本配置是很低的,有的低得只够带带IIS。而且我的客户听说ECC内存条要1500-2500/1G,居然想不加内存条。!!!所以三层有点跟服务器厂商打工的味道。
客户端的智能升级,自动升级现在很多软件都能解决得很好,所以不构成要用三层的理由。
复杂的统计逻辑等都需要procedure,所以也不构成需要三层的理由,因为商业逻辑也不是在三层里处理的。
三层能占的一个好处是,三层服务器跟数据库在一个局域网内。可能通讯上有优势。另外在复杂交易的控制上能起到很大作用。不过并非所有运用都如此。
那自然就想到:分布式数据库。
不仅可以把客户端的基础数据访问量分布在多台sql服务器,而且可以直接执行procedure和function,sql服务器现在也支持模组程序和扩展功能开发。那,我认为仅仅起到一个访问代理的作用的三层,已经显得毫无意义了。利用分布式数据库系统,更能支持更大规模的运用。就是把三层的服务器拿来配置服务器组用于sql分布式数据。而且访问和编程更简单。并发量和连接数也应该不是问题。从google等大规模运用来看,大型的高并发访问的最好办法不是用大型机,也不是分层,而是分布式,用服务器来组装成群组和流水线等,分而治之。至于数据在多台服务器之间复制,同步,分区,等等。或者复杂的访问策略,压力分配,都是可以在编程这个层面不用去考虑的。就像访问一台服务器一样的编程,岂不是我们都期望的吗。
所以后续将多看相关文章,深入研究一下。当然这个分布式主要指负载平衡!把多个使用者摊分到多台服务器上。
//以下是别人的文章:
http://www.javaeye.com/topic/225650
目前,分布式的概念越来越流行,但是在数据库领域里,分布式的应用相对较少。在参阅了Google的Map/Reduce概念后,我构思了一种分布式数据库的架构,并实现了其雏形,现在将其基本思路写出来,希望能起到抛砖引玉的作用。我工作时间不长,其中错误,不完善之处还请大家多多指出,谢谢。
设计这个分布式数据库的目的在于快速的处理海量数据。基本思路其实很简单,将数据分布到多个数据节点中,在执行SQL语句时,分析SQL语句的语义,对一个或多个数据库进行操作。这样就可以使查询的压力分散到每一个节点上面,面对海量数据时的处理时间大大缩短。
先拿几个简单的SQL语句做分析,看看在分布式的环境下和平常有何不同。假设我们现在有两个数据节点A和B,表名为Table,其中ID为1~100的数据保存在节点A,ID为101~200的数据保存在节点B。以下的SQL语句都是同时对2个数据库执行。
Select * from Table where ID=1
这样A数据库将返回ID为1的数据,数据库B返回为空。这时简单的合并A和B的数据,就可以得到正确的结果。
Select top 10 * from Table
这时A数据库将返回10条数据,B数据库返回10条数据,这时如果合并A和B,将返回20条结果。这时必须移除多余的10条数据才是正确的结果。
Select * from Table order by ID
这时A,B数据库将返回所有的数据,但是要使得数据符合order by的条件,很显然应该进行一次排序操作。
Select top 10 * from Table order by ID
这时A,B数据库都返回10条数据,经过合并后,还要经过排序,移除的操作,才能确保结果正确。
SQL语句中需要处理的关键字还有max,min,count,sum,avg等,这里就不写出来了。经过这几个例子我们可以看到,其实只要经过一些处理,分别对不同数据节点上的查询,可以转化成对单一数据库查询等效的结果。而这些处理归纳起来,只有合并,排序,移除这三种情况,其实这和Map/Reduce思想非常的类似,无论什么复杂的动作,最终归结都可以通过几个简单操作来完成。这些处理当然需要一定的时间,但是在面对海量数据时,很多情况下,处理所需要的时间可以小到忽略不计。
上面只是一些简单的SQL语句,面对一些复杂的SQL语句,要在SQL语句处理的过程中,进行数据节点之间的数据交换才能完成的(例子在文末会给出)。因此要实现一个完全能够处理SQL语句的分布式数据库,需要在数据库的内核部分进行改动。在实现这个组件时,时间是有限的,进行内核部分的改造不现实,所以我采取了中间件的方式,来实现了这个分布式数据库的雏形,采用的数据库是MSSQL2000,下图是我设计的分布式数据库的概念图(参见附件1):
如图所示,数据根据一定规则分布(一般可以直接Hash主键)到每一个数据节点中,由分布式数据库服务器对每个数据节点进行访问,进行归并/排序/移除操作,然后通过数据接口,返回给程序。
其中几个数据接口所适用的场景为:
Reader:提供对数据库的查询结果,逐条进行读取的接口。在海量数据下,有时候需要读取大量数据进行处理,如果一次读取到内存中显然不现实。此时可以使用Reader模式逐条读取,进行分批处理。
DataFiller:提供对数据的XML包装,适用于小数据量的读取,主要是给Web应用提供一个方便的接口。
Command:执行delete,update,insert等不返回数据的SQL语句。
BulkCopy:批量插入接口。主要是为大数据量的导入提供高速接口。
实现这个中间件,难点应该是在SQL语句的语义分析上。这块应该使用编译原理来实现,但是在我的实现中,并没有用到,原因一个是时间问题,另外一个是因为基于中间件的方式,对一些复杂的SQL语句无法得到正确的结果。所以使用了正则表达式和一些方法来对SQL语句进行分析,分析出应该如何对执行结果进行处理,以及SQL语句应该发送到单个节点还是多个节点。以下是处理的流程示意图(参见附件2):
在实现时需要注意的地方是,一定要让SQL语句从发送到执行,到返回结果之间没有任何延迟,否则每秒能够执行的SQL语句最多只有几十条。一开始我使用的模型是很常见的查询线程模型(参见附件3):
每个语句执行完毕之后,在HashMap中将执行状态设置为执行完毕。使用一个查询线程,不断的遍历HashMap,发现有执行完毕的语句,便将其发往结果处理模块。为了避免CPU占用率100%,查询线程必须要有Sleep语句,但是windows下线程轮切的最小时间段为15ms,并且在Sleep的过程中,CPU将优先处理其他线程,这样Sleep一次至少需要20ms。这样,无论SQL查询再快,分布式数据库的处理速度也会被限制在1000/20=50条/秒以下。在我做的第一个模型中,每秒最多只能处理20多条SQL语句,在面对Web应用时,显然是不够的。
后来我采用的是信号量机制,即在生成Query线程时,给其分配一个信号量,执行每个SQL语句都会将一个监视线程加入线程池,监视线程堵塞住,等待所有信号量置为发信状态,然后立刻将结果送入结果处理模块。Windows处理信号量是非常快的,可以以CPU指令周期来计量。经过这个改进,分布式数据库处理一个查询的语句,基本等同于执行查询所需的时间。当然,这样的设计造成了使用的线程比较多,调试起来非常困难,需要非常小心的设计,而且在数据节点多的时候,必须维护一个成百上千线程的线程池,个人觉得是非常不好的。我注意到无论处理多少数据,MSSQL中的线程只有20多个,可以判断出他们的设计是非常精巧的,肯定和我的这种设计不同。如果有更好的方法解决这个问题,请不吝赐教,谢谢。
以上便是一个分布式数据库中间件的基本概念和一个基本实现。当然,实现一个商用的中间件,还有很多工作需要做,例如权限,数据安全,节点故障处理,日志等模块,都有很多改进的地方。目前我实现的这个中间件非常简陋,由于MSSQL本身的限制,有很多模块实现得不够优雅,不过唯一值得欣慰的是,性能上来说是非常不错的,达到了分布式系统的初衷。目前有3台机器作为数据节点运行,进行随机数据访问时,负载基本平均分到了每一个节点上。大数据量读取,大数据量写入一般都有单数据库2倍以上的速度。当然,分布式不是万能的,目前有些问题是无法解决的。例如:
1、多表问题:简单的举个例子,例如有一张用户表,一张产品ID表,还有一张交易记录表,以用户表,产品ID表为外键,如果执行诸如
Select * from 交易记录表 where 交易记录表.产品ID=产品ID表.ID and 交易记录表.用户ID=用户表.用户ID
这样的语句时,如果只对执行完的结果进行处理,无论如何架构这几张表,都会出错。为什么?原因有点难说清楚,有兴趣的话仔细思考一下就知道了。
对于这样的语句,中间件根本无法处理,只有修改内核,在执行语句的过程中,对每个数据节点进行数据交换,才可以解决。目前的解决方法是把其中一张表放到单个数据库上。不过这样程序看起来就很怪异,一个查询动作要用到两个不同的数据库访问类,没有弄明白整个框架的程序员都不知道为什么要这样做。
2、语意分析:在分布式的环境下,SQL语意转换为操作原语的难度更加高了,确保其逻辑完全正确很困难,我离散数学学得很差,目前还不能达到100%的正确率,所以不得不在数据接口中保留了手动模式,即手工决定该如何处理数据,非常的丑陋。以目前的识别率,一些复杂的SQL语句要么分开几次写,要么使用手动模式自定义其处理流程才能确保其正确,目前也没时间去完善分析模块,只能随它去了。
提出这些问题希望能得到大家的指点,毕竟独自一人开发思路会有很多局限性,个人感觉其中还有很多地方可以挖掘,完全可能成为另外一种处理海量数据的方式。最后,谢谢你的观赏。
描述: 查询线程模型
大小: 15.3 KB
描述: SQL查询流程示意图
大小: 36.3 KB
描述: 分布式数据库的概念图
大小: 24.9 KB
还有一些文章参考:
http://tech.ddvip.com/2008-09/122180807067490.html
http://www.ningoo.net/html/2009/amoeba_for_mysql_distribute_environment.html
http://fineboy.cnblogs.com/archive/2005/08/03/206395.html
http://news.chinabyte.com/368/115368.shtml
http://news.csdn.net/n/20061124/98200.html