Що таке Unix Domain Socket: секретний тунель у Linux
Опубліковано

Що таке Unix Domain Socket: секретний тунель у Linux

 

У нашій подорожі світом сокетів ми почали з “верхнього поверху” — WebSocket у браузері, потім спустилися до фундаменту інтернету — TCP/IP сокетів. Але є ще один, особливий вид сокетів, який живе глибоко в надрах вашого сервера і про який часто забувають.

Ви, напевно, бачили у конфігах Nginx або MySQL дивні шляхи, що закінчуються на .sock, наприклад, /var/run/php/php8.2-fpm.sock. Це не картинка, не текстовий файл і не папка. Це — Unix Domain Socket (UDS). У цій статті я розповім, чому ці “файли” є секретною зброєю для прискорення локальної комунікації.

 

Аналогія: Пошта проти Записки

Щоб зрозуміти різницю між TCP-сокетом і Unix-сокетом, уявімо офіс.

  • TCP/IP Сокет (127.0.0.1:80): Ви хочете передати документ колезі, який сидить за сусіднім столом. Ви кладете документ у конверт, пишете адресу офісу, клеїте марку, кидаєте в поштову скриньку. Пошта сортує його і приносить назад у ваш офіс вашому колезі. Це надійно, але безглуздо довго, якщо ви в одній кімнаті.
  • Unix Сокет (/tmp/mysql.sock): Ви просто передаєте документ колезі прямо в руки. Жодних конвертів, адрес, марок і поштарів.

 

Як це працює технічно?

Unix-сокет — це стандартний механізм міжпроцесної взаємодії (IPC) в POSIX-сумісних системах (Linux, macOS). На відміну від мережевих сокетів, які використовують IP-адреси та порти, Unix-сокети використовують файлову систему як адресний простір.

Ось чому вони швидші:

  • Немає мережевого оверхеду: Ядру ОС не потрібно створювати TCP-пакети, рахувати контрольні суми, керувати порядком пакетів та підтвердженням доставки (ACK).
  • Пряме копіювання пам’яті: Дані просто копіюються з буфера однієї програми в буфер іншої через ядро.
  • Менше перемикань контексту: Процесор виконує менше зайвих операцій.

 

Безпека: права доступу як у файлів

Це одна з головних переваг. Оскільки Unix-сокет відображається як файл у файловій системі, до нього застосовуються стандартні права доступу Linux (chmod, chown).

Наприклад, якщо у вас є файл сокета бази даних /tmp/mysql.sock, ви можете налаштувати права так, що тільки користувач www-data (ваш веб-сервер) зможе в нього писати. Будь-який інший користувач на сервері навіть не зможе спробувати підключитися до бази. З TCP-портом (наприклад, 3306) це зробити складніше — він відкритий для всіх на localhost.

 

Практичне застосування: де ми це використовуємо?

 

1. Nginx + PHP-FPM

Це класика. У моїй статті про FastCGI ми налаштовували зв’язок між веб-сервером і PHP. Ви можете зробити це двома способами:

Метод Конфігурація Nginx Коли використовувати
TCP Сокет fastcgi_pass 127.0.0.1:9000; Якщо Nginx і PHP-FPM на різних серверах (розподілена архітектура).
Unix Сокет fastcgi_pass unix:/var/run/php/php-fpm.sock; Якщо вони на одному сервері. Дає приріст продуктивності.

 

2. Docker Daemon

Ви коли-небудь замислювалися, як Docker CLI спілкується з самим Docker двигуном? За замовчуванням це відбувається через Unix-сокет /var/run/docker.sock. Саме тому, щоб запустити Docker без sudo, вам потрібно додати користувача в групу, яка має права на цей файл-сокет.

 

3. Бази даних (MySQL, PostgreSQL, Redis)

Якщо ваш сайт підключається до бази даних на тому ж сервері (“localhost“), використання сокета (localhost:/tmp/mysql.sock) буде швидшим, ніж підключення через TCP (127.0.0.1:3306).

 

Практика: спілкуємося через файл-сокет на Python

Давайте створимо сервер, який слухає не порт, а файл. Зверніть увагу на використання socket.AF_UNIX замість AF_INET.

Код сервера (unix_server.py)
import socket
import os
socket_path = "/tmp/demo_socket.sock"
# Переконаємося, що файл сокета не існує
if os.path.exists(socket_path):
    os.remove(socket_path)
# Створюємо Unix-сокет (AF_UNIX)
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
# Прив'язуємо до файлу
server.bind(socket_path)
# Слухаємо
server.listen(1)
print(f"Слухаю на {socket_path}")
while True:
    connection, client_address = server.accept()
    try:
        print("З'єднання встановлено!")
        data = connection.recv(1024)
        print(f"Отримано: {data.decode()}")
        connection.sendall(b"Hello from Unix Socket!")
    finally:
        connection.close()

Клієнт для такого сервера виглядає майже так само, тільки замість IP та порту він підключається до шляху файлу:

client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client.connect("/tmp/demo_socket.sock")
client.sendall(b"Hello Server!")

 

Висновок: локальний герой

Unix Domain Sockets — це незамінний інструмент для оптимізації високопродуктивних систем. Вони прибирають зайвих посередників у спілкуванні програм на одному комп’ютері.

Якщо ваші сервіси (веб-сервер, база даних, кеш) живуть на одній машині, завжди надавайте перевагу Unix-сокетам перед TCP. Це безкоштовний і простий спосіб знизити затримки (latency) та навантаження на процесор.

 

 

 

Напишіть тут свою думку/питання

Ваша пошта не публікуватиметься. Обов’язкові поля позначені *