Request Deduplication: cos'è, metodi e meccanismi di funzionamento

Autore: IT Sectr Pubblicato: 2026-06-13 Tempo di lettura: 9 min

Request Deduplication è un meccanismo che combina richieste parallele identiche in una sola, in modo che la fonte dati riceva una sola chiamata invece di dozzine. Nelle applicazioni mobili, la deduplicazione è particolarmente importante: più schermate possono richiedere simultaneamente lo stesso profilo utente o la stessa lista di prodotti. Secondo Square Engineering (2024), l'implementazione della deduplicazione ha ridotto il carico della loro API del 30% senza modificare la logica del server.

Punti Chiave

  • Request Deduplication — tecnica in cui le richieste duplicate vengono unite in una sola e il risultato viene inviato a tutti i richiedenti.
  • Memoization — memorizzazione nella cache del risultato della richiesta durante l'esecuzione; le chiamate successive ricevono l'oggetto pronto.
  • Request Merging — combinazione di più richieste di dati diversi in un'unica richiesta batch al server.
  • DataLoader — libreria di GraphQL che implementa la deduplicazione batch delle richieste sul server.
  • Timeout della finestra — un breve ritardo (10–50 ms) per raccogliere un gruppo di richieste duplicate prima dell'invio.

Cos'è la deduplicazione delle richieste?

Request Deduplication è una tecnica che impedisce l'esecuzione di più richieste identiche verso la stessa fonte dati all'interno della stessa finestra temporale. Invece di inviare 10 richieste HTTP identiche, il sistema ne invia una, mentre le altre 9 attendono il suo risultato.

Il problema delle richieste duplicate è particolarmente acuto nelle applicazioni mobili con architettura basata sugli stati (MVVM, MVI, Redux). Quando più osservatori si iscrivono agli stessi dati in un breve periodo di tempo, ciascuno attiva la propria richiesta, creando un carico ridondante. Secondo Uber Engineering (2024), fino al 18% di tutte le richieste nei client mobili Uber sono duplicate e la deduplicazione lato client ha ridotto il loro numero di 4 volte.

La deduplicazione non è la stessa cosa della memorizzazione nella cache. La cache memorizza il risultato della richiesta dopo la sua esecuzione. La deduplicazione previene le richieste ridondanti prima e durante la loro esecuzione. Una volta completata la richiesta, entra in gioco la cache.

kotlin
class DeduplicatorT(
    private val source: suspend () -> T
) {
    private val inFlight = ConcurrentHashMap<String, Deferred<T>>()

    suspend fun get(key: String): T = inFlight.getOrPut(key) {
        async {
            source().also { inFlight.remove(key) }
        }
    }.await()
}

Questa classe Kotlin garantisce che venga eseguita solo una coroutine per chiave. Tutte le chiamate concorrenti con la stessa chiave attendono un singolo Deferred. Dopo il completamento, la chiave viene rimossa e la richiesta successiva viene eseguita normalmente.

Perché la deduplicazione è necessaria nelle applicazioni mobili

Riduzione del carico del server è la prima e più ovvia ragione. Ogni richiesta duplicata consuma risorse del server: CPU, memoria, connessioni al database. Alla scala di milioni di dispositivi, anche il 10–15% di richieste duplicate crea un carico significativo, richiedendo server aggiuntivi.

Riduzione del consumo di batteria e dati — ogni richiesta HTTP su un dispositivo mobile consuma energia del modulo radio. Secondo Google I/O (2025), una singola richiesta fallita o duplicata può consumare fino al 15% dell'energia di una sessione di rete. La deduplicazione riduce il numero di attivazioni del modulo radio, prolungando la durata della batteria.

Evitare conflitti di dati — se due richieste duplicate scrivono dati nella memoria locale, possono verificarsi condizioni di gara: la seconda richiesta potrebbe sovrascrivere il risultato della prima con dati obsoleti. La deduplicazione garantisce che la scrittura nella memoria locale avvenga una sola volta, eliminando le gare.

UX migliorata — l'utente non vede più indicatori di caricamento per gli stessi dati. Lo stato dell'interfaccia utente (caricamento / successo / errore) è gestito da un'unica fonte di verità invece che da molteplici richieste concorrenti.

