<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cache on 认真的雪</title><link>https://blog.wjhe.top/tags/cache/</link><description>Recent content in Cache on 认真的雪</description><generator>Hugo -- gohugo.io</generator><language>zh</language><lastBuildDate>Fri, 13 Dec 2024 09:28:00 +0800</lastBuildDate><atom:link href="https://blog.wjhe.top/tags/cache/index.xml" rel="self" type="application/rss+xml"/><item><title>Nginx 缓存 文件名和路径计算</title><link>https://blog.wjhe.top/nginx-%E7%BC%93%E5%AD%98-%E6%96%87%E4%BB%B6%E5%90%8D%E5%92%8C%E8%B7%AF%E5%BE%84%E8%AE%A1%E7%AE%97/</link><pubDate>Fri, 13 Dec 2024 09:28:00 +0800</pubDate><guid>https://blog.wjhe.top/nginx-%E7%BC%93%E5%AD%98-%E6%96%87%E4%BB%B6%E5%90%8D%E5%92%8C%E8%B7%AF%E5%BE%84%E8%AE%A1%E7%AE%97/</guid><description>&lt;p&gt;缓存键 (proxy_cache_key): proxy_cache_key 指定了 NGINX 如何根据请求生成一个缓存键。
&lt;strong&gt;缓存键 (proxy_cache_key)&lt;/strong&gt;
proxy_cache_key 指定了 NGINX 如何根据请求生成一个缓存键。
&lt;strong&gt;哈希计算&lt;/strong&gt;
对缓存键进行哈希处理，常使用 MD5 算法。
例如，如果缓存键是 example.com/image.png , 进行 MD5 哈希后会得到一个 32 字符的哈希值（c877fe850c17cb1a4d0b158dd2b64cfb）。
这里有一种特殊情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当第一次缓存的时候，得到的哈希，就是MD5(example.com/image.png)&lt;/li&gt;
&lt;li&gt;第二次缓存，如果源站有 Vary 响应头 并且 Vary 的值 与第一次缓存的不一致，则会通过 Vary 的值 计算一个新的哈希，如果没有 Vary 响应头，则不会计算新的哈希。
就是说，如果源站响应头没有 Vary，则每次的哈希都是一样的，缓存的是同一个文件，否则会生成新的缓存文件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;就是说，无论第一次的 Accept-Encoding 是什么，都不会被Accept-Encoding影响，第二次会因为Accept-Encoding影响。
第一次缓存算法：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-go" data-lang="go"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 直接对缓存键哈希&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// cacheKey: 缓存键&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;func&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;getCacheFileHash&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;cacheKey&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;string&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;keyHash&lt;/span&gt; &lt;span style="color:#f92672"&gt;:=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;md5&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;Sum&lt;/span&gt;([]byte(&lt;span style="color:#a6e22e"&gt;cacheKey&lt;/span&gt;))
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;hex&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;EncodeToString&lt;/span&gt;(&lt;span style="color:#a6e22e"&gt;keyHash&lt;/span&gt;[:])
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第二次缓存算法：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;// 计算缓存文件哈希
//
// 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 == &amp;#39;,&amp;#39; || unicode.IsSpace(r)
 })
 // 再去掉空白字符
 valueList := make([]string, 0, len(varyValueList))
 for _, s := range varyValueList {
 if s == &amp;#34;&amp;#34; {
 continue
 }
 valueList = append(valueList, s)
 }
 varyValue = strings.Join(valueList, &amp;#34;,&amp;#34;)
 // 开始 计算
 // hexEncode(md5(md5(cacheKey) + vary + &amp;#34;:&amp;#34; + varyValue + &amp;#34;\r\n&amp;#34;))
 // example.com/image.png Accept-Encoding deflate, gzip
 // = hexEncode(md5(md5(&amp;#34;example.com/image.png&amp;#34;) + &amp;#34;accept-encoding:deflate,gzip\r\n&amp;#34;))
 buf := bytes.NewBuffer(nil)
 
 keyHash := md5.Sum([]byte(cacheKey))
 buf.Write(keyHash[:])
 buf.WriteString(vary)
 buf.WriteString(&amp;#34;:&amp;#34;)
 buf.WriteString(varyValue)
 buf.WriteString(&amp;#34;\r\n&amp;#34;)
 newHash := md5.Sum(buf.Bytes())
 return hex.EncodeToString(newHash[:])
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;路径层次结构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在 proxy_cache_path 配置中，我们可以看到 levels=1:2。这表示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生成的缓存路径会被拆分成两级目录结构。&lt;/li&gt;
&lt;li&gt;第一层目录使用哈希值的倒数第一位字符（b）。&lt;/li&gt;
&lt;li&gt;第二层目录使用哈希值的倒数第三位和倒数第二位字符（cf）。&lt;/li&gt;
&lt;li&gt;最终的缓存文件名将使用哈希值（c877fe850c17cb1a4d0b158dd2b64cfb）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如，基于缓存键 example.com/image.png，假设其哈希值为 c877fe850c17cb1a4d0b158dd2b64cfb，则缓存文件的路径为：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/var/cache/nginx/b/cf/c877fe850c17cb1a4d0b158dd2b64cfb&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;参考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;nginx反向代理缓存实现，md5加密规则，gzip压缩问题：[https://blog.51cto.com/u_14210437/11868562][1]&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;源代码：[https://github.com/nginx/nginx/blob/master/src/http/ngx_http_file_cache.c][2]&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item></channel></rss>