yzprofile's Notebook

All Posts| Note| Books| About
16 Nov 2012

Nginx limit requests module 分析

介绍

Nginx Limit requests module: http://wiki.nginx.org/HttpLimitReqModule

This module allows you to limit the number of requests for a given session, or as a special case, with one address.

Restriction done using leaky bucket.

Limit requests使用的是漏桶算法.http://en.wikipedia.org/wiki/Leaky_bucket

ms = (ngx_msec_int_t) (now - lr->last);

excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000;

if (excess < 0) {
    excess = 0;
}

*ep = excess;

if ((ngx_uint_t) excess > limit->burst) {
    return NGX_BUSY;
}

if (account) {
    lr->excess = excess;
    lr->last = now;
    return NGX_OK;
}

lr->count++;

ctx->node = lr;

return NGX_AGAIN;

ctx->rate在配置解析时转换为QPS,并放大了1000倍以增加计算精度。

excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000,这个是将整个式子 * 1000来增大计算精度的,还原之后是:

excess = lr->excess - qps / 1000 * ngx_abs(ms) + 1, 当前时刻还能允许进入请求的余量。

burst的值也就是类似一个水桶,当excess余量大于burst上限时请求溢出直接就被拒绝了,当其大于0还没超出水桶上限时limit request模块会给请求加上定时器,延后处理,控制流速(这是在delay模式下)。

r->read_event_handler = ngx_http_test_reading;
r->write_event_handler = ngx_http_limit_req_delay;
ngx_add_timer(r->connection->write, delay);

延后时间为 delay = excess.其可将请求拉成匀速流向后端。当burst值(水桶)越大,hold住的请求也就越多,在有流量突发的时候也能以限定的速度去处理,减少后端压力。但是会导致RT普遍偏高。

在nodelay的模式下时,实际上应该被称作token bucket算法。即没有超过水桶上限的流量都会被立即处理,超出的被拒绝。nodelay是允许突发值的,这样也就给后端在请求突增的时候带来了不确定的压力。正常情况下用户体验要比delay好,它会及时响应用户的请求而不控制流速。不会像delay状态下增加用户rt时间。

hava fun :)

EOF