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

针对爬虫引发流量激增的Varnish防护策略咨询

解决方案:保护Drupal Term Pages后端免受分散爬虫流量冲击

针对你遇到的分散IP爬虫触发大量未缓存请求打垮后端的问题,结合Varnish特性和Drupal站点的特点,给出以下可落地的方案:

1. 宽限期内单URL后端请求并发控制(解决你的第一个疑问)

Varnish可以在宽限期内限制同一个URL的后端刷新请求,确保只有一个请求去后端获取新内容,其他请求直接返回过期缓存(stale内容),避免后端被重复请求压垮。

在VCL中添加如下逻辑:

sub vcl_hit {
    if (obj.ttl <= 0s) {
        # 进入宽限期,尝试获取新内容
        set req.http.X-Cache = "HIT-Stale";
        set req.http.X-Cache-Status = "Stale-While-Revalidate";
        # 仅允许一个请求去后端刷新,其余返回stale
        if (std.single_req(req.url)) {
            return (fetch);
        } else {
            return (deliver);
        }
    }
    return (deliver);
}

sub vcl_backend_response {
    # 根据更新频率设置合理宽限期(示例为4小时)
    set beresp.grace = 4h;
}

std.single_req会确保同一个URL同时只有一个请求发往后端,其他请求直接返回当前的stale缓存,直到新内容刷新完成。

2. 基于URL前缀的请求速率限制(绕过IP分散问题)

既然爬虫IP分散,就放弃按IP限流,转而针对Term Pages的URL前缀(比如/taxonomy/term/)做请求频率限制,统计单位时间内某个URL的请求次数,超过阈值则返回stale内容。

借助Varnish的vmod_ratecounter实现:

import ratecounter;

sub vcl_recv {
    # 匹配Term Pages路径
    if (req.url ~ "^/taxonomy/term/[0-9]+$") {
        # 限制单个URL每分钟最多20次请求
        if (ratecounter.check(req.url, 20, 60s)) {
            # 超过速率,直接尝试返回缓存(包括stale)
            return (lookup);
        }
    }
}

这个逻辑会限制单个Term Page URL的请求频率,不管来自哪个IP,超过阈值的请求会优先走缓存,避免触发后端请求。

3. 基于后端负载动态调整缓存策略

当后端服务器负载过高时,自动延长宽限期,强制返回stale内容;负载恢复正常后再允许刷新缓存。

可以通过Varnish的backend状态或者外部监控数据实现:

sub vcl_hit {
    if (obj.ttl <= 0s) {
        # 检查后端健康状态或负载(示例为调用内部负载监控接口)
        if (backend.default.health == sick || std.fetch("http://localhost/backend-load") > 80) {
            # 后端负载高,延长宽限期至8小时,返回stale
            set obj.grace = 8h;
            return (deliver);
        } else {
            # 后端正常,允许刷新缓存
            return (fetch);
        }
    }
    return (deliver);
}

这里的std.fetch可以调用内部的负载监控接口(比如通过Prometheus导出的后端负载数据),动态调整缓存策略。

4. 爬虫识别与差异化缓存

通过请求特征识别爬虫,对爬虫返回stale内容,对正常用户优先刷新缓存:

sub vcl_recv {
    # 通过UA或请求特征识别爬虫
    if (req.http.User-Agent ~ "(bot|crawler|spider|scraper)" || req.http.X-Forwarded-For ~ "爬虫IP段特征") {
        set req.http.X-Is-Crawler = "true";
    }
}

sub vcl_hit {
    if (obj.ttl <= 0s) {
        # 爬虫请求直接返回stale内容
        if (req.http.X-Is-Crawler == "true") {
            return (deliver);
        }
        # 正常用户请求触发缓存刷新
        return (fetch);
    }
    return (deliver);
}

也可以结合请求频率,比如某个IP在1分钟内请求超过10个不同的Term Page,标记为爬虫,后续请求直接返回stale。

5. 缓存主动预热

在Drupal节点更新触发缓存清除后,主动预热对应的Term Page,避免爬虫请求触发后端请求。

实现步骤:

  • 在Drupal中编写自定义模块,监听节点更新事件,获取关联的Term ID
  • 调用HTTP客户端批量请求这些Term Page的URL,让Varnish缓存起来
  • 示例Drupal钩子代码:
/**
 * Implements hook_node_update().
 */
function mymodule_node_update($node) {
    // 获取节点关联的Term ID
    $terms = taxonomy_term_load_multiple_by_name($node->field_tags->value, 'tags');
    foreach ($terms as $term) {
        // 发起预热请求
        $url = url('taxonomy/term/' . $term->tid, ['absolute' => TRUE]);
        drupal_http_request($url, ['headers' => ['Cache-Control' => 'no-cache']]);
    }
}

这样在缓存清除后,主动将页面加载到Varnish缓存中,爬虫请求时直接命中缓存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 05:22:47