Request Deduplication — eyni olan paralel sorğuların bir sorğuda birləşdirilməsi mexanizmidir ki, məlumat mənbəyi onlarla çağırış əvəzinə yalnız bir çağırış alır. Mobil tətbiqlərdə deduplikasiya xüsusilə vacibdir: bir neçə ekran eyni anda istifadəçinin profilini və ya məhsul siyahısını tələb edə bilər. Square Engineering (2024)-nin məlumatlarına görə, deduplikasiyanın tətbiqi server məntiqlərini dəyişmədən onların API yükünü 30% azaldıb.
Başlıca
Request Deduplication — bir məlumat mənbəyinə eyni vaxt pəncərəsində bir neçə eyni sorğunun yerinə yetirilməsinin qarşısını alan texnikadır. 10 eyni HTTP sorğusu göndərmək əvəzinə, sistem bir sorğu göndərir, qalan 9-u isə onun nəticəsini gözləyir.
Təkrarlanan sorğular problemi xüsusilə vəziyyətə əsaslanan arxitektura (MVVM, MVI, Redux) ilə mobil tətbiqlərdə kəskin şəkildə özünü göstərir. Bir neçə müşahidəçi qısa müddət ərzində eyni məlumatlara abunə olduqda, hər biri öz sorğusunu işə salır və həddindən artıq yük yaradır. Uber Engineering (2024)-nin məlumatlarına görə, Uber mobil kliyentlərində bütün sorğuların 18%-i təkrarlanır və kliyent tərəfində deduplikasiya onların sayını 4 dəfə azaldıb.
Deduplikasiya keşlənmə ilə eyni şey deyil. Keş sorğun nəticəsini yerinə yetirildikdən sonra saxlayır. Deduplikasiya həddindən artıq sorğuların əvvəl və icra zamanı qarşısını alır. Sorğu tamamlandıqdan sonra keş işə düşür.
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()
}
Bu Kotlin sinfi hər açar üçün yalnız bir korutinin yerinə yetirilməsini təmin edir. Eyni açarla bütün paralel çağırışlar bir Deferred-i gözləyir. Tamamlandıqdan sonra açar silinir və növbəti sorğu normal yerinə yetirilir.
Server yükünün azaldılması — ilk və açıq səbəb. Hər təkrarlanan sorğu server resurslarını (CPU, yaddaş, verilənlər bazası əlaqələri) istehlak edir. Milyonlarla cihaz miqyasında hətta 10–15% təkrarlanan sorğular əlavə serverlər tələb edən əhəmiyyətli yük yaradır.
Batareya və trafikə qənəət — mobil cihazda hər HTTP sorğusu radio modulun enerjisini sərf edir. Google I/O (2025)-nin məlumatlarına görə, bir uğursuz və ya təkrarlanan sorğu bir şəbəkə seansının enerjisinin 15%-nə qədər istehlak edə bilər. Deduplikasiya radio modulun aktivləşmə sayını azaldır və cihazın batareya ilə iş müddətini uzadır.
Məlumat münaqişələrinin qarşısının alınması — iki təkrarlanan sorğu yerli yaddaşa məlumat yazırsa, race condition yarana bilər: ikinci sorğu birincinin nəticəsini köhnəlmiş məlumatlarla əvəz edə bilər. Deduplikasiya yerli yaddaşa bir dəfə yazılmasını təmin edərək yarışmaları aradan qaldırır.
UX-nin yaxşılaşdırılması — istifadəçi eyni məlumatlar üçün çoxlu yüklənmə göstəriciləri görmür. UI vəziyyəti (loading / success / error) bir həqiqət mənbəyi tərəfindən idarə olunur, rəqabət edən bir neçə sorğu ilə deyil.
Memoization (memoizasiya) — funksiyanın nəticəsinin icra müddətində keşlənməsidir. Funksiya artıq eyni arqumentlərlə yerinə yetirilirsə, yeni çağırış ikinci prosesi işə salmır, birincinin nəticəsini alır. Bu, daxili proses ssenariləri üçün deduplikasiyanın ən sadə formasıdır.
Mobil tətbiqlərdə tipik tətbiq — Deferred və ya Promise-də açarların HashMap-i. Açar adətnə sorğun URL sətri və ya parametrlərin birləşməsidir. Qeydin ömrü — ilk sorğudan cavabın tamamlanmasına qədərdir. Dropbox Engineering (2024)-nin məlumatlarına görə, Dropbox mobil kliyentində memoizasiya API-yə təkrarlanan sorğuların sayını 40% azaldıb.
Flawed deduplication — təhlükəli səhv: xətadan sonra açarı silməsəniz, bütün sonrakı sorğular həmişə eyni xətanı qaytaracaq. Düzgün tətbiq xətalarla baş vermiş və uğursuz halları emal edərək keşi təmizləməli və təkrari cəhdlərə icazə verməlidir.
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 xətaların düzgün emalı üçün Result<T> istifadə edir: uğurda — keşləyir, xətada — təkrari cəhdə imkan verir. Bu yanaşma müvəqqəti şəbəkə nasazlığının sonrakı sorğuları bloklamamasını təmin edir.
Request Merging (sorğuların birləşdirilməsi) — bir mənbəyə bir neçə müxtəlif sorğun bir qrupda toplandığı və bir batch sorğu kimi göndərildiyi texnikadır. Deduplikasiyadan fərqli olaraq, sorğular eyni deyil — parametrlərinə görə fərqlənir, lakin bir resursa müraciət edir.
Tipik ssenari: tətbiqin 5 ekranı müxtəlif istifadəçilərin profillərini tələb edir. /api/users/1, /api/users/2 və s. üçün 5 fərdi sorğu göndərmək əvəzinə, sistem 20 ms gözləyir, bütün ID-ləri toplayır və bir /api/users?ids=1,2,3,4,5 sorğusu göndərir. Pəncərə vaxt həddi — əsas parametr: çox uzun pəncərə UX-i pisləşdirir, çox qısa isə kifayət qədər sorğu toplamağa imkan vermir.
Netflix Engineering (2023)-nin məlumatlarına görə, GraphQL BFF (Backend for Frontend) aqreqatorunda sorğuların birləşdirilməsi təbəqələr arasında HTTP çağırışlarının sayını 65% və orta cavab müddətini 120 ms azaldıb, əlavə RTT-ləri aradan qaldıraraq. Asinxron pəncərə (debounce) — korutinlər və ya RxJava vasitəsilə standart tətbiq.
class BatchMergerT {
private val pending = ConcurrentLinkedQueue<Pair<String, CompletableDeferred<T>>>()
suspend fun get(id: String): T = suspendCoroutine { cont ->
pending.add(Pair(id, cont))
scheduleFlush()
}
}
Bu mixin hər sorğunu dayandırmaq üçün suspendCoroutine və qrupu toplamaq üçün 30 ms pəncərə istifadə edir. Taymer bitdikdən sonra bütün toplanmış ID-lər bir batch sorğu ilə göndərilir və hər korutin öz nəticəsini alır.
DataLoader — server tərəfində batching və memoizasiyanı tətbiq edən kitabxanadır (əslində JavaScript/GraphQL üçün). Event loop-un bir ticki ərzində bir məlumat mənbəyinə bütün sorğuları qruplaşdırır və onları bir çağırışla yerinə yetirir. DataLoader GraphQL ilə geniş istifadə olunur, lakin istənilən REST tətbiqində tətbiq edilə bilər.
İş prinsipi: bir mikrotapşırıq ərzində bütün loader.load(id) çağırışları ID massivinə toplanır və batch funksiyasına ötürülür. Nəticələr alındıqdan sonra hər ID öz massiv elementini alır. DataLoader-də keşlənmə yalnız bir HTTP sorğu çərçivəsində işləyir — növbəti sorğuda keş təmizlənir ki, bu da məlumatların aktuallığını təmin edir.
Meta Engineering (2024)-nin məlumatlarına görə, Facebook-un GraphQL qatında DataLoader-in tətbiqi N+1 problemini aradan qaldıraraq, tipik səhifə üçün verilənlər bazası sorğularının sayını 200-dən 10-a endirib. Batch scheduling — DataLoader-in əsas innovasiyası — qruplaşdırmanı optimallaşdırmaq üçün process.nextTick (Node.js) və ya DispatchQueue.main (iOS) istifadə edir.
Memoization — bir proses üçün optimaldır (mobil tətbiq, mikroxidmət). Tətbiqi sadədir və eyni paralel çağırışlar üçün səmərəlidir. Mənfi cəhəti — proseslər və ya cihazlar arasında işləmir.
Request Merging — BFF qatı və ya aqreqator xidməti üçün uyğundur. Server tərəfində batch endpoint-lərinin dəstəyini tələb edir. Frontend eyni tipli müxtəlif məlumatlara çoxlu kiçik sorğular etdikdə ən yaxşı seçimdir.
DataLoader — GraphQL serverləri üçün deduplikasiya standartıdır. N+1 problemini avtomatik həll edir və keşin əl ilə konfiqurasiyasını tələb etmir. GraphQL qatı olan istənilən server üçün tövsiyə olunur.
Deduplikasiya ilə HTTP keşi — OkHttp (Android) və ya URLSession (iOS) səviyyəsində Interceptor və ya delegate vasitəsilə deduplikasiya konfiqurasiya edilə bilər. OkHttp CacheInterceptor — eyni URL ilə sorğun artıq yerinə yetirilib-yetirilmədiyini yoxlayan və onları birləşdirən xüsusi tutucudur. Bu üsul biznes məntiqindən aşağı səviyyədə işləyir və funksiya kodunu dəyişmədən tətbiqin bütün sorğularını əhatə edir.
Tez-tez verilən suallar
Deduplikasiya birinci sorğu hələ yerinə yetirilərkən təkrarlanan sorğun icrasının qarşısını alır. Keşlənmə yerinə yetirildikdən sonra nəticəni saxlayır. Onlar bir-birini tamamlayır: deduplikasiya yüklənmə zamanı təkrarlanan sorğulara qarşı qoruyur, keş isə sonra təkrarlanan sorğulara qarşı.
Deduplikasiya açarı səhv seçilərsə. Məsələn, bütün istifadəçilər bir açardan istifadə edərsə, ilk sorğu bütün digərlərini bloklayacaq. Açar spesifik olmalıdır: URL, parametrlər, istifadəçi ID-si daxil edilməlidir. Deduplikasiya həmçinin server problemlərini maskalaya bilər, metrikalarda sorğuların real tezliyini gizlədərək.
Optimal pəncərə — istifadəçi ssenariləri üçün 20–50 ms. Bu, sorğu qrupunu toplamaq üçün kifayətdir, lakin istifadəçinin gecikməni hiss etməsi üçün kifayət deyil. Fon əməliyyatları üçün (loglar, analitika) pəncərəni 200–500 ms-ə qədər artırmaq olar. Empirik qayda: pəncərə bir sorğun icra müddətinin 10%-dən çox olmamalıdır.
Bəli, prinsip eynidir: tətbiqin bir neçə hissəsi eyni WebSocket kanalına abunə olarsa, deduplikator bir əlaqə açır və mesajları bütün abunəçilərə göndərir. RxJava Share və ya Kotlin SharedFlow — kliyent tərəfində WebSocket mesajlarının deduplikasiyası üçün ideal alətlərdir.
Android üçün MockWebServer (OkHttp) və ya iOS üçün OHHTTPStubs istifadə edin. Eyni parametrlərlə 10 paralel sorğu işə salın və serverin dəqiq bir çağırış aldığını yoxlayın. CountDownLatch və ya coroutineScope testdə paralel çağırışları sinxronlaşdırmağa kömək edər.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun