Оптимизации огонь и забыть трекер страница


У меня есть немного кода, который пришел из яиц заведующий кафе долгое время назад и он работал большой. Но я прогнал весь сайт через профайлер Редгейт по. и он придумал, как самая большая горячая точка в моем коде. (Честно говоря, он побежал так жарко остальной части моего сайта вряд ли подсыпали.) Суть ее в том, чтобы захватить трафик на мой сайт и отфильтровать роботов, если это нуждаться, чтобы быть заблокирован. Он отлично работал в течение многих лет и я хочу использовать его, но надеясь, что он может быть оптимизирован.

Начинается в мировой.эйсакс:

protected void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
    Logger.LogRequest(sender as HttpApplication);
}

Это переходит в класс logger. Не настоящее имя, просто поменяли на пост.

public class Logger
{
    private static string _conn = ConfigurationManager.AppSettings["MyDatabase"];
    private static bool _denyBots = false;

    private static void DenyAccess(HttpApplication app)
    {
        app.Response.StatusCode = 0x191;
        app.Response.StatusDescription = "Access Denied";
        app.Response.Write("401 Access Denied");
        app.CompleteRequest();
    }


    public static bool IsCrawler(HttpRequest request)
    {
        bool isCrawler = request.Browser.Crawler;
        if (!isCrawler)
        {
            Regex regEx = new Regex("Slurp|slurp|ask|Ask|Teoma|teoma");//shortened
            isCrawler = regEx.Match(request.UserAgent).Success;
        }
        return isCrawler;
    }

    public static void LogRequest(HttpApplication app)
    {
        HttpRequest request = app.Request;

        bool isCrawler = IsCrawler(request);
        string userAgent = request.UserAgent;
        string requestPath = request.Url.AbsoluteUri;
        string referer = (request.UrlReferrer != null) ? request.UrlReferrer.AbsoluteUri : "";
        string userIp = request.UserHostAddress;
        string isCrawlerStr = isCrawler.ToString();

        object[] parms = new object[] { userIp, userAgent, requestPath, referer, isCrawlerStr };
        try
        {
            ThreadUtil.FireAndForget(new ThreadUtil.InsertOrUpdateDelegate(ThreadUtil.InsertLog), 
                new object[] { _conn, "insertRequest", parms });
        }
        catch (Exception ex)
        {
            app.Response.Write(ex.Message);
        }

        if (isCrawler && _denyBots)
            DenyAccess(app);

    }
}

И фактический код продевать нитку:

public class ThreadUtil
{
    private static AsyncCallback callback = new AsyncCallback(ThreadUtil.EndWrapperInvoke);
    private static DelegateWrapper wrapperInstance = new DelegateWrapper(ThreadUtil.InvokeWrappedDelegate);

    private static void EndWrapperInvoke(IAsyncResult ar)
    {
        wrapperInstance.EndInvoke(ar);
        ar.AsyncWaitHandle.Close();
    }

    public static void FireAndForget(Delegate d, params object[] args)
    {
        wrapperInstance.BeginInvoke(d, args, callback, null);
    }

    private static void InvokeWrappedDelegate(Delegate d, object[] args)
    {
        d.DynamicInvoke(args);
    }

    public static void InsertLog(string conn, string proc, object[] parms)
    {
        SqlHelper.ExecuteNonQuery(conn, proc, parms);
    }

    private delegate void DelegateWrapper(Delegate d, object[] args);

    public delegate void InsertOrUpdateDelegate(string conn, string proc, object[] parms);
}

Хранимая процедура будет заменена всего лишь параметризованные SQL-вставки. Может быть, это нормально, и это просто профайлер возникли проблемы с ним, как это было пару лет назад. Как я сказал, что он работал штрафа для меня это долго, но это только кажется, что может быть лучше. Также название может быть ужасной, что я хреново титулов.

Редактировать: подумав об этом сегодня утром, я подумал, может быть, Application_PreRequestHandlerExecute блокирует вызывающий ждать, прежде чем Новый Поток стреляет что может быть, почему profilier была такая проблема с ним? Может быть, кто-то мог звонить в это. Также обратите внимание, что код, который был profilied был под URL-адрес рерайтерам, так что все запросы будут обработаны ASP.NET поэтому каждая страница загружается могло вызвать этот код должен выполняться от одного до 30 раз или больше, если есть много изображения или скрипты загрузки на странице.

Редактировать: Запустил его снова через муравьев и нашли следующие горячие точки:

