Backend Deep Dives · موضوع ۰۳Backend Deep Dives · Topic 03

تقسیم افقی داده Data Sharding

وقتی یک دیتابیس دیگر جوابگوی حجم داده‌ها، نرخ نوشتن یا تعداد درخواست‌ها نیست، داده‌ها را بین چند دیتابیس مستقل توزیع می‌کنیم. در عوض، پیچیدگی مسیریابی، تراکنش‌ها و نگهداری سیستم بر عهده ما می‌افتد. When one database can no longer handle the data volume, write rate, or request load, we distribute data across independent databases. In return, routing, transactions, and operations become our responsibility.

نکته کلیدی: شاردینگ نه یک «ایندکس بزرگ‌تر» است و نه جایگزینی برای پارتیشن‌بندی درون یک دیتابیس؛ بلکه یک تصمیم معماری برای مقیاس‌پذیری افقی (Scale-out) است. The central idea: sharding is not a bigger index, nor a drop-in replacement for table partitioning; it is an architectural decision for scale-out.
shard-router.live
SELECT * FROM Orders WHERE TenantId = 42;
TenantId = 42 در بازه Shard A قرار دارد؛ روتر مستقیم به همان‌جا می‌زند. نقاط کوچک Replicaهای همان شاردند (کپی، نه شارد جدید). TenantId = 42 lives on Shard A; the router hits it directly. The small dots are its replicas (copies, not new shards).
01

شاردینگ دقیقاً چیست؟What exactly is sharding?

شاردینگ یعنی تقسیم افقی داده‌ها بین چند دیتابیس یا نود مستقل. هر شارد مالک بخش جداگانه‌ای از داده‌هاست و معمولاً ساختار جداول (Schema) در همه شاردها یکسان است. برای رساندن هر درخواست به مقصد درست، یک روتر، پروکسی یا خود موتور دیتابیس از کلیدی به نام Shard Key استفاده می‌کند. Sharding is horizontal distribution of data across multiple independent databases or nodes. Each shard owns a disjoint subset of the data, usually with the same schema. A router, proxy, or the database engine uses a shard key to find the right destination.

یکی از مفاهیمی که اغلب با شارد اشتباه گرفته می‌شود Replica است. Replica یک کپی از همان شارد است که برای افزایش دسترس‌پذیری (Availability) یا توزیع بار خواندن ساخته می‌شود. شارد داده‌های متفاوتی دارد؛ Replica داده‌های یکسانی دارد. مثلاً اگر ۳ شارد داشته باشید و هرکدام ۲ Replica، در مجموع ۳ مجموعه داده دارید که هرکدام در ۳ نسخه (۱ اصلی + ۲ کپی) نگهداری می‌شوند. A concept often confused with a shard is a Replica. A replica is a copy of the same shard, created for higher availability or to distribute read load. A shard holds different data; a replica holds the same data. For example, 3 shards with 2 replicas each means 3 distinct datasets, each maintained in 3 copies (1 primary + 2 replicas).

SHARD

مالک بخشی از داده‌هاOwns a subset of data

مثلاً Shard A ممکن است Tenantهای ۱ تا ۱۰۰ را نگه دارد و Shard B Tenantهای ۱۰۱ تا ۲۰۰ را.Shard A may own tenants 1–100 while Shard B owns tenants 101–200.

REPLICA

کپی همان بخش دادهCopies the same subset

Replica A دقیقاً همان داده‌های Shard A را نگه می‌دارد. اگر Shard A از کار بیفتد، Replica جایگزین می‌شود. Replica شارد جدید نیست.Replica A holds the exact same data as Shard A. If Shard A fails, a replica can take over. A replica is not a new shard.

تقسیم افقی داده‌هاRows are split horizontally

هر شارد تمام ستون‌های جدول را دارد، ولی فقط مالک بخشی از سطرهاست.Each shard has the schema's columns, but owns only part of the rows.

مسیریابی وارد بازی می‌شودRouting becomes a concern

برای هر درخواست باید بدانید کلید در کدام شارد است؛ وگرنه مجبورید درخواست را به همه شاردها بفرستید (Fan-out).Each request needs a destination; otherwise it may fan out to every shard.

