高性能服务器程序框架


将服务器解构成以下三个主要模块:

  • I/O处理单元:四种I/O模型和两种高效事件处理模式;
  • 逻辑单元:逻辑单元的两种高效并发模式,以及高效的逻辑处理方式——有限状态机;
  • 存储单元

1.服务器模型

1.1 C/S模型

     TCP/IP协议在设计和实现上并没有客户端和服务器的概念,在通信过程中所有机器都是对等。但是如下图1.1C/S模型所示:所有客户端都通过访问服务端都通过采用访问服务器获取资源C/S模型

     C/S模型:服务器启动后,首先创建一个(或者多个)监听socket,并调用bind函数将其绑定到服务器感兴趣的端口上,然后调用listen函数等待客户端连接。待服务器稳定之后,客户端调用connect函数向服务器发起连接了。
     由于客户端的连接请求是随机到达的异步事件 ,服务器需要某种特定的I/O模型来监听这一事件,下图为服务器使用的是I/O复用技术之一的select系统调用:当监听到连接请求后,服务器调用accept函数接受他,并分配一个逻辑单元为新的连接服务。逻辑单元可以是新创建的子进程、子线程或者其他。C/S模型非常适合资源相对集中的场合,但是缺点也比较明显:当访问量过大时,可能所有的客户都将得到很慢的响应。
在这里插入图片描述

1.2 P2P模型

     P2P(Peer to Peer, 点对点)模型比C/S模型更符合网络通信的实际情况,摒弃了以服务器为中心的格局,让网络上的所有主机重新回归对等的地位。P2P模型使得每台计算机在消耗服务的同时也为别人提供服务,缺点也明显:当用户之间的请求过多时,网络负载加重。由于主机之间很难相互发现,P2P模型还带有一个专门的发现服务器,通常还提供查找服务(甚至还可以提供内容服务)。

2. 服务器编程框架

基本框架:
在这里插入图片描述
     该图技能描述一台服务器也能描述一个服务机群,两种情况含义和功能如下:

模块单个服务器程序服务器机群
I/O处理单元处理客户连接,读写网络数据作为接入服务器,实现负载均衡
逻辑单元业务进程或线程逻辑服务器
网络存储单元本地数据库、文件或缓存数据库服务器
请求队列各单元之间的通信方式各服务器之间的永久TCP连接
  • I/O处理单元是服务器管理客户连接的模块。通常完成以下工作:等待并接受新的客户连接,接受客户数据,并将服务器响应数据返回给客户端。但是数据的收发不一定在I/O处理单元中执行,也可能在逻辑单元涨执行,具体实现方式取决于事件处理模式。对于一个服务器机群来说,I/O处理单元是一个专门的接入服务器,它实现负载均衡,从所有逻辑服务器中选取负荷最小的一台为新客户服务。

  • 逻辑单元通常是一个进程或线程。它分析或处理客户数据,然后将结果传递给I/O处理单元或者直接发送给客户端,具体实现方式取决于事件处理模式,对于服务器机群来说,一个逻辑单元本身就是一台逻辑服务器。网络中通常拥有多个逻辑单元,以实现对多个客户任务的并行处理。

  • 网络存储单元可以是数据库、缓存和文件,甚至是一台独立的服务器。但他不是必须的,比如ssh、telnet等登陆服务不要这个单元。

  • 请求队列是各单元之间通信方式的抽象。I/O处理单元接受到客户请求时,需要以某种方式通知一个逻辑单元来处理该请求。同样,多个逻辑单元同时访问一个存储单元时,也需要采用某种机制来协调处理竞态条件。请求队列通常被实现为的一部分。对于服务器机群而言,请求队列是各服务器之间预先建立的、静态的、永久的TCP连接。这种TCP连接能够提高服务器之间交换数据的效率,避免了动态建立TCP连接导致的额外系统开销。

3. I/O模型

     在socket创建中默认是阻塞的,可以给socket系统调用第二个参数传递SOCK_NONBLOCK标志,或者通过fcntl系统调用的F_SETFL命令将其设置为非阻塞的。阻塞和非阻塞概念能应用与所有的文件描述符,称阻塞的文件描述符为阻塞I/O,称非阻塞的文件描述符为非阻塞I/O。

3.1 阻塞I/O

     阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的时间发生为止。例如,客户端通过connect向服务器发送连接时,connect将首先发送同步报文段给服务器,然后服务器返回确认报文段。如果服务器的确认报文段没有立即到达客户端,则connect调用会被挂起,直到客户端收到确认报文段并唤醒connect调用。在socket的基础API中,可能被阻塞的系统调用包括acceptsendrecvconnect

在这里插入图片描述

3.2非阻塞I/O

     非阻塞的I/O调用总是立即返回的,而不管事件是否已经发生。如果事件没有立即发生,系统调用会返回-1,和出错情况一样。此时需要通过errno来区分两种情况。只有在检查无数据的时候是非阻塞的,在数据到达的时候依旧要等待数据从内核复制到用户空间,因此它还是同步I/O

在这里插入图片描述

     只有在事件已经发生的时候操作非阻塞I/O,才能提高程序的效率。因此,非阻塞I/O通常要和其他的I/O通知机制一起使用,比如I/O复用SIGNO信号:
     I/O复用是最常用的I/O通知机制。应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪事件通知给应用程序。Linux常用的I/O复用函数为selectpollepoll_wait。I/O复用函数本身是阻塞的,能提高效率是因为具有能够同时监听多个I/O事件的能力。
     SIGNO信号也可以报告I/O事件。可以为一个文件描述符指定宿主进程,那么被指定的宿主进程就能够捕获SIGIO信号,这样当文件描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,也就可以通过信号处理函数对目标文件描述符执行非阻塞I/O的相关操作。

POSIX(可移植操作系统接口)把同步IO操作定义为导致进程阻塞直到IO完成的操作,反之则是异步IO。

  • 同步I/O模型
         阻塞I/O、I/O复用和信号驱动I/O都属于同步I/O模型,I/O的读写都发生在I/O事件之后,由应用程序来完成。
  • 异步I/O模型
         用户可以直接对I/O执行读写操作,这些操作会告诉内核用户读写缓冲区的位置,以及I/O操作完成之后内核通知应用程序的方式。异步I/O的读写总是立即返回,而不论I/O是否被阻塞的,因为真正的读写已经由内核接管。同步I/O模型要求用户代码自行执行I/O操作,而异步I/O机制则由内核来执行I/O操作。同步I/O向应用程序通知的是I/O就绪事件,而异步I/O向应用程序通知的是I/O完成事件。

3.3 I/O模型对比

I/O模型读写操作和阻塞阶段
阻塞I/O程序阻塞于读写函数
I/O复用程序阻塞与I/O复用系统调用,但可同时监听多个I/O事件,对I/O本身的读写是非阻塞的
SIGIN信号信号触发读写就绪事件,用户程序执行读写操作。程序没有阻塞
异步I/O内核执行读写操作并触发读写完成事件。程序没有阻塞
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值