业务要求Cache服务器能够随时增删允许访问的HOST。而每个HOST有单独的配置,这些配置随时都可能更改。如果单纯采用静态配置文件(nginx.conf)的方式,每次修改都要reload NGINX。如果更改很频繁,会造成服务器上存在大量的NGINX进程,导致服务器负载很高。因而我们将需要随时更改的配置存储于一个独立的配置服务器中。请求处理时,先去配置服务器中获取该请求需要使用的配置,再根据这些配置进行相应的处理。因而,我们可以随时更改配置服务器中的相应内容。
其中一个配置就是文件缓存时间。NGINX中设置文件缓存时间有两种方法:
- 设置proxy_cache_valid指令
- 在上游响应中的添加”Cache-Control” header和”Expires” header
其中上游响应header的优先级更高。当不想使用上游响应header中所设置的缓存时间时,可以使用以下指令来禁用。
| 1
 | proxy_ignore_headers X-Accel-Expires;
 | 
这两种方法都无法满足我们根据动态配置来设置缓存时间的需求。因而我给NGINX添加了一个内置变量”cache_time”来支持灵活地设置缓存时间,并且该种方式具有最高的优先级。这样,可以非常方便地在ngx_lua等第三方模块中根据条件设置不同的缓存时间。
在ngx_http_request_t添加一个cache_time成员,在ngx_http_core_variables数组中添加内置变量”cache_time”,”cache_time”在被赋值时会将值存储在r->cache_time中。
| 12
 3
 4
 
 | { ngx_string("cache_time"), ngx_http_variable_request_set_time,ngx_http_variable_request_get_time,
 offsetof(ngx_http_request_t, cache_time),
 NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 
 | static voidngx_http_variable_request_set_time(ngx_http_request_t *r,
 ngx_http_variable_value_t *v, uintptr_t data)
 {
 ngx_str_t  val;
 time_t     valid, *vp;
 
 val.len = v->len;
 val.data = v->data;
 
 valid = ngx_parse_time(&val, 1);
 if (valid == (time_t) NGX_ERROR) {
 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
 "invalid time value "%V"", &val);
 return;
 }
 
 vp = (time_t *) ((char *) r + data);
 
 *vp = valid;
 
 return;
 }
 
 | 
因为”cache_time”变量需要比上游响应header具有更高的优先级,因而要在上游header处理之后再处理”cache_time”变量。上游响应的header在ngx_http_upstream_process_headers()中进行处理。因而我在upstream模块中添加了一个hook, 该hook在调用完ngx_http_upstream_process_headers()后,开始处理body前被调用。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {return;
 }
 
 if (u->post_headers) {
 rc = u->post_headers(r);
 if (rc != NGX_OK) {
 ngx_http_upstream_finalize_request(r, u, rc);
 return;
 }
 }
 
 | 
proxy模块在该hook上注册一个函数,这个函数执行时,首先检查上游响应的状态码判断是否需要处理”cache_time”变量。检查通过后,读取”cache_time”变量的值,依据值来进行各种操作。当值为0时,禁用cache.为正值,则将缓存时间修改为该值。当修改cache缓存时间后,将上游响应中的”Cache-Control”和”Expires” header去除,不再发送给下游。
| 1
 | u->post_headers = ngx_http_proxy_post_headers;
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | static ngx_int_tngx_http_proxy_post_headers(ngx_http_request_t *r)
 {
 ngx_uint_t         i;
 ngx_table_elt_t  **ph;
 
 if (ngx_http_upstream_check_status(r->upstream->conf->cache_time_valid,
 r->upstream->headers_in.status_n)
 == NGX_DECLINED)
 {
 return NGX_OK;
 }
 
 if (r->cache_time == (time_t) -1) {
 return NGX_OK;
 }
 
 if (r->cache_time == (time_t) 0) {
 r->upstream->cacheable = 0;
 return NGX_OK;
 }
 
 r->cache->valid_sec = ngx_time() + r->cache_time;
 
 r->headers_out.expires->hash = 0;
 
 ph = r->headers_out.cache_control.elts;
 for (i = 0; i < r->headers_out.cache_control.nelts; i++) {
 ph[i]->hash = 0;
 }
 
 return NGX_OK;
 }
 
 |