RFC: Сетевое взаимодействие между worker/supervisor #1

Open
opened 4 years ago by Ggg_123 · 2 comments
Ggg_123 commented 4 years ago
Owner

Q:Почему разделение на worker/supervisor?
A:Потому что иначе кто кому что-то будет слать?

Q:Как будут различаться эти 2 приложения?
A:Можно сделать один и запускать с разным флагом.
Можно флаги, можно конфиги - зависит от количества опций и личных предпочтений.
Для флагов - structopt или clap.
Для конфигов - toml-edit, потому что он сохраняет комменты и используется в популярном cargo-edit.
А можно просто сделать два разных бинарника. Что я вижу тут наиболее логичным.

Q:Нафига в конфигах комменты?
Чтобы обозначить, какие опции что делают и что там по умолчанию. Открыл конфиг и сразу всё видно.

Q:Откуда в конфиге значения по умолчанию?
Чтобы не захламлять репу и не заставлять юзера качать 3 файла, он качает только exe, конфиги создаются при запуске.
Но мне пока флаги видятся более логичным путём, так как настроек будет мало.

Теперь про кишки. Конкретнее - про протокол и связанное.
Нужна диаграмма подключений, чтобы идти дальше. Быстро накидал такое, но это только моё понимание:
scheme.png

Выбор транспортного протокола.
UDP/TCP.
Так как про kf_server я ничего не знаю, то и сказать, что там нужно/будет, кроме "там передаётся JSON", не могу.
Поэтому ниже только про rust magic часть.

TCP подходит, так как тут пофиг на задержку, и бонусы в виде reliability/ordering тут явно требуются.
Но я не знаю, как обрабатывать переподключения.
Если подключения самодостаточны (т.е. между запросами нет связи и пофиг, когда какой запрос шлётся), то всё просто - worker отвалился, worker переподключился, конец вопроса.
Но если нужно хранить какую-то инфу, то нужно как-то мапить worker к чему-то.
Тут развилка.
Может ли несколько worker запущено на одной машине?
Если нет, то просто мапим worker:worker_ip и при его переподключении реюзаем сессию с этого же ip.
Если да, то нужен уникальный id от supervisor.
Схема в обоих случаях схожая:
-supervsior запускается, ждёт коннектов
-worker подключается к supervisor, у него нет worker_id, значит это не переподключение - коннектится с need_id_plz
-supervisor видит, что коннектится worker без id, значит это не переподключение - генерит и отдаёт ему heres_ur_id(id)
-worker сохраняет id и шлёт команды
-supervisor отвечает на команды
-сеть мигает
-worker пытается послать команду, но сокет сдох.
-worker подключается к supervisor и шлёт ему тот id
-supervisor видит, что коннектится worker с id, значит это переподключение - убирает старый коннект (или тут, или по таймауту), пихает новый коннект в старую сессию

Ещё ты говорил про возможность S слать команды всем W.
В этой схеме он будет видеть только те, которые подключались к нему с момента запуска.
Не думаю, что это проблема, так как W должны быть приконектены к S всегда, когда они запущены, но если есть requirement "нужно видеть, какие W сейчас offline", то схему нужно менять.

UDP не подходит, так как нужен и order, и reliability. Поэтому нужен rUDP. То есть внешние либы. Тут выбор большой и фиг знает, что лучше подойдёт.
Нужно что-то типа https://crates.io/crates/laminar
Сразу говорю: своё писать здесь - самоубийство. Сеть это сложно и повсюду подводные камни.
Своё такое ты пишешь для курсача "показать-забыть", для рабочего проекта же ты сидишь на чужих плечах.

Кроме этого остальное выглядит простым.
Supervisor (S) запускается, проверяет БД и ждёт коннектов от Worker (W).
W запускается и пытается связаться с S.
Шлют Handshake, чтобы проверить, что это W-S связь и у них одна версия протокола и что всё ок и можно начинать работу.
W после каждой команды ждёт ACK от S. Нет ACK - считать, что команда или не дошла (в случае unreliable rUDP), или сервер упал, или коннект пропал.
S получает пакет от W, парсит его в enum, делает что-то и шлёт односложный ok/fail.
И каждые N секунд стороны обмениваются heartbeat ping-pong, чтобы держать и проверять коннект.

