1.关键的整体流程
cpp
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
cpp
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(缓存处理核心函数)
cpp
/*
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;
}