Назад | Перейти на главную страницу

Varnish cache, случайно изменяющий длину содержимого ответа

У меня есть система, обращающаяся к ряду серверных служб через четыре кэша лака с балансировкой нагрузки. Примерно 0,1% запросов усекается, поскольку varnish возвращает заголовок неверной длины содержимого. Эта ошибка возникает во всех кешах и различных серверных модулях.

Varnish настроен так, чтобы ничего не кэшировать без допустимых заголовков управления кешем, и эти конкретные запросы не кэшируются. Клиент не отправляет заголовок Accept-Encoding, поэтому Varnish запрашивает ответ в формате gzip с серверной части и отправляет клиенту несжатую версию.

В журнале varnishlog все запросы к серверу выглядят одинаково:

BerespStatus   200
BerespReason   OK
BerespHeader   Content-Encoding: gzip
BerespHeader   Content-Length: 1001
BerespHeader   Content-Type: application/json
BerespHeader   Date: Fri, 08 Feb 2019 14:59:06 GMT
BerespHeader   Vary: Accept-Encoding
TTL            RFC 0 10 0 1549637947 1549637947 1549637946 0 0 cacheable
VCL_call       BACKEND_RESPONSE
TTL            VCL 120 10 0 1549637947 cacheable
TTL            VCL 120 10 0 1549637947 uncacheable
VCL_return     deliver
Filters        testgunzip
Storage        malloc Transient
Fetch_Body     3 length stream
Gzip           u F - 1001 3792 80 7906 7944
BackendReuse   54 default
Length         1001

Я считаю, что линия Gzip u F - 1001 3792 80 7906 7944 заявляет, что заархивированный ответ размером 1001 байт не сжимается до 3792 байта.

Есть три разных типа ответа. Около 50% установили длину содержимого 3792:

VCL_call       RECV
ReqHeader      Surrogate-Capability: key=ESI/1.0
VCL_return     hash
VCL_call       HASH
VCL_return     lookup
HitMiss        1052359 119.885211
VCL_call       MISS
VCL_return     fetch
Link           bereq 1052362 fetch
Timestamp      Fetch: 1549633459.720553 0.004765 0.004765
RespProtocol   HTTP/1.1
RespStatus     200
RespReason     OK
RespHeader     Content-Encoding: gzip
RespHeader     Content-Length: 1000
RespHeader     Content-Type: application/json
RespHeader     Date: Fri, 08 Feb 2019 13:44:19 GMT
RespHeader     Vary: Accept-Encoding
RespHeader     Age: 0
RespHeader     Via: 1.1 varnish (Varnish/6.1)
VCL_call       DELIVER
RespHeader     X-Cache: MISS
RespHeader     X-Cache-Hits: 0
VCL_return     deliver
Timestamp      Process: 1549633459.720567 0.004779 0.000014
RespUnset      Content-Encoding: gzip
RespHeader     Accept-Ranges: bytes
RespUnset      Content-Length: 1000
RespHeader     Content-Length: 3792
Gzip           U D - 1001 3792 80 7906 7944

Около 50% без заголовка длины содержимого, но с фрагментированным кодированием передачи:

Same as above except
...
RespUnset      Content-Length: 1000
RespHeader     Transfer-Encoding: chunked
Gzip           U D - 1001 3792 80 7906 7944

И 0,1%, которые ломают клиента из-за неправильной длины содержимого:

...
RespUnset      Content-Length: 1001
RespHeader     Content-Length: 208
Gzip           U D - 1001 3792 80 7906 7944

Есть ли у кого-нибудь мысли относительно причины этого? Есть предложения по следующему шагу отладки?

Мой VCL ничего не делает с заголовками длины содержимого. Я использую varnish 6.1 (я собираюсь перейти на стабильную версию 6.0.2, но еще не пробовал)


РЕДАКТИРОВАТЬ:

Снижен до 6.0.2, но проблема все еще остается.


РЕДАКТИРОВАТЬ 2:

Я отключил varnish от обновления запроса до gzip с помощью переключателя команд -p "http_gzip_support=off" и это устранило проблему за счет того, что не заархивированные запросы все еще не заархивировались, когда они попадают в бэкэнд, но на данный момент этого достаточно.