You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Varnish中使用VCL配置基于请求体哈希的哈希式Director?

问题描述

我正尝试配置Varnish,基于请求体的哈希值在多个后端之间进行路由。我找到了不少利用body access配置缓存的示例,其中请求体哈希被用作缓存键,但找不到将请求体哈希用于路由的示例。

我尝试了以下配置,但似乎无法正常工作,这可能是因为bodyaccess并非用于此场景。请问如何在Varnish中使用VCL配置基于请求体哈希的哈希式Director?

vcl 4.1;

import directors;
import bodyaccess;

backend backend1 {
    .host = "backend1.example.com";
    .port = "80";
}

backend backend2 {
    .host = "backend2.example.com";
    .port = "80";
}

sub vcl_init {
    new xhash = directors.hash();
    xhash.add_backend(backend1);
    xhash.add_backend(backend2);
}

sub vcl_recv {
    set req.backend_hint = xhash.backend(bodyaccess.hash_req_body());
}
解决方案

你的思路没问题,但原配置存在几个关键问题需要修正:

  • 请求体读取时机错误:bodyaccess.hash_req_body()需要先加载请求体到内存才能计算哈希,直接在vcl_recv调用会因为请求体未读取导致哈希计算失效。
  • 未过滤请求方法:只有POST、PUT这类带请求体的请求才需要基于请求体哈希路由,GET等无请求体的请求应该按常规逻辑处理。
  • 哈希参数类型不匹配:directors.hash().backend()需要字符串类型的哈希值,而bodyaccess.hash_req_body()返回的是二进制数据,必须转成字符串才能正常使用。

修正后的完整VCL配置如下:

vcl 4.1;

import directors;
import bodyaccess;
import std;

backend backend1 {
    .host = "backend1.example.com";
    .port = "80";
}

backend backend2 {
    .host = "backend2.example.com";
    .port = "80";
}

sub vcl_init {
    new xhash = directors.hash();
    // 可设置后端权重,默认值为1,这里保持两台后端权重一致
    xhash.add_backend(backend1, 1);
    xhash.add_backend(backend2, 1);
}

sub vcl_recv {
    // 仅针对带请求体的请求执行哈希路由逻辑
    if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") {
        // 读取请求体,读取失败则返回503错误
        if (!bodyaccess.read_req_body()) {
            return (synth(503, "Failed to read request body"));
        }
        
        // 计算请求体的SHA256哈希并转成Base64字符串(也可用std.hex()转十六进制)
        set req.http.X-Body-Hash = std.base64_encode(bodyaccess.hash_req_body(sha256));
        
        // 基于哈希值路由到对应后端
        set req.backend_hint = xhash.backend(req.http.X-Body-Hash);
    }
    // 无请求体的请求按默认逻辑处理,示例为路由到backend1
    else {
        set req.backend_hint = backend1;
    }
}

// 可选:确保请求体能正确传递到后端
sub vcl_pass {
    if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") {
        bodyaccess.restore_req_body();
    }
}

sub vcl_miss {
    if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") {
        bodyaccess.restore_req_body();
    }
}

关键说明

  1. 请求体读取:必须先调用bodyaccess.read_req_body()加载请求体,否则哈希计算会失败。如果请求体过大超出Varnish配置的http_req_size限制,读取操作会失败,可根据业务需求调整配置或自定义错误逻辑。
  2. 哈希算法选择:bodyaccess.hash_req_body()支持md5、sha256等算法,默认使用md5,建议优先选择更安全的sha256。
  3. 哈希值转换:通过std.base64_encode()或std.hex()将二进制哈希转成字符串,满足directors.hash()的参数要求。
  4. 请求体恢复:在vcl_pass和vcl_miss中调用bodyaccess.restore_req_body(),确保请求体能完整传递到后端,避免后端接收不到请求体的问题。
  5. 性能考量:处理大请求体时,读取和哈希计算会消耗内存与CPU,建议通过vcl_recv过滤超大请求,或调整Varnish的内存配置优化性能。

内容的提问来源于stack exchange,提问作者Jeno Laszlo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 02:10:15