ACE之旅 (二)

 

                                       ACE之旅 (二)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

                 ——如何处理超过100个客户端的连接

                 (一)前记

 之所以学习ACE,是因为尝试利用ACE解决平时工作中遇到的问题。

   在平时从事分布式程序开发,直接调用系统的Socket API,很经常遇到如下的问题:

  1:程序被严重阻塞,导致程序滞留在某个地方。

  2:对于Socket API 返回的错误做了不当的处理。

  3:对客户端的并发处理能力较低。

4:对客户端的响应严重延迟。

以上的问题,也是我学习ACE的强烈动力。看到ACE的技术文档,有种冲动,寻找到解决问题的冲动。

                  (二)使用相关接口的注意事项

程序被严重阻塞,导致程序滞留在某个地方的原因,是因为调用具有阻塞作用的函数。如下的函数将会产生阻塞。

1accept

2recvrecvfrom

3sendsendto

LinuxUnix下可以使用以下的方式在涉及I/O接口上设置超时:

1)调用alarm,它在指定超时满慢时产生SIGALRM信号。

2)在select中阻塞等待I/Oselect有内置的时间限制),以此代替直接阻塞在recvrecvfromsendsendto

3)使用较新的SO_RCVTIMEO SO_SNDTIMEO套接口选项。

现在简要分析一下:

1)在多线程下正确使用信号却非常困难,因此方式1)建议在末线程化或单线程化的程序中使用。

2)使用方式2)在select调用返回后,在可读的套接口调用acceptrecvrecvfrom 也会产生阻塞。

 在调用accept的时候,如果客户端意外退出。

 在调用recvrecvfrom的时候,在等待读取指定长度后才返回。

 所以在使用方式2),还要对套接口使用方式3)或者设置其非阻塞方式。

 

3)在使用ACE编程的时候,对于ACE_SOCK_Acceptor对象调用enable设置

ACE_NONBLOCK标志。

   ACE_SOCK_Stream对象调用recv*(recv*_n) send*( send*_n)接口的时候,要传进非空的ACE_Time_Value 指针。

   但是调用recv*send* recv*_nsend*_n 是有区别的。最近在编程的时候,我在传进非空的ACE_Time_Value 指针,recv*_nsend*_n 的返回值进行判断,结果都返回-1

    后来改成recv*send*对返回值判断,结果是返回实际的操作值。后来看了ACEACE_SOCK_Stream 如下的描述,才知道必须对size_t *bytes_transferred进行判断才是合理的判断。

             如何降低对客户端响应延迟

对这个问题的思考,是想要对实际遇到的问题找到一个比较好的解决方案。

多数分布式程序设计导致客户端响应延迟的主要原因并发处理的客户端请求的机制不够理想。

在实际的工作中,我遇到如下的通信模式:

   客户端Client 通过中间服务器Servat Server获取某个信息。其通信图如下:

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />

    

 

                                                   图一

   我利用ACE组件进行验证我的并发实现响应,结果发现当客户端达到一定数量,并发的响应延迟比较严重。

   如下是并发实现模式:

  

 

                       图二

     对该模式,写了程序测试,测试效果如下:

1:处理单个客户的每个请求平均延迟是2秒。

2:在第1个客户端还在通信的情况下,响应第23个客户端的第一个请求延迟是2秒。

  但是在处理第4个客户端的第一个请求延迟是6秒。

  假设客户端123……N,按照顺序连接过来,Schedule接收每个客户端的Req的时间为t,那么第N个客户端的第一个请求被回复的时间

           TN = (N-1)*t + 2

 经过多次运行程序,统计t = 0.7秒。

 因此如果N >= 9,处理第N个的第一个请求的延迟TN >= 16秒。

虽然图二的模型是使用多线程,但是并发的模式存在以下的缺陷:

1:单线程Schedule  进行Recv Client Req,再分派给多个Servat处理,瓶颈是在Schedule的排队延迟。

   在这里说明单个线程对客户端轮询处理,满足在合理的时间延迟内处理的客户端是很有限的。

   多线程也不一定能够提高程序的并发处理效率,如果并发模式是不合理的。

由于程序的瓶颈先是在单个Schedule的队列延迟。

   因此我稍微做了修改并发的模式,如下是修改后的模式:

  

 

                               图三

经过测试如下:

1:处理单个客户端的第一个请求延迟是2秒。

2:如果程序中有K(K = 5)个客户端,那么第N个客户端的第一个请求被回复的最大延迟时间:

     N = K*q + r0<= r < k

   TN = (q + 1)*t + 2

   经过测试,当最大延迟是6秒的时候,N >= 17。在延迟的效率是明显有点提高。

  但是我在测试程序的过程中,发现如果处理并发处理63个客户端的请求时候,时间竟然延迟到60秒左右。

  因此这跟我要并发处理100多个客户端的目标还差远呢。而且在单进程内,SOCKET的最大句柄数是有效。

  因此距离处理N>=100个目标还是需要探索。

 

 

发布了49 篇原创文章 · 获赞 24 · 访问量 9万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章