2.2 nginx事件处理简单介绍
假设nginx使用的是epoll 【不同linux发行版本不同,centos是epoll的IO模型】。
nginx需要将所有关心的fd(file describe 文件描述符【linux基于文件表示网络io资源】)注册到epoll,添加方法声明如下:
static ngx_int_t ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
方法第一个参数是ngx_event_t结构体指针,代表关心的一个读或者写事件;nginx为事件可能会设置一个超时定时器,从而能够处理事件超时情况;定义如下:
struct ngx_event_s {
ngx_event_handler_pt handler; //函数指针:事件的处理函数
ngx_rbtree_node_t timer; //超时定时器,存储在红黑树中(节点的key即为事件的超时时间)
unsigned timedout:1; //记录事件是否超时
};
一般都会循环调用epoll_wait监听所有fd,处理发生的读写事件;epoll_wait是阻塞调用,最后一个参数timeout是超时时间,即最多阻塞timeout时间如果还是没有事件发生,方法会返回;
nginx在设置超时时间timeout时,会从上面说的记录超时定时器的红黑树中查找最近要过时的节点,以此作为epoll_wait的超时时间,如下面代码所示;
ngx_msec_t ngx_event_find_timer(void)
{
node = ngx_rbtree_min(root, sentinel);
timer = (ngx_msec_int_t) (node->key - ngx_current_msec);
return (ngx_msec_t) (timer > 0 ? timer : 0);
}
同时nginx在每次循环的最后,会从红黑树中查看是否有事件已经过期,如果过期,标记timeout=1,并调用事件的handler;
void ngx_event_expire_timers(void)
{
for ( ;; ) {
node = ngx_rbtree_min(root, sentinel);
if ((ngx_msec_int_t) (node->key - ngx_current_msec) <= 0) { //当前事件已经超时
ev = (ngx_event_t *) ((char *) node - offsetof(ngx_event_t, timer));
ev->timedout = 1;
ev->handler(ev);
continue;
}
break;
}
}
nginx就是通过上面的方法实现了socket事件的处理,定时事件的处理;
ngx_http_limit_req_module模块解析
ngx_http_limit_req_module模块是对请求进行限流,即限制某一时间段内用户的请求速率;并且使用的是令牌桶算法;
3.1配置指令
ngx_http_limit_req_module模块提供一些配置指令,供用户配置限流策略
//每个配置指令主要包含两个字段:名称,解析配置的处理方法
static ngx_command_t ngx_http_limit_req_commands[] = {
//一般用法:limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
//$binary_remote_addr表示远程客户端IP;
//zone配置一个存储空间(需要分配空间记录每个客户端的访问速率,超时空间限制使用lru算法淘汰;注意此空间是在共享内存分配的,所有worker进程都能访问)
//rate表示限制速率,此例为1qps
{ ngx_string(“limit_req_zone”),
ngx_http_limit_req_zone,
},
//用法:limit_req zone=one burst=5 nodelay;
//zone指定使用哪一个共享空间
//超出此速率的请求是直接丢弃吗?burst配置用于处理突发流量,表示最大排队请求数目,当客户端请求速率超过限流速率时,请求会排队等待;而超出burst的才会被直接拒绝;
//nodelay必须与burst一起使用;此时排队等待的请求会被优先处理;否则假如这些请求依然按照限流速度处理,可能等到服务器处理完成后,客户端早已超时
{ ngx_string(“limit_req”),
ngx_http_limit_req,
},
//当请求被限流时,日志记录级别;用法:limit_req_log_level info | notice | warn | error;
{ ngx_string(“limit_req_log_level”),
n