最近看了一些nginx相关的文章,在此把自己对nginx的理解做个总结。 nginx是一个支持高并发的web服务器。高并发的原因重要的一点来源于其异步非阻塞的事件处理模式。
进程模型
nginx是采用的是一个master进程,多个worker进程的模型。
master进程的工作:
- 创建对端口号的监听套接字
- fork处一系列的子进程
- 管理子进程的状态
子进程的工作:
- 接收新的连接请求
- 处理已经存在的连接上的事件
所有的worker进程都可以接受并处理新的请求,因为这个套接字是在master进程中打开的,子进程自动的具备读取这个套接字的能力。为了避免一个新请求到来时,所有的worker进程都被惊醒,称之为『惊群』。nginx采用了全局共享锁的方式,所有的进程中,要想监听这个套接字,就需要先获取到全局共享锁。只有获得该锁的进程,才可以监听。从而保证每次都只有一个进程,来accept新的请求。
共享锁
nginx自己实现了一个全局共享锁,实际是通过mmap创建了一块儿共享内存。在进程获取锁之后,把这块内存设置为自己的进程号。 这个锁的争夺,是通过原子操作来完成的。
epoll
epoll是linux中用来批量处理文件描述符的系统内核功能,能够实现高效得IO多路复用。
epoll的操作主要通过3个函数来完成:
1、int epoll_create(). 用于创建一个epoll对象。也是一个文件描述符. 所以在使用完之后,需要close。
2、int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event). 其中epfd是被创建的epoll描述符。 op是具体的操作命令。 fd是只要把命令应用的对象。 event 指向epoll_event 结构的指针。
OP具体的命令包括:
- EPOLL_CTL_ADD:注册新的fd到epfd中。
- EPOLL_CTL_DEL:从epfd中,删除fd。
- EPOLL_CTL_MOD:修改已经注册到epfd中的fd的事件。
epoll_event结构:
struct epoll_event
{
__uint32_t events;// 事件,按位设置
epoll_data_t data;//
}
其中epoll_data_t 结构如下:
typedef union epoll_data //长度为8个字节
{
void * ptr;//一个指针
int fd;//文件描述符
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
3、int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int
timeout);
epfd就是要等待的epoll文件描述符。 events 用于数据返回,发生事件的fd所对应的epoll_event。 maxevents 是最大文件描述符数量。 timeout是超时时间,单位是ms数量。 0 表示立即返回。
返回值表示需要处理的事件数目。 0 表示函数调用超时。