HISTORY: период таймаутов 32.9с (18 интервалов 32.7-33.0с) — таймер доказан; полная проверка скриптов и кредов OK; +tcp_mtu_probe.py
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env python3
|
||||
"""tcp_mtu_probe.py — бинарный поиск MTU-порога по TCP к шлюзу Nubes.
|
||||
|
||||
Критерий: время до ответа nginx. Тело дошло → мгновенный ответ (<2с).
|
||||
Сегмент дропнут (MTU/PMTUD) → ответ не приходит (nginx ждёт тело) → считаем
|
||||
"не прошло" по таймауту FAST_TIMEOUT. Порог ищем делением пополам между
|
||||
LO и HI, потом уточняем повторными пробами вокруг порога.
|
||||
"""
|
||||
import socket
|
||||
import ssl
|
||||
import time
|
||||
|
||||
HOST = "185.247.187.151"
|
||||
PORT = 443 # реальный путь клиентов; 32391 (NodePort) снаружи закрыт
|
||||
LO = 512 # заведомо проходит
|
||||
HI = 20000 # заведомо не проходит (14+ сегментов по MSS)
|
||||
FAST_TIMEOUT = 20 # быстрее полного зависания ~51с
|
||||
FAST_OK = 2.0 # ответ быстрее этого = прошло
|
||||
|
||||
ctx = ssl.create_default_context()
|
||||
ctx.check_hostname = False
|
||||
ctx.verify_mode = ssl.CERT_NONE
|
||||
|
||||
|
||||
def probe(n):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.settimeout(FAST_TIMEOUT)
|
||||
t0 = time.time()
|
||||
try:
|
||||
s.connect((HOST, PORT))
|
||||
mss = s.getsockopt(socket.IPPROTO_TCP, socket.TCP_MAXSEG)
|
||||
ss = ctx.wrap_socket(s, server_hostname="sqs.containerk8s.dev.nubes.ru")
|
||||
body = b"x" * n
|
||||
req = (b"POST / HTTP/1.1\r\n"
|
||||
b"Host: sqs.containerk8s.dev.nubes.ru\r\n"
|
||||
b"Content-Type: application/x-www-form-urlencoded\r\n"
|
||||
b"Content-Length: " + str(n).encode() + b"\r\n"
|
||||
b"Connection: close\r\n\r\n" + body)
|
||||
ss.sendall(req)
|
||||
data = ss.recv(4096)
|
||||
dt = time.time() - t0
|
||||
first = data.split(b"\r\n")[0][:40].decode("latin1", "replace")
|
||||
return dt, mss, first
|
||||
except Exception as e:
|
||||
return time.time() - t0, None, "%s" % type(e).__name__
|
||||
finally:
|
||||
try:
|
||||
s.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def passed(n):
|
||||
dt, mss, resp = probe(n)
|
||||
ok = dt < FAST_OK
|
||||
print(" size=%6d: %.2fs mss=%s %s -> %s" %
|
||||
(n, dt, mss if mss else "-", resp, "OK" if ok else "DROP"), flush=True)
|
||||
return ok
|
||||
|
||||
|
||||
def main():
|
||||
# санпроверка границ
|
||||
print("check LO=%d:" % LO)
|
||||
if not passed(LO):
|
||||
print("LO не проходит — границы неверны, выход")
|
||||
return
|
||||
print("check HI=%d:" % HI)
|
||||
if passed(HI):
|
||||
print("HI тоже проходит мгновенно — порога нет в диапазоне, выход")
|
||||
return
|
||||
|
||||
lo, hi = LO, HI
|
||||
while hi - lo > 50:
|
||||
mid = (lo + hi) // 2
|
||||
if passed(mid):
|
||||
lo = mid
|
||||
else:
|
||||
hi = mid
|
||||
print("\nпорог найден: lo=%d hi=%d (проходит <=lo, дроп >=hi)" % (lo, hi))
|
||||
|
||||
# уточнение вокруг порога: 3 пробы на каждую из 4 точек рядом
|
||||
print("\nуточнение (по 3 пробы):")
|
||||
for n in (lo - 200, lo, (lo + hi) // 2, hi + 200):
|
||||
res = sum(1 for _ in range(3) if passed(max(n, 1)))
|
||||
print(" size=%d: %d/3 прошли" % (n, res))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user