码迷,mamicode.com
首页 > 其他好文 > 详细

高性能、高并发网络通信系统的架构设计

时间:2014-05-10 08:39:49      阅读:326      评论:0      收藏:0      [点我收藏+]

标签:style   blog   tar   ext   color   c   

1 引言


    随着互联网和物联网的高速发展,使用网络的人数和电子设备的数量急剧增长,其也对互联网后台服务程序提出了更高的性能和并发要求。本文的主要目的是阐述如何进行高并发、高性能网络通信系统的架构设计,以及这样的系统的常用技术,但不对其技术细节进行讨论。本篇只起抛砖引玉的之效,如有更好的设计方案和思路,望您共分享之![注:此篇用select来讲解,如想用epoll,设计思路是一致的]

    我们首先来看看课本或学习资料上关于处理并发网络编程的三种常用方案,以及对应的大体思路和优缺点,其描述如下所示:

    1)、IO多路复用

     ->思路:单进程(非多线程)调用select()函数来处理多个连接请求。

     ->优点:单进程(非多线程)可支持同时处理多个网络连接请求。

      ->缺点:最大并发为1024个,当并发数较大时,其处理性能很低。

    2)、子进程处理

      ->思路:当连接请求过来时,主进程fork产生一个子进程,让子进程负责与客户端连接进行数据通信,当客户端主动关闭连接后,子进程结束运行。

      ->优点:模式简单,易于理解;连接请求很小时,效率较高。

      ->缺点:当连接请求过多时,系统资源很快被耗尽。比如:当连接请求达到10k时,难道要启动10k个进程吗?

    3)、线程处理

      ->思路:首先启动多个工作线程,而主线程负责接收客户端连接请求,工作线程负责与客户端通信;当连接请求过来时,ACCEPT线程将sckid放入一个数组中,工作线程中的空闲线程从数组中取走一个sckid,对应的工作线程再与客户端连接进行数据通信,当客户端主动关闭连接后,此工作线程又去从指定数组中取sckid,依次重复运行。

      ->优点:拥有方案②的优点,且能够解决方案②的缺点。

      ->缺点:不能支持并发量大的请求和量稍大的长连接请求。


    通过对以上三种方案的分析,显然以上方案均不能满足高并发、高性能的服务器的设计要求。针对以上设计方案问题的存在,那我们又该如何设计才能做到既满足高并发,又满足高性能呢?


2 设计方案


2.1 接收与处理


    IO多路复用中1个select()最多可管理1024个Socket FD,而如果要求并发量达到10k时,其显然大大超过了1个select()的管理能力。此问题该如何解决?

    很容易知道10k约等于10 * 1024并发,因此,需要大约10个select()才能有效管理,那该如何调用10个select()来管理10k的并发呢?

    因FD在进程之间是独立的,虽然子进程在创建之时,会继承父进程的FD,但后续连接产生的FD却无法让子进程继承,因此,要实现对10k并发的有效管理,使用多线程实现高并发是唯一的选择。即:每个线程调用1个select(),而每个select()最多可以管理1024个并发。

    在理想情况下,启动N个接收线程,便可管理N *1024的并发。比如:启动100个接收线程,便可管理100 * 1024 = 100k的网络并发。通过此方案,便可满足高并发的设计要求。


    为了进一步的提高处理性能,我们可以对线程进行分工划分:

        Recv线程池:Recv线程的集合 - 专门负责与多个客户端连接进行通信,也就是负责接和发送数据;

        Work线程池:Work线程的集合 - 专门负责处理Recv线程接收到的数据。

    Recv线程和Work线程协助处理的流程大体过程:

        ①、Recv线程将接收到的数据随机的放入到某个接收队列中;[注:随机放入起着负载均衡的作用]

        ②、接收完毕之后,再随机通知其中1个Work线程到指定的接收队列中去取数据;[注:随机通知起着负载均衡的作用]

        ③、Work线程接收通知后,到指定的接收队列中取走数据;

        ④、Work线程根据取到的数据信息做相应的处理。

    故,其大体设计架构如下图所示:[注:Recv线程数:接收队列数:工作线程数 = N:M:X的比例根据具体场景做适当的调整]

bubuko.com,布布扣

图1 数据接收与处理


2.2 连接分发


    总所周知,使用TCP绑定指定端口后,其他线程或进程想再次绑定指定端口时,肯定会失败。如果让每个Recv线程将Listen FD加入到select()的FD_SET中进行监听,当有1个新的连接到来时,所有的Recv线程都会被惊醒,这也就是“惊群”现象的一种,这显然是我们应该避免的。为了避免此问题的出现,最好让1个Accept线程专门负责Accept客户端的连接,再将新生成的Socket FD随机的分发给某1个Recv线程,该Recv线程再将FD加入select()的FD_SET中进行监听,从而实现Recv线程与客户端的通信。[注:随机分发起着负载均衡的作用]
bubuko.com,布布扣
图2 连接分发


2.3 消息通知机制


    看到这时你可能还会有如下几个疑问:

        ①、Accept线程通过何种方式将新连接的Socket FD分发给Recv线程呢?

        ②、Recv线程接收数据完毕后,通过何种方式通知Work线程到指定的接收队列取数据呢?

    在之前的一篇博文《日志系统系能对比分析》中对TCP、UDP、Unix-TCP、Unix-UDP的性能做了对比测试和分析,可发现在这几种传输协议中,Unix-UDP的效率是最高的,因此,本系统内部FD分发、消息通知等均通过UNIX-UDP协议传输。


    此设计思路在其他的应用场景可做适当的扩展变更,产生更适合具体应用场景的设计方案。总之,要做到高并发、高性能的网络通信系统,往往需要以下技术做支撑:

    ①非阻塞IO ②事件触发机制 ③线程池机制 ④负载均衡机制 ⑤内存池机制 ⑥缓存机制 ⑦高效算法和技巧的使用等等。

作者:邹祁峰 

 2014年05月04日

高性能、高并发网络通信系统的架构设计,布布扣,bubuko.com

高性能、高并发网络通信系统的架构设计

标签:style   blog   tar   ext   color   c   

原文地址:http://blog.csdn.net/qifengzou/article/details/23912267

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!