Q:Почему W->S, а не наоборот?
A:Чтобы убрать требования к безопасности подключения.
Когда к тебе кто угодно может подключиться, то нужно знать, кто это.
Но когда ты вручную вбиваешь addr:ip сервера с S на нём, то проблема сама по себе исчезает.
Хотя сейчас думаю и понимаю, что я не понимаю вектора атаки. В принципе можно что W->S, что S->W - зависит от требований и опасений.
У меня нет требований и я не вижу никакого риска в передаче незашифрованных данных, поэтому мне оба варианта подходят.

Сам протокол это просто парсинг приходящих байт в enum - для этого можно заюзать что-то типа https://crates.io/crates/protocol
Так как обе стороны на rust, то эта часть очень гибкая.

Ещё может потребоваться выбор веб-сервера, если TCP/UDP не хватит.
Я с выбором вебсерверов одно время заебался, когда выбирал для своего проекта, а с тех ещё прошло много времени, поэтому всё устарело и нужно разбираться заново.
Но - там будет async.
Почему там будет async?
Потому что найти не-async вебсервер для rust уже нельзя. Или async, или версии годичной давности. Get with the times, old man.

Ещё есть момент с обновлением данных/БД у worker.
Можно сделать так, чтобы W при запуске слал mk5/hash своей БД S, а тот отвечал - всё круто, или нужно качать новую. Это решит проблему, когда W пропустил какое-то обновление (был отключен/перезапускался или подобное).
Остальные изменения кидаются W->S-> все W как дельта (то есть не вся БД, а именно новое значение), потому что при запуске у них гарантированно новая БД.
Нужна ли W своя локальная БД или хватит запросов по сети - не знаю.

Q:Почему разделение на worker/supervisor? A:Потому что иначе кто кому что-то будет слать? Q:Как будут различаться эти 2 приложения? A:Можно сделать один и запускать с разным флагом. Можно флаги, можно конфиги - зависит от количества опций и личных предпочтений. Для флагов - structopt или clap. Для конфигов - toml-edit, потому что он сохраняет комменты и используется в популярном cargo-edit. А можно просто сделать два разных бинарника. Что я вижу тут наиболее логичным. Q:Нафига в конфигах комменты? Чтобы обозначить, какие опции что делают и что там по умолчанию. Открыл конфиг и сразу всё видно. Q:Откуда в конфиге значения по умолчанию? Чтобы не захламлять репу и не заставлять юзера качать 3 файла, он качает только exe, конфиги создаются при запуске. Но мне пока флаги видятся более логичным путём, так как настроек будет мало. Теперь про кишки. Конкретнее - про протокол и связанное. Нужна диаграмма подключений, чтобы идти дальше. Быстро накидал такое, но это только моё понимание: scheme.png Выбор транспортного протокола. UDP/TCP. Так как про kf_server я ничего не знаю, то и сказать, что там нужно/будет, кроме "там передаётся JSON", не могу. Поэтому ниже только про rust magic часть. TCP подходит, так как тут пофиг на задержку, и бонусы в виде reliability/ordering тут явно требуются. Но я не знаю, как обрабатывать переподключения. Если подключения самодостаточны (т.е. между запросами нет связи и пофиг, когда какой запрос шлётся), то всё просто - worker отвалился, worker переподключился, конец вопроса. Но если нужно хранить какую-то инфу, то нужно как-то мапить worker к чему-то. Тут развилка. Может ли несколько worker запущено на одной машине? Если нет, то просто мапим worker:worker_ip и при его переподключении реюзаем сессию с этого же ip. Если да, то нужен уникальный id от supervisor. Схема в обоих случаях схожая: -supervsior запускается, ждёт коннектов -worker подключается к supervisor, у него нет worker_id, значит это не переподключение - коннектится с need_id_plz -supervisor видит, что коннектится worker без id, значит это не переподключение - генерит и отдаёт ему heres_ur_id(id) -worker сохраняет id и шлёт команды -supervisor отвечает на команды -сеть мигает -worker пытается послать команду, но сокет сдох. -worker подключается к supervisor и шлёт ему тот id -supervisor видит, что коннектится worker с id, значит это переподключение - убирает старый коннект (или тут, или по таймауту), пихает новый коннект в старую сессию Ещё ты говорил про возможность S слать команды всем W. В этой схеме он будет видеть только те, которые подключались к нему с момента запуска. Не думаю, что это проблема, так как W должны быть приконектены к S всегда, когда они запущены, но если есть requirement "нужно видеть, какие W сейчас offline", то схему нужно менять. UDP не подходит, так как нужен и order, и reliability. Поэтому нужен rUDP. То есть внешние либы. Тут выбор большой и фиг знает, что лучше подойдёт. Нужно что-то типа https://crates.io/crates/laminar Сразу говорю: своё писать здесь - самоубийство. Сеть это сложно и повсюду подводные камни. Своё такое ты пишешь для курсача "показать-забыть", для рабочего проекта же ты сидишь на чужих плечах. Кроме этого остальное выглядит простым. Supervisor (S) запускается, проверяет БД и ждёт коннектов от Worker (W). W запускается и пытается связаться с S. Шлют Handshake, чтобы проверить, что это W-S связь и у них одна версия протокола и что всё ок и можно начинать работу. W после каждой команды ждёт ACK от S. Нет ACK - считать, что команда или не дошла (в случае unreliable rUDP), или сервер упал, или коннект пропал. S получает пакет от W, парсит его в enum, делает что-то и шлёт односложный ok/fail. И каждые N секунд стороны обмениваются heartbeat ping-pong, чтобы держать и проверять коннект. Q:Почему W->S, а не наоборот? A:Чтобы убрать требования к безопасности подключения. Когда к тебе кто угодно может подключиться, то нужно знать, кто это. Но когда ты вручную вбиваешь addr:ip сервера с S на нём, то проблема сама по себе исчезает. Хотя сейчас думаю и понимаю, что я не понимаю вектора атаки. В принципе можно что W->S, что S->W - зависит от требований и опасений. У меня нет требований и я не вижу никакого риска в передаче незашифрованных данных, поэтому мне оба варианта подходят. Сам протокол это просто парсинг приходящих байт в enum - для этого можно заюзать что-то типа https://crates.io/crates/protocol Так как обе стороны на rust, то эта часть очень гибкая. Ещё может потребоваться выбор веб-сервера, если TCP/UDP не хватит. Я с выбором вебсерверов одно время заебался, когда выбирал для своего проекта, а с тех ещё прошло много времени, поэтому всё устарело и нужно разбираться заново. Но - там будет async. Почему там будет async? Потому что найти не-async вебсервер для rust уже нельзя. Или async, или версии годичной давности. Get with the times, old man. Ещё есть момент с обновлением данных/БД у worker. Можно сделать так, чтобы W при запуске слал mk5/hash своей БД S, а тот отвечал - всё круто, или нужно качать новую. Это решит проблему, когда W пропустил какое-то обновление (был отключен/перезапускался или подобное). Остальные изменения кидаются W->S-> все W как дельта (то есть не вся БД, а именно новое значение), потому что при запуске у них гарантированно новая БД. Нужна ли W своя локальная БД или хватит запросов по сети - не знаю.
Poster
Owner

