背景

最近我们有一个公开服务提供给客户查询关键词的热度值,由于这个API做在官方网站上,自然没有用户登陆,也没有很高查询成本,所以设计上没有任何鉴权无法进行身份认定,于是就被一个爬虫开了超高并发请求,直接后端的AWS Tomcat CPU被用尽,导致无法响应。

爬虫显然是买了动态代理IP池,存在大量的不同IP进行请求,所以我们仅仅将几个IP加入 deny 策略是无法对其阻止。

方案

只好先用上 Nginx 自带的限制并发的模块 ngx_http_limit_req_module 做两个限制池,一次IP每秒3次请求,每分钟20个请求

http {
    limit_req_zone $binary_remote_addr zone=search_second:10m rate=3r/s;
    limit_req_zone $binary_remote_addr zone=search_minute:10m rate=20r/m;
}

在需要的 location 附加这块的限制

location ^~ /search{
        limit_req zone=search_second;
        limit_req zone=search_minute;
}

此时 Nginx error log 出现了大量的503请求,此时我们发现我们的CPU额度慢慢回复了,那么我们还需要一个优化,出现一定次数的503 IP,我们就可以标记为它为爬虫IP,自动追加到 block 列表中。

block-ip.sh

#!/bin/bash
ERR_LOG=/usr/local/nginx/logs/error.log
BLOCK_IP_FILE=/usr/local/nginx/conf/blockips.conf
BLOCKED_IP=/usr/local/nginx/conf/blocked-ip.txt
BLOCK_IP=/usr/local/nginx/conf/block-ip.txt
NGINX_CMD=/usr/local/nginx/sbin/nginx

#把屏蔽列表备份到blocked-ip.txt文件
#从错误日志中提取恶意访问IP记录到block-ip.txt文件
#清空错误日志
#重启Nginx

cat $BLOCK_IP_FILE > $BLOCKED_IP &&
/bin/sed -nr 's#.*[^0-9](([0-9]+\.){3}[0-9]+).*#\1#p' $ERR_LOG |/bin/awk '{IP[$1]++}END{for (i in IP) print IP[i],i}'|/bin/awk '{if($1>20)print "deny "$2";"}' > $BLOCK_IP &&
/bin/grep -v -f $BLOCK_IP_FILE $BLOCK_IP >> $BLOCK_IP_FILE &&
#cat /dev/null > $ERR_LOG &&
$($NGINX_CMD -s reload)

添加进入计划任务5分钟一次 crontab -e

*/5 * * * * /bin/bash /usr/bin/block-ip.sh &> /dev/null

参考文章:Runbing’s Blog

此时虽然负载下降,服务资源也可用,但是实际上对爬虫采集没有任何威胁,只是拉长它采集的时间而已,还是对我们的网站念念不忘,于是灵机一动,决定给他返回状态码从503改成正常返回200,同时构造了一个空返回值,毕竟很多关键词返回都是空的,这样我们就混淆的所有的结果,让爬虫获得非正确的结果数据。

我们在 search 设置一个 503 地址转 200 到一个固定的 Uri 上,通过这个 Uri 直接 Response API.

location ^~ /search{
        limit_req zone=search_second;
        limit_req zone=search_minute;
        error_page 503 =200 /search-503-res;
}

location /search-503-res {
        return 200 '{"code":1,"data":[]}';
}

当我们频繁刷新就会发现前几次数据正常,后面都都返回空数据,过一会又正常了,当然对于正常客户不会有类似的情况。

GoogleTagManager 国内代理以及Chrome Extension接入GA4

背景Google Analytics(UA) 于2023年7月要求全面下架,所以必须迁移使用 Google Analytics 4(GA4),在迁移的过程,因为GA4使用的是 GoogleTagManager 的方式进行装载,我们发现在中国内无法加载这个域名。详细监听请求后...… Continue reading

Redis原子性事务Lua应用

Published on June 28, 2020

Ngrok私有自定义域名部署

Published on February 24, 2020