هر شارد یک دیتابیس مجزاستEach shard is a data store

ظرفیت، خرابی، بکاپ، مهاجرت داده و مانیتورینگ دیگر به یک نمونه محدود نیستند.Capacity, failure, backups, migrations, and monitoring are no longer single-instance concerns.

تفاوت مهم

واژه «Partition» اصطلاحی عمومی برای تکه‌تکه کردن داده‌هاست. «Table Partitioning» معمولاً درون یک دیتابیس انجام می‌شود (موتور دیتابیس خودش داده‌ها را تکه‌تکه نگه می‌دارد)، ولی «Sharding» داده‌ها را بین چند دیتابیس یا سرور جداگانه توزیع می‌کند. مرز این دو در محصولات مختلف فرق دارد؛ همیشه معماری دیتابیس خودتان را بررسی کنید."Partition" is a broad term. Table partitioning usually keeps the data inside one database, while sharding distributes it across databases or nodes. Product terminology varies, so verify the actual architecture of the platform you use.

02

چه زمانی شاردینگ منطقی است؟When does sharding make sense?

شاردینگ اولین راه‌حل برای کندی کوئری‌ها نیست. قبل از آن راهکارهای ساده‌تری وجود دارد. جدول زیر این راهکارها را از ساده‌ترین تا پیچیده‌ترین مرتب کرده و نشان می‌دهد هرکدام چه مشکلی را حل می‌کنند و چه هزینه‌ای دارند. شاردینگ آخرین گزینه در این لیست است.Sharding is not the first tool for a slow query. Simpler options exist. The table below lists them from simplest to most complex, showing what each solves and what it costs. Sharding is the last resort.

مرحلهStep راهکارOption چه مشکلی را حل می‌کند؟What problem it solves هزینه و محدودیتCost and limitation
۱ بهینه‌سازی کوئری و ایندکسQuery and index optimization کوئری‌های کند، اسکن‌های غیرضروری جدولSlow queries, unnecessary table scans کم؛ بدون تغییر معماریLow; no architectural change
۲ ارتقای سخت‌افزار (Scale-up)Scale up (bigger hardware) کمبود CPU، RAM یا دیسک در یک سرورCPU, RAM, or storage shortage on one instance کم؛ کوئری‌ها تغییر نمی‌کنند. سقف فیزیکی و هزینه‌ای داردLow; queries stay the same. Has a physical and cost ceiling
۳ Replica خواندنی (Read Replica)Read replicas بار زیاد خواندن؛ درخواست‌های خواندن به کپی‌ها هدایت می‌شوندHigh read load; reads are routed to copies of the database متوسط؛ فقط خواندن را مقیاس می‌دهد. گلوگاه نوشتن باقی می‌ماندMedium; scales reads only. Write bottleneck remains
۴ پارتیشن‌بندی جدول (Table Partitioning)Table partitioning جداول بسیار بزرگ درون یک دیتابیس؛ موتور دیتابیس خودش مدیریت می‌کندVery large tables inside one database; engine-managed کم تا متوسط؛ همه داده‌ها هنوز روی یک سرورندLow to medium; all data still on one server
۵ شاردینگ (Sharding)Sharding ظرفیت و توان پردازشی از یک سرور فراتر رفته؛ داده‌ها بین چند دیتابیس توزیع می‌شوندCapacity and throughput exceed one server; data is distributed across databases زیاد؛ نیاز به مسیریابی، مدیریت تراکنش توزیع‌شده و عملیات پیچیده‌ترHigh; requires routing, distributed transaction handling, and complex operations
نکتهTip

این ترتیب قانون مطلق نیست، ولی یک قاعده سرانگشتی خوب است: همیشه ساده‌ترین راهکاری که مشکل را حل می‌کند انتخاب کنید. شاردینگ را فقط وقتی انتخاب کنید که راهکارهای قبلی مشکل شما را حل نکنند.This order is not absolute, but it is a good rule of thumb: always pick the simplest option that solves the problem. Choose sharding only when the simpler options are insufficient.

حالا ببینیم چه نشانه‌هایی نشان می‌دهد که واقعاً به شاردینگ نیاز دارید و چه نشانه‌هایی می‌گویند هنوز زود است:Now let's see which signals suggest you actually need sharding, and which suggest it's too early:

