SOCKET.IO И КУБЕРНЕТЫ

Развертывание Socket.io в Kubernetes — часть 1: приложение чата

Объяснение того, как работает приложение чата, и улучшения по сравнению с исходным руководством.

Чтобы прочитать другие части:

Добро пожаловать в мой путь по развертыванию Socket.io в Kubernetes! В этой части я хочу объяснить, как работает приложение чата, а также основные блоки приложения и мой опыт разработки приложения.

Как работает приложение для чата

Приложение для чата в основном состоит из двух частей: клиент/внешняя часть и сервер/внутренняя часть. Клиент и сервер подключаются через Socket.io, построенный поверх Websocket. В этом разделе я опишу, как клиент взаимодействует с сервером.

Клиент

Под клиентом/интерфейсом здесь подразумевается веб-сайт, который пользователи видят и с которым взаимодействуют. Клиент в этом проекте создан с помощью Next.js, потому что это высокоуровневая оболочка для React. Интегрировать с библиотеками CSS (например, Tailwind) проще, чем с React. Next.js также имеет структурированный макет папок с первого раза, по сравнению с React, где мы должны разместить свой собственный макет. Однако вы можете использовать React, если считаете, что Next.js слишком велик или просто не нужен.

Сейчас я не буду вдаваться в подробности о React и/или Next.js, но я хочу отметить некоторые важные части клиента, которые в первую очередь позволяют разрабатывать приложение для чата:

  1. useState хук: этот хук позволяет нам хранить данные в памяти. Но не только это, данные, хранящиеся в этом хуке, становятся состоянием компонента, то есть они влияют на поведение компонента, от отображения разных данных до выполнения фоновой обработки на основе разных состояний.
  2. useContext хук: если данные в useState могут использоваться внутри компонента, данные, хранящиеся в хуке useContext, могут храниться и использоваться во всем приложении. Это полезно для приложения чата, где мы хотим обрабатывать данные, которые используются между компонентами, например, идентификатор комнаты и наше текущее имя пользователя.
  3. useEffect ловушка: useEffect позволяет нам выполнять некоторую логику, основанную на определенных зависимостях. Это полезно для определенных сценариев, т. е. для повторного рендеринга страниц всякий раз, когда клиент получает новые сообщения. Кроме того, в этом приложении для чата я использую useEffect для создания прослушивателя Socket.io для каждого события, чтобы не создавать прослушиватель при каждой отрисовке страницы (подробнее об этой ошибке в последней части).

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



Сервер

В сервере нет ничего особенного, кроме того, что он используется для:

  1. получать сообщения;
  2. хранить сообщения в базе данных; и
  3. передать сообщение другим клиентам в той же комнате.

Сервер использует Socket.io для связи с клиентом, гарантируя, что каждое обновление от одного клиента может быть передано другим клиентам.

Сервер построен на основе Express.js, поскольку Socket.io предназначен для использования с Express.js. Команда Socket.io рекомендует программистам подключать библиотеку Socket.io к серверу Express.js, чтобы при запуске Express.js также запускалось соединение Socket.io.



Socket.io для связи

Socket.io — это библиотека двунаправленной сетевой связи, построенная поверх Websocket. Он использует протокол Websocket для отправки и получения сообщений от клиента и сервера. В случае, если Websocket недоступен, Socket.io может вернуться к HTTP-опросу (хотя я лично отключил это, поскольку HTTP-опрос требует больших ресурсов).

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

Причина, по которой я использую Socket.io, заключается в том, что Socket.io разработан как высокоуровневая оболочка для Websocket. Другими словами, Socket.io разработан так, чтобы его было проще использовать, чем Websocket. Также на Socket.io есть полезная шпаргалка, которая поможет программистам в процессе разработки.

ПРИМЕЧАНИЕ. Socket.io — это не выделенный сервис, а библиотека, прикрепленная к серверу и клиенту.

Редис

Вы можете подумать, что я использую Redis для кэширования. Однако нет, я не использую Redis для кеширования. Вместо этого я использую Redis Pub/Sub для связи между модулями. Мой план состоит в том, что когда я буду развертывать это приложение в Kubernetes, я создам более 1 пода (возможно, 3) просто для масштабируемости. Но это означает, что каждый модуль должен взаимодействовать с другими модулями, и именно поэтому нам нужна система pub-sub.

Итак, из всех систем pub-sub, почему именно Redis? Причина в том, что Redis Pub/Sub поддерживается Socket.io. Socket.io имеет функцию, называемую адаптеры, с помощью которой мы можем подключить несколько систем pub-sub к Socket.io, чтобы всякий раз, когда мы создаем кластер серверов Socket.io, эти серверы могли взаимодействовать и координировать свои действия для выполнения своих задач.

MongoDB

В этом приложении я сохраняю сообщения с помощью MongoDB. Для тех, кто не знает, MongoDB — это постоянная база данных NoSQL, популярная, особенно среди разработчиков JavaScript и TypeScript. Его гибкость нравится программистам. Что касается того, почему я использую MongoDB, вы можете прочитать в разделе Improvement #2: Persistent Messages ниже.

Где я этому научился?

Обо всем этом я узнаю из одного видео на YouTube, сделанного TomDoesTech. Он объяснил, как использовать Socket.io на Next.js. Это длинное видео (1 час, более или менее), но его стоит посмотреть. Тем не менее, есть некоторые улучшения, которые я могу сделать из видео.

Улучшение №1: ошибка утечки памяти



Если вы откроете код или увидите скриншот выше, вы увидите, что исходный код не помещает socket.on(...) внутрь хука useEffect. В результате Socket.io будет регистрировать (читай: создавать) каждого слушателя на каждой странице. Я понял это на собственном горьком опыте во время тестирования. Я не знал, почему страница перестала отвечать. Я спросил своих друзей, и они тоже не знали, почему. В конце концов я нашел эту статью на dev.to, в которой объясняется, как использовать Socket.io в React. Читая эту статью, я вдруг вспомнил, что все, что находится за пределами useEffect, будет выполняться при каждом рендеринге страницы.

Улучшение № 2: постоянные сообщения

Второе улучшение, которое я сделал для приложения для чата, заключается в сохранении этих сообщений в базе данных. Я выбираю MongoDB из-за двух факторов:

  1. В Kubernetes лучшей практикой использования базы данных является использование StatefulSet. Тем не менее, управление StatefulSet может быть проблемой для новичка в Kubernetes, такого как я. Итак, вместо этого я пытаюсь передать управление MongoDB третьей стороне. Даже Брет Фишер и Нана Джанашиа (из Techworld с Наной) (оба являются известными капитанами Docker) рекомендуют, если у нас нет специального администратора базы данных (для управления базой данных), лучше отдать управление базой данных на аутсорсинг.
  2. У меня есть бесплатный план от MongoDB Atlas. Хотя и немного (всего 5 ГБ), для учебных целей этого более чем достаточно.

Если вы хотите сохраниться, вам не нужно использовать MongoDB. Вы можете использовать любую доступную постоянную базу данных, будь то MySQL, PostgreSQL или другие базы данных. Так уж получилось, что у меня бесплатный тариф и мне лень писать SQL-скрипты для создания базы данных и таблиц :-)

Я надеюсь, что в приведенной выше статье объясняется часть приложения и то, как они работают вместе в качестве приложения для чата. В следующей части я расскажу об инфраструктуре и конфигурации, позволяющей развертывать Socket.io в Kubernetes. Следите за обновлениями!