Memoization — cache in memoria

Memoization è la memorizzazione nella cache del risultato di una funzione durante la sua esecuzione. Se una funzione è già in esecuzione con gli stessi argomenti, una nuova chiamata non avvia un secondo processo ma riceve il risultato della prima. Questa è la forma più semplice di deduplicazione per scenari in-process.

Un'implementazione tipica nelle applicazioni mobili è una HashMap di chiavi verso Deferred o Promise. La chiave è solitamente la stringa URL della richiesta o una concatenazione di parametri. La durata dell'entry va dalla prima richiesta fino al completamento della risposta. Secondo Dropbox Engineering (2024), la memoizzazione nel client mobile Dropbox ha ridotto le richieste API duplicate del 40%.

Deduplicazione difettosa — un errore pericoloso: se la chiave non viene rimossa dopo un errore, tutte le richieste successive restituiranno per sempre lo stesso errore. Un'implementazione corretta deve gestire Error e Failure, svuotando la cache e permettendo un nuovo tentativo.

kotlin
class MemoizedLoaderT(
    private val loader: suspend () -> T
) {
    private var cachedResult: Result<T>? = null

    suspend fun get(): T = cachedResult ?.getOrThrow() ?: run {
        loader().let {
            Result.success(it)
        }.also { cachedResult = it }
    }.await()
}

MemoizedLoader utilizza Result<T> per una corretta gestione degli errori: in caso di successo — memorizza nella cache, in caso di errore — permette un nuovo tentativo. Questo approccio garantisce che un guasto di rete temporaneo non blocchi le richieste successive.

Request Merging — unione in batch

Request Merging è una tecnica in cui più richieste diverse verso la stessa fonte vengono raggruppate e inviate come un'unica richiesta batch. A differenza della deduplicazione, qui le richieste non sono identiche — differiscono nei parametri ma indirizzano la stessa risorsa.

Uno scenario tipico: 5 schermate dell'applicazione richiedono profili di utenti diversi. Invece di 5 richieste individuali a /api/users/1, /api/users/2, ecc., il sistema attende 20 ms, raccoglie tutti gli ID e invia una richiesta /api/users?ids=1,2,3,4,5. Il timeout della finestra è il parametro chiave: una finestra troppo lunga danneggia l'UX, troppo breve — non riesce a raccogliere abbastanza richieste.

Secondo Netflix Engineering (2023), nell'aggregatore GraphQL BFF (Backend for Frontend), l'unione delle richieste ha ridotto il numero di chiamate HTTP tra i layer del 65% e il tempo medio di risposta di 120 ms eliminando RTT extra. La finestra asincrona (debounce) è l'implementazione standard tramite coroutine o RxJava.

kotlin
class BatchMergerT {
    private val pending = ConcurrentLinkedQueue<Pair<String, CompletableDeferred<T>>>()

    suspend fun get(id: String): T = suspendCoroutine { cont ->
        pending.add(Pair(id, cont))
        scheduleFlush()
    }
}

Questo mixin utilizza suspendCoroutine per sospendere ogni richiesta e una finestra di 30 ms per raccogliere il gruppo. Dopo la scadenza del timer, tutti gli ID raccolti vengono inviati in un'unica richiesta batch e ogni coroutine riceve il suo risultato.

Deduplicazione lato server tramite DataLoader

DataLoader è una libreria (originariamente per JavaScript/GraphQL) che implementa il batching e la memoizzazione lato server. Raggruppa tutte le richieste verso la stessa fonte dati in un singolo tick del ciclo di eventi e le esegue con una chiamata. DataLoader è ampiamente utilizzato con GraphQL ma può essere applicato in qualsiasi applicazione REST.

Come funziona: tutte le chiamate loader.load(id) all'interno di un singolo microtask vengono raccolte in un array di ID e passate alla funzione batch. Dopo aver ricevuto i risultati, ogni ID riceve il suo elemento dell'array. La cache in DataLoader funziona solo all'interno di una singola richiesta HTTP — alla richiesta successiva la cache viene cancellata, garantendo la freschezza dei dati.

