L
Cloud Architecture & Serverless • Literally Web ID

Arsitektur Serverless Berperforma Tinggi Menggunakan AWS Lambda, API Gateway, dan DynamoDB

⏱️ 15 menit baca • 📅 14 Oct 2026 • 👁️ 1 views
Arsitektur Serverless Berperforma Tinggi Menggunakan AWS Lambda, API Gateway, dan DynamoDB

1. Konteks Industri & Analisis Akar Masalah

Dalam lanskap rekayasa infrastruktur web modern, pergeseran dari arsitektur monolitik berbasis server persisten (seperti instance EC2 dengan Nginx dan PHP-FPM, atau VPS mandiri dengan MySQL dan Redis) menuju arsitektur serverless berbasis AWS telah mencapai tingkat adopsi massal. Namun, paradoks terbesar dari teknologi tanpa server ini adalah Cold Start Latency dan Inefisiensi Akses Data NoSQL.

Di dunia nyata, arsitektur konvensional yang mengandalkan server web persisten sering kali menghadapi masalah bottleneck pada utilisasi sumber daya saat lalu lintas bersifat fluktuatif (spiky traffic). Saat beban melonjak drastis, sysadmin harus mengandalkan Auto Scaling Group (ASG) yang membutuhkan waktu menit untuk memutar instans baru, membebani Load Balancer, dan berisiko mengalami Resource Exhaustion pada database relasional tradisional seperti MySQL akibat tingginya connection pooling.

Sebaliknya, arsitektur serverless menjanjikan penskalaan instan dari nol hingga ribuan eksekusi per detik. Kendati demikian, tanpa pemahaman mendalam tentang Cold Start Optimization, Single-Table Design DynamoDB, dan Secure API Authorization, aplikasi web serverless justru akan mengalami lonjakan latensi yang tidak terduga (P99 latency spike) dan pembengkakan biaya operasional akibat pembacaan tabel yang tidak terindeks dengan baik.

Perbandingan Kondisi Sebelum vs Sesudah Penerapan

Parameter Arsitektur Konvensional (EC2 + Nginx + MySQL) Arsitektur Serverless Berperforma Tinggi (Lambda + API Gateway + DynamoDB)
Skalabilitas Manual / Lambat (Auto Scaling memakan waktu 3-5 menit) Instan (Skala otomatis dalam milidetik tanpa intervensi manual)
Manajemen Kapasitas Membayar kapasitas penuh 24/7 meskipun tanpa lalu lintas Membayar murni berdasarkan jumlah eksekusi dan durasi milidetik (pay-per-request)
Manajemen Koneksi DB Rawan masalah connection exhaustion pada beban tinggi Menggunakan HTTP/API stateless, menghindari batasan connection pool tradisional
Maintenance Infrastruktur Membutuhkan OS patching, konfigurasi web server, tuning FPM Sepenuhnya dikelola oleh AWS (Managed Service), fokus murni pada logika bisnis

2. Konsep Inti & Deep Dive Arsitektur

Untuk memahami cara kerja arsitektur ini di balik layar (under the hood), kita perlu membedah alur hidup permintaan (request lifecycle) dari klien hingga penyimpanan data.

[ Client / Browser ]
         │
         ▼ (HTTPS)
[ Amazon API Gateway (HTTP API) ]
         │
         ├─► [ Lambda Authorizer (JWT / IAM Validation) ]
         │
         ▼
[ AWS Lambda (Node.js / Go Runtime) ]
         │
         ├─ (Koneksi Keep-Alive / SDK Client Cached)
         ▼
[ Amazon DynamoDB (Single-Table Design) ]

Alur Eksekusi Data:

  1. Klien mengirimkan request HTTPS ke Amazon API Gateway (disarankan menggunakan HTTP API demi latensi yang lebih rendah dibandingkan REST API).
  2. Lambda Authorizer memvalidasi token JWT secara asinkron atau melakukan caching hasil otorisasi untuk menghemat waktu komputasi.
  3. AWS Lambda mengeksekusi kode aplikasi. Pada fase ini, pemanggilan SDK DynamoDB diinisialisasi di luar fungsi handler (global scope) untuk memanfaatkan kembali koneksi TCP (Connection Reuse) pada eksekusi berikutnya (Warm Start).
  4. Amazon DynamoDB memproses kueri menggunakan prinsip Single-Table Design, di mana entitas berbeda digabungkan dalam satu tabel dengan kunci komposit (Partition Key dan Sort Key) untuk memastikan operasi baca-tulis terjadi dalam satu kali lompatan indeks tunggal (O(1)).