Идея - W не хранит локальную БД, а держит её в памяти, так как там будет мало (+сжатие).

Идея - W не хранит локальную БД, а держит её в памяти, так как там будет мало (+сжатие).
Collaborator

В приложении слегка обновленный файл с SRS.

Я не вижу смысла использовать что-то кроме tcp/ip, поэтому про udp (и все связанные костыли) можно забыть.

Я правильно понимаю что в этой модели, в будующем, именно worker будет заниматься администрированием конкретного сервера?

Может ли несколько worker запущено на одной машине?

Если соотношение 1 worker <-> 1 kf_server как на картинке, то это необходимо.

Хотя сейчас думаю и понимаю, что я не понимаю вектора атаки.

Основная проблема в том, чтобы запретить пересылать команды из внешних источников. Иначе кто угодно может менять базу данных (передавая данные на supervisor) или менять что-то на серверах (передавая данные на worker).

В приложении слегка обновленный файл с SRS. Я не вижу смысла использовать что-то кроме tcp/ip, поэтому про udp (и все связанные костыли) можно забыть. Я правильно понимаю что в этой модели, в будующем, именно worker будет заниматься администрированием конкретного сервера? > Может ли несколько worker запущено на одной машине? Если соотношение 1 worker <-> 1 kf_server как на картинке, то это необходимо. > Хотя сейчас думаю и понимаю, что я не понимаю вектора атаки. Основная проблема в том, чтобы запретить пересылать команды из внешних источников. Иначе кто угодно может менять базу данных (передавая данные на supervisor) или менять что-то на серверах (передавая данные на worker).
Sign in to join this conversation.
No Label
No Milestone
No Assignees
2 Participants
Notifications
Due Date

No due date set.

Dependencies

This issue currently doesn't have any dependencies.

Loading…
There is no content yet.