请选择 进入手机版 | 继续访问电脑版

程序人生

 找回密码
 注册

QQ登录

只需一步,快速开始

程序人生 门户 软件工程 查看内容

高性能服务器程序框架

2016-4-12 10:07| 发布者: sean| 查看: 759| 评论: 0

摘要: 将服务器解构为如下三个主要模块:I/O处理单元。包含:四种I/O模型和两种高效事件处理模式逻辑单元。包含:两种高效并发模式,以及高效的逻辑处理方式—有限状态机存储单元。如db,文件等将按照如下流程去学习:服务 ...
将服务器解构为如下三个主要模块:

I/O处理单元。包含:四种I/O模型和两种高效事件处理模式
逻辑单元。包含:两种高效并发模式,以及高效的逻辑处理方式—有限状态机
存储单元。如db,文件等
将按照如下流程去学习:

服务器模型
服务器编程框架
I/O模型
并发模式
如下思维导图:

一.服务器模型

分为:

  • C/S模型(大多数)
  • P2P模型(少数,点对点)

1. C/S模型

图1 CS模型

C/S模型的逻辑很简单。服务器启动后,首先创建一个或多个监听socket,并调用bind函数将其绑定到服务器指定的端口上,然后调用listen函数等待客户连接。服务器稳定运行之后,客户端就可以调用connect函数向服务器发起连接了。

由于客户连接请求是随机到达的异步事件,服务器需要使用某种I/O模型来监听这一事件。I/O模型有多种:如下是其中的一种。

图2 I/O复用技术之一的select系统调用

上图分析如下:

  • 当监听到连接请求后,服务器就调用accept函数接受它,并分配一个逻辑单元为新的连接服务。
  • 逻辑单元可以是新创建的子进程、子线程或者其他。上图服务器给客户端分配的逻辑单元是由fork系统调用创建的子进程
  • 逻辑单元读取客户请求,处理该请求,然后将处理结果返回给客户端。
  • 客户端接收到服务器反馈的结果之后,可以继续向服务器发送请求,也可以立即主动关闭连接。
  • 如果客户端主动关闭连接,则服务器执行被动关闭连接。至此,双方的通信结束。
  • 需要注意的是,服务器在处理一个客户请求的同时还会继续监听其他客户请求,否则就变成了效率低下的串行服务器了(必须先处理完前一个客户的请求,才能继续处理下一个客户请求)

CS模型的优缺点:

C/S模型非常适合资源相对集中的场合,并且它的实现也很简单,但其缺点也很明显:服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应。下面讨论的P2P模型解决了这个问题。

2. P2P模型

P2P(Peer to Peer,点对点)模型比C/S模型更符合网络通信的实际情况。它摒弃了以服务器为中心的格局,让网络上所有主机重新回归对等的地位。

图3 P2P模型

P2P模型的优缺点:

  • 优点:使得每台机器在消耗服务的同时也给别人提供服务,这样资源能够充分、自由地共享。云计算机群可以看作P2P模型的一个典范。
  • 缺点:当用户之间传输的请求过多时,网络的负载将加重。

从编程角度来讲,P2P模型可以看作C/S模型的扩展:每台主机既是客户端,又是服务器。因此,我们仍然采用C/S模型来讨论网络编程。

二. 服务器编程框架

图4 服务器基础框架

该图既能用来描述一台服务器,也能用来描述一个服务器机群。两种情况下各个部件的含义和功能如表所示:

1. I/O处理单元

I/O处理单元是服务器管理客户连接的模块

它通常要完成以下工作:

  • 等待并接受新的客户连接
  • 接收客户数据
  • 将服务器响应数据返回给客户端。

但是,数据的收发不一定在I/O处理单元中执行,也可能在逻辑单元中执行,具体在何处执行取决于事件处理模式。

对于一个服务器机群来说,I/O处理单元是一个专门的接入服务器。它实现负载均衡,从所有逻辑服务器中选取负荷最小的一台来为新客户服务。(相当于负载均衡服务器)

2.逻辑单元

一个逻辑单元通常是一个进程或线程。

它的工作:

  • 分析并处理客户数据
  • 将结果传递给I/O处理单元或者直接发送给客户端(具体使用哪种方式取决于事件处理模式)
  • 对服务器机群而言,一个逻辑单元本身就是一台逻辑服务器。服务器通常拥有多个逻辑单元,以实现对多个客户任务的并行处理。

