Business Systemsপড়তে ১২ মিনিট লাগবে

অ্যাড ক্লিক অ্যাগ্রিগেটর ডিজাইন

বিলিং এবং অ্যানালিটিক্সের জন্য নির্ভুলভাবে কোটি কোটি অ্যাড ক্লিক গোনার ব্যবস্থা
scope:বাস্তব সিস্টেমdifficulty:অ্যাডভান্সড

সমস্যাটি বোঝা

গুগল, ফেসবুক বা যেকোনো অ্যাড নেটওয়ার্কে যখন কেউ কোনো অ্যাডে ক্লিক করেন, ওই ক্লিকটিতে ঠিক একবারই গোনা (counted exactly once) হতে হবে। এই কাউন্টের ওপর ভিত্তি করেই বিল করা হয় (প্রতি ক্লিকের জন্য অ্যাডভার্টাইজাররা টাকা দেন) এবং অ্যানালিটিক্স (ক্যাম্পেইন কেমন চলছে তার ড্যাশবোর্ড) তৈরি হয়। এর হিসাবে একটু ভুল হওয়ার মানে হলো অ্যাডভার্টাইজারদের কাছ থেকে বেশি টাকা নিয়ে নেওয়া অথবা নিজেদের রেভিনিউ লস করা।

ফাংশনাল রিকয়ারমেন্টস:

  • প্রতিটি অ্যাড ক্লিকের মেটাডেটা (অ্যাড আইডি, ক্যাম্পেইন আইডি, ইউজার আইডি, টাইমস্ট্যাম্প, আইপি) রেকর্ড করা।
  • প্রতিটি অ্যাড, ক্যাম্পেইন এবং সময়ের উইন্ডো (১ মিনিট, ৫ মিনিট, ১ ঘণ্টা) অনুযায়ী ক্লিকের সংখ্যা অ্যাগ্রিগেট বা একত্র করা।
  • ফ্রড বা ভুয়া ক্লিক (বট, ক্লিক ফার্ম, ডুপ্লিকেট ক্লিক) শনাক্ত করে ফিল্টার করা।
  • অ্যাডভার্টাইজারদের জন্য প্রায় সাথে সাথেই (near real-time) রিপোর্টিংয়ের ড্যাশবোর্ড দেওয়া।

নন-ফাংশনাল রিকয়ারমেন্টস:

  • ঠিক-একবার (Exactly-once) গোনা: বিলিংয়ের জন্য ডাবল-কাউন্টিং চলবে না, আবার কোনো ক্লিক মিসও করা যাবে না।
  • নিয়ার রিয়েল-টাইম: ক্লিক করার <১ মিনিটের মধ্যেই অ্যাগ্রিগেটেড কাউন্ট দেখতে হবে।
  • বিশাল স্কেল: প্রতিদিন প্রায় ১০ বিলিয়ন (১০০০ কোটি) ক্লিক সামলানোর ক্ষমতা থাকতে হবে।
  • ৯৯.৯৯% অ্যাকুরেসি: আর্থিক লেনদেন জড়িত তাই ডেটা একদম নির্ভুল হতে হবে। রিয়েল-টাইম এবং ব্যাচ কাউন্টের মধ্যে রিকনসিলিয়েশনের ব্যবস্থা থাকতে হবে।
ধারণা: ক্লিক → কাউন্ট → বিল → রিপোর্ট

প্রাথমিক একটা হিসাব-নিকাশ

