SQS #

Dalam arsitektur sistem terdistribusi modern—terutama yang mengadopsi pola microservices, arsitektur berbasis peristiwa (event-driven), dan serverless—komunikasi langsung antar-layanan secara sinkron (seperti panggilan HTTP REST API langsung) sering kali memicu kerentanan sistem. Jika salah satu layanan tujuan mengalami kelebihan beban atau mati, layanan pengirim juga akan ikut gagal, menciptakan efek domino kegagalan (cascading failure).

Untuk mengatasi masalah ini, kita membutuhkan komponen perantara yang dapat memisahkan ketergantungan antar-layanan (decoupling) dan bertindak sebagai peredam lonjakan beban (load leveling). Di dalam ekosistem AWS, AWS Simple Queue Service (SQS) adalah layanan antrean pesan terkelola (fully managed message queue) berbasis serverless yang menjadi fondasi utama untuk membangun komunikasi asinkron yang andal, aman, dan sangat skalabel.


Apa itu AWS SQS? #

AWS SQS adalah layanan antrean pesan terkelola yang memungkinkan komponen-komponen aplikasi saling bertukar data secara asinkron tanpa perlu saling mengetahui lokasi atau status satu sama lain secara langsung.

Proses pengiriman pesan secara konseptual melibatkan tiga peran utama:

  1. Producer: Komponen aplikasi (misalnya web server atau fungsi Lambda) yang membuat dan mengirimkan pesan berisi data ke dalam antrean SQS.
  2. Message Queue: Antrean terkelola SQS yang menyimpan pesan secara aman dan tahan lama (durable) di atas kluster server AWS yang terdistribusi di beberapa Availability Zones.
  3. Consumer: Komponen aplikasi (seperti worker process di ECS atau fungsi Lambda) yang secara berkala menarik pesan dari antrean, memproses datanya, dan menghapus pesan tersebut dari antrean setelah selesai diproses.
flowchart LR
    Client["Klien HTTP"] -->|Request| APIGW["API Gateway"]
    APIGW -->|Trigger Sinkron| LambdaProd["Lambda Producer"]
    LambdaProd -->|Kirim Pesan (Asinkron)| SQS["AWS SQS Queue<br/>(Buffer / Load Leveling)"]
    SQS -->|Event Source Mapping| LambdaCons["Lambda Consumer"]
    LambdaCons -->|Simpan Data| DynamoDB["Amazon DynamoDB"]
    
    LambdaCons -.->|Gagal > maxReceiveCount| DLQ["Dead Letter Queue (DLQ)<br/>(Isolasi Pesan Error)"]

Jenis-Jenis Antrean di AWS SQS #

AWS SQS menyediakan dua jenis antrean dengan karakteristik performa dan batasan biaya yang berbeda. Pemilihan tipe antrean harus disesuaikan dengan kebutuhan logika bisnis aplikasi kita.

1. Standard Queue (Antrean Standar) #

Ini adalah tipe antrean default yang menawarkan skalabilitas horizontal yang hampir tanpa batas.

  • Pengiriman Setidaknya Sekali (At-Least-Once Delivery): SQS menjamin bahwa setiap pesan pasti akan terkirim setidaknya satu kali ke consumer. Namun, karena sifat sistem terdistribusi SQS, terkadang ada salinan pesan yang sama yang terkirim lebih dari satu kali.
  • Urutan Terbaik (Best-Effort Ordering): Urutan pesan keluar dari antrean diusahakan sama dengan urutan masuk, tetapi AWS tidak menjamin urutan tersebut secara mutlak.
  • Throughput Tanpa Batas: Mendukung jumlah transaksi (kirim/terima pesan) per detik dalam skala yang hampir tidak terbatas.
  • Use Case Ideal: Pemrosesan log aplikasi, pipeline konversi video, pengiriman email notifikasi massal, atau skenario apa pun yang tidak sensitif terhadap duplikasi dan urutan data.

2. FIFO Queue (First-In-First-Out) #

