能否用Delphi写大型的WebApp(WINCGI/IISCGI/SOAP),非高手莫进 ? (yysun老师在哪?)(0分)

  • 主题发起人 主题发起人 Rocklee
  • 开始时间 开始时间
R

Rocklee

Unregistered / Unconfirmed
GUEST, unregistred user!
这个问题我想问好久了。
现在的Web编程五花百门。有纯脚本的CGI、Perl、 Php、ASP+COM、JSP+Servlet/Bean,VC, VB, Delphi等写的WINCGI/IISCGI等。
Microsoft的VC与VB我就不说了,因为老早我就不用了,没有调查就没有发言权。
我就只谈谈我最熟悉的Delphi吧:
自从李维先生(不要说不知道啊)的那本Delphi3 XX深入XX(很抱歉,都很久了,我忘记了,书放在公司,我现在在家,是比较薄,颜色很深的那本)开始,我一直都买李维先生关于Delphi的书籍,尤其是关于多层的商务程序的编写,我更感兴趣。从Delphi5开始李维先生就开始独立写用Delphi编写商务网页的书(不好意思,年纪大了,也忘了书名,好像是淡绿色的书面),由于是工作比较记,所以只是拜读,而无时间去详细实践。今年李维先生又出了本Delphi6/Kylix的SOAP程序篇,我跑到广州买了本,不过里面好像没有Kylix的代码,也没所谓,我喜欢里面原理讲得挺明白。
但随着对Delphi的深入了解,心中的疑问就愈大,我们知道一个标准的用Delphi编写的数据库应用程序,除了GUI接受用户的I/O之外,其核心是BDE驱动程序,是以Dll形式存在的数据库驱动程序,如果你是有心人,可以用PrcView或是相关的工具查看其运行的Modules,会发现连接有许多相关的DLL,如果你有装内存监控工具的话,就会发现,256M的物理内存,就只运行Win98,什么都没有运行就会发现只剩下170多M,如果你再运行一个Delphi写的数据库应用程序,跑一下查询。就会发现只剩下60多M的物理内存。
我的意思是说,[red]一个实例的数据库应用程序,会吃掉几十M的物理内存呢[/red],假如有几百个实例同时跑,岂不?
也许有人会问:先生,我的Wincgi是Dll啊,跑的不是几百个实例而是几百个线程啊! 但你有无想过你的Dll有几百K甚至几M(如果你的功力真如此厉害)再加上必不可少的外围Dll(数个Bde或是MSADC的运行库),你的机能挺得过去吗? 更不用说几万人同时在线了。
SOAP是很好,也是Borland发展的大方向,但有没有留意一些细微的地方,比如:我以前都提过,如果我只想写一个Service或是纯的无需GUI的WinCGI,那我是不是无需再连接如Forms,Graphics之类的垃圾单元,但好像不可能,因为到现在的Delphi6,Tservices(好像是这个吧,相对应标准程序的Tapplication的那个类)还在Forms中定义! 以致我只写一个最简单的WinCGI(我是说从菜单中的New再选Web App)也要几百K!
是否吃CPU我先不管,这么大的内存开销,如果要写一个如Google一个的大型搜索网站,真不知怎办.
反而,用Php,Jsp之类写的脚本,倒是可以想像得过去,因为是虚拟运行的(即使Jsp运行前先编译成Servlet也是一样),需要什么代码才调入执行(我的想法而已)所以可以很轻松地运行之。
我在csdn也发出同样的疑问.
(我心目中的大型网站是能承受得起码30000人同时交易的网站)
yysun老师,听说Delphibbs的大改版是你搞的,也是用Delphi的Soap功能的吧?!
您老有什么高见?
 
(看到有人点我的名就害怕)
我觉得您把所有概念混杂在一起来想,所以就理不清了。如果分开来可以容易些:
1、WebApp 不等于 SOAP
如果我没有理解错,您所提的 WebApp,应该是基于 web 浏览器的应用系统。
它和 SOAP 不是一回事情,完全不同应用场合和目的。delphibbs.com 没有用到 SOAP。
2、Delphi 操作数据库 不一定只能用 BDE
ADO 也可以,还有其他办法。
3、选择 CGI/WinCGI 和 Delphi 无关
您“心目中的大型网站是能承受得起码30000人同时交易的网站”
先得从服务器和 OS 说起,Win 2K + IIS, Win 2K + apache, Solaris + apache,
Linux + apache 等等,加上服务器配置,看哪个能够承受。
即由需求决定 服务器 - OS - Web Server - Database server - 开发工具。
而不是先假定 Delphi 作为工具,来凑到您的需求。
4、您的内存使用分析也是不对的
不是一个程序占内存 20 M,100个例程就是 20 x 100 = 2000 M。对于程序,操作系统有
调度和优化。内存关键看动态数据的使用,以及您的程序是否泄漏。
所以,您需要弄清楚想问什么问题,一个个慢慢来。
您标题上的问题倒是很好回答,看着里:
http://borland.com/about/cases 是 Delphi 实际应用的情况,
你只需要判别一下:奔驰公司的在线卡车定购系统、美国劳工部赔偿系统、荷兰电视
Starring 节目配套网站 是否属于您的“大型的WebApp”?
 
对于你的想法:我心目中的大型网站是能承受得起码30000人同时交易的网站
我觉得是这样的,现在的大型网站不是在一台服务器上面运行的,是在多台服务器上面
运行的。。而对于是否可以承受你的强度,我觉得可以通过系统,程序的优化或者形成
服务器组进行解决。。。
 