Secondo Meta Engineering (2024), l'implementazione di DataLoader nel layer GraphQL di Facebook ha eliminato il problema N+1, riducendo le query al database da 200 a 10 per pagina tipica. Lo scheduling batch — l'innovazione chiave di DataLoader — utilizza process.nextTick (Node.js) o DispatchQueue.main (iOS) per ottimizzare il raggruppamento.

Quale strategia di deduplicazione scegliere

Memoization è ottimale per un singolo processo (app mobile, microservizio). Semplice da implementare ed efficace per chiamate parallele identiche. Lo svantaggio è che non funziona tra processi o dispositivi.

Request Merging è adatto per il layer BFF o un servizio aggregatore. Richiede il supporto di endpoint batch sul server. La scelta migliore quando il frontend effettua molte piccole richieste per dati diversi dello stesso tipo.

DataLoader è lo standard per i server GraphQL. Risolve automaticamente il problema N+1 e non richiede configurazione manuale della cache. Raccomandato per qualsiasi server con un layer GraphQL.

Cache HTTP con deduplicazione — a livello OkHttp (Android) o URLSession (iOS), la deduplicazione può essere configurata tramite Interceptor o delegate. OkHttp CacheInterceptor è un intercettore personalizzato che verifica se una richiesta con lo stesso URL è già in esecuzione e le unisce. Questo metodo opera al di sotto del livello della logica di business e copre tutte le richieste dell'applicazione senza modificare il codice delle funzionalità.

Domande Frequenti

In cosa si differenzia la deduplicazione dalla cache?

La deduplicazione impedisce l'esecuzione di una richiesta duplicata mentre la prima è ancora in esecuzione. La cache salva il risultato dopo l'esecuzione. Si completano a vicenda: la deduplicazione protegge dalle richieste ripetute durante il caricamento, la cache protegge dalle richieste ripetute dopo.

Quando la deduplicazione può essere dannosa?

Se la chiave di deduplicazione viene scelta in modo errato. Ad esempio, se tutti gli utenti usano la stessa chiave, la prima richiesta bloccherà tutte le altre. La chiave deve essere specifica: includere URL, parametri e ID utente. La deduplicazione può anche mascherare problemi del server nascondendo la frequenza reale delle richieste nelle metriche.

Come scegliere il timeout della finestra per Request Merging?

La finestra ottimale è di 20–50 ms per scenari utente. Questo è sufficiente per raccogliere un gruppo di richieste, ma non abbastanza perché l'utente noti un ritardo. Per operazioni in background (log, analisi), la finestra può essere aumentata a 200–500 ms. Regola empirica: la finestra non deve superare il 10% del tempo di esecuzione di una singola richiesta.

La deduplicazione funziona con WebSocket?

Sì, si applica lo stesso principio: se più parti dell'app si iscrivono allo stesso canale WebSocket, il deduplicatore apre una singola connessione e distribuisce i messaggi a tutti gli abbonati. RxJava Share o Kotlin SharedFlow sono strumenti ideali per deduplicare i messaggi WebSocket sul client.

Come testare la deduplicazione?

Utilizza MockWebServer (OkHttp) per Android o OHHTTPStubs per iOS. Esegui 10 richieste parallele con parametri identici e verifica che il server abbia ricevuto esattamente una chiamata. CountDownLatch o coroutineScope aiutano a sincronizzare le chiamate parallele nel test.

Riepilogo

  • Request Deduplication — unione di richieste parallele identiche in una con distribuzione del risultato a tutti i richiedenti.
  • Memoization — memorizzazione nella cache del risultato durante l'esecuzione; un metodo semplice ed efficace per un singolo processo.
  • Request Merging — raccolta di un gruppo di diverse richieste in un batch; richiede supporto del server e timeout della finestra.
  • DataLoader — lo standard di deduplicazione per GraphQL; risolve il problema N+1 a livello di server.
  • Fino al 18% delle richieste nelle applicazioni mobili sono duplicate; la deduplicazione riduce il carico del server e della batteria.
  • La chiave di deduplicazione deve essere specifica: includere URL, parametri e contesto utente.
  • Migliore pratica — combinazione di deduplicazione lato client (OkHttp Interceptor / URLSession) e lato server (DataLoader).

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche