记录一次 CloudFlare 缓存失效的问题
记录一次 CloudFlare 缓存失效的问题
此内容年代久远,谨慎参考

很久以前写了一个关于空气污染数据的接口,后端为 aspnetcore 3.1,前端随便糊了几个图表,通过 openresty 承载静态前端网页,代理并缓存来自后端的数据

nginxupstream upstream1 {
  server                      service1:5000;
  keepalive                   3;
}

server {
  listen                      80;
  server_name                 api.example.com;
  root                        /www/chart;
  index                       index.html;
  gzip                        off;
  access_log                  off;
  error_log                   off;
  real_ip_header              CF-Connecting-IP;
  proxy_cache                 zone1;
  add_header                  X-Openresty-Cache-Status $upstream_cache_status;
        
  location /data/mainland.json {
    proxy_http_version        1.1;
    proxy_pass                http://upstream1/Data/MainLand;
    proxy_set_header          X-Real-IP $http_cf_connecting_ip;
    proxy_set_header          X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header          Connection '';
    proxy_ignore_headers      Cache-Control;
    expires                   1h;
  }

  location /data/hongkong.json {
    proxy_http_version        1.1;
    proxy_pass                http://upstream1/Data/HongKong;
    proxy_set_header          X-Real-IP $http_cf_connecting_ip;
    proxy_set_header          X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header          Connection '';
    proxy_ignore_headers      Cache-Control;
    expires                   1h;
  }

  location ~* .(js|css|jpg|gif|png)$ {
    expires                   7d;
  }
}

以前是通过和某某云的员工批歪交易了一下,弄了个云分发来抗,源机压力不大。最近该员工即将离职了,我也早做打算开始搬家,准备用 CloudFlare 来抗,反正也不用考虑国内流量。开了个免费套餐,按经验配置完之后就睡觉去了,结果一觉起来源机早就挂了,源机配置比较差,QN 机房的物理机,x5670 双路,24G 内存,100M 带宽,重启机器后看日志发现接入 CloudFlare 不到 1 小时就被压死了。

恢复服务后,监控流量发现 QPS 已经高达 5000,即每秒 5000 个请求,带宽都直接拉满了,正常流量对于源机来说已经算是 DDOS 了。

经过检查,发现问题主要出在 /data/*.json 这些接口地址上,套 CloudFlare 后仅有前端文件(.css、.js)同时满足 X-Openresty-Cache-Status: HITcf-cache-status: HIT,被转发的接口并则是 X-Openresty-Cache-Status: HITcf-cache-status: DYNAMIC,即本机 openresty 正确将接口数据缓存了,但 CloudFlare 那边直接回源了(DYNAMIC 代表部分回源,但绝大多数情况下是完全回源)。

本以为免费套餐的限制,于是花了 100 元买 20 刀开通了专业版套餐,发现现象依旧。联系客服后得知,原来 CloudFlare 默认是按文件后缀名而不是 MIME 配置缓存的,样式表和脚本自然可以被缓存,但这个默认规则将 *.json 视为动态请求排除在外。

csharp// 伪代码
switch(url.postfix){
  case 'txt':
  case 'js':
  case 'css':
  case 'ttf':
  case '......':
    allpyCache(context);
  break;
  default:
    transport(context);
  break;
}

按客服的提示,将 缓存 -> 配置 -> 缓存级别 设置为忽略查询字符串,然后去 规则 -> 页面规则 中新建一条规则

ini[匹配]
api.example.com/data/*
[缓存级别]
缓存所有内容
[源服务器缓存控制]
启用
[边缘缓存 TTL]
与 浏览器缓存 TTL 相同
[浏览器缓存 TTL]
与 边缘缓存 TTL 相同
页面规则
页面规则

设置完成后不到 1 分钟就看到源机压力立刻下降了,5 分钟不到就几乎归零了。

不太清楚为什么 CloudFlare 要通过文件后缀名来设置缓存,一般都是用 MIME 配置的,很多文件存储(图床、视频等)网页应用都是没有后缀名的,比如 https://static.example.com/file-content-hash/format/webp/width/320 这样的形式,这种站默认情况下就完全穿透了。

作者
ragnaroks
发布时间
2022-03-02
创作协议