3.网络存储单元

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

4.请求队列

请求队列是各单元之间的通信方式的抽象。

I/O处理单元接收到客户请求时,需要以某种方式通知一个逻辑单元来处理该请求。同样,多个逻辑单元同时访问一个存储单元时,也需要采用某种机制来协调处理竞态条件。请求队列通常被实现为的一部分。

对于服务器机群而言,请求队列是各台服务器之间预先建立的、静态的、永久的TCP连接。这种TCP连接能提高服务器之间交换数据的效率,因为它避免了动态建立TCP连接导致的额外的系统开销。

三. I/O模型

是服务器编程框架中I/O处理单元的一个细分

从两大方面开始:

  • 阻塞与非阻塞
  • 同步与异步

在知乎回答:“怎样理解阻塞非阻塞与同步异步的区别?”中理解两者的概念和区别。

1. 阻塞与非阻塞

基础socket默认是阻塞的,我们可以给socket系统调用的第2个参数传递SOCK_NONBLOCK标志,或者通过fcntl系统调用的F_SETFL命令,将其设置为非阻塞的。

注:阻塞和非阻塞的概念能应用于所有文件描述符,而不仅仅是socket。我们称阻塞的文件描述符为阻塞I/O,称非阻塞的文件描述符为非阻塞I/O。

1.1 阻塞I/O

针对阻塞I/O执行的系统调用可能因为无法立即完成而被操作系统挂起,直到等待的事件发生为止 socket的基础API中,可能被阻塞的系统调用包括acceptsendrecvconnect

1.2 非阻塞I/O

针对非阻塞I/O执行的系统调用则总是立即返回,而不管事件是否已经发生。

如果事件没有立即发生,这些系统调用就返回-1,和出错的情况一样。此时我们必须根据errno来区分这两种情况。对acceptsendrecv而言,事件未发生时errno通常被设置成EAGAIN(意为“再来一次”)或者EWOULDBLOCK(意为“期望阻塞”);对connect而言,errno则被设置成EINPROGRESS(意为“在处理中”)。

显然,我们只有在事件已经发生的情况下操作非阻塞I/O(读、写等),才能提高程序的效率。因此,非阻塞I/O通常要和其他I/O通知机制一起使用,比如I/O复用和SIGIO信号。

1). I/O复用

I/O复用是最常使用的I/O通知机制。

I/O复用使得程序能同时监听多个文件描述符。应用程序通过I/O复用函数向内核注册一组事件,内核通过I/O复用函数把其中就绪的事件通知给应用程序。

网络编程中使用I/O复用的场景:

  • 客户端程序需要同时处理多个socket时,如非阻塞connect程序
  • 客户端程序同时处理用户输入和网络连接时,如聊天室程序
  • TCP服务器要同时处理监听socket和连接socket时 (这是I/O复用使用最多的场合)
  • 服务器要同时处理TCP请求和UDP请求时

Linux上常用的I/O复用函数是selectpollepoll_wait

需要指出的是,I/O复用函数本身的调用是阻塞的,它们能提高程序效率的原因在于它们具有同时监听多个I/O事件的能力。

2).SIGIO信号(信号驱动I/O)

SIGIO信号也可以用来报告I/O事件

我们可以为一个目标文件描述符指定宿主进程,那么被指定的宿主进程将捕获到SIGIO信号。这样,当目标文件描述符上有事件发生时,SIGIO信号的信号处理函数将被触发,我们也就可以在该信号处理函数中对目标文件描述符执行非阻塞I/O操作了。

2. 同步与异步

从理论上说,阻塞I/O、I/O复用和信号驱动I/O都是同步I/O模型。因为在这三种I/O模型中,I/O的读写操作,都是在I/O事件发生之后,由应用程序来完成的。

而POSIX规范所定义的异步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完成事件

Linux环境下,aio.h头文件中定义的函数提供了对异步I/O的支持

4种I/O模型的差异:

四.两种高效的事件处理模式

也是服务器编程框架中I/O处理单元的一个细分

服务器程序通常需要处理三类事件:

  • I/O事件
  • 信号
  • 定时事件

鲜花

握手

雷人

路过

鸡蛋

相关阅读

最新评论


关于程序人生网|小黑屋|手机版|Archiver|

程序人生 | QQ

粤公网安备 44040202000007号

( 粤ICP备13038131号-5 )

返回顶部