Javascript-форум (https://javascript.ru/forum/)
-   Оффтопик (https://javascript.ru/forum/offtopic/)
-   -   синхронизация пользователей (вкладки, сессии...) (https://javascript.ru/forum/offtopic/56860-sinkhronizaciya-polzovatelejj-vkladki-sessii.html)

Gozar 07.07.2015 11:50

синхронизация пользователей (вкладки, сессии...)
 
Как правильно организовать синхронизацию пользователей?

Пользователи ходят по страницам сайта, чтобы не дергать все время базу на сервере, на сервере кешированы последние 40 разделов информации.

в наличии есть nodejs и socket.io.

Задача синхронизировать пользователей с сервером, обеспечив их чатом, обновлениями сообщений и т.д. при этом по максимуму сократить избыточные операции. В идеале при переходе со страницы на страницу запрос должен идти лишь на соединение socket.io, а запрашиваться инфа должна только в начале сессии и обновляться только тогда, когда сервер говорит: на новую инфу.

Кто-нибудь сталкивался с подобной задачей или видел статьи на эту тему?

kobezzza 07.07.2015 12:08

Я могу много рассказать про этот кейз, но нужно больше инфы, про твой случай, т.к. паттернов оч много.

Gozar 07.07.2015 12:27

Цитата:

Сообщение от kobezzza
нужно больше инфы

Какой именно?

nodejs+express+nginx. ограничений в устанавливаемом ПО нет.

Хочу, чтобы пользователи при логинизации запрашивали последние обновления (они хранятся в кэше nodejs и отдаются быстро).

Т.к. пользователи ходят по страницам, то каждый раз гонять инфу с сервера не кавайно, поэтому инфа хранится в браузере в localStorage, а запрашивать будем только изменения, проверяя к примеру последний добавленную запись в кэш на сервере.

Самый большой вопрос связан с запросами кто онлайн: когда запрашивать кто онлайн, как узнать что пользователь закрыл браузер|вкладку, как определить что пользователь онлайн, активен, где и как хранить сессию, чтобы работало быстро и не нужно было в течении 1 сессии кидать запрос в базу на чтение инфы о пользователе?

Через socket.io я могу с сервера посылать нужные обновления пользователям, но не понимаю как проверять онлайность.


Предполагаю:
при открытии вкладки(браузера) нужно создавать сессию и отдавать её пользователю

kobezzza 07.07.2015 12:30

Там все сложнее, вечером постараюсь описать, ща на работе.

Gozar 07.07.2015 12:37

ок, может я до вечера ещё чего надумаю :)

kobezzza 08.07.2015 21:52

Вчера пришёл убитый, поэтому пишу только сейчас.

Итак, начнём с самого важного. Главное при работе с сокетами - это заложить горизонтальное масштабирование, хотя пожалуй это главное почти для всего. Дело в том, что у тебя не будет проблем, когда все твои коннекты висят на одном сервере, но если ты допускаешь, что нагрузка будет расти и понадобится кластер, то ты сразу получишь граблемя по лицу, например: чат между двумя юзерами - один работает с одним сервером, другой с другим и поэтому они про друг по друга ничего не знают и нет никакой возможности узнать о новых сообщениях, кроме как время от времени чекать БД, но сам понимаешь, что это плохой способ. Путей решения несколько, начну от простого к сложному.

1) Заюзать сторонний сервис уведомлений (например, https://pusher.com/) и работать по схеме: подключаешь их браузерную либу, клиенты конектятся по сокету к их серверам, а они в свою очередь шлют уведомления на твои сервера, где ты через их серверную либу обрабатываешь их.

Плюсы:

Очень просто реализовать.
Легко масштабировать.

Минусы:

Это платная услуга.
Каждый клиент создаёт коннекшин, а число коннекшинов ограничено тарифами.
Каждый клиент генерирует сообщения, число которых также ограничено тарифом.

2) Заюзать сторонний сервис уведомлений, но в качестве клиента использовать свои сервера, т.е. твои пользователи конектятся напрямую к твоим серверам, а они уже конектятся к API сервиса и шлюс сообщения.

Плюсы:

Не сложно реализовать.
Легко масштабировать.
Количество коннекшинов = количество серверов в кластере, а не пользователей, как при первом подходе.
Количество сообщений можно оптимизировать: не слать сообщения, если нет нужны, например если все нужные пользователи подключены к одному серверу.


Минусы:

Это платная услуга.

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

Плюсы:

Не надо платить за внешний сервис.
Легко масштабировать (при условии если нормально напишешь).

Минусы:

Это сложнее реализовать.
Появляется дополнительная головная боль, которую сторонний сервис инкапсулирует от нас.

4) WebRTC. Использование P2P подхода может сделать твою систему децентролизованой и значительно облегчить нагрузку на сервер, т.к. он будет рулить рукопожатия клиентов, при необходимости ходить в базу и рассылать сообщения при необходимости.

