Как регистрировать изменения в базе данных каждые 5 минут в приложении с высокой транзакцией с помощью C# и SQL?

представьте себе такой сценарий: у вас есть веб-службу WCF, которая попадает до миллиона раз в день. Каждый удар содержит идентификатор" Account ID". Служба WCF размещается в распределенном ASP.NET кластер, и у вас нет доступа к удаленному рабочему столу к серверу.

ваша цель-сохранить" количество просмотров в час " для каждого идентификатора учетной записи в базе данных SQL. Результаты должны выглядеть так:

[Time], [AccountID], [NumberOfHits]
1 PM, Account ID (Bob), 10 hits
2 PM, Account ID (Bob), 10 hits
1 PM, Account ID (Jane), 5 hits

вопрос: Как вы можете сделать это без подключения к База данных SQL server при каждом попадании?

вот одно решение, о котором я подумал: сохраните временные результаты в системе.Сеть.Кэшировать объект, прослушивать его срок действия, а по истечении срока действия кэша записывать все накопленные данные в базу данных по истечении срока действия кэша.

есть мысли о лучшем подходе?

6 ответов


Deffered update-это ключ, действительно, и вы находитесь на правильном пути с вашим подходом к локальному кэшу. Пока у вас нет требования отображать последнее обновление-количество при каждом посещении, решение простое: обновите локальный кэш account_id->count и периодически просматривайте этот кэш, замените счетчик на 0 и добавьте счетчик к общему количеству в базе данных. Вы мая потерять некоторые посещения рассчитывает, если ваш ASP.Net процесс потерян, и ваш дисплей hit count не точная (Node 1 int he ASP farm возвращает количество латов, узел 2 возвращает свой собственный локальный, отличный от узла 1).

Если вы должны иметь точное отображение подсчетов на каждый результат возврата (будь то возврат страницы или возврат службы, мало значения), то он становится волосатым довольно быстро. Централизованный кэш, такой как Memcache, может помочь создать решение, но не является тривиальным.

вот как я бы сохранил локальный кэш:

class HitCountCache
{
   class Counter 
   {
       public unsigned int count {get;set}
       public accountid {get;set}
   };

   private Dictionary<accountType, Counter> _counts = new Dictionary<...>();
   private Object _lock= new Object();

   // invoke this on every call
   //
   void IncrementAccountId (accountId)
   {
      Counter count;
      lock(_lock) 
      {
         if (_counts.TryGetValue (accountId, out count))
         {
            ++count.count;
         }
         else
         {
            _counts.Add (accountId, 
                new Counter {accountId = accountId; count=0});
         }
      }
   } 

   // Schedule this to be invoked every X minutes
   //
   void Save (SqlConnection conn)
   {
      Counter[]  counts;

      // Snap the counts, under lock
      //
      lock(_lock)
      {
          counts = _counts.ToArray();
          _counts.Clear();
      }

      // Lock is released, can do DB work
      //
      foreach(Counter c in counts)
      {
          SqlCommand cmd = new SqlCommand(
                 @"Update table set count+=@count where accountId=@accountId", 
                 conn);
          cmd.Parameters.AddWithValue("@count", c.count);
          cmd.Parameters.AddWithValue("@accountId", accountId);
          cmd.ExecuteNoQuery();
      }
   } 
}

это скелет, это может быть улучшено, а также может быть сделано, чтобы вернуть текущее общее количество, если это необходимо, по крайней мере общее количество, известное локальным узлом.


один из вариантов-сбросить соответствующую информацию в журналы сервера (API ведения журнала уже оптимизированы для работы с большими объемами транзакций) и получить их с помощью отдельного процесса.


вы спросили: "Как вы можете сделать это без подключения к базе данных SQL server при каждом попадании?"

использовать пул соединений. При пуле соединений несколько подключений к SQL server открываются один раз, а затем повторно используются для последующих вызовов. Таким образом, при каждом попадании в базу данных вам не нужно подключаться к SQL server, потому что вы уже подключены и можете повторно использовать существующее соединение для доступа к базе данных.

обратите внимание, что пул соединений используется по умолчанию в SQL ado.net провайдер, поэтому вы можете использовать уже, даже не зная об этом.


предлагаемый объект в памяти является самым быстрым, но рискует потерять данные в случае сбоя приложения или сервера. Чтобы уменьшить потерю данных, вы можете лениво записать кэшированные данные на диск. Затем периодически считывайте данные из файла кэша и записывайте агрегированные данные на SQL server.


любая причина, почему они не используют App fabric или тому подобное?

можете ли вы войти в реализацию сервиса? Если это так, способ поразить это, чтобы иметь реализацию службы огонь "огонь и забыть" стиль ведения журнала вызова любой другой службы, которую вы настроили для регистрации этого щенка. Не должен задерживать выполнение, должен выживать при сбоях приложений и тому подобное и не требует копания в угол SQL.

Я честно не взял бы работу, если бы я не мог попасть на фронт в конце концов, большинство других подходов обречены на провал.


Если ваша цель-производительность на веб-сайте, то, как сказал другой плакат, просто используйте огонь и забудьте. Это может быть веб-сервис, в который вы отправляете данные, или вы можете создать службу, работающую в фоновом режиме, прослушивая очередь MSMQ. Если вам интересно, я могу привести еще несколько примеров. Если вам нужно синхронизировать веб-сайт или инструмент администрирования с базой данных, вы можете хранить значения в кэше высокой производительности, например memcache, одновременно обновляя базу данных.

Если вы хотите запустить пакет из 100 запросов в БД в одном запросе, а затем создать отдельную службу, снова с MSMQ, которая опрашивает очередь и ждет > 100 сообщений в очереди. Как только он обнаруживает, что есть 100 сообщений, он открывает транзакцию с MSTDC и считывает все сообщения в память и пакует их для запуска в одном запросе. MSMQ прочный, это означает, что если сервер отключается или служба не работает при отправке сообщения, он все равно будет доставлен, когда служба выйдет в интернет. Сообщения удаляется из очереди только после завершения запроса. Если ошибки запроса или что-то происходит со службой, сообщения по-прежнему будут в очереди для обработки, вы ничего не потеряете. MSTDC просто помогает вам сохранить все в одной транзакции, поэтому, если одна часть процесса терпит неудачу, все откатывается.

Если вы не можете сделать службу windows для этого, просто сделайте веб-сервис, который вы вызываете. Вы по-прежнему отправляете сообщение MSMQ каждый раз при загрузке страницы и говорите раз в 10 раз страница загружается Вы запустите веб-сервис для обработки всех сообщений в очереди. Единственная проблема, с которой вы можете столкнуться, - это установка службы MSMQ, однако многие хостинги и установить что-то подобное для вас, если вы попросите.