Таблицы Erlang ETS в сравнении с передачей сообщений: проблемы оптимизации? - PullRequest
14 голосов
/ 03 августа 2011

Я вхожу в существующий (игровой) проект, серверный компонент которого полностью написан на erlang. Иногда бывает сложно получить часть данных из этой системы (мне интересно, сколько у игрока 56 виджетов) из процесса, которому она принадлежит. Предполагая, что я могу найти процесс, которому принадлежат данные, я могу передать сообщение этому процессу и подождать, пока он не передаст сообщение обратно, но это плохо масштабируется для нескольких машин и убивает время ответа.

Я рассматривал вопрос о замене многих задач, существующих в этой игре, системой, в которой информация, к которой часто обращаются несколько процессов, будет храниться в защищенной таблице ets. Владелец стола ничего не будет делать, кроме как получать сообщения об обновлении (игрок только что потратил пять виджетов) и соответственно обновлять таблицу. Он перехватит все исключения и просто перейдет к следующему сообщению об обновлении. Любой процесс, который хотел бы знать, было ли у игрока достаточно виджетов, чтобы купить дурак, должен был бы только заглянуть за стол. (Да, я понимаю, что сообщение может находиться в буфере, что уменьшает количество виджетов, но у меня есть проблема под контролем.)

Боюсь, что мой вопрос - это не вопрос, а запрос комментариев. Я опишу все, что будет полезным и достаточно объяснено или на которое есть ссылки.

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

Ответы [ 3 ]

7 голосов
/ 03 августа 2011

Прежде всего, поведение ETS по умолчанию является последовательным, как вы можете видеть из документации: Erlang ETS . Он обеспечивает атомарность и изоляцию, а также множественные обновления / чтения, если они выполняются в одной и той же функции (помните, что в Erlang вызов функции приблизительно эквивалентен сокращению, единица измерения, которую планировщик Erlang использует для разделения времени между процессами, поэтому множественная функция ETS Операция может быть разделена на несколько частей, создавая возможное состояние гонки).

Если вас интересует архитектура ETS с несколькими узлами, возможно, вам стоит взглянуть на mnesia, если вы хотите одновременный доступ нескольких узлов OOTB к ETS: Mnesia . (подсказка: я говорю конкретно о таблицах ram_copies, методах add_table_copy и change_config).

При этом я не понимаю проблемы с процессом (возможно, подкрепленной неназванной таблицей ets). Я объясню лучше: главная проблема вашего проекта - это первое, основное предположение. Все просто: у вас нет ни одного процесса записи!

Каждый раз, когда игрок берет объект, поражает игрока и т. Д., Он вызывает функцию без побочных эффектов, обновляющую игровое состояние, поэтому даже если у вас есть один процесс, управляющий игровым состоянием, он также должен сообщить другим игрокам клиентов эй, ты помнишь этот объект там? Просто забудь это!'; вот почему основная проблема во многих многопользовательских играх заключается в задержке: задержка, когда работа в сети не является основной проблемой, часто возникает из-за блокировки процедур отправки / получения.

С этой точки зрения, использование непосредственно таблицы ETS, использование постоянной таблицы, словаря процессов (BAD !!!) и т. Д. - это одно и то же, поскольку необходимо учитывать проблемы синхронизации, как в объектно-ориентированном программировании. языки, использующие разделяемую память (Java, все?).

В конце концов, вы должны рассмотреть только ОДНУ главную задачу разработки вашего приложения: согласованность. После разработки согласованного приложения только тогда вам следует заняться настройкой производительности.

Надеюсь, это поможет!

Примечание: я говорил о чем-то вроде сервера MMORPG, потому что я думал, что вы говорите о чем-то подобном.

6 голосов
/ 03 августа 2011

Таблица ETS не решит ваши проблемы в этом отношении.Ваш код (который хочет получить или установить счетчик виджетов игрока) всегда будет выполняться в процессе, и данные должны быть скопированы туда.

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

Однако будет иметь значение, если данные кэшируются на локальном узле или нет.Вот тут-то и появляются системы самореплицирующихся баз данных, такие как Mnesia, Riak или CouchDB. Mnesia фактически реализована с использованием таблиц ETS.

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

Обратите внимание, что все взаимодействие с таблицами ETS не транзакционное!Это означает, что вы не можете полагаться на запись значения, основанного на предыдущем чтении, потому что значение могло измениться за это время.Mnesia обрабатывает это, используя транзакции.Вы все еще можете использовать функции dirty_* в Mneisa, чтобы выжать производительность, близкую к ETS, из большинства операций, если вы знаете, что делаете.

4 голосов
/ 03 августа 2011

Похоже, у вас есть куча вещей, которые могут произойти в любое время, и вам нужно объединять данные безопасным, единообразным способом. Взгляните на поведение Generic Event . Я бы порекомендовал использовать это для создания сервера событий, и чтобы все эти процессы передавали эту информацию через события на ваш сервер, тогда вы можете зарегистрировать ее или сохранить где-нибудь (например, в таблице ETS). Кроме того, таблицы ETS не годятся для постоянных данных, таких как количество «виджетов», которые есть у игрока - рассмотрим Mnesia , или превосходный сбой только дБ, например CouchDB . Оба они очень хорошо воспроизводятся на разных машинах.


Вы вызываете конфликт блокировки - у вас не должно быть никаких блокировок. Сообщения обрабатываются в синхронном порядке по мере их получения каждым процессом. Фактически, весь смысл семантики передачи сообщений, встроенной в язык, состоит в том, чтобы избежать одновременного использования общего состояния.
Подводя итог, обычно вы общаетесь с сообщениями, от процесса к процессу. Это очень сложно для вас, потому что вам нужна информация о процессах, разбросанных повсюду, поэтому моя рекомендация для вас основана на идее сосредоточения всей «интересной» информации вне исходных процессов в одном источнике в реальном времени. .

...