针对‘消息队列繁忙排队连续超时该如何处理’的解决方案

发表于:2007-05-25来源:作者:点击数: 标签:队列繁忙排队连续消息
[code:1:bbc52bf8d4] ①请求消息处理线程 负责端口监听,如果有新连接进入则验证连接合法性,如果成功则加入连接池,连接池只能容纳一定量的连接 监听连接池中所有连接是否有消息输入,如果有则读取请求消息 处理连接非协议性关闭(如断电) ②将请求消息写

[code:1:bbc52bf8d4]
① 请求消息处理线程  
     负责端口监听,如果有新连接进入则验证连接合法性,如果成功则加入连接池,连接池只能容纳一定量的连接
     监听连接池中所有连接是否有消息输入,如果有则读取请求消息
     处理连接非协议性关闭(如断电)

② 将请求消息写入消息队列
     这时必须换过消息格式,在原来的消息头中加入进队列的时间戳和所属连接。

③ 通知连接无法处理请求
     由于消息队列可容纳的消息个数有限,并且消息队列是循环可丢弃型的,只有在消息处理线程组太忙而客户又有大量请求进来时才须要抛弃最旧的消息。在抛弃最旧消息时查一下时间戳,如果未超时则可产生一个‘系统太忙未处理请求’的结果消息加到结果队列去。
     如果消息队列已满,可以考虑动态增加处理线程的个数,但处理线程组的个数必须是有限的。

④ 处理消息请求
     把消息队列出队作为临界区使用,这样所有处理线程可以及时单一地取到有效请求,否则就会进入等待状态。
     当一个处理线程进入临界区取到一个请求消息时,首先检查时间戳,如果超时则抛弃此请求消息并取下一个请求消息,如果未超时则计算出此消息已等待了多长时间T1,由此可知此消息还有多长时间T2超时(如等T1为10秒,则T2为19秒就会超时,预留一秒作为结果消息回传时间)。如果T2太小可考虑不处理此请求,因为很有可能在T2的时间内完成不了交易,这时发一个‘重试’的结果消息加到结果队列去。这样直至取到一个有效请求消息为止,然后才退出临界区。要取到一个有效请求的时间会特别短,最长是将队列出空,但队列中消息的个数是有限的。
     处理线程在执行请求消息时只等待小于T2的时间,如果在T2时间内没有完成客户端就已经超时了所以必须中止交易。另一思路是处理了T2时间后如果未完交易再延时T1时间并发消息通知客户端再等待T1时间,如果在T1时间内还未能完成交易则必须中止交易,同时通知客户端交易太大无法处理。
     如果消息处理线程在规定的时间内完成交易则将交易结果加入结果队列。
     此时再进入消息队列的出队临界区等待请求消息。

⑤ 将结果消息发给连接
     结果消息头中含有连接池中指定的连接,此时检测连接池中是否存在此连接,因为此连接可能异常中断,如果存在则将结果信息发给客户端,否则丢弃交易结果。
    结果信息可能是‘系统忙’、‘重试’、‘再等待T1时间’或‘交易成功’。


  在以上系统中客户最糟的情况是一直收到‘系统忙’消息或‘重试’ 消息,如果消息队列太大则可能是直接超时,当重试时还是收到‘系统忙’消息或‘重试’ 消息。但服务器后台却是满负荷运转,只要所有交易时间小于超时时间,则只要是经过处理的交易都会成功,否则应该加长超时时间。此时系统的瓶颈就是在数据库系统上了。

[/code:1:bbc52bf8d4]



系统结果图


 BingbingNorth 回复于:2004-01-14 17:16:18
我想对楼主提出的解决方案发表一下看法,如果有不妥当的地方,还请楼主及各位同仁多提宝贵意见。

1。连接池和请求消息处理线程
这实际上模拟了一个unix域的tcp套接字实现,如果事务处理方式是“请求-应答”方式的话,完全可以省去。

如果要实现的话工作量是比较大的。既然要做到能接受连接,当然要做到能结束连接。如果按照tcp实现的话,就要6次通讯(结束连接时,ack1和fin2合在一起发出,否则是7个),如果程序风格好的话,就要处理4次异常。另外,检测“连接非协议性关闭”问题就要实现保活定时器,这时的客户端就要具有处理服务器端发来的检测报文的能力,也就是说,要具有当服务器的能力,也加大了客户端编写的复杂性。如果用消息队列实现这一功能的话,那么编程者的水平必须较高才行。

当然,如果用tcp套接字来实现这些问题的话就比较容易,但是利用tcp的功能再构造一个tcp,让人觉得有点画蛇添足的感觉。

2。通讯中的超时处理

首先要说的是,读消息队列的操作是原子性的,不用加以互斥。Richard Stevens的《unix网络编程》中提到的“惊群”问题,经过我的测试,在aix 4.3上并不存在,我想到的解释是:各大unix供应商的开发人员在1997年看了Stevens的书后,大吃一惊,赶紧查看自己编写的程序是不是也有这个问题,并改正过来了,当然,也许有的公司的程序员光顾着在chinaunix上灌水了,就没改,到底谁改了,谁没改,大家测测看。:)

服务器根据超时时间采用不同的处理策略,看起来是很智能的,但是:

服务器认为在客户要求的时间内,可能处理完也可能处理不完,向客户端发一个“重试”包。如果服务器处理得快,在客户要求的时间内处理完了,这个包就浪费了。如果客户要求的时间内处理不完,那么客户收到这个包后,也不需要重发,只要多等一会就行了。如果客户重发的话,我感觉情形就像服务器罚客户一样:
服务器:"What can I do for you?"
客户:"Ok,let me see..."
服务器:"How can you say that to a server! Let's try again,What can I do for you?"
如果我是客户,我会说"No,sir!"

