Arsitektur & Desain Sistem
distlimit dirancang khusus untuk mengatasi masalah bottleneck performa, risiko thundering herd, dan contention lock global yang umum terjadi pada library rate-limiting tradisional.
Diagram Arsitektur Tingkat Tinggi
Section titled “Diagram Arsitektur Tingkat Tinggi”flowchart TD
Req[HTTP / gRPC Incoming Request] --> Shield[Trusted Proxies Check]
Shield --> Limiter[distlimit Limiter]
subgraph CoreEngine [Core Execution Engine]
direction LR
Limiter --> Alg[Pluggable Algorithms]
Limiter --> Driver[Storage Drivers]
end
CoreEngine --> Observer[metrics Observer Engine]
Komponen Utama Arsitektur
Section titled “Komponen Utama Arsitektur”1. Concurrent Memory Map 64-Shard
Section titled “1. Concurrent Memory Map 64-Shard”Go map standar yang dilindungi oleh satu sync.RWMutex mengalami lock contention parah di bawah beban kerja multi-threaded tinggi.
distlimit menyelesaikan masalah ini dengan membagi penyimpanan key ke dalam 64 shard independen:
type Driver struct { shards [64]*shard}- Indeks Shard: Penentuan posisi key dihitung via hashing
fnv32a:shardIndex = hash(key) % 64. - Granularitas Lock: Setiap shard memiliki
sync.RWMutexsendiri. Request konkuren yang menargetkan key berbeda akan mengakses shard yang berbeda secara paralel, menghilangkan bottleneck lock global. - Eliminasi Jeda GC: Struktur entri penyimpanan dioptimalkan untuk pengaplikasian ulang di memori, menjaga alokasi tetap pada
0 B/op.
2. Redis Cluster Hash Tags {} & Skrip Lua Atomik
Section titled “2. Redis Cluster Hash Tags {} & Skrip Lua Atomik”Rate limiting terdistribusi membutuhkan evaluasi status secara atomik di seluruh node Redis untuk mencegah race condition.
Cluster Hash Tags {}
Section titled “Cluster Hash Tags {}”Saat beroperasi di dalam Redis Cluster, operasi yang melibatkan beberapa key harus menargetkan hash slot yang sama untuk menghindari error CROSSSLOT. distlimit membungkus nama key Redis dalam hash tag: distlimit:{key}.
Redis menghitung hash slot hanya menggunakan karakter di dalam {}. Ini menjamin semua operasi untuk suatu key rate-limiting dieksekusi pada node slot cluster yang sama.
Eksekusi Skrip Lua Atomik
Section titled “Eksekusi Skrip Lua Atomik”Semua transisi status algoritma (refill token, pembersihan timestamp, inkremen counter) ditulis dalam skrip Lua teroptimasi. Redis mengeksekusi skrip Lua secara atomik dalam single thread, menjamin zero race condition antar node aplikasi terdistribusi.
3. Dual-Tier Hybrid Driver & Half-Open Circuit Breaker
Section titled “3. Dual-Tier Hybrid Driver & Half-Open Circuit Breaker”Driver Hybrid melapisi driver Redis utama di atas driver fallback In-Memory sekunder:
flowchart TD
Req[Incoming Request] --> Hybrid[Hybrid Driver]
Hybrid -->|Primary OK| Redis[Redis Driver]
Hybrid -->|Primary Fail| CB[Circuit Breaker - Cool-Off State]
Redis -->|Error| CB
CB --> Memory[Failover Memory Driver]
Siklus Hidup Transisi Status
Section titled “Siklus Hidup Transisi Status”- Normal Flow (Closed): Semua pemeriksaan rate limit dieksekusi ke Redis Primary.
- Failover (Open): Jika Redis mengembalikan error jaringan atau timeout koneksi, Circuit Breaker langsung terbuka. Request langsung dialihkan ke driver In-Memory 64-Shard lokal tanpa memblokir request client.
- Durasi Cool-Off: Driver berada dalam mode fallback selama durasi terkonfigurasi (default:
5 detik), meredam panggilan jaringan yang gagal ke Redis. - Half-Open Probing: Setelah timer cool-off habis, driver Hybrid memasuki mode Half-Open. Satu goroutine melakukan uji coba (probe) ke Redis menggunakan lock atomik
CompareAndSwap(false, true).- Jika uji coba berhasil, Circuit Breaker menutup dan operasi normal ke Redis dilanjutkan.
- Jika uji coba gagal, timer cool-off di-reset. Ini mencegah lonjakan Thundering Herd ke node Redis yang sedang pulih.
4. Engine Dynamic Policy Lock-Free
Section titled “4. Engine Dynamic Policy Lock-Free”distlimit menggunakan atomic.Pointer[Policy] untuk menyimpan aturan rate limit yang aktif:
type Limiter struct { policy atomic.Pointer[Policy]}Saat limiter.UpdatePolicy(newLimit, newWindow) dipanggil saat runtime:
- Struct
Policybaru dialokasikan. policy.Store()melakukan swap pointer secara atomik.
Goroutine yang mengeksekusi AllowKey() membaca pointer via policy.Load(). Ini memberikan kemampuan pembaruan aturan secara realtime tanpa downtime dan tanpa lock contention dengan latensi nanodetik $O(1)$.