Files
SQS-service/tests/compare_ymq_vs_shared.py
T

154 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""Сравнение shared-SQS vs Yandex YMQ (очередь newsqs).
Короткий замер: последовательные операции, N send → N receive+delete.
Метрики: p50/p95/max латентности send/receive/delete, число ошибок.
Требуемые переменные окружения:
SHARED_AK, SHARED_SK — креды shared-SQS
YMQ_AK, YMQ_SK — креды Yandex YMQ (SA newsqs)
YMQ_QUEUE_URL — URL очереди Яндекса (newsqs)
Запуск: python3 tests/compare_ymq_vs_shared.py [N]
"""
import os
import sys
import time
import uuid
import boto3
from botocore.config import Config
N = int(sys.argv[1]) if len(sys.argv) > 1 else 50
BODY = "x" * 512
SHARED_EP = "https://sqs.containerk8s.dev.nubes.ru"
YMQ_EP = "https://message-queue.api.cloud.yandex.net"
SHARED_AK = os.environ["SHARED_AK"]
SHARED_SK = os.environ["SHARED_SK"]
YMQ_AK = os.environ["YMQ_AK"]
YMQ_SK = os.environ["YMQ_SK"]
YMQ_QUEUE_URL = os.environ["YMQ_QUEUE_URL"]
CFG = Config(connect_timeout=15, read_timeout=30, retries={"max_attempts": 0})
def mk_client(endpoint, region, ak, sk):
return boto3.client(
"sqs",
endpoint_url=endpoint,
region_name=region,
aws_access_key_id=ak,
aws_secret_access_key=sk,
config=CFG,
)
def stats(name, values):
v = sorted(values)
if not v:
print("%s: n=0" % name)
return
n = len(v)
print("%s: n=%d p50=%.0fms p95=%.0fms max=%.0fms" %
(name, n, v[n // 2] * 1000, v[int(n * .95)] * 1000, v[-1] * 1000))
def bench(client, queue_url, label):
errs = 0
lat_send, lat_recv, lat_del = [], [], []
t_start = time.time()
for i in range(N):
t0 = time.time()
try:
client.send_message(QueueUrl=queue_url, MessageBody=BODY)
lat_send.append(time.time() - t0)
except Exception as e:
errs += 1
if errs <= 3:
print(" send err: %s %s" % (type(e).__name__, str(e)[:80]))
got = 0
tries = 0
while got < N and tries < N * 6:
tries += 1
t0 = time.time()
try:
r = client.receive_message(
QueueUrl=queue_url, MaxNumberOfMessages=1, VisibilityTimeout=30)
lat_recv.append(time.time() - t0)
msgs = r.get("Messages", [])
except Exception as e:
errs += 1
if errs <= 3:
print(" recv err: %s %s" % (type(e).__name__, str(e)[:80]))
continue
for m in msgs:
got += 1
t0 = time.time()
try:
client.delete_message(QueueUrl=queue_url, ReceiptHandle=m["ReceiptHandle"])
lat_del.append(time.time() - t0)
except Exception as e:
errs += 1
if errs <= 3:
print(" del err: %s %s" % (type(e).__name__, str(e)[:80]))
total = time.time() - t_start
print("== %s (N=%d) ==" % (label, N))
stats(" send ", lat_send)
stats(" receive", lat_recv)
stats(" delete ", lat_del)
print(" received=%d/%d errors=%d total=%.1fs" % (got, N, errs, total))
print(" throughput: send=%.1f op/s, recv+del=%.1f op/s" %
(N / total if total else 0, got / total if total else 0))
return errs
def drain(client, queue_url):
while True:
r = client.receive_message(QueueUrl=queue_url, MaxNumberOfMessages=10)
msgs = r.get("Messages", [])
if not msgs:
break
for m in msgs:
try:
client.delete_message(QueueUrl=queue_url, ReceiptHandle=m["ReceiptHandle"])
except Exception:
pass
def main():
shared = mk_client(SHARED_EP, "us-east-1", SHARED_AK, SHARED_SK)
ymq = mk_client(YMQ_EP, "ru-central1", YMQ_AK, YMQ_SK)
# Временная очередь shared-SQS
qname = "cmp-%s" % uuid.uuid4().hex[:8]
shared_url = shared.create_queue(QueueName=qname)["QueueUrl"]
print("shared queue: %s" % shared_url)
# YMQ newsqs: перед тестом чистим
drain(ymq, YMQ_QUEUE_URL)
print("ymq queue: %s (drained)" % YMQ_QUEUE_URL)
print()
e1 = bench(shared, shared_url, "shared-SQS (наш сервис)")
print()
e2 = bench(ymq, YMQ_QUEUE_URL, "Yandex YMQ (newsqs)")
# Очистка
drain(ymq, YMQ_QUEUE_URL)
try:
shared.delete_queue(QueueUrl=shared_url)
print("\ncleanup: shared temp queue deleted, ymq drained")
except Exception as ex:
print("\ncleanup err: %s" % str(ex)[:80])
print("\nRESULT: errors shared=%d ymq=%d" % (e1, e2))
if __name__ == "__main__":
main()