3. Perbandingan Komparatif / Analisis Pendekatan

Dalam membangun backend web serverless, pemilihan bahasa pemrograman dan konfigurasi memori Lambda memegang peran krusial terhadap performa dan biaya.

Aspek Pendekatan AWS Lambda (Node.js / TypeScript) AWS Lambda (Golang / Go) AWS Lambda (Python / FastAPI)
Cold Start Duration Sedang (200ms - 600ms tergantung ukuran bundle) Sangat Cepat (50ms - 150ms karena binary native) Sedang (300ms - 700ms)
Memory Footprint Menengah (128MB - 512MB optimal) Sangat Rendah (64MB - 128MB sudah sangat cepat) Menengah
Developer Velocity Tinggi (ekosistem npm sangat luas) Tinggi (tipe statis yang kuat dan performa tinggi) Sangat Tinggi (sintaks ringkas)
CPU Allocation Proporsional terhadap alokasi memori Proporsional terhadap alokasi memori Proporsional terhadap alokasi memori

[!TIP] Di AWS Lambda, CPU tidak dialokasikan secara terpisah. Mengubah konfigurasi memori (misalnya dari 128MB ke 1024MB) secara linear akan meningkatkan kapasitas CPU yang dialokasikan oleh AWS, yang justru dapat mempercepat waktu eksekusi secara drastis dan menekan total biaya eksekusi.


4. Prasyarat Sistem & Persiapan Lingkungan

Sebelum melangkah ke implementasi kode, pastikan environment lokal Anda telah dilengkapi dengan perangkat lunak berikut:

  • Node.js (Versi 20.x LTS atau lebih baru)
  • AWS CLI (Telah dikonfigurasi dengan kredensial IAM yang memiliki hak akses penuh ke Lambda, API Gateway, dan DynamoDB)
  • AWS Serverless Application Model (SAM CLI) atau Terraform untuk orkestrasi infrastruktur
  • Git untuk manajemen versi

Verifikasi instalasi AWS CLI dengan perintah terminal:

aws --version
sam --version
node -v

5. Panduan Implementasi Langkah demi Langkah

Berikut adalah implementasi lengkap infrastruktur menggunakan AWS SAM (Serverless Application Model) beserta kode sumber fungsi Lambda dalam Node.js (TypeScript).

A. File Konfigurasi Infrastruktur: template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >-
  Arsitektur Serverless Berperforma Tinggi
  Lambda, API Gateway, dan DynamoDB Single-Table

Globals:
  Function:
    Timeout: 10
    MemorySize: 512
    Runtime: nodejs20.x
    Architectures:
      - arm64 # Menggunakan AWS Graviton2 untuk performa dan efisiensi biaya optimal

Resources:
  HttpApi:
    Type: AWS::Serverless::HttpApi
    Properties:
      Auth:
        Authorizers:
          JwtAuthorizer:
            JwtConfiguration:
              issuer: https://cognito-idp.us-east-1.amazonaws.com/us-east-1_EXAMPLE
              audience:
                - example-audience-client-id
            IdentitySource: $request.header.Authorization

  CoreFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: src/
      Handler: index.handler
      Environment:
        Variables:
          TABLE_NAME: !Ref HighPerformanceTable
      Policies:
        - DynamoDBCrudPolicy:
            TableName: !Ref HighPerformanceTable
      Events:
        GetResource:
          Type: HttpApi
          Properties:
            ApiId: !Ref HttpApi
            Path: /items/{id}
            Method: GET
            Auth:
              Authorizer: JwtAuthorizer
        PostResource:
          Type: HttpApi
          Properties:
            ApiId: !Ref HttpApi
            Path: /items
            Method: POST
            Auth:
              Authorizer: JwtAuthorizer

  HighPerformanceTable:
    Type: AWS::DynamoDB::Table
    Properties:
      TableName: HighPerformanceAppTable
      BillingMode: PAY_PER_REQUEST
      AttributeDefinitions:
        - AttributeName: PK
          AttributeType: S
        - AttributeName: SK
          AttributeType: S
      KeySchema:
        - AttributeName: PK
          KeyType: HASH
        - AttributeName: SK
          KeyType: RANGE

