Pendahuluan
Selamat datang di part 32 dari seri tutorial Pemrograman & Komputer ini! Pada part sebelumnya, kita telah mempelajari cara membangun komunikasi real-time menggunakan WebSockets. Sekarang, kita akan melangkah lebih jauh dengan membahas topik penting dalam pengembangan aplikasi web, yaitu Rate Limiting. Rate limiting adalah teknik untuk membatasi jumlah permintaan yang dapat dibuat oleh pengguna atau klien dalam periode waktu tertentu. Implementasi yang efektif akan melindungi aplikasi Anda dari penyalahgunaan, serangan DDoS, dan memastikan ketersediaan layanan bagi semua pengguna.
Dalam tutorial ini, kita akan menggunakan Redis, sebuah in-memory data structure store yang sangat cepat, untuk mengimplementasikan rate limiting. Redis sangat cocok untuk tugas ini karena kemampuannya untuk melakukan operasi atomik dan menyimpan data sementara.
Prasyarat:
- Pemahaman dasar tentang HTTP request dan response.
- Pengetahuan dasar tentang Redis (instalasi dan penggunaan dasar).
- PHP diinstal dan dikonfigurasi.
- Composer (untuk manajemen dependencies PHP).
- Part sebelumnya tentang WebSockets: Mastering WebSockets for Real-Time Communication
Konsep Dasar
Rate limiting pada dasarnya adalah menerapkan kebijakan yang membatasi frekuensi akses ke suatu resource. Bayangkan sebuah klub malam dengan pintu masuk yang ketat. Hanya sejumlah orang yang diizinkan masuk setiap menitnya. Ini mencegah kerumunan dan memastikan semua orang di dalam memiliki pengalaman yang menyenangkan. Dalam dunia aplikasi web, rate limiting berfungsi serupa: mencegah banjirnya permintaan yang dapat membebani server dan mengganggu layanan.
Mengapa Rate Limiting Penting?
- Keamanan: Mencegah brute-force attacks (misalnya, percobaan login berulang-ulang).
- Ketersediaan: Melindungi server dari lonjakan traffic yang tidak terduga.
- Pengalaman Pengguna: Memastikan semua pengguna mendapatkan respons yang cepat dan andal.
- Kontrol Biaya: Membatasi penggunaan sumber daya yang berlebihan.
Algoritma Rate Limiting Umum:
- Token Bucket: Mirip ember yang diisi token secara berkala. Setiap permintaan mengambil satu token. Jika ember kosong, permintaan ditolak.
- Leaky Bucket: Mirip ember yang bocor. Permintaan masuk ke ember, dan ember bocor dengan kecepatan tetap. Jika ember penuh, permintaan ditolak.
- Fixed Window Counter: Menghitung jumlah permintaan dalam jangka waktu tertentu (misalnya, satu menit). Jika jumlahnya melebihi batas, permintaan ditolak hingga jendela waktu berikutnya.
- Sliding Window Log: Mencatat setiap permintaan dengan timestamp. Menghitung jumlah permintaan dalam jendela waktu geser.
Dalam tutorial ini, kita akan menggunakan pendekatan Fixed Window Counter dengan Redis karena kesederhanaannya dan kemampuannya untuk memberikan kinerja yang baik.
Hands-on Coding
Kita akan membuat middleware PHP sederhana yang menggunakan Redis untuk menerapkan rate limiting.
Langkah 1: Instalasi Redis dan Predis (PHP Client)
Pastikan Redis sudah terinstal dan berjalan di server Anda. Kemudian, instal Predis, library PHP untuk berinteraksi dengan Redis, menggunakan Composer:
composer require predis/predis
Langkah 2: Membuat Middleware Rate Limiter
Buat file PHP bernama `RateLimiterMiddleware.php`:
redis = $redis;
$this->limit = $limit; // Jumlah request per periode
$this->period = $period; // Periode dalam detik
}
public function handle(Request $request, callable $next):
Response
{
$ip = $request->getClientIp();
$key = 'rate_limit:' . $ip;
$count = $this->redis->incr($key);
if ($count === 1) {
$this->redis->expire($key, $this->period);
}
if ($count > $this->limit) {
return new Response(
'Terlalu banyak permintaan. Silakan coba lagi nanti.',
429, // HTTP status code untuk Too Many Requests
['Content-Type' => 'text/plain']
);
}
return $next($request);
}
}
Penjelasan Kode:
- `namespace App\Middleware;`: Mendefinisikan namespace untuk middleware kita.
- `use Predis\Client;`: Mengimport class `Client` dari library Predis.
- `use Symfony\Component\HttpFoundation\Request;` dan `use Symfony\Component\HttpFoundation\Response;`: Mengimport class Request dan Response dari Symfony HTTP Foundation.
- `__construct(Client $redis, int $limit = 100, int $period = 60)`: Constructor yang menerima instance Redis client, limit jumlah request, dan periode waktu. Defaultnya adalah 100 request per 60 detik.
- `handle(Request $request, callable $next)`: Method utama middleware. Method ini menerima objek Request dan callable $next (closure yang akan menjalankan request selanjutnya dalam pipeline).
- `$ip = $request->getClientIp();`: Mendapatkan IP address dari client.
- `$key = 'rate_limit:' . $ip;`: Membuat key Redis berdasarkan IP address.
- `$count = $this->redis->incr($key);`: Mengincrement counter di Redis untuk key tersebut. Jika key belum ada, Redis akan membuat key baru dengan nilai 0 dan kemudian mengincrement menjadi 1. Operasi ini bersifat atomik.
- `if ($count === 1) { $this->redis->expire($key, $this->period); }`: Jika ini adalah request pertama dari IP address ini dalam periode ini, set TTL (Time To Live) untuk key tersebut. Setelah periode waktu berakhir, key akan dihapus secara otomatis oleh Redis.
- `if ($count > $this->limit)`: Memeriksa apakah jumlah request melebihi limit. Jika ya, mengembalikan response dengan status code 429 (Too Many Requests).
- `return $next($request);`: Jika jumlah request belum melebihi limit, memanggil $next untuk meneruskan request ke handler selanjutnya.
Langkah 3: Menggunakan Middleware dalam Aplikasi Anda
Contoh penggunaan dalam aplikasi PHP (misalnya, menggunakan framework seperti Slim atau Laravel):
'tcp',
'host' => '127.0.0.1',
'port' => 6379,
]);
$rateLimiter = new RateLimiterMiddleware($redis, 5, 10); // 5 request per 10 detik
$app->add(function (Request $request, Response $response, callable $next) use ($rateLimiter) {
return $rateLimiter->handle($request, $next);
});
$app->get('/api/data', function (Request $request, Response $response) {
$response->getBody()->write(json_encode(['message' => 'Success!']));
return $response->withHeader('Content-Type', 'application/json');
});
$app->run();
Penjelasan:
- Membuat instance Redis client.
- Membuat instance `RateLimiterMiddleware` dengan Redis client, limit 5 request, dan periode 10 detik.
- Menambahkan middleware ke aplikasi.
- Route `/api/data` yang akan dilindungi oleh rate limiter.
Common Pittfalls
- Lupa menginstal Redis atau Predis. Pastikan kedua komponen ini terinstal dan terkonfigurasi dengan benar.
- Salah konfigurasi Redis. Pastikan Redis berjalan di host dan port yang benar.
- Tidak menangani exception dari Redis. Jika Redis tidak tersedia, middleware Anda akan gagal. Tambahkan error handling untuk menangani kasus ini.
- Menggunakan IP address client yang tidak akurat. Jika aplikasi Anda berada di belakang load balancer atau proxy, Anda mungkin perlu menggunakan header `X-Forwarded-For` untuk mendapatkan IP address client yang sebenarnya.
- Tidak mempertimbangkan autentikasi. Rate limiting berdasarkan IP address mungkin tidak cukup jika Anda memiliki pengguna yang terautentikasi. Pertimbangkan untuk menggunakan ID pengguna sebagai kunci untuk rate limiting.
Challenge
Modifikasi middleware rate limiter untuk menggunakan ID pengguna (jika tersedia) sebagai kunci rate limiting, selain atau sebagai pengganti IP address.
Sumber Referensi