nginx 限速指令limit_rate

近在学习Nginx(著名的高性能http服务器和反向代理服务器)的模块开发,在此分享nginx的限速实现核心代码。

Nginx的http核心模块ngx_http_core_module中提供limit_rate这个指令可以用于控制速度,limit_rate_after用于设置http请求传输多少字节后开始限速。
另外两个模块ngx_http_limit_conn_modulengx_http_limit_req_module分别用于连接数和连接频率的控制。

限制速度的配置指令简单易懂,限速支持固定的数值

[plain]  view plain copy
  1. location /flv/ {  
  2.     limit_rate_after 500k;  
  3.     limit_rate       50k;  
  4. }  

查看nginx源代码,可以发现ngx_http_write_filter_module.c源文件具体实现了速度的控制,nginx的特点是高度模块化,从名字可以看出这个文件其实也是一个filter模块(nginx中的模块分handler,filter,upstream等三类),这个模块属于filter类别。

[cpp]  view plain copy
  1. static ngx_int_t  
  2. ngx_http_write_filter_init(ngx_conf_t *cf)  
  3. {  
  4.     ngx_http_top_body_filter = ngx_http_write_filter;  
  5.    
  6.     return NGX_OK;  
  7. }  

模块挂载了一个函数在filter的顶端(经过编译链接后此模块即被“压”到filter“链表”的尾部),用于控制数据的输出,这个函数里面就包含了速度的控制。

[cpp]  view plain copy
  1. if (r->limit_rate) {  
  2.     limit = r->limit_rate * (ngx_time() - r->start_sec + 1)  
  3.             - (c->sent - clcf->limit_rate_after);  
  4.   
  5.     if (limit <= 0) {  
  6.         c->write->delayed = 1;  
  7.         ngx_add_timer(c->write,  
  8.                       (ngx_msec_t) (- limit * 1000 / r->limit_rate + 1));  
  9.   
  10.         c->buffered |= NGX_HTTP_WRITE_BUFFERED;  
  11.   
  12.         return NGX_AGAIN;  
  13.     }  
  14.   
  15.     if (clcf->sendfile_max_chunk  
  16.         && (off_t) clcf->sendfile_max_chunk < limit)  
  17.     {  
  18.         limit = clcf->sendfile_max_chunk;  
  19.     }  
  20.   
  21. }  

上面代码的逻辑是:如果配置文件设置了限速(limit_rate是速度值,size_t类型,0表示不限速)

  1. 当c->sent<clcf->limit_rate_after时,说明还没有到需要限速的阈值,计算limit值大于0(下一次应该传输位置偏移量),不必限速
  2. 当c->sent>clcf->limit_rate_after时,需要控制限速,分两种情况:
    • r->limit_rate * (ngx_time() – r->start_sec + 1)>(c->sent – clcf->limit_rate_after)      理论传输量>实际传输量,不必控制(传得慢了)
    • r->limit_rate * (ngx_time() – r->start_sec + 1)<(c->sent – clcf->limit_rate_after)      理论传输量<实际传输量,需要设置延时(传得快了)
    chain = c->send_chain(c, r->out, limit);

通过上面的c->send_chain函数异步发送数据,nginx在处理完上面send_chain函数后做了延时的微调,倘若进行到下面的程序之前异步IO使得c->sent增加了,则按照增加量添加延时时间delay,因为一般情况这段时间c->sent应该不会来得及改变的。所以如果异步IO改变了数据传输量,也应该及时做速度限制的调整,看得出来nginx对这些细节上的处理非常仔细啊,保证一个准确度。

[cpp]  view plain copy
  1. if (r->limit_rate) {  
  2.   
  3.     nsent = c->sent;  
  4.   
  5.     if (clcf->limit_rate_after) {  
  6.   
  7.         sent -= clcf->limit_rate_after;  
  8.         if (sent < 0) {  
  9.             sent = 0;  
  10.         }  
  11.   
  12.         nsent -= clcf->limit_rate_after;  
  13.         if (nsent < 0) {  
  14.             nsent = 0;  
  15.         }  
  16.     }  
  17.   
  18.     delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate);  
  19.   
  20.     if (delay > 0) {  
  21.         limit = 0;  
  22.         c->write->delayed = 1;  
  23.         ngx_add_timer(c->write, delay);  
  24.     }  
  25. }  
接下来nginx还做了点延时的微调,不过这个是涉及到sendfile_max_chunk指令,而不是limit_rate指令的,所以不做分析。

[cpp]  view plain copy
  1. if (limit  
  2.     && c->write->ready  
  3.     && c->sent - sent >= limit - (off_t) (2 * ngx_pagesize))  
  4. {  
  5.     c->write->delayed = 1;  
  6.     ngx_add_timer(c->write, 1);  
  7. }  

总之,可以看出nginx是通过使用ngx_add_timer函数实现对write event的控制,进而实现速度上限的控制。

题外话:nginx对于速度的限制不止是通过limit_rate设置阈值,在upstream模块中通过获取上游服务器返回的响应头headers[“X-Accel-Limit-Rate”]的值也可来动态调整limit_rate的具体数值,这个可以用来实现变化的速度控制。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值