Устранение сбоев проверки работоспособности в Azure Load Balancer

Сводка

В этой статье приведены пошаговые инструкции по диагностике и устранению сбоев проб работоспособности в Azure Load Balancer.

Сбои проверок работоспособности в Azure Load Balancer приводят к тому, что внутренние серверы помечаются как неработоспособные и исключаются из балансировки, что приводит к потере сетевого подключения или ухудшению работы службы. Наиболее распространенными первопричинами являются:

  • Серверная часть не прослушивает порт пробы.
  • Правила группы безопасности сети (NSG) блокируют исходный IP-адрес пробы (168.63.129.16).
  • Неактивные сетевые адаптеры (NIC) находятся во внутреннем пуле.
  • Несоответствие порта или пути пробы.
  • Тайм-аут серверного приложения, превышающий порог срабатывания проверки.

Симптомы

Вы можете столкнуться с одним или несколькими из следующих симптомов:

  • На портале Azure отображаются экземпляры серверного пула с состоянием работоспособности «Недоступно» или «С ухудшением».
  • Метрики балансировщика нагрузки показывают, что Health Probe Status равно 0 % для одного или нескольких внутренних экземпляров.
  • Клиенты сталкиваются с тайм-аутами подключения или ошибками connection refused при доступе к конечной точке с балансировкой нагрузки.
  • Трафик направляется только на часть экземпляров серверной части (неравномерное распределение).
  • Предупреждение: All backend instances for load balancer are probed down.

Prerequisites

Чтобы устранить неполадки пробы работоспособности, вам потребуется следующее:

  • Требуемые разрешения:Network Contributor роль в группе ресурсов балансировщика нагрузки, а также Virtual Machine Contributor разрешения, если необходимо выполнять команды на серверных виртуальных машинах (ВМ).
  • Средства: Azure CLI 2.x или агент ИИ с доступом Azure MCP или CLI.
  • Обязательные переменные и примеры этих переменных, как показано в следующей таблице
Variable Description Пример
$SUBSCRIPTION Идентификатор подписки Azure xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$RG Группа ресурсов, содержащая Load Balancer myResourceGroup
$LB_NAME Имя ресурса балансировщика нагрузки myLoadBalancer

СОВЕТ: Каждый скрипт, предоставленный в следующих разделах, запрашивает необходимые значения в интерактивном режиме. Чтобы открыть Cloud Shell и ответить на запросы, нажмите кнопку "Попробовать". Значения кэшируются для этого сеанса. Поэтому вы вводите их только один раз.

Note

Эти действия предназначены исключительно для ознакомления ("только для чтения"). Они не вносят изменения в среду.

Шаг 1

Проверьте общее состояние проверки работоспособности для каждого внутреннего экземпляра в пуле и определите, какие именно внутренние серверы не проходят проверку работоспособности.

Выполните следующие команды в Azure CLI:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME

az network lb show \
  --name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --query "{name:name, sku:sku.name, probes:probes[].{name:name, protocol:protocol, port:port, intervalInSeconds:intervalInSeconds, numberOfProbes:numberOfProbes, requestPath:requestPath}, backendPools:backendAddressPools[].{name:name, backendCount:length(backendAddresses || loadBalancerBackendAddresses || backendIPConfigurations || \`[]\`)}}" \
  --output json

Интерпретация результатов

Если вы видите... Meaning Дальнейшие действия
probes массив пуст. Проба работоспособности не настроена. Load Balancer использует пробу по умолчанию для порта правила. Выполните шаг 2 и проверьте выравнивание портов пробы.
backendCount равно 0 для пула. Во внутреннем пуле не настроены участники. Выполните вариант C и устраните проблему со скрытыми сетевыми адаптерами или пустым пулом.
Зонд protocolHttp или Https с помощью requestPath. Настраивается настраиваемая проба HTTP или HTTPS. Выполните шаг 2 и проверьте сведения о конфигурации пробы.
Зонд protocolTcp без requestPath. Проба TCP проверяет доступность порта только. Выполните шаг 2.
ResourceNotFound Ошибка. Неверно указано имя подписки, группы ресурсов или балансировщика нагрузки. Проверьте переменные и повторно запустите.

Шаг 2

Проверьте, соответствует ли конфигурация пробы (порт, протокол и путь), что на самом деле обслуживает серверное приложение.

Выполните следующие команды в Azure CLI:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME

az network lb probe list \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --output json

Интерпретация результатов

Запишите следующие значения из выходных данных:

  • Порт проверки: порт, который проба проверяет на каждом сервере.
  • Протокол: Tcp, Httpили Https.
  • Путь. Для проб HTTP или HTTPS проверяется путь универсального идентификатора ресурса (URI) (например, /health).
  • Интервал и количество проверок: как часто выполняются проверки и сколько сбоев должно произойти, прежде чем объект будет помечен как недоступный.
