니스가 새로운 데이터를 가져 오는 동안 캐시에서 오래된 데이터를 보내도록 하시겠습니까?


8

동적으로 생성 된 페이지 (PHP-FPM, NGINX)를 캐싱하고 있으며 그 앞에 광택이 있습니다. 이는 매우 잘 작동합니다.

그러나 캐시 시간 초과에 도달하면 다음과 같이 표시됩니다.

  • 새로운 고객 요청 페이지
  • 바니시는 캐시 시간 초과를 인식합니다
  • 클라이언트가 기다립니다
  • 바니시는 백엔드에서 새 페이지를 가져옵니다.
  • 니스는 클라이언트에 새 페이지를 전달합니다 (다음 요청을 위해 페이지를 캐시하여 즉시 가져옵니다).

내가하고 싶은 것은 :

  • 클라이언트 요청 페이지
  • 바니시는 타임 아웃을 인식
  • 니스는 클라이언트에게 이전 페이지를 제공합니다
  • 니스는 백엔드에서 새 페이지를 가져 와서 캐시에 넣습니다.

필자의 경우 오래된 정보가 큰 문제가되는 사이트가 아니며 특히 몇 분 후에 캐시 시간 초과에 대해 이야기 할 때 아닙니다.

그러나 나는 처벌 사용자가 줄을 서서 기다리는 것을 원하지 않습니다. 어떤 식 으로든 가능합니까?

예를 들어, 1 분 동안 캐시하도록 구성된 서버에 대해 5 분 동안 포위 공격을 실행 한 샘플 출력이 있습니다.

HTTP/1.1,200,  1.97,  12710,/,1,2013-06-24 00:21:06
...
HTTP/1.1,200,  1.88,  12710,/,1,2013-06-24 00:21:20
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:22:08
...
HTTP/1.1,200,  1.89,  12710,/,1,2013-06-24 00:22:22
...
HTTP/1.1,200,  1.94,  12710,/,1,2013-06-24 00:23:10
...
HTTP/1.1,200,  1.91,  12709,/,1,2013-06-24 00:23:23
...
HTTP/1.1,200,  1.93,  12710,/,1,2013-06-24 00:24:12
...

수백 건의 요청이 빠져 나갔습니다 0.02. 그러나 여전히 원시 HTML을 거의 2 초 동안 기다려야하는 사용자가 있다는 점에 대해 우려하고 있습니다.

여기서 더 잘할 수 없습니까?

( 캐시 동안 Varnish send를 보았습니다. 유사하게 들리지만 정확히하려고하는 것은 아닙니다.)

해결책

Shane Madden의 답변에 솔루션이 포함되어 있지만 바로 그것을 알지 못했습니다. 관련이 없다고 생각했기 때문에 내 질문에 포함시키지 않은 또 다른 세부 사항이 있었지만 실제로는 관련이 있습니다.

현재 사용중인 CMS 솔루션에는 니스 데이터베이스 리스너가 있으므로 내용이 변경된 페이지를 금지하도록 니스에 알리는 기능이 있습니다. PURGE특정 페이지를 금지하라는 정규 표현식으로 요청을 보냈습니다 .

요약하자면, 운이 좋지 않은 사용자가있는 두 가지 경우가 있습니다.

  1. 페이지의 일반 광택 TTL이 만료됩니다
  2. 백엔드 사용자가 콘텐츠를 변경하면 삭제 요청을 니스로 보냅니다.

두 경우 모두 "운이 좋지 않은"사용자가 있습니다. 두 번째 경우에는 백엔드 사용자가 페이지를 변경 한 후 일반적으로 페이지를 확인한다는 사실이 완화됩니다. 그러나 반드시 그런 것은 아닙니다.

