Tizim dizayni kursi · 6-mavzu
TuzdiDinMuhammad

Database Sharding — ma’lumotni bo‘lib masshtablash

Bitta baza yozuv va hajmda yetmay qolganda, ma’lumotni bir nechta serverga gorizontal bo‘lib tashlaymiz. Noldan boshlab routing, taqsimlash strategiyalari, eng muhim qaror — shard key tanlash, NestJS/Prisma implementatsiyasi va sharding’ning qiyin tomonlarini (cross-shard, resharding) o‘rganamiz.

Stack: PostgreSQL · Prisma · NestJSMavzular: shard key · range/hash · cross-shardBog‘liq: 7-mavzu (Replikatsiya), 13 (Saga)

Bu darsda nima bor

1–5-qismlar sharding’ni noldan quradi: nega kerak, routing va bo‘laklar, taqsimlash strategiyalari, shard key tanlash va NestJS/Prisma implementatsiya. 6-qism sharding olib keladigan qiyinchiliklarni (cross-shard, resharding, hotspot) ochadi. 7-qism — eng muhimi: sharding oxirgi chora ekani va undan oldin nima qilish kerakligi.

01
Sharding · qism 1

Nega kerak — yozuv va hajm chegarasi

📚

Oddiy o‘xshatish: bitta ulkan kutubxonadagi millionlab kitobni topish va saqlash qiyin. Ularni harf bo‘yicha bo‘lasiz: A–G bitta binoda, H–O ikkinchisida… Endi har bino kichik va tez ishlaydi.

Bitta PostgreSQL serveringiz bor. Foydalanuvchilar o‘sdi, jadval 500 million qatorga yetdi, sekundiga yozuvlar soni ortdi.

Muammo

Bitta baza ma’lumot hajmi va yozuv tezligida chegaraga yetadi: disk to‘ladi, indekslar RAM’ga sig‘maydi, yozuv (write) bitta nodening imkonidan oshadi. Serverni kuchaytirish (vertikal masshtab) ma’lum chegaragacha ishlaydi — keyin eng qimmat server ham yetmaydi.

Yechim — sharding

Ma’lumotni bir nechta bazaga gorizontal bo‘lib tashlash (shard). Har shard ma’lumotning bir qismini saqlaydi (hammasining nusxasini emas!). Qaysi qator qaysi shardga tushishi shard key orqali aniqlanadi. Natijada yozuv va saqlash hajmi serverlar soniga ko‘paytiriladi.

3 ta tushunchani adashtirmang

Replikatsiya (7-mavzu) — bir xil ma’lumotning nusxalari (HA + o‘qish uchun). Partitioning — bitta baza ichida jadvalni bo‘laklarga bo‘lish (Postgres partitioning). Sharding — ma’lumotni bir nechta alohida serverga bo‘lish (yozuv + hajm uchun). Sharding — eng kuchli, lekin eng qiyin.

02
Sharding · qism 2

Asosiy g‘oya — routing va bo‘laklar

Sharding’ning yuragi — routing: kelgan so‘rov qaysi shardga borishini aniqlash. Buni shard key belgilaydi.

Routing layershard key = user_id Shard Auser_id % 3 = 0~33% ma’lumot Shard Buser_id % 3 = 1~33% ma’lumot Shard Cuser_id % 3 = 2~33% ma’lumot
Har shard — ma’lumotning bir BO‘LAGI (nusxa emas!), shard key bilan tanlanadi

Eng muhim farqni yana ta’kidlaymiz: replikatsiyada har node butun ma’lumotni saqlaydi (nusxa), shardingda har node faqat o‘z bo‘lagini. Shuning uchun sharding yozuv va hajmni haqiqatan masshtablaydi.

Birgalikda ishlatiladi

Katta tizimlar ikkalasini birga qo‘llaydi: har bir shard ichida yana replikalar bo‘ladi (har bo‘lak ham ishonchli, ham o‘qish uchun masshtablangan).

03
Sharding · qism 3

Strategiyalar — range, hash, directory

Ma’lumotni shardlarga taqsimlashning 3 asosiy usuli bor — har biri turli kelishuv bilan:

1 · Range-based (oraliq bo‘yicha)

Shard key qiymat oralig‘i bo‘yicha: ID 1–1M → Shard A, 1M–2M → Shard B. + Oraliq so‘rovlar oson (ketma-ket qatorlar bitta shardda). Notekislik xavfi: yangi ID’lar doim oxirgi shardga tushib, uni hotspot qiladi.

2 · Hash-based (xesh bo‘yicha) — eng keng tarqalgan

hash(user_id) % N. + Eng tekis taqsimot. Oraliq so‘rovlar qiyin (qo‘shni qatorlar har xil shardda); va oddiy % N bilan shard qo‘shish/o‘chirish og‘riqli (deyarli hammasi qayta ko‘chadi — buni consistent hashing hal qiladi, Deep’da).

3 · Directory/Lookup (kataloq bo‘yicha)

Alohida lookup jadval qaysi kalit qaysi shardda ekanini saqlaydi. + Eng moslashuvchan (istalgancha ko‘chirish mumkin). Qo‘shimcha "hop" va lookup jadval o‘zi zaiflik nuqtasi/bottleneck bo‘lishi mumkin.

Range 1–1M → A 1M–2M → B yangi → oxirgi (hotspot) Hash hash(key) % N tekis, lekin oraliq qiyin Directory lookup jadval moslashuvchan, +hop
Range (oraliq) · Hash (tekis) · Directory (moslashuvchan)
04
Sharding · qism 4

Shard key — eng muhim qaror

cardinality · distribution
🔑

Shard key — sharding’dagi ENG muhim qaror. U barcha narsani belgilaydi: taqsimot tekismi, so‘rovlar tez yoki sekinmi. Va uni keyin o‘zgartirish juda qiyin — shuning uchun boshidan to‘g‘ri tanlang.

Yaxshi shard key 3 ta shartni bajaradi

  • Yuqori kardinallik — ko‘p turli qiymat (user_id yaxshi; "mamlakat" yomon — atigi bir nechta qiymat).
  • Tekis taqsimot — qiymatlar shardlarga teng tarqalsin (hotspot bo‘lmasin).
  • So‘rov naqshiga mos — eng ko‘p so‘rovlar bitta shardga tushsin (cross-shard bo‘lmasin).
✓ Yaxshi: user_id (tekis) ABC ✕ Yomon: timestamp (hotspot) ABC 🔥
Yaxshi key tekis taqsimlaydi; yomon key bitta shardni yuklaydi
Klassik yomon tanlovlar

Timestamp / ketma-ket ID: barcha yangi yozuvlar oxirgi shardga tushadi → hotspot. Past kardinallik (status, mamlakat): bir nechta katta bo‘lak. Mashhur entity: bitta "yulduz" foydalanuvchi (millionlab follower) o‘z shardini cho‘ktiradi.

So‘rov naqshiga moslash

Agar tizim asosan "foydalanuvchi bo‘yicha" so‘rasa (uning buyurtmalari, profili) — user_id bo‘yicha shardlash ideal: bir foydalanuvchining hamma ma’lumoti bitta shardda, so‘rov tez. Lekin "mahsulot bo‘yicha" tez-tez so‘rasangiz, user_id yomon bo‘ladi — har so‘rov hamma shardga borishi kerak.

05
Sharding · qism 5

NestJS / Prisma implementatsiya

shard router · UUID

NestJS’da sharding uchun maxsus paket shart emas — har shardga alohida PrismaClient ulanib, kichik router servisi kalitni to‘g‘ri shardga yo‘naltiradi.

1 · Har shard uchun ulanish

// shard.config.ts — HAR shard uchun alohida Prisma client
const SHARD_URLS = [
  process.env.SHARD_0_URL,   // postgres://...@shard0:5432/shop
  process.env.SHARD_1_URL,   // postgres://...@shard1:5432/shop
  process.env.SHARD_2_URL,
];

2 · Shard router — kalitdan shardni topish

// shard-router.service.ts — kalitni to'g'ri shardga yo'naltiradi
@Injectable()
export class ShardRouter implements OnModuleInit {
  private clients: PrismaClient[] = [];

  onModuleInit() {
    this.clients = SHARD_URLS.map(
      (url) => new PrismaClient({ datasources: { db: { url } } }),
    );
  }

  // shard key (userId) -> qaysi shard (barqaror hash + modulo)
  forUser(userId: string): PrismaClient {
    const hash = createHash('md5').update(userId).digest().readUInt32BE(0);
    return this.clients[hash % this.clients.length];
  }

  all(): PrismaClient[] { return this.clients; }   // cross-shard uchun
}

3 · Foydalanish — so‘rov to‘g‘ri shardga

// orders.service.ts — foydalanuvchining buyurtmalari BITTA shardda (key=userId)
@Injectable()
export class OrdersService {
  constructor(private shards: ShardRouter) {}

  async getUserOrders(userId: string) {
    const db = this.shards.forUser(userId);          // to'g'ri shardni tanla
    return db.order.findMany({ where: { userId } }); // faqat SHU shardga so'rov (tez)
  }

  async create(userId: string, dto: CreateOrderDto) {
    const db = this.shards.forUser(userId);
    return db.order.create({ data: { userId, ...dto } });
  }
}
Global ID muammosi

Auto-increment ID sharding’da ishlamaydi: har shard 1, 2, 3… deb boshlaydi → konflikt. Yechim — boshidanoq UUID yoki Snowflake ID ishlatish (global noyob, shardga bog‘liq emas): id String @id @default(uuid()).

06
Chuqurlashtirilgan mavzu

Sharding‘ning qiyin tomonlari

cross-shard · resharding
⚠️

Sharding qudratli, lekin juda qimmat. Quyidagi muammolarni bilmasdan shardlamang — aks holda tizimingiz murakkablashadi-yu, foydasini ko‘rmaysiz.

1 · Cross-shard so‘rov va JOIN

Bir foydalanuvchining ma’lumoti bitta shardda bo‘lsa — tez. Lekin "barcha buyurtmalarni sana bo‘yicha sarala" kabi so‘rov hamma shardga borib, natijani birlashtirishni talab qiladi (scatter-gather) — sekin. Cross-shard JOIN esa umuman ishlamaydi:

// CROSS-SHARD so'rov: hamma shardga borib, natijani birlashtirish ("scatter-gather")
async countAllOrders(): Promise<number> {
  const counts = await Promise.all(
    this.shards.all().map((db) => db.order.count()),   // HAR shardga
  );
  return counts.reduce((a, b) => a + b, 0);            // app tomonida yig'amiz
}
// Sekin va og'ir: imkon qadar QOCHISH kerak (yoki alohida analitika DB ishlatish).

2 · Cross-shard tranzaksiya

Ikki foydalanuvchi turli shardda bo‘lsa, ular orasidagi pul o‘tkazmasi bitta ACID tranzaksiyada bo‘lmaydi (baza chegarasidan oshadi). Yechim — Saga + kompensatsiya (13-mavzu).

3 · Resharding (qayta taqsimlash) — eng og‘riqli

% N ishlatsang, shard qo‘shganda N o‘zgaradi va deyarli barcha ma’lumot ko‘chishi kerak — tizimni to‘xtatmasdan buni qilish juda qiyin. (Yechim: consistent hashing / virtual buckets — Deep qatlamda.)

4 · Hotspot va unique constraint

Yomon key bitta shardni cho‘ktiradi (hotspot). Bundan tashqari, global unique (masalan, email noyobligi) ham qiyinlashadi — chunki tekshiruv hamma shardga borishi kerak.

Sharding beradi
  • Yozuv va saqlash hajmini cheksizga yaqin masshtablaydi
  • Kichik indekslar — har shard tezroq
  • Parallel ishlash (so‘rovlar turli shardga)
Sharding olib keladi
  • Cross-shard so‘rov/JOIN/tranzaksiya qiyinlashadi
  • Resharding og‘riqli; shard key’ni o‘zgartirib bo‘lmaydi
  • Operatsion murakkablik keskin oshadi
07
Qaror

Qachon shardlash (va qachon yo‘q)

🛑

Eng muhim maslahat: sharding — oxirgi chora. Aksariyat loyihalar sharding’ga umuman muhtoj emas; ko‘pchilik undan oldingi arzonroq yechimlarni o‘tkazib yuborib, erta shardlaydi va keraksiz murakkablik oladi.

Sharding’dan OLDIN sinab ko‘ring (tartib bilan)

  • 1. Indekslash va so‘rov optimizatsiyasi — ko‘pincha "sekin baza" aslida yomon indeks/so‘rov.
  • 2. Keshlash (4-mavzu) — o‘qish yukini Redis bilan keskin kamaytirish.
  • 3. O‘qish replikalari (7-mavzu) — o‘qishni replikalarga taqsimlash.
  • 4. Vertikal masshtab — kuchliroq server (oddiy va arzonroq, ma’lum chegaragacha).
  • 5. Faqat shulardan keyin — sharding.
Agar baribir shardlash kerak bo‘lsa

1. Shard key’ni juda diqqat bilan tanla — u so‘rov naqshlaringizga mos, tekis va yuqori kardinalli bo‘lsin. Keyin o‘zgartirish deyarli imkonsiz.

2. Boshidanoq UUID/Snowflake ID ishlat (auto-increment emas).

3. Ilovani cross-shard JOIN’ga tayanmaydigan qilib loyihala (denormalizatsiya yoki alohida analitika bazasi).

4. Resharding’ni boshidan rejala — consistent hashing yoki ko‘p "virtual bucket" bilan (Deep).

08
Yakuniy

Eslab qolish kerak bo‘lgan 5 jumla

  • Sharding = ma’lumotni bir nechta serverga bo‘lib tashlash (har shard — bo‘lak, nusxa emas). Yozuv va hajmni masshtablaydi. Replikatsiya (nusxa) va partitioning (bitta baza ichida)dan farqli.
  • Strategiyalar: range (oraliq, hotspot xavfi), hash (tekis, oraliq qiyin), directory (moslashuvchan, +hop).
  • Shard key — eng muhim qaror: yuqori kardinallik + tekis taqsimot + so‘rov naqshiga mos. Timestamp/ketma-ket ID — hotspot.
  • Sharding olib keladigan qiyinchiliklar: cross-shard so‘rov/JOIN/tranzaksiya, resharding, hotspot, global unique. ID — UUID/Snowflake.
  • Sharding — oxirgi chora. Avval indeks, kesh, o‘qish replikasi, vertikal masshtab. Faqat chinakam yetmaganda shardla.

Bu mavzuning Deep/Senior qatlami (consistent hashing/virtual buckets, downtime’siz resharding, Vitess/Citus, distributed query, global secondary index, hot shard splitting) kerak bo‘lsa — ayting.

Yoki keyingi mavzu: “7-mavzu: Database Replication” — sharding’ning tabiiy jufti.