চলুন সিস্টেমটার বড়সড় একটা সাইজের হিসাব করি:

  • প্রতিদিনের ক্লিক: ১০ বিলিয়ন (১০০০ কোটি) প্রতিদিন = গড়ে প্রতি সেকেন্ডে ~১১৫,০০০ ক্লিক
  • পিক ট্রাফিক: প্রতি সেকেন্ডে ~৫০০,০০০ ক্লিক (বড় কোনো ইভেন্ট বা ছুটির দিনে)
  • ক্লিক ইভেন্ট সাইজ: ~২০০ বাইট (অ্যাড আইডি, ক্যাম্পেইন আইডি, ইউজার আইডি, টাইমস্ট্যাম্প, আইপি, ইউজার এজেন্ট, জিও-লোকেশন)
  • র স্টোরেজ (Raw storage): ১০ বিলিয়ন × ২০০ বাইট = প্রতিদিন ২ TB, বছরে ~৭৩০ TB
  • অ্যাগ্রিগেটেড ডেটা: তুলনামূলকভাবে বেশ ছোট — ১ মিলিয়ন অ্যাড × ১৪৪০ মিনিট × ৫০ বাইট ≈ প্রতিদিন ৭২ GB
  • নেটওয়ার্ক ব্যান্ডউইথ: পিক টাইমে ইনজেশনের জন্য ৫০০,০০০ × ২০০ বাইট = ~১০০ MB/s

এটি মূলত একটি স্ট্রিমিং সমস্যার সমাধান। আমাদের ইভেন্টের এক বিশাল স্রোত (firehose) প্রসেস করতে হবে, সেগুলোকে ডিডুপ্লিকেট করতে হবে, সময়ের উইন্ডোতে অ্যাগ্রিগেট করতে হবে এবং কোয়েরির রেজাল্ট দেখাতে হবে — এবং সবকিছুই করতে হবে প্রায় রিয়েল-টাইমে।

এটা আসলে এত কঠিন কেন?

ক্লিক গোনা শুনতে সহজ মনে হলেও, এত বিশাল স্কেলে এটা বেশ কঠিন কাজ:

ডুপ্লিকেট ক্লিক: ইউজাররা ডাবল-ক্লিক করেন, ব্রাউজার রিট্রাই করে, বা মোবাইল নেটওয়ার্কগুলো রিকোয়েস্ট রিপ্লে করে দেয়। একই ক্লিক ২-৩ বারও আসতে পারে। কিন্তু বিলিংয়ের জন্য আমাদের তা ঠিক একবারই গুনতে হবে।

বটের ক্লিক: প্রতিযোগী কোম্পানি বা ক্লিক ফার্মগুলো অ্যাডভার্টাইজারের বাজেট শেষ করে দেওয়ার জন্য ক্লিকের বন্যা বইয়ে দিতে পারে। এর জন্য আমাদের রিয়েল-টাইম ফ্রড ডিটেকশনের ব্যবস্থা থাকতে হবে।

নেটওয়ার্ক রিট্রাই: যদি ক্লিক কালেক্টর দ্রুত অ্যাকনলেজমেন্ট (ACK) না দেয়, তবে ক্লায়েন্ট SDK আবার চেষ্টা করে। ডিডুপ্লিকেট না করলে প্রতিটি রিট্রাইকে নতুন ক্লিক মনে হবে।

টাইম-উইন্ডোড অ্যাগ্রিগেশন (Time-windowed aggregation): অ্যাডভার্টাইজাররা ১-মিনিট, ৫-মিনিট এবং ১-ঘণ্টা উইন্ডোতে হিসাব চান। নেটওয়ার্ক ডিলের কারণে দেরিতে আসা ইভেন্টগুলোকে বর্তমান উইন্ডোর বদলে সঠিক উইন্ডোতেই বসাতে হবে। এর জন্য ওয়াটারমার্কস (watermarks) এবং ইভেন্ট-টাইম প্রসেসিং (event-time processing) লাগে।

এক্সাক্টলি-ওয়ান্স সেমান্টিকস (Exactly-once semantics): ডিস্ট্রিবিউটেড সিস্টেমগুলোতে এই গ্যারান্টি দেওয়া সবচেয়ে কঠিন কাজ। কার্যকরভাবে একবার গোনার জন্য আমরা আইডেমপোটেন্ট রাইটস (idempotent writes) ও ডিডুপ্লিকেশন ব্যবহার করি।

স্ট্রিমিং প্রসেস: রিয়েল-টাইম ক্লিক অ্যাগ্রিগেশন
Click chart to zoom
ক্লিক ফ্লো: SDK থেকে শুরু করে এক মিনিটেরও কম সময়ে রিয়েল-টাইম ড্যাশবোর্ড পর্যন্ত

ডিডুপ্লিকেশন এবং এক্সাক্টলি-ওয়ান্স কাউন্টিং

এটি সিস্টেমের সবচেয়ে গুরুত্বপূর্ণ অংশ। স্ট্র্যাটেজিটা হলো এ রকম:

ক্লিক আইডি (Click ID): প্রতিটি ক্লিক ইভেন্টে অ্যাড SDK একটি ইউনিক click_id তৈরি করে দেয় (UUID + টাইমস্ট্যাম্প হ্যাশ)। এটাই হলো ডিডুপ্লিকেট করার কি (key)।

টু-লেয়ার ডিডুপ্লিকেশন:

  1. ব্লুম ফিল্টার (Bloom filter) (ফাস্ট পাথ): এটি ইন-মেমোরি প্রোব্যাবিলিস্টিক চেক। যদি ব্লুম ফিল্টার বলে "এখনো দেখিনি", তবে ক্লিকটি নিশ্চিতভাবেই নতুন। যদি বলে "হয়তো দেখেছি", তবে আমরা এক্সাক্ট স্টোরে চেক করি। ফলস পজিটিভ রেট ~১%, কিন্তু ফলস নেগেটিভ জিরো।
  2. এক্সাক্ট ডিডুপ স্টোর (Redis/RocksDB): এটি click_id → 1 স্টোর করে রাখে এবং একটি TTL (সাধারণত ২ ঘণ্টা) থাকে। ব্লুম ফিল্টারের "হয়তো দেখেছি" বলা ক্লিকগুলোর চূড়ান্ত উত্তর এখানেই পাওয়া যায়।

দেরিতে আসা ইভেন্টের জন্য ওয়াটারমার্কস: ইভেন্ট-টাইম প্রোগ্রেস ট্র্যাক করতে Flink ওয়াটারমার্ক ব্যবহার করে। ৫ মিনিট পর্যন্ত দেরিতে আসা ইভেন্টগুলোকেও সঠিক টাইম উইন্ডোতে জায়গা দেওয়া হয়। এর চেয়েও বেশি দেরিতে আসা ইভেন্টগুলোকে হয় বাদ দিয়ে দেওয়া হয় অথবা ম্যানুয়াল রিভিউর জন্য একটি ডেড-লেটার কিউতে (dead-letter queue) পাঠানো হয়।

রিকনসিলিয়েশনের জন্য MapReduce: একটি দৈনন্দিন ব্যাচ জব (Spark) HDFS থেকে সমস্ত র বা কাঁচা ক্লিকগুলোকে আবার অ্যাগ্রিগেট করে। ব্যাচ কাউন্টটিকে রিয়েল-টাইম কাউন্টের সাথে তুলনা করা হয়। দুই হিসেবের মধ্যে অমিল পাওয়া গেলে তা অ্যালার্ট তৈরি করে এবং ঠিক করে দেয়।

ডিডুপ্লিকেশন এবং ঠিক-একবার (exactly-once) গোনা

ফ্রড ডিটেকশন এবং রিকনসিলিয়েশন

রিয়েল-টাইম ফ্রড সিগন্যাল:

  • অস্বাভাবিক ক্লিক রেট: যদি একটি আইপি থেকে ১ মিনিটে একই অ্যাডে ১০০টি ক্লিক আসে, তবে সেটা সন্দেহজনক। আইপি ও অ্যাড অনুযায়ী একটি রেট লিমিট বসাতে হবে।
  • আইপি ক্লাস্টারিং: একই /24 সাবনেট থেকে অনেক ক্লিক আসা মানে সেটি হয়তো একটি ক্লিক ফার্ম।
  • ক্লিক-টু-কনভার্শন রেশিও: যদি কোনো অ্যাডে ১০,০০০ ক্লিক পড়ে কিন্তু কোনো কনভার্শন বা প্রফিট না হয়, তবে বুঝতে হবে কোথাও কোনো সমস্যা আছে।
  • এমএল (ML) মডেল: লেবেল করা ফ্রড বা ভুয়া ডেটা দিয়ে ট্রেইন করতে হবে। এর ফিচারের মধ্যে থাকতে পারে: ক্লিকের টাইমিং প্যাটার্ন, সেশন বিহেভিয়ার, ডিভাইস ফিঙ্গারপ্রিন্ট, জিওলোকেশন মিসম্যাচ ইত্যাদি।

