সেশন ০৫

Sharding - Data স্প্লিট করে Write Scale করা

এই সেশনের লক্ষ্যঃ Replica আর caching দিয়ে যে write bottleneck solve করা গেলো না, সেটা কীভাবে solve করবো। Sharding, shard key এর decision, sharding যেসব problem তৈরি করে, আর consistent hashing। এগুলো বোঝা।
Sharding - Data স্প্লিট করে Write Scale করা
Sharding - Data স্প্লিট করে Write Scale করা
সতর্কতা

এখানেই অনেক 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 এ।

মানে পুরো system এর প্রতিটা insert, update, delete একটা machine এ গিয়ে জমা হয়। শুধু write volume ই যখন ওই একটা primary কে overwhelm করে (মিনিটে লাখ লাখ order, message, post), তখন write ই হয়ে যায় bottleneck। Replica আর caching এই write ceiling পার করতে পারে না।

Replica কেন এটা solve করতে পারে না

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 আছে:

  1. Physical ceiling: Hardware এর একটা physical ceiling আছে। সবচেয়ে বড় machine এ পৌঁছে গেলে আর scale করার জায়গা থাকে না।
  2. Cost curve: Power, price এর সাথে linearly বাড়ে না। উপরের দিকে গেলে অল্প gain এর জন্য অনেক বেশি খরচ করতে হয়।
  3. এখনো single point of failure: যত বড়ই হোক, সব write এর জন্য এটা একটাই machine। Down হলে সব write থেমে যায়।
বাস্তব order টা এমন

আগে primary কে vertical scale করুন (সহজ); তারপর read এর জন্য replica আর cache যোগ করুন (Session 03, 04); তারপর যখন সবচেয়ে বড় single primary ও write এর চাপ সামলাতে পারে না, কেবল তখনই shard করুন। Shard করবেন সবার শেষে, প্রথমে না।

০৩ একটা database কে shard করার basic idea টা কী?

মূল breakthrough চিন্তাটা হলো:

Clone নাকি Slice?

Replica হলো clone (same data, একটা writer)। কিন্তু machine গুলো যদি আলাদা data ধরে রাখতো, তাহলে কেমন হতো?

ধরুন, Machine A তে আছে user 1-1M আর Machine B তে আছে user 1M-2M। এরা আলাদা data ধরে রাখছে। তাই দুজনেই একসাথে write নিতে পারবে। কোনো conflict নেই, কারণ এরা কখনো একই row modify করে না।

Replica - Clone Machine A user 1 - 10M Machine B user 1 - 10M একই data copy একটাই Writer - conflict এড়াতে Shard - Slice Machine A user 1 - 5M Machine B user 5M - 10M আলাদা data আলাদা Writer - দুজনেই write নিতে পারে
বাম: Replica = Clone। সব machine এ same data, একটাই writer। ডান: Shard = Slice। প্রতিটা machine এ আলাদা data, প্রতিটাই write নিতে পারে।
Sharding কী

Data কে টুকরো টুকরো (shard) করে ভাগ করা, যেখানে প্রতিটা টুকরো আলাদা machine এ থাকে। যেহেতু প্রতিটা machine আলাদা data ধরে, তাই প্রতিটা একসাথে নিজের write নিতে পারে। Write এভাবেই horizontally scale হয়।

Shard যোগ করলে write capacity বাড়ে। Write ceiling এভাবে সরানো যায়।

০৪ কোন data কোন shard এ যাবে, সেটা কীভাবে ঠিক করবো?

Shard key কী

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-basedHash-based
Data distributionUneven। Data order এ আসলে hot shard হয় (নতুন ID সব একটা shard এ জমে, বাকিগুলো idle থাকে)Even। Insertion order যাই হোক, data সমানভাবে ছড়িয়ে দেয়
Range queryসহজ। related row একটা shard এ একসাথে store হয়কঠিন। row সব shard এ ছড়িয়ে যায়, সবাইকে query করতে হয়
মূল trade-off

Range-based related data একসাথে রাখে (range query এর জন্য ভালো), কিন্তু hot shard এর risk থাকে। Hash-based data সমানভাবে ছড়ায়, কিন্তু related data আলাদা হয়ে যায়। Universally সঠিক কোনো choice নেই। আপনার application কীভাবে data read করে, তার উপর নির্ভর করে।

ভালো shard key এর গুণ

দুইটা property একসাথে থাকলে তবেই shard key কাজের।

  1. 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_idHigh cardinality, even distribution”customer X এর সব order” সব shard এ ছড়িয়ে যায়
customer_idএকজন customer এর order এক shard এ group হয়। “আমার সব order দেখাও” fastবিশাল corporate customer hot shard তৈরি করে
countryতেমন কোনো সুবিধা নেইLow cardinality; distribution অত্যন্ত uneven
মূল lesson

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 করতে হবে।

Scatter-Gather

সব 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 গুলোর একটা।

এক কথায় lesson

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।

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 বলে।

Runtime Fix গুলো
  1. Hot key টা cache করুন (Session 04)। বেশিরভাগ read shard পর্যন্ত পৌঁছায়ই না। সাধারণত এটাই FIRST move (সবচেয়ে cheap, fast, আর অনেক identical read এর জন্য best fit)।
  2. Hot shard টা replicate করুন (Session 03)। Read replica যোগ করে read load ছড়িয়ে দিন।
  3. ওই outlier এর জন্য একটা dedicated shard। Permanent mega-key (celebrity account) কে তার নিজস্ব shard দিয়ে দিন।
Lesson

ভালো 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 এ দুই ধরনের জিনিস বসানো হয়:

  1. Shard গুলো: প্রতিটা shard এর identifier (নাম বা IP) hash করে ring এ একটা fixed position পায়। Shard A, B, C, D; প্রতিটার position বদলায় না।
  2. 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।

