服务器编程框架| 青训营笔记

100 阅读4分钟

这是我参与 第三届青训营-后端场 笔记创作活动的第5篇笔记

0. 点对点通讯

单线程阻塞

1. 多线程 or 多进程

概念

在 Linux 环境下多进程的应用很多,其中最主要的就是网络/客戶服务器。多进程服务器是当
客戶有请求时,服务器用一个子进程来处理客戶请求。父进程继续等待其它客戶的请求。这
种方法的优点是当客戶有请求时,服务器能及时处理客戶,特别是在客戶服务器交互系统
中。对于一个 TCP 服务器,客戶与服务器的连接可能并不⻢上关闭,可能会等到客戶提交
某些数据后再关闭,这段时间服务器端的进程会阻塞,所以这时操作系统可能调度其它客戶
服务进程,这比起迭代服务器大大提高了服务性能。
多线程服务器是对多进程服务器的改进,由于多进程服务器在创建进程时要消耗较大的系统
资源,所以用线程来取代进程,这样服务处理程序可以较快的创建。据统计,创建线程与创
建进程要快 10100 倍,所以又把线程称为“轻量级”进程。线程与进程不同的是:一个进程内
的所有线程共享相同的全局内存、全局变量等信息,这种机制又带来了同步问题。

体现

池的出现

线程池,内存池,进程池

优点

  1. 资源利用率更好;

  2. 程序设计在某些情况下更简单;

  3. 程序响应更快;

缺点

  1. 每个线程与主程序共用地址空间;

  2. 线程之间的同步和加锁控制比较麻烦;

  3. 一个线程的崩溃可能影响到整个程序的稳定性;

到达一定的线程数程度后,即使再增加CPU也无法提高性能,例如Windows Server 2003
大约是 1500 个左右的线程数就快到极限了(线程堆栈设定为1M),如果设定线程堆栈为
2M,还达不到 1500 个线程总数;
线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要
消耗较多的CPU

2. 多路 io 复用

概念

单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力。

1.select 模型

缺点

  1. 每次调用用select,都需要把fd集合从用用戶态拷⻉到内核态,这个开销在fd很多时会很大大

  2. 同时每次调用用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大大

  3. select支支持的文文件描述符数量太小小了,默认是 1024

2.poll 模型

poll将输入参数从位图改成数组,这意味着虽然数组占用的空间更大,使用poll能够监控的文

3.epoll 模型

上述select和poll的缺点是,内核要以O(n)的时间复杂度遍历文件描述符,当客戶端连接越 多,集合越大,消耗的CPU资源比较高,epoll就解决了这个问题。在内核版本>=2.6则,具 体的SelectorProvider为EPollSelectorProvider,否则为默认的PollSelectorProvider。可⻅ select和poll已经过时了,epoll才是主流。

优点

epoll_wait就只检查就绪链表,如果链表不为空,就返回就绪链表中就绪的socket,否则就 等待。只将有事件发生的 Socket 集合传递给应用程序,不需要像 select/poll 那样轮询扫描 整个集合(包含有和无事件的 Socket ),大大提高了检测的效率。

缺点

server的accpet操作是阻塞的,业务处理中的handler中的读写请求也是阻塞的。那么这样的 一种IO模式将会导致一个线程的请求没有处理完成无法处理下一个请求,这样就大大降低了 吞吐量,这将是一个严重的问题。

3. 综合使用

1. Reactor

Reactor模式实现非常简单,使用同步IO模型,即业务线程处理数据需要主动等待或询问, 主要特点是利用epoll监听listen描述符是否有响应,及时将客戶连接信息放于一个队列, epoll和队列都是在主进程/线程中,由子进程/线程来接管各个描述符,对描述符进行下一步 操作,包括connect和数据读写。主程读写就绪事件。

2. Preactor

Preactor模式完全将IO处理和业务分离,使用异步IO模型,即内核完成数据处理后主动通知 给应用处理,主进程/线程不仅要完成listen任务,还需要完成内核数据缓冲区的映射,直接 将数据buff传递给业务线程,业务线程只需要处理业务逻辑即可。

总结

单线程,一般阻塞->多线程,一般阻塞(一条连接一线程)->线程池(减少线程创建销毁开销)-

reactor(更小粒度的线程)