Getting random "http first read error: EOF" errors in varnish
Getting random "http first read error: EOF" errors in varnish
我不时在日志中看到 varnish 中的以下 503 错误:
* << BeReq >> 213585014
- Begin bereq 213585013 fetch
- Timestamp Start: 1452675822.032332 0.000000 0.000000
- BereqMethod GET
- BereqURL /client/hedge-funds-asset-managers/
- BereqProtocol HTTP/1.1
- BereqHeader X-Real-IP: 123.125.71.28
- BereqHeader Host: XXXXXXXXXXXXXXXXXXX
- BereqHeader X-Forwarded-Proto: http
- BereqHeader User-Agent: Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
- BereqHeader Accept-Encoding: gzip
- BereqHeader Accept-Language: zh-cn,zh-tw
- BereqHeader Accept: */*
- BereqHeader X-Forwarded-For: 172.18.210.22
- BereqHeader X-Varnish: 213585014
- VCL_call BACKEND_FETCH
- VCL_return fetch
- BackendOpen 232 reload_2016-01-12T07:28:50.cp_12 162.251.80.23 80 172.18.210.71 40019
- Timestamp Bereq: 1452675822.047840 0.015508 0.015508
- FetchError http first read error: EOF
- BackendClose 232 reload_2016-01-12T07:28:50.cp_12
- Timestamp Beresp: 1452675876.038544 54.006212 53.990704
- Timestamp Error: 1452675876.038555 54.006223 0.000010
- BerespProtocol HTTP/1.1
- BerespStatus 503
- BerespReason Service Unavailable
- BerespReason Backend fetch failed
- BerespHeader Date: Wed, 13 Jan 2016 09:04:36 GMT
- BerespHeader Server: Varnish
- VCL_call BACKEND_ERROR
- BerespHeader Content-Type: text/html; charset=utf-8
- BerespHeader Retry-After: 5
- VCL_return deliver
- Storage malloc Transient
- ObjProtocol HTTP/1.1
- ObjStatus 503
- ObjReason Backend fetch failed
- ObjHeader Date: Wed, 13 Jan 2016 09:04:36 GMT
- ObjHeader Server: Varnish
- ObjHeader Content-Type: text/html; charset=utf-8
- ObjHeader Retry-After: 5
- Length 286
- BereqAcct 350 0 350 0 0 0
- End
问题不在于后端连接,因为来自清漆服务器的相同 URL 的卷曲工作正常。 varnish 的版本是 4.1.0。我不确定 "http first read error: EOF" 是什么意思,感谢您对这个问题的任何了解。由于这个问题的随机性,我也没有办法重现它。
当您在调用 vcl_fetch
之前尝试从后端读取 headers 并且 Varnish 未能获得响应时,"first read error" 会在 Varnish 中发生。 TL;DR:您的后端要么在传递响应之前关闭连接,要么传递响应超时。您可以使用 wireshark 之类的工具来确定发生了这两种情况中的哪一种。
要了解发生了什么,让我们进行一些源代码潜水:
static int __match_proto__(vdi_gethdrs_f)
vbe_dir_gethdrs(const struct director *d, struct worker *wrk,
struct busyobj *bo)
{
int i, extrachance = 1;
struct backend *bp;
struct vbc *vbc;
...
do {
vbc = vbe_dir_getfd(wrk, bp, bo);
没有过多关注董事,vbe_dir_gethdrs
在 Varnish 已经打开一个新连接,或者决定重新使用一个连接后被调用。
if (vbc->state != VBC_STATE_STOLEN)
extrachance = 0;
如果我们重用连接,vbc->state
将设置为 VBC_STATE_STOLEN
(Varnish-Cache/bin/varnishd/cache/cache_backend_tcp.c
行 364
)。当我们打开一个新连接时,这个值没有被设置。到目前为止,还不错。
i = V1F_SendReq(wrk, bo, &bo->acct.bereq_hdrbytes, 0);
if (vbc->state != VBC_STATE_USED)
VBT_Wait(wrk, vbc);
assert(vbc->state == VBC_STATE_USED);
if (i == 0)
i = V1F_FetchRespHdr(bo);
这样做是将请求发送到后端。如果一切顺利,我们然后调用 V1F_FetchRespHdr
,它等待源发送其协议响应和 headers。如果我们按照代码进入V1F_FetchRespHdr
:
VTCP_set_read_timeout(htc->fd, htc->first_byte_timeout);
...
do {
...
i = read(htc->fd, htc->rxbuf_e, i);
if (i <= 0) {
bo->acct.beresp_hdrbytes +=
htc->rxbuf_e - htc->rxbuf_b;
WS_ReleaseP(htc->ws, htc->rxbuf_b);
VSLb(bo->vsl, SLT_FetchError, "http %sread error: EOF",
first ? "first " : "");
htc->doclose = SC_RX_TIMEOUT;
return (first ? 1 : -1);
}
在这里,我们看到我们在执行 read
系统调用之前在套接字上设置了超时。如果读取 returns 错误(< 0
情况)或 EOF(== 0
情况),并且这是我们第一次调用 read,我们最终记录 http first read error: EOF
正如您在 varnishlog
输出中看到的那样。
因此,如果您打开一个新的到后端的连接,并且在发送请求后后端超时或关闭连接,则会出现此错误。
就个人而言,我会怀疑您的来源是否正在关闭连接;我认为超时通常更有可能。但是如果您的后端认为它有太多打开的连接,或者它可能通过连接收到太多请求,或者类似这样的情况,连接可能会被关闭。
希望对您有所帮助!
我不时在日志中看到 varnish 中的以下 503 错误:
* << BeReq >> 213585014
- Begin bereq 213585013 fetch
- Timestamp Start: 1452675822.032332 0.000000 0.000000
- BereqMethod GET
- BereqURL /client/hedge-funds-asset-managers/
- BereqProtocol HTTP/1.1
- BereqHeader X-Real-IP: 123.125.71.28
- BereqHeader Host: XXXXXXXXXXXXXXXXXXX
- BereqHeader X-Forwarded-Proto: http
- BereqHeader User-Agent: Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)
- BereqHeader Accept-Encoding: gzip
- BereqHeader Accept-Language: zh-cn,zh-tw
- BereqHeader Accept: */*
- BereqHeader X-Forwarded-For: 172.18.210.22
- BereqHeader X-Varnish: 213585014
- VCL_call BACKEND_FETCH
- VCL_return fetch
- BackendOpen 232 reload_2016-01-12T07:28:50.cp_12 162.251.80.23 80 172.18.210.71 40019
- Timestamp Bereq: 1452675822.047840 0.015508 0.015508
- FetchError http first read error: EOF
- BackendClose 232 reload_2016-01-12T07:28:50.cp_12
- Timestamp Beresp: 1452675876.038544 54.006212 53.990704
- Timestamp Error: 1452675876.038555 54.006223 0.000010
- BerespProtocol HTTP/1.1
- BerespStatus 503
- BerespReason Service Unavailable
- BerespReason Backend fetch failed
- BerespHeader Date: Wed, 13 Jan 2016 09:04:36 GMT
- BerespHeader Server: Varnish
- VCL_call BACKEND_ERROR
- BerespHeader Content-Type: text/html; charset=utf-8
- BerespHeader Retry-After: 5
- VCL_return deliver
- Storage malloc Transient
- ObjProtocol HTTP/1.1
- ObjStatus 503
- ObjReason Backend fetch failed
- ObjHeader Date: Wed, 13 Jan 2016 09:04:36 GMT
- ObjHeader Server: Varnish
- ObjHeader Content-Type: text/html; charset=utf-8
- ObjHeader Retry-After: 5
- Length 286
- BereqAcct 350 0 350 0 0 0
- End
问题不在于后端连接,因为来自清漆服务器的相同 URL 的卷曲工作正常。 varnish 的版本是 4.1.0。我不确定 "http first read error: EOF" 是什么意思,感谢您对这个问题的任何了解。由于这个问题的随机性,我也没有办法重现它。
当您在调用 vcl_fetch
之前尝试从后端读取 headers 并且 Varnish 未能获得响应时,"first read error" 会在 Varnish 中发生。 TL;DR:您的后端要么在传递响应之前关闭连接,要么传递响应超时。您可以使用 wireshark 之类的工具来确定发生了这两种情况中的哪一种。
要了解发生了什么,让我们进行一些源代码潜水:
static int __match_proto__(vdi_gethdrs_f)
vbe_dir_gethdrs(const struct director *d, struct worker *wrk,
struct busyobj *bo)
{
int i, extrachance = 1;
struct backend *bp;
struct vbc *vbc;
...
do {
vbc = vbe_dir_getfd(wrk, bp, bo);
没有过多关注董事,vbe_dir_gethdrs
在 Varnish 已经打开一个新连接,或者决定重新使用一个连接后被调用。
if (vbc->state != VBC_STATE_STOLEN)
extrachance = 0;
如果我们重用连接,vbc->state
将设置为 VBC_STATE_STOLEN
(Varnish-Cache/bin/varnishd/cache/cache_backend_tcp.c
行 364
)。当我们打开一个新连接时,这个值没有被设置。到目前为止,还不错。
i = V1F_SendReq(wrk, bo, &bo->acct.bereq_hdrbytes, 0);
if (vbc->state != VBC_STATE_USED)
VBT_Wait(wrk, vbc);
assert(vbc->state == VBC_STATE_USED);
if (i == 0)
i = V1F_FetchRespHdr(bo);
这样做是将请求发送到后端。如果一切顺利,我们然后调用 V1F_FetchRespHdr
,它等待源发送其协议响应和 headers。如果我们按照代码进入V1F_FetchRespHdr
:
VTCP_set_read_timeout(htc->fd, htc->first_byte_timeout);
...
do {
...
i = read(htc->fd, htc->rxbuf_e, i);
if (i <= 0) {
bo->acct.beresp_hdrbytes +=
htc->rxbuf_e - htc->rxbuf_b;
WS_ReleaseP(htc->ws, htc->rxbuf_b);
VSLb(bo->vsl, SLT_FetchError, "http %sread error: EOF",
first ? "first " : "");
htc->doclose = SC_RX_TIMEOUT;
return (first ? 1 : -1);
}
在这里,我们看到我们在执行 read
系统调用之前在套接字上设置了超时。如果读取 returns 错误(< 0
情况)或 EOF(== 0
情况),并且这是我们第一次调用 read,我们最终记录 http first read error: EOF
正如您在 varnishlog
输出中看到的那样。
因此,如果您打开一个新的到后端的连接,并且在发送请求后后端超时或关闭连接,则会出现此错误。
就个人而言,我会怀疑您的来源是否正在关闭连接;我认为超时通常更有可能。但是如果您的后端认为它有太多打开的连接,或者它可能通过连接收到太多请求,或者类似这样的情况,连接可能会被关闭。
希望对您有所帮助!