近期遭遇了sqlserver2005 cpu 使用率居高不下,导致网站动态页面无法打开的情况。
对于数据库的sql语句优化仅局限在网站在被正常用户正常访问的时候。而如果出现恶意用户,大量访问动态页则无能为力。
基于这样一个事实:作为一个正常用户通常很少在一天内大量访问一个网站的动态页(>100),否则就可以将其视为非正常用户,可通过技术手段将其重定向到静态页面。
相关技术:.net http请求处理、唯一实例类、DataTable
实现一个HttpModule类:用户http请求的处理,获取当前url \用户ip等信息
实现一个Single类:只有一个实例对象,用于每个ip请求的控制。
Single类中静态化一个DataTable,用于存储ip以及访问次数。通过DataView查找ip
这样再通过设置每个ip的最大访问次数就可以有效的防止恶意用户访问,从而使网站平稳运行。
一点心得,不吝赐教。
------------------------------------------------------------------------------------------------------------------------------------------
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
///
///myHttpModule 的摘要说明
///
public class myHttpModule:IHttpModule
{
public myHttpModule()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
public void Dispose() { }
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(Application_BeginRequest);
}
public void Application_BeginRequest(object sender, EventArgs e)
{
string oldurl = HttpContext.Current.Request.RawUrl;
string ip = HttpContext.Current.Request.UserHostAddress;
if (oldurl.IndexOf(".aspx") >= 0)
{
//获取当前ip计数
int count = Visitor.getInstance().setDt(ip);
int max = Visitor.getInstance().getMaxCount();
if (count > max)
{
HttpContext.Current.Response.Redirect("~/0.html");
}
}
}
}
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
///
///访问控制
///
public class Visitor
{
public Visitor()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
private static Visitor _instance;
private static int _count;
private static DataTable dt;
private static DateTime next;
private static int _MAX;
public static Visitor getInstance()
{
if (_instance == null)
{
_instance = new Visitor();
}
return _instance;
}
//获取当前计数
public int getCount()
{
_count += 1;
return _count;
}
public int setDt(string ip)
{
int _result = 0;
if (dt == null)
{
dt = new DataTable();
}
if (dt.Columns.Count == 0)
{
dt.Columns.Add("IP");
dt.Columns.Add("COUNT");
DataColumn[] dc = { dt.Columns["IP"] };
dt.PrimaryKey = dc;
}
Clear();
//保存数据
DataView dv = dt.DefaultView;
dv.RowFilter = "IP='" + ip + "'";
DataTable dtTemp = dv.ToTable();
if (dtTemp.Rows.Count > 0)
{
_result = Convert.ToInt16(dv.Table.Rows[0]["COUNT"]) + 1;
//编辑
dv.Table.Rows[0]["COUNT"] = _result;
//dtTemp.Rows[0]["COUNT"] = _count;
}
else
{
//新增
DataRow dr = dt.NewRow();
dr["IP"] = ip;
dr["COUNT"] = 1;
dt.Rows.Add(dr);
_result = 1;
}
return _result;
}
public void Clear()
{
if (next == null)
{
next = DateTime.Now.AddDays(1);
}
if (DateTime.Now > next)
{
dt.Clear();
next = DateTime.Now.AddDays(1);
}
}
//获取dt记录数
public int getRowsCount()
{
if (dt != null)
{
return dt.Rows.Count;
}
else
{
return -1;
}
}
//获取最大访问量
public int getMaxCount()
{
if (_MAX == 0)
{
_MAX = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings.Get("MAX_COUNT"));
}
return _MAX;
}
}
web.config中添加
//.............................方案优化.............................................................
以上解决方案在实际使用中存在不足,首先局域网用户IP一样,这样每天设置一个上限机动性不强,大小不好掌控。
现采取如下方案,每隔一段时间(20分钟)清理一次记录,这样20分钟内访问次数可控制在200次左右,小区间内重复率也可以降低,应该比上面的方式更人性化。