রিকনসিলিয়েশন (ল্যাম্বডা আর্কিটেকচার):

  • রিয়েল-টাইম পাথ (স্পিড লেয়ার): Flink কয়েক সেকেন্ডের মধ্যেই প্রায় সঠিক বা আনুমানিক কাউন্ট বের করে দেয়।
  • ব্যাচ পাথ (ব্যাচ লেয়ার): Spark প্রতিদিন রাতে HDFS থেকে র বা কাঁচা ইভেন্টগুলোকে প্রসেস করে একদম নির্ভুল কাউন্ট তৈরি করে।
  • সার্ভিং লেয়ার: কোয়েরি সার্ভিস এই দুটো লেয়ারকে একসাথে মিলিয়ে কাজ করে। ব্যাচ কাউন্ট পাওয়া গেলে তা রিয়েল-টাইম কাউন্টকে ওভাররাইড করে দেয়।

এটাই ল্যাম্বডা আর্কিটেকচার (Lambda Architecture) প্যাটার্ন — স্পিড এবং অ্যাকুরেসি, দুটো পাওয়ার জন্যই স্ট্রিমিং এবং ব্যাচ প্রসেসিংয়ের একটি কম্বিনেশন।

সম্পূর্ণ আর্কিটেকচার
Note: ইন্টারভিউ টিপস: একটি অ্যাড ক্লিক সিস্টেমে সবচেয়ে গুরুত্বপূর্ণ জিনিসটি হলো ঠিক-একবার (exactly-once) গোনার নিয়মটি। আপনি কীভাবে এটি অর্জন করবেন তা ঠিকঠাক বুঝিয়ে বলুন: SDK থেকে ইউনিক ক্লিক আইডি তৈরি, ব্লুম ফিল্টার + এক্সাক্ট ডিডুপ্লিকেট স্টোর, অ্যাগ্রিগেশন স্টোরে আইডেমপোটেন্ট রাইট এবং সেফটি নেট হিসেবে ব্যাচ রিকনসিলিয়েশন। এর মাধ্যমে ইন্টারভিউয়ারকে বোঝানো যায় যে, ডিস্ট্রিবিউটেড গোনার কনসেপ্টটি যতটা না সহজ মনে হয় আসলে তার চেয়েও কঠিন এবং আপনি তা ভালোভাবেই বোঝেন।

Key Metrics

ক্লিক ইনজেশন রেট
Kafka-তে অ্যাড আইডি দ্বারা পার্টিশন করা
পিক সময়ে ৫০০K ক্লিক/সে. —
অ্যাগ্রিগেশন ল্যাটেন্সি
Flink মাইক্রো-ব্যাচ উইন্ডোজ
<১ মিনিট —
ডিডুপ্লিকেট অ্যাকুরেসি
ব্লুম ফিল্টার + Redis এক্সাক্ট চেক
৯৯.৯৯% —
প্রতিদিনের র স্টোরেজ
১০ বি. ক্লিক × ২০০ বাইট
~২ TB/দিন —
প্রতিদিনের অ্যাগ্রিগেটেড স্টোরেজ
১ মি. অ্যাড × ১৪৪০ মিনিট উইন্ডোজ
~৭২ GB/দিন —
ফ্রড ডিটেকশন
রিয়েল-টাইম এমএল + রুল ইঞ্জিন
<৫ সে. —

ছোট কুইজ

সরাসরি Redis-এ যাওয়ার বদলে প্রথম লেয়ারে ব্লুম ফিল্টার ব্যবহার করা হয় কেন?

পড়া চালিয়ে যান