2013-03-25 3 views
0

У вас уже есть вопрос об этом issue, но это не говорит мне, что мне нужно знать: Предположим, у меня есть веб-приложение, и есть много регистрации в каждом кругообороте. Я не хочу открывать дебаты о , почему столько журналов, или как я могу сделать меньше операций loggin. Я хочу знать, какие возможности у меня есть, чтобы сделать эту проблему каротажа. исполнитель и clean.Как свести к минимуму влияние каротажа

До сих пор я реализовал декларативное (основанное на атрибутах) и обязательное ведение журнала, что, кажется, классный и чистый способ сделать это ... теперь, Что я могу сделать с производительностью, предполагая, что могу ожидать эти журналы занимают больше времени, чем ожидалось. Можно ли открыть тему и оставить эту работу?

+0

Не то, чтобы это достаточно конкретный ответ, но я знаю, что если вы регистрируетесь, вы должны выйти из сети на диск, в котором нет вашего веб-приложения. Потому что тогда производительности не будет препятствовать запись журнала на тот же диск, на котором работает webapp. – leeand00

+0

@ leeand00 Это чепуха. –

+1

Вы можете использовать что-то вроде Gurock Smartinspect, которое позволяет вести журнал через трубы, tcp, а также регистрировать файлы. Он также позволяет вести асинхронную регистрацию и прост в использовании. http://www.gurock.com/smartinspect/ –

ответ

1

Я использую приведенный ниже код для регистрации. Это singleton, который принимает Logging и помещает каждое сообщение в concurrentqueue. Каждые две секунды он записывает все, что попало на диск. Теперь ваше приложение откладывается только на время, необходимое для размещения каждого сообщения в списке. Это мой собственный код, не стесняйтесь использовать его.

using System; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading; 
using System.Windows.Forms; 

namespace FastLibrary 
{ 
    public enum Severity : byte 
    { 
     Info = 0, 
     Error = 1, 
     Debug = 2 
    } 

    public class Log 
    { 
     private struct LogMsg 
     { 
      public DateTime ReportedOn; 
      public string Message; 
      public Severity Seriousness; 
     } 

     // Nice and Threadsafe Singleton Instance 
     private static Log _instance; 

     public static Log File 
     { 
      get { return _instance; } 
     } 

     static Log() 
     { 
      _instance = new Log(); 
      _instance.Message("Started"); 
      _instance.Start(""); 
     } 

     ~Log() 
     { 
      Exit(); 
     } 

     public static void Exit() 
     { 
      if (_instance != null) 
      { 
       _instance.Message("Stopped"); 
       _instance.Stop(); 
       _instance = null; 
      } 
     } 

     private ConcurrentQueue<LogMsg> _queue = new ConcurrentQueue<LogMsg>(); 
     private Thread _thread; 
     private string _logFileName; 
     private volatile bool _isRunning; 

     public void Message(string msg) 
     { 
      _queue.Enqueue(new LogMsg { ReportedOn = DateTime.Now, Message = msg, Seriousness = Severity.Info }); 
     } 

     public void Message(DateTime time, string msg) 
     { 
      _queue.Enqueue(new LogMsg { ReportedOn = time, Message = msg, Seriousness = Severity.Info }); 
     } 

     public void Message(Severity seriousness, string msg) 
     { 
      _queue.Enqueue(new LogMsg { ReportedOn = DateTime.Now, Message = msg, Seriousness = seriousness }); 
     } 

     public void Message(DateTime time, Severity seriousness, string msg) 
     { 
      _queue.Enqueue(new LogMsg { ReportedOn = time, Message = msg, Seriousness = seriousness }); 
     } 

     private void Start(string fileName = "", bool oneLogPerProcess = false) 
     { 
      _isRunning = true; 
      // Unique FileName with date in it. And ProcessId so the same process running twice will log to different files 
      string lp = oneLogPerProcess ? "_" + System.Diagnostics.Process.GetCurrentProcess().Id : ""; 
      _logFileName = fileName == "" 
           ? DateTime.Now.Year.ToString("0000") + DateTime.Now.Month.ToString("00") + 
           DateTime.Now.Day.ToString("00") + lp + "_" + 
           System.IO.Path.GetFileNameWithoutExtension(Application.ExecutablePath) + ".log" 
           : fileName; 
      _thread = new Thread(LogProcessor); 
      _thread.IsBackground = true; 
      _thread.Start(); 
     } 

     public void Flush() 
     { 
      EmptyQueue(); 
     } 

     private void EmptyQueue() 
     { 
      while (_queue.Any()) 
      { 
       var strList = new List<string>(); 
       // 
       try 
       { 
        // Block concurrent writing to file due to flush commands from other context 
        lock (_queue) 
        { 
         LogMsg l; 
         while (_queue.TryDequeue(out l)) strList.Add(l.ReportedOn.ToLongTimeString() + "|" + l.Seriousness + "|" + l.Message); 
         if (strList.Count > 0) 
         { 
          System.IO.File.AppendAllLines(_logFileName, strList); 
          strList.Clear(); 
         } 
        } 
       } 
       catch 
       { 
        //ignore errors on errorlogging ;-) 
       } 
      } 
     } 

