高性能服务器程序框架——《Linux高性能服务器编程》第8章——读书笔记
1、概述
本章的每个小节都在讲提升服务器程序性能的利器。
2、服务器模型
2.1 C/S模型
客户端 / 服务器模型。服务器监听客户的服务请求,并利用 I / O复用技术处理请求。
C/S模型非常适合资源相对集中的场合,并且它的实现简单,但其缺点也很明显:服务器是通信的中心,当访问量过大时,可能所有客户都将得到很慢的响应。下面讨论的P2P模型解决了这个问题。
2.2 P2P模型
点对点模型。网络上的每个主机,既是服务的享受者,又是服务的提供者。云计算机群可以看作P2P模型的一个典范。
P2P也有缺点:当用户之间传输的请求过多时,网络的负载加重。而且,主机之间很难发现。
所以,实际使用的P2P模型通常带有一个专门的发现服务器,发现服务器通常还提供查找服务(甚至可以提供内容服务),使每个客户端都能尽快地找到自己需要的资源。
从编程角度来讲,P2P模型可看作C/S模型的扩展:每台主机既是客户端,又是服务器。因此,仍然采用C/S模型讨论网络编程。
3、服务器编程框架
服务器框架,骨架:
Linux服务器程序有很多,他们都有个大致的框架结构,这个骨架由下面4个模块组成:
- IO处理单元: 接受连接,收发数据(也可能是逻辑单元来干)
- 逻辑单元: 处理业务逻辑,客户端请求的具体是什么东西
- 网络存储单元: 存大量数据,可有可无
- 请求队列: 模块间交互
哎,有了这四个模块,服务器总算是能实现和客户端交互的功能啦!
- I/O处理单元是等待并接受客户端连接的模块,收发数据由后面的逻辑单元完成,但I/O处理单元也能完成该工作。I/O处理单元主要实现负载均衡,他从所有逻辑服务器中选负荷最小的为客户端服务。
- 逻辑单元通常是个进程或线程。他分析并处理客户数据,向I/O处理单元或直接向客户端发送结果。服务器通常有多个逻辑单元。
- 网络存储单元不是必须的。他可以是数据库、缓存和文件,甚至可以是台独立的服务器。
- 请求队列是各个单元通信方式的抽象。
4、I/O模型
????啥玩意?干啥的?为啥存在?
IO,就是输入输出,服务器骨架里有个叫IO处理单元的模块,专门处理服务器数据的输入输出,
IO模型就是 数据输入输出的特定方式,这是前人总结好的,我们只要接受他,学习他就好了。
既然是模型,那就是已经有了大致的框架了,所以书中列出几种各具特色的IO模型。
五种I/O模型通俗理解
socket阻塞和非阻塞对connect、accept、recv、read、close等函数的影响
socket阻塞与非阻塞,同步与异步I/O模型详解
5、两种高效的【事件处理模式】
????啥玩意?干啥的?为啥存在?
既然是服务器,那肯定要和客户端交互,过程中会发生一些事情,那我们要处理这些事情,保证交互正常进行。
“事件处理模式”指的就是处理这些事情的一系列方法,这些方法都是前人总结好的,咱只要接受,学习就行。
服务器程序通常需要处理三类事件:I/O事件、信号、定时事件。后面章节会详细讨论。下面介绍两种高效的事件处理模式:Reactor 和 Proactor。
同步I/O模型通常用于实现Reactor模式,异步I/O模型则用于实现Proactor模式。不过也可以使用同步I/O方式模拟出Proactor模式。
5.1 Reactor模式
5.2 Proactor模式
理解两种事件处理模式
两种高效的事件处理模式(reactor模式、proactor模式),C/C++编码实现
6、两种高效的并发模式
服务器这么大个程序,肯定不能同时只干一件事,所以需要实现并发。
如何并发??前人也帮我们搞好了,我们直接学习就行。
并发编程的目的是让程序 “同时” 执行多个任务。
- 如果程序是计算密集型的,并发编程没有优势,任务切换使效率降低。
- 如果程序是I/O密集型的,则程序执行效率显著提升。
从实现的角度说,并发编程主要有多进程和多线程两种方式,后面会详细讨论。
下面主要讨论并发模式。并发模式是指:I/O处理单元 和 多个逻辑单元之间协调完成任务的方法。
服务器主要有两种并发编程模式:
- 半同步 / 半异步(half-sync / half-async)模式
- 领导者 / 追随者(Leader / Followers)模式
6.1 半同步 / 半异步模式
半同步 / 半异步模式中的“同步” 和 “异步”与前面的I/O模型中的“同步” 和 “异步”是完全不同的概念。
- 在I/O模型中,“同步” 和 “异步”区分的是内核向应用程序通知的是何种I/O事件(就绪事件还是完成事件),以及 该由谁完成I/O读写(应用程序还是内核)。
- 在并发模式中:
——同步:程序完全按照代码顺序执行
——异步:程序的执行要由系统事件来驱动。常见的系统事件包括中断,信号等。
半同步/半异步模式中,同步线程用于处理客户逻辑,异步线程用于处理I/O事件。
6.2 领导者/追随者模式
领导者/追随者模式是多个工作线程轮流获得事件源集合,轮流监听、处理事件的一种模式。在任意时间点,程序都仅有一个领导者线程,它负责监听IO事件。而其他线程都是追随者,它们休眠在线程池中等待成为新的领导者。当前的领导者如果检测到IO事件,首先要从线程池中推选出新的领导者线程,然后处理IO事件。此时,新的领导者等待新的IO事件,而原来的领导者则处理IO事件,二者实现了并发。
领导者/追随者模式包含如下几个组件:
- 句柄集(HandleSet)
- 线程集(ThreadSet)
- 事件处理器(EventHandler)
- 具体的事件处理器(ConcreteEventHandler)
7、有限状态机
8、池
池,就是一组资源的集合。
池提升效率的原理是:以 “空间” 换时间。我们事先预分配好足够的资源,那么程序在使用资源时就可以直接拿,不需要再分配了。
预分配资源的策略有两种:
- 开始就分配足够多,可以满足任何要求
- 开始分配一定资源,如果不够用,就再动态分配一点并加入池中
池有很多种:
- 内存池:通常用于
socket
的接收缓存和发送缓存。对于某些长度有限的客户请求,比如HTTP请求,预先分配一个大小足够(比如5000字节)的接收缓存区是很合理的。当客户请求的长度超过接收缓冲区的大小时,我们可以选择丢弃请求或者动态扩大接收缓冲区。 - 进程池和线程池:多用于并发编程。当我们需要一个工作进程或工作线程来处理新到来的客户请求时,我们可以直接从进程池或线程池中取得一个执行实体,而无须动态地调用
fork
或pthread_create
等函数来创建进程和线程。 - 连接池:是服务器预先和数据库程序建立的一组连接的集合。当某个逻辑单元需要访问数据库时,它可以直接从连接池中取得一个连接的实体并使用之。待完成数据库的访问之后,逻辑单元再将该连接返还给连接池。