Интернет-пользователи хранят эликсир

Я работаю над одним приложением чата [все для всех] в Elixir, используя OTP Genserver и получаю сообщения от js-клиента, когда пользователь регистрируется со своими именами в качестве первого этапа. Теперь я просто немного не уверен, как лучше всего хранить эти имена на моем сервере эликсира и отправлять регулярные обновления клиенту со списком пользователей в сети или в хранилище базы данных. Пожалуйста, предложите лучший подход.


person Coder    schedule 07.08.2014    source источник


Ответы (2)


Я согласен с bitwalker, что ETS подходит.

Вот краткое изложение того, что я сделал в производстве. Это был не чат-сервер, а пуш-сервер с парой тысяч пользователей, подключающихся через долгий опрос. Отправляемые данные были разделены примерно на 50 категорий, и пользователи могли выбирать, какие из них им нужны. В часы пик сервер отправлял новые сообщения каждые 2 секунды и обрабатывал > 2000 запросов в секунду.

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

Очевидно, что при поступлении запроса вам нужно найти специфический для пользователя процесс, и для этого хорошо подходит ETS, поскольку у вас нет узкого места в одном процессе. Вместо ручной работы с ETS я бы рекомендовал использовать gproc в сочетании с via кортежами. По сути, при запуске пользовательского gen_server вы можете указать name: {:via, :gproc, {:n, :l, key}}, где key — это некоторый пользовательский ключ (произвольный термин), который вы создаете на основе вашего внутреннего идентификатора пользователя (:n и :l указывают уникальное имя на локальном узле). Затем вы можете использовать тот же кортеж via при выполнении вызовов/кастов, а gen_server будет использовать gproc для поиска соответствующего процесса.

Наконец, вам нужна логика тайм-аута/отключения для очистки пользовательских процессов. В моем случае я просто завершал процесс пользователя, если не было активности веб-слоя (конечный пользователь не приходил за данными в течение некоторого времени). Gproc автоматически удалит записи для завершенного процесса из своей внутренней таблицы ETS. Вероятно, лучше всего контролировать пользовательские процессы в соответствии со стратегией temporary.

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

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

person sasajuric    schedule 07.08.2014
comment
о, отлично, большое спасибо за ваше предложение! Но когда пользователи отправляют свои имена для регистрации на моем handle_info, они сохраняются только одним пользователем. Когда какой-то другой пользователь пытается получить регистрацию, сервер падает. Итак, ETS поддерживает состояние? или может быть я реализую это неправильно. Пожалуйста, предложите. def create(user) do :ets.new(:call_table, [:named_table, :bag]) :ets.insert(:call_table, {:user, user}) end def lookupuser do :ets.lookup(:call_table, : пользователь) конец - person Coder; 07.08.2014
comment
Ваш ETS по умолчанию защищен, что означает, что только процесс, который владеет (создает) таблицей, может писать. Вам нужно сделать его общедоступным или сериализовать все записи через процесс владельца. Более подробно ознакомьтесь с документацией :ets.new (erlang.org/ doc/man/ets.html#new-2). Кроме того, имейте в виду, что таблица ETS освобождается, когда процесс владельца (по умолчанию создатель) завершается, поэтому будьте осторожны при создании таблицы. Если вы помещаете pids в таблицу, действительно лучше использовать gproc, который делает это и все другие полезные функции. - person sasajuric; 07.08.2014

Звучит как хороший пример использования ETS.

Более простым подходом может быть использование агента для хранения информации о онлайн-пользователях, но это во многом зависит от того, что вам нужно от выбранного вами механизма хранения.

person bitwalker    schedule 07.08.2014
comment
Спасибо за ваш быстрый ответ, однако я не получил все сообщение. Можете ли вы предложить такой же код (если возможно), чтобы моя функция handle_info выглядела так: def handle_info(message, state) do {a,b} = message username = b[:body] {:noreply, state} end - person Coder; 07.08.2014