ОС и сети для Go-бэкендера — что под рантаймом
Go прячет операционную систему за удобным рантаймом: вы пишете os.Open, http.Get, go func() — и не видите ни системных вызовов, ни потоков ядра, ни страниц памяти. Но в проде эта абстракция протекает. Сервис ловит SIGKILL от OOM killer, упирается в лимит файловых дескрипторов, top рисует «невозможные» 146% CPU, а медленный сокет держит поток ядра. Объяснение каждого из этих случаев лежит на уровне ОС — и backend-инженера на собеседовании проверяют именно здесь.
Темы группируются вокруг одной границы — между user space и kernel space. Ваш код работает в ограниченном режиме и не может сам открыть файл или сокет; он просит ядро через syscall, и этот переход в привилегированный режим стоит дорого. Память ваша — виртуальная, разбитая на страницы, которые ядро отображает на физические кадры. Ресурсы ядра вы держите за дескрипторы, а управляете процессом через сигналы. Снаружи всё это общается по сети — надёжным TCP или быстрым UDP, поверх которого живут HTTP и новый QUIC. Эта тема разбирает слой под рантаймом по частям.
Карта темы
- User space и kernel space — почему код приложения работает в ограниченном режиме и зачем нужна граница привилегий.
- Системные вызовы — как запрос сервиса ОС переводит CPU из пользовательского режима в режим ядра и почему это дорого.
- Виртуальная память и страницы — страница как единица управления памятью, отображение виртуальных страниц на физические кадры и page fault.
- Процесс против потока — потоки делят адресное пространство, процессы изолированы; в Linux оба это задачи планировщика.
- Файловые дескрипторы — целое число от ОС на открытый ресурс, дескрипторы 0/1/2 и утечка через незакрытые ресурсы.
- Сигналы процесса —
SIGTERMдля аккуратного завершения противSIGKILL, который ядро не даёт перехватить. - OOM killer — что происходит при исчерпании RAM: своп и thrashing либо принудительное убийство процесса ядром.
- Чтение загрузки CPU — почему
topпоказывает больше 100%: это сумма по всем ядрам, а не доля одного. - TCP против UDP — надёжная упорядоченная доставка против быстрой доставки без гарантий, и когда выбирать UDP.
- Устройство HTTP — текстовый запрос/ответ: стартовая строка, заголовки, тело и коды состояния.
- QUIC и HTTP/3 — транспорт поверх UDP со встроенным TLS 1.3, независимыми потоками и миграцией соединения.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Считать загрузку top выше 100% ошибкой | Это сумма по ядрам; 146% — это ~1.46 ядра, норма для многопоточного процесса |
Сразу слать kill -9 | SIGKILL не даёт процессу закрыть ресурсы и сохранить данные — сначала SIGTERM |
Не закрывать ресурсы (файлы, resp.Body) | Утечка файловых дескрипторов и too many open files под нагрузкой |
| Думать, что процессы делят память как потоки | Процессы изолированы; для обмена нужен IPC |
| Считать syscall обычным вызовом функции | Это переход в режим ядра с заметной ценой; в Go он отвязывает P от потока |
| Брать UDP ради скорости, забыв про потери | UDP не гарантирует доставку и порядок — надёжность реализуете сами |
| Полагать, что OOM killer убьёт «виновника» | Он выбирает по oom_score; может убить не тот процесс, особенно без лимитов |
| Путать страницу виртуальной памяти с физической | Виртуальная страница отображается на физический кадр через таблицы страниц |
Значение для собеседований
ОС и сети — обязательная секция backend-интервью на Go. Проверяют не знание команд, а модель: где проходит граница ядра, что стоит за syscall и как сервис взаимодействует с ОС и сетью под нагрузкой.
Что обычно проверяют:
- Зачем нужна граница user/kernel space и что её пересекает.
- Что такое syscall и что происходит с CPU при его выполнении.
- Чем процесс отличается от потока по памяти и изоляции.
- Что такое файловый дескриптор и как утекают
too many open files. - Разница
SIGTERM/SIGKILLи почемуkill -9— плохой первый выбор. - Чем TCP отличается от UDP и когда оправдан UDP (и QUIC поверх него).
Типичный неверный ответ: «146% CPU в top — это баг, процесс не может занять больше ядра». Это запускает разбор того, что top суммирует загрузку по всем ядрам, поэтому 146% означает примерно полтора ядра одновременно — нормально для процесса с несколькими потоками или активным рантаймом Go.