Initial commit

This commit is contained in:
step305
2026-09-29 20:20:26 +03:00
parent 61d0ec3bcd
commit 17b5d19f69
17 changed files with 808 additions and 14 deletions
+110 -12
View File
@@ -1,12 +1,110 @@
# Установка Go
```bash
sudo apt update
sudo apt upgrade -y
wget https://go.dev/dl/go1.27.1.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.27.1.linux-amd64.tar.gz
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.profile
source ~/.profile
rm go1.27.1.linux-amd64.tar.gz
go version
```
## Итоговое техническое описание проекта: Высоконагруженный STUN-сервер на Go
Данный проект представляет собой сверхбыстрый, отказоустойчивый и оптимизированный
под экстремальные нагрузки STUN-сервер (Session Traversal Utilities for NAT),
написанный на языке Go (Golang). Сервер разработан в соответствии со стандартами
RFC 5389 и RFC 8489 и предназначен для использования в инфраструктурах реального
времени (WebRTC, VoIP, SIP, онлайн-игры) с целью определения внешних IP-адресов
и портов клиентов, находящихся за NAT.
Проект полностью контейнеризирован с помощью Docker и Docker Compose, а также
защищен на уровне ядра ОС Linux, что позволяет ему обрабатывать тысячи запросов
в секунду (RPS) на минимальных серверных мощностях.
------------------------------
## 🚀 Архитектурные особенности и ключевые фишки
Архитектура проекта сфокусирована на достижении максимальной пропускной способности
и минимального времени отклика (в тестах задержка составляет всего 20–30 мс):
1. Концепция True Zero-Alloc (Нулевое выделение памяти в куче):
* Вместо аллокации нового буфера под каждый входящий UDP-пакет, каждый независимый
* воркер создает фиксированный срез байт (buf := make([]byte, 1500)) единожды
* перед запуском бесконечного цикла.
* Ответ клиенту формируется в том же самом массиве данных поверх исходного
запроса (buf = buf[:cap(buf)]).
* Сборщик мусора Go (Garbage Collector) вообще не нагружается во время
обработки сетевого флуда. Это исключает микропаузы (STW) сервера под нагрузкой.
2. Использование современного пакета net/netip:
* Взамен старого типа net.IP (который является срезом и всегда аллоцируется в куче),
в коде применен пакет net/netip.
* Объект netip.AddrPort хранит данные в виде легковесной структуры фиксированного
размера, которая обрабатывается исключительно на уровне быстрого стека процессора.
3. Многопоточный пул воркеров (Worker Pool):
* Сервер автоматически определяет количество доступных логических ядер процессора
(runtime.NumCPU()) и запускает строго эквивалентное количество горутин-воркеров.
* Ядро Linux равномерно распределяет сетевые прерывания от UDP-сокета,
утилизируя процессор на все 100%.
4. Мягкое завершение работы (Graceful Shutdown):
* Сервер перехватывает системные сигналы остановки от операционной системы
или Docker-демона (SIGINT, SIGTERM).
* При получении команды на выключение сокет закрывается, воркеры корректно
дорабатывают текущую итерацию, а sync.WaitGroup гарантирует завершение процессов
без потери обрабатываемых пакетов.
------------------------------
## 🐳 Контейнеризация и Безопасность в Docker
Проект поставляется со специализированной конфигурацией развертывания,
обеспечивающей максимальную производительность и изоляцию:
* Многоэтапная сборка (Multi-stage Build): Образ собирается в официальном
контейнере golang:alpine, где происходит компиляция бинарника со флагами
-ldflags="-s -w" (вырезаются отладочные символы, что уменьшает размер файла
в 2 раза).
* Супер-легковесный и безопасный финальный слой (scratch): Финальный образ
собирается на базе абсолютно пустого слоя FROM scratch. Внутри контейнера
нет Linux-дистрибутива, нет пакетных менеджеров, утилит (sh, bash, ls)
и зависимостей. Вес готового Docker-образа составляет всего ~15-20 МБ.
* Принцип Non-Root: Внутри контейнера процесс STUN-сервера запускается
от имени непривилегированного системного пользователя stunuser.
В случае гипотетической уязвимости в коде, злоумышленник не сможет выйти на
хост-систему или получить права суперпользователя.
* Сетевой режим network_mode: "host": Контейнер подключен к сетевой карте
VPS напрямую. Это исключает прослойку docker-proxy и встроенную маршрутизацию
Docker, которая является главным «узким горлышком» для UDP-трафика и приводит
к потере пакетов под нагрузкой.
------------------------------
## 🛠️ Системный тюнинг ОС Linux под Highload UDP
По умолчанию буферы сетевых сокетов в Linux настроены на низкую нагрузку.
При шторме UDP-запросов буфер быстро переполняется, и ядро ОС начинает молча
дропать (терять) пакеты еще до того, как Go-приложение успеет их прочитать.
Для решения этой проблемы в проекте применяется сетевой тюнинг ядра через
конфигурацию sysctl. Максимальные и дефолтные буферы приема (rmem) и отправки
(wmem) сетевых сокетов расширяются до 25 Мегабайт (26214400 байт):
* net.core.rmem_max=26214400
* net.core.wmem_max=26214400
Эти настройки жестко фиксируются в системном файле /etc/sysctl.conf хост-машины,
благодаря чему сервер гарантированно выдерживает кратковременные всплески трафика
(микро-штормы), удерживая пакеты в памяти ОС до момента их вычитки воркерами.
------------------------------
## 📋 Структура конфигурационных файлов проекта
Проект имеет модульную и простую структуру, состоящую из следующих компонентов:
1. main.go — Весь исходный код сервера. Содержит логику инициализации,
пул воркеров, парсинг сырых байт STUN-заголовка, генерацию XOR-маппинга для
обхода NAT и отправку ответов.
2. go.mod — Файл описания Go-модуля (проект STUN на базе Go 1.27.1) с
автоматической фиксацией низкоуровневых системных зависимостей (golang.org/x/sys).
3. Dockerfile — Инструкция сборки безопасного микро-контейнера на базе
scratch от лица non-root пользователя.
4. docker-compose.yml — Манифест для оркестрации: настраивает запуск в
режиме host, прокидывает переменные окружения, ограничивает ресурсы
(Limits: 2 CPU, 128MB RAM) и защищает диск от переполнения логами
(ротация логов ограничена 3 файлами по 10МБ).
5. .env — Файл конфигурации переменных среды, где хранится внешний публичный
IPv4-адрес сервера (PUBLIC_IP), необходимый для корректного заполнения
STUN-аттрибутов ответа.
------------------------------
## 📈 Результаты тестирования пропускной способности
В ходе стресс-тестирования методом асинхронного UDP-флуда
(параллельный запуск тысячи клиентов turnutils_stunclient), сервер показал
следующие результаты:
* Линейная масштабируемость: Обработка пакета из 2000 одновременных
запросов выполняется за ~1.19 сек, демонстрируя чистую скорость ~1550-1700 RPS
(запросов в секунду) на один клиентский поток тестирования.
* Параллельная утилизация ядер: Время работы в пользовательском пространстве
(user) и пространстве ядра (sys) превышает реальное время теста (real),
что доказывает идеальную параллельную работу пула воркеров на всех доступных
ядрах процессора хоста.