ЗАМЕР
bench/load-balancing/ecs.py
Скрипт, которым получены числа в статье, и запись прогона. Файл читается на сборке из репозитория — это тот самый код, который запускали, а не его копия.
- Цитируется в статье
- /ru/system-design/traffic/load-balancing
- Как запустить
python3 bins.py python3 sim2.py python3 sim3.py python3 herd.py python3 herd2.py pip install dnspython && python3 dns2.py && python3 ecs.py
Запись прогона
Замеры для статьи «Балансировка нагрузки»
Два разных вида доказательств, и путать их нельзя.
Живые замеры DNS
dns2.py — ротация ответов: двадцать запросов подряд к трём доменам, печатает
число адресов в ответе, диапазон TTL и распределение того, какой адрес оказался
первым.
ecs.py — geoDNS через EDNS Client Subnet (RFC 7871): один и тот же вопрос
задаётся с подстановкой четырёх клиентских подсетей, печатает адреса и
SCOPE PREFIX-LENGTH из ответа.
Требует dnspython и сетевого доступа. Адреса у вас будут другие — они
зависят от того, откуда вы спрашиваете и через какой резолвер. Воспроизводится
не адрес, а scope: ноль означает «ответ годится всем», ненулевой — «ответ
зависит от подсети». Именно на этом различии построен раздел про geoDNS.
Модель очередей
bins.py — чистая задача о шарах и корзинах: n шаров в n корзин, случайный
выбор против выбора менее полной из двух. Пятнадцать прогонов на каждое n,
рядом печатаются асимптотические оценки ln n / ln ln n и ln ln n / ln 2.
sim2.py — основная модель: шестнадцать бэкендов, каждый — одна очередь FIFO с
одним обслуживающим прибором (G/G/1). Пуассоновский поток, логнормальное время
обработки. Сравниваются random, round-robin, least-conn, least-time, p2c на
одинаковых серверах, на кластере с медленным сервером и при загрузке 95%.
sim3.py — взвешенный round-robin с угаданным, отсутствующим и заниженным
весом, и отдельно цена закреплённых сессий при 5000, 500 и 50 живых сессиях.
herd.py — несколько независимых балансировщиков, у каждого свои счётчики.
herd2.py — те же балансировщики, но с общим снимком состояния,
устаревающим на refresh. Эти два скрипта дают главный результат статьи и
отвечают на разные вопросы: первый показывает, что неполнота данных не ломает
least connections, второй — что общая устаревшая ошибка ломает.
Модель отвечает на один вопрос — как распределение запросов влияет на ожидание в очередях. В ней нет сети и её задержек, разрывов соединений, проверок живости, кеша на бэкенде и ограничений по памяти. Числа воспроизводятся точно: зёрна фиксированы, первые 20 000 запросов из 300 000 отбрасываются, результат усредняется по пяти прогонам.
python3 bins.py
python3 sim2.py
python3 sim3.py
python3 herd.py
python3 herd2.py
pip install dnspython && python3 dns2.py && python3 ecs.py
Скрипт
25 строкimport dns.message, dns.query, dns.edns, dns.rdatatype
SUBNETS = [("США, Нью-Йорк", "68.192.0.0", 24), ("Германия, Франкфурт", "91.65.0.0", 24),
("Япония, Токио", "133.11.0.0", 24), ("Бразилия, Сан-Паулу", "177.54.0.0", 24)]
def ask(name, ip, prefix, server="8.8.8.8"):
q = dns.message.make_query(name, "A", use_edns=0, payload=1232,
options=[dns.edns.ECSOption(ip, prefix)])
resp = dns.query.udp(q, server, timeout=6)
ips = sorted(r.address for rr in resp.answer if rr.rdtype == dns.rdatatype.A for r in rr)
scope = None
for o in (resp.options or []):
if isinstance(o, dns.edns.ECSOption):
scope = o.scopelen
return ips, scope
for name in ["www.bing.com", "www.microsoft.com", "d1.awsstatic.com", "www.netflix.com"]:
print(f"--- {name}")
for label, ip, plen in SUBNETS:
try:
ips, scope = ask(name, ip, plen)
print(f" {label:22s} scope=/{scope} {ips[:3]}")
except Exception as e:
print(f" {label:22s} {type(e).__name__}: {e}")