如果服务器发“再等T1时间"的话,我感觉就像我们在餐馆吃菜,催服务员:“我们那个菜怎么还没上啊?”服务员总会说:“已经在做了,马上就好,请再等一会吧。”这种情况叫做客户的超时时间没有得到服务器的尊重,更严重的是,如果碰巧这个客户比较智能化,认为自己的超时时间设得太短了,下次发请求的时候主动加大了一些,那服务质量可能越来越低(响应时间是服务质量的一个重要部分)。

无论服务器的预测多么准确,都存在服务器处理完了客户的请求后,在将应答发给客户前,客户超时停止接收的情况,这时不但要将应答包丢弃,还要进行事务回滚之类的操作。

就写这么多,大家一起研究研究问题,开开玩笑,请别见怪:)

 sca_99 回复于:2004-01-14 22:16:55
BingbingNorth提出的问题很有针对性。

1、对于连接池的实现,直接基于异步TCP,无须任何增加检测及结束操作的协议,用一个select可以了,正常的SOCKET读写操作,但要考虑速度匹配问题。这一点无须争辩,因为我常采用此方式,代码特少。

2、消息队列的出队是否锁定不做讨论,只要从书上看到有哪些方法就可以,可根据自己的具体要求借用或自己开发都无所谓。

3、如果服务器处理得够快又何必提出‘繁忙排队连续超时’呢?第三步的‘重试’消息是必要的,如果消息队列可以容纳10个消息,在2秒钟内客户提交了10请求,但这时处理线程已经全部用光,在第3秒时又有客户提交5个请求,这时最开始的5个客户的请求已经被抛弃,如果不通知那5个客户那他们就得再傻傻地等27秒。

4、出于公平性,服务器会规定一个最大的超时时间,客户可以设置比这更小的超时时间,如果完全尊重客户超时时间的话,消息处理线程只要在T2时间内不能完成任务就任务中断并回滚就可以了,这势必造成服务器资源潜在地浪费。

5、如果交易时间(排队除外)超过超时时间此交易将永远无法完成,除非将超时时间扩大。如果客户可以忍耐的话,只要多等有限的T1时间就可以完成交易。如下情景:我排队到银行处理账务,已经轮到我进行处理了,而且都处理了4分钟,但这时我已经有些不耐烦了,因为从排队到现在我已经过了10分钟了,这时银行人员告诉我最多还要6分钟就可以完成交易,你作为我的朋友却对我说别处理了,咱们重新排队,如果重新排队最少也要再花10分钟才能搞定,甚至有10分钟后根本就排不上队的危险,如果我智商是两位数的话我就不会听你的。

6、只要消息队列可容纳的请求个数小于等于处理线程的个数,客户就可以在服务器超时时间内没有得到明确的回复。再结合于上述的第5点,服务质量还会有问题吗?

7、‘无论服务器的预测多么准确,都存在服务器处理完了客户的请求后,在将应答发给客户前,客户超时停止接收的情况,这时不但要将应答包丢弃,还要进行事务回滚之类的操作。’只有在客户提交请求后而意外中断时才会出现这种情况。至于如何应付这种情况我就不愿再说了,因为连接中断是可以检测到的。

 sca_99 回复于:2004-01-14 22:33:04
此时当系统的处理能力很有限时系统是公平的,当你被别人挤出去时系统会通知你,你可以再去挤别人。如果你排到你了,系统可以会告诉你你最多只须再等一个有限时间就可以完成交易,这个时间一定会比你耍酷再去排队重新交易来的短,而且这个时间很有可能就是1秒钟

 BingbingNorth 回复于:2004-01-15 09:40:38
ca_99兄:
从您的解释可以看出,这个客户-服务器模型已经很完善了,而且已经经过了实践的检验,感谢您在百忙中回答我疑问!

 sca_99 回复于:2004-01-16 00:13:52
这种模型中如果处理能力比请求消息的速度还快的,消息管道的速度就可能是一个潜在的瓶颈了

 sunlan 回复于:2004-01-16 09:04:14
[quote:b753f2b446="sca_99"]这种模型中如果处理能力比请求消息的速度还快的,消息管道的速度就可能是一个潜在的瓶颈了[/quote:b753f2b446]

在应用系统中,要求处理进程的处理速度高于提交进程是一种过于理想化的想法。尤其是在多提交——单处理的情况下更无法保证。如果对提交进程的数量不做流量控制,则在突然大量并发的情况很有可能导致消息队列堵塞。

因此,必须对消息队列的资源进行控制。最简单、有效的办法就是使用信号量进行控制。

我在另一个帖子里描述了具体的解决办法(奇怪,那个帖子不见了),即设置信号灯,数量为最大待处理消息数,提交进程进行P(减)操作;处理进程读取一条待处理消息后做V(加)操作,以使队列不至于堵塞,起到控制流量的作用。

 sca_99 回复于:2004-01-16 12:58:00
消息管道是用的可丢弃型循环队列,根本就不用信号灯了,这需要看具体的系统要求是否可忍受消息丢弃,但超时或将超时的消息一定要丢弃,否则就多等一会儿

 chenhao_no1 回复于:2004-01-29 10:37:56
如果瓶颈是数据处理,那么下的工夫应该在数据处理。才能事半功倍。

原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
  • seo优化
    2016-08-04 08:55:01发表

    嘿嘿,自己抢个顶。

  • 中国历史
    2014-11-04 19:31:15发表

    有现成的例子吗