Представьте себе классический кошмар системного администратора или SRE: три часа ночи, в управлении огромный кластер Greenplum на сотню сегмент-хостов, и вам нужно запустить тяжелый ETL-процесс или проверить доступность gpfdist строго одновременно на всех узлах.

Вы начинаете перебирать инструменты. Стандартный Cron? Он локальный, замучаешься синхронизировать конфиги. Ansible или SaltStack? Хороши, но требуют центрального «мастера» и стабильного SSH-соединения в момент старта. А если в дата-центре «моргнула» сеть и часть сегментов оказалась изолирована? Команда просто не дойдет.

Я решил, что миру нужен инструмент, который ведет себя как «умный почтовый ящик»: вы закидываете в него зашифрованную команду, а она сама расползается по всей сети и ждет своего часа, чтобы «выстрелить» точно в срок. Так появилась Gorgona.

В этой статье я расскажу о тернистом пути создания распределенной системы на чистом C, о том, как я боролся с «сетевым эхо» и почему это решение заставляет админов больших баз данных спать спокойнее.


Хотя я начинал с Greenplum, архитектура Gorgona идеально ложится на любые распределенные системы, где количество узлов переваливает за десятки, а цена ошибки при рассинхроне растет экспоненциально.

1. ClickHouse: Управление без «тормозов» ZooKeeper или ClichouseKeeper

В ClickHouse часто возникают ситуации, когда нужно выполнить DDL-запросы или обслуживание на сотнях шардов. Если Keeper (координатор) перегружен, стандартные механизмы ON CLUSTER начинают тормозить.

  • Gorgona-кейс: Вы доставляете команды обслуживания (например, FREEZE PARTITION для бэкапа) через P2P-сеть Gorgona. Команды исполняются локально на каждом узле строго в назначенное время, не создавая нагрузки на координатор БД.

2. Ceph: Диагностика OSD в режиме «реального времени»

Когда в Ceph начинается «шторм» (rebalancing) после падения дисков, нагрузка на сеть и CPU зашкаливает. Пытаться пробиться по SSH на каждый из 500 OSD-узлов в этот момент - сомнительное удовольствие.

  • Gorgona-кейс: Заранее развернутые агенты Gorgona позволяют «пробросить» команду диагностики через Mesh-сеть. Даже если прямой канал к узлу забит трафиком репликации Ceph, пакет Gorgona дойдет «окольными путями» через соседей и выполнит smartctl или iostat, вернув результат.

3. Apache Kafka: Массовое изменение конфигов брокеров

Kafka-брокеры очень чувствительны к сетевым задержкам. При обновлении правил фильтрации или лимитов (quotas) на лету, важно, чтобы изменения вступили в силу максимально синхронно, чтобы избежать перекосов в партициях.

  • Gorgona-кейс: Распространяем новые параметры через зашифрованный канал. Ноды применяют их автономно. Это исключает ситуацию, когда половина брокеров работает по старым правилам, а половина - по новым из-за того, что ваш Ansible-скрипт «завис» на середине списка.


Почему C и зачем такие сложности?

Когда начинаешь проект подобного уровня, всегда есть искушение взять Go, Python или Rust. Но у меня была идея-фикс: Zero Dependencies. Инструмент должен запускаться на любой «железке», иметь минимальный след в памяти и не тянуть за собой мегабайты библиотек. Только чистый C по заветам старой школы и OpenSSL.

Философия «Слепого сервера»

Главная интрига Gorgona в том, что сервер абсолютно «глуп» и «слеп». Он работает по принципу End-to-End Encryption.

  1. Клиент шифрует команду на своей стороне (RSA-OAEP для ключей + AES-GCM для данных).

  2. Сервер получает бинарный блоб. Он не знает, что внутри: команда rm -rf / или отчет о погоде.

  3. Команда снабжается метаданными: unlock_at (когда выполнить) и expire_at (когда удалить).

