Redis, chiamato anche Remote Dictionary Server, è un database in-memory open source. È un sistema di memorizzazione basato su strutture dati che viene eseguito sulla RAM di un server, il che è molto più veloce del più rapido Solid State Drive (SSD). Di conseguenza, Redis è molto reattivo e si adatta perfettamente al rate limiting.
Il rate limiting limita il numero di volte in cui un utente può richiedere una risorsa a un server. Molti servizi utilizzano i limiti di frequenza per prevenire l'abuso del servizio, ad esempio quando un utente tenta di sovraccaricare un server con un carico eccessivo. Ad esempio, quando si utilizza PHP per sviluppare un' API (Application Programming Interface) pubblica per la tua applicazione web, sono necessarie limitazioni di frequenza. Questo perché quando esponi un'API al pubblico, vorrai limitare il numero di volte in cui un individuo può ripetere un'attività in un determinato periodo di tempo. Gli utenti che non hanno autorità sul tuo sistema potrebbero causarne il blocco.
Il rate limiting consente alla tua applicazione di funzionare senza problemi rifiutando le richieste degli utenti che superano un limite stabilito. Se hai un gran numero di client, la limitazione della frequenza impone una politica di fair-use che consente a ciascun utente di accedere alla tua applicazione a velocità elevate. Il rate limiting può anche aiutarti a risparmiare denaro sulla larghezza di banda riducendo la congestione sul tuo server.
Tracciando l'attività dell'utente in un database come MySQL, sarebbe possibile creare un programma di rate limiting. Tuttavia, poiché tali dati dovrebbero essere scaricati dal disco e valutati rispetto al limite definito, il risultato finale potrebbe non essere scalabile quando più persone contattano il sistema. Non solo questo è inefficiente, ma le soluzioni di gestione di database relazionali non sono state progettate per questo.
Redis è un'ottima scelta per creare un rate limiter perché funziona come un database in-memory ed è stato dimostrato essere affidabile per questo. In questo tutorial, ti guideremo attraverso i passaggi per implementare il rate limiting in PHP utilizzando Redis su Ubuntu 20.04.
Cominciamo!
Prerequisiti
Per seguire questo tutorial, avrai bisogno di quanto segue:
-
L'ultima versione di Ubuntu installata sul tuo sistema.
-
Gli utenti di sistema devono avere privilegi sudo.
-
Uno stack LAMP.
-
Configuralo seguendo il tutorial Come configurare lo stack LAMP.
-
-
Un server Redis.
-
Segui la guida Come installare e proteggere il server Redis per configurare Redis nel tuo sistema.
-
Passaggio 1: Installa l'estensione Redis per PHP
Prima di iniziare, aggiorniamo i repository per evitare conflitti tra pacchetti:
|
1 |
sudo apt update |
Successivamente, installa l'estensione php-redis, un pacchetto che rende possibile l'utilizzo di Redis nei programmi PHP. Esegui il seguente comando sudo per installare php-redis:
|
1 |
sudo apt install -y php-redis |
Dopodiché, riavvia il server Apache per caricare la libreria php-redis:
|
1 |
sudo systemctl restart apache2 |
Il passaggio successivo consiste nell'aggiornare le informazioni nel tuo indice software e installare la libreria Redis per PHP. Successivamente, creeremo una risorsa PHP che limita l'accesso in base all'indirizzo IP dell'utente.
Passaggio 2: Crea una risorsa web PHP per il rate limiting
In questo passaggio, creerai un file demo.php nella directory principale del tuo server web ( /var/www/html/). Questo file sarà aperto al pubblico e gli utenti potranno aprire l'URL nel loro browser web preferito. Successivamente, utilizzeremo il comando curl per verificare l'accessibilità della risorsa che vogliamo utilizzare. Gli utenti possono accedere al file di risorsa di esempio tre volte in un intervallo di 15 secondi. Un tentativo che supera il limite massimo genererà un messaggio di errore.
La funzionalità principale di questo file dipende fortemente dal server Redis. Il codice PHP nel file crea una chiave sul server Redis in base all'indirizzo IP dell'utente quando l'utente accede alla risorsa per la prima volta. Il codice tenterà di far corrispondere l'indirizzo IP dell'utente con las chiavi salvate nel server Redis e aumenterà il valore di uno se la chiave esiste quando l'utente torna alla risorsa. Il codice PHP continuerà a controllare se il nuovo valore ha raggiunto il limite massimo.
Dopo 15 secondi, la chiave Redis, che si basa sull’indirizzo IP dell’utente, scadrà e il tracciamento delle visite dell’utente alla risorsa web ricomincerà. Apri il /var/www/html/demo.php file nel nano editor di testo:
|
1 |
sudo nano /var/www/html/demo.php |
Quindi, compila tutti i campi per inizializzare la classe Redis. Non dimenticare di impostare il REDIS_PASSWORD al valore corretto:
|
1 2 3 4 |
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('REDIS_PASSWORD'); |
Redis->auth supporta l’autenticazione in testo normale del server Redis. Questo funziona bene se stai lavorando localmente (tramite localhost), ma se hai a che fare con un server Redis remoto, l’autenticazione SSL è consigliata.
Successivamente, nello stesso file, imposta le seguenti variabili sui loro valori predefiniti:
|
1 2 3 4 5 |
. . . $max_calls_limit = 3; $time_period = 15; $total_user_calls = 0; |
Comprendiamo queste istruzioni nel dettaglio:
-
$max_calls_limit: Un utente non può accedere alla risorsa oltre questo limite massimo di chiamate.
-
$time_period: Questo viene utilizzato come intervallo di tempo ed è calcolato in secondi. Qui, l'utente è autorizzato ad accedere alla risorsa secondo i limiti impostati nel $max_calls_limit .
-
$total_user_calls: Somma il numero di volte in cui un utente ha richiesto l'accesso alla chiamate limite in un determinato periodo di tempo.
Quindi, aggiungi il seguente codice per ottenere l'indirizzo IP del richiedente che chiede di accedere alla pagina web:
|
1 2 3 4 5 6 7 8 9 10 |
. . . if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $user_ip_address = $_SERVER['HTTP_CLIENT_IP']; } elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $user_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $user_ip_address = $_SERVER['REMOTE_ADDR']; } |
A scopo dimostrativo, questo codice registra le azioni degli utenti in base ai loro indirizzi IP. Se hai una risorsa protetta sul server che richiede l'autenticazione, puoi tracciare le azioni degli utenti utilizzando i loro nomi utente o token di accesso.
Nella nostra guida, a ogni utente che accede al tuo sistema verrà assegnato un identificativo unico (ad esempio, un ID cliente, un ID sviluppatore, un ID fornitore o persino un ID utente). Ricorda di utilizzare questi ID al posto dell' $user_ip indirizzo se stai seguendo il nostro tutorial.
Qui, l'indirizzo IP dell'utente è sufficiente per dimostrare il concetto. Aggiungi il seguente blocco di codice al tuo file una volta ottenuto l'indirizzo IP dell'utente dallo snippet di codice precedente:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
. . . if (!$redis->exists($user_ip_address)) { $redis->set($user_ip_address, 1); $redis->expire($user_ip_address, $time_period); $total_user_calls = 1; } else { $redis->INCR($user_ip_address); $total_user_calls = $redis->get($user_ip_address); if ($total_user_calls > $max_calls_limit) { echo "User " . $user_ip_address . " limit exceeded."; exit(); } } echo "Benvenuto " . $user_ip_address . " chiamate totali effettuate " . $total_user_calls . " in " . $time_period . " secondi"; |
Ecco una panoramica di queste istruzioni:
-
if...else: L'istruzione verifica se sul server Redis è definita una chiave con l'indirizzo IP.
-
Se la chiave non viene trovata, if (!$redis->exists($user_ip_address)) {...}, puoi impostare la chiave e definirne il valore a 1 usando $redis->set($user_ip_address, 1).
-
-
$redis->expire($user_ip_address, $time_period): Imposta la scadenza della chiave a un tempo specificato. In questo tutorial, l'abbiamo impostata su 15 secondi.
-
Se l'indirizzo IP dell'utente non viene trovato nella chiave Redis, imposta la variabile $total_user_calls valore come 1.
-
else {...}: Il blocco di istruzioni utilizza il comando $redis->INCR($user_ip_address); per incrementare il valore della chiave Redis di 1. Questo verrà applicato a ciascun indirizzo IP associato alla chiave.
-
Nota: Puoi ottenere questo risultato solo quando la chiave è già impostata nel server Redis e conteggiata come richiesta ripetuta.
-
-
$total_user_calls = $redis->get($user_ip_address): Questa istruzione recupera le richieste totali verificando la rispettiva chiave basata sull'indirizzo IP sul server Redis.
-
if ($total_user_calls > $max_calls_limit) {... }..: Questa istruzione if viene utilizzata per verificare il superamento del limite. In caso positivo, notifichi l'utente con echo "Utente" . $user_ip_address . " limite superato.";.
Infine, notifichi all'utente il numero di visite in un periodo specificato utilizzando l'istruzione echo "Benvenuto" . $user_ip_address . "chiamate totali effettuate" . $total_user_calls . "in" . $time_period . "secondi";.
Dopodiché, aggiungi le seguenti righe di codice nel tuo file /var/www/html/demo.php:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?php $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('REDIS_PASSWORD'); $max_calls_limit = 3; $time_period = 15; $total_user_calls = 0; if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $user_ip_address = $_SERVER['HTTP_CLIENT_IP']; }elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $user_ip_address = $_SERVER['HTTP_X_FORWARDED_FOR']; } else { $user_ip_address = $_SERVER['REMOTE_ADDR']; } if (!$redis->exists($user_ip_address)) { $redis->set($user_ip_address, 1); $redis->expire($user_ip_address, $time_period); $total_user_calls = 1; } else { $redis->INCR($user_ip_address); $total_user_calls = $redis->get($user_ip_address); if ($total_user_calls > $max_calls_limit) { echo "Utente " . $user_ip_address . " limite superato."; exit(); } } echo "Benvenuto " . $user_ip_address . " chiamate totali effettuate " . $total_user_calls . " in " . $time_period . " secondi"; ?> |
Salva e chiudi il file /var/www/html/demo.php dopo aver finito di modificarlo. Sulla pagina web demo.php, hai ora creato la logica richiesta per limitare la frequenza delle richieste degli utenti. Testiamo il nostro script nel passaggio successivo.
Passaggio 3: Esegui il test di limitazione della frequenza di Redis
Utilizzerai il comando curl in questo passaggio per richiedere la risorsa web che hai scritto nel Passaggio 2. Per testare a fondo lo script, invia un singolo comando che richieda la risorsa cinque volte. Questo può essere ottenuto aggiungendo un argomento URL segnaposto a demo.php fine del file. Per eseguire le curl istruzioni cinque volte, usa il valore ?[1-5] alla fine della tua richiesta.
Esegui il seguente curl comando qui sotto:
|
1 |
curl -H "Accept: text/plain" -H "Content-Type: text/plain" -X GET http://localhost/demo.php?[1-5] |
Quando esegui il codice, dovresti ottenere qualcosa di simile a questo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[1/5]: http://localhost/demo.php?1 --> <stdout> --_curl_--http://localhost/demo.php?1 Benvenuto 127.0.0.1 totale chiamate effettuate 1 in 15 secondi [2/5]: http://localhost/demo.php?2 --> <stdout> --_curl_--http://localhost/demo.php?2 Benvenuto 127.0.0.1 totale chiamate effettuate 2 in 15 secondi [3/5]: http://localhost/demo.php?3 --> <stdout> --_curl_--http://localhost/demo.php?3 Benvenuto 127.0.0.1 totale chiamate effettuate 3 in 15 secondi [4/5]: http://localhost/demo.php?4 --> <stdout> --_curl_--http://localhost/demo.php?4 Utente 127.0.0.1 limite superato. [5/5]: http://localhost/demo.php?5 --> <stdout> --_curl_--http://localhost/demo.php?5 Utente 127.0.0.1 limite superato. |
Le prime tre richieste, come puoi vedere, sono andate a buon fine senza problemi. La quarta e la quinta query, tuttavia, sono state limitate dal tuo script. C'è una buona probabilità che il server Redis stia rallentando la velocità con cui gli utenti possono effettuare query.
Hai specificato valori bassi per le due variabili elencate di seguito in questa guida:
|
1 2 3 4 |
... $max_calls_limit = 3; $time_period = 15; ... |
Quando crei la tua app in un ambiente di produzione, potresti voler considerare l'uso di numeri più grandi, a seconda di quanto spesso pensi che le persone la useranno.
È una buona idea esaminare le statistiche in tempo reale prima di regolare questi numeri. In questo esempio, se i log del tuo server mostrano che un utente medio visita la tua applicazione 1.000 volte ogni 60 secondi, puoi usare quel numero come esempio di quanta limitazione applicare.
Conclusione
In questa guida, hai imparato come utilizzare un server Redis con PHP su Ubuntu 20.04. Sebbene questo articolo mostri come funziona la limitazione della frequenza (rate limiting) con Redis, puoi personalizzarlo per soddisfare le esigenze della tua applicazione web. Ti invitiamo a esplorare esempi reali come limite massimo di richieste di Twitter, Custom Search JSON API di Google, e altra documentazione simile per approfondire la tua conoscenza sulla limitazione della frequenza e provare a sperimentare tu stesso utilizzando diversi limiti di tempo.
Inoltre, ci sono molti altri materiali di apprendimento su Redis e PHP a cui puoi accedere dai nostri blog:
- Distribuire un'applicazione PHP su un cluster Kubernetes con Ubuntu 18.04
- Installazione e messa in sicurezza di phpMyAdmin su Ubuntu 20.04
- Come installare lo stack LEMP (Linux Nginx MySQL PHP) su Ubuntu 20.04
Buona programmazione!
Commenti
Ancora nessun commento. Scrivi il primo.