Request Deduplication: ano ito, mga pamamaraan at mekanismo ng paggana

May-akda: IT Sectr Nai-publish: 2026-06-13 Oras ng pagbabasa: 9 min

Request Deduplication — ay isang mekanismo ng pagsasama-sama ng magkakaparehong parallel na kahilingan sa iisa, upang ang pinagmulan ng data ay makatanggap lamang ng isang tawag sa halip na dose-dosenang. Sa mga mobile application, ang deduplikasyon ay lalong mahalaga: maraming screen ay maaaring sabay na humiling ng parehong profile ng user o listahan ng produkto. Ayon sa Square Engineering (2024), ang pagpapatupad ng deduplikasyon ay nagbawas ng karga sa kanilang API ng 30% nang hindi binabago ang lohika ng server.

Mga Pangunahing

  • Request Deduplication — teknik kung saan ang mga duplicate na kahilingan ay pinagsama sa iisa, at ang resulta ay ipinapadala sa lahat ng nagpasimula.
  • Memoization — pag-cache ng resulta ng kahilingan habang isinasagawa; ang mga paulit-ulit na tawag ay tumatanggap ng handa na object.
  • Request Merging — pagsasama-sama ng maraming kahilingan ng magkakaibang data sa isang batch request sa server.
  • DataLoader — aklatan mula sa GraphQL na nagpapatupad ng batched request deduplication sa server.
  • Timeout ng window — maikling pagkaantala (10–50 ms) para tipunin ang grupo ng mga duplicate na kahilingan bago ipadala.

Ano ang deduplikasyon ng kahilingan?

Request Deduplication — ay isang teknik na pumipigil sa pagsasagawa ng maraming magkakaparehong kahilingan sa iisang pinagmulan ng data sa loob ng isang window ng oras. Sa halip na magpadala ng 10 magkakaparehong HTTP request, ang sistema ay nagpapadala ng isa, at ang iba pang 9 ay naghihintay sa resulta nito.

Ang problema ng mga duplicate na kahilingan ay lalo na talamak sa mga mobile application na may arkitekturang nakabatay sa estado (MVVM, MVI, Redux). Kapag maraming tagamasid ang nag-subscribe sa parehong data sa maikling panahon, bawat isa ay naglulunsad ng sarili nitong kahilingan, na lumilikha ng labis na karga. Ayon sa Uber Engineering (2024), hanggang 18% ng lahat ng kahilingan sa mga mobile client ng Uber ay mga duplicate, at ang deduplikasyon sa client ay nagbawas ng bilang nito ng 4 na beses.

Ang deduplikasyon ay hindi katulad ng pag-cache. Ang cache ay nag-iimbak ng resulta ng kahilingan pagkatapos ng pagsasagawa nito. Pinipigilan ng deduplikasyon ang labis na kahilingan bago at habang isinasagawa ang mga ito. Pagkatapos makumpleto ang kahilingan, ang cache ay pumapasok at iniimbak ang resulta.

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()
}

Ang Kotlin class na ito ay ginagarantiyahan na para sa bawat key, isang coroutine lamang ang isinasagawa. Lahat ng parallel na tawag na may parehong key ay naghihintay ng isang Deferred. Pagkatapos makumpleto, ang key ay tatanggalin at ang susunod na kahilingan ay isasagawa nang normal.

Bakit kailangan ang deduplikasyon sa mga mobile application

Pagbawas ng karga sa server — una at pinaka-halatang dahilan. Bawat duplicate na kahilingan ay kumukonsumo ng mga mapagkukunan ng server: CPU, memorya, mga koneksyon sa database. Sa sukat ng milyun-milyong device, kahit 10–15% na mga duplicate na kahilingan ay lumilikha ng malaking karga na nangangailangan ng karagdagang server.

Pagtitipid ng baterya at trapiko — bawat HTTP request sa isang mobile device ay kumukonsumo ng enerhiya ng radio module. Ayon sa Google I/O (2025), isang nabigo o duplicate na kahilingan ay maaaring kumonsumo ng hanggang 15% ng enerhiya ng isang network session. Binabawasan ng deduplikasyon ang bilang ng pag-activate ng radio module, na nagpapahaba ng oras ng paggana ng device sa baterya.

Pag-iwas sa mga salungatan ng data — kung ang dalawang duplicate na kahilingan ay sumusulat ng data sa lokal na imbakan, maaaring magkaroon ng race condition: maaaring i-overwrite ng pangalawang kahilingan ang resulta ng una gamit ang lumang data. Ginagarantiyahan ng deduplikasyon na ang pagsulat sa lokal na imbakan ay isinasagawa nang isang beses, na inaalis ang mga kondisyon ng karera.

Pagpapabuti ng UX — ang user ay hindi nakakakita ng maramihang loading indicator para sa parehong data. Ang estado ng UI (loading / success / error) ay pinamamahalaan ng iisang source ng katotohanan, hindi ng maraming magkakalabang kahilingan.

