Kapan Harus Menggunakan ElastiCache Redis: Solusi Cache untuk RDS yang Lambat
RDS mulai terasa berat bukan karena query-nya kompleks, tapi karena query yang sama dieksekusi ratusan kali per menit untuk data yang jarang berubah. Ini adalah skenario klasik di mana menambahkan lapisan ElastiCache Redis antara aplikasi dan database bisa memotong latensi secara dramatis tanpa menyentuh skema atau kode query sama sekali.
TL;DR: ElastiCache Redis sebagai Cache Layer untuk RDS
| Aspek | Tanpa Cache | Dengan ElastiCache Redis |
|---|---|---|
| Latensi read | Puluhan hingga ratusan ms (RDS) | Sub-milidetik (Redis in-memory) |
| Beban RDS | Semua read query ke DB | Hanya cache miss yang sampai ke DB |
| Skalabilitas read | Terbatas kapasitas RDS | Horizontal via Redis cluster/replica |
| Kompleksitas operasional | Rendah | Perlu strategi invalidasi cache |
| Biaya | Upgrade instance RDS mahal | Node Redis lebih murah untuk read-heavy |
Bagaimana ElastiCache Redis Bekerja sebagai Cache Layer
Redis adalah in-memory data store yang menyimpan data dalam RAM, bukan disk. Ketika aplikasi membutuhkan data, ia pertama-tama memeriksa Redis. Jika data ada (cache hit), respons langsung dikembalikan tanpa menyentuh RDS. Jika tidak ada (cache miss), aplikasi mengambil dari RDS, menyimpan hasilnya ke Redis dengan TTL tertentu, lalu mengembalikan ke client.
Pola ini disebut cache-aside (lazy loading) — pola paling umum untuk read-heavy workload. Aplikasi mengontrol penuh apa yang masuk cache dan kapan data diperbarui.
- Cache Hit: Aplikasi query ke Redis, data ditemukan, langsung dikembalikan ke client. RDS tidak disentuh.
- Cache Miss: Redis tidak punya data, aplikasi fallback ke RDS, hasil disimpan ke Redis dengan TTL, baru dikembalikan ke client.
- Write Path: Pada operasi tulis ke RDS, aplikasi menginvalidasi atau memperbarui entry Redis yang relevan agar data tidak stale.
Kapan ElastiCache Redis Layak Digunakan
Tidak semua masalah performa RDS diselesaikan dengan cache. Sebelum menambahkan Redis, pastikan workload memenuhi kriteria berikut:
- Read-heavy dengan data repetitif: Query yang sama dieksekusi berulang untuk data yang jarang berubah — misalnya katalog produk, konfigurasi sistem, atau hasil agregasi harian.
- Toleransi terhadap data stale: Aplikasi bisa menerima data yang mungkin beberapa detik atau menit tertinggal dari kondisi aktual database.
- Latensi menjadi bottleneck: RDS CPU dan I/O masih rendah, tapi latensi query tinggi karena volume koneksi dan antrian query.
- Pola akses yang dapat diprediksi: Ada subset data yang diakses jauh lebih sering dari yang lain — Redis paling efektif untuk data 'panas' ini.
Sebaliknya, Redis bukan solusi tepat jika data berubah setiap detik, jika konsistensi kuat diperlukan, atau jika masalah sebenarnya ada di query yang tidak dioptimasi (missing index, N+1 query).
Membuat ElastiCache Redis Cluster
Langkah pertama adalah membuat subnet group yang menentukan VPC dan subnet mana yang akan digunakan oleh cluster Redis. Cluster harus berada di VPC yang sama dengan RDS dan aplikasi agar komunikasi internal bisa terjadi tanpa melewati internet.
# Buat subnet group untuk ElastiCache
aws elasticache create-cache-subnet-group \
--cache-subnet-group-name my-redis-subnet-group \
--cache-subnet-group-description "Subnet group untuk Redis cache" \
--subnet-ids subnet-0abc12345 subnet-0def67890
Setelah subnet group siap, buat replication group Redis. Menggunakan replication group (bukan single node) memberikan ketersediaan tinggi dengan automatic failover ke replica jika primary node gagal.
# Buat Redis replication group dengan Multi-AZ
aws elasticache create-replication-group \
--replication-group-id my-redis-cluster \
--replication-group-description "Cache layer untuk RDS read queries" \
--cache-node-type cache.r7g.large \
--engine redis \
--engine-version 7.0 \
--num-cache-clusters 2 \
--cache-subnet-group-name my-redis-subnet-group \
--security-group-ids sg-0abc123456789 \
--automatic-failover-enabled \
--at-rest-encryption-enabled \
--transit-encryption-enabled
Verifikasi status cluster hingga statusnya menjadi available:
aws elasticache describe-replication-groups \
--replication-group-id my-redis-cluster \
--query 'ReplicationGroups[0].{Status:Status,PrimaryEndpoint:NodeGroups[0].PrimaryEndpoint}' \
--output table
Konfigurasi Security Group
Security group Redis harus mengizinkan inbound traffic pada port 6379 hanya dari security group aplikasi — bukan dari CIDR block yang luas. Ini memastikan hanya instance aplikasi yang bisa mengakses Redis, bukan semua resource di subnet.
# Izinkan akses Redis dari security group aplikasi
aws ec2 authorize-security-group-ingress \
--group-id sg-0abc123456789 \
--protocol tcp \
--port 6379 \
--source-group sg-0app987654321
Implementasi Cache-Aside Pattern di Aplikasi
Pola cache-aside menempatkan logika caching di sisi aplikasi. Ini memberikan kontrol penuh atas apa yang di-cache dan kapan invalidasi terjadi, tapi membutuhkan penanganan eksplisit di kode.
🔽 Klik untuk melihat contoh implementasi Python (redis-py)
import redis
import json
import boto3
from typing import Optional
# Inisialisasi Redis client
# Gunakan primary endpoint untuk write, reader endpoint untuk read
redis_client = redis.Redis(
host='my-redis-cluster.abc123.ng.0001.use1.cache.amazonaws.com',
port=6379,
ssl=True, # Wajib jika transit-encryption-enabled
decode_responses=True
)
def get_product_catalog(category_id: str) -> Optional[dict]:
cache_key = f"product:catalog:{category_id}"
# Langkah 1: Cek cache terlebih dahulu
cached_data = redis_client.get(cache_key)
if cached_data:
return json.loads(cached_data) # Cache hit
# Langkah 2: Cache miss - ambil dari RDS
db_result = query_rds_for_catalog(category_id) # Query ke RDS
if db_result:
# Langkah 3: Simpan ke cache dengan TTL 300 detik
redis_client.setex(
name=cache_key,
time=300,
value=json.dumps(db_result)
)
return db_result
def invalidate_product_cache(category_id: str):
# Panggil ini setiap kali data produk diupdate di RDS
cache_key = f"product:catalog:{category_id}"
redis_client.delete(cache_key)
Perhatikan penggunaan setex yang menggabungkan SET dan EXPIRE dalam satu operasi atomik. Ini mencegah race condition di mana key tersimpan tapi TTL belum diset ketika terjadi kegagalan di antara dua operasi terpisah.
Menentukan TTL yang Tepat
TTL adalah trade-off antara freshness data dan efisiensi cache. Tidak ada nilai universal yang benar — TTL harus mencerminkan seberapa sering data berubah dan seberapa besar toleransi aplikasi terhadap data stale.
- Data konfigurasi sistem: TTL panjang (1-24 jam) karena jarang berubah.
- Katalog produk / harga: TTL menengah (5-30 menit) tergantung frekuensi update.
- Hasil query agregasi: TTL sesuai interval refresh (misalnya 1 jam jika laporan diperbarui per jam).
- Data sesi pengguna: TTL pendek (15-30 menit) dengan sliding expiration.
Konfigurasi Eviction Policy
Ketika Redis kehabisan memori, eviction policy menentukan key mana yang dihapus untuk memberi ruang bagi data baru. Untuk use case cache, allkeys-lru adalah pilihan yang paling umum — Redis akan menghapus key yang paling lama tidak diakses, terlepas dari apakah key tersebut memiliki TTL atau tidak.
Untuk melihat eviction policy yang aktif pada cluster, ada dua cara:
Melalui AWS Management Console: Buka halaman detail cluster di ElastiCache Console, pilih tab Parameter group, lalu cari parameter maxmemory-policy.
Melalui AWS CLI: Proses dua langkah — pertama dapatkan nama parameter group dari deskripsi cluster, lalu query parameter group tersebut.
# Langkah 1: Dapatkan nama parameter group dari cluster
aws elasticache describe-cache-clusters \
--query 'CacheClusters[?contains(CacheClusterId, `my-redis-cluster`)].CacheParameterGroup.CacheParameterGroupName' \
--output text
# Langkah 2: Lihat nilai maxmemory-policy dari parameter group tersebut
# Ganti 'default.redis7' dengan nama parameter group dari langkah 1
aws elasticache describe-cache-parameters \
--cache-parameter-group-name default.redis7 \
--query 'Parameters[?ParameterName==`maxmemory-policy`].{Name:ParameterName,Value:ParameterValue}' \
--output table
Untuk mengubah eviction policy, buat custom parameter group (karena default group tidak bisa dimodifikasi) lalu assign ke cluster:
# Buat custom parameter group
aws elasticache create-cache-parameter-group \
--cache-parameter-group-name my-redis7-params \
--cache-parameter-group-family redis7 \
--description "Custom params dengan allkeys-lru"
# Set eviction policy
aws elasticache modify-cache-parameter-group \
--cache-parameter-group-name my-redis7-params \
--parameter-name-values ParameterName=maxmemory-policy,ParameterValue=allkeys-lru
Memantau Efektivitas Cache dengan CloudWatch
Setelah Redis aktif, metrik paling penting untuk dipantau adalah cache hit rate — rasio antara cache hit dan total request. Hit rate yang rendah (di bawah 80%) mengindikasikan TTL terlalu pendek, key space terlalu besar untuk memori yang tersedia, atau pola akses yang tidak cocok untuk caching.
# Lihat CacheHits dan CacheMisses dalam 1 jam terakhir
aws cloudwatch get-metric-statistics \
--namespace AWS/ElastiCache \
--metric-name CacheHits \
--dimensions Name=CacheClusterId,Value=my-redis-cluster-0001-001 \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics Sum \
--output table
# Pantau penggunaan memori
aws cloudwatch get-metric-statistics \
--namespace AWS/ElastiCache \
--metric-name DatabaseMemoryUsagePercentage \
--dimensions Name=CacheClusterId,Value=my-redis-cluster-0001-001 \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--period 300 \
--statistics Average \
--output table
Jika DatabaseMemoryUsagePercentage konsisten di atas 80%, pertimbangkan untuk menaikkan ukuran node atau mengaktifkan cluster mode untuk distribusi data horizontal.
Pengalaman Lapangan: Misdiagnosis yang Sering Terjadi
Skenario yang sering muncul: tim menambahkan Redis, cache hit rate mencapai 90%, tapi latensi RDS tidak turun signifikan. Dugaan awal — ada bug di implementasi cache. Investigasi lebih dalam menunjukkan sesuatu yang berbeda.
Ternyata ada dua kelompok query: query katalog produk yang memang berhasil di-cache, dan query laporan real-time yang tidak pernah di-cache karena parameternya selalu berbeda (filter tanggal dinamis, kombinasi filter pengguna). Kelompok kedua ini justru yang menghasilkan query paling berat ke RDS, dan Redis sama sekali tidak membantu untuk mereka.
Pelajarannya: cache hit rate agregat bisa menyembunyikan masalah. Segmentasi metrik per jenis query — bukan hanya total hit/miss — adalah satu-satunya cara untuk memastikan cache benar-benar mengurangi beban pada query yang paling mahal.
Redis seperti meja kerja — data yang sering dipakai ada di atas meja, bukan di lemari arsip (RDS). Tapi kalau setiap dokumen yang diambil berbeda, meja kerja tidak membantu. Yang perlu dioptimasi adalah dokumen mana yang layak ditaruh di atas meja.
IAM untuk Akses ElastiCache dari Aplikasi
Untuk aplikasi yang berjalan di EC2 atau ECS, gunakan IAM role dengan permission minimal. Akses ke ElastiCache Redis sendiri dikontrol melalui kombinasi Security Group (network level) dan Redis AUTH token atau IAM authentication (jika menggunakan ElastiCache dengan IAM auth yang didukung pada engine tertentu). Untuk operasi manajemen cluster via AWS API, berikut contoh policy minimal:
🔽 Klik untuk melihat IAM policy untuk operasi monitoring ElastiCache
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ElastiCacheReadOnly",
"Effect": "Allow",
"Action": [
"elasticache:DescribeReplicationGroups",
"elasticache:DescribeCacheClusters",
"elasticache:DescribeCacheParameters",
"elasticache:ListTagsForResource"
],
"Resource": "*"
},
{
"Sid": "CloudWatchElastiCacheMetrics",
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricStatistics",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}
Catatan: DescribeReplicationGroups dan DescribeCacheClusters memerlukan "Resource": "*" karena tidak mendukung resource-level restriction pada operasi List/Describe. Verifikasi ini di Service Authorization Reference untuk ElastiCache.
Kapan ElastiCache Redis Tidak Cukup
Ada situasi di mana Redis sudah terpasang dengan benar tapi masalah performa RDS tetap ada. Ini biasanya berarti bottleneck bukan di read volume, tapi di tempat lain:
- Write-heavy workload: Cache tidak membantu operasi INSERT/UPDATE/DELETE yang berat. Pertimbangkan RDS Proxy untuk connection pooling atau read replica untuk offload read analytics.
- Query tidak dioptimasi: Query dengan full table scan atau missing index akan tetap lambat bahkan jika dipanggil sekali. EXPLAIN ANALYZE di PostgreSQL/MySQL harus jadi langkah pertama sebelum menambahkan cache.
- Connection exhaustion: Jika RDS kehabisan koneksi, tambahkan RDS Proxy — bukan Redis. Redis tidak mengurangi jumlah koneksi aktif ke database untuk query yang tetap lolos cache.
sama berulang?"} Q2{"Apakah data
jarang berubah?"} Q3{"Apakah ada
missing index?"} Q4{"Apakah koneksi
DB exhausted?"} Q5{"Apakah write
sangat tinggi?"} SolCache["ElastiCache Redis
(Cache-Aside Pattern)"] SolIndex["Optimasi Query
& Tambah Index"] SolProxy["RDS Proxy
(Connection Pooling)"] SolReplica["RDS Read Replica
atau Aurora"] Start --> Q1 Q1 -->|Ya| Q2 Q1 -->|Tidak| Q3 Q2 -->|Ya| SolCache Q2 -->|Tidak| Q3 Q3 -->|Ya| SolIndex Q3 -->|Tidak| Q4 Q4 -->|Ya| SolProxy Q4 -->|Tidak| Q5 Q5 -->|Ya| SolReplica Q5 -->|Tidak| SolCache
- Identifikasi bottleneck: Jika masalah adalah read volume dengan data repetitif, ElastiCache Redis adalah solusi tepat.
- Query tidak optimal: Perbaiki query dan tambahkan index terlebih dahulu — cache tidak menyembunyikan query yang buruk selamanya.
- Write-heavy atau connection exhaustion: RDS Proxy atau read replica lebih relevan dari Redis untuk skenario ini.
Wrap-Up: ElastiCache Redis untuk RDS yang Lebih Responsif
Menambahkan ElastiCache Redis sebagai cache layer adalah salah satu cara paling efektif untuk mengurangi beban RDS pada workload read-heavy. Kuncinya adalah memilih data yang tepat untuk di-cache (data repetitif dengan toleransi stale), menentukan TTL yang sesuai dengan frekuensi perubahan data, dan memantau cache hit rate per segmen query — bukan hanya secara agregat.
Langkah selanjutnya yang direkomendasikan:
- Tinjau dokumentasi resmi ElastiCache untuk Redis untuk fitur terbaru termasuk ElastiCache Serverless.
- Eksplorasi RDS Proxy jika connection pooling juga menjadi masalah.
- Pertimbangkan ElastiCache Global Datastore jika aplikasi berjalan di multiple AWS region dan membutuhkan cache dengan latensi rendah di setiap region.
Glosarium
| Istilah | Definisi |
|---|---|
| Cache Hit | Kondisi di mana data yang diminta ditemukan di Redis, sehingga tidak perlu query ke RDS. |
| Cache Miss | Kondisi di mana data tidak ada di Redis, sehingga aplikasi harus fallback ke RDS. |
| Cache-Aside Pattern | Pola caching di mana aplikasi bertanggung jawab mengisi dan menginvalidasi cache secara eksplisit. |
| TTL (Time To Live) | Durasi sebuah key Redis tetap valid sebelum otomatis dihapus. |
| Eviction Policy | Aturan yang menentukan key mana yang dihapus Redis ketika memori penuh. |
Komentar
Posting Komentar