синхронизация пользователей (вкладки, сессии...)
Как правильно организовать синхронизацию пользователей?
Пользователи ходят по страницам сайта, чтобы не дергать все время базу на сервере, на сервере кешированы последние 40 разделов информации. в наличии есть nodejs и socket.io. Задача синхронизировать пользователей с сервером, обеспечив их чатом, обновлениями сообщений и т.д. при этом по максимуму сократить избыточные операции. В идеале при переходе со страницы на страницу запрос должен идти лишь на соединение socket.io, а запрашиваться инфа должна только в начале сессии и обновляться только тогда, когда сервер говорит: на новую инфу. Кто-нибудь сталкивался с подобной задачей или видел статьи на эту тему? |
Я могу много рассказать про этот кейз, но нужно больше инфы, про твой случай, т.к. паттернов оч много.
|
Цитата:
nodejs+express+nginx. ограничений в устанавливаемом ПО нет. Хочу, чтобы пользователи при логинизации запрашивали последние обновления (они хранятся в кэше nodejs и отдаются быстро). Т.к. пользователи ходят по страницам, то каждый раз гонять инфу с сервера не кавайно, поэтому инфа хранится в браузере в localStorage, а запрашивать будем только изменения, проверяя к примеру последний добавленную запись в кэш на сервере. Самый большой вопрос связан с запросами кто онлайн: когда запрашивать кто онлайн, как узнать что пользователь закрыл браузер|вкладку, как определить что пользователь онлайн, активен, где и как хранить сессию, чтобы работало быстро и не нужно было в течении 1 сессии кидать запрос в базу на чтение инфы о пользователе? Через socket.io я могу с сервера посылать нужные обновления пользователям, но не понимаю как проверять онлайность. Предполагаю: при открытии вкладки(браузера) нужно создавать сессию и отдавать её пользователю |
Там все сложнее, вечером постараюсь описать, ща на работе.
|
ок, может я до вечера ещё чего надумаю :)
|
Вчера пришёл убитый, поэтому пишу только сейчас.
Итак, начнём с самого важного. Главное при работе с сокетами - это заложить горизонтальное масштабирование, хотя пожалуй это главное почти для всего. Дело в том, что у тебя не будет проблем, когда все твои коннекты висят на одном сервере, но если ты допускаешь, что нагрузка будет расти и понадобится кластер, то ты сразу получишь граблемя по лицу, например: чат между двумя юзерами - один работает с одним сервером, другой с другим и поэтому они про друг по друга ничего не знают и нет никакой возможности узнать о новых сообщениях, кроме как время от времени чекать БД, но сам понимаешь, что это плохой способ. Путей решения несколько, начну от простого к сложному. 1) Заюзать сторонний сервис уведомлений (например, https://pusher.com/) и работать по схеме: подключаешь их браузерную либу, клиенты конектятся по сокету к их серверам, а они в свою очередь шлют уведомления на твои сервера, где ты через их серверную либу обрабатываешь их. Плюсы: Очень просто реализовать. Легко масштабировать. Минусы: Это платная услуга. Каждый клиент создаёт коннекшин, а число коннекшинов ограничено тарифами. Каждый клиент генерирует сообщения, число которых также ограничено тарифом. 2) Заюзать сторонний сервис уведомлений, но в качестве клиента использовать свои сервера, т.е. твои пользователи конектятся напрямую к твоим серверам, а они уже конектятся к API сервиса и шлюс сообщения. Плюсы: Не сложно реализовать. Легко масштабировать. Количество коннекшинов = количество серверов в кластере, а не пользователей, как при первом подходе. Количество сообщений можно оптимизировать: не слать сообщения, если нет нужны, например если все нужные пользователи подключены к одному серверу. Минусы: Это платная услуга. 3) Написать свой (или настроить готовый модуль) сервер сообщений и балансировщик (стратегии использования такие же, как в примерах выше). Плюсы: Не надо платить за внешний сервис. Легко масштабировать (при условии если нормально напишешь). Минусы: Это сложнее реализовать. Появляется дополнительная головная боль, которую сторонний сервис инкапсулирует от нас. 4) WebRTC. Использование P2P подхода может сделать твою систему децентролизованой и значительно облегчить нагрузку на сервер, т.к. он будет рулить рукопожатия клиентов, при необходимости ходить в базу и рассылать сообщения при необходимости. Плюсы: Очень сильно сбивает нагрузку на сервер. Не надо платить за внешний сервис. Легко масштабировать (при условии если нормально напишешь). Минусы: Это сложно реализовать по нормальному. Постоянный затрах с синхронизацией состояний на разных клиентах. *** Я юзаю 2-й и 4-й подходы. Следующим постом продолжу лекцию :) |
Теперь поговорим про локальную БД. Сразу скажу, что это реально геморой.
Начнём с синхронизации данных между клиентом и сервером. Лучше всего, использовать паттерн версионирования данных, т.е. заводим в нашей коллекции/таблице у документов/строк дополнительные поля, обычно хватает одного, назовём его __v и пускай это будет целое число, которое будет увеличиваться при каждом обновлении записи, и тогда для синхронизации данных будет достаточно прикрепить версию локальных данных в запросе, и если они отличаются, то сервер отдаст новые данные, а если нет - то пустой ответ. Разумеется, когда пользователь обновляет данные, то вместе с ответом сервера, что всё ок, он должен возвращать новую версию __v. Более подробны про доступные паттерны версионирования можно почитать в книге Фаулера NoSQL. Теперь про локальные хранилища: не юзай голый local storage, ибо без нормальной абстракции ты рискуешь огрести граблями. Лучше всего заюзать SQLLite (есть порт на asm.js) / IndexedDB (есть во всех современных браузерах) или библиотеку, которая инкапсулирует общения с хранилищем и даёт нормальный интерфейс запросов. Про синхронизацию событий между вкладками: это геморой, но вообще можно юзать localStorage / sessionStorage и его событие onChange, или заюзать ServiceWorker (это вариант WebWorker, который биндится к домену, а не вкладке). |
Цитата:
|
Цитата:
|
Цитата:
|
Часовой пояс GMT +3, время: 08:22. |