Memoization — pag-cache sa memorya

Memoization (memoisasyon) — ay pag-cache ng resulta ng isang function habang ito ay isinasagawa. Kung ang function ay isinasagawa na gamit ang parehong mga argumento, ang bagong tawag ay hindi maglulunsad ng pangalawang proseso, bagkus ay tatanggap ng resulta ng una. Ito ang pinakasimpleng anyo ng deduplikasyon para sa mga in-process na sitwasyon.

Karaniwang implementasyon sa mga mobile application — HashMap ng mga key sa Deferred o Promise. Ang key ay karaniwang URL string ng kahilingan o kumbinasyon ng mga parameter. Ang habang-buhay ng record — mula sa unang kahilingan hanggang sa pagkumpleto ng tugon. Ayon sa Dropbox Engineering (2024), ang memoisasyon sa Dropbox mobile client ay nagbawas ng bilang ng mga duplicate na kahilingan sa API ng 40%.

Flawed deduplication — mapanganib na pagkakamali: kung hindi mo tatanggalin ang key pagkatapos ng error, lahat ng susunod na kahilingan ay palaging magbabalik ng parehong error. Ang tamang implementasyon ay dapat humawak ng Error at Failure, linisin ang cache, at payagan ang muling pagsubok.

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()
}

Ang MemoizedLoader ay gumagamit ng Result<T> para sa tamang paghawak ng error: sa tagumpay — nag-ca-cache, sa error — nagpapahintulot ng muling pagsubok. Ang approach na ito ay ginagarantiyahan na ang pansamantalang pagkabigo ng network ay hindi haharang sa mga susunod na kahilingan.

Request Merging — pagsasama-sama sa batch

Request Merging (pagsasama-sama ng kahilingan) — teknik kung saan maraming magkakaibang kahilingan sa iisang source ay tinipon sa isang grupo at ipinapadala bilang isang batch request. Hindi tulad ng deduplikasyon, ang mga kahilingan ay hindi magkakapareho — nagkakaiba sa mga parameter, ngunit tumutukoy sa parehong resource.

Karaniwang senaryo: 5 screen ng application ay humihiling ng mga profile ng magkakaibang user. Sa halip na 5 indibidwal na kahilingan sa /api/users/1, /api/users/2 atbp., ang sistema ay naghihintay ng 20 ms, tinipon ang lahat ng ID, at nagpapadala ng isang kahilingan /api/users?ids=1,2,3,4,5. Timeout ng window — pangunahing parameter: ang sobrang haba ng window ay nagpapalala ng UX, ang sobrang ikli ay hindi nagpapahintulot na makapagtipon ng sapat na kahilingan.

Ayon sa Netflix Engineering (2023), sa GraphQL BFF (Backend for Frontend) aggregator, ang pagsasama-sama ng kahilingan ay nagbawas ng bilang ng HTTP tawag sa pagitan ng mga layer ng 65% at average na oras ng tugon ng 120 ms sa pamamagitan ng pag-aalis ng labis na RTT. Asynchronous window (debounce) — karaniwang implementasyon sa pamamagitan ng 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()
    }
}

Ang mixin na ito ay gumagamit ng suspendCoroutine upang i-suspend ang bawat kahilingan at window na 30 ms upang tipunin ang grupo. Pagkatapos ng timer, lahat ng natipong ID ay ipapadala sa isang batch request, at bawat coroutine ay tatanggap ng sarili nitong resulta.

Deduplikasyon sa server sa pamamagitan ng DataLoader

DataLoader — ay isang aklatan (orihinal para sa JavaScript/GraphQL) na nagpapatupad ng batching at memoisasyon sa panig ng server. Pinagpapangkat nito ang lahat ng kahilingan sa iisang source ng data sa loob ng isang tick ng event loop at isinasagawa ang mga ito sa isang tawag. Ang DataLoader ay malawakang ginagamit sa GraphQL, ngunit maaaring ilapat sa anumang REST application.

Prinsipyo ng paggana: lahat ng tawag na loader.load(id) sa loob ng isang microtask ay tinipon sa isang array ng ID at ipinapasa sa batch function. Pagkatapos matanggap ang mga resulta, bawat ID ay tatanggap ng sarili nitong elemento ng array. Pag-cache sa DataLoader ay gumagana lamang sa loob ng isang HTTP request — sa susunod na kahilingan, ang cache ay ni-reset, na ginagarantiyahan ang pagiging bago ng data.

Ayon sa Meta Engineering (2024), ang pagpapatupad ng DataLoader sa GraphQL layer ng Facebook ay nag-alis ng N+1 na problema, na nagbawas ng bilang ng mga database query mula 200 hanggang 10 bawat tipikal na page. Batch scheduling — pangunahing inobasyon ng DataLoader — gumagamit ng process.nextTick (Node.js) o DispatchQueue.main (iOS) para i-optimize ang pagpapangkat.