Сервер честно хранит этот мусор до наступления unlock_at, и только в этот момент клиент, имеющий приватный ключ, может забрать и выполнить команду.

Путь к Mesh-сети: Инженерная драма в трех актах

Изначально Gorgona была классическим клиент-сервером. Но для кластера Greenplum, где узлов может быть сто и больше, один сервер - это «точка отказа». Упал сервер - кластер ослеп. Нужно было делать репликацию.

Акт I: Рождение сплетника

Я решил внедрить Active-Active репликацию на основе Gossip-протокола. Идея проста: каждый сервер - это и клиент, и сервер одновременно. Как только одна нода получает команду от админа, она тут же «бежит» рассказывать об этом всем своим соседям (пирам).

Акт II: Бесконечное эхо

И вот тут я наступил на классические грабли распределенных систем. Мои серверы оказались слишком «болтливыми». Сервер А шлет весть Серверу Б. Сервер Б принимает её и, как добросовестный сплетник, шлет её обратно Серверу А. Сервер А снова её принимает… Через секунду мои логи превратились в бесконечный поток однотипных сообщений, процессор ушел в 100%, а сеть забилась «мусором». Это был идеальный шторм в стакане воды.

Акт III: Правило «Стоп-крана»

Решение пришло через внедрение идемпотентности. Я переписал логику сохранения сообщений так, чтобы сервер сначала проверял: «А видел ли я этот пакет раньше?». Теперь функция возвращает разные статусы:

  • Status 0 (Новинка): «О, этого я еще не слышал!» - сохраняем и пересылаем всем соседям.

  • Status 1 (Дубликат): «Я это уже знаю, замолчи» - игнорируем и прекращаем пересылку.

Это простое правило мгновенно превратило хаос в упорядоченную Mesh-сеть. Пакет разлетается по любой сложной топологии (цепочка, звезда, паутина) и затихает ровно в тот момент, когда все узлы получили свою копию.

Как не потерять историю: Snowflake и Mutual Sync

А что если один из серверов сегментов был выключен на профилактику? Пока он «спал», в сеть прилетело три важных команды.

Чтобы ноды могли «догонять» друг друга, я использовал Snowflake ID (привет Твиттеру > X). Это 64-битные идентификаторы, в которых зашифровано время создания. Они уникальны и всегда идут в порядке возрастания.

При подключении ноды делают «взаимное признание»:

  1. Node A: «Привет, мой последний ID в базе - 162045…».

  2. Node B: «О, а у меня есть кое-что поновее!» - и выплевывает из своего mmap-буфера всю историю, которую пропустил сосед.

Это называется Mutual Sync. Нодам не нужна центральная БД типа Postgres или Redis, чтобы договориться. Они делают это сами, на лету.

На передовой: Greenplum, ETL и gpfdist

Давайте вернемся к нашему кластеру Greenplum. Почему это решение так нравится админам?

В MPP-системах основная нагрузка (и основные проблемы) живут на сегмент-хостах. Типичный сценарий: вам нужно запустить проверку gpfdist (сервиса раздачи данных) на всех сегментах перед огромной загрузкой данных.

Как это работает с Gorgona:

  1. Вы запускаете клиент gorgona listen -e на каждом хосте.

  2. Отправляете одну команду с ноутбука на любой ближайший сервер.

  3. Через миллисекунды команда «просачивается» на все 50-100 серверов.

  4. В назначенные 03:00 все хосты одновременно дергают локальный скрипт проверки.

Безопасность здесь запредельная: даже если хакер получит Root-доступ к вашему репликационному серверу, он увидит только зашифрованные куски данных. Он не может подменить команду или прочитать её, потому что приватный ключ лежит только на целевых сегмент-хостах.

Немного легкости: Зашифрованная погода

Система получилась настолько гибкой, что её можно использовать даже для повседневных нужд. Например, я настроил себе команду получения погоды в любом городе на выбор (когда скомпилируете клиента и скопируете ключи в /etc/gorgona, город и глубину можете указать свои) и на глубину дней. Выглядит это максимально по-хакерски:

echo "weather 3 Moscow" | gorgona send "$(date -u '+%Y-%m-%d %H:%M:%S')" \
"$(date -u -d '+30 days' '+%Y-%m-%d %H:%M:%S')" - "RWTPQzuhzBw=.pub" && gorgona listen new

Через мгновение по всей цепочке репликации прилетает ответ:

Received Alert: Recipient_Hash=RWTPQzuhzBw=
Alert ID: 162045830651904
Timestamps (Local): Created: 2026-04-04 00:26:10
Decrypted Content:
Weather for Moscow, RU

               overcast clouds
      .--.     7 (6) °C       
   .-(    ).   ↘ 6 km/h       
  (___.__)__)                 
               0.0 mm/h     
в репозитории на https://github.com/psqlmaster/gorgona находится публичный и приватный ключ для этой команды
в репозитории на https://github.com/psqlmaster/gorgona находится публичный и приватный ключ для этой команды

Да, это консольно, сурово, но это работает через распределенную сеть без единой точки отказа!


Примеры использования: От мониторинга до «самолечения» кластера

1. Мгновенный аудит нагрузки (Load Average)

Традиционный пример: получение статуса конкретного узла. Благодаря mmap и неблокирующему I/O, ответ прилетает мгновенно, как только нода видит разблокированное сообщение.

# Отправляем запрос на получение кастомного Load Average и ждем ответа
gorgona send "$(date -u '+%Y-%m-%d %H:%M:%S')" \
             "$(date -u -d '+30 days' '+%Y-%m-%d %H:%M:%S')" \
             "la" "BTW9V5jVztY=.pub" && gorgona listen new BTW9V5jVztY=

# Вывод клиента:
# Server response: Alert added successfully
# Server: Subscription updated
# Received Alert: Recipient_Hash=BTW9V5jVztY=
# Alert ID: 162195016097792
# Timestamps (Local): Created: 2026-04-04 10:33:12, Unlock: 2026-04-04 10:33:12
# Decrypted Content:
#  10:33:12 up 5 days, 9:41 LA=0.14, 0.11, 0.09 | CPU_USAGE:7.1% | CORES:16 | MEM:17Gi/124Gi

2. Пробитие сетевой изоляции (P2P Relay)

Допустим, у вас есть 3 сегмента сети: A, B и C. Ваша админская машина видит только сегмент A. Ноды сегмента A видят B, а те видят C.

В случае с SSH вам пришлось бы строить цепочку Jump-хостов. В Gorgona вы просто кидаете пакет в ближайшую ноду:

# Мы шлем пакет ноде в сегменте A, а она сама "расплетничает" его в сегменты B и C
echo "check_status" | gorgona send "$(date -u '+%Y-%m-%d %H:%M:%S')" "$(date -u -d '+30 days' '+%Y-%m-%d %H:%M:%S')" - "segments_all.pub"

Репликация сама найдет путь до целевых хостов в Mesh-сети. Это делает управление инфраструктурой устойчивым к сложным топологиям и временным разрывам связности.

3. Синхронный «выстрел» без jitter (разброса по времени)

Даже с xargs -P100 ssh, время запуска команды на 1-й и 100-й ноде будет разным из-за времени на установку TCP-соединения и Handshake. Для точных тестов производительности это критично.

В Gorgona вы заранее (за 10 минут) распространяете пакет:

# Команда уже лежит в памяти всех нод, ожидая наступления 15:00:00 UTC
gorgona send "2026-04-04 15:00:00" "2026-04-04 15:01:00" "run_heavy_etl_test" "db_nodes.pub"

Ровно в 15:00:00.000 все 100 серверов одновременно начнут выполнение. Это истинная атомарность в распределенной системе.