回yysun:
每次请教您,都给你会错意 ...
我还不至于不明白什么叫SOAP, 因为李维先生的书介绍得很清楚嘛,只是我不会怎么表达而已:(
也不会不知道用Borland工具写程序也有ADO方式的选择,我的重点并不在SOAP,我只是听说大富翁现在的版面是
使用了SOAP技术(也许是其他论坛,我忘记了),而是你说的Web App(WINCGI)上。
现在我想问:如果使用DLL技术,是不是不同的进程使用相同的DLL,都会使用同一地址的代码段(总之
是代码部分的数据不会是重复载入内存的),而会每个进程中使用独立的数据? 而我们用Borland或其他工具写的
WINCGI或apache Cgi不就是相当于一个独立的DLL,给IIS或APACHE动态加载吗?
我们的CGI应该是以多线程并发的吧, 如果是这样,每个线程都应该保留独立的数据以便服务于客户端,而且
我看Borland的例子还是李维先生的例子都是[red]每份实例都会生成一个Tdatabase[/red](书上说为了更好地处理Transaction),
给我的感觉,这东西很吃内存!我就想问如果有30000多人同时发出请求时,我们的服务器怎办。
我发出这种疑问是有原因的:我自己试玩着Borland的Web Service例程,听着硬盘的响声,心里就毛。
而我公司试行的在Linux下架设的Tomcat+JSP,就跑得非常轻松(虽然当服务器第一次接受请求时特别慢,但接着就
跟IIS+CGI DLL速度一样快,反正感觉不出差异),所以就发出这种疑问。
我现在在Web的选择上,正处于Borland/JSP的十字路。
我心中是偏向于JSP,但由于它没有一个顺心的IDE编辑器,所以觉得特别别扭。而我又觉得
看李维的书,觉得是一个享受(我并不急于实践,也无此时间).....
但就是觉得Borland在很不严紧,我觉得把一个如TServiceApplication之类的类放于Forms中,都出到6.0了...
相比之下,Nevrona Designsis的Indy方面就做得非常出色,绝对不会在你的程序中增加多余的代码。
 
Rocklee,非常抱歉,没有能领会您问题的主要精神。
不好意思的是,对于您的回贴,我还是发现很多概念不清晰的地方,比如:
- WinCGI 和 ISAPI DLL 不是一回事情,也许您也是早就知道的。
- 生成一个 Tdatabase 和生成一个 session 相比,并没有什么大不了,微乎其微。
等等,不扣您的字样了。[:D]
一般来说,无论 ASP,Delphi,还是 Java,都能很好地扩展 Web server,基本上不
用担心“30000多人同时发出请求”。因为,首先的考虑服务器的 socket 能承受吗?
web server 能接受吗?还有 database 能承受吗?等到您解决这些问题,象上面 CJF 朋友说的 - 用服务器组。
实际上,用 server cluster 以及 web farm,您的单个服务器基本不会面对“30000多人”的情况。
ASP,Delphi,Java 的结构差异远远大于性能差异。
“把一个如TServiceApplication之类的类放于Forms中 ...”不是Borland“很不严紧”
实际上是您没有领会 Delphi 的精神。
关于 Tomcat/JSP,您可能也不知道它的内存需求和 CPU 需求的程度。
我认为:
- MS .NET 的特色将是 web form 和 web control。
- Delphi 的特色是 WebSnap - 将网页结构、流程构件化(通过配置属性和事件编程)。
- JSP 的特色是 Tag Lib。
每一条都可以大做一篇文章,这里无法深入了,有时间慢慢再聊。
 
是吗?
我还有问题呢?
比如,如果我的WebApp中有一个查询,会返回1万条记录,并且平均每次查询会耗用一分钟,
这样,每个连接发出查询请求时都会耗用一笔服务器不菲的资源,即使你的程序可以为浏览器分页。
所以当相当多的客户同时发出查询时,我的服务器将会死掉,而实际上,我只尝试了10个左右的
并发请求,服务器就变得迟顿。而Delphi的VCL并没提供如Cancel之类的方法中断进行中的查询,
(即使将其放于线程内,然后中止线程,但这样会很容易死机,且后台服务器(如MSSQL)的任务
还在运行),相信很多人都有此经验。所以当用户用IE等Browse发出查询,并不等结果就关闭此页时,
资源得不到回收。
环境: WebApp用Delphi5编写,用传统的BDE VCL,
后台用MSSQL 运行于Server1, WebApp与IIS运行于Server2.
而这带出的问题似乎并不止是编写用Delphi编写WebApp遇到的问题,比如:无法中止长时间的查询
,在传统的数据库编写中,也会遇上(好像MS自己的数据访问组件很好地解决这个问题,比如MSSQL前端
的ISQL)。而后面的当查询运行中,用户关闭浏览器,在其他的Httpd环境中也会遇到,比如Tomcat+JSP,
也会出现Connection pool溢出之类,好像这也要我们自己想办法去解决吧。
欢迎各位讨论以上问题。
 
正在学习...
 
出现“返回1万条记录”的情况必定是系统没有设计好。而不是 Delphi 的能力问题。
比如大富翁论坛的待答问题 26800 个,我们的问题列表不可能一次返回那么多,必须
做分页处理。
WebApp 基本的设计原则之一就是,保持每次请求处理简短。
 
也有可能是1万多条记录啊,比如,我要做一个DMS的Web查询吧,数据库非常庞大,用户就好像使用普通的搜索引擎一样,
输入关键字,然后作全文搜索 ...
而分页问题,我也好像问过您吧,都好像在WebApp端无法得益,因为传统的分页,只是为浏览器而作吧。
如果硬要做的话,就要在Select 后,加上 Top nn了, 而nn 则取决于一页能显示的记录数。
不知除了这愚笨的方法之外,各位还有什么高见?

 
数据库中当然可以有1万条记录,如果说有10亿条也不稀奇啊。
最基本的原则是:
1、尽量一次操作一个记录(通过合理的逻辑设计和界面设计)比如信用卡系统,数据库非
常庞大,这个不是 web app,却给我们提示了它就工作在信用卡号这个主关键字基础上。
刷卡机就是一个拨号 modem,处理器很弱小。一划卡,嘟嘟嘟就拨号,等上三五秒,就得到结果。
2、合理的索引设计,比如 clustered index 更加适合范围查询,SQL Server 2000 的
View 上面也可以加索引。
3、合理的 cursor 设计,有时候可以使用 server side cusor。
4、利用 stored procedure 和 transcation
5、利用 SQL Server 的 XML 功能,它是基于流操作的,有时候比传统 Recordset 效率高。
等等。技术上讲,数据库端已经有很多方法可以来提高 web app 的效率。
而 web app 本身的[red]设计[/red]则更加重要。也就是说:“有1万条记录”并不可怕,
但是,有一次“返回1万条记录”的设计需求就可怕了。
 
yysun老师,用for xml子句查询返回的值,怎么从delphi的SQLQuery组件中
取出来呢?
 
yysun老师,我有问题:
DELPHI 6 抢先研究-- BizSnap/SOAP/WebService 之三(附图)
在前面的例子(见 《DELPHI 6 抢先研究 -- BizSnap/SOAP/WebService 之一 -- 一个 Hello world! 的例子》 和《DELPHI 6 抢先研究-- BizSnap/SOAP/WebService 之二 -- 通过 SOAP 传递自定义类型数据》 )中我们看到了 SOAP 的强大功能,特别是第二个例子。如上一个例子所示,我们只要利用 Midas/DataSnap 的 Provide/Resovle 架构,将 Data/Delta 包做成自定义类型,在 Web services 与客户端之间传递,便可以通过 SOAP 实现三层数据库应用。这固然是一个方法,但未免麻烦一些,其实 Delphi 6 早已为我们准备好了,而且她做得更好,她将 IAppServer 接口进行 SOAP 封装,使得我们可以用和 Midas/DataSnap 一样的方式来开发基于 SOAP 的多层数据库应用。
当然还是以一个例子来说明:
服务端:
1.New|WebServices|Soap Server Application ,如下图:
这次我们用 Web App Debugger (详见《DELPHI 6 抢先研究 -- Web 应用开发及调试》),设置其 CoClass Name 为 wadSoapDemo3 , 如下图:
2.SaveAll , Unit2 命名为: SvrWMMain , Unit1 不改名, Project1 命名为: Demo3 ;
3.New|WebServices|Soap Server Data Module ,如下图:
在弹出的对话框中输入 Class Name 为 SoapDemo3DM ,如下图:
确定后将此单元保存为 SvrDMSoap ;
4.在 SoapDemo3DM 中放入三个控件: SQLConnection1, SQLDataSet1, DataSetProvider1 ,如下图:
其属性设置为:
SQLConnection1 ConnectionName := IBLocal;
LoginPrompt := false;
Params.Values['Database'] := '[...]/Examples/Database/Employee.gdb';
// 上面的 [...] 为你的 InterBase 安装路径
SQLDataSet1 SQLConnection := SQLConnection1;
CommandText := 'select EMP_NO, FULL_NAME, PHONE_EXT from EMPLOYEE';
DataSetProvider1 DataSet := SQLDataSet1;
5.服务端就这样完成了,不用写一行代码,编译并运行,然后退出即完成 Web App Debugger 应用的注册。
启动 Web App Debugger ,再启动浏览器,在地址栏输入: http://localhost:1024/Demo3.wadSoapDemo3/wsdl 即可看到三个接口:
Port Type Namespace URI do
cumentation WSDL
IWSDLPublish urn:WSDLPub-IWSDLPublish WSDL for IWSDLPublish
IAppServer urn:Midas-IAppServer WSDL for IAppServer
ISoapDemo3DM urn:SvrDMSoap-ISoapDemo3DM WSDL for ISoapDemo3DM
这其中除了有 DataModule 的接口 ISoapDemo3DM 以外,最重要的是多了一个 IAppServer 接口,只要有这个接口,就有 Midas/DataSnap 。
接下来做客户端:
1.New|Application 新建一个一般 VCL 应用程序;
2.SaveAll , Unit1 命名为 ClnMain , Project1 命名为 Client ;
3.在 Form1 上放上 SoapConnection1(在 WebService 页中的最后一个), ClientDataSet1, DataSource1, DBNavigator1, Button1, DBGrid1 等控件,如下图:
设置各自的属性如下表,如果设置正确的话,应该如上图那样在 DBGrid1 中显示出数据来:
SoapConnection1 URL := 'http://localhost:1024/demo3.wadsoapdemo3/soap';
ClientDataSet1 RemoteServer := SoapConnection1;
ProviderName := 'DataSetProvider1';
Active := true;
DataSource1 DataSet := ClientDataSet1;
DBNavigator1 DataSource := DataSource1;
DBGrid1 DataSource := DataSource1;
Button1 Caption := 'Apply';
4.双击 Button1 输入下面的程序:
procedure TForm2.Button1Click(Sender: TObject);
begin
ClientDataSet1.ApplyUpdates( -1 );
end;
5.至此,客户端程序也完成了,编译并运行(确定 Web App Debugger 已运行),可以看到服务端运行一会儿,它的窗体闪现几秒钟后客户端程序即可取得数据并显示出来。现在可以通过 DBNavigate/DBGrid 对数据进行操作,操作完成后按 Apply 按钮即可将数据修改提交到服务端,此操作会运行服务端程序。
就这样,我们只写了一行程序就完成了一个基于 SOAP 的多层数据库应用。
请问为什么我将上面的服务器程序转换成dll后,然后又把它放在同一台机器的iis的可执行目录下,接着就是做客户端,可是客户端的ClientDataset就是
连不上服务端,一连接就没有响应,请问为什么会这样??

 
上面的高手您们好啊
我公司现在有个项目,要用 Web Service 方式,我准备用Delphi来实现前后台的处理。
我对 Borland 的 Web Service 方式不是很懂(公司有搞 VB.NET 在用)。
1、Borland Web Service 是采用什么方式,与微软的有什么不同。
2、Borland Web Service 的 DataSnap 可以封装 XML的解析吗? 是不是就不用手工
进行XML文件处理? 数据更新采用什么样的方式? 是不是将更新的 SQL 语句进行封装?
网络传输量大吗???
最重要是的,我才开始学习,有些机制不是很懂。象Borland 的 WEB Service 是怎么
运行? 是通过 IIS 吗? 我做的程序,怎么就是不能连接呢?
我用Delphi6/Kylix的SOAP程序篇例子中的程序,怎么,客户端就是不能连接呢?是
WEB Service 要通过什么方式进行发布吗??
请教了哈,我现在还不想转VB, 如果不能解决,只能用VB了!
 
为了说明问题,送您一个 stored precedure:
CREATE PROCEDURE usp_GetSomethingList @PageNo int, @PageSize int AS
SET NOCOUNT ON
CREATE TABLE #Temp (
Id int IDENTITY primary key,
rid int
)
declare @MaxGet int
set @MaxGet=@PageSize*@PageNo
SET ROWCOUNT @MaxGet;
INSERT INTO #Temp (rid) SELECT SomethingId FROM tblSomething ORDER BY SomethingId
SELECT Something.* FROM #Temp a right Join tblSomething Something on a.rid=Something.SomethingId
WHERE a.Id>@MaxGet-@PageSize
ORDER BY SomethingId
GO
 
