我正在使用开源 Nginx 作为带有 Proxy_cache 的 Web 服务器。
我有一个独特的用例,即删除缓存中的密钥,并将请求传递给后端服务器以删除数据库中的密钥而不缓存响应。
因此,在同一请求中删除 Web 服务器缓存和后端数据库中的键。
客户端 => 负载均衡器 => Nginx(proxy_cache) => 应用程序 => PostgreSQL
例如 Nginx.conf
if ( $http_x_delete_key ){
content_by_lua_file ./purge_key.lua;
proxy_pass http://backend_servers;
}
例如purge_key.lua
...
if ngx ~= nil then
...
delete_file(filename)
ngx.log(ngx.NOTICE, 'deleted')
-- ngx.exit(ngx.OK);
-- return
end
Nginx location 部分中的 'if' 块只是停止了流程(nginx “location if” 的工作原理) 并返回响应而不将其发送到后端,并且不会按原样传递请求。
我甚至使用免费的“ngx_cache_purge”模块编译了 OpenResty,但 purge 命令也不会将请求传递给后端。
通常,您会使用后端响应超时或刷新密钥,但就我而言,我需要更明确的控制来在同一请求或其响应中删除密钥。
Openresty+Memcache、Apache httpd、Apache Traffic Server 或 Varnish(vcl_purge 和 pass)是否可以解决这个用例,或者还有其他方法可以解决吗?
答案1
我已经找到了一种方法来做到这一点。
根据 HTTP 请求标头的值,运行 lua 脚本删除 Nginx 的 proxy_cache 中的缓存文件(如果是 x:y 缓存级别,则为键的哈希值及其最后 x+y 个字符)。
使用“access_by_lua”而不是“content_by_lua”作为内容处理程序阶段将始终退出并返回,即使我没有写“ngx.exit”或“ngx.OK”。
我必须在NGX_HTTP_访问阶段而不是在NGX_HTTP_CONTENT_PHASE因为在我的场景中我没有生成应该来自后端的内容或响应。
例如 Nginx.conf
proxy_cache_bypass $http_x_delete_key;
proxy_no_cache $http_x_delete_key;
if ( $http_x_delete_key ){
...
access_by_lua_file ./purge_key.lua;
}
当删除键的请求到来时,Nginx 将
1. 运行 lua 脚本来删除缓存文件,但不会立即返回,因为它处于访问阶段
2. 请求将绕过缓存
3. 收到请求后,应用程序将在 DB 中删除键
4. 响应不会缓存在 Nginx proxy_cache 中
答案2
常见的方法是让应用程序同时执行从缓存和数据库中删除的操作。或者,让 nginx 托管的 lua 同时执行这两项操作。
一般而言,任何多阶段/多上游类型的请求处理都是应用层,而不是 Web 服务器/网络层。任何配置驱动的代理服务器都不应被扭曲为解决该问题的形式。
因此,将其作为应用程序的一部分,并确定正确的足迹是在上游代码库中还是在 lua 中。最有可能的最佳位置是上游代码库。