很多人学习编程技术一般都通过一本编程语言的入门书籍,然后尝试做一些例子和小项目。但是这些都不能让我们深入的学习很多的编程技巧和高深技术,当然这个时候很多有经验的学习人员就会告诉大家,找一个好的开源软件理解它的设计与实现原理,阅读开源项目的源代码,都知道源码之前了无秘密。我也承认读源码能够快速提高我们的编程能力和编程思维,我也经常研究很多项目的源代码,有些是工作需要,有些是兴趣。但是我今天想说的都不是这些,我想说的是更高一层的学习方案,就是通过自己的实践实现一个开源软件,也许这个开源软件没有任何人使用,但是在实现的这个过程中你会学习到很多,因为实现一个真正的开源软件需要使用到很多编程知识和技巧,这就会驱使你不断去学习这些编程知识和技巧,学会之后能够马上用于实践,真正实践完成以后你对这些编程知识和技巧理解就更深入了。
我目前就正在做这样一件事情,我选择的是实现一个类似nginx的高性能http服务器。选择这个的理由很简单,我在一个互联网公司,http协议和http服务器经常和我打交道,在架构设计和分布式系统实现的时候可能都需要考虑这些。我开源的地址如下:https://github.com/brucewoo/JHttpServer,如果你也对这个感兴趣可以一起参与,包括设计功能,架构和实现。做这个开源项目的唯一目的就是学习,通过实践的方式来学习。关于这个开源软件的一切我都会以博客或者wiki的方式记录,包括每一个模块实现的原理,考虑,设计等等,可能还有核心代码的解读,争取做第一个学习型的开源软件。虽然这个开源项目没有实际的需求来驱动,但是nginx就是我的目标和超越的对象,当然实现的过程中肯定会借鉴其他很多开源软件的设计思想和编程思维,也会借鉴某一个模块或者功能的实现,或者基于改进。
说了这么多一点儿也没有和标题扯上关系,今天就是为我这个开源软件写的第一个博客,实现一个高性能的网络服务器的第一个就需要选择一个很好的高性能编程框架,今天就分析这个,这个也算自己开始前的准备,学习高性能服务器编程框架:
网络服务器的编程步骤就不需要多介绍了,有网络编程知识的都很清楚。首先对网络服务器组成的基本软件模块做一个简单的说明,如下表:
模块 |
单机 |
集群 |
I/O处理单元 | 处理客户端连接,读写网络数据 | 作为介入服务器,实现负载均衡 |
逻辑单元 | 业务进程或者线程 | 逻辑服务器 |
网络存储单元 | 本地数据库,文件或者缓存 | 数据库服务器 |
请求队列 | 各单元之间的同学方式 | 各服务器之间的永久tcp连接 |
既然上面提到的第一个模块是IO处理单元,我们就分析和学习一下IO模型,IO处理单元主要处理客户端连接,接收客户端发送过来的数据,还有就是返回服务器返回给客户端的数据。下面还是通过表格的方式展示IO模型,如下:
IO模型 | 读写操作和阻塞阶段 |
阻塞 | 程序阻塞于读写函数 |
复用 | 程序阻塞于IO复用系统调用,但可同时监听多个IO事件。对IO本身的读写操作是非阻塞的 |
SIGIO信号 | 信号触发读写就绪事件,用户程序执行读写操作,程序没有阻塞阶段 |
异步 | 内核执行读写操作并触发读写完成事件,程序没有阻塞阶段。 |
下面在说说高效的事件处理模式:
三类事件,IO事件,信号和定时事件;两种高效的事件处理模式:Reactor和Proactor。
(1)先说说Reactor模式:主线程负责监听文件描述上的事件,然后把事件丢给工作线程处理。下面以epoll模型为例说明处理流程:
1) 主线程往epoll内核事件表中注册socket的读就绪事件;
2)主线程调用epoll_wait等待socket上有数据可读;
3)当socket上有数据可读时,epoll_wait通知主线程,主线程将可读事件放入请求队列;
4)工作线程被唤醒,读取客户端数据,处理客户端请求然后往epoll内核事件表中注册socket上的可写就绪事件;
5)主线程继续调用 epoll_wait等待socket可写事件;
6)socket可写,epoll_wait通知主线程,主线程放入socket可写事件到请求队列;
7)工作线程处理可写事件。
(2)再说说Proactor模式:今天已经很晚,改天再下一篇博客继续介绍。