NATS ve AWS SQS/SNS yük testi: onay süresi ve uçtan uca gecikme
Mesajlaşma sistemlerinde "istek süresi" iki ayrı şeydir: gönderenin onayı ne kadar beklediği ve mesajın alıcıya ne kadar sürede vardığı. Bir sipariş servisi JetStream'e 3 ms'de yazabilir, ama işleyiciler geride kaldıysa sipariş ancak 40 saniye sonra işlenir. NATS ve SQS yük testinin işi bu iki süreyi ayrı ayrı ölçmek ve hangisinin hangi yükte bozulduğunu göstermektir.
Neyi ölçüyoruz?
- Yayın onayı: core NATS'te yayın onay beklemez; süre mesajın istemci tamponuna yazılmasıdır ve sunucu hakkında az şey söyler. JetStream'de süre stream'in PubAck'ine, SQS'te
SendMessage'ın cevabına kadardır: mesajın kalıcı olarak yazıldığı an. - İstek/yanıt: NATS'in request-reply düzeninde gidiş-dönüş süresi, yani yanıt veren servisin kendisi.
- Uçtan uca gecikme: mesajın gönderilmesinden alınmasına kadar geçen süre. Kuyruk birikmeye başladığında ilk bozulan sayı budur; onay süreleri o sırada hâlâ iyi görünebilir.
- Hatalar: dinleyeni olmayan istekler, var olmayan stream ya da kuyruklar, kimlik ve izin hataları, AWS'nin kısıtlaması (throttling) ve zaman aşımları.
Yük modelini kurmak
Mesajlaşmada yük "kaç kullanıcı" değil "saniyede kaç mesaj"tır. Gönderen tarafı sabit bir varış hızıyla (arrival rate) kurun; tüketen tarafı gerçek işleyici sayısı kadar VU ile. Gönderim hızı tüketim kapasitesini aştığında uçtan uca gecikme dakikadan dakikaya büyür; bunu görmek için testi birkaç dakika değil en az on dakika koşturun ve hızı basamaklarla artırın.
Sık yapılan hatalar
- Gerçek servisin consumer'ını ya da kuyruğunu kullanmak. Work-queue stream'de onaylanan ve SQS'te alınıp silinen mesaj kaybolur: test, gerçek servisin mesajlarını tüketir. Test için ayrı bir consumer adı ve ayrı bir kuyruk kullanın.
- SQS'in faturasını unutmak. SQS ve SNS istek başına ücretlidir; saniyede yüz mesajlık on dakikalık bir test yüz binlerce istektir. Testi ayrı bir hesapta ya da önce LocalStack veya ElasticMQ ile deneyin.
- Saat farkıyla gecikme ölçmek. Gönderen ve alan farklı makinelerse saatlerindeki birkaç milisaniyelik fark uçtan uca gecikmeye karışır. Gecikmeyi aynı makinede gönderilip alınan mesajlarla ölçün.
- Ortalamaya bakmak. Kuyruk gecikmesinin kuyruğu uzundur; p95 ve p99'a bakın (p95 ve p99 rehberi).
Spitfire ile: NATS
Bağlantılar'da bir NATS bağlantısı ekleyin: sunucular, kimlik doğrulama (kullanıcı ve parola, token, NKey seed ya da .creds dosyası; şifreli saklanır), TLS ve gerekiyorsa JetStream domain. Bir runner'daki VU'lar varsayılan olarak 4 bağlantıyı paylaşır; bağlantı sayısı sınırını denemek için her VU'ya ayrı bağlantı açılabilir. NATS adımının beş eylemi vardır:
- Yayınla: core publish; onay beklenmez.
- Mesaj bekle: VU subject'e bir kez abone olur (
orders.*,orders.>); queue group verilirse mesajlar VU'lar arasında paylaşılır. - İstek/yanıt: süre gidiş-dönüştür; dinleyen yoksa hata
no_respondersolur. - JetStream'e yayınla: süre PubAck'e kadardır; subject'i kapsayan stream yoksa hata
no_stream. - JetStream'den al: bir durable pull consumer'dan mesaj alınır ve onaylanır. Consumer runner'daki VU'lar arasında paylaşılır; yoksa yeni mesajlardan başlayan bir consumer oluşturulur, varsa ayarlarına dokunulmaz.
Spitfire ile: SQS ve SNS
Bir AWS bağlantısı ekleyin: bölge ve access key (şifreli saklanır) ya da makinenin kendi kimlik bilgileri (ortam değişkenleri, profil, IAM rolü). İkincisini yalnız kurulum yöneticisi açabilir, çünkü bağlantıyı kullanan herkes kurulumun AWS kimliğiyle işlem yapar. LocalStack, ElasticMQ ya da bir VPC endpoint için özel bir endpoint yazılır. SQS adımının üç eylemi vardır: Gönder (FIFO kuyruklarda message group ve deduplication ID, 0–15 dakika gecikme, mesaj attribute'ları), long polling ile Al ve sil (isterseniz silmeden bırakın; mesaj görünürlük süresi bitince kuyruğa döner) ve SNS'e yayınla. Kuyruk adıyla ya da URL'siyle yazılır.
Uçtan uca gecikme
Spitfire gönderdiği mesajları damgalar: NATS'te Spitfire-Ts header'ı, SQS'te spitfire-ts attribute'u. Alma adımları, aynı koşuda aynı runner'ın gönderdiği mesajlar için nats_e2e_latency ve sqs_e2e_latency ölçer: iki uç aynı saati okuduğu için saat farkı karışmaz. SNS'ten bir SQS kuyruğuna giden akışta raw message delivery açıksa gecikme yine ölçülür. Bu metriklere diğerleri gibi eşik yazılır.
Saniyede 200 siparişin JetStream'e yayınlandığı ve her biri için bir faturanın SQS kuyruğuna atıldığı, 20 işleyicinin ikisini de tükettiği 10 dakikalık bir test. JetStream onayının p95'i 20 ms'nin, NATS uçtan uca gecikmesinin p95'i 50 ms'nin, SQS'inki 1 saniyenin altında kalmalı. Test spitfire validate ile doğrulandı.
{
"name": "Sipariş akışı: NATS ve SQS",
"scenarios": [
{ "name": "siparisler",
"executor": { "type": "constant-arrival-rate", "rate": 200, "timeUnit": "1s",
"duration": "10m", "preAllocatedVUs": 50, "maxVUs": 200 },
"steps": [
{ "id": "place", "name": "Siparişi yayınla", "protocol": "nats", "connection": "bus",
"nats": { "action": "jsPublish", "subject": "orders.{{__VU}}", "payload": "{\"vu\": {{__VU}}}" } },
{ "id": "queue", "name": "Faturayı kuyruğa at", "protocol": "sqs", "connection": "aws-test",
"sqs": { "action": "send", "queue": "invoices-loadtest", "body": "{\"order\": {{__ITER}}}" } } ] },
{ "name": "isleyiciler",
"executor": { "type": "constant-vus", "vus": 20, "duration": "10m" },
"steps": [
{ "id": "handle", "name": "Siparişi al", "protocol": "nats", "connection": "bus",
"nats": { "action": "jsConsume", "subject": "orders.>", "stream": "ORDERS", "consumer": "spitfire", "wait": "5s" } },
{ "id": "take", "name": "Faturayı al", "protocol": "sqs", "connection": "aws-test",
"sqs": { "action": "receive", "queue": "invoices-loadtest", "wait": "10s" } } ] }
],
"thresholds": [
{ "metric": "req_duration", "filter": { "step": "place" }, "expr": "p(95)<20" },
{ "metric": "nats_e2e_latency", "expr": "p(95)<50" },
{ "metric": "sqs_e2e_latency", "expr": "p(95)<1000" },
{ "metric": "req_failed", "expr": "rate<0.001" }
]
}Spitfire tek komutla Docker'a ya da Kubernetes'e kurulur; ücretsiz sürümde bütün test özellikleri ve protokoller açıktır.