Совсем недавно Microsoft презентовал большой пакет обновлений для платформы Windows Azure. В список нововведений входило долгожданное обновление Windows Azure Caching. Раньше разработчик сталкивался с некоторыми трудностями при работе с системой распределенного кэширования — кэш работал очень медленно. Так как Windows Azure хранил данные кэша на отдельных серверах, то на запрос выборки данных уходило порядка 30-100 мс, что является непозволительным для системы, ускоряющей доступ к данным.
Итак, что же изменилось в системе кэширования?
Microsoft решила не отставать от своих конкурентов и добавила поддержку In-Memory Caching. Теперь данные хранятся не на отдельном сервере, а в оперативной памяти сервера и, соответственно, доступ к данным происходит моментально. Попробуем реализовать новый кэш и сравнить скорость работы со старым на примере ASP.NET MVC 3 (C#).
Для доступа к кэшу нам понадобится провайдер. Чтобы реализовть провайдер, создадим для него интерфейс с необходимыми методами:
Первый метод, очевидно, удаляет объект из кэша по ключу, остальные получают (добавляют в случае отсутствия в кэше) данные с установленным ключом и периодом.
Следующим шагом реализуем сам провайдер. Здесь не описывается процесс установки Windows Azure SDK 1.7, подразумевается, что у разработчика стоят все необходимые библиотеки и компоненты для разработки под Windows Azure
Отметим несколько основных моментов, которые следует учесть при реализации провайдера:
Сам провайдер будет выглядеть так:
После написания провайдера нужно настроить кэш. В версии SDK 1.7 в свойствах роли появилась новая вкладка Caching.
На данной вкладке нужно включить поддержку кэша (Enable Caching) и установить количество выделяемого объема памяти под наши данные (например: Сo-located Role: Cache Size 30%)
Последней подготовкой будет добавление новых секций в Web.config. Если в самом начале файла отсутствует раздел
В конец Web.config добавляем описание секции
На этом настройка Windows Azure Caching закончена. Перейдем к проверке работоспособности.
Для тестирования кэша создадим простенькую страничку, которая будет кэшировать текущее время:
Действие
После компилирования проекта и запуска странички в облаке мы видим следующий результат:
При первом открытии страницы происходит добавление записи в кэш, которое в данном примере занимает где-то 16 мс. При последующем обновлении страницы результат получается таким:
Выборка данных из нового In-Memory Distributed Cache занимает меньше 1мс. По скорости, данный кэш не уступает InProc кэшу.
Чтобы узнать, как было раньше, необходимо откатить SDK до версии 1.6 и провести небольшую модификацию Web.config. Заменить секцию
После компиляции проекта и открытия тестовой страницы видим следующие результаты:
Т.е. 29 мс на добавление записи в кэш и после обновления странички:
32 мс на извлечение записи из кэша.
Последнее нововведение Microsoft решило одну из главных проблем Windows Azure — проблему распределенного кэширования. Теперь использовать распределенный кэш можно, не опасаясь за падение производительности приложения, а те, кто использовал для этого другие средства внутри облака Azure, могут вновь вернуться к функционалу предоставляемому Windows Azure API.
Итак, что же изменилось в системе кэширования?
Microsoft решила не отставать от своих конкурентов и добавила поддержку In-Memory Caching. Теперь данные хранятся не на отдельном сервере, а в оперативной памяти сервера и, соответственно, доступ к данным происходит моментально. Попробуем реализовать новый кэш и сравнить скорость работы со старым на примере ASP.NET MVC 3 (C#).
Caching Provider
Для доступа к кэшу нам понадобится провайдер. Чтобы реализовть провайдер, создадим для него интерфейс с необходимыми методами:
public interface ICacheProvider { void RemoveFromCache(string key); T GetFromMethod<T>(string cacheKey, TimeSpan cacheDuration, Func<T> method); T GetFromMethod<T>(string cacheKey, Func<T> method); }
Первый метод, очевидно, удаляет объект из кэша по ключу, остальные получают (добавляют в случае отсутствия в кэше) данные с установленным ключом и периодом.
Следующим шагом реализуем сам провайдер. Здесь не описывается процесс установки Windows Azure SDK 1.7, подразумевается, что у разработчика стоят все необходимые библиотеки и компоненты для разработки под Windows Azure
Отметим несколько основных моментов, которые следует учесть при реализации провайдера:
- Кэш не имеет функционала полной очистки, поэтому нужно предусмотреть возможность инвалидации старых данных при выпуске обновлений;
- Запись в кэш может производить только один поток, во избежание ошибок;
- Windows Azure Caching не бесплатный функционал, поэтому нужно сократить обращения к кэшу до минимума.
Сам провайдер будет выглядеть так:
public class AzureCacheProvider : ICacheProvider { //Необходимо для инвалидации старого кэша при новом релизе private readonly string _prefix = StaticHelper.GetCurrentVersion(); private readonly object _locker = new object(); private readonly DataCache _cache; public AzureCacheProvider() { lock (_locker) { { var factory = new DataCacheFactory(); _cache = factory.GetDefaultCache(); } } } private void RemoveFromCache(string key, DataCache cache) { lock (_locker) { cache.Remove(_prefix + key); HttpContext.Current.Items.Remove(_prefix + key); } } private T GetFromCache<T>(string key, TimeSpan expiration, Func<T> method, DataCache cache) { object cacheItem = HttpContext.Current.Items[_prefix + key]; if (cacheItem == null) { cacheItem = cache.Get(_prefix + key); if (cacheItem != null) HttpContext.Current.Items[_prefix + key] = cacheItem; } if (cacheItem == null) { lock (_locker) { cacheItem = cache.Get(_prefix + key); if (cacheItem == null) { cacheItem = method(); if (cacheItem != null) { HttpContext.Current.Items[_prefix + key] = cacheItem; cache.Put(_prefix + key, cacheItem, expiration); } } } } return (T)cacheItem; } public void RemoveFromCache(string key) { RemoveFromCache(key, _cache); } public T GetFromMethod<T>(string cacheKey, TimeSpan expirationSeconds, Func<T> method) { return GetFromCache(cacheKey, expirationSeconds, method, _cache); } public T GetFromMethod<T>(string cacheKey, Func<T> method) { return GetFromMethod(cacheKey, TimeSpan.FromMinutes(15), method); } }
HttpContext.Current.Items здесь используется для хранения в памяти уже полученных в текущем запросе объектов из кэша, на случай повторного обращения к данным.Конфигурация роли
После написания провайдера нужно настроить кэш. В версии SDK 1.7 в свойствах роли появилась новая вкладка Caching.
На данной вкладке нужно включить поддержку кэша (Enable Caching) и установить количество выделяемого объема памяти под наши данные (например: Сo-located Role: Cache Size 30%)
Web.config
Последней подготовкой будет добавление новых секций в Web.config. Если в самом начале файла отсутствует раздел
configSections, то его необходимо добавить. После чего внутрь поместить следующий код:<section name="dataCacheClients" type="Microsoft.ApplicationServer.Caching.DataCacheClientsSection, Microsoft.ApplicationServer.Caching.Core" allowLocation="true" allowDefinition="Everywhere"/>
В конец Web.config добавляем описание секции
dataCacheClients:<dataCacheClients> <tracing sinkType="DiagnosticSink" traceLevel="Error" /> <dataCacheClient name="default"> <autoDiscover isEnabled="true" identifier="Указываем здесь название Web-роли, в которой настраивали кэш на предыдущем этапе" /> </dataCacheClient> </dataCacheClients>
На этом настройка Windows Azure Caching закончена. Перейдем к проверке работоспособности.
Тестирование кэша
Для тестирования кэша создадим простенькую страничку, которая будет кэшировать текущее время:
<h1>Cache test</h1> Before: <%=DateTime.Now.Millisecond%> ms<br/> <%=Facade.Instance.Cache.GetFromMethod("currentTime", () => DateTime.Now)%><br/> After: <%=DateTime.Now.Millisecond%> ms<br/> <%using(Html.BeginForm("ClearCache","Admin"))%> <%{%> <input type="submit" value="Clear Cache"/> <%}%>
Facade.Instance.Cache в коде выше является экземпляром объекта AzureCacheProvider , полученным с помощью IoC.Действие
ClearCache выглядит достаточно просто: public ActionResult ClearCache() { Facade.Instance.Cache.RemoveFromCache("currentTime"); return View("admin"); }
Результаты
После компилирования проекта и запуска странички в облаке мы видим следующий результат:
Cache test
Before: 553 ms
6/10/2012 11:09:40 AM
After: 569 msПри первом открытии страницы происходит добавление записи в кэш, которое в данном примере занимает где-то 16 мс. При последующем обновлении страницы результат получается таким:
Cache test
Before: 508 ms
6/10/2012 11:09:40 AM
After: 508 msВыборка данных из нового In-Memory Distributed Cache занимает меньше 1мс. По скорости, данный кэш не уступает InProc кэшу.
Как было раньше?
Чтобы узнать, как было раньше, необходимо откатить SDK до версии 1.6 и провести небольшую модификацию Web.config. Заменить секцию
dataCacheClients на:<dataCacheClients> <dataCacheClient name="default"> <hosts> <host name="[Ваш ID].cache.windows.net" cachePort="22233" /> </hosts> <securityProperties mode="Message"> <messageSecurity authorizationInfo="[Ваш ключ]"></messageSecurity> </securityProperties> </dataCacheClient> </dataCacheClients>
После компиляции проекта и открытия тестовой страницы видим следующие результаты:
Cache test
Before: 521 ms
6/10/2012 11:09:40 AM
After: 550 msТ.е. 29 мс на добавление записи в кэш и после обновления странички:
Cache test
Before: 501 ms
6/10/2012 11:09:40 AM
After: 533 ms32 мс на извлечение записи из кэша.
Итог
Последнее нововведение Microsoft решило одну из главных проблем Windows Azure — проблему распределенного кэширования. Теперь использовать распределенный кэш можно, не опасаясь за падение производительности приложения, а те, кто использовал для этого другие средства внутри облака Azure, могут вновь вернуться к функционалу предоставляемому Windows Azure API.