Если вы видите... Meaning Дальнейшие действия
Порт пробы не соответствует порту, который прослушивает ваше приложение. Несоответствие портов. Проба проверяет неправильный порт. Выполните Resolution D.
Протокол проверки — Http или Https, и requestPath возвращает ответ, отличный от 200. Несоответствие пути. Путь проверки выдаёт ошибку. Выполните Resolution D.
intervalInSeconds значение меньше или равно пяти и numberOfProbes меньше или равно одному (или probeThreshold меньше или равно одному). Агрессивные интервалы проверки. Один медленный ответ может в течение одного интервала отметить бэкенд как недоступный. Запишите эти значения. Шаг 5 сравнивает наблюдаемую задержку с ними. Выполните шаг 3 и продолжайте, но перенесите далее PROBE_INTERVAL и PROBE_PROTOCOL или PROBE_PATH.
Порт датчика и путь указаны правильно, а значение intervalInSeconds больше пяти или значение numberOfProbes больше единицы. Конфигурация согласована, и тайминги не слишком агрессивные. Выполните Шаг 3 и проверьте элементы серверного пула.

Note

Запишите intervalInSeconds, numberOfProbes (или probeThreshold), protocol, port и requestPath из этого шага. Шаг 5 предлагает ввести intervalInSeconds для параметра PROBE_INTERVAL и использует это значение как пороговое, отличающее медленный бэкенд от нормально работающего.

Шаг 3

Проверьте, содержит ли backend-пул корректные ссылки на сетевые интерфейсы (NIC), а также находятся ли эти сетевые интерфейсы в исправном состоянии подготовки.

Выполните следующие команды в Azure CLI:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME
[ -z "$BACKEND_POOL_NAME" ] && read -rp "Backend Pool Name: " BACKEND_POOL_NAME

az network lb address-pool show \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --name "$BACKEND_POOL_NAME" \
  --output json

Интерпретация результатов

Проверьте массив backendIPConfigurations или loadBalancerBackendAddresses. Каждая запись представляет серверный элемент.

Если вы видите... Meaning Дальнейшие действия
backendIPConfigurations содержит идентификаторы NIC, ссылающиеся на удаленные или деаллоцированные виртуальные машины. Фантомные сетевые карты. Сетевой адаптер удален из виртуальной машины, но по-прежнему находится в пуле. Выполните операцию C.
Все записи имеют корректные ссылки на NIC. Принадлежность к пулу корректна. Выполните шаг 4 и проверьте правила NSG.
loadBalancerBackendAddresses отображает IP-адреса без ссылки на виртуальную сеть. Элемент пула на основе IP-адреса с отсутствующей связью с виртуальной сетью (VNet). Выполните операцию C.

Затем проверьте состояние питания виртуальной машины для каждой сетевой карты в пуле:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NIC_NAME" ] && read -rp "NIC Name to check (from above output): " NIC_NAME
[ -z "$NIC_RG" ] && read -rp "NIC Resource Group: " NIC_RG

VM_ID=$(az network nic show \
  --name "$NIC_NAME" \
  --resource-group "$NIC_RG" \
  --subscription "$SUBSCRIPTION" \
  --query "virtualMachine.id" \
  --output tsv 2>/dev/null)

if [ -z "$VM_ID" ]; then
  echo "NO_VM: NIC has no associated VM (ghosted NIC)"
else
  VM_RG=$(echo "$VM_ID" | awk -F'/' '{for(i=1;i<=NF;i++) if ($i=="resourceGroups") print $(i+1)}')
  VM_NAME=$(basename "$VM_ID")
  echo "VM_NAME=$VM_NAME"
  az vm get-instance-view \
    --name "$VM_NAME" \
    --resource-group "$VM_RG" \
    --subscription "$SUBSCRIPTION" \
    --query "{vmName:name, powerState:instanceView.statuses[?starts_with(code,'PowerState/')].displayStatus|[0], agentStatus:instanceView.vmAgent.statuses[0].displayStatus}" \
    --output json
fi
Если вы видите... Meaning Дальнейшие действия
NO_VM Сообщение. Сетевой интерфейс существует, но не связан ни с одной виртуальной машиной («призрачный» сетевой интерфейс). Выполните операцию C.
powerState — это VM deallocated или VM stopped. Виртуальная машина отключена, а серверная часть не может принимать подключения, поэтому все пробы завершаются ошибкой. Запустите виртуальную машину, если она должна быть активной. Если он выведен из эксплуатации, удалите его из пула с помощью резолюции C.
agentStatus не является Ready или имеет значение NULL. Виртуальная машина запускается или находится в состоянии сбоя. Подождите, пока агент будет готов. Если она по-прежнему неработоспособна, проверьте состояние работоспособности виртуальной машины в портале.
powerState имеет значение VM running, И agentStatus имеет значение Ready. Виртуальная машина включена и работоспособна с точки зрения платформы. Запишите VM_NAME, чтобы использовать на шаге 4.

Шаг 4

Проверьте, не блокирует ли какое-либо правило NSG для сетевого интерфейса или подсети серверной виртуальной машины входящий трафик с IP-адреса источника проверки работоспособности Azure (168.63.129.16) на порту проверки работоспособности. az network nic list-effective-nsg возвращает все эффективные входящие правила как из NSG на уровне сетевого интерфейса, так и из NSG на уровне подсети за один вызов, что позволяет выявить любое правило Deny, которое блокирует проверочный запрос, прежде чем он достигнет серверной части.