Antrean FIFO dirancang untuk skenario yang membutuhkan kepastian urutan eksekusi dan eliminasi pesan duplikat secara mutlak.

  • Urutan Ketat (Strict Ordering): Pesan dijamin akan keluar dari antrean dalam urutan yang sama persis dengan saat pesan tersebut masuk.
  • Pemrosesan Tepat Sekali (Exactly-Once Processing): SQS secara otomatis mendeteksi dan menghapus pesan duplikat yang dikirim dalam jendela waktu 5 menit menggunakan parameter MessageDeduplicationId.
  • Throughput Terbatas: Secara default mendukung hingga 300 transaksi per detik (atau hingga 3.000 transaksi per detik jika fitur high throughput FIFO diaktifkan).
  • Use Case Ideal: Transaksi keuangan/perbankan, sistem checkout e-commerce (untuk mencegah pembelian ganda), atau alur persetujuan dokumen berurutan.

Opsi Konfigurasi Esensial #

Memahami parameter konfigurasi SQS adalah kunci untuk menghindari bug operasional seperti pemrosesan pesan ganda (double processing) atau hilangnya data.

1. Visibility Timeout #

Ketika seorang consumer mengambil sebuah pesan dari antrean SQS, pesan tersebut tidak langsung dihapus. SQS menyembunyikan pesan tersebut sementara waktu agar consumer lain tidak ikut mengambilnya. Jendela waktu penyembunyian ini disebut Visibility Timeout.

  • Cara Kerja: Consumer harus memproses pesan dan mengirimkan perintah hapus (delete request) ke SQS sebelum Visibility Timeout habis.
  • Potensi Masalah: Jika consumer membutuhkan waktu memproses pesan lebih lama daripada durasi Visibility Timeout, pesan tersebut akan muncul kembali di antrean dan akan diambil oleh consumer lain, memicu pemrosesan ganda.
Pencegahan Pemrosesan Ganda: Selalu konfigurasi Visibility Timeout minimal 6 kali lipat dari durasi eksekusi maksimum fungsi Lambda consumer Anda. Jika fungsi Lambda Anda memiliki timeout 30 detik, konfigurasi Visibility Timeout antrean SQS Anda minimal 180 detik.

2. Long Polling vs. Short Polling #

Long polling membantu kita mereduksi biaya panggilan API SQS dan menghemat penggunaan CPU consumer.

  • Short Polling (ReceiveMessageWaitTimeSeconds = 0): SQS langsung mengembalikan respon kosong jika antrean sedang sepi. Ini memicu tingginya jumlah request HTTP kosong yang tidak perlu dan meningkatkan tagihan bulanan kita.
  • Long Polling (ReceiveMessageWaitTimeSeconds = 1 sampai 20): SQS akan menahan koneksi HTTP selama maksimal 20 detik jika antrean kosong. Jika ada pesan masuk selama masa tunggu tersebut, SQS langsung mengirimkannya ke consumer.

Selalu gunakan Long Polling dengan nilai 20 detik di lingkungan produksi untuk efisiensi biaya request.

3. Dead Letter Queue (DLQ) #

DLQ adalah antrean SQS penampung khusus untuk pesan-pesan yang berulang kali gagal diproses oleh consumer karena adanya kerusakan data (poison pill) atau bug kode aplikasi.

Kita mengonfigurasi parameter maxReceiveCount (misalnya 3). Jika sebuah pesan telah dicoba diambil dan diproses sebanyak 3 kali namun selalu gagal (kembali ke antrean karena visibility timeout habis), SQS akan memindahkan pesan tersebut ke DLQ secara otomatis. Ini mencegah pesan rusak menyumbat antrean utama secara terus-menerus.


Contoh Implementasi Praktis: Node.js #

Berikut adalah contoh penulisan kode produser untuk mengirim pesan ke SQS, serta konsumen yang memproses pesan dari SQS dengan menerapkan logika pencegahan duplikasi menggunakan DynamoDB (idempotency tracking).

1. Produser (Mengirim Pesan ke SQS) #

import { SQSClient, SendMessageCommand } from "@aws-sdk/client-sqs";

