Request Deduplication হল একটি প্রক্রিয়া যা অভিন্ন সমান্তরাল অনুরোধগুলোকে একটিতে একত্রিত করে, যাতে ডেটা উৎস ডজনখানেকের পরিবর্তে শুধুমাত্র একটি কল পায়। মোবাইল অ্যাপ্লিকেশনে, ডিডুপ্লিকেশন বিশেষভাবে গুরুত্বপূর্ণ: একাধিক স্ক্রিন একই সময়ে একই ব্যবহারকারী প্রোফাইল বা পণ্যের তালিকা অনুরোধ করতে পারে। Square Engineering (2024) অনুসারে, ডিডুপ্লিকেশন বাস্তবায়ন তাদের API লোড 30% কমিয়েছে সার্ভার লজিক পরিবর্তন না করেই।
মূল বিষয়
Request Deduplication একটি কৌশল যা একই সময় উইন্ডোর মধ্যে একই ডেটা উৎসে একাধিক অভিন্ন অনুরোধ নির্বাহ করা প্রতিরোধ করে। 10টি অভিন্ন HTTP অনুরোধ পাঠানোর পরিবর্তে, সিস্টেম একটি পাঠায়, বাকি 9টি তার ফলাফলের জন্য অপেক্ষা করে।
ডুপ্লিকেট অনুরোধের সমস্যা বিশেষ করে অবস্থা-ভিত্তিক আর্কিটেকচার (MVVM, MVI, Redux) সহ মোবাইল অ্যাপ্লিকেশনে তীব্র। যখন একাধিক পর্যবেক্ষক অল্প সময়ের মধ্যে একই ডেটাতে সাবস্ক্রাইব করে, প্রতিটি তার নিজস্ব অনুরোধ শুরু করে, অপ্রয়োজনীয় লোড তৈরি করে। Uber Engineering (2024) অনুসারে, Uber মোবাইল ক্লায়েন্টে সমস্ত অনুরোধের 18% পর্যন্ত ডুপ্লিকেট, এবং ক্লায়েন্ট-সাইড ডিডুপ্লিকেশন তাদের সংখ্যা 4 গুণ কমিয়েছে।
ডিডুপ্লিকেশন ক্যাশিংয়ের মতো নয়। ক্যাশ নির্বাহের পরে অনুরোধের ফলাফল সংরক্ষণ করে। ডিডুপ্লিকেশন তাদের নির্বাহের আগে এবং সময় অপ্রয়োজনীয় অনুরোধ প্রতিরোধ করে। অনুরোধ সম্পূর্ণ হওয়ার পরে, ক্যাশিং কার্যকর হয়।
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()
}
এই Kotlin ক্লাস গ্যারান্টি দেয় যে প্রতি কী-তে শুধুমাত্র একটি করুটিন চলে। একই কী-সহ সমস্ত সমসাময়িক কল একটি Deferred-এর জন্য অপেক্ষা করে। সম্পূর্ণ হওয়ার পরে, কী সরানো হয় এবং পরবর্তী অনুরোধ স্বাভাবিকভাবে নির্বাহ হয়।
সার্ভার লোড কমানো প্রথম এবং সবচেয়ে স্পষ্ট কারণ। প্রতিটি ডুপ্লিকেট অনুরোধ সার্ভার সম্পদ ব্যবহার করে: CPU, মেমরি, ডেটাবেস সংযোগ। লক্ষ লক্ষ ডিভাইসের স্কেলে, এমনকি 10–15% ডুপ্লিকেট অনুরোধও উল্লেখযোগ্য লোড তৈরি করে, যার জন্য অতিরিক্ত সার্ভার প্রয়োজন।
ব্যাটারি এবং ডেটা ব্যবহার কমানো — মোবাইল ডিভাইসে প্রতিটি HTTP অনুরোধ রেডিও মডিউল শক্তি ব্যবহার করে। Google I/O (2025) অনুসারে, একটি ব্যর্থ বা ডুপ্লিকেট অনুরোধ একটি নেটওয়ার্ক সেশনের 15% পর্যন্ত শক্তি খরচ করতে পারে। ডিডুপ্লিকেশন রেডিও মডিউল সক্রিয়করণের সংখ্যা কমায়, ডিভাইসের ব্যাটারি জীবন বাড়ায়।
ডেটা দ্বন্দ্ব এড়ানো — যদি দুটি ডুপ্লিকেট অনুরোধ স্থানীয় স্টোরেজে ডেটা লেখে, তাহলে রেস কন্ডিশন হতে পারে: দ্বিতীয় অনুরোধ প্রথমটির ফলাফল পুরানো ডেটা দিয়ে ওভাররাইট করতে পারে। ডিডুপ্লিকেশন গ্যারান্টি দেয় যে স্থানীয় স্টোরেজে লেখা শুধুমাত্র একবার হয়, রেস দূর করে।
উন্নত UX — ব্যবহারকারী একই ডেটার জন্য একাধিক লোডিং নির্দেশক দেখতে পান না। UI অবস্থা (লোড হচ্ছে / সফল / ত্রুটি) একাধিক প্রতিযোগী অনুরোধের পরিবর্তে সত্যের একক উৎস দ্বারা পরিচালিত হয়।
Memoization হল একটি ফাংশনের ফলাফল তার নির্বাহের সময় ক্যাশে করা। যদি একটি ফাংশন ইতিমধ্যেই একই আর্গুমেন্ট নিয়ে চলছে, তাহলে একটি নতুন কল দ্বিতীয় প্রক্রিয়া শুরু করে না বরং প্রথমটির ফলাফল গ্রহণ করে। এটি ইন-প্রসেস পরিস্থিতির জন্য ডিডুপ্লিকেশনের সবচেয়ে সহজ রূপ।
মোবাইল অ্যাপ্লিকেশনে একটি সাধারণ বাস্তবায়ন হল Deferred বা Promise-এর জন্য কী-এর HashMap। কী সাধারণত অনুরোধ URL স্ট্রিং বা প্যারামিটারের সংযোজন। এন্ট্রির জীবনকাল প্রথম অনুরোধ থেকে প্রতিক্রিয়া সম্পূর্ণ হওয়া পর্যন্ত। Dropbox Engineering (2024) অনুসারে, Dropbox মোবাইল ক্লায়েন্টে মেমোইজেশন ডুপ্লিকেট API অনুরোধ 40% কমিয়েছে।
ত্রুটিপূর্ণ ডিডুপ্লিকেশন — একটি বিপজ্জনক ভুল: যদি ত্রুটির পরে কী সরানো না হয়, তাহলে পরবর্তী সমস্ত অনুরোধ চিরতরে একই ত্রুটি ফিরিয়ে দেবে। সঠিক বাস্তবায়নকে Error এবং Failure পরিচালনা করতে হবে, ক্যাশ পরিষ্কার করতে হবে এবং পুনরায় চেষ্টার অনুমতি দিতে হবে।
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 সঠিক ত্রুটি পরিচালনার জন্য Result<T> ব্যবহার করে: সফল হলে — ক্যাশ করে, ত্রুটিতে — পুনরায় চেষ্টার অনুমতি দেয়। এই পদ্ধতি নিশ্চিত করে যে অস্থায়ী নেটওয়ার্ক ব্যর্থতা পরবর্তী অনুরোধগুলিকে ব্লক করে না।
Request Merging একটি কৌশল যেখানে একই উৎসের একাধিক ভিন্ন অনুরোধকে একটি গ্রুপে সংগ্রহ করা হয় এবং একটি ব্যাচ অনুরোধ হিসাবে পাঠানো হয়। ডিডুপ্লিকেশনের বিপরীতে, এখানে অনুরোধগুলি অভিন্ন নয় — এগুলি প্যারামিটারে ভিন্ন কিন্তু একই রিসোর্সকে সম্বোধন করে।
একটি সাধারণ দৃশ্য: 5টি অ্যাপ্লিকেশন স্ক্রিন বিভিন্ন ব্যবহারকারীর প্রোফাইল অনুরোধ করে। /api/users/1, /api/users/2 ইত্যাদিতে 5টি পৃথক অনুরোধ পাঠানোর পরিবর্তে, সিস্টেম 20 মি.সে. অপেক্ষা করে, সমস্ত ID সংগ্রহ করে এবং একটি অনুরোধ /api/users?ids=1,2,3,4,5 পাঠায়। উইন্ডো টাইমআউট মূল প্যারামিটার: খুব দীর্ঘ উইন্ডো UX খারাপ করে, খুব ছোট — পর্যাপ্ত অনুরোধ সংগ্রহ করতে ব্যর্থ হয়।
Netflix Engineering (2023) অনুসারে, GraphQL অ্যাগ্রিগেটর BFF (ব্যাকএন্ড ফর ফ্রন্টএন্ড)-এ, অনুরোধ মার্জিং স্তরগুলির মধ্যে HTTP কলের সংখ্যা 65% এবং অতিরিক্ত RTT দূর করে গড় প্রতিক্রিয়া সময় 120 মি.সে. কমিয়েছে। অ্যাসিঙ্ক্রোনাস উইন্ডো (debounce) করুটিন বা RxJava-এর মাধ্যমে মানক বাস্তবায়ন।
class BatchMergerT {
private val pending = ConcurrentLinkedQueue<Pair<String, CompletableDeferred<T>>>()
suspend fun get(id: String): T = suspendCoroutine { cont ->
pending.add(Pair(id, cont))
scheduleFlush()
}
}
এই মিক্সিন প্রতিটি অনুরোধ স্থগিত করতে suspendCoroutine এবং গ্রুপ সংগ্রহ করতে 30 মি.সে. উইন্ডো ব্যবহার করে। টাইমার শেষ হওয়ার পরে, সমস্ত সংগ্রহ করা ID একটি ব্যাচ অনুরোধে পাঠানো হয় এবং প্রতিটি করুটিন তার ফলাফল পায়।
DataLoader একটি লাইব্রেরি (মূলত JavaScript/GraphQL-এর জন্য) যা সার্ভার সাইডে ব্যাচিং এবং মেমোইজেশন বাস্তবায়ন করে। এটি একটি ইভেন্ট লুপ টিকের মধ্যে একই ডেটা উৎসের সমস্ত অনুরোধকে গ্রুপ করে এবং একটি কল দিয়ে সেগুলি নির্বাহ করে। DataLoader ব্যাপকভাবে GraphQL-এর সাথে ব্যবহৃত হয় তবে যেকোনো REST অ্যাপ্লিকেশনে প্রয়োগ করা যেতে পারে।
এটি কীভাবে কাজ করে: একটি মাইক্রোটাস্কের মধ্যে সমস্ত loader.load(id) কল ID-এর একটি অ্যারেতে সংগ্রহ করা হয় এবং ব্যাচ ফাংশনে পাস করা হয়। ফলাফল পাওয়ার পরে, প্রতিটি ID তার অ্যারে উপাদান পায়। DataLoader-এ ক্যাশিং শুধুমাত্র একটি HTTP অনুরোধের মধ্যে কাজ করে — পরবর্তী অনুরোধে ক্যাশ পরিষ্কার হয়, যা ডেটার তাজাতা নিশ্চিত করে।
Meta Engineering (2024) অনুসারে, Facebook-এর GraphQL স্তরে DataLoader বাস্তবায়ন N+1 সমস্যা দূর করেছে, প্রতি সাধারণ পৃষ্ঠায় ডেটাবেস কোয়েরি 200 থেকে 10-এ কমিয়েছে। ব্যাচ শিডিউলিং — DataLoader-এর মূল উদ্ভাবন — গ্রুপিং অপ্টিমাইজ করতে process.nextTick (Node.js) বা DispatchQueue.main (iOS) ব্যবহার করে।
Memoization একটি একক প্রক্রিয়ার (মোবাইল অ্যাপ, মাইক্রোসার্ভিস) জন্য সর্বোত্তম। বাস্তবায়নে সহজ এবং অভিন্ন সমান্তরাল কলের জন্য কার্যকর। অসুবিধা — এটি প্রক্রিয়া বা ডিভাইসের মধ্যে কাজ করে না।
Request Merging BFF স্তর বা অ্যাগ্রিগেটর পরিষেবার জন্য উপযুক্ত। সার্ভারে ব্যাচ এন্ডপয়েন্ট সমর্থন প্রয়োজন। সর্বোত্তম পছন্দ যখন ফ্রন্টএন্ড একই ধরণের বিভিন্ন ডেটার জন্য অনেক ছোট অনুরোধ করে।
DataLoader GraphQL সার্ভারের জন্য মানক। এটি স্বয়ংক্রিয়ভাবে N+1 সমস্যা সমাধান করে এবং ম্যানুয়াল ক্যাশ কনফিগারেশনের প্রয়োজন নেই। যেকোনো সার্ভারের জন্য সুপারিশ করা হয় যার GraphQL স্তর রয়েছে।
ডিডুপ্লিকেশন সহ HTTP ক্যাশ — OkHttp (Android) বা URLSession (iOS) স্তরে, ইন্টারসেপ্টর বা ডেলিগেটের মাধ্যমে ডিডুপ্লিকেশন কনফিগার করা যায়। OkHttp CacheInterceptor একটি কাস্টম ইন্টারসেপ্টর যা পরীক্ষা করে যে একই URL-সহ একটি অনুরোধ ইতিমধ্যে চলছে কিনা এবং সেগুলি একীভূত করে। এই পদ্ধতি ব্যবসায়িক লজিক স্তরের নীচে কাজ করে এবং ফিচার কোড পরিবর্তন না করেই সমস্ত অ্যাপ্লিকেশন অনুরোধ কভার করে।
সচরাচর জিজ্ঞাসা
ডিডুপ্লিকেশন প্রথমটি চলাকালীন ডুপ্লিকেট অনুরোধ নির্বাহ প্রতিরোধ করে। ক্যাশিং নির্বাহের পরে ফলাফল সংরক্ষণ করে। তারা একে অপরের পরিপূরক: ডিডুপ্লিকেশন লোডিংয়ের সময় পুনরাবৃত্ত অনুরোধ থেকে রক্ষা করে, ক্যাশ পরে পুনরাবৃত্ত অনুরোধ থেকে রক্ষা করে।
যদি ডিডুপ্লিকেশন কী ভুলভাবে বেছে নেওয়া হয়। উদাহরণস্বরূপ, যদি সমস্ত ব্যবহারকারী একটি কী ব্যবহার করে, তাহলে প্রথম অনুরোধটি বাকি সবগুলিকে ব্লক করবে। কী নির্দিষ্ট হতে হবে: URL, প্যারামিটার, ব্যবহারকারী ID অন্তর্ভুক্ত করুন। ডিডুপ্লিকেশন মেট্রিক্সে অনুরোধের প্রকৃত ফ্রিকোয়েন্সি লুকিয়ে সার্ভার সমস্যাও মাস্ক করতে পারে।
ব্যবহারকারী পরিস্থিতির জন্য সর্বোত্তম উইন্ডো 20–50 মি.সে.। এটি অনুরোধের একটি গ্রুপ সংগ্রহ করার জন্য যথেষ্ট, কিন্তু ব্যবহারকারীর বিলম্ব লক্ষ্য করার জন্য যথেষ্ট নয়। ব্যাকগ্রাউন্ড অপারেশনের (লগ, অ্যানালিটিক্স) জন্য, উইন্ডো 200–500 মি.সে. পর্যন্ত বাড়ানো যেতে পারে। অভিজ্ঞতামূলক নিয়ম: উইন্ডো একটি অনুরোধের নির্বাহ সময়ের 10% অতিক্রম করা উচিত নয়।
হ্যাঁ, একই নীতি প্রযোজ্য: যদি অ্যাপের একাধিক অংশ একই WebSocket চ্যানেলে সাবস্ক্রাইব করে, ডিডুপ্লিকেটর একটি একক সংযোগ খোলে এবং সমস্ত সাবস্ক্রাইবারকে বার্তা সম্প্রচার করে। ক্লায়েন্টে WebSocket বার্তা ডিডুপ্লিকেট করার জন্য RxJava Share বা Kotlin SharedFlow আদর্শ সরঞ্জাম।
Android-এর জন্য MockWebServer (OkHttp) বা iOS-এর জন্য OHHTTPStubs ব্যবহার করুন। অভিন্ন প্যারামিটার সহ 10টি সমান্তরাল অনুরোধ চালান এবং যাচাই করুন যে সার্ভারটি ঠিক একটি কল পেয়েছে। CountDownLatch বা coroutineScope পরীক্ষায় সমান্তরাল কল সিঙ্ক্রোনাইজ করতে সাহায্য করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।