Skip to content

optimize/na-rps: юнит рапортует success при неприменённом RPS — гонка с появлением default route #30

Closed

Description

@jestivald

Симптом

На ноде fra1 (Debian 13, XanMod 6.18.47, NIC ens18) после ребута RPS не применён, хотя юнит зелёный:

# systemctl is-active na-rps.service
active
# cat /sys/class/net/ens18/queues/rx-0/rps_cpus
0

na-diagnose при этом противоречит сам себе — в одной секции:

▲ RPS выключен — на 3 ядрах приём может висеть на cpu0
✔ na-rps.service активен

В журнале юнита нет строки, которую скрипт печатает при успешной работе:

# journalctl -u na-rps.service -b
Starting na-rps.service - node-accelerator RPS/RFS/XPS tuning...
Finished na-rps.service - node-accelerator RPS/RFS/XPS tuning.

Для сравнения, на нодах, где RPS применился (hel1, ams1, waw1), в журнале есть na-rps: NIC=eth0 mask=3 cpus=2.

Причина

scripts/optimize.sh:454-460 — генератор /usr/local/sbin/na-rps-setup:

NIC="${1:-$(ip -o -4 route show default 2>/dev/null | awk '{print $5; exit}')}"
[ -z "$NIC" ] && exit 0

Интерфейс определяется по default route в момент запуска, а при его отсутствии скрипт молча выходит с кодом 0. Юнит (scripts/optimize.sh:479-491) объявлен как

After=network-online.target
Wants=network-online.target
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/local/sbin/na-rps-setup

network-online.target на Debian 13 с dhcpcd достигается раньше, чем в таблице появляется маршрут по умолчанию (та же гонка, что известна с /etc/resolv.conf). В итоге exit 0 + RemainAfterExit=yes = active (exited) навсегда, а тюнинг не выполнен. Молчаливость двойная: сам скрипт не логирует причину выхода, а systemd считает задачу успешной.

Воспроизводится не на каждом ребуте и не на каждом хостере — это гонка. На флоте из 14 нод после одновременного ребута поймана на одной.

Почему это стоит чинить

RPS на single-queue virtio — не косметика: без него весь RX-softirq висит на cpu0, и на 2–3 vCPU это потолок PPS. Отказ при этом полностью бесшумный: юнит зелёный, na-diagnose печатает «активен» рядом с «выключен», и заметить можно только сравнив ноды между собой.

Предложение

Любой из трёх (первый выглядит самым дешёвым):

  1. Передавать NIC аргументом из персиста. optimize уже сохраняет его в optimize.installed (scripts/optimize.sh:861-868: nic=${NIC:-none}), а скрипт уже принимает $1. Достаточно генерировать ExecStart=/usr/local/sbin/na-rps-setup <nic> с фолбэком на автоопределение.
  2. ExecStartPre с ожиданием маршрута (until ip route show default | grep -q .; do sleep 1; done с таймаутом).
  3. Не выходить нулём: [ -z "$NIC" ] && { echo "na-rps: default route not found, giving up" >&2; exit 1; } + Restart=on-failure / RestartSec.

Плюс, независимо от выбора, в diagnose — не печатать «na-rps.service активен» как ✔, если rps_cpus пуст: сейчас две строки в одной секции утверждают противоположное (scripts/diagnose.sh:441-448 считает RPS_ON, и этот же факт уже известен коду).

Окружение

node-accelerator 4.0.0 (по исходникам v4.0.1 код не менялся), Debian 13 trixie, XanMod 6.18.47-x64v3, NIC ens18 (virtio, single-queue), 3 vCPU.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions