Nginx 缓存 文件名和路径计算
缓存键 (proxy_cache_key): proxy_cache_key 指定了 NGINX 如何根据请求生成一个缓存键。
缓存键 (proxy_cache_key)
proxy_cache_key 指定了 NGINX 如何根据请求生成一个缓存键。
哈希计算
对缓存键进行哈希处理,常使用 MD5 算法。
例如,如果缓存键是 example.com/image.png , 进行 MD5 哈希后会得到一个 32 字符的哈希值(c877fe850c17cb1a4d0b158dd2b64cfb)。
这里有一种特殊情况:
- 当第一次缓存的时候,得到的哈希,就是MD5(example.com/image.png)
- 第二次缓存,如果源站有 Vary 响应头 并且 Vary 的值 与第一次缓存的不一致,则会通过 Vary 的值 计算一个新的哈希,如果没有 Vary 响应头,则不会计算新的哈希。
就是说,如果源站响应头没有 Vary,则每次的哈希都是一样的,缓存的是同一个文件,否则会生成新的缓存文件。
就是说,无论第一次的 Accept-Encoding 是什么,都不会被Accept-Encoding影响,第二次会因为Accept-Encoding影响。
第一次缓存算法:
// 直接对缓存键哈希
// cacheKey: 缓存键
func getCacheFileHash(cacheKey string) string {
keyHash := md5.Sum([]byte(cacheKey))
return hex.EncodeToString(keyHash[:])
}
第二次缓存算法:
// 计算缓存文件哈希
//
// cacheKey: 缓存键
// vary: 响应头的Vary字段 Accept-Encoding | Accept-Charset | Accept-Language | other
// varyValue: deflate, gzip
func getCacheFileHash(cacheKey string, vary string, varyValue string) string {
// 转小写 并且去除两边空格
vary = strings.TrimSpace(strings.ToLower(vary))
// 通过逗号或者空格分隔,然后再通过逗号join
// 先转小写 并且去除两边空格
varyValue = strings.TrimSpace(strings.ToLower(varyValue))
varyValueList := strings.FieldsFunc(varyValue, func(r rune) bool {
return r == ',' || unicode.IsSpace(r)
})
// 再去掉空白字符
valueList := make([]string, 0, len(varyValueList))
for _, s := range varyValueList {
if s == "" {
continue
}
valueList = append(valueList, s)
}
varyValue = strings.Join(valueList, ",")
// 开始 计算
// hexEncode(md5(md5(cacheKey) + vary + ":" + varyValue + "\r\n"))
// example.com/image.png Accept-Encoding deflate, gzip
// = hexEncode(md5(md5("example.com/image.png") + "accept-encoding:deflate,gzip\r\n"))
buf := bytes.NewBuffer(nil)
keyHash := md5.Sum([]byte(cacheKey))
buf.Write(keyHash[:])
buf.WriteString(vary)
buf.WriteString(":")
buf.WriteString(varyValue)
buf.WriteString("\r\n")
newHash := md5.Sum(buf.Bytes())
return hex.EncodeToString(newHash[:])
}
路径层次结构
在 proxy_cache_path 配置中,我们可以看到 levels=1:2。这表示:
- 生成的缓存路径会被拆分成两级目录结构。
- 第一层目录使用哈希值的倒数第一位字符(b)。
- 第二层目录使用哈希值的倒数第三位和倒数第二位字符(cf)。
- 最终的缓存文件名将使用哈希值(c877fe850c17cb1a4d0b158dd2b64cfb)。
例如,基于缓存键 example.com/image.png,假设其哈希值为 c877fe850c17cb1a4d0b158dd2b64cfb,则缓存文件的路径为:
/var/cache/nginx/b/cf/c877fe850c17cb1a4d0b158dd2b64cfb
参考:
- nginx反向代理缓存实现,md5加密规则,gzip压缩问题:https://blog.51cto.com/u_14210437/11868562
- 源代码:https://github.com/nginx/nginx/blob/master/src/http/ngx_http_file_cache.c
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。