আগে - ৪টা Shard clockwise A B C D user_7 → B user_m → A user_m clockwise → D পার করে → A তে পৌঁছায় E যোগ হওয়ার পর affected ~1/5 data A B C D E নতুন! user_7 → B user_m → E শুধু D-E arc এর key গুলো E তে গেলো। বাকি সব অপরিবর্তিত।
বাম: ৪টা shard; user_m clockwise হেঁটে A তে পৌঁছায়। ডান: E যোগ হলো D আর A এর মাঝে। শুধু highlighted arc এর key গুলো নতুন E তে গেলো, বাকি সব অপরিবর্তিত।

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।

Virtual Nodes

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 আছে।

CLIENT LOAD BALANCER APPLICATION CACHE SHARD ROUTER SHARDS ইউজার ইউজার ইউজার LB-1 Active LB-2 Passive heartbeat Stateless Web 1 App Server Web 2 App Server Web 3 App Server Redis Cache cache-aside · TTL · delete-on-write cache miss Shard Router hash(shard_key) → correct shard Shard A Primary Shard B Primary Shard C Primary Replica Layer প্রতিটা Shard Primary নিজের Replica তৈরি করে Read Traffic এই Layer থেকে Serve হয় · Write সরাসরি সংশ্লিষ্ট Primary তে আসে Sharding replication আর caching কে replace করে না - এদেরকে সাথে নিয়ে কাজ করে
Web → Cache = primary read path (highlighted). Cache miss → Shard Router → correct Shard Primary. প্রতিটা Shard Primary নিজের Replica manage করে - read সেই replica layer থেকে serve হয়।

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 - সবকিছু হ্যান্ডেল করতে হয় কোড লেভেল থেকে।
সবচেয়ে গুরুত্বপূর্ণ lesson

Write bottleneck প্রমাণিত না হওয়া পর্যন্ত shard করবেন না। এটা scaling এর last step, first না। আগে vertical scaling, read replica, আর caching শেষ করুন। শুধু যখন একটা primary সত্যিই write volume সামলাতে পারে না এবং আপনার কাছে তার যথেষ্ট প্রমাণ আছে, তখনই sharding এর permanent complexity গ্রহণ করুন। অনেকেই অনেক আগেই shard করে ফেলে, আর তার cost বহন করতে থাকে, অথচ হয়তো সেই মুহূর্তে sharding এর দরকারই ছিলো না।

০৯ মগজে প্রেশার দিন

আগে নিজে ভাবুন। তারপর দেখুন: সবাই যেভাবে ভাবে, কেন সেটা অসম্পূর্ণ, আর আসল insight টা কোথায়।

প্রশ্ন ১: Replication যেখানে পারেনি, Sharding সেখানে write scale করে কেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“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।

প্রশ্ন ২: Chat app এ একটা messages table shard করতে হবে। সবচেয়ে common query হলো "conversation #123 এর সব message order এ দেখাও।" Shard key কী হবে? Downside কী?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

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 হয়ে যায়।

মূল pattern

Dominant query কে access pattern হিসেবে চিনুন, তারপর সেই pattern অনুযায়ী shard key বেছে নিন। একসাথে ব্যবহার হওয়া data একই shard এ রাখুন। Trade-off টা (hot shard এর risk) মেনে নিন, কারণ alternative (scatter-gather) আরো খারাপ।

প্রশ্ন ৩: ৫,০০০ user এর একটা startup বলছে "এখনই shard করবো, যাতে পরে scale নিয়ে কখনো চিন্তা করতে না হয়।" কীভাবে পুশব্যাক করবেন?
উত্তর দেখুন আগে নিজে ভাবুন

সবাই যেভাবে ভাবে

“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।

১০ যে টার্মগুলো শিখলাম

টার্মমানে
ShardingData কে টুকরো (shard) করে ভাগ করা, প্রতিটা আলাদা machine এ আলাদা data ধরে।
Shardভাগ করা data এর একটা টুকরো। একটা slice, clone না।
Shard keyযে data field দিয়ে ঠিক করা হয় একটা row কোন shard এ থাকবে।
Range-based shardingKey এর range দিয়ে ভাগ করা। Range query ভালো, hot shard এর risk।
Hash-based shardingKey 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 / transactionShard cross করা operation। কঠিন বা impossible; app-level handling বা distributed transaction লাগে।
ReshardingShard যোগ/বাদ দিয়ে data সরানো। % N এ massive data movement, consistent hashing এ সহনীয়।
Consistent hashingKey আর shard কে একটা ring এ বসানো, যাতে shard যোগ/বাদ দিলে শুধু ~1/N data সরে।
Virtual nodesপ্রতিটা physical shard কে ring এ অনেক জায়গায় বসানো, যাতে load even থাকে।
Shard routerযে component shard key hash করে request টা সঠিক shard এ route করে।

১১ সর্ট সামারী

  1. Sharding data কে slice করে অনেক machine এ ছড়ায়, যাতে প্রতিটা নিজের write নিতে পারে। writes scale করার এটাই একমাত্র উপায়, যেটা replica আর cache পারে না।
  2. Shard key সবচেয়ে গুরুত্বপূর্ণ decision: high cardinality আর even access থাকতে হবে, আর এটাই ঠিক করে কোন operation fast থাকবে (single-shard) আর কোনটা কঠিন হবে (cross-shard)।
  3. Naive % N hashing এ একটা shard যোগ করলে প্রায় সব data সরে যায়; consistent hashing এটা fix করে key আর shard কে একটা ring এ বসিয়ে, যাতে শুধু ~1/N data সরে।

১২ মনে রাখুন