এখানেই অনেক system fail করে। Sharding একটা real problem solve করে ঠিকই, কিন্তু সাথে system design এর সবচেয়ে কঠিন কিছু problem ও তৈরি করে। Write bottleneck প্রমাণিত না হওয়া পর্যন্ত shard করবেন না।
০০ যে প্রশ্নগুলোর উত্তর খুঁজবো
প্রতিটা প্রশ্নের উত্তর জানার পর আপনি write bottleneck থেকে শুরু করে production sharding পর্যন্ত পুরোটা বুঝতে পারবেন।
- ১ Replica আর cache দিয়ে read scale করলাম। এখনো কী solve হয়নি?
- ২ আমরা কি শুধু আরো বড় primary machine কিনতে থাকতে পারি না?
- ৩ একটা database কে shard করার basic idea টা কী?
- ৪ কোন data কোন shard এ যাবে, সেটা কীভাবে ঠিক করবো?
- ৫ cross-shard data দরকার হলে কী হবে?
- ৬ যখন একটা shard বাকিদের চেয়ে অনেক বেশি traffic পায়, তখন কী হবে?
- ৭ পরে যখন একটা shard অ্যাড করতে হবে, তখন কী হবে?
- ৮ এখন system টা দেখতে কেমন, আর downside গুলো কী?
০১ Replica আর cache দিয়ে read scale করলাম। এখনো কী solve হয়নি?
Session 04 এর শেষে read গুলো ভালোভাবেই handle হচ্ছিলো। Replica read load ছড়িয়ে দিচ্ছিলো, cache বেশিরভাগ read serve করছিলো।
কিন্তু সব write এখনো কোথায় যায়? একটা single primary database এ।
- Replica write এ help করে না। Primary যা করেছে, সেটা শুধু copy করে।
- Cache write এ help করে না। এটা একটা read optimization।
মানে পুরো system এর প্রতিটা insert, update, delete একটা machine এ গিয়ে জমা হয়। শুধু write volume ই যখন ওই একটা primary কে overwhelm করে (মিনিটে লাখ লাখ order, message, post), তখন write ই হয়ে যায় bottleneck। Replica আর caching এই write ceiling পার করতে পারে না।
Replica হলো একটা clone। Primary এর মতো হুবহু সব data এর full copy ধরে রাখে। Clone গুলোকে identical থাকতে হয়, তাই একটাই writer হতে পারে। দুইটা clone দুজনেই write নিলে তাদের data আলাদা হয়ে যেতো। কোনটা সঠিক, সেটা বলার উপায় থাকতো না (Session 03 এর split-brain problem)। Replica যোগ করলে read capacity বাড়ে, write capacity কখনোই বাড়ে না।
০২ আমরা কি শুধু আরো বড় primary machine কিনতে থাকতে পারি না?
পারা যায়, এবং শুরুতে সেটাই করা উচিত। Vertical scaling (বড় machine, বেশি CPU, RAM, disk) হলো সঠিক first move। সহজ, code change লাগে না, নতুন কোনো problem ও তৈরি হয় না।
কিন্তু এর তিনটা hard limit আছে:
- Physical ceiling: Hardware এর একটা physical ceiling আছে। সবচেয়ে বড় machine এ পৌঁছে গেলে আর scale করার জায়গা থাকে না।
- Cost curve: Power, price এর সাথে linearly বাড়ে না। উপরের দিকে গেলে অল্প gain এর জন্য অনেক বেশি খরচ করতে হয়।
- এখনো single point of failure: যত বড়ই হোক, সব write এর জন্য এটা একটাই machine। Down হলে সব write থেমে যায়।
আগে primary কে vertical scale করুন (সহজ); তারপর read এর জন্য replica আর cache যোগ করুন (Session 03, 04); তারপর যখন সবচেয়ে বড় single primary ও write এর চাপ সামলাতে পারে না, কেবল তখনই shard করুন। Shard করবেন সবার শেষে, প্রথমে না।
০৩ একটা database কে shard করার basic idea টা কী?
মূল breakthrough চিন্তাটা হলো:
Replica হলো clone (same data, একটা writer)। কিন্তু machine গুলো যদি আলাদা data ধরে রাখতো, তাহলে কেমন হতো?
ধরুন, Machine A তে আছে user 1-1M আর Machine B তে আছে user 1M-2M। এরা আলাদা data ধরে রাখছে। তাই দুজনেই একসাথে write নিতে পারবে। কোনো conflict নেই, কারণ এরা কখনো একই row modify করে না।
Data কে টুকরো টুকরো (shard) করে ভাগ করা, যেখানে প্রতিটা টুকরো আলাদা machine এ থাকে। যেহেতু প্রতিটা machine আলাদা data ধরে, তাই প্রতিটা একসাথে নিজের write নিতে পারে। Write এভাবেই horizontally scale হয়।
Shard যোগ করলে write capacity বাড়ে। Write ceiling এভাবে সরানো যায়।
০৪ কোন data কোন shard এ যাবে, সেটা কীভাবে ঠিক করবো?
Shard key হলো ওই data field, যেটা দিয়ে ঠিক করা হয় একটা row কোন shard এ থাকবে। user_id দিয়ে shard করলে,
user_id ই আপনার shard key।
Sharding এ এটাই সবচেয়ে গুরুত্বপূর্ণ decision। ভুল করলে পরে কোনো hardware upgrade দিয়ে সেটা ঠিক করা যাবে না।
দুইটা main strategy
Range-based sharding: key কে range এ ভাগ করা।
Shard A: user_id 1 - 1,000,000 Shard B: user_id 1,000,001 - 2,000,000
Hash-based sharding: key কে hash করে shard বেছে নেওয়া।
shard_number = hash(user_id) % number_of_shards
Trade-off
| Range-based | Hash-based | |
|---|---|---|
| Data distribution | Uneven। Data order এ আসলে hot shard হয় (নতুন ID সব একটা shard এ জমে, বাকিগুলো idle থাকে) | Even। Insertion order যাই হোক, data সমানভাবে ছড়িয়ে দেয় |
| Range query | সহজ। related row একটা shard এ একসাথে store হয় | কঠিন। row সব shard এ ছড়িয়ে যায়, সবাইকে query করতে হয় |
Range-based related data একসাথে রাখে (range query এর জন্য ভালো), কিন্তু hot shard এর risk থাকে। Hash-based data সমানভাবে ছড়ায়, কিন্তু related data আলাদা হয়ে যায়। Universally সঠিক কোনো choice নেই। আপনার application কীভাবে data read করে, তার উপর নির্ভর করে।
ভালো shard key এর গুণ
দুইটা property একসাথে থাকলে তবেই shard key কাজের।
- High cardinality: field এ অনেক distinct possible value থাকতে হবে।
Shard key এর unique value এর সংখ্যাই সর্বোচ্চ shard count নির্ধারণ করে। is_active এ মাত্র দুইটা value। তাই সর্বোচ্চ দুইটা shard, সব active user একটায়, সব inactive আরেকটায়। Scale করার জায়গাই নেই। country (~200 value) কিছুটা ভালো, কিন্তু USA shard এ কোটি কোটি row, Iceland shard এ হাজার কয়েক। Cardinality আছে, কিন্তু distribution নেই। user_id (কোটি কোটি distinct value) ভালো। যত shard দরকার, তৈরি করা যায়।
2. Even access: কোনো একটা value বাকিদের চেয়ে নাটকীয়ভাবে বেশি traffic পাওয়া চলবে না।
High cardinality থাকলেই যথেষ্ট না। user_id দিয়ে hash করলে data সমানভাবে ছড়ায় (row count balanced)। কিন্তু একজন celebrity user এর post viral হলে তার user_id যে shard এ আছে, সেটা সেকেন্ডে লাখো request পায়, বাকি shard গুলো idle থাকে। Data distribution ভালো হলেও traffic distribution খারাপ। এটাই hot key।
উদাহরণ: E-commerce Orders Table
| Shard key | সুবিধা | Downside |
|---|---|---|
order_id | High cardinality, even distribution | ”customer X এর সব order” সব shard এ ছড়িয়ে যায় |
customer_id | একজন customer এর order এক shard এ group হয়। “আমার সব order দেখাও” fast | বিশাল corporate customer hot shard তৈরি করে |
country | তেমন কোনো সুবিধা নেই | Low cardinality; distribution অত্যন্ত uneven |
Perfect shard key বলে কিছু নেই। Dominant access pattern দেখে বেছে নিন, আর trade-off টা মেনে নিন। Shard key বেছে নেওয়া মানেই, কোন problem গুলো accept করতে রাজি, সেটা বেছে নেওয়া।
০৫ cross-shard data দরকার হলে কী হবে?
এক database এ কিছু operation একদম সহজ ছিলো। Shard করার পর সেই operation গুলোই কঠিন, slow, বা impossible হয়ে যায়।
সমস্যা ১: Cross-shard Query
“আজকের সব order দেখাও”। customer_id দিয়ে shard করা থাকলে আজকের order সব shard এ ছড়িয়ে আছে। আপনাকে সব shard query করতে হবে, সবচেয়ে slow shard টার জন্য wait করতে হবে, আর result গুলো নিজে merge করতে হবে।
সব shard query করে result merge করার এই pattern কে বলে scatter-gather (slow, আর shard বাড়লে আরো খারাপ)।
সমস্যা ২: Cross-shard Join
SQL join শুধু একটা database এর ভেতরে কাজ করে। Related data আলাদা shard এ থাকলে DB এগুলো join করতে পারে না। তখন প্রতিটা shard থেকে data fetch করতে হয়, আর application code এ join করতে হয়।
এই কারণেই একটা ভালো shard key একসাথে use হওয়া data কে একই shard এ রাখে।
সমস্যা ৩: Cross-shard Transaction
“A থেকে B তে ৳১০০ transfer করুন”। এক DB তে এটা একটা safe atomic transaction। কিন্তু A আর B আলাদা shard এ থাকলে এদের একটা clean transaction এ আবদ্ধ করা যায় না। deduction succeed করলো, কিন্তু addition fail করলো, তখন কী? ১০০ টাকা কোথাও থাকলো না, account থেকে কেটে গেলো অথচ অন্য account এ যোগ হলো না।
এর জন্য distributed transaction লাগে (two-phase commit, saga), যা computing এর সবচেয়ে কঠিন problem গুলোর একটা।
Sharding single-shard operation কে fast আর scalable বানায়, কিন্তু cross-shard operation (query, join, transaction) গুলোকে কঠিন problem বানিয়ে দেয়। Sharding এর আসল কারিগরি হলো এমনভাবে shard key বেছে নেওয়া, যাতে common operation গুলো একটা shard এর ভেতরেই থাকে।
ভারী cross-shard analytics (“সব customer এর total revenue”) সাধারণত live shard এ চালানো হয় না। এই query গুলো সব shard এ scatter-gather করে, live user দের slow করে দেয়। দুইটা বিকল্প আছে:
- আলাদা analytics database: সব shard এর raw data একটা আলাদা read-only database এ copy করে রাখা হয়। সেখানে যত ইচ্ছা heavy query চালানো যায়, যেকোনো সময়ে। Live shard এ কোনো প্রভাব নেই।
- Scheduled bulk job: raw data কোথাও copy করা হয় না। বরং off-peak সময়ে (রাতে) একটা job সব shard থেকে data pull করে aggregate করে শুধু final result টা store করে। যেমন: আজকের total revenue ৳৪৭ লাখ।
০৬ যখন একটা shard বাকিদের চেয়ে অনেক বেশি traffic পায়, তখন কী হবে?
Even data মানে কিন্তু even traffic না। এই problem এর দুইটা আলাদা version আছে।
Version 1: খারাপ Data Distribution থেকে Hot Shard
খারাপ shard key এর কারণে একটা shard বাকিদের চেয়ে অনেক বেশি row ধরে রাখে। উদাহরণ: country দিয়ে shard করলে India shard এ 400M row, Iceland shard এ 80,000।
- Cause: low-cardinality বা uneven shard key।
- Fix: ভালো একটা shard key বেছে নিন। এটা একটা design-time fix।
Version 2: Uneven Access থেকে Hot Key
Data সমানভাবে distributed, কিন্তু একটা specific key অনেক বেশি traffic পায়। উদাহরণ: user_id hash করে post shard করা। Row সব balanced, কিন্তু এক celebrity এর viral post সেকেন্ডে লাখ লাখ read পাচ্ছে। ওই key যে shard এ আছে সেটা overloaded হয়ে যায়। Row count এর জন্য না, বরং একটা row অস্বাভাবিক রকম popular বলে।
- Cause: বাস্তব দুনিয়ার popularity unpredictable। কোনো hash virality predict করতে পারে না।
- Hot key টা cache করুন (Session 04)। বেশিরভাগ read shard পর্যন্ত পৌঁছায়ই না। সাধারণত এটাই FIRST move (সবচেয়ে cheap, fast, আর অনেক identical read এর জন্য best fit)।
- Hot shard টা replicate করুন (Session 03)। Read replica যোগ করে read load ছড়িয়ে দিন।
- ওই outlier এর জন্য একটা dedicated shard। Permanent mega-key (celebrity account) কে তার নিজস্ব shard দিয়ে দিন।
ভালো shard key design-time এ Version 1 (খারাপ distribution) আটকায়। কিন্তু Version 2 (hot key) আটকাতে পারে না, কারণ virality আগে থেকে predict করা যায় না। Version 2 fix হয় runtime এ, caching আর replica দিয়ে, যেগুলো আগেই শিখেছেন। Sharding এগুলোকে replace করে না, complement করে।
কোন case এ কোন fix:
- Cache: read-heavy + identical (সবাই একই key চাইছে) + temporary virality।
- Dedicated shard: permanent (viral event ছাড়াই সবসময় বেশি traffic) + data-heavy (ওই key তে অনেক data)।
০৭ পরে যখন একটা shard অ্যাড করতে হবে, তখন কী হবে?
Naive % N Hashing এ Resharding Problem
4 টা shard ধরুন: shard = hash(key) % 4। Hash value 10-14 কোন shard এ পড়ে, দেখুন:
10 % 4 = 2 11 % 4 = 3 12 % 4 = 0 13 % 4 = 1 14 % 4 = 2
একটা 5th shard যোগ করলে, formula হয়ে যায় % 5:
10 % 5 = 0 11 % 5 = 1 12 % 5 = 2 13 % 5 = 3 14 % 5 = 4
প্রতিটা single key অন্য একটা shard এ চলে গেলো। Divisor বদলালে প্রায় প্রতিটা key এর result বদলে যায়। Scale এ (500M row), একটা machine যোগ করতে গেলে কোটি কোটি row physically সরাতে হবে। এটাই resharding, আর naive hashing এই operation কে massive data movement এ পরিণত করে।
Fix: Consistent Hashing
Naive % N এর root cause: key এর shard নির্ভর করে shard এর সংখ্যার উপর। N বদলালে প্রায় সব calculation নতুন হয়। Consistent hashing এই সংখ্যাকে routing logic থেকে সরিয়ে দেয়। Key এর position fixed থাকে, shard count irrelevant হয়ে যায়।
Ring তৈরি হয় কীভাবে
০ থেকে ২৩২ পর্যন্ত সংখ্যার একটা range কে ring আকারে ভাবুন (শেষ সংখ্যা আবার শুরুতে ফেরে)। এই ring এ দুই ধরনের জিনিস বসানো হয়:
- Shard গুলো: প্রতিটা shard এর identifier (নাম বা IP) hash করে ring এ একটা fixed position পায়। Shard A, B, C, D; প্রতিটার position বদলায় না।
- Key গুলো: প্রতিটা data key (যেমন user_id) hash করে ring এ position পায়। এই position টাও fixed। Shard এর সংখ্যার সাথে কোনো সম্পর্ক নেই।
Routing rule: key এর ring position থেকে clockwise এগোন। প্রথম যে shard পড়বে, সেটাই ওই key এর shard।
বাম diagram এ: user_m hash করে ring এ একটা position পায়। Clockwise এগোলে A তে পৌঁছায়। তাই user_m এর shard হবে A। user_7 clockwise এগিয়ে সরাসরি B তে পৌঁছায়, তাই user_7 যাবে shard B তে।
নতুন shard যোগ হলে কী বদলায়
E যোগ করতে হবে। E এর identifier hash করে ring এ position পায়, D আর A এর মাঝে। এখন D এর পর clockwise এগোলে আগে E আসে, তারপর A।
ফলাফল: শুধু D→E arc এর key গুলো A থেকে E তে সরে। বাকি সব key (E→A) এর clockwise neighbor আগের মতোই থাকে। কোনো পরিবর্তন নেই।
N টা shard থাকলে ring roughly N টা arc এ ভাগ হয়। নতুন shard একটা arc এর মাঝে বসে, আর শুধু সেই arc এর data নেয়। Average এ এটা মোট data এর ~1/N।
Diagram এ দেখুন: শুধু highlighted D→E arc এর key গুলো E তে গেছে। user_7 আগে B তে ছিলো, এখনো B তেই আছে। ওর arc এ E পড়েনি। বাকি সব অপরিবর্তিত।
Naive % N এ প্রতিটা key এর shard নির্ভর করে সরাসরি N এর উপর (hash(key) % N)। N বদলালে প্রায় সব result নতুন হয়।
Consistent hashing এ key এর ring position নির্ভর করে শুধু hash(key) এর উপর। N এর কোনো ভূমিকা নেই। তাই শুধু নতুন
shard এর পূর্ববর্তী arc এর data সরে, বাকি সব unchanged।
Diagram এ চারটা shard ঠিক ৯০° ব্যবধানে বসানো হয়েছে। দেখতে সুন্দর, কিন্তু বাস্তবে এমন হয় না। বাস্তবে প্রতিটা shard এর identifier hash করলে ring এ random position পড়ে। Random position মানে shard গুলোর মধ্যবর্তী arc গুলো uneven হয়ে যায়। একটা shard ring এর ৪০% cover করতে পারে, আরেকটা মাত্র ৫%। বেশি arc মানে বেশি key, বেশি key মানে বেশি load। Data even distribute হওয়ার কথা ছিলো, কিন্তু হলো না।
Virtual nodes এই সমস্যার fix। প্রতিটা physical shard কে ring এ একটা position এর বদলে অনেকগুলো position এ (সাধারণত ১৫০-২০০ টা) বসানো হয়। এই প্রতিটা position কে বলে একটা virtual node। Shard A এর ১৫০ টা virtual node ring এ ছড়িয়ে থাকে, Shard B এর ১৫০ টাও ছড়িয়ে থাকে। Random হলেও ১৫০ টা point এর মোট arc coverage গড়ে balance হয়ে যায়। তখন কোনো একটা physical shard অনুপাতের বাইরে বেশি বা কম key পায় না।
০৮ এখন system টা দেখতে কেমন, আর downside গুলো কী?
আগে সব write একটা primary তে যেতো। এখন তিনটা independent primary, প্রতিটা নিজের write নিচ্ছে। এভাবেই write scale হয়। প্রতিটা shard এর এখনো নিজের replica, backup, আর সামনে cache আছে।
Sharding আপনাকে কী দিলো
- Write scalability: যেটা replica আর cache দিতে পারেনি।
- Data capacity: এক machine এর জন্য যে data বড়ো, সেটা অনেক machine এ ভাগ হয়ে যায়।
- Smaller blast radius: একটা shard fail করলে শুধু তার ভাগের user রা affected হয়।
Downside গুলো
- Cross-shard query, join, transaction কঠিন বা impossible: scatter-gather, app-level join, distributed transaction দরকার হয়।
- Shard key প্রায়-permanent একটা decision: ভুল choice মানে hot shard, নয়তো লাগাতার cross-shard অপারেশন দরকার পড়ে।
- Consistent hashing দিয়েও resharding কঠিন: সহনীয়, কিন্তু free না।
- Operational complexity ব্লাস্ট করেঃ অনেক DB cluster monitor করা, back up করা, fail over করা, debug করা - কাজ অনেক বেড়ে যায়।
- Application code আরো complex হয়: routing, cross-shard handling, partial failure - সবকিছু হ্যান্ডেল করতে হয় কোড লেভেল থেকে।
Write bottleneck প্রমাণিত না হওয়া পর্যন্ত shard করবেন না। এটা scaling এর last step, first না। আগে vertical scaling, read replica, আর caching শেষ করুন। শুধু যখন একটা primary সত্যিই write volume সামলাতে পারে না এবং আপনার কাছে তার যথেষ্ট প্রমাণ আছে, তখনই sharding এর permanent complexity গ্রহণ করুন। অনেকেই অনেক আগেই shard করে ফেলে, আর তার cost বহন করতে থাকে, অথচ হয়তো সেই মুহূর্তে sharding এর দরকারই ছিলো না।
০৯ মগজে প্রেশার দিন
আগে নিজে ভাবুন। তারপর দেখুন: সবাই যেভাবে ভাবে, কেন সেটা অসম্পূর্ণ, আর আসল insight টা কোথায়।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“Replication এ সব machine এ same data থাকে, তাই একটাই writer হতে হয়। Sharding এ আলাদা data থাকে, তাই অনেকে write করতে পারে।”
এই চিন্তা সঠিক direction এ, কিন্তু একটা nuance miss করছে।
যে জায়গাটা সবাই miss করে
শুধু “অনেকে write করতে পারে” বললে যথেষ্ট হয় না। Key insight হলো conflict এর অনুপস্থিতি। Shard গুলো কখনো একই row modify করে না। তাই cross-shard write conflict বলে কিছু নেই।
তবে সতর্কতা: “কোনো sync issue নেই” বলাটা একটু ভুল। প্রতিটা shard এর ভেতরে replica এখনো sync করে। Per-shard replication lag এখনো থাকে। যেটা চলে যায়, সেটা হলো cross-shard write conflict।
Replica তে একটাই writer থাকে, কারণ same data মানে shared state। Shared state মানে কোন write কোন order এ apply হবে, সেটা সবাইকে agree করতে হবে। এই coordination enforce করতে একটাই writer রাখা হয়, বাকিরা তার পিছনে চলে।
Shard এ এই problem নেই, কারণ কোনো shared state নেই। Shard A user 1-5M ধরে, Shard B user 5M-10M। তারা কখনো একই row modify করে না, তাই তাদের মধ্যে কোনো coordination দরকার নেই।
Coordination না থাকা মানে প্রতিটা shard একটা সম্পূর্ণ autonomous write endpoint। একটা shard যোগ করলে একটা নতুন স্বাধীন write pipeline যোগ হয়। 4 টা shard থেকে 8 টা করলে write capacity roughly double হয়। এটাই horizontal write scaling।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“message_id দিয়ে shard করব। High cardinality আছে।”
High cardinality ঠিকই আছে, কিন্তু dominant query কে ignore করা হয়েছে।
সঠিক choice আর কেন
conversation_id দিয়ে shard করা উচিত। কারণ:
- একটা conversation এর সব message একটা shard এ group হয়।
- তাই “conversation #123 এর সব message দেখাও” এই dominant query single-shard এ হয়। Scatter-gather লাগে না।
কিন্তু message_id দিয়ে করলে একটা conversation এর message সব shard এ ছড়িয়ে পড়তো। প্রতিটা read request
scatter-gather হয়ে যেতো। সব shard query করতে হতো, সবচেয়ে slow shard টার জন্য wait করতে হতো।
Downside টা কী
বিশাল active group chat (ধরুন, লাখো member এর একটা group) তার shard কে overload করে দেয়। একটা single conversation এর কারণেই পুরো shard hot হয়ে যায়।
Dominant query কে access pattern হিসেবে চিনুন, তারপর সেই pattern অনুযায়ী shard key বেছে নিন। একসাথে ব্যবহার হওয়া data একই shard এ রাখুন। Trade-off টা (hot shard এর risk) মেনে নিন, কারণ alternative (scatter-gather) আরো খারাপ।
উত্তর দেখুন আগে নিজে ভাবুন
সবাই যেভাবে ভাবে
“Shard করা উচিত নয়। Complexity বাড়ে, transaction কঠিন হয়, shard key select করা কঠিন।”
এই কারণগুলো সত্যি, কিন্তু পুশব্যাকের সবচেয়ে শক্তিশালী যুক্তিটা miss করা হয়েছে।
আরো ধারালো পুশব্যাক
৫,০০০ user এর একটা startup এর কোনো write-scaling problem নেই। একটা সাধারণ DB ই এদের অনায়াসে সামলায়। যে problem নেই, সেটা solve করতে গেলে বিশাল permanent complexity গ্রহণ করতে হবে।
| সঠিক order | কেন |
|---|---|
| Simple single DB থেকে শুরু | কোনো problem নেই এখন |
| Vertical scale করুন | সহজ, code change নেই, কোনো নতুন problem নেই |
| Replica + Cache যোগ করুন | Read scale করুন |
| প্রমাণিত write bottleneck এলে তখন shard করুন | Complexity টা তখন justified |
আগেভাগে shard করা মানে একটা imaginary problem solve করতে গিয়ে কিছু real problem তৈরি করা (cross-shard join এর জটিলতা, shard key এর wrong choice এর permanent consequence, operational complexity)।
কোনো engineering decision নেওয়ার আগে যাচাই করুন: সমস্যাটা কি আদৌ আছে? ৫,০০০ user এ write bottleneck নেই। Proof নেই। Proof ছাড়া সমাধান নেওয়া premature optimization।
১০ যে টার্মগুলো শিখলাম
| টার্ম | মানে |
|---|---|
| Sharding | Data কে টুকরো (shard) করে ভাগ করা, প্রতিটা আলাদা machine এ আলাদা data ধরে। |
| Shard | ভাগ করা data এর একটা টুকরো। একটা slice, clone না। |
| Shard key | যে data field দিয়ে ঠিক করা হয় একটা row কোন shard এ থাকবে। |
| Range-based sharding | Key এর range দিয়ে ভাগ করা। Range query ভালো, hot shard এর risk। |
| Hash-based sharding | Key hash করে shard বেছে নেওয়া। Even distribution, range query কঠিন। |
| High cardinality | অনেক possible distinct value। ভালো shard key এর একটা গুণ। |
| Hot shard | যে shard বেশি DATA এর কারণে overloaded। খারাপ distribution, Version 1। |
| Hot key | যে single key বেশি TRAFFIC এর কারণে overloaded। Uneven access, Version 2। |
| Scatter-gather | সব shard query করে result merge করা। Cross-shard query এর জন্য লাগে। |
| Cross-shard join / transaction | Shard cross করা operation। কঠিন বা impossible; app-level handling বা distributed transaction লাগে। |
| Resharding | Shard যোগ/বাদ দিয়ে data সরানো। % N এ massive data movement, consistent hashing এ সহনীয়। |
| Consistent hashing | Key আর shard কে একটা ring এ বসানো, যাতে shard যোগ/বাদ দিলে শুধু ~1/N data সরে। |
| Virtual nodes | প্রতিটা physical shard কে ring এ অনেক জায়গায় বসানো, যাতে load even থাকে। |
| Shard router | যে component shard key hash করে request টা সঠিক shard এ route করে। |
১১ সর্ট সামারী
- Sharding data কে slice করে অনেক machine এ ছড়ায়, যাতে প্রতিটা নিজের write নিতে পারে। writes scale করার এটাই একমাত্র উপায়, যেটা replica আর cache পারে না।
- Shard key সবচেয়ে গুরুত্বপূর্ণ decision: high cardinality আর even access থাকতে হবে, আর এটাই ঠিক করে কোন operation fast থাকবে (single-shard) আর কোনটা কঠিন হবে (cross-shard)।
- Naive
% Nhashing এ একটা shard যোগ করলে প্রায় সব data সরে যায়; consistent hashing এটা fix করে key আর shard কে একটা ring এ বসিয়ে, যাতে শুধু ~1/N data সরে।
১২ মনে রাখুন
- Clone vs Slice: replica হলো clone (একটা writer), shard হলো slice (অনেক writer)। এই কারণেই sharding write scale করে।
- Even data মানে even traffic না। ভালো shard key distribution fix করে (Version 1) কিন্তু hot key আটকাতে পারে না (Version 2)।
- Sharding replication আর caching এর উপরে কাজ করে, এদের অল্টারনেটিভ না। বাস্তব system তিনটাই একসাথে use করে।
- Shard key বেছে নেওয়া হয় dominant access pattern দিয়ে। একসাথে use হওয়া data একই shard এ রাখুন।
- Cross-shard operation হলো sharding এর cost। Key এমনভাবে বেছে নিন যাতে common operation single-shard থাকে।
- Consistent hashing resharding কে সহনীয় বানায়। Key গুলোকে fixed ring position এর সাথে বাঁধে, shard count এর সাথে না।
- Write bottleneck প্রমাণিত না হওয়া পর্যন্ত shard করবেন না। Last step, first না। আগে সহজ option গুলো শেষ করুন আর sharding এর প্রয়োজনীয়তা প্রমাণ করুন।