نشانه‌های مناسبSignals that may justify it

  • حجم داده‌ها یا Working Set از ظرفیت عملی یک سرور فراتر می‌رود.The total data or working set exceeds one instance's practical capacity.
  • نرخ نوشتن از توان یک سرور بیشتر می‌شود و Replica مشکل نوشتن را حل نمی‌کند.Write throughput exceeds one instance, and replicas do not solve write pressure.
  • بیشتر درخواست‌ها ذاتاً به یک Tenant یا حساب کاربری محدودند.Most requests are naturally scoped to one tenant or account.

نشانه‌های نامناسبSignals to stop and reconsider

  • مشکل فقط یک کوئری بد یا ایندکس ناقص است.The problem is one bad query or a missing index.
  • گزارش‌های کلان و JOINهای سراسری بخش عمده بار سیستم‌اند.Global reports and cross-entity joins dominate the workload.
  • تراکنش‌ها دائماً نیاز به تغییر اتمیک داده در چند شارد دارند.Transactions frequently need atomic writes across several shards.
03

Shard Key؛ حیاتی‌ترین تصمیم طراحیThe shard key: the most important design decision

Shard Key ستون یا ترکیبی از ستون‌هاست که مشخص می‌کند هر رکورد در کدام شارد ذخیره شود. یک کلید خوب هم بار را توزیع می‌کند و هم کوئری‌های پرتکرار را تک‌شاردی نگه می‌دارد؛ هیچ کلیدی برای همه سناریوها بی‌نقص نیست.A shard key is the field or compound key that determines where a row or entity lives. A good key balances load and keeps common queries targeted; no key is best for every workload.

یک Shard Key خوب باید سه ویژگی اصلی داشته باشد:A good shard key must have three main properties:

1قابلیت توزیعDistributable

باید مقادیر متنوعی با توزیع نسبتاً یکنواخت داشته باشد. کلیدی مثل Status که فقط سه مقدار دارد برای توزیع بار مناسب نیست.It should have enough values and reasonably even distribution; a three-value field such as Status is usually a poor distribution key.

2قابلیت مسیریابیRoutable

باید در کوئری‌های پرکاربرد حضور داشته باشد تا روتر مجبور به Broadcast به همه شاردها نشود.It should appear in important queries so the router can avoid broadcasting to every shard.

3پایدار و غیرقابل تغییرStable and immutable

تا حد امکان نباید تغییر کند؛ تغییر کلید یعنی جابه‌جایی داده و حفظ یکپارچگی حین انتقال.It should rarely change; changing it can mean moving an entity and coordinating consistency during the move.

الگوی چندمستاجری (Multi-tenant)Multi-tenant pattern

اگر تقریباً هر درخواستی TenantId دارد، شارد کردن بر اساس Tenant می‌تواند بیشتر کوئری‌ها را تک‌شاردی نگه دارد. اما یک Tenant خیلی بزرگ ممکن است Hot Shard ایجاد کند و کلید مرکب (Compound Key) ضروری شود.If almost every request has a TenantId, tenant-based sharding can keep most queries single-shard. But one very large tenant can create a hot shard; large tenants may need a compound key or special treatment.

توزیع خوب به‌تنهایی کافی نیستEven distribution is not enough

کلیدی که داده‌ها را عالی پخش می‌کند ولی در کوئری‌ها نیست، فقط باعث Fan-out می‌شود. همراه با تنوع مقادیر، باید الگوهای دسترسی و JOINهای آینده را هم در نظر بگیرید.A key that distributes evenly but never appears in queries only creates fan-out. Evaluate workload, joins, entity size, and future operations alongside cardinality.

04

استراتژی‌های توزیع: Range، Hash و DirectoryDistribution strategies: range, hash, and directory

این نام‌ها دسته‌بندی‌های رایج‌اند، نه سینتکسی یکسان برای همه دیتابیس‌ها. تفاوت اصلی در نحوه تعیین مقصد هر رکورد، امکان اجرای کوئری بازه‌ای و سادگی جابه‌جایی داده‌هاست.These are common families, not a universal syntax. The key differences are how each record's destination is determined, whether range queries can be targeted, and how easy it is to move data.

