Прежде чем я начну, давайте настроим пример использования моего вопроса. Наше приложение чата быстро растет среди пользователей, и мы должны расширяться в запущенных экземплярах нашего серверного приложения. Реализация языка не имеет значения, но, скорее всего, делается на Java или C ++.
Наличие одного сервера, принимающего всех клиентов и отправляющего сообщения пользователям, очень легко. Вы можете создать пул пользователей, а затем отправить сообщение нужным подключенным пользователям. Работает отлично. Однако, как я уже сказал, база пользователей быстро растет, и мы вынуждены расширяться. Тогда давайте скажем, что мы информируем наш сервер о других узлах сервера. Так что теперь у вас есть node1 и node2. Соединены друг с другом и общаются друг с другом по собственному протоколу поверх TCP / IP.
Узел 1 и узел 2 могут спрашивать друг друга, подключен ли определенный пользователь, и если да, то сообщение будет переадресовано другому узлу, поэтому сообщение окажется у нужного пользователя, если пользователь не может быть найден на своем собственном узле. Работает идеально и почти аналогично EMQ реализовано без единой точки отказа.
Теперь предположим, что мы становимся еще больше, чем размер Facebook. Не реалистично, но допустим, что мы делаем. Очевидно, что в нашей команде было бы много экспертов, которые знают, как реализовать и спроектировать эту архитектуру, и, вероятно, хотели бы объяснить ее мне, но сейчас это не так.
Мы решили настроить кластеры узлов. Например, каждый кластер имеет около 20 узлов. Каждый узел знает друг друга в своем собственном кластере. Допустим, у нас есть три кластера иФред‘связан с cluster1 а также ‘Рыба‘связан с cluster2.
Сейчас Фред отправляет сообщение Рыба. Как cluster1 узнает о cluster2 и ее пользователях?
Я придумал несколько вещей. 1) Я мог бы создать экземпляр redis и сохранить там каждый сеанс пользователя с кластером и узлом, к которому подключен пользователь, а затем отправить сообщение в нужный кластер и узел ИЛИ ЖЕ 2) спросить у каждого кластера, есть ли у одного из его узлов пользователь, так называемый Рыба ИЛИ ЖЕ 3) сохранить сообщение в некоторой базе данных и опросить, если есть входящие сообщения из других кластеров.
Мне нравится вариант 1, но я не уверен, что это правильно. Вариант 2 звучит немного тяжело для балансировщиков нагрузки кластеров. Вариант 3 не совсем подходит для варианта использования, потому что мы хотим, чтобы это сообщение доставлялось в режиме реального времени.
Я просто не знаю, как это реализовать. Facebook, Twitter и любое другое приложение, отправляющее сообщения своим пользователям в режиме реального времени, сделали это, и я хотел бы узнать, как это сделать наиболее эффективным способом.
Я предлагаю использовать шлюзы для пользовательских подключений. Эти шлюзы не ваши каналы обмена сообщениями, но знают, как их найти.
У вас также есть узел, который содержит каналы, они общаются только со шлюзами.
Каждый клиент может подключиться к одному шлюзу. Каждый шлюз имеет соединение с каждым канальным сервером. Таким образом, одно клиентское соединение может получить доступ к каналам на любом количестве серверов. Если у вас очень высокий внутренний вентилятор, вы можете использовать надежный протокол UDP для передачи сообщения.
Такое расположение NxM позволяет масштабировать как клиентские соединения, так и каналы.
Кстати, именно так работает большинство финансовых бирж. Они рассчитаны на задержки менее миллисекунды и могут иметь очень высокие скорости передачи сообщений, например 10 миллионов в секунду.
Других решений пока нет …