273 lines
12 KiB
Bash
273 lines
12 KiB
Bash
#!/bin/bash
|
||
# compare_sqs.sh — сравнительный бенчмарк Yandex MQ vs shared-sqs
|
||
# Запуск из ЛОКАЛИ для равных условий
|
||
# Created: 2026-04-11
|
||
|
||
set -uo pipefail
|
||
|
||
# ═══ CREDENTIALS ═══
|
||
# Yandex MQ
|
||
Y_AK="YCAJEQDz_Eg_i4C4M7TAen2fd"
|
||
Y_SK="YCMDfD8OKFK51knPyydwQOYts7Q81_3YBhv4sd_j"
|
||
Y_REGION="ru-central1"
|
||
Y_ENDPOINT="https://message-queue.api.cloud.yandex.net"
|
||
Y_QURL="https://message-queue.api.cloud.yandex.net/b1gatc4m3hv1ldldhljp/dj60000000k2jb2o02mt/foropus"
|
||
|
||
# Our SQS
|
||
O_AK="SSAK-ed0b0c64dcc135adad9e11be"
|
||
O_SK="f917c133e4ad74cf37c8e3ba29d74a39f42f117a202bd672436c92fdb6b6f3dc"
|
||
O_REGION="us-east-1"
|
||
O_ENDPOINT="https://qu.kube5s.ru"
|
||
O_QURL="https://qu.kube5s.ru/t-e0ce25e83be94c58/foropus-test"
|
||
|
||
# ═══ ПАРАМЕТРЫ ═══
|
||
SEQ_COUNT=20 # последовательных send/receive
|
||
PAR_WORKERS=10 # параллельных воркеров
|
||
PAR_MSGS=5 # сообщений на воркер (итого 50)
|
||
BURST=30 # burst одновременно
|
||
|
||
TMPDIR_CMP=$(mktemp -d /tmp/sqs_compare_XXXXX)
|
||
trap "rm -rf $TMPDIR_CMP" EXIT
|
||
|
||
# ═══ ХЕЛПЕРЫ ═══
|
||
ysqs() {
|
||
AWS_ACCESS_KEY_ID="$Y_AK" AWS_SECRET_ACCESS_KEY="$Y_SK" \
|
||
AWS_DEFAULT_REGION="$Y_REGION" \
|
||
aws --endpoint-url "$Y_ENDPOINT" --output json sqs "$@" 2>&1
|
||
}
|
||
|
||
osqs() {
|
||
AWS_ACCESS_KEY_ID="$O_AK" AWS_SECRET_ACCESS_KEY="$O_SK" \
|
||
AWS_DEFAULT_REGION="$O_REGION" \
|
||
aws --endpoint-url "$O_ENDPOINT" --output json sqs "$@" 2>&1
|
||
}
|
||
|
||
# ms_since — миллисекунды с момента $1
|
||
ms_now() { date +%s%3N; }
|
||
|
||
echo "╔═══════════════════════════════════════════════════════════════════╗"
|
||
echo "║ BENCHMARK: Yandex MQ vs shared-sqs — $(date '+%Y-%m-%d %H:%M:%S') ║"
|
||
echo "║ Из локали, равные условия ║"
|
||
echo "╚═══════════════════════════════════════════════════════════════════╝"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# 1. SEQUENTIAL SEND — latency per message
|
||
# ═══════════════════════════════════════
|
||
echo "═══ 1. Sequential SendMessage (${SEQ_COUNT} msgs) ═══"
|
||
|
||
# Yandex
|
||
echo -n " Yandex: "
|
||
Y_START=$(ms_now)
|
||
Y_SEND_OK=0
|
||
for i in $(seq 1 $SEQ_COUNT); do
|
||
R=$(ysqs send-message --queue-url "$Y_QURL" --message-body "bench-seq-${i}")
|
||
if echo "$R" | grep -q "MessageId"; then Y_SEND_OK=$((Y_SEND_OK+1)); fi
|
||
echo -n "."
|
||
done
|
||
Y_SEND_MS=$(( $(ms_now) - Y_START ))
|
||
Y_SEND_AVG=$(( Y_SEND_MS / SEQ_COUNT ))
|
||
echo " ${Y_SEND_OK}/${SEQ_COUNT} ok, ${Y_SEND_MS}ms total, avg=${Y_SEND_AVG}ms"
|
||
|
||
# Ours
|
||
echo -n " Ours: "
|
||
O_START=$(ms_now)
|
||
O_SEND_OK=0
|
||
for i in $(seq 1 $SEQ_COUNT); do
|
||
R=$(osqs send-message --queue-url "$O_QURL" --message-body "bench-seq-${i}")
|
||
if echo "$R" | grep -q "MessageId"; then O_SEND_OK=$((O_SEND_OK+1)); fi
|
||
echo -n "."
|
||
done
|
||
O_SEND_MS=$(( $(ms_now) - O_START ))
|
||
O_SEND_AVG=$(( O_SEND_MS / SEQ_COUNT ))
|
||
echo " ${O_SEND_OK}/${SEQ_COUNT} ok, ${O_SEND_MS}ms total, avg=${O_SEND_AVG}ms"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# 2. SEQUENTIAL RECEIVE — latency per message
|
||
# ═══════════════════════════════════════
|
||
echo "═══ 2. Sequential ReceiveMessage (${SEQ_COUNT} msgs) ═══"
|
||
|
||
# Yandex
|
||
echo -n " Yandex: "
|
||
Y_START=$(ms_now)
|
||
Y_RECV_OK=0
|
||
for i in $(seq 1 $SEQ_COUNT); do
|
||
R=$(ysqs receive-message --queue-url "$Y_QURL" --max-number-of-messages 1 --wait-time-seconds 2)
|
||
if echo "$R" | grep -q "MessageId"; then
|
||
Y_RECV_OK=$((Y_RECV_OK+1))
|
||
H=$(echo "$R" | grep -oP '"ReceiptHandle"\s*:\s*"\K[^"]+')
|
||
ysqs delete-message --queue-url "$Y_QURL" --receipt-handle "$H" >/dev/null 2>&1
|
||
fi
|
||
echo -n "."
|
||
done
|
||
Y_RECV_MS=$(( $(ms_now) - Y_START ))
|
||
Y_RECV_AVG=$(( Y_RECV_MS / SEQ_COUNT ))
|
||
echo " ${Y_RECV_OK}/${SEQ_COUNT} ok, ${Y_RECV_MS}ms total, avg=${Y_RECV_AVG}ms"
|
||
|
||
# Ours
|
||
echo -n " Ours: "
|
||
O_START=$(ms_now)
|
||
O_RECV_OK=0
|
||
for i in $(seq 1 $SEQ_COUNT); do
|
||
R=$(osqs receive-message --queue-url "$O_QURL" --max-number-of-messages 1 --wait-time-seconds 2)
|
||
if echo "$R" | grep -q "MessageId"; then
|
||
O_RECV_OK=$((O_RECV_OK+1))
|
||
H=$(echo "$R" | grep -oP '"ReceiptHandle"\s*:\s*"\K[^"]+')
|
||
osqs delete-message --queue-url "$O_QURL" --receipt-handle "$H" >/dev/null 2>&1
|
||
fi
|
||
echo -n "."
|
||
done
|
||
O_RECV_MS=$(( $(ms_now) - O_START ))
|
||
O_RECV_AVG=$(( O_RECV_MS / SEQ_COUNT ))
|
||
echo " ${O_RECV_OK}/${SEQ_COUNT} ok, ${O_RECV_MS}ms total, avg=${O_RECV_AVG}ms"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# 3. PARALLEL SEND — throughput
|
||
# ═══════════════════════════════════════
|
||
TOTAL_PAR=$((PAR_WORKERS * PAR_MSGS))
|
||
echo "═══ 3. Parallel SendMessage (${PAR_WORKERS} workers × ${PAR_MSGS} = ${TOTAL_PAR} msgs) ═══"
|
||
|
||
# Yandex
|
||
echo -n " Yandex: "
|
||
Y_START=$(ms_now)
|
||
for w in $(seq 1 $PAR_WORKERS); do
|
||
(
|
||
ok=0
|
||
for m in $(seq 1 $PAR_MSGS); do
|
||
R=$(ysqs send-message --queue-url "$Y_QURL" --message-body "par-${w}-${m}")
|
||
if echo "$R" | grep -q "MessageId"; then ok=$((ok+1)); fi
|
||
done
|
||
echo "$ok" > "${TMPDIR_CMP}/y_par_${w}"
|
||
) &
|
||
done
|
||
wait
|
||
Y_PAR_MS=$(( $(ms_now) - Y_START ))
|
||
Y_PAR_OK=0
|
||
for w in $(seq 1 $PAR_WORKERS); do
|
||
[[ -f "${TMPDIR_CMP}/y_par_${w}" ]] && Y_PAR_OK=$((Y_PAR_OK + $(cat "${TMPDIR_CMP}/y_par_${w}")))
|
||
done
|
||
Y_PAR_RPS=$(( Y_PAR_OK * 1000 / Y_PAR_MS ))
|
||
echo "${Y_PAR_OK}/${TOTAL_PAR} ok, ${Y_PAR_MS}ms, ~${Y_PAR_RPS} msg/sec"
|
||
|
||
# Ours
|
||
echo -n " Ours: "
|
||
O_START=$(ms_now)
|
||
for w in $(seq 1 $PAR_WORKERS); do
|
||
(
|
||
ok=0
|
||
for m in $(seq 1 $PAR_MSGS); do
|
||
R=$(osqs send-message --queue-url "$O_QURL" --message-body "par-${w}-${m}")
|
||
if echo "$R" | grep -q "MessageId"; then ok=$((ok+1)); fi
|
||
done
|
||
echo "$ok" > "${TMPDIR_CMP}/o_par_${w}"
|
||
) &
|
||
done
|
||
wait
|
||
O_PAR_MS=$(( $(ms_now) - O_START ))
|
||
O_PAR_OK=0
|
||
for w in $(seq 1 $PAR_WORKERS); do
|
||
[[ -f "${TMPDIR_CMP}/o_par_${w}" ]] && O_PAR_OK=$((O_PAR_OK + $(cat "${TMPDIR_CMP}/o_par_${w}")))
|
||
done
|
||
O_PAR_RPS=$(( O_PAR_OK * 1000 / O_PAR_MS ))
|
||
echo "${O_PAR_OK}/${TOTAL_PAR} ok, ${O_PAR_MS}ms, ~${O_PAR_RPS} msg/sec"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# 4. BURST — все сразу
|
||
# ═══════════════════════════════════════
|
||
echo "═══ 4. Burst SendMessage (${BURST} одновременно) ═══"
|
||
|
||
# Yandex
|
||
echo -n " Yandex: "
|
||
Y_START=$(ms_now)
|
||
for b in $(seq 1 $BURST); do
|
||
( R=$(ysqs send-message --queue-url "$Y_QURL" --message-body "burst-${b}")
|
||
echo "$R" | grep -q "MessageId" && echo 1 || echo 0
|
||
) > "${TMPDIR_CMP}/y_burst_${b}" &
|
||
done
|
||
wait
|
||
Y_BURST_MS=$(( $(ms_now) - Y_START ))
|
||
Y_BURST_OK=0
|
||
for b in $(seq 1 $BURST); do
|
||
[[ -f "${TMPDIR_CMP}/y_burst_${b}" ]] && Y_BURST_OK=$((Y_BURST_OK + $(cat "${TMPDIR_CMP}/y_burst_${b}")))
|
||
done
|
||
echo "${Y_BURST_OK}/${BURST} ok, ${Y_BURST_MS}ms"
|
||
|
||
# Ours
|
||
echo -n " Ours: "
|
||
O_START=$(ms_now)
|
||
for b in $(seq 1 $BURST); do
|
||
( R=$(osqs send-message --queue-url "$O_QURL" --message-body "burst-${b}")
|
||
echo "$R" | grep -q "MessageId" && echo 1 || echo 0
|
||
) > "${TMPDIR_CMP}/o_burst_${b}" &
|
||
done
|
||
wait
|
||
O_BURST_MS=$(( $(ms_now) - O_START ))
|
||
O_BURST_OK=0
|
||
for b in $(seq 1 $BURST); do
|
||
[[ -f "${TMPDIR_CMP}/o_burst_${b}" ]] && O_BURST_OK=$((O_BURST_OK + $(cat "${TMPDIR_CMP}/o_burst_${b}")))
|
||
done
|
||
echo "${O_BURST_OK}/${BURST} ok, ${O_BURST_MS}ms"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# 5. GetQueueAttributes — latency
|
||
# ═══════════════════════════════════════
|
||
echo "═══ 5. GetQueueAttributes (5 раз) ═══"
|
||
|
||
echo -n " Yandex: "
|
||
Y_START=$(ms_now)
|
||
for i in $(seq 1 5); do
|
||
ysqs get-queue-attributes --queue-url "$Y_QURL" --attribute-names ApproximateNumberOfMessages >/dev/null 2>&1
|
||
echo -n "."
|
||
done
|
||
Y_ATTR_MS=$(( $(ms_now) - Y_START ))
|
||
Y_ATTR_AVG=$(( Y_ATTR_MS / 5 ))
|
||
echo " ${Y_ATTR_MS}ms total, avg=${Y_ATTR_AVG}ms"
|
||
|
||
echo -n " Ours: "
|
||
O_START=$(ms_now)
|
||
for i in $(seq 1 5); do
|
||
osqs get-queue-attributes --queue-url "$O_QURL" --attribute-names ApproximateNumberOfMessages >/dev/null 2>&1
|
||
echo -n "."
|
||
done
|
||
O_ATTR_MS=$(( $(ms_now) - O_START ))
|
||
O_ATTR_AVG=$(( O_ATTR_MS / 5 ))
|
||
echo " ${O_ATTR_MS}ms total, avg=${O_ATTR_AVG}ms"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# 6. PURGE — очистка после тестов
|
||
# ═══════════════════════════════════════
|
||
echo "═══ 6. Purge (очистка) ═══"
|
||
ysqs purge-queue --queue-url "$Y_QURL" >/dev/null 2>&1 && echo " Yandex: purged" || echo " Yandex: purge failed (cooldown?)"
|
||
osqs purge-queue --queue-url "$O_QURL" >/dev/null 2>&1 && echo " Ours: purged" || echo " Ours: purge failed"
|
||
echo ""
|
||
|
||
# ═══════════════════════════════════════
|
||
# ИТОГОВАЯ ТАБЛИЦА
|
||
# ═══════════════════════════════════════
|
||
echo "╔══════════════════════════════════════════════════════════════════════════╗"
|
||
echo "║ РЕЗУЛЬТАТЫ СРАВНЕНИЯ ║"
|
||
echo "╠══════════════════════════╦══════════════════╦══════════════════╦════════╣"
|
||
echo "║ Тест ║ Yandex MQ ║ shared-sqs ║ Winner ║"
|
||
echo "╠══════════════════════════╬══════════════════╬══════════════════╬════════╣"
|
||
printf "║ %-24s ║ %4dms avg %2d/%2d ║ %4dms avg %2d/%2d ║ %-6s ║\n" \
|
||
"Seq Send (${SEQ_COUNT}msg)" "$Y_SEND_AVG" "$Y_SEND_OK" "$SEQ_COUNT" "$O_SEND_AVG" "$O_SEND_OK" "$SEQ_COUNT" \
|
||
"$([ $Y_SEND_AVG -le $O_SEND_AVG ] && echo 'YMQ' || echo 'OURS')"
|
||
printf "║ %-24s ║ %4dms avg %2d/%2d ║ %4dms avg %2d/%2d ║ %-6s ║\n" \
|
||
"Seq Recv+Del (${SEQ_COUNT}msg)" "$Y_RECV_AVG" "$Y_RECV_OK" "$SEQ_COUNT" "$O_RECV_AVG" "$O_RECV_OK" "$SEQ_COUNT" \
|
||
"$([ $Y_RECV_AVG -le $O_RECV_AVG ] && echo 'YMQ' || echo 'OURS')"
|
||
printf "║ %-24s ║ %4dms %3d msg/s ║ %4dms %3d msg/s ║ %-6s ║\n" \
|
||
"Parallel Send (${TOTAL_PAR}msg)" "$Y_PAR_MS" "$Y_PAR_RPS" "$O_PAR_MS" "$O_PAR_RPS" \
|
||
"$([ $Y_PAR_RPS -ge $O_PAR_RPS ] && echo 'YMQ' || echo 'OURS')"
|
||
printf "║ %-24s ║ %4dms %2d/%2d ║ %4dms %2d/%2d ║ %-6s ║\n" \
|
||
"Burst (${BURST} simultaneous)" "$Y_BURST_MS" "$Y_BURST_OK" "$BURST" "$O_BURST_MS" "$O_BURST_OK" "$BURST" \
|
||
"$([ $Y_BURST_MS -le $O_BURST_MS ] && echo 'YMQ' || echo 'OURS')"
|
||
printf "║ %-24s ║ %4dms avg ║ %4dms avg ║ %-6s ║\n" \
|
||
"GetQueueAttributes (5x)" "$Y_ATTR_AVG" "$O_ATTR_AVG" \
|
||
"$([ $Y_ATTR_AVG -le $O_ATTR_AVG ] && echo 'YMQ' || echo 'OURS')"
|
||
echo "╚══════════════════════════╩══════════════════╩══════════════════╩════════╝"
|