نمونه تعاملی: انتخاب استراتژیConceptual strategy demo

در هر تب، یک مجموعه داده را با مدل توزیع متفاوت ببینید. هدف درک trade-offهاست، نه نمایش سینتکس یک محصول خاص.Switch tabs to see the same data under different placement models. These diagrams explain trade-offs; they are not product-specific syntax or guarantees.

range map

A1–100
B101–200
C201–300
D301–400

Range Sharding (توزیع بازه‌ای)Range sharding

مقادیر نزدیک به هم در یک شارد قرار می‌گیرند. کوئری‌های بازه‌ای می‌توانند هدفمند باشند، ولی اگر بار روی یک بازه خاص متمرکز شود، Hotspot ایجاد می‌شود.Nearby values stay together. Range queries can be targeted, but a busy recent range or a popular value can create skew and a hot shard.

1–100 → A · 101–200 → B · 201–300 → C

فارغ از نوع استراتژی، دو نکته مهم وجود دارد:Regardless of the strategy, two important points apply:

کلید مرکب و نگهداری داده‌های مرتبط کنار همCompound keys and keeping related data together

اگر چند جدول (مثلاً Orders و OrderItems) همیشه با هم JOIN می‌شوند، بهتر است هر دو را بر اساس TenantId توزیع کنید. اینطوری داده‌های یک Tenant در همه جداول روی همان شارد قرار می‌گیرند و JOIN بدون رفتن به شاردهای دیگر انجام می‌شود. به این کار Co-location (هم‌مکان‌سازی) می‌گویند.If multiple tables (e.g. Orders and OrderItems) are always joined together, distribute both by TenantId. This way, one tenant's data across all tables lives on the same shard, and joins complete without crossing shard boundaries. This is called co-location.

Hotspot را جداگانه مدیریت کنیدTreat hotspots separately

حتی اگر تعداد رکوردها بین شاردها مساوی باشد، بار ترافیک ممکن است مساوی نباشد. مثلاً یک Tenant کوچک ممکن است ۸۰٪ کل درخواست‌ها را تولید کند. برای تشخیص Hotspot، به‌جای شمردن سطرها، CPU، I/O و Latency هر شارد را اندازه بگیرید.Even if row counts are equal across shards, traffic load may not be. A small tenant might generate 80% of all requests. To detect hotspots, measure each shard's CPU, I/O, and latency instead of just counting rows.

05

مسیریابی: چطور درخواست به شارد درست می‌رسد؟Routing: how does a request reach the right shard?

وقتی کوئری‌ای اجرا می‌شود، روتر باید تصمیم بگیرد آن را به کدام شارد(ها) بفرستد. بسته به اینکه Shard Key در کوئری هست یا نه، یکی از این الگوها اتفاق می‌افتد:When a query runs, the router must decide which shard(s) to send it to. Depending on whether the shard key is in the query, one of these patterns occurs:

Targeted (هدفمند)Targeted

کوئری شامل Shard Key است. روتر دقیقاً می‌داند به کدام شارد(ها) برود. سریع‌ترین و ارزان‌ترین حالت.The query includes the shard key. The router knows exactly which shard(s) to hit. The fastest and cheapest pattern.

Scatter/Gather (پخش و جمع‌آوری)Scatter/Gather

کوئری شامل Shard Key نیست. روتر مجبور است آن را به همه شاردها بفرستد، جواب‌ها را جمع‌آوری (Gather) و ادغام (Merge) کند. زمان پاسخ وابسته به کندترین شارد است.The query does not include the shard key. The router must send it to all shards, gather and merge the results. Response time depends on the slowest shard.

در دموی زیر، سه سناریو را امتحان کنید و ببینید هر کوئری چند شارد را درگیر می‌کند. اعداد Latency صرفاً آموزشی‌اند.In the demo below, try three scenarios and see how many shards each query touches. Latency numbers are educational only.

یک کوئری را به روتر بسپاریدSend a query through the router
SELECT * FROM Orders WHERE TenantId = 42;
API
client
router / shard map
Shard A1–100primary + replica
Shard B101–200primary + replica
Shard C201–300primary + replica
Shard D301–400primary + replica
شاردهای درگیرshards touched1 / 4
الگوی اجراexecution patterntargeted
latency مفهومیconceptual latency1×
روتر فقط Shard A را صدا می‌زند؛ بقیه شاردها درگیر نمی‌شوند.The router calls only Shard A; other shards are not involved.
هزینه Scatter/GatherScatter/Gather Cost

