对 Cookie 大小导致的 500 错误进行故障排除

Troubleshooting 500 Error Due to Cookie Size

网站访问者在浏览一段时间后收到 500 内部服务器错误,这是由于跟踪 cookie 将我们域的整体 cookie 大小推到超过 4kb(这是一个页面浏览 cookie,所以它每次都会附加页面名称你访问了一个新页面)。

我可以使用带有非常大的 cookie 负载的 curl 重现该问题。在这样做的过程中,我已经能够验证 500 的确切来源(我们从 Cloudflare 到 Varnish 再到后端网络服务器)。我已经验证失败的请求不会到达网络服务器,所以我相信 Varnish 是服务于 500s 的那个。我也看过 varnishlog 并看到 500s 出现了。

这是来自 varnishlog 的示例响应

--  VCL_return     hash
--  VCL_call       HASH
--  VCL_return     lookup
--  Hit            57254162
--  VCL_call       HIT
--  VCL_return     deliver
--  RespProtocol   HTTP/1.1
--  RespStatus     200
--  RespReason     OK
--  RespHeader     X-Powered-By: Express
--  RespHeader     Date: Thu, 01 Aug 2019 23:05:52 GMT
--  RespHeader     Content-Type: application/json; charset=utf-8
--  RespHeader     Content-Length: 1174
--  RespHeader     X-Varnish: 57156196 57519178
--  RespHeader     Age: 86
--  RespHeader     Via: 1.1 varnish-v4
--  VCL_call       DELIVER
--  RespHeader     X-Cache: HIT
--  RespUnset      X-Powered-By: Express
--  VCL_return     deliver
--  Timestamp      Process: 1564700838.564547 0.000354 0.000354
--  RespHeader     Accept-Ranges: bytes
--  Debug          "RES_MODE 2"
--  RespHeader     Connection: keep-alive
--  Error          workspace_client overflow
--  RespProtocol   HTTP/1.1
--  RespStatus     500
--  RespReason     Internal Server Error
--  Timestamp      Resp: 1564700838.564580 0.000387 0.000033
--  ReqAcct        10063 0 10063 0 0 0
--  End

这是我添加到 vcl_recv 部分以删除违规 cookie 的内容

set req.http.Cookie = regsuball(req.http.Cookie, "_loc_[^;]+(; )?", "");

我不明白这里的两个 RespStatus 条目有什么意义。为什么是200,然后是500?我还注意到,如果我使用使用 HTTP/1.1 的 curl,我会得到 500,但是如果我使用使用 HTTP/2 的 HTTPie,我会得到 200。这是预期的吗? Varnish 会根据 http 版本以不同方式处理 cookie 大小吗?

*编辑:我想我已经弄清楚了两种响应状态的区别在于,一种是将内容传递给清漆,第二种是将内容传递给客户端。

正如日志所说,工作量space 太小无法容纳事务(headers,特别是),请尝试增加它:

varnishadm param.set workspace_client 128k

详细解释:varnish 对每笔交易使用 "worspace"。这是一块用于分配数据的内存,整个块在事务结束时被擦除。 header特别是被复制到作品space中,每次添加或修改一个header,它也会去那里。

这里的问题是你没有足够的space。早期版本只会恐慌,但现在更智能,只会产生状态为 500 的综合响应。诀窍在于它在复制初始响应后意识到缺少 workspace,因此您会在日志中看到这两个响应。