Выполните следующие команды в Azure CLI:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name (from Step 3): " VM_NAME

# Auto-derive NIC name from VM
NIC_ID=$(az vm show \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --query "networkProfile.networkInterfaces[0].id" \
  --output tsv 2>/dev/null)
NIC_NAME=$(basename "$NIC_ID")
NIC_RG=$(echo "$NIC_ID" | awk -F'/' '{for(i=1;i<=NF;i++) if ($i=="resourceGroups") print $(i+1)}')

echo "Listing effective NSG rules for NIC: $NIC_NAME"

az network nic list-effective-nsg \
  --name "$NIC_NAME" \
  --resource-group "$NIC_RG" \
  --subscription "$SUBSCRIPTION" \
  --query "value[].effectiveSecurityRules[?direction=='Inbound'].{priority:priority, access:access, name:name, sourceAddressPrefix:sourceAddressPrefix, destinationPortRange:destinationPortRange}" \
  --output json

Интерпретация результатов

Сканируйте каждое правило в обоих массивах выходных данных JSON (правила уровня сетевого адаптера и правила уровня подсети). Оцените следующую таблицу по номеру приоритета (меньшее число означает более высокий приоритет).

Если вы видите... Meaning Дальнейшие действия
Любое правило с "access": "Deny", у которого sourceAddressPrefix имеет значение 168.63.129.16, 168.63.129.16/32, AzureLoadBalancer или *, и у которого destinationPortRange охватывает порт проверки, с меньшим значением priority, чем у любого правила Allow для того же источника и порта Правило NSG Deny блокирует пробу работоспособности и name поле определяет точное правило. Выполните разрешение B.
Правила Deny, охватывающие порт зонда из 168.63.129.16 или AzureLoadBalancer, не отображаются с более низким приоритетом, чем соответствующие правила Allow. NSG разрешает поток пробы работоспособности. Выполните шаг 5 и проверьте серверное приложение.
ResourceNotFound Ошибка. Неправильное имя виртуальной машины или сетевого адаптера. Проверьте значения из шага 3 и повторно выполните команду.

Шаг 5

Проверьте, прослушивает ли серверное приложение порт пробы и отвечает ли оно в течение интервала пробы. Замеры времени отклика — это показатель, позволяющий отличить медленное приложение (Resolution E) от исправного бэкенда с блокировкой на уровне сети (Step 4) и от HTTP-пути, который возвращает ошибки (Resolution D). Без этой информации выбор между этими решениями нельзя сделать только из выходных данных терминала.

Note

Введите следующее из шага 2: PROBE_INTERVAL (то intervalInSeconds, которое вы записали), PROBE_PROTOCOL (Tcp, Http или Https) и PROBE_PATH (оставьте пустым для TCP-проб). Таблица интерпретации сравнивает наблюдаемую задержку с PROBE_INTERVAL.

Выполните следующие команды в Azure CLI:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$PROBE_PORT" ] && read -rp "Probe Port (from Step 2): " PROBE_PORT
[ -z "$PROBE_INTERVAL" ] && read -rp "Probe intervalInSeconds (from Step 2): " PROBE_INTERVAL
[ -z "$PROBE_PROTOCOL" ] && read -rp "Probe Protocol from Step 2 (Tcp/Http/Https): " PROBE_PROTOCOL
[ -z "$PROBE_PATH" ] && read -rp "Probe Path from Step 2 (blank for TCP): " PROBE_PATH

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunShellScript \
  --scripts "
set +e
echo '=== Listening ports (all TCP sockets) ==='
ss -tlnp 2>/dev/null || netstat -tlnp 2>/dev/null || echo 'ss/netstat not available'
echo ''
if ss -tlnp 2>/dev/null | grep -qE ':$PROBE_PORT[[:space:]]'; then
  echo 'LISTEN_ON_PROBE_PORT=yes'
else
  echo 'LISTEN_ON_PROBE_PORT=no'
