Следует ли использовать Disruptor (LMAX) с большой моделью в памяти и CQRS?


Наша система имеет структурированную модель (около 30 различных сущностей с несколькими видами отношений), полностью сохраненную в памяти (около 10 Гб) из соображений производительности. На этой модели мы должны выполнить 3 вида операций:

  1. обновление одной или нескольких сущностей
  2. запрос на определенные данные (для этого обычно требуется прочитать тысячи сущностей)
  3. получить статистические данные (сколько памяти используется, сколько запросов на вид и т.д.)

В настоящее время архитектура является довольно стандартный, с пулом потоков для сервлетов, использующих общую модель. Внутри модели есть много параллельных коллекций, но все же есть много ожиданий, потому что некоторые сущности "горячее" и в основном потоки хотят читать/записывать их. Обратите внимание также, что обычно запросы занимают гораздо больше времени и ресурсов процессора, чем записи.

Я изучаю возможность перехода на архитектуру Disruptor, сохраняя модель в одном потоке, перемещая все возможное (проверка валидности, аудита и т. д.) из модели в отдельный потребитель.

Первый вопрос, конечно: имеет ли это смысл?

Второй вопрос: в идеале запросы на запись должны иметь приоритет над запросами на чтение. Что является лучшим способом, чтобы иметь приоритет в Дизраптор? Я думал о 2-х кольцевых буферах, а затем попытался читать из высокоприоритетного чаще, чем из низкоприоритетного.

Чтобы прояснить вопрос больше архитектурный, чем о фактическом коде LMAX Разрушитель.

Обновление с более подробной информацией

Данные-это сложная область, в которой множество сущностей (>100k) различных типов (~20) связаны между собой в виде древовидной структуры с множеством различных коллекций.

Запросы обычно включают в себя обход тысяч сущностей для поиска правильных данных. Обновления часты, но довольно ограничены, например, 10 сущностей за раз, поэтому в целом данные не меняются очень сильно (например, 20% за час).

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

2 6

2 ответа:

" в идеале запросы на запись должны иметь приоритет над запросами на чтение."

Почему ? Большинство быстрых блокировок, таких как C# ReaderWriterLockSlim, делают обратное.. Запись должна блокировать все операции чтения, чтобы избежать частичного чтения. Таким образом, такие блокировки позволяют многим одновременным считываниям надеяться, что все будет "совсем", а затем делать запись .. (Запись действительно выполняется по своему номеру в очереди, но очень вероятно, что многие чтения, которые пришли после нее, были обработаны до ее блокировки)..

Приоритизация записей-хороший способ убить совпадение..

Является ли возможным параллелизм / CQRS вариантом ?

LMAX может быть подходящим ..

Люди LMAX сначала реализовали традиционные, затем они реализовали актеров (с очередями) и обнаружили, что актеры проводят большую часть времени в очередях. Затем они перешли к однопоточной архитектуре..Теперь disruptor - это не ключ к архитектуре, ключ-это однопоточный BL. С помощью 1 writer (single thread) и небольших объектов вы получите высокий кэш-хит и никаких разногласий. Для этого они должны переместить весь долго работающий код из Бизнес-уровень (который включает в себя IO) . Теперь для этого они используют они использовали disruptor его в основном просто кольцевой буфер с одним писателем, как это было использовано в коде драйвера устройства в течение некоторого времени, но в огромном масштабе сообщений.

Во-первых , у меня есть одно несогласие с этим, LMAX-это акторная система .. Где у вас есть 1 актер для всех BL (и разрушители подключают других актеров) .. Они могли бы значительно улучшить там актерскую систему вместо того, чтобы прыгать до 1 актера для BL , а именно

  1. Не располагайте большим количеством сервисов / акторов, старайтесь иметь обычно используемые компоненты в одном сервисе. ( это происходит снова и снова в SOA / распределенных системах также)
  2. при общении между акторами используйте очереди точка-точка не много к 1. ( как и все служебные автобусы!)
  3. Когда у вас есть очереди точка-точка, убедитесь, что хвост является указателем на отдельную область памяти . С помощью 2 и 3 Теперь можно использовать очереди без блокировки, а очереди / потоки имеют только 1 writer (и вы даже можете использовать не темпоральные 256, а YMM-битные записи в очередь). Однако теперь система имеет больше потоков (и если вы сделали 1 правильно, то относительно небольшое количество сообщений между участниками). Очереди подобны разрушителям и могут пакетной обработкой многих записей и могут использовать стиль кольцевого буфера.

С этими акторами у вас есть более модульная (и, следовательно, главная таблица) система ( и система может запускать больше акторов для обработки очередей-Примечание 1 writer ! )

В вашем случае я думаю, что 20% изменений за час-это огромное количество... Всегда ли запросы включены в объектах памяти ? Есть ли у вас в памяти хэш-таблицы / индексы ? Можно ли использовать коллекции только для чтения ? Имеет ли значение, если ваши данные устарели, например, Ebay использует 1-часовое обновление своей коллекции элементов, поэтому сама коллекция элементов статична. С помощью статической коллекции и статических сводок элементов, они имеют статический индекс, и вы можете искать и находить элементы быстро и все в памяти . Каждый час он перестраивается и когда завершите (это может занять несколько минут для восстановления), система переключится на новые данные. Обратите внимание, что сами элементы не являются статичными.

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

Система, основанная на агентах, может быть лучшим выбором именно потому, что куча сущностей может быть сгруппирована и, следовательно, иметь высокий кэш-хит. Но мне нужно знать больше. например, перемещение проверяет законность и обоснованность , аудит, регистрация и т. д.-Это, вероятно, хороший план . Меньше кода = меньше объектов = больше попаданий в кэш, а объекты LMAX были маленькими.

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