或者 这个用 cursor 的算法
set nocount on declare
@nextid int, @counter int
set @counter=5
create table #t ( rid int )
declare AA insensitive scroll cursor for select UserId from tblUser order by UserId for read only
open AA
fetch absolute 2 from AA into @nextid
while @counter>0 begin

fetch next from AA into @nextid
if @@fetch_status=0 insert #t (rid) values (@nextid)
set @counter = @counter-1
end
close AA
deallocate AA
select * from tblUser u inner join #t t on UserId=t.rid order by UserId
drop table #t
在 1 百万 user 中,按每页 5 个,跳到 2500 页,几乎没有停顿的感觉。
 
哈哈,我在聽課!
 
真的在听课呀!
不过反对顶楼的,不是高手别进来的说法,嘻嘻
 
果真如此?
那服务器端会否有很大的资源损耗?
最近我买了李维先生的ADO,MTS/COM+编程一书,挺贵,应该三本书中,最贵,终于三本书都买齐了,就是没好好
深入研究,嘿嘿。然后正在试着按李维先生灌输的原理,用ado与MSSQL写,好像好像挺快,挺稳定。不知道是不是我
是现在是用Win2000+Delphi6,以前用Delphi5(即使加了补丁),写ado常出错。
但李维先生的建议与yysun老师的有一点出入,李维先生建议[red]尽量小的数量流量+客户端curror+异步索取模式[/red]才
为之精。特别强调可以避免使用服务端curror的,就不要使用之。
yysun的第2种方法也很新颖,应该挺有效率。但是fetch absolute 2 from AA into @nextid,
不应该固定是2吧,我要赶快试试才行。
我又想问下, yysun老师:
select * from tblUser u inner join #t t on UserId=t.rid order by UserId
与 select * from #t t inner join tblUser u on UserId=t.rid order by UserId
是否有分别。
我自己老是认为sql总是先从from 的table1扫描,再搜索inner join的table2,不知道
是不是,如果我的想法是对的话,那么用第2句是否效率高些?(MSSQL也许会智能调整,会根据
两者数据大小而决定谁先扫描), 这个老观念,来自读书时的,嘿嘿。
yysun,我还有问题啊,不好意思,应该不是这个主题的,但我懒得再开一个...
如果我用tadodataset, 设为locktype 为batch模式。用sql跟踪器看,我在做的一批更新,
在updatebatch时才发出sql更新命令。而且在一个transaction中,但如果其中一些更新出错(如
重复键之类),会致使整个transaction失败。这时,我也想其他合法的记录得到更新,且要得到
非法的更新,我该怎样做?
 
后退
顶部