.net网站应对大批量爬虫造成的压力

知识共享许可协议 版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

网站上线时间长了,内容质量高了,越来越多的爬虫来的越发频繁了,然后问题就频频出现了。。。。

一个网站服务器,一个数据库服务器,两个独立服务器最大支持并发能支持多少,文盲并不清楚,毕竟没有专门研究过这些,但是,爬虫过来后,直接造成cpu100%的情况太恶心了,不能不处理。。。。于是文盲琢磨了一下,觉得可以尝试一下

首先是第一步:如何确定当前请求过多

嗯,开始是考虑检测cpu使用率,后来觉得不合适,于是决定使用网站的应用程序池排队的数量来作为依据

        public static int IIS_QueueCount()
        {
            int r = 0;
            Process p = new Process();
            try
            {
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardInput = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.StartInfo.CreateNoWindow = true;
                p.Start();
                string cmd = @"c:\windows\system32\inetsrv\appcmd list requests";
                p.StandardInput.WriteLine(cmd);
                p.StandardInput.WriteLine("exit");
                while (!p.HasExited)
                {
                    p.WaitForExit(1000);
                }
                string output = p.StandardOutput.ReadToEnd();
                string error = p.StandardError.ReadToEnd();
                p.StandardError.Close();
                p.StandardOutput.Close();
                if (!string.IsNullOrEmpty(error))
                {
                    LogHelper.LogMessage("Server", error);
                }
                else
                {
                    r = output.Split(new string[] { "\n" }, StringSplitOptions.None).Length;
                }
            }
            catch (Exception ex)
            {
                LogHelper.LogMessage("Server", ex);
            }
            finally
            {
                p.Close();
                p.Dispose();
            }
            return r;
        }

LogHelper忽视吧,用来记录异常的一个静态类

这个静态方法是模拟执行命令“c:\windows\system32\inetsrv\appcmd list requests”,来获取该指令返回的数据,这个数据就是当前在IIS应用程序池内正在处理的请求,可以打开IIS管理器,根节点,工作进程,然后打开每个应用程序池看排队队列

在获得了当前队列数量后,我们开始做一个阈值,这个阈值是自行设定的支持的并发数量

然后开始判定,当前请求是否正常响应

        private bool IpFilter()
        {
            bool r = false;
            if (Common.IIS_QueueCount() < 220)
            {
                return r;
            }
            r = true;
            return r;
        }

因为文盲的数据库不够强壮,部分指令相对耗时,所以文盲的网站自认为支持200个并发就差不多了,所以,先把阈值设定成220,后边再修改这个方法

然后,所有页面继承一个基类

    public class BasePage : Page
    {
        protected override void OnLoad(EventArgs e)
        {
            if (IpFilter())
            {
                HttpStateHelper.Return502();
                return;
            }
            base.OnLoad(e);
        }
    }

在请求进来之后,我们处理之前,先判断一下是否有阻塞现象,如果阻塞了,那就不再处理,直接返回502状态码,否则正常处理

嗯。。。。基本上就是这么个流程

然后,下一个问题,如何区分是蜘蛛或者正常访问

文盲使用了一个最笨的办法,那就是打开IIS日志,把里边的所有IP做了分析,并通过whois、nslookup等方法来确定IP所属,然后将IDC机房的IP做了一个IP池,当请求时的IP处于IP池内时,再判断是否有队列,否则全部正常返回

再然后,有些蜘蛛是我们所需要的,也进行放行

