Pada industri perkeretaapian seperti Union Pacific (UP), rel baja memuai ekstrem saat terpapar suhu tinggi dan berisiko melengkung (sun kink). UP mengantisipasinya dengan memantau panas dan mengecat rel menjadi putih sebelum ambang batas kritis tercapai. Dalam arsitektur sistem terdistribusi, Redis mengalami kondisi serupa yang disebut thermal throttling cache: beban throughput tinggi memicu fragmentasi, memori menembus batas maxmemory, dan siklus CPU habis untuk alokasi ulang sinkron serta stop-the-world eviction.
Artikel ini membahas konfigurasi dan strategi proaktif untuk memitigasi degradasi latensi Redis sebelum memicu Out Of Memory (OOM) atau lonjakan tajam pada tail latency p99.
1. Gejala Thermal Throttling pada Redis Cluster
Saat Redis mendekati batas kapasitas tanpa mitigasi awal, dua fenomena degradasi performa terjadi secara bersamaan:
- Sinkronisasi Eviction Blocking: Redis mengeksekusi perintah pada single-threaded event loop. Jika memori mencapai
maxmemory, thread utama dipaksa mencari key kadaluarsa atau melakukan kalkulasi eviksi sebelum mengeksekusi operasi baca/tulis baru, sehinggaused_cpu_sysnaik tajam. - Fragmentasi Memori (High
mem_fragmentation_ratio): Alokator seperti jemalloc sering mengalokasikan ukuran blok statis. Operasi mutasi key berukuran variatif menyebabkan fragmentasi tinggi (> 1.5). Sistem operasi mulai melakukan swapping ke disk yang melipatgandakan latensi baca. - Kaskade Failover: Node cluster yang terlambat mengirimkan detak jantung
PING/PONGakibat thread terblokir akan dianggap mati oleh sentry/master lain, memicu rebalance dan failover yang tidak perlu saat trafik puncak.
2. Proactive Eviction Policy dan Early Invalidation Dinamis
Mengandalkan eviksi reaktif bawaan Redis saat memori 100% penuh adalah kegagalan desain. Dua strategi berikut memotong beban kerja eviksi thread utama:
Perbandingan: volatile-lru vs allkeys-lfu
Gunakan konfigurasi yang tepat sesuai pola beban:
volatile-lru: Membatasi eviksi hanya pada key yang memiliki TTL berbasis waktu akses terakhir. Risiko: jika data non-TTL bertambah, Redis tetap menabrak error OOMOOM command not allowed.allkeys-lfu: Memantau Least Frequently Used menggunakan counter frekuensi probabilistik (Morris counter) untuk seluruh namespace. Pilihan terbaik untuk cache murni guna memastikan key bernilai rendah dibuang lebih awal.
Terapkan via konfigurasi:
maxmemory 4gb
maxmemory-policy allkeys-lfu
maxmemory-samples 10Dynamic TTL Invalidation dengan Jitter
Mencegah thundering herd dan beban eviksi terkonsentrasi pada detik yang sama dengan menerapkan delta random (jitter) pada layer aplikasi:
import math
import random
import time
def calculate_dynamic_ttl(base_ttl: int, current_memory_ratio: float) -> int:
"""
Memperpendek TTL saat kapasitas memori Redis meningkat (Early Invalidation).
Analog dengan mengecat rel lebih awal saat sensor suhu rel mendeteksi panas naik.
"""
# Jitter 10% untuk mencegah key expired bersamaan
jitter = random.randint(-int(base_ttl * 0.1), int(base_ttl * 0.1))
# Jika penggunaan memori > 80%, kompres TTL secara proporsional
if current_memory_ratio > 0.8:
compression_factor = 1.0 - (current_memory_ratio - 0.8) * 3
compression_factor = max(0.2, compression_factor) # Batas bawah 20%
return int((base_ttl * compression_factor) + jitter)
return base_ttl + jitter3. Tuning Active Defragmentation dan Maxmemory Samples
Secara default, Redis mengorbankan ketepatan algoritma eviksi demi throughput pemrosesan. Nilai default maxmemory-samples 5 sering membuang key yang salah (false eviction). Naikkan sampel ke 10 untuk akurasi mendekati true-LRU/LFU dengan overhead CPU yang terukur.
Aktifkan defragmentasi memori latar belakang untuk alokator jemalloc tanpa mengorbankan latensi p99:
# Aktifkan active defrag
activedefrag yes
# Mulai defrag jika fragmentasi mencapai minimal 100MB
active-defrag-ignore-bytes 100mb
# Mulai defrag jika rasio fragmentasi > 1.25 (25% memori terbuang)
active-defrag-threshold-lower 25
# Defrag agresif maksimal jika rasio > 1.50
active-defrag-threshold-upper 50
# Alokasi CPU minimum untuk defrag agar latensi thread utama aman
active-defrag-cycle-min 5
# Alokasi CPU maksimum saat batas upper tercapai
active-defrag-cycle-max 25
# Jumlah komputasi per siklus tick jemalloc
active-defrag-max-scan-fields 10004. Simulasi Benchmark Beban Tinggi dan Observabilitas Latency p99
Gunakan skrip Python dengan koneksi pool asinkron untuk menyimulasikan lonjakan beban dan mengukur tail latency p99 saat proses eviksi berjalan.
import asyncio
import numpy as np
import redis.asyncio as redis
import time
async def stress_worker(r: redis.Redis, worker_id: int, iterations: int, latencies: list):
for i in range(iterations):
key = f"sensor_rail_{worker_id}_{i % 500}"
val = "x" * 1024 # Payload 1KB
start = time.perf_counter()
# Pipeline write + read
async with r.pipeline(transaction=False) as pipe:
pipe.set(key, val, ex=60)
pipe.get(key)
await pipe.execute()
latency = (time.perf_counter() - start) * 1000 # ms
latencies.append(latency)
await asyncio.sleep(0.001)
async def main():
pool = redis.ConnectionPool(host="127.0.0.1", port=6379, max_connections=50)
r = redis.Redis(connection_pool=pool)
latencies = []
print("Memulai benchmark beban eviksi...")
tasks = [stress_worker(r, w, 200, latencies) for w in range(20)]
await asyncio.gather(*tasks)
await pool.disconnect()
# Hitung metrik latency percentiles
p50 = np.percentile(latencies, 50)
p95 = np.percentile(latencies, 95)
p99 = np.percentile(latencies, 99)
print(f"p50 Latency : {p50:.2f} ms")
print(f"p95 Latency : {p95:.2f} ms")
print(f"p99 Latency : {p99:.2f} ms")
if __name__ == "__main__":
asyncio.run(main())Metrik Kunci Observabilitas
Pantau metrik berikut secara berkala menggunakan perintah CLI:
redis-cli --latency-dist: Menampilkan sebaran distribusi latensi secara berkala langsung dari soket engine.redis-cli info stats | grep evicted_keys: Periksa laju key yang dibuang per detik. Lonjakan mendadak mengindikasikanmaxmemoryterlalu rendah atau dynamic TTL tidak berjalan efektif.redis-cli latency latest: Memeriksa subsistem Redis mana (sepertieviction-delataudefrag-cycle) yang menyebabkan spike latency lebih dari 10 milidetik.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!