Outputs:
  ApiEndpoint:
    Description: "API Gateway HTTP API Endpoint URL"
    Value: !Sub "https://${HttpApi}.execute-api.${AWS::Region}.amazonaws.com"

B. Kode Implementasi Fungsi Lambda: src/index.ts

import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, GetCommand, PutCommand } from '@aws-sdk/lib-dynamodb';

// Inisialisasi klien DynamoDB di luar handler untuk caching koneksi (Cold Start Optimization)
const client = new DynamoDBClient({ region: process.env.AWS_REGION || 'us-east-1' });
const ddbDocClient = DynamoDBDocumentClient.from(client, {
  marshallOptions: {
    removeUndefinedValues: true,
  },
});

const TABLE_NAME = process.env.TABLE_NAME || 'HighPerformanceAppTable';

export const handler = async (event: APIGatewayProxyEventV2): Promise<APIGatewayProxyResultV2> => {
  const method = event.requestContext.http.method;
  const pathParameters = event.pathParameters;

  try {
    if (method === 'GET' && pathParameters?.id) {
      const itemId = pathParameters.id;
      const params = {
        TableName: TABLE_NAME,
        Key: {
          PK: `ITEM#${itemId}`,
          SK: `METADATA#${itemId}`,
        },
      };

      const { Item } = await ddbDocClient.send(new GetCommand(params));

      if (!Item) {
        return {
          statusCode: 404,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'Item not found' }),
        };
      }

      return {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(Item),
      };
    }

    if (method === 'POST') {
      if (!event.body) {
        return {
          statusCode: 400,
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ error: 'Missing request body' }),
        };
      }

      const body = JSON.parse(event.body);
      const itemId = body.id || Date.now().toString();

      const item = {
        PK: `ITEM#${itemId}`,
        SK: `METADATA#${itemId}`,
        GSI1PK: `TYPE#${body.type || 'DEFAULT'}`,
        GSI1SK: `DATE#${new Date().toISOString()}`,
        name: body.name,
        payload: body.payload,
        createdAt: new Date().toISOString(),
      };

      await ddbDocClient.send(
        new PutCommand({
          TableName: TABLE_NAME,
          Item: item,
        })
      );

      return {
        statusCode: 201,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ message: 'Item created successfully', data: item }),
      };
    }

    return {
      statusCode: 400,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ error: 'Unsupported route or method' }),
    };
  } catch (error: any) {
    console.error('Execution Error:', error);
    return {
      statusCode: 500,
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ error: 'Internal Server Error', details: error.message }),
    };
  };
};

6. Bedah Kode & Penjelasan Detail Baris Kunci

  1. Arsitektur ARM64 (AWS Graviton2) pada template.yaml: Penggunaan arsitektur arm64 memberikan peningkatan performa harga (price-performance) hingga 34% dibandingkan arsitektur tradisional x86_64, yang sangat berdampak pada penurunan durasi eksekusi Lambda.

  2. Inisialisasi Klien di Luar Handler (src/index.ts):

    const client = new DynamoDBClient({ region: process.env.AWS_REGION || 'us-east-1' });
    const ddbDocClient = DynamoDBDocumentClient.from(client);
    

    Penempatan baris ini di luar fungsi handler memastikan bahwa objek klien SDK dipertahankan selama siklus hidup kontainer Lambda (Warm Container). Hal ini menghilangkan overhead pembuatan koneksi TCP baru pada setiap permintaan masuk.

  3. Single-Table Design pada DynamoDB (PK dan SK): Pola penamaan PK: ITEM#${itemId} dan SK: METADATA#${itemId} memungkinkan penyimpanan berbagai entitas bisnis (misal: User, Order, Item) di dalam satu tabel fisik yang sama, menghindari operasi JOIN yang mahal dan memastikan latensi konstan berskala milidetik.


