Производительность NHibernate SecondLevel Cache
При исследовании возможностей, которые предоставляет кэш второго уровня в nhibernate, я протестировал некоторые реализации. В настоящее время результат довольно неожиданный, и я задаюсь вопросом, не оправданы ли мои ожидания.
- Сценарий (Чтение-Тяжелый)
Сначала в базу данных вставляются 4 * 20000 простых объектов с одним строковым свойством, затем четыре потока получают их по идентификатору объекта (session.Get<SimpleObj>(id)
). Каждый поток обращается только к идентификаторам, которые он создал. Шаблон доступа является случайным и получает 1000 объектов, а затем воссоздает сеанс.
while (true)
{
using (var session = sf.OpenSession())
using (var tx = session.BeginTransaction())
{
for (int i3 = 0; i3 < 1000; i3++)
{
long id = (long)ids[rnd.Next(19999)];
var t = session.Get<SimpleObject>(id);
var no = t.StringProperty;
}
Interlocked.Add(ref ops, 1000);
tx.Commit();
}
}
Результаты
- Redis 5000 чтений в секунду
- MemCached 8000 операций чтения в секунду (EnyimMemcached)
- Нет кэширования 15000 операций чтения в секунду (та же машина, TCP-IP)
- Нет кэширования 25000 операций чтения в секунду (та же машина, общая память)
- SysCache2 200000 операций чтения в секунду
- HashtableCacheProvider 380000 операций чтения в секунду
Используемые версии
- NHibernate 4.0.0.4000 и текущая версия https://github.com/nhibernate/NHibernate-Caches
- Redis Server 3.0.501 от https://msopentech.com/opentech-projects/redis/
- MemCached 1.4.5_4_gaa7839e от Couchbase ( http://www.couchbase.com/)
Ожидается ли разная производительность между этими поставщиками и реализацией SysCache2?
Обновление 1
Как отметил Фредерик, сценарий тестирования не имеет особого смысла, поскольку сравниваются два разных класса кэширующих архитектур с двумя разными вариантами использования. Первый класс (5 и 6) нельзя масштабировать по горизонтали, в то время как 1 и 2 можно. В настоящее время SQL-сервер работает на том же компьютере, поэтому используется общая память в качестве механизма IPC, поэтому я отключил все возможности подключения IPC и настроил его для использования TCP/IP для подключения к базе данных. В результате производительность сценария без кэширования падает примерно до 10000 операций в секунду, что приводит к тому, что самый быстрый поставщик распределенного кэширования находится на разумном расстоянии.
При сравнении провайдеров кэширования я хочу проверить, можно ли использовать этих провайдеров в настройке сеанса для запроса для кэширования справочных данных, таких как страны, валюты или структуры баланса. Поскольку производительность наиболее эффективного распределенного кэша по-прежнему составляет лишь половину операций по сравнению с простой версией NHibernate, я не уверен, стоит ли идти этим путем.
2 ответа
Это не удивительно, чтобы иметь SysCache(2)
(или же RtMemoryCache
если вы попробуете этот другой тоже), чтобы работать лучше, чем Redis
или же MemCached
, Преобразователи являются кэшами оперативной памяти, их использование не приводит к сетевому вводу-выводу или межпроцессному взаимодействию. Последние являются распределенными кешами, они подразумевают как минимум межпроцессное взаимодействие и в большинстве случаев сетевой ввод-вывод, что влечет за собой довольно высокую стоимость использования.
Нет никакого смысла сравнивать исполнения распределенных кешей с исполнениями нераспределенных кэшей. Вы должны использовать распределенные кеши, только если вам нужно разделить кеш между многими процессами. Вы не сможете использовать нераспределенные кэши, если у вас есть это требование.
Что удивительно, так это то, что сценарий "без кэша" (то есть SQL-запросы) работает намного лучше, чем распределенные кэши.
На мой взгляд, в вашем описании теста отсутствует один ключевой момент: что влияет на производительность SQL-запросов в вашем сценарии? Если сервер БД размещен на том же физическом хосте, что и веб-сервер, эта стоимость будет довольно низкой по сравнению с более обычной установкой. Некоторое решение БД, такое как SQL-сервер, может даже пропустить любой сетевой ввод-вывод и пойти на межпроцессное взаимодействие в памяти (через именованные каналы), когда они размещены на том же хосте, что и веб-сервер.
Примечание: если вы не планируете настройку SysCache2
для получения аннулирования через уведомления об изменении данных SQL Server, вы должны проверить SysCache
вместо этого, который легче. (Это, вероятно, не изменит результаты в вашем тестовом сценарии.)
Обновление адресации 1:
Самый первый момент - убедиться, что вам действительно нужен ваш кеш для распределения. Каждый процесс может безопасно иметь свой собственный кеш, если:
- Кэшированные данные доступны только для чтения (или, в конечном итоге, если некоторые процессы, обслуживающие устаревшие кэшированные данные, не вызывают проблем в вашем приложении).
- Это не вызывает большого потребления памяти. (Кэшированные данные не тяжелые, дублирование их между многими процессами не будет проблемой.)
Конечно, разогрев кеша данных будет медленнее с нераспределенными кешами, но если распределенный кеш работает слишком плохо, это не главное.
Если вам нужно, чтобы он был распространен, вам следует оценить, является ли ваш SQL Server узким местом под нагрузкой или нет. Если под нагрузкой ваш SQL Server может стать узким местом для вашего приложения, то распределенный кеш поможет его разгрузке. В противном случае лучше не использовать их, если в вашей настройке распределенные кэши стабильно работают хуже, чем ваш db-сервер.
Примечание: если выполняется только условие (2.), вы также можете попробовать нераспределенный кеш с аннулированием из уведомления SQL Server, что позволит вам избежать устаревших данных. Смотрите здесь, как настроитьSysCache2
за уведомление SQL Server.
Фредерик уже писал, что вы тестировали два совершенно разных типа кэширования, поэтому я не собираюсь повторять это снова. Но я добавлю некоторую информацию о том, как работает NH кэш, и отвечу на комментарий Фредерика:
Что удивительно, так это то, что сценарий "без кэша" (то есть SQL-запросы) работает намного лучше, чем распределенные кэши.
На самом деле, это не удивительно:) Вы должны помнить, что:
- NHibernate пытается быть осторожным с кешами и эмулирует "транзакции" для каждой кешированной сущности. В зависимости от его реализации распределенный (NHibernate) кеш может отправлять два дополнительных запроса к серверу кеша (объект блокировки и освобождения), что приводит к серьезному снижению производительности
- разные кеши используют разные сериализаторы. Например, кэш Redis использует встроенный сериализатор XML.NET, который не известен своей скоростью;)
- в зависимости от настроенной политики истечения срока действия, вы можете также получить дополнительное снижение производительности, если вы используете распределенные кэши
- некоторые серверы кэширования (например, Redis) могут вызывать серьезные проблемы с производительностью, удаляя кэшированные записи из-за нехватки ресурсов на их стороне (в этом случае NH попадет на сервер кэширования, получит промах кэша и только затем попытается извлечь сущность из базы данных => 2x сетевые звонки)
Также я должен сказать, что ваши тесты не очень представительные. Перед выполнением этих тестов производительности вам необходимо
- проверьте, сколько объектов будет храниться в кеше
- сколько "ставит" против "получает" у вас для этих лиц
- сколько связанных коллекций у вас в кэшированных объектах
- сколько предметов хранится в связанных коллекциях в среднем
- какие у вас объекты (только для чтения, в основном неизменяемые или все они обновляемые?)
- так далее
И, конечно же, запускайте тесты на ваших данных, а не на фиктивных данных;)