그럼에도 불구하고 두 번째 경우에는 해결책을 만들었습니다 (예,이 질문은 첫 번째 경우에 대한 답을 찾는 것으로 시작한다는 것을 알고 있습니다 ...

삭제 요청을 보내는 대신 Shanes 제안을 사용하고 VCL을 조정하여 내 광택 데이터베이스 리스너가로 hash_always_miss설정하여 페이지를 가져 오기 위해 특수 요청을 보낼 수 있습니다 true.

현재 아키텍처를 사용하면 실제 비동기 요청을 할 수있는 고급 스러움이 없지만 PHP에서 비동기 GET 요청을 어떻게합니까? 페이지가로드 될 때까지 기다리지 않지만 백엔드에서 페이지를 가져 와서 캐시 할 수있는 니스를 트리거하기에 좋은 GET 요청을 작성할 수있었습니다.

결과적으로 데이터베이스 리스너는 요청을 바니시로 보냈고 특정 페이지를 폴링하는 동안 요청을 "불운"으로 만들지 않았지만 일단 바니시는 백엔드에서 페이지를 완전히 가져 왔습니다 (300ms에서 2 초까지 가능). 갑자기 거기에 있었다.

나는 정상적인 TTL이 떨어졌을 때 동일한 문제를 피하는 방법을 아직 찾지 못했지만 해결책은 Shane이 제안한 것과 정확히 같다고 생각합니다 .wget을 사용하여를 트리거 hash_always_miss하면 목록을 얻을 수있을만큼 똑똑해야합니다. 새로 고침 한 페이지 수

답변:


3

이 문제를 해결하는 데 사용한 솔루션은 페이지의 TTL을 새로 고치기 전에 만료되지 않도록하는 것입니다. 내 시스템 중 하나에서 실행중인 HTTP 클라이언트가 불행한 클라이언트 대신 느린로드를 갖도록 강제하는 것입니다. 의뢰.

필자의 경우 wget에는 cron에서 요청을 표시하고 req.hash_always_miss이를 기반으로 설정하기 위해 특수 헤더를 전송 하여 콘텐츠의 새 사본을 캐시로 가져옵니다.

acl purge {
    "localhost";
}

sub vcl_recv {
    /* other config here */
    if (req.http.X-Varnish-Nuke == "1" && client.ip ~ purge) {
        set req.hash_always_miss = true;
    }
    /* ... */
}

콘텐츠의 경우, 이는 Varnish TTL을 5 분으로 설정하지만 매분마다 캐시 새로 고침 요청을 수행하도록 cron'd wget을 구성하는 것을 의미 할 수 있습니다.


나는 당신이 무슨 뜻인지 이해한다고 생각합니다. 이것은 한 페이지에 좋지만 다른 수천 페이지에 적합합니까? 해당 스케일에서 cron / wget을 사용할 수 없습니다.
mark

본질적으로 캐시에서 현재 유지하려는 페이지를 적어도 선언해야합니다. 이 목록이 주어지면 cron 스크립트의 wget이 도움이되지 않는 이유가 없습니다.
Falcon Momot

나는 이것이 "외부 접근 방식을 바꾼다"는 도전이라고 생각합니다. 궁극적으로 앉아서 각 페이지마다 결정을 내려야합니다. "ttl이 다 되었습니까? 새 버전을 가져 오십시오. 그러나 그 때까지는 이전 버전을 제공하십시오." 흠.
Mark

4

@편집하다:

이 기능이 마스터 브랜치의 최신 버전에서만 구현 된 것 같다는 것을 알려주는 간단한 방법입니다. 귀하의 버전이 아직 유효 하지 않은 정품 확인을 지원하지 않을 수 있습니다 / 게시 한 예제가 제공됩니다. 하나의 불량한 버그가있는 9999/10000 요청이 여전히 백엔드에서 요청이 완료 될 때까지 기다려야합니다.


글쎄, 왜 이전 의견이 작동하지 않는다고 말했는지 100 % 확실하지 않지만 https://www.varnish-software.com/static/book/Saving_a_request.html

  • req.grace- 니스가 오브젝트를 유예 모드로 계속 고려할 수있는 기간을 정의합니다.
  • beresp.grace -beresp.ttl-time Varnish가 오브젝트를 유지하는 기간을 정의합니다.
  • req.grace- 종종 백엔드 상태에 따라 vcl_recv에서 수정됩니다.

나는 현재 매뉴얼에서 말하는 것과 같은 구성을 사용하고 있으며 잘 작동하고 있습니다 ... 여기 내 vcl 파일의 스 니펫이 있습니다 ...

sub vcl_recv {
    # Cache rules above here...
    if (req.backend.healthy) {
        set req.grace = 30d;
    } else {
        set req.grace = 300d;
    }
}

sub vcl_fetch {
    # Fetch rules above here ...

    # If backend returns 500 error then boost the cache grace period...
    if (beresp.status == 500) {
        set beresp.grace = 10h;
        return (restart);
    }

    # How long carnish should keep the objects in cache..
    set beresp.grace = 1h;

    # Actual TTL of cache - If an object is older than this an update will be triggered to the backend server :)
    set beresp.ttl = 1m;
}

더 긴 백엔드 응답 유예 기간 (내 구성과 같은 500 오류)을 제공하려면 백엔드 프로브를 설정해야합니다 ... 백엔드 프로브 사본이 있습니다.

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = { 
        .url = "/nginx-status";
        .timeout = 500 ms; 
        .interval = 3s; 
        .window = 10;
        .threshold = 4;
    }
}

이것은 vcl 4.0에도 유효합니까?
Gadelkareem

0

니스 3에서는 "그레이스 모드"를 통해이 작업을 수행합니다. 설명서 [1]에 따르면 다음 로직을 추가해야합니다.

sub vcl_fetch {
  set beresp.grace = 30m;
} // Makes objects to be cached/stored 30 min beyond its max-age/ttl

sub vcl_recv {
  set req.grace = 60s;
} // Allows varnish to serve objects which expired within last minute.

[1] https://www.varnish-cache.org/docs/3.0/tutorial/handling_misbehaving_servers.html#grace-mode


이것은 OP의 목표를 달성하지 못할 것입니다. 한 클라이언트는 백엔드에서 콘텐츠를 가져 오기를 기다리는 동안 여전히 지연 될 것입니다. 그 클라이언트 뒤에있는 다른 클라이언트는 오래된 유예 결과가 제공 되기는합니다. "TTL이 만료되면 콘텐츠를 요청하는 첫 번째 클라이언트는 15 초 동안 멈추어야하고 두 번째 클라이언트는 유예 사본을 가져와야합니다." - varnish-software.com/static/book/Saving_a_request.html
팍스

죄송합니다. 처음 만료 된 요청에서 실제로 어떻게 작동하는지 알지 못했습니다.
NITEMAN

"배경 요청"을 시작하기 위해 ttl cheat & inline C를 사용하여 원하는 목표를 달성 할 수도 있습니다.
NITEMAN
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.