Плюсы:

Очень сильно сбивает нагрузку на сервер.
Не надо платить за внешний сервис.
Легко масштабировать (при условии если нормально напишешь).

Минусы:

Это сложно реализовать по нормальному.
Постоянный затрах с синхронизацией состояний на разных клиентах.


***

Я юзаю 2-й и 4-й подходы. Следующим постом продолжу лекцию :)

kobezzza 08.07.2015 22:18

Теперь поговорим про локальную БД. Сразу скажу, что это реально геморой.

Начнём с синхронизации данных между клиентом и сервером. Лучше всего, использовать паттерн версионирования данных, т.е. заводим в нашей коллекции/таблице у документов/строк дополнительные поля, обычно хватает одного, назовём его __v и пускай это будет целое число, которое будет увеличиваться при каждом обновлении записи, и тогда для синхронизации данных будет достаточно прикрепить версию локальных данных в запросе, и если они отличаются, то сервер отдаст новые данные, а если нет - то пустой ответ. Разумеется, когда пользователь обновляет данные, то вместе с ответом сервера, что всё ок, он должен возвращать новую версию __v.

Более подробны про доступные паттерны версионирования можно почитать в книге Фаулера NoSQL.

Теперь про локальные хранилища: не юзай голый local storage, ибо без нормальной абстракции ты рискуешь огрести граблями. Лучше всего заюзать SQLLite (есть порт на asm.js) / IndexedDB (есть во всех современных браузерах) или библиотеку, которая инкапсулирует общения с хранилищем и даёт нормальный интерфейс запросов.

Про синхронизацию событий между вкладками: это геморой, но вообще можно юзать localStorage / sessionStorage и его событие onChange, или заюзать ServiceWorker (это вариант WebWorker, который биндится к домену, а не вкладке).

kobezzza 08.07.2015 22:25

Цитата:

Через socket.io я могу с сервера посылать нужные обновления пользователям, но не понимаю как проверять онлайность.
Заведи отдельную базу типа ключ-значение, например для таких задач ох хорошо подходит Redis, где кешируй эту инфу.

cyber 08.07.2015 22:26

Цитата:

Сообщение от kobezzza
4) WebRTC. Использование P2P подхода может сделать твою систему децентролизованой и значительно облегчить нагрузку на сервер, т.к. он будет рулить рукопожатия клиентов, при необходимости ходить в базу и рассылать сообщения при необходимости.

Опиши подробнее плиз

kobezzza 08.07.2015 22:32

Цитата:

Сообщение от cyber (Сообщение 378285)
Опиши подробнее плиз

Ну, WebRTC позволяет общаться клиентам напрямую друг с другом, внешний сервер нужен только для рукопожатия, а дальше вы уже общаетесь сами, а если нужна история сообщений, то фоном время от времени можно дампить инфу на сервер. С помощью WebRTC можно также делать аудио и видео конференции, см например сервис Firefox Hello или либу https://togetherjs.com/


Часовой пояс GMT +3, время: 08:22.