در Fan-out، زمان پاسخ وابسته به کندترین شارد به‌علاوه هزینه شبکه و Merge است. حتی اگر درخواست‌ها به‌صورت موازی ارسال شوند، یک شارد کند می‌تواند Latency کل درخواست را بالا ببرد. موازی‌سازی این هزینه را حذف نمی‌کند، فقط کمترش می‌کند.For fan-out, response time is bounded by the slowest shard plus network and merge cost. Even with parallel requests, one slow shard can raise the entire request's latency. Parallelism reduces but does not eliminate this cost.

06

JOIN، تراکنش و یکپارچگی در مرز شاردهاJoins, transactions, and consistency across shards

در یک دیتابیس معمولی، JOIN بین جداول و تراکنش‌های اتمیک کاملاً طبیعی‌اند. ولی وقتی داده‌ها بین چند شارد پخش شده‌اند، دو مشکل جدید پیش می‌آید:In a regular database, joins and atomic transactions are natural. But when data is spread across shards, two new problems arise:

عملیات درون‌شاردی (Single-shard)Single-shard operations

وقتی تمام داده‌های مورد نیاز یک کوئری یا تراکنش روی یک شارد هستند، همه چیز مثل یک دیتابیس عادی کار می‌کند: JOIN، تراکنش اتمیک و Constraintها همه در دسترس‌اند. این بهترین حالت است.When all data needed by a query or transaction is on one shard, everything works like a normal database: joins, atomic transactions, and constraints are all available. This is the best case.

عملیات بین‌شاردی (Cross-shard)Cross-shard operations

وقتی داده‌ها روی چند شارد مختلف پخش‌اند، JOIN مستقیم ممکن نیست. تراکنش اتمیک هم پیچیده می‌شود چون باید چند دیتابیس مستقل هم‌زمان Commit کنند. خرابی شبکه بین شاردها ممکن است یکی Commit کند و دیگری نکند.When data is on different shards, direct joins are not possible. Atomic transactions become complex because multiple independent databases must commit together. A network failure between shards may cause one to commit while another does not.

هدف طراحی این است که تا حد ممکن از عملیات بین‌شاردی اجتناب کنید:The design goal is to avoid cross-shard operations as much as possible:

چطور عملیات را درون‌شاردی نگه داریم؟How to keep operations single-shard

  • درخواست‌ها را همیشه با Shard Key شروع کنید تا تراکنش داخل یک شارد بسته شود.Always start requests with the shard key so the transaction stays on one shard.
  • جدول‌هایی که همیشه JOIN می‌شوند (مثل Orders و OrderItems) را با کلید مشترک توزیع کنید تا کنار هم بمانند (Co-location).Distribute tables that always join (e.g. Orders and OrderItems) with the same key so they stay together (co-location).
  • داده‌های مرجع کوچک و کم‌تغییر (مثل لیست کشورها) را در صورت پشتیبانی دیتابیس، در همه شاردها کپی کنید.Replicate small, rarely-changing reference data (e.g. country list) to all shards if the database supports it.

وقتی عملیات بین‌شاردی اجتناب‌ناپذیر استWhen cross-shard is unavoidable

  • Fan-out و Merge را در یک لایه مشخص پیاده کنید و هزینه‌اش را حساب کنید.Make fan-out and merge explicit in one layer and account for its cost.
  • برای فرآیندهای چندمرحله‌ای، از الگوی Saga استفاده کنید: هر مرحله یک عملیات مستقل است و در صورت خطا، مراحل قبلی جبران (Compensate) می‌شوند.For multi-step processes, use the Saga pattern: each step is independent, and earlier steps are compensated on failure.
  • اگر اتمیک بودن حیاتی است، Two-Phase Commit (2PC) ممکن است لازم باشد، ولی Latency و پیچیدگی مدیریت خطا زیاد می‌شود.If atomicity is critical, Two-Phase Commit (2PC) may be needed, but it adds significant latency and error-handling complexity.
