在 Varnish 4 中重试时更改后端

问题描述 投票:0回答:2

我希望能够在 Varnish 4 中重试时更改后端。我们已经使用 Varnish 3 在不同的(较旧的)应用程序上进行了此操作,但我无法弄清楚 v4 的情况,也找不到太多文档。我们想要的设置是有 2 组控制器 - 一组用于初始请求,尝试在与 varnish 相同的数据中心中尝试本地服务器,因为这样速度更快,然后只有在失败时,才从其他控制器中随机选择服务器数据中心。

在 v3 中,这很简单:

sub vcl_recv {
    if (req.restarts == 0) {
        set req.backend = defaultdirector;
    } else {
        set req.backend = backupdirector;
    }
}

#Then in vcl_fetch and/or vcl_error something like:
if (beresp.status >= 500 && req.restarts < some_max) {
    return(restart);
}

但现在在 v4 中,重启据说已经被重试取代,整个文档是:

在3.0中,可以在注意到后端响应错误后执行返回(重新启动),以更改为不同的后端。

这现在称为返回(重试),并跳回到 vcl_backend_fetch。

这只影响后端获取线程,客户端处理不受影响。

但是我仍然看到一些人的示例代码包含 return(restart) 而不是 return(retry),并且没有一个使用重试命令的示例。

我理解varnish不应该再次执行vcl_recv中的所有工作(例如剥离cookie),因为这只是与后端的通信失败,所以反弹回后端获取而不是有意义重做所有前端处理,但如果我尝试更改 vcl_backend_fetch 中的后端,则会出现编译错误。我怎样才能做到这一点?

varnish varnish-vcl
2个回答
12
投票

官方文档有点误导。事实上,restart仍然存在:你可以在vcl_deliver中捕获错误,并使用req.backend_hintvcl_recv中相应地设置后端:

sub vcl_recv {
    if (req.restarts == 0) {
        set req.backend_hint = defaultdirector.backend();
    } else {
        set req.backend_hint = backupdirector.backend();
    }
}

sub vcl_deliver {
    if (resp.status >= 500 && req.restarts < some_max) {
        return(restart);
    }
}

或者,如果更合适,您可以在 vcl_backend_responsevcl_backend_fetch 之间使用 retry

sub vcl_backend_fetch {
    if (bereq.retries > 0) {
        set bereq.backend = backupdirector.backend();
    }
}

sub vcl_backend_response {
    if (beresp.status >= 500 && bereq.retries < some_max) {
        return(retry);
    }
}

0
投票

我正在写另一个答案,因为@komuta 答案中没有处理一个案例。有趣的是,我在 2017 年添加了一条评论...

所以缺失的情况就是后端没有回复!如果是这样,则不会调用

vcl_backend_response
,因为根据定义,没有响应!

sub vcl_recv {
    set req.backend_hint = defaultdirector.backend();
}
 
sub vcl_backend_fetch {
    // builtin, not sure it's needed...
    if (bereq.method == "GET") {
        unset bereq.body;
    }

    // if there was a call to the first director, which failed, then we're back with a (retry) call, now we change the director:
    if (bereq.retries > 0) {
        set bereq.backend = backupdirector.backend();
    }

    return (fetch);
}

sub vcl_backend_response {
    // for example if you don't expect an HTTP 500 error, then let's retry!
    if (beresp.status == 500 && bereq.method == "GET") {
        return (retry);
    }

    [...]

    return (deliver);
}

sub vcl_backend_error {
    // here we've had an error with the backend, possibly a network error, or webserver crash, so we want to retry it!
    return (retry);
}

sub vcl_synth {
    // this is where we'll end when bereq.retries will hit max_retries (defaults to 4)

    set resp.body = {"oops..."}

    return (deliver);
}
© www.soinside.com 2019 - 2024. All rights reserved.