Aling strategy ng deduplikasyon ang pipiliin

Memoization — optimal para sa isang proseso (mobile app, microservice). Simple i-implement at epektibo para sa magkakaparehong parallel na tawag. Disbentaha — hindi gumagana sa pagitan ng mga proseso o device.

Request Merging — angkop para sa BFF layer o aggregator service. Nangangailangan ng suporta sa batch endpoint sa server. Pinakamahusay na pagpipilian kapag ang frontend ay gumagawa ng maraming maliliit na kahilingan sa magkakaibang data ng parehong uri.

DataLoader — standard ng deduplikasyon para sa mga GraphQL server. Awtomatikong nilulutas ang N+1 na problema at hindi nangangailangan ng manual na configuration ng cache. Inirerekomenda para sa anumang server na may GraphQL layer.

HTTP cache na may deduplikasyon — sa antas ng OkHttp (Android) o URLSession (iOS) ay maaaring i-configure ang deduplikasyon sa pamamagitan ng Interceptor o delegate. OkHttp CacheInterceptor — custom na interceptor na sumusuri kung ang isang kahilingan na may parehong URL ay isinasagawa na at pinagsasama ang mga ito. Ang pamamaraang ito ay gumagana sa antas na mas mababa kaysa sa business logic at sumasaklaw sa lahat ng kahilingan ng application nang hindi binabago ang code ng feature.

Mga Madalas Itanong

Ano ang pagkakaiba ng deduplikasyon sa pag-cache?

Ang deduplikasyon ay pumipigil sa pagsasagawa ng duplicate na kahilingan habang ang una ay isinasagawa pa. Ang pag-cache ay nag-iimbak ng resulta pagkatapos ng pagsasagawa. Sila ay nagpupuno sa isa't isa: pinoprotektahan ng deduplikasyon laban sa mga paulit-ulit na kahilingan habang naglo-load, ang cache — laban sa mga paulit-ulit na kahilingan pagkatapos.

Kailan maaaring makasama ang deduplikasyon?

Kung ang key ng deduplikasyon ay napili nang hindi tama. Halimbawa, kung ang lahat ng user ay gumagamit ng iisang key, ang unang kahilingan ay haharang sa lahat ng iba pa. Ang key ay dapat na tiyak: isama ang URL, mga parameter, ID ng user. Gayundin, maaaring itago ng deduplikasyon ang mga problema sa server sa pamamagitan ng pagtatakip sa tunay na dalas ng mga kahilingan sa mga metrik.

Paano pumili ng timeout ng window para sa Request Merging?

Optimal na window — 20–50 ms para sa mga senaryo ng user. Ito ay sapat upang tipunin ang isang grupo ng mga kahilingan, ngunit hindi sapat para mapansin ng user ang pagkaantala. Para sa mga background operation (logs, analytics), ang window ay maaaring itaas sa 200–500 ms. Empirikal na tuntunin: ang window ay hindi dapat lumampas sa 10% ng oras ng pagsasagawa ng isang kahilingan.

Gumagana ba ang deduplikasyon sa WebSocket?

Oo, pareho ang prinsipyo: kung maraming bahagi ng application ay nag-subscribe sa parehong WebSocket channel, ang deduplikator ay nagbubukas ng isang koneksyon at nagpapadala ng mga mensahe sa lahat ng subscriber. RxJava Share o Kotlin SharedFlow — mainam na mga tool para sa deduplikasyon ng WebSocket na mensahe sa panig ng client.

Paano subukan ang deduplikasyon?

Gamitin ang MockWebServer (OkHttp) para sa Android o OHHTTPStubs para sa iOS. Magpatakbo ng 10 parallel na kahilingan na may parehong mga parameter at suriin na ang server ay nakatanggap ng eksaktong isang tawag. CountDownLatch o coroutineScope ay makakatulong sa pag-synchronize ng mga parallel na tawag sa test.

Buod

  • Request Deduplication — pagsasama-sama ng magkakaparehong parallel na kahilingan sa iisa na may pagpapadala ng resulta sa lahat ng nagpasimula.
  • Memoization — pag-cache ng resulta habang isinasagawa; simple at epektibong pamamaraan para sa isang proseso.
  • Request Merging — pagtitipon ng grupo ng magkakaibang kahilingan sa batch; nangangailangan ng suporta ng server at timeout ng window.
  • DataLoader — standard ng deduplikasyon para sa GraphQL; nilulutas ang N+1 na problema sa antas ng server.
  • Hanggang 18% ng mga kahilingan sa mga mobile application ay mga duplicate; binabawasan ng deduplikasyon ang karga ng server at baterya.
  • Ang key ng deduplikasyon ay dapat na tiyak: isama ang URL, mga parameter, at konteksto ng user.
  • Pinakamahusay na kasanayan — kombinasyon ng deduplikasyon sa panig ng client (OkHttp Interceptor / URLSession) at server (DataLoader).

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din