如何让中间层MIDAS/DATASNAP支持大量的并发用户并且控制连接数量
最近在写一个基于XE2 DATASNAP的中间层,以前也写过基于DCOM的MIDAS中间层,看到网上一些同仁对中间层的提问。我摘录俩个典型的提问,如下:
第一个提问:
Midas三层程序,如何支持大量用户同时请求连接?
系统结构: TClientDataSet -> TSocketServer -> scktsrvr.exe -> RemoteDataModule -> ADO
要求:允许500-1000个客户端同时“请求”连接,服务器和客户端均不能死掉。
现状:在现有的程序中,只要同时“请求”连接的客户端达到一个较大的数量,例如80或100,应用服务器就停止响应了。客户端尝试连接时,不但无法建立连接,甚至都无法获得
一个“返回错误”,而是跟着一起停止响应。
期望:能够允许500-1000个客户端同时发出连接请求、尝试连接。当然,可以限制并发工作数,哪怕限制到很小的数量;但是,超出这个数量的客户端在执行
TSocketConnection.Open时,必须能立刻收到一个“连接数已满,拒绝连接”的返回信息;或者进入一个等待队列,重试指定次数或者重试指定时间;或者,哪怕仅仅抛出个异常
。但不允许停止响应,不允许无声无息地死掉。
第二个提问:
基于Midas/Socket/Scktsrvr的三层程序,如何在连接环节限制连接数?
架构:TSocketConnection -> scktsrvr.exe -> RemoteDataModule
现状:大量客户端(如200个)同时发起连接请求,中间层或scktsrvr明明无法处理这么多的连接,却又不推辞,最终导致客户端、中间层和scktsrvr都死掉。
期望:让scktsrvr限制Socket的数量,超过限度(如20个)之后的客户端可以向scktsrvr发出连接请求,但scktsrvr不分配给Socket,拒绝连接;客户端超时之后,弹出对话框提示用户。
网上关于中间层的提问看似千奇百怪,其实集中起来,无非就是上面的俩个大问题(虽然上面的提问都是针对MIDAS的,但同样适合于DATASNAP):
1。让中间层支持大量并发而不会死掉;
2.控制最大的连接数量,防止服务器因硬件资源被耗完而死掉。其实这俩个问题也可以说是等同一个问题。
这俩个问题可以解决吗?答案是能。
首先描述一下许多同仁写中间层的方法:
1. 中间层线程服务方式选择“SESSION”,这也是MIDAS/DATASNAP默认的线程方式,大家往往跟着默认;
2. 在远程数据模块上放一些诸如数据库连接控件、数据集控件。。。。。。
无可否定,这样写中间层是最容易,也是许多教科书中介绍的方式。但正因为这样才导致了上面的问题。
因为这样的方式对服务器端的资源消耗是重量级的:当一个客户端连接上来,服务端对应开一个线程为其服务,直至客户端终止连接才关闭这个线程。为什么说是重量级的呢?当线程开启后,会创建远程数据模块,然后远程数据模块里面的一大堆数据集对象、数据连接对象都会被创建,如此多的对象在客户端的连接周期内一直存在,且只能为一个客户连接提供服务。因为服务器的资源消耗是重量级的,一旦客户连接数量稍微一多,服务器的硬件资源很可能马上就消耗完。此时如果又没有做最大连接数量上限的控制,就只能任由服务器因资源耗尽而当机。这就是这种方式写中间层的弊端。即这种方式决定了中间层能够支持的客户端并发数量是非常有限的,因为每一个客户端对服务端的资源占用都是重量级的:一是占用时间长(客户端只要还保持着连接,服务端资源就一直被占着),二是服务端要创建一大堆对象给每一个客户连接服务。
如何解决?
1. 化重量级对象占用为轻量级占用;2. 化长时间占用为实时占用。
于是对象池呼之欲出,对象池中的对象们能够为所有的客户连接服务,再不是某些对象资源只能为某一个客户连接服务。
最关键的是改变服务端的线程服务方式:不能用默认的"session"线程方式,要改成线程池的方式。对于操作系统来说,能够创建线程的数量总是有限的,比如WINDOWS大概能够创建2000个左右的空线程对象。改为了线程池的方式以后,线程数量再不是限制。
改造成线程池这是第一步,然后改造数据库连接对象池,数据集对象池。。。。。。
这样实现有什么好处?
对象池中的对象只是实时被占用,这个占用只发生在一个客户的一个事件动作发生的那一瞬间,当这个事件一完成,对象即归还对象池中(只是归还池中,并没有释放对象)。对象避免了频繁地创建和释放,减少了许多对象创建所消耗的时间(对象的创建是比较耗时的,何况是如此众多的对象的创建,这要消耗多少时间)。减少了因对象频繁地创建和释放所产生的内存碎片(对象的每一次创建和释放都会产生微量的内存碎片,看似微不足道。但你想过没有:服务器是7*24运行的,且频繁地创建和释放的对象数量是如此众多,这会产生多么大的内存碎片啊。内存碎片一是会影响服务器的执行性能,二个可能使服务器当机)。
如何控制最大的客户连接数量?
设置服务端线程池的上限(PoolSize)吧,控制了线程池最大创建线程的数量,就控制了最大的客户连接数量。
这个上限设置多少合适?
具体要看那台服务器的硬件配置情况了。实际进行压力测试才可得知。
本文来自博客园,作者:{咏南中间件},转载请注明原文链接:https://www.cnblogs.com/hnxxcxg/archive/2012/02/25/2367488.html