🔗 Feature: Store ID
- 目标: 当使用不同的URL访问相同的缓存内容时,减少缓存未命中。
- 状态:已完成。
- 版本: 3.4
- 开发者: Eliezer Croitoru
- 更多:
- 赞助者: Eliezer Croitoru 和 NgTech
🔗 详细信息
“Store ID”是 Squid 缓存键的另一种说法。默认情况下,store ID 由 Squid 计算,以便将不同的 URL 映射到不同的 store ID。此功能允许代理管理员通过辅助程序指定自定义的 store ID 计算算法。它通常用于为具有不同请求 URL 的事务分配相同的 store ID。这种映射可以在处理 CDN URL 和类似情况时减少未命中(即提高命中率),因为不同的 URL 已知会指向基本相同的内容。
Store ID 违反 HTTP,如果将指向不同内容的 URL 错误地映射到同一个 Store ID,会造成混乱。Squid 管理员无法控制外部 CDN 和内容提供商使用的 URL 到内容的映射。即使最初对其 URL 空间进行了逆向工程,由于外部映射的突然更改,保持 Store ID 辅助程序的正确性通常也很困难。
此功能是 Squid-2.7 Store-URL 功能的移植,但其工作方式略有不同,并且将使 Squid-3.4 或更高版本将所有与 store/cache 相关的工作应用于 StoreID 而不是请求 URL。这包括 refresh_pattern。这为管理员使用辅助程序提供了更大的灵活性。
此功能以后将允许我们将 Metalink 支持集成到 squid 中。
🔗 已知问题
- 在两个 URL 上使用 StoreID 假设每个 URL 提供的资源是完全相同的副本。包括 HTTP 条件请求和重新验证请求使用的元数据信息。 - 使用 StoreID 辅助程序时必须小心,确保 URL 确实是精确的副本,否则最终结果可能是降低了命中率并导致代理性能不佳,而不是提高了缓存效果。 - 例如;HTTP ETag 标头的值仅保证每个 URL 唯一,如果 CDN 从每个服务器使用不同的 ETag,那么涉及 ETag 的条件请求将更频繁地出现 MISS 或 REFRESH,尽管内容对象/文件是相同的。这可能会导致比根本不存在 StoreID 时更大的带宽消耗。
- 如果 Squid 未配置为避免缓存重定向响应(HTTP 允许缓存某些重定向响应),StoreID 会导致 HTTP 重定向循环。如果请求 URL 和相应的重定向响应的 Location URL 都映射到同一个 Store ID,则*重定向*的请求将在缓存的重定向响应上命中,从而形成循环。请参阅 Squid bug 3937。
- 缺少 ICP 和 HTCP 支持。- 从 cache_peer 兄弟节点收到的 URL 查询不会通过 StoreID 辅助程序。因此,生成的 store/cache 查找将对通常由 StoreID 更改的 URL 出现 MISS。
🔗 可用辅助程序
- Eliezer Croitoru 设计了几个 Ruby 辅助程序,包括 示例辅助程序
- Alan Mizrahi 的 **storeid_file_rewrite** 是一个简单的辅助程序,随 Squid-3.4 一起打包。它可用于加载*模式数据库*,而无需编辑辅助程序内部代码。
任何先前为 Squid-2.7 StoreURL 功能设计的辅助程序都应能与 Squid-3.4 一起工作。但是,建议升级返回给 Squid 的响应语法以获得更好的性能和与未来 Squid 版本的向前兼容性。
SQUIRM 和 Jesred 等较旧的 URL 重写程序也可以使用上述向后兼容性支持。但是,为 Squid-3.4 响应语法设计的新 URL 重写辅助程序,除非它们具有特定的 Store-ID 接口支持,否则将不会在 Store-ID 接口上工作。
🔗 CDN 模式数据库
由于该功能本身已经设计完成,现在只需要允许基本和高级用法,我们就可以继续进行一个 CDN 数据库,该数据库可以由各种辅助程序共享。
模式数据库为像 SourceForge CDN 或 Linux 发行版存储库镜像等内容提供去重。欢迎贡献。
🔗 我们想缓存 YouTube 视频吗?
与其问“这是否可能做到?”,真正的问题是“我们真的想缓存 YouTube 视频吗?”
从我的角度来看,答案是:在大多数地方,YouTube 视频会非常接近其 CDN 网络。
如果您在一个已经有 YouTube CDN 网络或 Akamai 的地方,那么您可以考虑缓存 YouTube 视频。
缓存 YouTube 视频和内容是可能的,但由于 YouTube 视频不是“小”文件,不适合缓存,因此由于针对此单一目的对 squid 进行不当的微调,有时可能会导致性能下降。
由于缓存代理服务器管理员应该考虑几个方面,他/她应该考虑这样做的真正开销。
🔗 仅基于 URL 的 StoreID 与基于深度检查的 StoreID 比较
有几种方法可以确定对象的 StoreID。目前 squid 的 StoreID 辅助程序接口只允许根据请求 URL 来确定 StoreID,这非常有限,因为并非所有 URL 都包含静态标识数据。
一个很好的例子是基于 token 的访问控制下载,用户永远不会获得可以与文件/对象的某个唯一 ID 相关联的 URL,而是获得一个带有随机或加密 token 的 URL,这将导致文件下载。例如
上面的 URL 在每次下载请求时都是唯一的,因此无法仅通过 URL 来预测。为了预测此 URL 并将其关联到某个 StoreID,需要进行一些深度 HTTP 内容检查。
如今,许多网站使用 POST 请求来获取唯一的下载 URL/token。如果我们检查完整的请求和响应(使用 ICAP 或 eCAP),我们可以轻松知道可以将嵌入在 POST 响应中的基于 token 的 URL 关联到哪个 ID。
理论上,由 eCAP 服务计算出的 ID 已经可以通过 eCAP 注解(又名元标头)传递给 Squid,然后通过 store_id_extras 传递给 storeID 辅助程序。目前,ICAP 服务不支持在请求和响应处理过程中发送 StoreID 的选项。
一个适配服务可以使用内存数据库,如 memcached 或 redis 或其他数据库,来存储特定请求 URL 的 StoreID,之后 StoreID 辅助程序将获取这些信息并进行设置。
上述 ICAP + StoreID 辅助程序方案已在生产环境中与多个网站配合使用一段时间,但存在一些开销,我将此类型的设置评定为仅供专家使用。
🔗 Squid 配置
一个小的 StoreID 刷新模式示例
refresh_pattern ^http://(youtube|ytimg|vimeo|[a-zA-Z0-9\-]+)\.squid\.internal/.* 10080 80% 79900 override-lastmod override-expire ignore-reload ignore-must-revalidate ignore-private
acl rewritedoms dstdomain .dailymotion.com .video-http.media-imdb.com .c.youtube.com av.vimeo.com .dl.sourceforge.net .ytimg.com .vid.ec.dmcdn.net .videoslasher.com
store_id_program /usr/local/squid/bin/new_format.rb
store_id_children 40 startup=10 idle=5 concurrency=0
store_id_access allow rewritedoms !banned_methods
store_id_access deny all
辅助程序的输入输出示例
root# /usr/local/squid/bin/new_format.rb
ERR
http://i2.ytimg.com/vi/95b1zk3qhSM/hqdefault.jpg
OK store-id=http://ytimg.squid.internal/vi/95b1zk3qhSM/hqdefault.jpg
从 Squid-3.5 开始,此辅助程序可以支持并发设置的任何值。
🔗 开发者信息
🔗 辅助程序示例
此辅助程序仅为示例。它不提供任何保证,不建议用于生产环境。
有一个更新的 StoreID 辅助程序,其中包含更多 URL 模式,您可以从中学习 URL 模式。
#!/usr/bin/ruby
# encoding: utf-8
require "rubygems"
require 'syslog'
class Cache
def initialize
end
def sfdlid(url)
m = url.match(/^http:\/\/.*\.dl\.sourceforge\.net\/(.*)/)
if m[1]
return m[1]
else
return nil
end
end
end
def rewriter(request)
case request
when /^http:\/\/[a-zA-Z0-9\-_\.]+\.dl\.sourceforge\.net\/.*/
vid = $cache.sfdlid(request)
url = "http://dl.sourceforge.net.squid.internal/" + vid if vid != nil
return url
when /^quit.*/
exit 0
else
return ""
end
end
def log(msg)
Syslog.log(Syslog::LOG_ERR, "%s", msg)
end
def eval
request = gets
if (request && (request.match(/^[0-9]+\ /)))
conc(request)
return true
else
noconc(request)
return false
end
end
def conc(request)
return if !request
request = request.split
if request[0] && request[1]
log("original request [#{request.join(" ")}].") if $debug
result = rewriter(request[1])
if result
url = request[0] +" OK store-id=" + result
else
url = request[0] +" ERR"
end
log("modified response [#{url}].") if $debug
puts url
else
log("original request [had a problem].") if $debug
url = request[0] + "ERR"
log("modified response [#{url}].") if $debug
puts url
end
end
def noconc(request)
return if !request
request = request.split
if request[0]
log("Original request [#{request.join(" ")}].") if $debug
result = rewriter(request[0])
if result && (result.size > 10)
url = "OK store-id=" + rewriter(request[0])
#url = "OK store-id=" + request[0] if ( ($empty % 2) == 0 )
else
url = "ERR"
end
log("modified response [#{url}].") if $debug
puts url
else
log("Original request [had a problem].") if $debug
url = "ERR"
log("modified response [#{url}].") if $debug
puts url
end
end
def validr?(request)
if (request.ascii_only? && request.valid_encoding?)
return true
else
STDERR.puts("errorness line#{request}")
return false
end
end
def main
Syslog.open('new_helper.rb', Syslog::LOG_PID)
log("Started")
c = eval
if c
while request = gets
conc(request) if validr?(request)
end
else
while request = gets
noconc(request) if validr?(request)
end
end
end
$debug = true
$cache = Cache.new
STDOUT.sync = true
main
🔗 辅助程序输入/输出示例
#./new_helper.rb
http://freefr.dl.sourceforge.net/project/vlc/2.0.5/win32/vlc-2.0.5-win32.exe
OK store-id=http://dl.sourceforge.net.squid.internal/project/vlc/2.0.5/win32/vlc-2.0.5-win32.exe
http://www.google.com/
ERR
quit
#tail /var/log/messages
Feb 17 17:32:07 www1 new_helper.rb[21352]: Started
Feb 17 17:32:08 www1 new_helper.rb[21352]: Original request [http://freefr.dl.sourceforge.net/project/vlc/2.0.5/win32/vlc-2.0.5-win32.exe].
Feb 17 17:32:08 www1 new_helper.rb[21352]: modified response [OK store-id=http://dl.sourceforge.net.squid.internal/project/vlc/2.0.5/win32/vlc-2.0.5-win32.exe].
Feb 17 17:32:39 www1 new_helper.rb[21352]: Original request [http://www.google.com/].
Feb 17 17:32:39 www1 new_helper.rb[21352]: modified response [ERR].
Feb 17 17:32:51 www1 new_helper.rb[21352]: Original request [quit].
🔗 如何制作我自己的辅助程序?
辅助程序必须在标准输入上读取 URL(每行一个),并在标准输出上写入 OK 和一个唯一的标识符(ID)或 ERR/BH 行。Squid 在 URL 之后写入额外的信息,辅助程序可以使用这些信息来做出决定。
从 Squid 接收的输入行
[channel-ID] URL [key-extras]
-
- channel-ID
- 当启用并发时,这是行的 ID。当禁用并发(设置为1)时,此字段以及后面的空格将完全缺失。
-
- URL
- 从客户端接收的 URL。在支持 ICAP 的 Squid 中,这是 ICAP REQMOD 发生后的 URL。
-
- key-extras
- 从 Squid-3.5 开始,传递给辅助程序的额外参数可以通过 url_rewrite_extras 进行配置。为了向后兼容,URL 辅助程序的默认 key-extras 匹配 Squid-3.4 及更早版本在此字段位置发送的格式字段
ip/fqdn ident method [urlgroup] kv-pair
-
- ip
- 这是客户端的 IP 地址。后面跟着一个斜杠(/),如上所示。
-
- fqdn
- 客户端的 FQDN rDNS(如果已知)。Squid 通常不会执行查找,除非日志记录或 ACL 需要。Squid 不会等待任何结果,除非配置了等待的 ACL。如果不可用,将发送-给帮助程序。
-
- ident
- 客户端机器的 IDENT 协议用户名(如果已知)。Squid 不会等待 IDENT 用户名可知,除非有 ACL 依赖它。因此,在重写器运行时,IDENT 用户名可能尚未可知。如果不可用,将发送-给帮助程序。
-
- method
- HTTP 请求方法。URL 更改,尤其是重定向,仅在某些方法上可能,并且像 POST 和 CONNECT 这样的方法需要特别小心。
-
- kv-pair
- 一个或多个键=值对。下面仅记录了“myip”和“myport”对,并且它们是由 Squid-3.4 及更早版本无条件发送的。
myip=… Squid 接收地址 myport=… Squid 接收端口
返回给 Squid 的结果行
[channel-ID] result kv-pair
-
- channel-ID
- 当收到并发channel-ID时,它必须作为行上的第一个条目不变地发送回 Squid。
-
- result
- 其中一个结果代码
OK 成功。为该 URL 提供了一个新的存储 ID。 ERR 成功。此 URL 无更改。 BH 失败。帮助程序遇到问题。
-
- kv-pair
- 一个或多个键=值对。在此接口上为 URL 重写保留的键名称
clt_conn_tag=… 标记客户端 TCP 连接 (Squid-3.5) message=… reserved store-id=… 设置该 URL 的缓存存储 ID。 tag=… reserved ttl=… reserved *_=… 以 (_) 结尾的键名保留给本地管理员使用。
此辅助程序返回的 kv-pair 可以通过 %note logformat 代码进行日志记录。
此接口还将接受由为 Squid-2.7 编写的 Store URL-rewrite 功能辅助程序提供的语法中的响应。但是,此语法已弃用,应尽快升级此类辅助程序以使用此 Store-ID 语法。
类别:功能
导航:站点搜索,站点页面,类别,🔼 向上