Database Sharding
- ●Sharding হলো একটা বড় ডেটাবেজকে অনেক ছোট অংশে (shard) ভাগ করে আলাদা সার্ভারে রাখা — horizontal partitioning।
- ●সঠিক shard key বাছাই সবচেয়ে গুরুত্বপূর্ণ সিদ্ধান্ত; ভুল বাছাইয়ে hotspot তৈরি হয়।
- ●Range, hash, ও geo/directory — তিন মূল কৌশল; resharding আর cross-shard query এর বড় চ্যালেঞ্জ।
সমস্যাটা কী?
ধরো তোমার সোশ্যাল অ্যাপ দারুণ চলছে — ব্যবহারকারী এখন ৫ কোটি, আর ডেটাবেজে রোজ লক্ষ লক্ষ পোস্ট জমছে। এক সময় তোমার একটাই শক্তিশালী ডেটাবেজ সার্ভার সব সামলাত। কিন্তু এখন:
- ডেটা এত বড় যে একটা মেশিনের disk/RAM-এ আঁটছে না।
- এত query আসছে যে একটা সার্ভার CPU ও connection-এ হাঁপিয়ে উঠছে।
- সার্ভারটা আরও বড় করা (vertical scaling — বেশি RAM, বেশি CPU) একটা সীমার পর সম্ভব নয়, আর ভয়ানক ব্যয়বহুল।
প্রথমে তুমি read replica যোগ করলে — পড়ার চাপ ভাগ হলো। কিন্তু লেখা (write) এখনো একটাই সার্ভারে, আর পুরো ডেটা একটাই মেশিনে। যখন একটা মেশিনে আর কুলোয় না, তখন উপায় একটাই — ডেটাকে অনেক মেশিনে ভাগ করে দেওয়া। এটাই Sharding।
মূল ধারণা
Sharding হলো horizontal partitioning — একটা বড় টেবিলের row-গুলোকে নির্দিষ্ট নিয়মে ভাগ করে একাধিক স্বাধীন ডেটাবেজ সার্ভারে (shard) ছড়িয়ে দেওয়া, যেখানে প্রতিটা shard পুরো schema-র একটা অংশ ধরে রাখে।
লক্ষ করো — এটা horizontal partitioning (row ভাগ করা), vertical নয় (vertical মানে কলাম আলাদা করা)। প্রতিটা shard হলো একটা পূর্ণাঙ্গ ডেটাবেজ, কিন্তু তাতে থাকে মোট ডেটার একটা অংশ। যেমন ৫ কোটি user-কে ৫টা shard-এ ভাগ করলে প্রতিটায় থাকবে ১ কোটি করে।
কোন row কোন shard-এ যাবে তা ঠিক করে Shard Key — যেমন user_id। এই key-ই sharding-এর সবচেয়ে গুরুত্বপূর্ণ সিদ্ধান্ত।
কীভাবে কাজ করে
ধাপে ধাপে
- তুমি একটা shard key বেছে নাও (যেমন
user_id)। - একটা নিয়ম ঠিক করো — যেমন
shard_number = hash(user_id) % 4। - কোনো ব্যবহারকারীর ডেটা লাগলে অ্যাপ আগে নিয়ম প্রয়োগ করে বের করে কোন shard-এ যেতে হবে, তারপর সরাসরি সেই shard-এ যায়।
- এতে প্রতিটা shard মোট ট্রাফিকের একটা ভগ্নাংশ সামলায়, আর তুমি নতুন shard যোগ করে আনুভূমিকভাবে (horizontally) scale করতে পারো।
routing-এর তুলনা
| কৌশল | নিয়ম | সুবিধা | অসুবিধা |
|---|---|---|---|
| Range | key-র সীমা অনুযায়ী (A–M, N–Z) | range query সহজ | hotspot হওয়ার ঝুঁকি বেশি |
| Hash | hash(key) % N | ডেটা সমান ছড়ায় | range query কঠিন, resharding ব্যয়বহুল |
| Geo/Directory | অঞ্চল/lookup টেবিল অনুযায়ী | নমনীয়, locality ভালো | আলাদা lookup ব্যবস্থা লাগে |
Consistent Hashing-এর সম্পর্ক
সাধারণ hash(key) % N-এ একটা বড় সমস্যা আছে — shard সংখ্যা N বদলালে (নতুন সার্ভার যোগ করলে) প্রায় সব key-র জন্য % N-এর ফল বদলে যায়, ফলে প্রায় পুরো ডেটা নতুন জায়গায় সরাতে হয়। এটা বিপর্যয়। এই সমস্যা সমাধানে ব্যবহৃত হয় consistent hashing, যেখানে সার্ভার যোগ/বাদ দিলে শুধু সামান্য ডেটা সরে। নিচের টুলে নিজে হাতে চালিয়ে দেখো এটা কীভাবে কাজ করে:
ভাবো বাংলাদেশের একটা বিশাল ডাক বিভাগ। সব চিঠি যদি একটাই কেন্দ্রীয় অফিসে জমা হয়, সেটা উপচে পড়বে। তাই দেশকে জেলা/বিভাগ অনুযায়ী ভাগ করা হয়েছে — ঢাকার চিঠি ঢাকার সর্টিং অফিসে, চট্টগ্রামের চিঠি চট্টগ্রামে (এটাই geo sharding)। ঠিকানার পোস্ট কোডই হলো shard key — সেটা দেখেই বোঝা যায় চিঠি কোন অফিসে যাবে। কোনো একটা শহরে হঠাৎ অনেক বেশি চিঠি এলে সেই অফিস hotspot হয়ে যায়।
কৌশল
১. Range-based Sharding
key-র মান অনুযায়ী টানা সীমায় ভাগ — যেমন user_id ১–১০ লাখ shard 1-এ, ১০–২০ লাখ shard 2-এ।
- সুবিধা: range query (যেমন একটা সময়সীমার ডেটা) সহজ, কারণ পাশাপাশি ডেটা একই shard-এ।
- অসুবিধা: নতুন user সবসময় শেষ shard-এ যায়, ফলে সেটা hotspot হয়ে পড়ে; ডেটা অসম হয়।
২. Hash-based Sharding
shard key-কে hash করে % N দিয়ে shard ঠিক করা।
- সুবিধা: ডেটা প্রায় সমানভাবে ছড়ায়, hotspot কম।
- অসুবিধা: পাশাপাশি ডেটা ছড়িয়ে যায় বলে range query কঠিন; shard সংখ্যা বদলালে resharding কষ্টকর (এখানেই consistent hashing দরকার)।
৩. Geo / Directory-based Sharding
ব্যবহারকারীর অঞ্চল অনুযায়ী (যেমন ইউরোপের ডেটা ইউরোপীয় shard-এ), অথবা একটা আলাদা lookup directory টেবিল রেখে যা বলে দেয় কোন key কোন shard-এ।
- সুবিধা: locality ভালো (ব্যবহারকারীর কাছের shard), নমনীয় — directory বদলে সহজে rebalance করা যায়।
- অসুবিধা: directory নিজেই একটা single point of failure হতে পারে; বাড়তি একটা lookup ধাপ লাগে।
Resharding-এর কষ্ট
ডেটা বাড়লে shard সংখ্যা বাড়াতে হয় — একে বলে Resharding। এটা ঝুঁকিপূর্ণ ও ব্যয়বহুল কাজ, কারণ চলন্ত সিস্টেমে বিপুল ডেটা এক shard থেকে আরেকটায় সরাতে হয়। তাই অনেকে আগেভাগেই বেশি (logical) shard বানিয়ে রাখে।
কখন ব্যবহার করবে / করবে না
করবে:
- যখন ডেটা/ট্রাফিক একটা মেশিনের সীমা ছাড়িয়ে গেছে এবং read replica-ও যথেষ্ট নয়।
- যখন write throughput-ও scale করা দরকার।
করবে না (যতক্ষণ না নিশ্চিত দরকার):
- ছোট/মাঝারি অ্যাপে — sharding আগে বসিয়ে ফেলা মানে অযথা জটিলতা ডেকে আনা।
Sharding হলো শেষ অস্ত্র, প্রথম নয়। একবার shard করলে cross-shard JOIN, distributed transaction, আর global unique ID সব কঠিন হয়ে যায়। সবচেয়ে বড় ফাঁদ — ভুল shard key। key এমন হতে হবে যা ডেটা ও ট্রাফিক সমানভাবে ছড়ায়। যেমন country-কে shard key বানালে বাংলাদেশের shard উপচে পড়বে আর ছোট দেশের shard ফাঁকা থাকবে — ধ্রুপদী hotspot। key বদলানো প্রায় অসম্ভব, তাই আগে ভালো করে ভাবো।
বাস্তব উদাহরণ
Instagram তাদের PostgreSQL ডেটাবেজ shard করেছে user-ভিত্তিক ভাগে। তারা একটা চতুর কৌশল ব্যবহার করে — প্রতিটা ID-র ভেতরেই shard নম্বর এমনভাবে এনকোড করা থাকে যে ID দেখেই বোঝা যায় ডেটা কোন shard-এ আছে, আলাদা lookup ছাড়াই। এতে কোটি কোটি ব্যবহারকারীর ডেটা বহু মেশিনে ছড়িয়েও দ্রুত route করা যায়।
আবার Discord তাদের বিশাল message ডেটার জন্য Cassandra (পরে ScyllaDB) ব্যবহার করে, যা ভেতরে ভেতরে consistent hashing দিয়ে স্বয়ংক্রিয়ভাবে ডেটা shard ও rebalance করে।
ইন্টারভিউতে "ডেটাবেজ scale করবে কীভাবে?" জিজ্ঞেস করলে লাফিয়ে sharding-এ যেও না। ক্রম মেনে বলো — প্রথমে index ও query অপটিমাইজেশন, তারপর caching, তারপর read replica, এবং একদম শেষে sharding। আর sharding বললেই সাথে shard key-র যুক্তি, hotspot ঝুঁকি, আর consistent hashing উল্লেখ করো — তবেই উত্তরটা পূর্ণ মনে হবে।
মূল শব্দ (Key Terms)
মিনি কুইজ
1. Sharding আসলে কী?
2. ভুল shard key বাছাইয়ের সবচেয়ে সাধারণ সমস্যা কোনটি?
3. Cross-shard query কেন কঠিন?