fi
echo ''
echo '=== Service status (top 20 running) ==='
systemctl list-units --type=service --state=running --no-pager 2>/dev/null | head -20 || echo 'systemctl not available'
echo ''
echo \"=== TCP connect-time samples (10 attempts, probe interval = ${PROBE_INTERVAL}s) ===\"
for i in 1 2 3 4 5 6 7 8 9 10; do
  T=\$(curl -s -o /dev/null -w '%{time_connect}' --connect-timeout $PROBE_INTERVAL telnet://127.0.0.1:$PROBE_PORT 2>/dev/null)
  RC=\$?
  if [ \$RC -ne 0 ] || [ -z \"\$T\" ]; then
    echo \"Sample \$i: TIMEOUT (>${PROBE_INTERVAL}s, exit=\$RC)\"
  else
    echo \"Sample \$i: connect=\${T}s\"
  fi
done
PROTO_LOWER=\$(echo '$PROBE_PROTOCOL' | tr '[:upper:]' '[:lower:]')
if [ \"\$PROTO_LOWER\" = 'http' ] || [ \"\$PROTO_LOWER\" = 'https' ]; then
  echo ''
  echo \"=== HTTP probe-path response samples (10 attempts, probe interval = ${PROBE_INTERVAL}s) ===\"
  MAX_T=\$(( PROBE_INTERVAL * 2 ))
  for i in 1 2 3 4 5 6 7 8 9 10; do
    OUT=\$(curl -sk -o /dev/null -w 'HTTP %{http_code} total=%{time_total}s' --connect-timeout $PROBE_INTERVAL --max-time \$MAX_T \"\${PROTO_LOWER}://127.0.0.1:$PROBE_PORT$PROBE_PATH\" 2>/dev/null)
    RC=\$?
    if [ \$RC -ne 0 ] || [ -z \"\$OUT\" ]; then
      echo \"Sample \$i: FAILED (timeout or connection error, exit=\$RC)\"
    else
      echo \"Sample \$i: \$OUT\"
    fi
  done
fi
"

Для Windows виртуальных машин используйте:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$PROBE_PORT" ] && read -rp "Probe Port (from Step 2): " PROBE_PORT
[ -z "$PROBE_INTERVAL" ] && read -rp "Probe intervalInSeconds (from Step 2): " PROBE_INTERVAL
[ -z "$PROBE_PROTOCOL" ] && read -rp "Probe Protocol from Step 2 (Tcp/Http/Https): " PROBE_PROTOCOL
[ -z "$PROBE_PATH" ] && read -rp "Probe Path from Step 2 (blank for TCP): " PROBE_PATH

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunPowerShellScript \
  --scripts "
Write-Output '=== Listening ports (all TCP sockets) ==='
Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | Sort-Object LocalPort | Format-Table -AutoSize LocalAddress, LocalPort, OwningProcess
if (Get-NetTCPConnection -LocalPort $PROBE_PORT -State Listen -ErrorAction SilentlyContinue) {
  Write-Output 'LISTEN_ON_PROBE_PORT=yes'
} else {
  Write-Output 'LISTEN_ON_PROBE_PORT=no'
}
Write-Output \"=== TCP connect-time samples (10 attempts, probe interval = ${PROBE_INTERVAL}s) ===\"
for (\$i = 1; \$i -le 10; \$i++) {
  \$sw = [System.Diagnostics.Stopwatch]::StartNew()
  try {
    \$c = New-Object System.Net.Sockets.TcpClient
    \$task = \$c.ConnectAsync('127.0.0.1', $PROBE_PORT)
    if (\$task.Wait([TimeSpan]::FromSeconds($PROBE_INTERVAL))) {
      \$sw.Stop()
      Write-Output (\"Sample {0}: connect={1:N3}s\" -f \$i, (\$sw.Elapsed.TotalSeconds))
    } else {
      Write-Output (\"Sample {0}: TIMEOUT (>${PROBE_INTERVAL}s)\" -f \$i)
    }
    \$c.Close()
  } catch {
    Write-Output (\"Sample {0}: FAILED ({1})\" -f \$i, \$_.Exception.Message)
  }
}
\$proto = '$PROBE_PROTOCOL'.ToLower()
if (\$proto -eq 'http' -or \$proto -eq 'https') {
  Write-Output \"=== HTTP probe-path response samples (10 attempts, probe interval = ${PROBE_INTERVAL}s) ===\"
  \$url = \"\${proto}://127.0.0.1:$PROBE_PORT$PROBE_PATH\"
  for (\$i = 1; \$i -le 10; \$i++) {
    try {
      \$sw = [System.Diagnostics.Stopwatch]::StartNew()
      \$r = Invoke-WebRequest -Uri \$url -UseBasicParsing -TimeoutSec ($PROBE_INTERVAL * 2) -SkipCertificateCheck -ErrorAction Stop
      \$sw.Stop()
      Write-Output (\"Sample {0}: HTTP {1} total={2:N3}s\" -f \$i, \$r.StatusCode, (\$sw.Elapsed.TotalSeconds))
    } catch {
      Write-Output (\"Sample {0}: FAILED ({1})\" -f \$i, \$_.Exception.Message)
    }
  }
}
"

Интерпретация результатов

Оцените следующую таблицу по порядку. Первая соответствующая строка имеет приоритет.

Если вы видите... Meaning Дальнейшие действия
LISTEN_ON_PROBE_PORT=no и выходные данные прослушивающих портов показывают процесс, привязанный к другому TCP-порту (например, порт 80, 443, 5000, 8000 или любой другой несистемный порт приложения). Приложение прослушивает порт, отличный от пробы. Несоответствие порта датчика. Выполните Resolution D.
LISTEN_ON_PROBE_PORT=no и не присутствует никакая другая TCP-служба, работающая как приложение (только системные службы, такие как sshd на порту 22, systemd-resolved на 127.0.0.53:53, сопоставитель конечных точек Remote Procedure Call (RPC) на порту 135, протокол удаленного рабочего стола (RDP) на порту 3389). Приложение не запущено или не привязано ни к одному порту. Выполните вариант A.
Любой образец времени установления TCP-соединения показывает TIMEOUT, или любой образец HTTP показывает FAILED. Серверная часть не может завершить пробу в течение одного интервала. Есть медленное или насыщенное приложение или ядро. Выполните операцию Resolution E.
Любой пример HTTP содержит код состояния, отличный от 200299 (например, HTTP 404 total=... или HTTP 500 total=...). Путь проверки возвращает сообщение об ошибке. Путь или конечная точка проверки работоспособности приложения указаны неправильно. Выполните Resolution D.
Любой пример HTTP показывает total=Xs , где X больше или равно 50 процентов PROBE_INTERVAL, или любой пример TCP показывает connect=Xs , где X больше или равно 50 процентов PROBE_INTERVAL. Наблюдаемое время отклика составляет не более половины интервала пробы. Зонд подвержен непосредственному риску тайм-аута. Выполните операцию Resolution E.
Все образцы выполняются успешно, и все наблюдаемые значения времени меньше PROBE_INTERVAL, а на этапе Step 2 зафиксировано, что intervalInSeconds меньше или равно пяти, и numberOfProbes меньше или равно одному. Серверная часть сейчас работает быстро, но интервалы проверки слишком короткие. Нормальное отклонение достаточно, чтобы вызвать вспышку. Выполните операцию Resolution E.
Все выборки выполняются успешно, и все наблюдаемые значения времени составляют менее 50 % от PROBE_INTERVAL, а интервал проверки не задан слишком агрессивно (например, intervalInSeconds больше пяти или numberOfProbes больше единицы). Бэкенд работоспособен изнутри виртуальной машины, и запас для проверки достаточен. Проблема заключается в сетевом уровне между Load Balancer и виртуальной машиной. Выполните шаг 4 и повторно запустите list-effective-nsg.

Карта принятия решений

Используйте следующую таблицу карты принятия решений, чтобы определить соответствующие действия на основе результатов диагностики.

Результат диагностики Дальнейшие действия
Серверный пул пуст или не содержит ни одного участника. Выполните операцию C.
Порт пробы не соответствует порту прослушивания приложения. Выполните Resolution Dh.
Путь проверки HTTP или HTTPS возвращает код состояния, отличный от 200 (наблюдаемый в образцах на шаге 5). Выполните Resolution D.
Правило NSG Deny блокирует 168.63.129.16 или AzureLoadBalancer порт пробы. Выполните разрешение B.
Приложение не прослушивает порт пробы (служба остановлена или сбой). Выполните вариант A.
NIC в пуле ссылается на удалённую или освобождённую виртуальную машину. Выполните операцию C.
Образцы на шаге 5 показывают любой TCP TIMEOUT, любой HTTP FAILED, или время выборки, большее или равное intervalInSeconds. Выполните операцию Resolution E.
Все образцы шага 5 выполняются успешно и быстро, но конфигурация проб является агрессивной (intervalInSeconds меньше или равно пяти и numberOfProbes меньше или равно одному). Выполните операцию Resolution E.

Разрешение A

Серверное приложение не прослушивает порт, который проверяет проба работоспособности. Служба может аварийно завершить работу, остановиться или не запуститься после перезагрузки.

Распространенные причины:

  • Служба приложения аварийно завершила работу или остановлена.
  • Приложение привязывается к localhost (127.0.0.1) вместо всех интерфейсов (0.0.0.0.
  • Сбой зависимости запуска приложения (база данных, сертификат или конфигурация).
  • Перезапуск виртуальной машины и служба приложений не настроена для автоматического запуска.

Выполните следующие команды в Azure CLI.

  1. Проверьте состояние службы приложений на серверной виртуальной машине:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$PROBE_PORT" ] && read -rp "Probe Port: " PROBE_PORT

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunShellScript \
  --scripts "echo '=== Processes on port $PROBE_PORT ==='; ss -tlnp | grep ':$PROBE_PORT'; echo ''; echo '=== All listening ports ==='; ss -tlnp | grep LISTEN; echo ''; echo '=== Failed services ==='; systemctl --failed 2>/dev/null || echo 'systemctl not available'"

Запишите, какая служба должна прослушивать порт пробы. Если ни один процесс не прослушивает порт, определите ожидаемое имя службы.

  1. Запустите или перезапустите службу приложений.

Important

Следующие команды — это все операции записи, требующие утверждения, прежде чем их можно будет запустить.

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$SERVICE_NAME" ] && read -rp "Service name to restart (e.g., nginx, httpd, webapp): " SERVICE_NAME

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunShellScript \
  --scripts "systemctl start $SERVICE_NAME && systemctl enable $SERVICE_NAME && echo 'Service started and enabled' || echo 'FAILED to start service - check logs with: journalctl -u $SERVICE_NAME --no-pager -n 50'"

Для виртуальных машин Windows:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$SERVICE_NAME" ] && read -rp "Windows Service name (e.g., W3SVC, nginx): " SERVICE_NAME

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunPowerShellScript \
  --scripts "Start-Service '$SERVICE_NAME' -ErrorAction Stop; Set-Service '$SERVICE_NAME' -StartupType Automatic; Write-Output 'Service started and set to Automatic'"
  1. Проверьте исправление, убедившись, что порт пробы прослушивается:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$PROBE_PORT" ] && read -rp "Probe Port: " PROBE_PORT

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunShellScript \
  --scripts "timeout 5 bash -c \"echo > /dev/tcp/127.0.0.1/$PROBE_PORT\" 2>&1 && echo 'SUCCESS: Port $PROBE_PORT is now listening' || echo 'FAIL: Port $PROBE_PORT still not listening'"

Проба работоспособности восстанавливается в течение одного интервала пробы (обычно 5–15 секунд). Повторно выполните Шаг 1, чтобы убедиться, что бэкенд отображается как healthy в метриках балансировщика нагрузки.

Если служба завершает работу, изучите журналы приложений на виртуальной машине и устраните проблемы с базовым приложением, прежде чем продолжить.

Разрешение B

Правило NSG в серверной подсети или на сетевом интерфейсе (NIC) блокирует входящий трафик проверки работоспособности с IP-адреса источника проверки Azure (168.63.129.16) на порту проверки.

Load Balancer пробы работоспособности исходят из IP-адреса 168.63.129.16 независимо от заданного диапазона источников. Серверная часть должна разрешить входящий IP-адрес через порт пробы.

Выполните следующие команды в Azure CLI.

  1. Определите блокирующее правило NSG:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NSG_NAME" ] && read -rp "NSG Name: " NSG_NAME
[ -z "$NSG_RG" ] && read -rp "NSG Resource Group: " NSG_RG
[ -z "$PROBE_PORT" ] && read -rp "Probe Port: " PROBE_PORT

az network nsg rule list \
  --nsg-name "$NSG_NAME" \
  --resource-group "$NSG_RG" \
  --subscription "$SUBSCRIPTION" \
  --query "[?direction=='Inbound' && access=='Deny'].{name:name, priority:priority, sourceAddress:sourceAddressPrefix, destPort:destinationPortRange, protocol:protocol}" \
  --output table

Найдите правила Deny с приоритетом ниже, чем у любого правила Allow для 168.63.129.16 или AzureLoadBalancer на порту зонда.

  1. Добавьте правило Allow для IP-адреса источника проверки работоспособности с приоритетом ниже (то есть с более высоким приоритетом обработки), чем правило Deny блокировки.

Important

Следующие команды — это все операции записи, требующие утверждения, прежде чем их можно будет запустить.

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NSG_NAME" ] && read -rp "NSG Name: " NSG_NAME
[ -z "$NSG_RG" ] && read -rp "NSG Resource Group: " NSG_RG
[ -z "$PROBE_PORT" ] && read -rp "Probe Port: " PROBE_PORT
[ -z "$RULE_PRIORITY" ] && read -rp "Rule Priority (must be lower number than blocking Deny rule): " RULE_PRIORITY

az network nsg rule create \
  --nsg-name "$NSG_NAME" \
  --resource-group "$NSG_RG" \
  --subscription "$SUBSCRIPTION" \
  --name Allow-AzureLB-HealthProbe \
  --priority "$RULE_PRIORITY" \
  --direction Inbound \
  --source-address-prefixes 168.63.129.16 \
  --destination-port-ranges "$PROBE_PORT" \
  --protocol Tcp \
  --access Allow

Note

Приоритеты правил NSG должны быть в диапазоне от 100 до 4096. Если правило блокировки Deny уже имеет приоритет 100 (минимальное значение), нельзя добавить правило с более Allow высоким приоритетом. В этом случае удалите Deny правило вместо этого с помощью az network nsg rule delete --nsg-name "$NSG_NAME" --resource-group "$NSG_RG" --name <deny-rule-name>.

  1. Убедитесь, что NSG теперь разрешает трафик проверок работоспособности:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NSG_NAME" ] && read -rp "NSG Name: " NSG_NAME
[ -z "$NSG_RG" ] && read -rp "NSG Resource Group: " NSG_RG

az network nsg rule list \
  --nsg-name "$NSG_NAME" \
  --resource-group "$NSG_RG" \
  --subscription "$SUBSCRIPTION" \
  --query "sort_by([?direction=='Inbound'], &priority)[].{name:name, priority:priority, access:access, sourceAddress:sourceAddressPrefix, destPort:destinationPortRange}" \
  --output table

Убедитесь, что Allow правило 168.63.129.16 отображается с меньшим числом приоритета, чем любое Deny правило, охватывающее тот же порт. Зонд должен восстановиться в течение одного интервала. Чтобы подтвердить, выполните повторное выполнение шага 1 .

Резолюция C

Серверный пул содержит ссылки на сетевые адаптеры, которые больше не подключены к запущенным виртуальным машинам (фантомные сетевые адаптеры), или пул пуст, так как вы удалили элементы без замены.

Распространенные причины:

  • Вы удалили виртуальную машину, но не удалили ее сетевой адаптер из внутреннего пула.
  • Вы освободили ресурсы виртуальной машины и отсоединили её сетевой адаптер.
  • Вы масштабировались в масштабируемом наборе, но не очищали ссылки на пул.
  • Адреса бэкенда на основе IP содержат устаревшие записи.

Выполните следующие команды в Azure CLI.

  1. Выведите список текущих участников серверного пула и их состояние подготовки:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME
[ -z "$BACKEND_POOL_NAME" ] && read -rp "Backend Pool Name: " BACKEND_POOL_NAME

az network lb address-pool show \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --name "$BACKEND_POOL_NAME" \
  --query "{name:name, backendIPConfigurations:backendIPConfigurations[].id, loadBalancerBackendAddresses:loadBalancerBackendAddresses[].{name:name, ip:ipAddress, subnet:subnet.id, nicId:networkInterfaceIPConfiguration.id}}" \
  --output json

Для каждого перечисленного идентификатора сетевого адаптера проверьте, что он по-прежнему существует:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NIC_NAME" ] && read -rp "NIC Name to check: " NIC_NAME
[ -z "$NIC_RG" ] && read -rp "NIC Resource Group: " NIC_RG

az network nic show \
  --name "$NIC_NAME" \
  --resource-group "$NIC_RG" \
  --subscription "$SUBSCRIPTION" \
  --query "{name:name, provisioningState:provisioningState, vmId:virtualMachine.id, primary:primary}" \
  --output json

Интерпретация результатов

Если вы видите... Meaning
Параметр vmId имеет значение null. Сетевой адаптер существует, но не подключен ни к одной виртуальной машине (не привязан).
ResourceNotFound Ошибка. Сетевой адаптер был удален, но на него по-прежнему есть ссылка в пуле.
provisioningState не является Succeeded. Сетевой адаптер находится в неисправном состоянии.
  1. Удалите неактивный или недействительный сетевой адаптер из серверного пула. Для пулов на основе NIC отвяжите сетевой интерфейс от балансировщика нагрузки.

Important

Следующие команды — это все операции записи, требующие утверждения, прежде чем их можно будет запустить.

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NIC_NAME" ] && read -rp "Ghosted NIC Name: " NIC_NAME
[ -z "$NIC_RG" ] && read -rp "NIC Resource Group: " NIC_RG
[ -z "$IP_CONFIG_NAME" ] && read -rp "IP Config Name (usually ipconfig1): " IP_CONFIG_NAME

az network nic ip-config address-pool remove \
  --nic-name "$NIC_NAME" \
  --resource-group "$NIC_RG" \
  --subscription "$SUBSCRIPTION" \
  --ip-config-name "$IP_CONFIG_NAME" \
  --lb-name "$LB_NAME" \
  --address-pool "$BACKEND_POOL_NAME"

Для серверных пулов на основе IP-адресов удалите устаревший адрес:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME
[ -z "$BACKEND_POOL_NAME" ] && read -rp "Backend Pool Name: " BACKEND_POOL_NAME
[ -z "$ADDRESS_NAME" ] && read -rp "Backend Address Name (from C.1): " ADDRESS_NAME

az network lb address-pool address remove \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --pool-name "$BACKEND_POOL_NAME" \
  --name "$ADDRESS_NAME"
  1. Убедитесь, что пул теперь содержит только допустимых участников. Повторите шаг 3 и убедитесь, что не осталось фантомных ссылок. Затем повторно выполните Шаг 1, чтобы убедиться, что оставшиеся серверы проходят проверку работоспособности.

Если пул теперь пуст и вам нужно добавить новые внутренние серверы, добавьте исправные виртуальные машины обратно в пул:

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$NIC_NAME" ] && read -rp "NIC Name of healthy VM: " NIC_NAME
[ -z "$NIC_RG" ] && read -rp "NIC Resource Group: " NIC_RG
[ -z "$IP_CONFIG_NAME" ] && read -rp "IP Config Name (usually ipconfig1): " IP_CONFIG_NAME

az network nic ip-config address-pool add \
  --nic-name "$NIC_NAME" \
  --resource-group "$NIC_RG" \
  --subscription "$SUBSCRIPTION" \
  --ip-config-name "$IP_CONFIG_NAME" \
  --lb-name "$LB_NAME" \
  --address-pool "$BACKEND_POOL_NAME"

Разрешение D

Вы настроили пробу работоспособности с помощью порта или пути HTTP, который не соответствует тому, что обслуживает серверное приложение. В результате проба получает отклоненное подключение, время ожидания или ответы, отличные200 от HTTP.

Распространенные причины:

  • Проба проверяет порт 80, но приложение прослушивает порт 8080.
  • Путь HTTP-пробы — /health, а конечная точка проверки работоспособности приложения — /healthz или /api/health.
  • Приложение возвращает ошибки 404 по настроенному пути проверки.
  • Проба HTTPS активна, но серверная часть обслуживает только HTTP (или наоборот).

Выполните следующие команды в Azure CLI.

  1. Подтвердите текущую конфигурацию пробы и фактическое состояние прослушивания приложения:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME

az network lb probe list \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --query "[].{name:name, protocol:protocol, port:port, requestPath:requestPath, intervalInSeconds:intervalInSeconds, numberOfProbes:numberOfProbes}" \
  --output table

Сравните порт проверки и путь с тем, что фактически обслуживает внутреннее приложение (по результатам шага 5).

  1. Обновите пробу, чтобы использовать правильный порт и путь.

Important

Следующие команды — это все операции записи, требующие утверждения, прежде чем их можно будет запустить.

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME
[ -z "$PROBE_NAME" ] && read -rp "Probe Name: " PROBE_NAME
[ -z "$CORRECT_PORT" ] && read -rp "Correct probe port (port app listens on): " CORRECT_PORT
[ -z "$CORRECT_PATH" ] && read -rp "Correct probe path (e.g., / or /health, leave blank for TCP): " CORRECT_PATH

if [ -n "$CORRECT_PATH" ]; then
  az network lb probe update \
    --lb-name "$LB_NAME" \
    --resource-group "$RG" \
    --subscription "$SUBSCRIPTION" \
    --name "$PROBE_NAME" \
    --port "$CORRECT_PORT" \
    --path "$CORRECT_PATH"
else
  az network lb probe update \
    --lb-name "$LB_NAME" \
    --resource-group "$RG" \
    --subscription "$SUBSCRIPTION" \
    --name "$PROBE_NAME" \
    --port "$CORRECT_PORT"
fi
  1. Проверьте исправление. Повторно запустите шаг 2 , чтобы подтвердить конфигурацию пробы, которая теперь соответствует приложению. Затем подождите один интервал проверки и повторите шаг 1, чтобы убедиться, что серверы серверной части переходят в работоспособное состояние.

Разрешение E

Серверное приложение отвечает на проверки работоспособности слишком медленно, из-за чего время ответа превышает порог тайм-аута проверки. После заданного количества последовательных сбоев (numberOfProbes) экземпляр помечается как неработоспособный.

Распространенные причины:

  • Запуск приложения занимает больше времени, чем тайм-аут проверки (холодный запуск).
  • Конечная точка работоспособности приложений зависит от медленной нижестоящей службы.
  • Интервал пробы и пороговое значение слишком агрессивны для времени отклика приложения.
  • Приложение при высокой нагрузке не может отвечать на проверки за отведенное время.

Выполните следующие команды в Azure CLI.

  1. Проверьте текущую конфигурацию времени ожидания пробы и порогового значения.
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME

az network lb probe list \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --query "[].{name:name, protocol:protocol, port:port, intervalInSeconds:intervalInSeconds, numberOfProbes:numberOfProbes, probeThreshold:probeThreshold}" \
  --output table

Для балансировщика нагрузки уровня Standard значение probeThreshold определяет, сколько последовательных успешных проверок работоспособности необходимо, чтобы снова считать экземпляр работоспособным.

Parameter Рекомендуемый минимум для медленных приложений
intervalInSeconds 15–30 секунд.
numberOfProbes 2–4 (количество сбоев перед маркировкой).
probeThreshold 1–2 (чтобы пометить, нужны 1–2 успешные попытки подряд).
  1. Проверьте время отклика серверного приложения:
# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$VM_NAME" ] && read -rp "Backend VM Name: " VM_NAME
[ -z "$PROBE_PORT" ] && read -rp "Probe Port: " PROBE_PORT
[ -z "$PROBE_PATH" ] && read -rp "Probe Path (e.g., / or /health): " PROBE_PATH

az vm run-command invoke \
  --name "$VM_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --command-id RunShellScript \
  --scripts "echo '=== Response time test (3 attempts) ==='; for i in 1 2 3; do echo \"Attempt \$i:\"; time curl -s -o /dev/null -w 'HTTP %{http_code} in %{time_total}s\n' http://127.0.0.1:$PROBE_PORT$PROBE_PATH; sleep 1; done"

Если время отклика превышает текущее время ожидания пробы (по умолчанию примерно пять секунд для TCP, настраиваемого для HTTP), время ожидания пробы истекает.

  1. Увеличьте интервал пробы и пороговое значение, чтобы обеспечить время отклика приложения.

Important

Следующие команды — это все операции записи, требующие утверждения, прежде чем их можно будет запустить.

# ── Collect inputs (cached if already set in this session) ──
[ -z "$SUBSCRIPTION" ] && read -rp "Subscription ID: " SUBSCRIPTION
[ -z "$RG" ] && read -rp "Resource Group:  " RG
[ -z "$LB_NAME" ] && read -rp "Load Balancer Name: " LB_NAME
[ -z "$PROBE_NAME" ] && read -rp "Probe Name: " PROBE_NAME

az network lb probe update \
  --lb-name "$LB_NAME" \
  --resource-group "$RG" \
  --subscription "$SUBSCRIPTION" \
  --name "$PROBE_NAME" \
  --interval 15 \
  --probe-threshold 2

Note

Параметр --probe-threshold определяет количество последовательных успешных и неудачных попыток пробы для изменения состояния работоспособности серверной части. Более старый --threshold (который задаёт numberOfProbes) считается устаревшим и больше не распознаётся Load Balancer. Используйте --probe-threshold исключительно. Настройте --interval и --probe-threshold на основе времени отклика, измеряемого на шаге E.2. Интервал должен быть по крайней мере в два раза меньше времени отклика на худший случай, наблюдаемый.

  1. Проверьте исправление. Подождите 2–3 интервала пробы (30–45 секунд с обновленными параметрами), а затем повторно запустите шаг 1. Бэкенды должны переходить с Down на healthy по мере того, как проверки успешно выполняются в пределах нового интервала ожидания.

Если приложение постоянно занимает более 30 секунд для реагирования на проверки работоспособности, следует изучить базовую проблему производительности приложения отдельно. Настройка пробы — это временная мера, а не устранение проблемы.

References