نوع عملیاتOperation type مثالExample هزینهCost راه‌حل طراحیDesign solution
خواندن/نوشتن درون‌شاردیSingle-shard read/write خواندن سفارش‌های TenantId = 42Read orders for TenantId = 42 کم؛ مثل دیتابیس عادیLow; like a normal database Shard Key را در API الزامی کنیدRequire the shard key in the API
JOIN درون‌شاردیCo-located join JOIN بین Orders و OrderItems برای یک TenantJoin Orders with OrderItems for one tenant کم؛ اگر هر دو جدول با کلید مشترک توزیع شده باشندLow; if both tables share the distribution key جداول مرتبط را با کلید مشترک توزیع کنیدDistribute related tables with the same key
Scatter/GatherScatter/gather جمع کل فروش همه TenantهاTotal sales across all tenants متوسط تا زیاد؛ همه شاردها درگیرندMedium to high; all shards involved Timeout بگذارید و نتایج را موازی جمع کنیدSet timeouts and gather results in parallel
تراکنش بین‌شاردیCross-shard transaction انتقال موجودی بین دو Tenant روی شاردهای مختلفTransfer balance between two tenants on different shards زیاد؛ هماهنگی و Rollback دشوارHigh; coordination and rollback are hard بازطراحی با Saga یا 2PCRedesign with Saga or 2PC
.NET

در EF Core، هر DbContext معمولاً به یک کانکشن و در نتیجه یک شارد متصل است. اگر بخواهید از یک Context برای چند شارد استفاده کنید، ممکن است ندانید داده از کجا می‌آید. روش درست این است: ابتدا شارد مقصد را پیدا کنید، سپس با کانکشن همان شارد یک Context بسازید. مثال زیر این الگو را نشان می‌دهد:In EF Core, each DbContext is normally connected to one connection and therefore one shard. If you try to use one context for multiple shards, you may lose track of where data comes from. The correct approach: first find the target shard, then create a context with that shard's connection. The example below shows this pattern:

c# — data-dependent routing with EF Core
// 1. Find which shard owns this tenant
var shard = await shardResolver.ResolveAsync(tenantId, cancellationToken);

// 2. Create a DbContext connected to that specific shard
await using var db = await contextFactory.CreateAsync(
    shard.ConnectionString,
    cancellationToken);

// 3. Query — this only touches the target shard
var orders = await db.Orders
    .Where(x => x.TenantId == tenantId)
    .ToListAsync(cancellationToken);

// 4. Write — transaction stays on one shard
db.Orders.Add(new Order { TenantId = tenantId, Total = 1200 });
await db.SaveChangesAsync(cancellationToken);
نکته عملیPractical Tip

کد بالا مفهومی است. در محیط عملیاتی، ShardResolver باید کانکشن‌استرینگ‌ها را از Secret Manager بگیرد، Timeout و Retry داشته باشد، و حین Rebalancing از نقشه‌های قدیمی جلوگیری کند. هرگز کانکشن را بر اساس ورودی کاربر بدون اعتبارسنجی باز نکنید.The code above is conceptual. In production, the ShardResolver should get connection strings from a secret manager, have timeouts and retries, and prevent stale maps during rebalancing. Never open connections based on unvalidated user input.

07

عملیات واقعی: Rebalancing، جابه‌جایی و .NETOperations: rebalancing, movement, and .NET

اضافه کردن شارد جدید فقط ساخت یک دیتابیس نیست. باید اسکیما را Deploy کنید، نقشه مسیریابی را آپدیت کنید، بخشی از داده‌ها را منتقل کنید، درخواست‌های هم‌زمان حین جابه‌جایی را مدیریت کنید و صحت مسیرها را تأیید کنید.Adding a shard is more than creating a database. You must deploy the schema, update the map, move data, handle concurrent requests during the move, and verify counts and routes afterward.

افزودن شارد و انتقال یک بازهAdd a shard and move one range

این دمو فقط مفهوم Rebalancing را نشان می‌دهد: یک بازه از Shard A به Shard D منتقل می‌شود و نقشه باید هم‌زمان با داده‌ها به‌روز شود. در واقعیت، Locking، کپی داده، Cut-over و مدیریت خطا جزئیات حیاتی‌اند.This only illustrates rebalancing: one range moves from Shard A to Shard D, and the map must change consistently with the data. A real product must handle locking, copying, cut-over, and failures.

