রিকয়ারমেন্ট : আমার দুইটা ভিন্ন ডাটাবেইজের দুইটা ভিন্ন কালেকশন এর উপর একত্রিত এগ্রিগেশন চালিয়ে একটা ফাইনাল সামারি রেডি করা লাগবে,যেটা হিসাব শেষে ফাইনাল রেজাল্ট টা আরেকটা কালেকশনে আপডেট করে দিতে হবে। ক্যালকুলেশন করতে হবে সর্বনিম্ন মেমোরি খরচ করে।
আমার নুব এপ্রোচ থেকে একটু অপটিমাইজ সল্যুশনসের দিকে নিয়ে আসা নিয়ে লিখা যাক।
Task : ইউজারদের টিমের গ্লোবাল বাজেট ডিস্ট্রিবিউশন হিসাব করা। মানে ইউজার রা তাদের বাজেট এর কত % gk,def,mid,fwd এর পেছনে খরচ করেছে তার সামারি।
বিজনেস এন্ড থেকে ছোট ব্রিফ: আমাদের ফ্যান্টাসি ফুটবল টাইপ প্রজেক্ট। ইউজার রা একেকজন টিম মেনেজার ( পেপ গার্দিওয়ালা, হ্যান্সি ফ্লিক, আনচেলত্তি,,, এমন ভাবসাব😂)। ইউজার রা তাদের নির্ধারিত ১০০মিলিয়ন ডলার বাজেটের মধ্যে ১৫ জন প্লেয়ার কিনে ১১ জন একাদশে রেখে খেলায়, প্রতি গেম ওইকে আবার ট্রান্সফার ও করে ১/২ জন প্লেয়ার আউট, ইন হয়। এসব ট্রান্সফার রেকর্ড থাকে Transfer টেবিলে যেখানে একটা ইউজার এর এগেইন্সট এ সিজন শুরুতে ১৫ টা প্লেয়ার, (১৫ টা ডক) এটা আস্তে আস্তে বাড়ে প্রতি গেম ওইকে ট্রান্সফার করলে বাড়ে। ১ টা নিউ প্লেয়ার নিলে তার জাগায় আগের টা ট্রান্সফার আউট হয় নতুন টা ইন হয়। ইউজার এর লেটেস্ট ১৫ জনের স্কোয়াড ট্র্যাক রাখার জন্য একটা ফ্ল্যাগ আছে (is_carried_forward) ট্রু বা ফলস।
সহজ কথা ১ মিলিয়ন ইউজার থাকলে Transfer কালেকশন এ মিনিমাম ১৫ মিলিয়ন ডকুমেন্টস থাকবে। ধরেন মোট ডকুমেন্টস ১ মিলিয়ন।
worst case : প্রতি ডকুমেন্টস ম্যাক্স 1KB সাইজ হলে
- 1,000,000 doc
- 1,000,000KB
- 1,000MB
- 1GB ( প্রায়)
১ মিলিয়ন ডকুমেন্টস প্রায় 1GB
আর লাগবে আমার এই প্লেয়ার দের প্রাইস, পজিশন গ্রুপ যেটা আছে Players কালেকশনে।
আসল কাহীনি শুরু -
আমার কালেকশন ইউজ হবে দুইটা ( Transfer, Players) এখানে Transfer কালেকশন টা আছে ফ্যান্টাসি মেনেজমেন্ট db তে, আর Players আছে Livescore মেনেজমেন্ট db তে। এখানে আসে একটা চ্যালেঞ্জ। দুইটা একই db তে থাকলে একসাথে এগ্রিগেশন চালানো যেত। যাহোক রিকয়ারমেন্ট আছে যেহতু সমাধান তো করা লাগবেই
১. ব্রুট ফোর্স সমাধান
- প্লেয়ার কালেকশন থেকে সব প্লেয়ার নিয়ে এসে ইন-মেমোরিতে রাখি
- Transfer collection থেকে user_team_id ধরে গ্রুপ করে ১৫ জনের স্কোয়াড বানায় db থেকে ফেচ করে এনে রাখি ( মোট ট্রান্সফার 15 মিলিয়ন ডকুমেন্টস [ যদিও সিলেক্ট করে অনলি রিকয়ার ফিল্ড আনলেও per team ডক ম্যাক্স 1KB হলেও মোট 1 GB data এনে মেমোরিতে রাখা লাগবে ]
- পরে প্লেয়ার আইডি সাথে ম্যাপ করে এভারেজ পার টিম এর বাজেট ডিস্ট্রিবিউশন হিসাব ধরে রেখে [ আবারো র্যাম খেকো কাজকাম 🤧 ]
- ফাইনালি গ্লোবাল এভারেজ হিসাব করা যাবে
এই সলুশন দেখতেই কেমন ভয় লাগে, হিউজ মেমোরি কস্ট, টাইম কস্ট
মাঝখানে আরো কয়েকটা সলুশন ট্রাই করা হইছে, লেখা বেশি বড় হয়ে যাচ্ছে অসব বাদ।
২. ফাইনাল সলুশন
একটা সিজনের জন্য প্লেয়ার যেহেতু নির্দিষ্ট (700-800 মতন সর্বোচ্চ ) [ EPL -20 ta club প্রতি সিজন ] আর প্লেয়ার কালেকশন অন্য db তে তো এইটা স্ট্যাটিক, আনা লাগবেই তাহলে আগে ৮০০ প্লেয়ার এনে ক্যাশ করা যাক। কিন্তু,,,
1️⃣ একটু ভিন্ন উপায়ে। Total 800KB সাইজের প্লেয়ার গুলাকে তাদের id ধরে Set বানায়ে Key-value পেয়ারে রাখি৷ পরে যখন প্লেয়ার এর ডিটেইলস লাগবে, আইডি ধরে ডাক দিলে O(1) টাইমে প্লেয়ার এর ডিটেইলস পাওয়া যাবে ( প্রাইস,পজিসজন গ্রুপ)
2️⃣ introduce batch wise skip/limit মেকানিজম : আসল খেলাটা এইখানেই, একদম শুরুতে skip = 0 db থেকে ইউজার টিম এনে জমায় না রেখে এক ব্যাচে 1000 করে টিম নিয়ে আসি 1000kb size max ( 1MB)
এইটুকুর এভারেজ হিসেব করে 5 টা মাত্র 8 byte সাইজের integer ভ্যারিয়েবলে স্টোর করি। ( avgGkPct, avgDefPct,avgMidPct,avgFwd, team_count)
Total 40 byte size for 5 variable.
নেক্সট ব্যাচ যখন আসবে ফাইনাল এভারেজ টা এই গ্লোবাল এভারেজ এর সাথে মার্জ করে দিলেই আর কিচ্ছু মনে রাখা লাগতেছে না
40 byte মেমোরিতে রাখা ফলাফল টাই ফাইনাল গ্লোবাল এভারেজ হিসাবের ফলাফল হতে যাচ্ছে😉
একেক্টা ব্যাচ হিসাব শুরুতে লিমিট = batch size শেষে skip = skip+batch size
অর্থাৎ, step 1: skip = 0 step 2: skip = 1000 step 3: skip = 2000
এই লুপে গ্লোবাল এভারেজ বাজেট ডিস্ট্রিবিউশন বের হয়ে আসবে মাত্র 1MB +/- মেমোরি খরচ করে
এটা যেহেতু দিনে একবার জব চলবে সময় ২/৩ মিনিট বা কম বেশি যা খুশি লাগুগ কনসার্ন নাই। এর ভেতরে আবার retry mechanism এডজাস্ট করে দিলেই আরো সুন্দর হয়।
finnaly db write on GlobalBudgetDistribution collection with the final sumery.
এভাবে সম্ভব হয়ে উঠে ১জিবি ডাটা প্রসেস ইন ১এমবি মেমোরি
আজ এই পর্যন্তই। কোন ভুল ত্রুটি থাকলে অবশ্যই পরামর্শ দিতে ভুলবেন না।
ধন্যবাদ