Эта документация предназначена для системных архитекторов, желающих понимать, за счет каких инженерных решений slyber_turn достигает высокой пропускной способности и минимальных накладных расходов на CPU и память.
1. Сетевой стек: SO_REUSEPORT и автотюнинг буферов сокетов
В классических реализациях TURN один UDP сокет на порту 3478 становится узким местом из за блокировок на уровне ядра ОС при чтении пакетов из одной очереди.
- Масштабирование по ядрам CPU: На Linux
slyber_turnпо умолчанию создает столько UDP сокетов на порту3478, сколько доступно ядер процессора (TURN_THREADS = runtime.NumCPU()), устанавливая флаг сокетаSO_REUSEPORTиSO_REUSEADDR. Ядро Linux самостоятельно распределяет входящие пакеты по очередям разных сокетов, позволяя горутинамpion/turnобрабатывать трафик параллельно без конкуренции за один дескриптор. - Каскадный тюнинг
SO_RCVBUFиSO_SNDBUF: - Для управляющих сокетов (
3478) сервер последовательно пытается установить размер буфера приема и отправки в8 МБ→4 МБ→1 МБ→512 КБ(выбирая максимально разрешенный ядром размер). - Для каждого выделяемого релейного сокета (
49152–65535) автоматически применяется буфер1 МБ→512 КБ→256 КБ.
2. Неблокирующий шейпинг трафика и батчинг телеметрии
Каждое релейное соединение оборачивается в trackedPacketConn (для UDP) или trackedConn (для TCP). Так как через эти методы проходят десятки тысяч пакетов в секунду, на горячем пути (ReadFrom / WriteTo) полностью исключены мьютексы (sync.Mutex):
- Lock Free
bandwidthLimiter: Ограничитель скорости на сессию реализован на атомарных операциях (atomic.Int64+CompareAndSwap) с окном пополнения токенов10 мс. При превышении лимита на UDP сокете пакеты отбрасываются без блокировки потока, а на TCP сокете применяется мягкое ожидание (wait). - Пакетный сброс счетчиков трафика: Чтобы не вызывать глобальную синхронизацию телеметрии на каждый 100 байтный голосовой пакет, каждая сессия накапливает байты в локальном атомике
unflushedBytesи сбрасывает их в глобальный счетчикDefaultTelemetryтолько при накоплении 64 КБ (или при закрытии/опросе сессии).
3. Zero Allocation аутентификация и защита от утечек памяти
- Вычисление паролей на стеке: В методе
computePassword(и в клиентскомturnclient.GenerateLocal) буферы для хеша SHA1 (var sumBuf [20]byte) и Base64 (var b64Buf [28]byte) выделяются в виде фиксированных массивов на стеке, что минимизирует нагрузку на сборщик мусора (GC) при массовых переподключениях клиентов. - Жесткие лимиты таблиц (
maxTrackedEntries = 50000): Таблицы отслеживания сессий (sessions) и дедупликации ошибок (failDedup) защищены атомарным счетчиком до 50 000 записей и очищаются в фоновой горутине не чаще одного раза в 30 секунд без остановки обработки запросов.
4. Связывание авторизации и аллокации
Поскольку библиотека pion/turn разделяет интерфейс проверки пароля (AuthHandler) и интерфейс выделения релейного порта (RelayAddressGenerator), slyber_turn связывает их через высокоскоростную кольцевую очередь authQueue на 64 элемента и атомарный указатель lastAuth в NodeTelemetry. Это позволяет точно привязать user_id и client_ip к конкретному выделенному UDP/TCP-порту ретрансляции в момент AllocatePacketConn / AllocateConn.