Shard Aقبل: دو بازهBefore: two ranges101–1501–100
Shard B151–250
Shard C251–350
هنوز جابه‌جایی انجام نشده.No movement has happened yet.

نقشه شاردها (Shard Map)Shard map

نقشه باید منبع قابل اعتمادی برای ارتباط کلید و مقصد باشد. کش کردن آن مفید است، ولی Invalidation، نسخه‌بندی و رفتار حین جابه‌جایی را از قبل تعریف کنید.The map must be a trusted source for the key-to-destination relationship. Caching helps, but define invalidation, versions, and behavior during moves.

اسکیما و MigrationSchema and migrations

مهاجرت دیتابیس باید روی تمام شاردها به نسخه یکسان برسد. استقرار مرحله‌ای و سازگاری رو به عقب (Backward Compatibility) امن‌تر از Deploy یک‌باره‌اند.Migrations must converge on the same version across shards. Staged rollout and backward compatibility are safer than a blind one-shot deploy.

.NET

مایگریشن‌های EF Core را برای هر شارد جداگانه و کنترل‌شده اجرا کنید. یک اسکریپت یا Pipeline بسازید که روی همه شاردها به‌ترتیب یا موازی Migration اجرا کند و نتیجه هرکدام را گزارش دهد. قبل از هر Deploy، سازگاری رو به عقب اسکیما را بررسی کنید.Run EF Core migrations for each shard separately through a controlled pipeline. Build a script that runs migrations on all shards and reports results. Always verify schema backward compatibility before deploying.

✓

خودآزمایی — قبل از شارد کردن پاسخ دهیدSelf-check — answer before you shard

اگر پاسخ سوالی را نمی‌دانید، به همان بخش برگردید. هدف حفظ کردن نام ابزارها نیست؛ باید بتوانید هزینه و مسیر یک درخواست را توضیح دهید.If you cannot answer one, return to that section. The goal is not memorizing product names; it is explaining the cost and path of a request.

شارد مالک بخش متفاوتی از داده‌هاست؛ Replica کپی همان بخش است. سه شارد می‌توانند داده‌ها را تقسیم کنند و هرکدام دو Replica برای دسترس‌پذیری بالاتر داشته باشند.A shard owns a different subset of data; a replica copies that same subset. Three shards can divide the data while each has two replicas.
روتر مجبور به Scatter/Gather می‌شود: کوئری به همه شاردها فرستاده می‌شود، پاسخ‌ها Merge می‌شوند و زمان پاسخ وابسته به کندترین شارد است.The router must scatter/gather: the query goes to every shard, results are merged, and response time depends on the slowest shard.
سه ویژگی: ۱) توزیع بار مناسب (Cardinality کافی) ۲) حضور در کوئری‌های پرتکرار (قابل مسیریابی) ۳) پایداری (تغییر نکند). یکنواختی تعداد سطرها به‌تنهایی کافی نیست؛ الگوهای دسترسی و Hotspot هم مهمند.Three properties: 1) good distribution (enough cardinality), 2) present in frequent queries (routable), 3) stable (rarely changes). Even row counts alone are not enough; access patterns and hotspots matter too.
درون‌شاردی: همه داده‌ها روی یک شاردند، JOIN و تراکنش مثل دیتابیس عادی کار می‌کنند. بین‌شاردی: داده‌ها روی چند شاردند، JOIN مستقیم ممکن نیست و تراکنش اتمیک نیاز به هماهنگی پیچیده (مثل 2PC یا Saga) دارد.Single-shard: all data on one shard, joins and transactions work normally. Cross-shard: data on multiple shards, direct joins are impossible, and atomic transactions need complex coordination (2PC or Saga).
بعد از پیدا کردن شارد مقصد و با کانکشن مخصوص همان شارد. هر Context به یک شارد متصل است. هرگز کانکشن را بر اساس ورودی غیرقابل اعتماد باز نکنید.After resolving the destination shard, using that shard's connection. Each context connects to one shard. Never open connections from unvalidated input.