那么,修改上边的IpFilter方法

        private bool IpFilter()
        {
            bool r = false;
            if (!HttpStateHelper.IsSpider)
            {
                return r;
            }
            if (Common.IIS_QueueCount() < 220)
            {
                return r;
            }
            if (HttpStateHelper.IsBaidu)
            {
                return r;
            }
            r = true;
            return r;
        }
        public static bool IsSpider
        {
            get
            {
                if (RegexExpand.IsMatch(Agent, @"spider"))
                {
                    return true;
                }
                long[] spider_ip_list = new long[]
                {
                    IPv4ToNum("38.75.137.100"),  // 华盛顿Cogent通信公司
                    IPv4ToNum("38.108.108.178"), // 华盛顿Cogent通信公司
                    IPv4ToNum("45.58.125.90"),   // 美国
                    IPv4ToNum("61.185.255.173"), // Xi'An silver fox Netbar
                    IPv4ToNum("66.117.9.26"),    // 加利福利亚州洛杉矶Corporate Colocation公司
                    IPv4ToNum("69.195.137.34"),  // 美国
                    IPv4ToNum("104.149.7.122"),  // readers.popularsunglassonline-plc.club
                    IPv4ToNum("192.89.0.73"),    // 芬兰
                    IPv4ToNum("192.161.85.250"), // 美国
                    IPv4ToNum("192.186.48.2"),   // 韩国
                    IPv4ToNum("216.244.66.246"), // 加利福尼亚州洛杉矶Wowrack科技公司

                    IPv4ToNum("17.58.103.0"),    // APPLE-WWNET
                    IPv4ToNum("23.19.69.0"),     // 亚利桑那州凤凰城LeaseWeb数据中心
                    IPv4ToNum("23.19.70.0"),     // 亚利桑那州凤凰城LeaseWeb数据中心
                    IPv4ToNum("23.89.139.0"),    // 内华达州克拉克县亨德森市Enzu股份有限公司
                    IPv4ToNum("23.89.142.0"),    // rdns.scalabledns.com
                    IPv4ToNum("36.110.147.0"),   // sogou spider
                    IPv4ToNum("39.104.160.0"),   // aliyun
                    IPv4ToNum("39.105.214.0"),   // aliyun
                    IPv4ToNum("40.77.167.0"),    // search.msn.com
                    IPv4ToNum("42.120.160.0"),   // aliyun
                    IPv4ToNum("42.120.161.0"),   // aliyun
                    IPv4ToNum("42.156.136.0"),   // aliyun
                    IPv4ToNum("42.156.137.0"),   // aliyun
                    IPv4ToNum("42.156.138.0"),   // aliyun
                    IPv4ToNum("42.156.139.0"),   // aliyun
                    IPv4ToNum("42.156.254.0"),   // aliyun
                    IPv4ToNum("42.157.128.0"),   // IDC 雷傲科技IDC机房
                    IPv4ToNum("42.236.10.0"),    // 北京奇虎科技有限公司联通CDN节点
                    IPv4ToNum("42.236.12.0"),    // 360搜索蜘蛛
                    IPv4ToNum("42.236.46.0"),    // 360搜索蜘蛛
                    IPv4ToNum("42.236.54.0"),    // 360搜索蜘蛛
                    IPv4ToNum("42.236.55.0"),    // 360搜索蜘蛛
                    IPv4ToNum("42.236.99.0"),    // 360搜索蜘蛛
                    IPv4ToNum("42.236.101.0"),   // 360搜索蜘蛛
                    IPv4ToNum("42.236.102.0"),   // 360搜索蜘蛛
                    IPv4ToNum("42.236.103.0"),   // 360搜索蜘蛛
                    IPv4ToNum("43.239.120.0"),   // Hebei HuiRi Information Technology Co. Ltd.  ||  河北惠日信息技术有限公司
                    IPv4ToNum("43.239.122.0"),   // Hebei HuiRi Information Technology Co. Ltd.  ||  河北惠日信息技术有限公司
                    IPv4ToNum("45.124.124.0"),   // IDC 驰联网络电信数据中心
                    IPv4ToNum("45.194.243.0"),   // 百度蜘蛛香港IP
                    IPv4ToNum("46.4.96.0"),      // iis server of Germany(de)
                    IPv4ToNum("46.229.168.0"),   // bl.semrush.com
                    IPv4ToNum("47.89.178.0"),    // aliyun
                    IPv4ToNum("47.89.181.0"),    // aliyun
                    IPv4ToNum("47.92.118.0"),    // aliyun
                    IPv4ToNum("49.4.93.0"),      // compute.hwclouds-dns.com
                    IPv4ToNum("52.83.226.0"),    // 宁夏回族自治区中卫市 BGP多线
                    IPv4ToNum("54.36.148.0"),    // a.ahrefs.com
                    IPv4ToNum("54.36.149.0"),    // a.ahrefs.com
                    IPv4ToNum("54.36.150.0"),    // a.ahrefs.com
                    IPv4ToNum("58.87.62.0"),     // 韩国
                    IPv4ToNum("58.87.68.0"),     // 腾讯云
                    IPv4ToNum("60.247.77.0"),    // IDC 中国数码港科技有限公司BGP节点
                    IPv4ToNum("62.234.79.0"),    // 腾讯云
                    IPv4ToNum("66.249.79.0"),    // google bot
                    IPv4ToNum("101.132.173.0"),  // aliyun
                    IPv4ToNum("104.161.102.0"),  // we.love.servers.at.ioflood.com
                    IPv4ToNum("106.11.152.0"),   // aliyun
                    IPv4ToNum("106.11.153.0"),   // aliyun
                    IPv4ToNum("106.11.154.0"),   // aliyun
                    IPv4ToNum("106.11.155.0"),   // aliyun
                    IPv4ToNum("106.11.156.0"),   // aliyun
                    IPv4ToNum("106.11.157.0"),   // aliyun
                    IPv4ToNum("106.11.158.0"),   // aliyun
                    IPv4ToNum("106.11.159.0"),   // aliyun
                    IPv4ToNum("106.14.197.0"),   // aliyun
                    IPv4ToNum("106.38.241.0"),   // sogou spider
                    IPv4ToNum("106.120.173.0"),  // sogou spider
                    IPv4ToNum("106.120.185.0"),  // IDC 北京电信互联网数据中心节点
                    IPv4ToNum("106.120.188.0"),  // sogou spider
                    IPv4ToNum("107.167.77.0"),   // we.love.servers.at.ioflood.com
                    IPv4ToNum("107.167.79.0"),   // we.love.servers.at.ioflood.com
                    IPv4ToNum("107.189.157.0"),  // we.love.servers.at.ioflood.com && www.10mvps.com
                    IPv4ToNum("111.202.100.0"),  // sogou spider
                    IPv4ToNum("111.206.36.0"),   // IDC 北京百度网讯科技有限公司联通节点(BGP)
                    IPv4ToNum("111.206.221.0"),  // baidu spider
                    IPv4ToNum("111.230.136.0"),  // tencent yun
                    IPv4ToNum("115.182.24.0"),   // IDC 北京市 BGP多线
                    IPv4ToNum("115.182.25.0"),   // IDC 北京市 BGP多线
                    IPv4ToNum("115.239.212.0"),  // IDC 百度网讯科技电信节点
                    IPv4ToNum("119.57.158.0"),   // IDC 东四机房
                    IPv4ToNum("119.57.159.0"),   // IDC 东四机房
                    IPv4ToNum("119.90.61.0"),    // IDC 北京市门头沟区 BGP多线
                    IPv4ToNum("121.52.226.0"),   // IDC 诺信科技有限公司
                    IPv4ToNum("123.125.67.0"),   // baidu 
                    IPv4ToNum("123.125.71.0"),   // baidu spider
                    IPv4ToNum("123.125.125.0"),  // sogou spider
                    IPv4ToNum("123.126.68.0"),   // sogou spider
                    IPv4ToNum("123.126.113.0"),  // sogou spider
                    IPv4ToNum("138.201.126.0"),  // webmeup.com
                    IPv4ToNum("140.143.183.0"),  // tencent yun
                    IPv4ToNum("140.143.236.0"),  // tencent yun
                    IPv4ToNum("144.76.22.0"),    // clients.your-server.de
                    IPv4ToNum("151.80.39.0"),    // ahrefs.com
                    IPv4ToNum("157.55.39.0"),    // search.msn.com
                    IPv4ToNum("178.255.215.0"),  // exalead.com
                    IPv4ToNum("180.76.15.0"),    // baidu spider
                    IPv4ToNum("180.97.35.0"),    // 北京百度网讯科技有限公司电信节点
                    IPv4ToNum("191.101.75.0"),   // 黑森州法兰克福Host1Plus数据中心
                    IPv4ToNum("192.80.158.0"),   // rdns.scalabledns.com
                    IPv4ToNum("192.168.1.0"),    // wan
                    IPv4ToNum("207.46.13.0"),    // search.msn.com
                    IPv4ToNum("220.181.51.0"),   // baidu
                    IPv4ToNum("220.181.108.0"),  // baidu spider
                    IPv4ToNum("220.181.125.0"),  // sogou spider
                    IPv4ToNum("220.243.135.0"),  // IDC 广州恒汇网络通信有限公司
                    IPv4ToNum("220.243.136.0"),  // IDC 广州恒汇网络通信有限公司
                    IPv4ToNum("127.0.0.0")       // local
                };
                for (int i = 0; i < spider_ip_list.Length; i++)
                {
                    string ip = Common.NumToIPv4(spider_ip_list[i]);
                    if (RegexExpand.IsMatch(ip, @"\.0$"))
                    {
                        if (ClientIP_Num > spider_ip_list[i] && ClientIP_Num < spider_ip_list[i] + 256)
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (ip == ClientIP)
                        {
                            return true;
                        }
                    }
                }
                return false;
            }
        }

IsSpider方法就是用来验证访问的IP是否是IDC过来的,这个数据可以自行补充调整,然后IsBaidu和这个方法一样,不过是允许放行的IP段,IPv4ToNum就是把IP地址转换成Int64格式的数字,以方便比较

经过这么一番操作后,对数据库压力明显降低,队列池拥塞现象基本不存在了,网站服务器CPU也不会永远飚到100%了,嗯,就是需要维护,如果发现大并发请求过来,还需要自行维护IP池

再说个题外话,如果是服务器组或者购买的CDN服务的话,可以不用考虑这个办法,小公司可以尝试下

猜你喜欢

转载自blog.csdn.net/superwfei/article/details/94730695