public static void LogRequest(HttpApplication app)
{
    ...
    bool isCrawler = IsCrawler(request);
    string requestPath = request.Url.AbsoluteUri;
    ...
    string userIp = request.UserHostAddress;
    ...
    ThreadUtil.FireAndForget(new ThreadUtil.InsertOrUpdateDelegate(ThreadUtil.InsertLog),
                    new object[] { _conn, "insertRequest", parms });
    ...
}

public static void FireAndForget(Delegate d, params object[] args)
{
    wrapperInstance.BeginInvoke(d, args, callback, null);
}

Двумя основными правонарушителями являются строки requestPath = запрос.URL-адрес.AbsoluteUri; и wrapperInstance.Метод BeginInvoke(д аргументы, обратного вызова, значение null);



1328
5
задан 8 сентября 2011 в 01:09 Источник Поделиться
Комментарии
2 ответа

Методы BeginInvoke() вызов-это точка, потому что он будет нужен поток из пула потоков (и когда есть слишком много используется, он будет ждать, пока один будет доступен).

Как микро-оптимизации, попробуйте заменить, что с помощью класса ThreadPool.Метод queueuserworkitem и снова измерять, но в конце концов ты начинаешь один (или более) SQL и вставить запрос в запрос, который будет использовать некоторые ресурсы независимо от того, что асинхронный подход вы используете.

Вы могли бы также использовать sqlcommand, который по BeginExecuteNonQuery / EndExecuteNonQuery делать свои вставки асинхронного (вместо метода BeginInvoke / EndInvoke или пул потоков), но в итоге быстрый решение предполагает не делаешь вставку в БД по запросу, просто напишите необходимые вещи в какой-то очереди (желательно быстрее, чем дБ) и вставить в БД на более позднее время.

5
ответ дан 19 декабря 2011 в 05:12 Источник Поделиться

Выглядит резким для меня. Я бы сделал немного декларативные намерения:

public static class Logger
{
private static readonly string _conn = ConfigurationManager.AppSettings["MyDatabase"];
private const bool _denyBots = false;

private static void DenyAccess(HttpApplication app)
{
app.Response.StatusCode = 0x191;
app.Response.StatusDescription = "Access Denied";
app.Response.Write("401 Access Denied");
app.CompleteRequest();
}

public static bool IsCrawler(HttpRequest request)
{
bool isCrawler = request.Browser.Crawler;
if (!isCrawler)
{
Regex regEx = new Regex("Slurp|slurp|ask|Ask|Teoma|teoma");//shortened
isCrawler = regEx.Match(request.UserAgent).Success;
}
return isCrawler;
}

public static void LogRequest(HttpApplication app)
{
HttpRequest request = app.Request;

bool isCrawler = IsCrawler(request);
string userAgent = request.UserAgent;
string requestPath = request.Url.AbsoluteUri;
string referer = (request.UrlReferrer != null) ? request.UrlReferrer.AbsoluteUri : string.Empty;
string userIp = request.UserHostAddress;
string isCrawlerStr = isCrawler.ToString();

object[] parms = new object[] { userIp, userAgent, requestPath, referer, isCrawlerStr };
try
{
ThreadUtil.FireAndForget(
new ThreadUtil.InsertOrUpdateDelegate(ThreadUtil.InsertLog),
new object[] { _conn, "insertRequest", parms });
}
catch (Exception ex)
{
app.Response.Write(ex.Message);
}

if (isCrawler && _denyBots)
DenyAccess(app);
}
}

и

public static class ThreadUtil
{
private static readonly AsyncCallback callback = EndWrapperInvoke;
private static readonly DelegateWrapper wrapperInstance = InvokeWrappedDelegate;

public delegate void InsertOrUpdateDelegate(string conn, string proc, object[] parms);

private delegate void DelegateWrapper(Delegate d, object[] args);

public static void FireAndForget(Delegate d, params object[] args)
{
wrapperInstance.BeginInvoke(d, args, callback, null);
}

public static void InsertLog(string conn, string proc, object[] parms)
{
SqlHelper.VinManager.ExecuteNonQuery(conn, proc, parms);
}

private static void EndWrapperInvoke(IAsyncResult ar)
{
wrapperInstance.EndInvoke(ar);
ar.AsyncWaitHandle.Close();
}

private static void InvokeWrappedDelegate(Delegate d, object[] args)
{
d.DynamicInvoke(args);
}
}

3
ответ дан 19 декабря 2011 в 11:12 Источник Поделиться