Прокси-поток TCP (MySQL и Redis) с Nginx

Я читал о Nginx Fabric Model, и это привлекает мое внимание к перенастройке того, как приложение взаимодействует с MySQL и Redis. Если локальный экземпляр Nginx может эффективно и быстро проксировать HTTP-трафик, теперь он также может использовать TCP-прокси, не беспокоясь о сети, даже используя ведомое устройство базы данных в качестве главного в случае чрезвычайной ситуации и потенциально инкапсулируя разбиение базы данных. Все преимущества могут упростить настройку приложения, и его логика, сеть (перегрузка, задержка, время ожидания, повторные попытки) больше не будет фокусироваться на разработке функций.

Я использую последний Docker и набор контейнеров: Nginx, Redis, MySQL. Я попробовал следующую конфигурацию:

user  nginx;
worker_processes  1;

error_log  /var/log/nginx/error.log info;
pid        /var/run/nginx.pid;


events {
  worker_connections  1024;
}

stream {
  upstream redis {
    # prefer first server but limit connections
    server 172.17.0.8:6379 weight=2 max_conns=1;
    server 172.17.0.3:6379;
  }

  upstream mysql {
    # use second server in case of failure
    server 172.17.0.4:3306;
    server 172.17.0.5:3306 backup;
  }

  server {
    listen 6379 so_keepalive=on;
    proxy_pass redis;
  }

  server {
    listen 3306 so_keepalive=on;
    proxy_pass mysql;
  }
}

У меня есть несколько вопросов:

  • ведение журнала. Как узнать, какая конечная точка используется, сколько раз Nginx повторял определенный запрос?

  • статистика в реальном времени - возможно ли получить пропускную способность для потокового модуля?

  • с точки зрения сегментирования базы данных - возможно ли отправить запрос в базу данных с сегментированием на основе некоторой логики, кроме $ remote_addr?

Последний вопрос очень важен, я нашел модули ngx_stream_map_module и ngx_stream_split_clients_module, но $ remote_addr не подходит для разделения, можем ли мы перехватить cookie из раздела http и повторно использовать в разделе потока, где у нас нет заголовков? Можем ли мы ввести код Lua в секцию потока? Является ли ngx_stream_ssl_preread_module решением этой проблемы, как заставить его работать для соединения без шифрования?

Ответ 1

Я не думаю, что Nginx можно использовать для того, для чего вы пытаетесь его использовать. Хотя он может использоваться для прокси-потоков tcp или балансировки нагрузки, он не обязательно знает о протоколе и структуре запросов в них. Итак, чтобы ответить на ваш вопрос:

с точки зрения сегментирования базы данных - возможно ли отправить запрос в базу данных с сегментированием на основе некоторой логики, кроме $ remote_addr?

На самом деле, нет. Он не может перенаправлять разные запросы Redis или MySQL от одного соединения к разным серверам на основе их содержимого, поскольку эти вещи, к nginx, являются просто потоком, который он не может прочитать. Он назначает ему пункт назначения во время инициации потока и следит за тем, чтобы все пакеты туда и обратно отправлялись в одни и те же пункты назначения, и что об этом.

Например, в статье по разделению MySQL, которую вы связали, он выполняет командную строку mysql, чтобы выполнить один запрос и проверить имя узла. Каждый раз, когда он запускается, он устанавливает соединение, выполняет запрос и отключается. Таким образом, каждый раз, когда это происходит, новое соединение направляется на другой сервер с помощью nginx. Однако, если бы вы выполняли один и тот же запрос дважды над одним и тем же экземпляром командной строки mysql, он дал бы вам одно и то же имя узла. Стоит также отметить, что это использует MySQL Galera, который является конфигурацией с несколькими мастерами MySQL, которая обрабатывает маршрутизацию чтения и записи внутри себя, что позволяет выполнять произвольную маршрутизацию запросов на стороне клиента, как это. Это не относится к Redis.

Кроме того, это также не освобождает от обработки всего соединения для вашего приложения. Ошибки, такие как недоступность нисходящего потока, могут по-прежнему распространяться вплоть до клиента.

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


мы можем перехватить cookie из раздела http и повторно использовать его в потоке, где у нас нет заголовков?

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


Можем ли мы ввести код Lua в секцию потока?

Это потенциально возможно, но для этого потребуется модуль Lua, который может анализировать протоколы приложений, такие как проводной протокол Redis и MySQL. Но, как я упоминал ранее, маршрутизация запросов в соединении от (даже если вы можете обнаружить и направить их в nginx) не обязательно проста с точки зрения базы данных/согласованности, и я бы не рекомендовал делать это.