Что под капотом? (Для тех, кто любит погорячее)

  • Сетевой движок: Однопоточный select() с неблокирующими сокетами. Почему не epoll? Для 100-200 соединений в кластере select() проще в отладке и переносимее.

  • Хранение: База на mmap(). Весь индекс - это кольцевой буфер в памяти, который ядро Linux само сбрасывает на диск. Скорость доступа - космическая.

  • Anti-Replay: Двухуровневая защита. Мы отсекаем пакеты, которые «протухли» (unlock_at слишком далеко в прошлом), и храним скользящее окно хешей последних 50 сообщений, чтобы никто не смог отправить одну и ту же команду дважды.

Итоги и планы

Gorgona превратилась из маленького эксперимента в полноценный P2P-движок управления инфраструктурой. Она позволяет строить автономные системы, которым не нужен «большой брат» в виде центральной БД.

В ближайших планах:

  • epoll: Если вы вдруг захотите построить кластер на 10 000 нод.

  • Web-дашборд: Чтобы видеть «карту сплетен» в реальном времени.

Резюме проекта:

Gorgona - это высокопроизводительная «цифровая нервная система» для распределенной инфраструктуры, сочетающая в себе свойства защищенного мессенджера и децентрализованного планировщика задач. Благодаря интеграции криптографии RSA-AES-GCM с механизмом отложенного выполнения (Time-Lock) и возможностью безопасного запуска системных команд (-e), проект предлагает решение для скрытого и отказоустойчивого управления парком серверов. Это не просто инструмент для обмена сообщениями, а полноценный криптографический оркестратор, способный функционировать в условиях агрессивной сетевой среды, где доверие к центральному звену исключено, а точность и конфиденциальность исполнения команд являются приоритетом.

Это «доверенный канал управления через недоверенную сеть». Вы можете управлять серверами даже через публичный интернет, не боясь перехвата или подделки команд.
Gorgona нужна там, где стандартные инструменты управления (SSH, Ansible, Cloud) либо слишком уязвимы, либо слишком централизованы.

Проект полностью открыт. Если вам близка тема системного программирования на C, заглядывайте на GitHub. Буду рад звездам, форкам и обсуждениям новых сценариев использования!

[Ссылка на GitHub: https://github.com/psqlmaster/gorgona]



get cluster status:

cmd="status BQQCyN8zo4La2lRSIQ2jLp5imEa0JzdXp2PKogP3"; echo "$cmd" | nc 64.188.70.158 7777; echo "$cmd" | nc 46.138.247.148 7777

output:

--- Gorgona Node [64.188.70.158 7777] Detailed Status ---
Version: 2.9.0
Uptime: 0d 1h 27m
Connections:
  - Active Clients: 3 / 100
  - Authenticated Peers: 2 / 1 (configured)
Storage Metrics:
  - DB Storage Mode: Persistent (Disk)
  - Unique Recipients (Keys): 5
  - Active Alerts (Live): 3041
  - Database Size: 1.23 MB
  - Disk Waste (Awaiting Vacuum): 0
  - Vacuum Threshold: 50%
  - History Starts From: 2026-04-05 12:45:55 UTC
Operational Configuration:
  - Max Alerts per Key: 1000
  - Max Message Size: 2 MB
  - Logging Level: info
-----------------------------------------------------
--- Gorgona Node [192.168.1.200 7777] Detailed Status ---
Version: 2.9.0
Uptime: 0d 1h 27m
Connections:
  - Active Clients: 2 / 100
  - Authenticated Peers: 2 / 1 (configured)
Storage Metrics:
  - DB Storage Mode: Persistent (Disk)
  - Unique Recipients (Keys): 5
  - Active Alerts (Live): 3041
  - Database Size: 1.23 MB
  - Disk Waste (Awaiting Vacuum): 0
  - Vacuum Threshold: 50%
  - History Starts From: 2026-04-05 12:45:55 UTC
Operational Configuration:
  - Max Alerts per Key: 1000
  - Max Message Size: 2 MB
  - Logging Level: info
-----------------------------------------------------