7. Skenario Produksi & Studi Kasus Dunia Nyata

Dalam skenario penerapan sistem Flash Sale e-commerce dengan perkiraan 50.000 permintaan per detik (requests per second), arsitektur serverless ini menunjukkan ketahanan yang luar biasa:

  • API Gateway secara otomatis mendistribusikan beban masuk tanpa memerlukan pemeliharaan load balancer manual.
  • DynamoDB dikonfigurasi dengan mode pembayaran On-Demand (PAY_PER_REQUEST), yang secara dinamis menyesuaikan kapasitas throughput tanpa memerlukan Provisioned Capacity pra-alokasi.
  • Lambda Concurrency dikontrol menggunakan Reserved Concurrency untuk memastikan fungsi kritikal tidak kehabisan alokasi kuota eksekusi global akun AWS.

8. Common Pitfalls, Anti-Patterns & Solusi

[!WARNING] Anti-Pattern Utama: Melakukan inisialisasi koneksi database atau SDK di dalam handler fungsi Lambda. Hal ini akan memicu TCP handshake baru pada setiap permintaan, memperlambat waktu tanggap (latency), dan memicu rate limiting pada layanan AWS.

Kesalahan umum lainnya meliputi:

  • Mengabaikan ukuran deployment package: Mengunggah node_modules yang membengkak (>50MB) akan memperpanjang waktu pembongkaran kode saat Cold Start. Solusinya: gunakan bundler seperti esbuild atau Webpack untuk meminimalkan ukuran file zip fungsi Lambda.
  • Scan vs Query pada DynamoDB: Menggunakan operasi SCAN pada tabel besar akan membaca seluruh item dan menghabiskan unit kapasitas baca secara masif. Selalu gunakan QUERY berdasarkan Partition Key dan Sort Key.

9. Benchmark, Metrik Kinerja & Tuning Performa

Untuk menguji ketahanan performa API yang telah dibangun, kita dapat menggunakan tool benchmark modern seperti k6.

Buat file skrip pengujian load-test.js:

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '30s', target: 100 }, // Naikkan ke 100 virtual users dalam 30 detik
    { duration: '1m', target: 500 },  // Pertahankan beban di 500 virtual users
    { duration: '30s', target: 0 },   // Turunkan kembali ke 0
  ],
};

export default function () {
  const url = 'https://<your-api-id>.execute-api.us-east-1.amazonaws.com/items/12345';
  const params = {
    headers: {
      'Authorization': 'Bearer <valid-jwt-token>',
    },
  };

  const res = http.get(url, params);
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 200ms': (r) => r.timings.duration < 200,
  });
  sleep(1);
}

Jalankan pengujian dengan perintah:

k6 run load-test.js

Metrik utama yang harus dievaluasi meliputi P99 Latency, Error Rate (< 0.1%), dan Throttling Count pada DynamoDB.


10. Checklist Penerapan Produksi & Kesimpulan

Sebelum merilis arsitektur ini ke lingkungan produksi publik, pastikan seluruh item dalam checklist berikut telah terpenuhi:

  • Mengaktifkan AWS X-Ray untuk Distributed Tracing dan analisis performa end-to-end.
  • Menetapkan Reserved Concurrency pada fungsi Lambda kritikal guna mencegah lonjakan lalu lintas tak terduga menghabiskan kuota region.
  • Menerapkan Lambda Insights atau CloudWatch Alarms untuk memantau lonjakan Cold Start dan error rate 5xx.
  • Memastikan seluruh peran IAM menerapkan prinsip Least Privilege (hak akses sekecil mungkin).
  • Menggunakan esbuild/bundler untuk mengompresi kode Lambda di bawah ambang batas 5MB.

Dengan memadukan optimalisasi Cold Start, desain Single-Table DynamoDB yang efisien, serta otorisasi API yang aman, arsitektur serverless Anda kini siap menangani beban skala enterprise secara stabil, cepat, dan efisien dari segi biaya.

🏷️ Tags: #Nginx #High Concurrency #Performance #Sysadmin #Web Server