以前对nginx的认识就只是停留在一个反向代理服务器上。目前nginx也很火,仅次于apache和微软的iis。nginx的主要特点就是占用系统资源少,并发能力强,稳定性好。
第1,2章主要讲了下基本的代码分析的准备工作,介绍了一些便于调试代码的工具,以及在linux环境下运用gdb对其代码进行调试,这里不多描述。
第3章主要介绍了Nginx的进程模型。一般情况下,在启动Nginx后,将会出现多个Nginx进程,各个进程各司其职共同完成对客户端处理响应的任务。从整体架构上来看,有监控进程(也叫做主进程),也有工作进程以及缓存进程。监控进程大部分时间都处于挂起等待状态,直到监控进程收到信号为止,通俗点来说也就是有客户端发送请求。对于nginx的工作进程,此时它充当了客户端与后端服务器之间的代理服务器,它的重心主要就是客户端与后端服务器之间的I数据读写的I/O交互事件,而不是进程信号。关于缓存进程,它不处理客户端的请求,就是它不管数据的读写操作,它只管超时操作。如果开启缓存功能,则会同时开启两个缓存进程,分别是缓存管理进程和缓存加载进程。缓存管理进程的主要任务就是清理超时缓存文件,限制缓存文件的总大小,此后这个过程来回往复,一直到整个进程退出为止。缓存加载进程一般是在nginx正常启动后(一般为60秒)将磁盘中上次缓存的对象加载到内存中,这个过程一般是一次性的,当缓存加载进程完成它的任务以后它就自动退出了。
进程间通信,这里介绍了第一种channel方式的通信,其实channel就是一个元素个数为2的一个数组,里面存放着一对socket描述符,对于继承了父进程的子进程,他们都拥有了这一对socket描述符,而Nginx将channel[0]给父进程使用,channel[1]给子进程使用,利用数组下标的不同来错开的使用不同的描述符,从而来实现父子进程之间的通信。但是子进程并没有向父进程发送任何消息,子进程之间也没有相互进行通信的逻辑,即channel通信目前只作为父进程来给子进程发送消息使用。
进程间通信的第二种方式,也是在linux下最有效的进程通信的方式之一,共享内存。在nginx中,共享内存使用一个结构体来表示,其中封装的有共享内存的名字(主要用作共享内存的唯一标识,便于让nginx知道我们想使用的哪一块共享内存),大小,标签(主要用于解决不同模块使用相同名字的共享内存而引发的冲突,使用标签后,比如模块A和模块B以相同的名称sa去获得模块A所创建的共享内存sa,模块A将获得它之间创建的共享内存sa的引用,而模块B则将获得一个共享内存sa已有他用的错误提示)以及分配内存的起始地址。在Nginx配置解析完成后,所有共享内存结构体将连在一起构成一个全局链表。Nginx此时通过遍历链表来实现实际的分配内存,管理机制初始化(例如锁,slab)等。一个完整的共享内存的初始化主要基于slab高效的访问机制,而关于共享内存的使用,由于是多进程共同使用共享内存,则要考虑到进程间的互斥问题,记得以前在上java课的时候老师讲多线程的时候也讲过锁的机制,运用在这里大概就是强制同一时刻只能有一个进程去访问共享内存。 关于Nginx的slab机制主要是两点:缓存和对齐,缓存意味着提前申请好内存并对内存进行划分形成内存池,当我们需要一块内存空间时,Nginx直接从内存池中取出一块大小合适的内存空间即可,而内存释放也是把内存又重新返还给内存池,而不是操作系统。对齐意味着内存的申请总是遵循2的幂次方,8,16,32,64,如果只申请33个字节的内存,也将获得64字节的内存,虽然存在内存的浪费,但有利于提升性能。Nginx的共享内存与slab机制共同使用,对于共享内存(一个以结构体为节点的全局链表),在初始化完成之后,就由slab机制来对它进行内部的划分以及管理。