const sqsClient = new SQSClient({ region: "ap-southeast-1" });
const QUEUE_URL = process.env.SQS_QUEUE_URL;

export const handler = async (event) => {
    try {
        const orderData = {
            orderId: "ORD-998273",
            amount: 150000,
            timestamp: new Date().toISOString()
        };

        const command = new SendMessageCommand({
            QueueUrl: QUEUE_URL,
            MessageBody: JSON.stringify(orderData),
            // ✓ Mengirimkan atribut tambahan sebagai metadata
            MessageAttributes: {
                "EventType": {
                    DataType: "String",
                    StringValue: "OrderCreated"
                }
            }
        });

        const response = await sqsClient.send(command);
        console.log(`Pesan sukses dikirim ke SQS. MessageId: ${response.MessageId}`);

        return {
            statusCode: 200,
            body: JSON.stringify({ success: true, messageId: response.MessageId })
        };
    } catch (error) {
        console.error("Gagal mengirim pesan ke SQS", error);
        return { statusCode: 500, body: JSON.stringify({ error: error.message }) };
    }
};

2. Konsumen Idempotent (Memproses Event SQS) #

// BENAR: Mencegah efek samping ganda dengan mencatat MessageId yang sukses diproses
import { DynamoDBClient, PutItemCommand } from "@aws-sdk/client-dynamodb";

const dbClient = new DynamoDBClient({ region: "ap-southeast-1" });
const IDEMPOTENCY_TABLE = process.env.IDEMPOTENCY_TABLE_NAME;

export const handler = async (event) => {
    // SQS trigger mengirimkan array rekaman pesan (batch)
    for (const record of event.Records) {
        const messageId = record.messageId;
        const body = JSON.parse(record.body);

        try {
            // ✓ Langkah 1: Coba simpan messageId ke tabel idempotensi DynamoDB
            // Jika MessageId sudah ada, database akan menolak request (Conditional Write)
            await dbClient.send(new PutItemCommand({
                TableName: IDEMPOTENCY_TABLE,
                Item: {
                    "MessageId": { S: messageId },
                    "ProcessedAt": { S: new Date().toISOString() }
                },
                ConditionExpression: "attribute_not_exists(MessageId)"
            }));

            // ✓ Langkah 2: Proses logika bisnis utama jika messageId belum pernah diproses
            console.log(`Memproses order: ${body.orderId} dengan ID unik SQS: ${messageId}`);
            
            // Lakukan kalkulasi bisnis di sini...

        } catch (dbError) {
            if (dbError.name === "ConditionalCheckFailedException") {
                // ✓ BENAR: Deteksi pesan duplikat secara aman dan abaikan pemrosesan ulang
                console.warn(`Pesan dengan ID ${messageId} sudah pernah diproses sebelumnya. Mengabaikan.`);
                continue;
            }
            // Lempar kembali error tak terduga lainnya agar Lambda melakukan retry
            throw dbError;
        }
    }
};

Ringkasan #

  • AWS SQS adalah fully managed message queue berbasis serverless yang memisahkan dependensi antar-layanan (decoupling) secara asinkron.
  • Standard Queue menawarkan throughput tanpa batas dengan jaminan pengiriman at-least-once, namun tidak menjamin urutan mutlak.
  • FIFO Queue menjamin urutan pesan yang ketat (first-in-first-out) dan pemrosesan tepat sekali (exactly-once), dengan batasan throughput maksimal tertentu.
  • Visibility Timeout harus dikonfigurasi lebih besar (minimal 6 kali) dari durasi eksekusi maksimum consumer untuk menghindari pemrosesan ganda.
  • Aktifkan Long Polling (20 detik) untuk menghemat biaya pemanggilan API SQS secara signifikan dengan mengurangi respon kosong (empty receives).
  • Dead Letter Queue (DLQ) wajib digunakan untuk mengisolasi pesan-pesan rusak (poison pills) agar tidak menyumbat antrean utama sistem.

← Sebelumnya: Fargate   Berikutnya: SNS →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact