从源码看nginx的缓存功能(一)

1.关键的整体流程

1. ngx_http_proxy_handler()                    // 入口
   ↓
2. ngx_http_upstream_init()                    // 初始化上游
   ↓
3. ngx_http_upstream_init_request()              // 初始化请求
   ↓
4. ngx_http_upstream_cache()                   // 缓存处理
   ↓
5. ngx_http_file_cache_exists()               // 检查缓存是否存在
   ↓
6. ngx_http_file_cache_open()                 // 打开缓存文件

2. ngx_http_upstream_init_request


static void
ngx_http_upstream_init_request(ngx_http_request_t *r)
{ 
  // ...
#if (NGX_HTTP_CACHE)

    if (u->conf->cache) {
        ngx_int_t  rc;

        rc = ngx_http_upstream_cache(r, u);
        if (rc == NGX_BUSY) {
            r->write_event_handler = ngx_http_upstream_init_request;
            return;
        }
        r->write_event_handler = ngx_http_request_empty_handler;

        if (rc == NGX_ERROR) {
            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
            return;
        }

        if (rc == NGX_OK) {
            rc = ngx_http_upstream_cache_send(r, u);

            if (rc == NGX_DONE) {
                return;
            }

            if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
                rc = NGX_DECLINED;
                r->cached = 0;
                u->buffer.start = NULL;
                u->cache_status = NGX_HTTP_CACHE_MISS;
                u->request_sent = 1;
            }
        }

        if (rc != NGX_DECLINED) {
            ngx_http_finalize_request(r, rc);
            return;
        }
    }

#endif
 // ...

}

3.ngx_http_upstream_cache(缓存处理核心函数)

/*
1. 检查请求方法是否支持缓存
2. 获取缓存配置
3. HEAD请求特殊处理
4. 创建缓存上下文
5. 生成缓存键
6. 检查缓冲区大小
7. 检查缓存绕过条件
8. 设置缓存锁参数
9. 标记为缓存未命中
*/

static ngx_int_t
ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
    ngx_int_t               rc;
    ngx_http_cache_t       *c;
    ngx_http_file_cache_t  *cache;

    c = r->cache;
  
    // 这里加c == NULL判断的用户是可能会出现重入ngx_http_upstream_cache这个函数
    if (c == NULL) {
    
        /*
         1.检查请求方法是否支持缓存
         检查当前请求的方法是否在配置的缓存方法位掩码中. 
         如果不在,直接返回 NGX_DECLINED,跳过缓存处理.
         默认只支持GET和HEAD这两种方法,可以通过 proxy_cache_methods指令配置.
        */
        if (!(r->method & u->conf->cache_methods)) {
            return NGX_DECLINED;
        }
        /*
          2.获取缓存配置
          如果返回 NGX_OK,继续缓存处理
          如果返回 NGX_DECLINED,跳过缓存
          如果返回 NGX_ERROR,记录错误
        */
        rc = ngx_http_upstream_cache_get(r, u, &cache);

        if (rc != NGX_OK) {
            return rc;
        }

        if (r->method == NGX_HTTP_HEAD && u->conf->cache_convert_head) {
            u->method = ngx_http_core_get_method;
        }
        // 这里如果成功处理,r->cache将会被赋值
        if (ngx_http_file_cache_new(r) != NGX_OK) {
            return NGX_ERROR;
        }

        if (u->create_key(r) != NGX_OK) {
            return NGX_ERROR;
        }

        /* TODO: add keys */

        ngx_http_file_cache_create_key(r);

        if (r->cache->header_start + 256 > u->conf->buffer_size) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "%V_buffer_size %uz is not enough for cache key, "
                          "it should be increased to at least %uz",
                          &u->conf->module, u->conf->buffer_size,
                          ngx_align(r->cache->header_start + 256, 1024));

            r->cache = NULL;
            return NGX_DECLINED;
        }

        u->cacheable = 1;

        c = r->cache;

        c->body_start = u->conf->buffer_size;
        c->min_uses = u->conf->cache_min_uses;
        c->file_cache = cache;

        switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) {

        case NGX_ERROR:
            return NGX_ERROR;

        case NGX_DECLINED:
            u->cache_status = NGX_HTTP_CACHE_BYPASS;
            return NGX_DECLINED;

        default: /* NGX_OK */
            break;
        }

        c->lock = u->conf->cache_lock;
        c->lock_timeout = u->conf->cache_lock_timeout;
        c->lock_age = u->conf->cache_lock_age;

        u->cache_status = NGX_HTTP_CACHE_MISS;
    }

    rc = ngx_http_file_cache_open(r);

    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "http upstream cache: %i", rc);

    switch (rc) {

    case NGX_HTTP_CACHE_STALE:

        if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
             || c->stale_updating) && !r->background
            && u->conf->cache_background_update)
        {
            if (ngx_http_upstream_cache_background_update(r, u) == NGX_OK) {
                r->cache->background = 1;
                u->cache_status = rc;
                rc = NGX_OK;

            } else {
                rc = NGX_ERROR;
            }
        }

        break;

    case NGX_HTTP_CACHE_UPDATING:

        if (((u->conf->cache_use_stale & NGX_HTTP_UPSTREAM_FT_UPDATING)
             || c->stale_updating) && !r->background)
        {
            u->cache_status = rc;
            rc = NGX_OK;

        } else {
            rc = NGX_HTTP_CACHE_STALE;
        }

        break;

    case NGX_OK:
        u->cache_status = NGX_HTTP_CACHE_HIT;
    }

    switch (rc) {

    case NGX_OK:

        return NGX_OK;

    case NGX_HTTP_CACHE_STALE:

        c->valid_sec = 0;
        c->updating_sec = 0;
        c->error_sec = 0;

        u->buffer.start = NULL;
        u->cache_status = NGX_HTTP_CACHE_EXPIRED;

        break;

    case NGX_DECLINED:

        if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
            u->buffer.start = NULL;

        } else {
            u->buffer.pos = u->buffer.start + c->header_start;
            u->buffer.last = u->buffer.pos;
        }

        break;

    case NGX_HTTP_CACHE_SCARCE:

        u->cacheable = 0;

        break;

    case NGX_AGAIN:

        return NGX_BUSY;

    case NGX_ERROR:

        return NGX_ERROR;

    default:

        /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */

        u->cache_status = NGX_HTTP_CACHE_HIT;

        return rc;
    }

    if (ngx_http_upstream_cache_check_range(r, u) == NGX_DECLINED) {
        u->cacheable = 0;
    }

    r->cached = 0;

    return NGX_DECLINED;
}