     public void LogProcessor() 
     { 
      while (_isRunning) 
      { 
       EmptyQueue(); 
       // Sleep while running so we write in efficient blocks 
       if (_isRunning) Thread.Sleep(2000); 
       else break; 
      } 
     } 

     private void Stop() 
     { 
      // This is never called in the singleton. 
      // But we made it a background thread so all will be killed anyway 
      _isRunning = false; 
      if (_thread != null) 
      { 
       _thread.Join(5000); 
       _thread.Abort(); 
       _thread = null; 
      } 
     } 
    } 
}             
+0

Я использую метод расширения для «переопределения» ведения журнала и использования этой техники параллельной очереди, я дам вам знать, улучшится ли время, но это то, что я искал, спасибо за пример кода. –

2

Вещи, которые я хотел бы рассмотреть:

  • Используйте эффективный формат файла, чтобы минимизировать количество данных, которые должны быть записаны (например, XML и текстовые форматы легко читать, но, как правило, очень неэффективно - та же информация может храниться в двоичном формате в гораздо меньшем пространстве). Но не тратьте много времени на процессор, пытаясь упаковать данные «оптимально». Просто перейдите на простой формат, компактный, но быстрый для записи.

  • Испытание на сжатие на бревнах. Это может быть не так с быстрым SSD, но в большинстве ситуаций ввода-вывода накладные расходы на сжатие данных меньше, чем накладные расходы ввода-вывода, поэтому сжатие дает чистый выигрыш (хотя это компромисс - увеличение использования ЦП для снижения I/O).

  • Зарегистрировать только полезную информацию. Независимо от того, насколько важно, что вы думаете, все, вероятно, вы можете найти что-то, что нужно вырезать.

  • Устранение повторных данных. например Вы повторно регистрируете IP-адрес клиента или имя домена? Могут ли они быть сообщены один раз для сеанса, а затем не повторены? Или вы можете хранить их в файле карты и использовать компактное значение индекса, когда вам нужно ссылаться на них? и т. д.

  • Проверка того, что буферизация записанных данных в ОЗУ помогает повысить производительность (например, запись тысяч записей в 20 байтов журнала будет означать 1000 вызовов функций и может вызвать много дискового поиска и других накладных расходов на запись при записи одного 20 000 байт блок в одном пакете означает только один вызов функции и может дать значительное увеличение производительности и максимизировать скорость пакета, которую вы выберете на диск). Часто записи блоков в размерах, таких как (4k, 16k, 32, 64k) данных, хорошо работают, так как он имеет тенденцию соответствовать архитектуре диска и ввода-вывода (но проверьте свою конкретную архитектуру на предмет того, какие размеры могут повысить эффективность). Нижняя сторона буфера ОЗУ - это то, что если произойдет перебой в питании, вы потеряете больше данных. Таким образом, вам, возможно, придется балансировать производительность с надежностью.

  • (Особенно, если вы буферизируете ...) Дамп информации в структуру данных в памяти и передайте ее в другой поток, чтобы передать ее на диск. Это поможет остановить вашу основную нить, поддерживаемую лог-вводом-выводом. Позаботьтесь о потоках, хотя, например, вам, возможно, придется подумать о том, как вы будете справляться со временем, когда вы создаете данные быстрее, чем это может быть зарегистрировано для коротких всплесков - вам нужно реализовать очередь и т. Д.?

  • Вы регистрируете несколько потоков? Могут ли они быть мультиплексированы в один журнал, чтобы, возможно, уменьшить поиск дисков и количество открытых файлов?

  • Есть ли аппаратное решение, которое даст большой взрыв для вашего доллара? например Использовали ли вы диски SSD или RAID? Будет ли демпинг данных на другую серверную помощь или помешать? Возможно, не всегда имеет смысл потратить 10 000 долларов на время разработки, чтобы сделать что-то лучше, если вы можете потратить 500 долларов на простое обновление диска.

+0

Остерегайтесь использования буфера ОЗУ в режиме, чувствительном к времени, так это то, что в какой-то момент буфер должен сместиться на диск, и это может быть дорогостоящей операцией. Вы можете подумать о том, чтобы промыть буфер прямо перед началом операции, чувствительной к времени, чтобы избежать заполнения буфера и принудительного вымывания во время операции. –

+0

За журнальными сообщениями есть журналы и окна событий. Меня интересует открытие потоков и вызовов в очереди. Как вы думаете, это может быть хорошим решением? Я в основном хочу отвлечь этот процесс от основной темы. У вас есть ссылка o что-то об этой «очереди журналов» stuf? –

+0

@Denise: Да, лучше избегать как крошечных, так и больших буферов, поскольку обе экстремумы могут вызвать проблемы с производительностью. 4k-64k обычно хороши, чтобы попробовать. –

Смежные вопросы