Какой участок сломан
Чтение и практика ~60 мин
по выводу клиента вы называете участок, на котором остановился запрос, — имя, соединение, HTTP или приложение, — подтверждаете это одним наблюдением и знаете, кому передать.
Подготовка: скачать лабораторию и открыть два терминала
Скачать лабораторию глав 1–5 · Памятка по запуску
Распакуйте архив в новую отдельную папку. Внутри будет папка network-diagnostics с lab/.
Откройте её в двух терминалах Linux. Нужны Python 3.12, curl, ss, nc и OpenSSL 3;
проверено на Ubuntu 24.04. Из Windows можно работать в уже настроенной Ubuntu в WSL.
macOS и обычная консоль Windows для этой лаборатории не проверены.
Проверьте инструменты до старта:
python3 --version
curl --version
ss --version
command -v nc
openssl version
Лаборатория занимает только loopback-порты, указанные в памятке, и не меняет DNS,
/etc/hosts, файрвол и часы компьютера. Если порт занят, остановите свой прежний запуск
через Ctrl+C или выберите другую учебную машину; чужой процесс завершать не нужно.
Глава 5 создаёт учебные сертификаты во временной папке и убирает их при остановке.
CA не нужно добавлять в доверие системы или браузера.
В первом терминале остаётся запущенный сценарий и его журнал. Во втором выполняются
наблюдения. Перед следующим сценарием остановите прежний через Ctrl+C. start начинает
новую учебную попытку, включая исходные заметки; set меняет работающий сценарий.
Путь запроса
клиент ──(1) имя──▶ DNS ──(2) адрес──▶ соединение TCP с адрес:порт ──(3)──▶ HTTP-сервер ──(4)──▶ приложение
Запрос проходит участки по порядку. Если он остановился на участке 1, до сервера он не дошёл вовсе. Если на участке 4, то участки 1–3 работают — и чинить их бессмысленно.
Подготовка
Все команды — из папки курса (network-diagnostics/). В первом окне терминала (это будет журнал сервера):
python3 lab/netlab.py start ch1
Во втором окне — все остальные команды. Если у вас задан HTTP_PROXY, у прямых вызовов curl добавляйте
--noproxy '*'.
Мини-задача: три жалобы
09:40. Три сообщения в чат поддержки, все про «Заметки», все — «не работает». У каждого пользователя свой клиент со своей настройкой адреса службы:
| Кто | Клиент | Адрес службы в настройке клиента |
|---|---|---|
| Анна | мобильное приложение | http://notes-api.lab.test:18080/api/notes |
| Борис | скрипт выгрузки | http://notes.lab.test:18081/api/notes |
| Вика | сайт | http://notes.lab.test:18080/api/notes |
Повторите запрос каждого клиента:
python3 lab/netlab.py fetch <адрес из таблицы>
echo "код выхода: $?"
До того как читать дальше, запишите для каждой жалобы: на каком участке (1–4) остановился запрос и какая строка вывода на это указывает. Одна строка на жалобу.
Что вы должны были увидеть
Анна: curl: (6) Could not resolve host: notes-api.lab.test код 6
Борис: curl: (7) Failed to connect to notes.lab.test port 18081 after 0 ms: Couldn't connect to server код 7
Вика: HTTP/1.1 500 Internal Server Error ... {"error": "database connection pool exhausted"} код 0
Если вывод другой — проверьте, что в первом окне запущен сценарий ch1.
Разбор мини-задачи
Откройте, когда записали свои ответы
Анна — участок 1, имя. Код 6 у curl — «не удалось разрешить имя»: до соединения дело не дошло, сервер этого
запроса не видел. Это не значит, что DNS сломан: может быть, неверно само имя.
Борис — участок 2, соединение. Код 7 — «не удалось подключиться». Имя разрешилось (иначе был бы код 6), но на
адресе и порту никто не принял соединение. Почему именно — краткая строка curl 8.5 не говорит: Couldn't connect to server
одинакова для разных причин. Подробность видна с --verbose: connect to … failed: Connection refused — порт закрыт,
отказ пришёл сразу.
Вика — участок 4, приложение. Код 0: для curl запрос успешен — соединение установлено, HTTP-ответ получен.
Участки 1–3 работают. Ответ 500 и тело database connection pool exhausted пришли от приложения
(Server: notes-app/3.0). Сеть здесь ни при чём; чинить нужно приложение или его базу. Если вызвать curl -f,
код станет 22 — флаг просит считать HTTP-ошибку неудачей; без него curl проверяет транспорт, а не смысл ответа.
Три одинаковые жалобы — три разных участка и три разных владельца.
Развилка: что делать дальше
Коллега предлагает: «Все три про "Заметки" — перезапущу приложение, и всё заработает». У вас 15 минут до разговора с владельцем службы. Решения (порядок случайный):
- А. Перезапустить приложение: все три жалобы про один сервис.
- Б. Для каждой жалобы — своё следующее наблюдение: для Анны спросить DNS про её имя и про имя из документации;
для Бориса посмотреть, кто слушает порт 18081 на сервере; для Вики проверить
/healthи журнал приложения. - В. Проверить
ping notes.lab.test: если отвечает — сеть в порядке, значит, во всём виновато приложение. - Г. Попросить всех троих очистить кэш и переустановить клиент.
- Д. Сначала сверить настройки клиентов Анны и Бориса с документацией службы (имя
notes.lab.test, порт 18080), затем для Вики — журнал приложения.
Для выбранного: что вы узнаете через 5 минут и кому что передадите.
Последствия
- А. Анна и Борис по-прежнему получают коды 6 и 7: перезапуск приложения не меняет ни имя в настройке Анны, ни порт Бориса. У Вики ответ, возможно, на несколько минут станет 200, пока пул соединений с базой снова не исчерпается. Вы потратили окно и потеряли состояние, по которому разработчики искали бы причину.
- Б.
python3 lab/netlab.py dig notes-api.lab.test→NXDOMAIN(такого имени нет),dig notes.lab.test→127.0.0.1: DNS работает, у Анны неверное имя в настройке.ss -ltn '( sport = :18080 or sport = :18081 )'→ слушает только 18080: Борис ходит не на тот порт.fetch …/health→ 200, а/api/notes→ 500 с текстом о пуле базы: приложение живо, но не может работать с базой — к разработчикам с этой строкой. Три адресные передачи. - В.
pingпроверяет, отвечает ли адрес на служебные сообщения ICMP, — не имя из настройки Анны, не порт Бориса и не HTTP. «Пинг есть» ничего не говорит ни об одной из трёх жалоб (подробно — глава 2). - Г. Пользователи тратят время, ничего не меняется: ни у одного из клиентов нет кэша, который вызвал бы эти коды.
- Д. Сравнение настроек сразу находит и имя Анны, и порт Бориса — без единой команды на сервере. Это так же верно,
как Б, если документация актуальна; если нет —
digиssиз Б покажут фактическое состояние.
Приёмка
Проверяется по вашим записям и по выводу команд, не по словам:
- Для каждой жалобы назван участок и приведена строка вывода или код выхода, которые на него указывают.
- Для каждой жалобы есть одно следующее наблюдение, которое подтверждает участок (
dig,ssилиnc -zv,/healthи журнал), и его результат. - Для Анны: с исправленным именем
fetch http://notes.lab.test:18080/api/notesдаёт уже не код 6, а ответ приложения — и это500, как у Вики. Вы объясняете, почему исправление одного участка открыло следующий. - Для каждой жалобы назван владелец: настройка клиента, настройка порта, приложение и база.
Подсказки
Подсказка 1 — направление
Посмотрите на код выхода curl: какие коды означают, что сервер вообще не получил запрос? При каком коде HTTP-ответ
пришёл?
Подсказка 2 — нужное наблюдение
python3 lab/netlab.py dig <имя> скажет, существует ли имя. ss -ltn покажет, какие порты слушают на сервере
(в лабе сервер — ваш компьютер). fetch …/health и строка Server: скажут, кто ответил.
Подсказка 3 — разбор
Анна — участок 1: NXDOMAIN для notes-api.lab.test, а notes.lab.test разрешается в 127.0.0.1 — неверное имя
в настройке клиента. Борис — участок 2: имя разрешилось, --verbose даёт Connection refused, ss показывает, что
слушает только 18080, — неверный порт в настройке скрипта. Вика — участок 4: curl код 0, HTTP 500 от notes-app/3.0,
/health 200, тело — исчерпан пул соединений с базой; сеть в порядке, нужен разработчик. Допустимы Б и Д; А тратит
окно и стирает улики, В проверяет не то, Г ничего не меняет.
Второй вариант
Через два дня, 14:10. Опоры меньше. Остановите сценарий в первом окне (Ctrl+C) и запустите ch1b:
python3 lab/netlab.py start ch1b
Жалобы:
| Кто | Адрес в настройке клиента |
|---|---|
| Вика | http://notes.lab.test:18080/api/notes |
| Борис | http://reports.lab.test:18082/export (служба отчётов, свой процесс) |
Повторите оба запроса (fetch, для Бориса — с --max-time 3) и запишите участок и следующее наблюдение. Затем выберите
решения.
Для Вики (порядок случайный):
- А. Ошибка приложения, как у Вики в прошлый раз: передать разработчикам тело ответа.
- Б. Посмотреть, кто сформировал ответ (заголовки, тело, журнал в окне лабы), и проверить, слушает ли что-нибудь адрес, куда этот сервер передаёт запрос дальше.
- В. Проверить DNS: вдруг имя теперь указывает на другой сервер.
Для Бориса (порядок случайный):
- А. Неверный порт, как в прошлый раз: исправить порт в настройке скрипта.
- Б. Увеличить тайм-аут клиента до 60 секунд.
- В. Посмотреть с
--verbose, установлено ли соединение, и если да — смотреть процесс и журнал службы отчётов.
Подсказка 1
Код curl у Вики — 0, как и в прошлый раз. Но кто ответил? Сравните строку Server: и тело с прошлым ответом.
У Бориса код другой, чем в прошлый раз, — какой и что он значит?
Подсказка 2
В окне лабы есть строка журнала посредника — куда он пытался передать запрос. ss -ltn покажет, слушает ли кто-нибудь
этот порт. Для Бориса: есть ли в --verbose строка Connected to?
Подсказка 3 — разбор
Вика: ответ 502 Bad Gateway сформировал посредник (Server: lab-proxy, HTML-страница вместо JSON приложения).
В журнале лабы: upstream 127.0.0.1:19000: connection refused, ss порт 19000 не показывает. Запрос дошёл до участка 3,
а на отрезке «посредник → приложение» соединение не установилось: приложение не запущено или слушает другой порт.
Буквальный повтор (А) отправит разработчикам страницу посредника вместо ошибки приложения — они будут искать в коде то,
чего нет. Допустимо Б. В — в этой ситуации журнал посредника уже указывает на недоступный upstream: его стоит проверить следующим. Сам по себе HTTP-ответ не доказывает правильность адреса DNS — это увидим в следующей главе.
Борис: код 28 — тайм-аут, --verbose показывает Connected to reports.lab.test (127.0.0.1) port 18082 и
0 bytes received. Соединение установлено — порт верный и открыт, но служба не отвечает. Буквальный повтор (А) меняет
верный порт на неверный. Б — частичное: если служба зависла, ответа не будет и через минуту, а скрипт будет ждать
дольше. Допустимо В.
Факт, который меняет решение: в основной части код 0 означал «ответило приложение», здесь код 0 — ответ посредника; там код 7 — порт закрыт, здесь код 28 после установленного соединения — порт открыт, молчит процесс.
Источники
- Руководство curl: параметры и коды выхода.
- HTTP: имя целевого сервера, ошибки сервера.
- DNS: TTL записи.
- Linux: порядок источников имён в nsswitch.conf.
Тексты сообщений могут отличаться между сборками curl. Поведение учебного DNS и службы задаёт лаборатория; в главе 2 вывод ping обозначен как модель. TTL в опыте — поле ответа, кэширование всех реальных клиентов лаборатория не воспроизводит.
Прочитали и разобрались? Отметьте урок — прогресс сохранится в этом браузере.