4.缓存状态枚举值

#define NGX_HTTP_CACHE_MISS          1
#define NGX_HTTP_CACHE_BYPASS        2
#define NGX_HTTP_CACHE_EXPIRED       3
#define NGX_HTTP_CACHE_STALE         4
#define NGX_HTTP_CACHE_UPDATING      5
#define NGX_HTTP_CACHE_REVALIDATED   6
#define NGX_HTTP_CACHE_HIT           7
#define NGX_HTTP_CACHE_SCARCE        8


#define NGX_HTTP_CACHE_MISS          1  缓存未命中.请求的资源不在缓存中,需要向后端服务器请求。
#define NGX_HTTP_CACHE_BYPASS        2  绕过缓存.由于proxy_cache_bypass指令或其他原因,请求跳过了缓存。
#define NGX_HTTP_CACHE_EXPIRED       3  缓存已过期.缓存存在但已过期,需要向后端验证或重新获取。
#define NGX_HTTP_CACHE_STALE         4  使用过期缓存.当配置了 proxy_cache_use_stale且后端服务器不可用时,使用了过期的缓存。
#define NGX_HTTP_CACHE_UPDATING      5  缓存正在更新.缓存已过期,但当前有其他请求正在更新这个缓存(在 proxy_cache_use_stale updating配置下使用)。
#define NGX_HTTP_CACHE_REVALIDATED   6  重新验证成功.通过 If-Modified-Since 或 If-None-Match 验证,发现缓存仍然有效(返回 304)。
#define NGX_HTTP_CACHE_HIT           7  缓存命中.直接从缓存中获取响应,是最理想的状态。
#define NGX_HTTP_CACHE_SCARCE        8  缓存空间不足​或者缓存管理器正在清理文件

5.nginx中常用的返回值

#define  NGX_OK          0
#define  NGX_ERROR      -1
#define  NGX_AGAIN      -2
#define  NGX_BUSY       -3
#define  NGX_DONE       -4
#define  NGX_DECLINED   -5
#define  NGX_ABORT      -6

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值