Tasma
Dars 04
System Design darsligi
@darslik · Dars 04
04o'rta160 daqiqa

Twitter tasmasi qanday ishlaydi

Ishni qachon bajarish kerak — yozishdami yoki o'qishda? 2012-yilgi 300K QPS Redis tasmasidan 2023-yilgi ochiq tavsiya algoritmigacha: 100 million obunachili akkaunt bu savolni qanday o'zgartiradi.

Fan-out on writeFan-out on readGibrid fan-outHot keySnowflake IDHidratsiyaTombstoneReytingk-way mergeSizga tavsiya (2023)Qayta qurish

Bu darsda nima o‘rganasiz

Oddiy tilda: siz har kuni ertalab o‘zingizga yoqqan 200 ta muallifning yangi maqolalarini o‘qimoqchisiz. Ikki yo‘l bor. Birinchisi — har ertalab 200 ta gazeta do‘koniga borib, har biridan oxirgi sonni olish. Ikkinchisi — mualliflar yangi maqola yozishi bilan uni sizning pochta qutingizga tashlab ketishlari, siz esa ertalab faqat qutini ochasiz. Ikkinchisi siz uchun ancha qulay. Lekin muallifning 100 million o‘quvchisi bo‘lsa, u bitta maqolani 100 million qutiga tashlashi kerak bo‘ladi.

Twitter tasmasi aynan shu ikki yo‘l orasidagi tanlov. “Twitter tasmasini loyihalang” — tizim dizayni intervyularidagi eng mashhur savol. U aldamchi: masala oddiy ko‘rinadi (“obunalarim yozgan narsalarni vaqt bo‘yicha ko‘rsat”), lekin ichida taqsimlangan tizimlarning eng nozik kelishuvlari yotadi.

Bu darsda asosiy savol bitta: ishni qachon bajaramiz — yozishda yoki o‘qishda? Javob “ikkalasida ham, lekin har xil odamlar uchun har xil” bo‘lib chiqadi. Nima uchun aynan shunday ekanini raqamda ko‘ramiz.

Dars noldan hozirgi holatigacha boradi. 2006-yildagi bitta Rails ilova va bitta MySQL bazadan boshlanadi. Keyin 2012-yilgi Redis klasteriga o‘tadi: u sekundiga 300 ming marta tasma o‘qishga xizmat qilgan. 2023-yilda Twitter o‘z tavsiya algoritmini ochiq e’lon qildi va bu algoritm kuniga milliardlab marta ishlaydi.

SavolJavob shu darsdaBo‘lim
Nega oddiy JOIN bilan bo‘lmaydi?v0 va uning hisobi3–4
Fan-out on write yoki on read?Ikki strategiyaning narxi5
100 million obunachili akkaunt tweet yozsa nima bo‘ladi?Mashhur akkaunt muammosi5.3
Tasma keshi qancha xotira yeydi?Kesh byudjeti hisobi6-bo‘lim, 1-qadam
Tweet ID nega shunchaki avtoinkrement emas?Snowflake6-bo‘lim, 7-qadam
Bitta post 5 soniyada qanday tarqaladi?Bitta postning hayoti7
“Sizga tavsiya” tasmasi qanday tuziladi?2023-yilgi ochiq algoritm8
Tasma yangilanmay qolsa nima qilamiz?Degradatsiya tartibi10.3

1. Muammo: aslida nimani qurmoqchimiz?

Oddiy tilda: tasma — sizning shaxsiy gazetangiz. Uni har kim uchun alohida, har necha soniyada yangidan “chop etish” kerak. Bunda yuzlab million o‘quvchi bor va har birining “mualliflar ro‘yxati” boshqacha.

1.1 Funksional talablar

  1. Foydalanuvchi qisqa post (tweet) yozadi
  2. Foydalanuvchi boshqalarga obuna bo‘ladi (bir tomonlama — do‘stlik emas)
  3. Foydalanuvchi tasma ko‘radi: obuna bo‘lganlari yozgan postlar
  4. Post yoqtiriladi, repost qilinadi, javob yoziladi
  5. Qidiruv va xeshteglar

Bizni asosan 3-punkt qiziqtiradi. Qolgan hammasi shunga xizmat qiladi.

1.2 Nofunksional talablar

TalabKo‘rsatkichNega
Tasma yuklaniship99 ≤ 200 msFoydalanuvchi kuniga o‘nlab marta ochadi
Post ko‘rinishi≤ 5 soniya“Yozdim, lekin ko‘rinmadi” — eng ko‘p shikoyat
Mavjudlik (o‘qish)99.99%Tasma ishlamasa mahsulot ishlamaydi
IzchillikOxir-oqibat (eventual)Bir necha soniya kechikish maqbul
Masshtab500M kunlik faol foydalanuvchiYirik ijtimoiy tarmoq tartibi

1.3 Konvert orqasidagi hisob

300K/s
Tasma o'qish, 2012
Twitter, QCon 2012
~4 600/s
Yangi tweet, o'rtacha
Kuniga 400 mln+, 2012
800
Tasmadagi yozuvlar chegarasi
Redis klasteridagi tasma
1 500
'Sizga tavsiya' nomzodlari
Ochiq algoritm, 2023
Hisob · Yozish va o'qish yuki
Farazlar (taxminiy, illyustratsiya uchun): Kunlik faol foydalanuvchi 500 000 000 Kuniga yoziladigan post 300 000 000 Foydalanuvchi kuniga tasmani ochadi ~60 marta Cho'qqi koeffitsienti 3x Yozish: 300e6 / 86400 = 3 472 post / soniya Cho'qqida: ~10 400 / soniya O'qish (tasma yuklanishi): 500e6 x 60 / 86400 = 347 222 / soniya Cho'qqida: ~1 040 000 / soniya O'qish / yozish nisbati: 100:1
Natija: Yozish 3500/s — kichik son. O'qish 350 000/s — 100 barobar ko'p. Butun arxitektura shu nisbatga qurilgan

1.4 Bu masala qanday hal qilingan: qisqa tarix

Twitter‘ning arxitektura tarixi — bu darsdagi qarorlarning haqiqiy sabablari.

Raqamlar bilan: 2012-yilda Twitter muhandisi Raffi Krikorian QCon konferensiyasida tizimni ochiq tasvirlab berdi. O‘sha paytda 150 million faol foydalanuvchi bor edi, tasmalar sekundiga 300 ming marta o‘qilardi, kuniga 400 milliondan ortiq tweet yozilardi (o‘rtacha ~4 600 / s). Har foydalanuvchining uy tasmasi Redis klasterida ko‘pi bilan 800 ta yozuv sifatida saqlanardi. Maqsad esa “tweet 5 soniyada barcha obunachilarga yetsin” edi.

2006–2008
Rails monoliti va bitta MySQL
Tasma JOIN bilan quriladi. Trafik o'sgani sari sayt tez-tez tushadi — 'fail whale' davri boshlanadi.
2009
Tasma keshi va fan-out on write
O'qish/yozish nisbati 100:1 ekani aniqlanadi va ish yozish paytiga ko'chiriladi. Bu darsning asosiy g'oyasi shu yerda tug'ilgan.
2010
Snowflake ID
Taqsimlangan tizimda tartiblanadigan ID kerak bo'ladi; avtoinkrement koordinatsiya nuqtasi bo'lib qoladi.
2011–2012
Monolitdan xizmatlarga o'tish
Tasma, graf, tweet saqlash va qidiruv alohida xizmatlarga ajratiladi — har biri o'z masshtablash muammosiga ega.
2012
Mashhur akkauntlar uchun pull
Fan-out on write yirik akkauntlarda yiqilib qoladi; gibrid model paydo bo'ladi.
2015–2016
Xronologiyadan reytingga
Foydalanuvchi obunalari o'sib, hamma postni ko'rish imkonsiz bo'ladi. Tanlovni model qila boshlaydi.
2020+
ML reyting va nomzod generatsiyasi
Tasma endi faqat obunalardan emas — 'sizga qiziq bo'lishi mumkin' postlar ham qo'shiladi. Hisob narxi keskin oshadi.
2023
Tavsiya algoritmi ochiq e'lon qilinadi
31-mart: 'Sizga tavsiya' tasmasining kodi ochiladi — har so'rovda ~1 500 nomzod, ~48 mln parametrli reyting modeli, kuniga ~5 mlrd marta (8-bo'lim).

Diqqat qiling: har bir qadam oldingi qadamning muammosidan tug‘ilgan. Bu darsda ham xuddi shu yo‘ldan boramiz — chunki qarorni uning sababisiz o‘rganish yodlashdan farq qilmaydi.

Hisob · 2012-yilgi haqiqiy raqamlar bizning farazlarimiz bilan
2012 (QCon, Raffi Krikorian): Faol foydalanuvchi 150 000 000 Tweet / kun 400 000 000+ -> ~4 600 / s Tasma o'qish 300 000 / s O'qish / yozish 300 000 / 4 600 = ~65 : 1 Bizning farazlarimiz (1.3): Tweet / s ~3 500 Tasma o'qish / s ~347 000 O'qish / yozish ~100 : 1 Fan-out (2012, o'rtacha ~200 obunachi deb): 4 600 x 200 = ~920 000 tasma yozuvi / s -> Redis klasteri, pipelining bilan
Natija: 2012-yilgi tizim bizning farazdan taxminan 1.2 barobar kichik o'qish va 1.3 barobar katta yozish bilan ishlagan — ya'ni darsdagi hisoblar real tizim tartibida
Nazorat savoli · javobni ko‘rish2012-yilda o'qish/yozish nisbati ~65:1 edi. Nega aynan shu raqam 'ishni yozishga ko'chirish' qarorini oqladi?

Chunki har post bir marta yoziladi, lekin uning natijasi (obunachilarning tasmasi) o‘nlab marta o‘qiladi. Yozish paytida bir marta qilingan ish 65 ta o‘qishda qayta ishlatiladi.

Teskarisi — o‘qish paytida yig‘ish (JOIN) — har o‘qishda yuzlab mualliflarni ko‘rib chiqishni talab qiladi. Ish 65 barobar ko‘proq takrorlanadi va eng qimmat joyda: foydalanuvchi kutayotgan paytda.

Lekin bu hisob o‘rtacha odam uchun. Mashhur akkauntda nisbat teskari: uning bitta posti 100 million yozuv talab qiladi. Ular esa shu daqiqada o‘qilmaydi, chunki o‘sha obunachilarning ko‘pi hozir tarmoqda emas. Gibrid yechim (5.4) shu ikki holatni ajratadi.

2. Nol nuqta: tasma nima degan masala

Oddiy tilda: tasma uchun bor-yo‘g‘i ikki narsa kerak — postlar daftari (kim nima yozdi) va obunalar daftari (kim kimni o‘qiydi). Tasma — bu ikki daftarni “mening obunalarim yozgan oxirgi postlar” degan savol bilan birga ochish.

2.1 Ma’lumot modeli

Ikkita asosiy jadval yetarli:

CREATE TABLE tweets (
    id          BIGINT PRIMARY KEY,     -- vaqt bo'yicha tartiblanadigan ID (6-bo'lim, 7-qadam)
    author_id   BIGINT NOT NULL,
    text        VARCHAR(280) NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL,
    reply_to    BIGINT,                 -- javob bo'lsa
    quoted      BIGINT                  -- iqtibos bo'lsa
);

CREATE TABLE follows (
    follower_id  BIGINT NOT NULL,       -- kim obuna bo'ldi
    followee_id  BIGINT NOT NULL,       -- kimga
    created_at   TIMESTAMPTZ NOT NULL,
    PRIMARY KEY (follower_id, followee_id)
);
CREATE INDEX idx_followee ON follows (followee_id);   -- "menga kim obuna?"

Diqqat: follows yo‘naltirilgan graf. Ikki xil savol beriladi va ular butunlay boshqacha ishlatiladi:

SavolIndeksKim uchun
“Men kimga obunaman?”(follower_id, ...)Tasmani o‘qishda
“Menga kim obuna?”(followee_id, ...)Post tarqatishda

2.2 Tasma — bu bitta so‘rov

Mantiqan tasma juda oddiy:

SELECT t.*
FROM tweets t
JOIN follows f ON f.followee_id = t.author_id
WHERE f.follower_id = :men
ORDER BY t.id DESC
LIMIT 50;

Bu — butun mahsulotning yuragi. Va u ishlamaydi. Nega ishlamasligini keyingi bo‘limda raqam bilan ko‘ramiz.

2.3 Ikki yo‘l: ishni qayerda bajaramiz

Bu darsning markaziy tushunchasi. Har qanday “kim nimani ko‘radi” tizimida ikkita imkoniyat bor:

Fan-out on read (pull)
  • Post yozilganda faqat bitta yozuv qilinadi
  • Tasma o'qilganda barcha obunalar bo'yicha yig'iladi
  • Yozish arzon, o'qish qimmat
  • Har doim eng yangi ma'lumot
Fan-out on write (push)
  • Post yozilganda har bir obunachining tasmasiga nusxa qo'yiladi
  • Tasma o'qilganda tayyor ro'yxat olinadi
  • Yozish qimmat, o'qish juda arzon
  • Xotira ko'p ketadi, kechikish bor

O‘qish yozishdan 100 barobar ko‘p bo‘lgani uchun intuitsiya “push” tomonga ishora qiladi. Lekin u bitta halokatli holatga uchraydi — 5.3-bo‘limda ko‘ramiz.

Nazorat savoli · javobni ko‘rishNima uchun 'menga kim obuna?' indeksi alohida kerak? Bitta jadval yetmaydimi?

Jadval bitta, lekin kirish naqshlari ikki xil. PRIMARY KEY (follower_id, followee_id) faqat birinchi ustun bo‘yicha samarali qidiradi — ya’ni “men kimga obunaman?” savoliga tez javob beradi.

“Menga kim obuna?” savoli esa ikkinchi ustun bo‘yicha qidirishni talab qiladi va indekssiz bu butun jadvalni skanerlash demak. Post tarqatishda (fan-out) aynan shu savol beriladi va u sekundiga minglab marta so‘raladi.

Katta tizimlarda bu ikki savol ko‘pincha ikki xil saqlashda yashaydi: “kimga obunaman” ro‘yxati keshda (tasma yig‘ish uchun), “menga kim obuna” esa shardlangan grafda (tarqatish uchun).

2.4 Graf qanchalik katta

Obunalar grafi — tizimdagi eng katta ma’lumotlardan biri va u ikki tomonlama saqlanadi.

Hisob · Obunalar grafining hajmi
500 000 000 foydalanuvchi O'rtacha 200 ta obuna Qirralar (edges): 500e6 x 200 = 100 000 000 000 (100 milliard) Har bir qirra IKKI marta saqlanadi: following:<user> -> kimga obunaman followers:<user> -> menga kim obuna 200 milliard yozuv Bitta yozuv (ID + indeks ustamasi): ~16 bayt 200e9 x 16 = 3.2 TB
Natija: ~3.2 TB, faqat 'kim kimga obuna' uchun. Bu tasma keshidan ikki barobar katta — va u ham keshlanishi kerak
▸Chuqurroq: Ikki tomonlama grafda izchillik

following va followers — bir xil faktning ikki ko‘rinishi. Obuna bo‘lish ikkala ro‘yxatni ham yangilashni talab qiladi, lekin ular turli shardlarda yotadi (biri obuna bo‘luvchining, ikkinchisi obuna bo‘linayotganning shardida).

Ya’ni bu taqsimlangan yozuv va u atomik emas. Nima bo‘lishi mumkin:

1. following:A ga B qo'shildi     ✓
2. followers:B ga A qo'shilishi kerak... server tushdi  ✗

Natija: A o'zini B ga obuna deb ko'radi,
        lekin B ning postlari A ga tarqatilmaydi

Yechimlar, murakkabligi bo‘yicha:

  1. Hodisalar navbati — obuna hodisasi navbatga yoziladi va ikkala tomon shundan yangilanadi. Kechikish bor, lekin yo‘qotish yo‘q
  2. Davriy tekshiruv — fon jarayoni ikki ro‘yxatni solishtiradi va farqni tuzatadi
  3. Bitta manba haqiqat — masalan faqat following saqlanadi, followers esa undan hosila sifatida quriladi

Amalda 1 va 2 birga ishlatiladi. Bu — “hosila ma’lumotni qayta qurish mumkin” degan tamoyilning yana bir ko‘rinishi.

Obunachilar soni ham alohida masala: SCARD followers:<user> 100 million elementli to‘plamda qimmat. Shuning uchun son denormallashtiriladi — alohida hisoblagichda saqlanadi va u ham vaqti-vaqti bilan haqiqiy son bilan solishtiriladi.

3. v0: eng sodda ishlaydigan yechim

Oddiy tilda: har ertalab 200 ta gazeta do‘koniga borib, har biridan oxirgi sonni olish. Do‘konlar uyingiz yonida bo‘lsa va o‘quvchi siz yolg‘iz bo‘lsangiz — muammo yo‘q.

@app.post("/tweet")
def post_tweet(user_id, text):
    tweet_id = snowflake()                     # vaqt bo'yicha tartiblanadigan ID
    db.execute("INSERT INTO tweets (id, author_id, text) VALUES (%s,%s,%s)",
               (tweet_id, user_id, text))
    return tweet_id

@app.get("/timeline")
def timeline(user_id):
    return db.query("""
        SELECT t.* FROM tweets t
        JOIN follows f ON f.followee_id = t.author_id
        WHERE f.follower_id = %s
        ORDER BY t.id DESC LIMIT 50
    """, (user_id,))
Mijoz
API
JOIN so'rovi
Baza
50 ta post
v0: har bir tasma yuklanishida baza JOIN bajaradi va tartiblaydi.

Kod to‘g‘ri va kichik loyihada yillab ishlaydi. Endi uni raqamlar bilan buzamiz.

4. Nima sindi: v0 ning to‘rtta o‘limi

Oddiy tilda: endi o‘quvchi siz yolg‘iz emas — yuz million. Har biri har kuni o‘nlab marta 200 ta do‘konni aylanib chiqyapti. Do‘konlar bir shaharda ham emas, va ularning soatlari ham bir xil yurmaydi.

4.1 JOIN har safar minglab qatorni ko‘radi

Hisob · Bitta tasma so'rovining haqiqiy narxi
O'rtacha foydalanuvchi 200 kishiga obuna. Ular so'nggi kunlarda ~100 tadan post yozgan. Bitta tasma so'rovi uchun: 200 obuna x 100 post = 20 000 nomzod qator Ularni ID bo'yicha tartiblash: O(n log n) Natijada faqat 50 tasi qaytariladi Sekundiga 347 000 tasma: 347 000 x 20 000 = 6.9e9 qator / soniya Solishtiring: yaxshi sozlangan Postgres tuguni ~1e6 - 1e7 qator/soniya uddalaydi (issiq keshda) Kerak: 1000 dan ortiq tugun, faqat O'QISH uchun
Natija: Bitta tasma uchun baza ~20 000 qatorni ko'radi va tartiblaydi. Sekundiga 350 000 marta — bu 7 milliard qator/soniya. Hech qanday baza buni uddalamaydi

4.2 Kesh yordam bermaydi

“Tasmani keshlaymiz” degan fikr birinchi bo‘lib keladi, lekin:

  • Har bir foydalanuvchining tasmasi noyob (uning obunalari to‘plamiga bog‘liq)
  • U doim o‘zgaradi — obunalaridan biri post yozsa, kesh eskiradi
  • 500 million foydalanuvchi = 500 million alohida kesh yozuvi

Ya’ni klassik “so‘rov natijasini keshlash” bu yerda ishlamaydi. Kesh boshqacha qurilishi kerak — va bu 6-bo‘limning 1-qadami.

4.3 Postlar va obunalar bir joyda yashay olmaydi

tweets jadvali kuniga 300 million qator o‘sadi — yiliga ~110 milliard. follows jadvali esa milliardlab qator. Ikkalasi ham shardlanishi kerak, lekin turli kalitlar bo‘yicha:

  • tweets — tweet ID bo‘yicha (yozish tekis taqsimlanadi)
  • follows — foydalanuvchi ID bo‘yicha (bir odamning obunalari birga tursin)

Shardlangandan keyin ular orasida JOIN umuman mumkin emas — ular boshqa mashinalarda. Ya’ni 2.2-bo‘limdagi so‘rov nafaqat sekin, balki printsipial jihatdan bajarilmaydigan bo‘lib qoladi.

4.4 Tartib muammosi

ORDER BY created_at taqsimlangan tizimda ishonchsiz: turli serverlarning soatlari farq qiladi, bir xil millisekundda yozilgan postlar tartibi noaniq bo‘ladi va sahifalash (pagination) buziladi.

Bu kichik detal kabi ko‘rinadi, lekin u ID dizayni degan alohida masalaga olib keladi (6-bo‘lim, 7-qadam).

5. Ikki strategiya va ularning narxi

Oddiy tilda: yo do‘konlarni aylanish (pull), yo maqolani muallif darhol qutilarga tarqatishi (push). Birinchisi o‘quvchining vaqtini, ikkinchisi muallifning ishini yeydi. Mashhur muallif esa million qutiga tarqata olmaydi.

5.1 Fan-out on write: ishni yozishga ko‘chirish

G‘oya: post yozilganda darhol har bir obunachining tayyor tasmasiga uning ID sini qo‘shamiz. O‘qishda hech qanday hisob qolmaydi — tayyor ro‘yxat olinadi.

Post yozildi
  -> "menga kim obuna?" ro'yxatini olamiz  (200 kishi)
  -> har birining tasma ro'yxatiga ID qo'shamiz
       LPUSH timeline:<obunachi> <tweet_id>
       LTRIM timeline:<obunachi> 0 799
Hisob · Fan-out on write yuki
Postlar: 3 472 / soniya (cho'qqida 10 400) O'rtacha obunachi soni: 200 Tasma yozuvlari: 3 472 x 200 = 694 400 yozuv / soniya Cho'qqida: 10 400 x 200 = 2 080 000 / soniya Redis klasteri (pipelining bilan, 100 tadan paket): bitta tugun ~500 000 yozuv/s Kerak: ~5 tugun (zaxira bilan 10-12) O'qish tomonida: LRANGE timeline:<men> 0 49 -> bitta komanda, O(50)
Natija: Sekundiga 2 million yozuv — bu ko'p, lekin Redis klasteri uchun real. Buning evaziga o'qish deyarli bepul bo'ladi

5.2 Fan-out on read: ishni o‘qishga qoldirish

G‘oya: hech narsa oldindan tayyorlanmaydi. Tasma so‘ralganda obunalar bo‘yicha har birining oxirgi postlari olinadi va birlashtiriladi.

Hisob · Fan-out on read yuki
Tasma so'rovlari: 347 222 / soniya Har birida 200 ta obunaning oxirgi postlari kerak 347 222 x 200 = 69 444 400 so'rov / soniya Hatto har biri keshdan kelsa ham: bitta Redis tuguni ~100 000 - 500 000 ops/s Kerak: 140 - 700 tugun, faqat SHU ish uchun Plus har bir tasma uchun 200 x 50 = 10 000 elementni birlashtirish va tartiblash — ilova serverlarida
Natija: Sekundiga 70 million so'rov — Redis klasterida ham imkonsiz. Bu strategiya sof holda ishlamaydi

Xulosa: sof pull ishlamaydi. Sof push esa ishlaydi — bitta holatdan tashqari.

5.3 Mashhur akkaunt muammosi

Obunachilar soni darajali taqsimot (power law) bo‘yicha tarqalgan: ko‘pchilikda yuzlab obunachi, bir nechtasida yuz millionlab.

Hisob · Bitta mashhur post nima qiladi
Mashhur akkaunt: 100 000 000 obunachi U bitta post yozdi. Kerakli tasma yozuvlari: 100 000 000 ta Butun klaster sig'imi (5.1-bo'limdan): ~2 000 000 yozuv/s 100e6 / 2e6 = 50 soniya (BUTUN klaster faqat shu postga) Amalda fan-out uchun sig'imning ~10% i ajratiladi: 100e6 / 200 000 = 500 soniya = 8.3 daqiqa Va shu paytda qolgan hamma postlar navbatda kutadi.
Natija: Bitta postning tarqatilishi butun klasterning 100 soniyalik butun sig'imini yeydi. Amalda 10% byudjet bilan bu 17 daqiqa — ya'ni post 'kechagi yangilik' bo'lib yetadi

Bundan ham yomoni — bu bitta post emas:

Hisob · Mashhur akkauntlarning umumiy hissasi
Faraz: 1000 ta yirik akkaunt har biri o'rtacha 20 000 000 obunachi har biri kuniga 5 ta post Kunlik fan-out yozuvlari (faqat ular): 1000 x 5 x 20e6 = 1e11 yozuv / kun 1e11 / 86400 = 1 157 000 yozuv / soniya Qolgan 500 million foydalanuvchi: 694 400 yozuv / soniya (5.1-bo'lim) Ya'ni 1000 ta akkaunt qolgan 500 millionidan KO'PROQ yuk yaratadi.
Natija: Foydalanuvchilarning 0.0002% i butun fan-out yukining yarmidan ko'pini yaratadi. Klassik uzun dum muammosi, faqat teskari tomondan

5.4 Gibrid yechim

Amaliy tizimlar ikkalasini birlashtiradi:

Gibrid fan-out
Post yozilganda
Obunachilar soni tekshiriladi

Chegaradan kam bo'lsa — push; ko'p bo'lsa — hech narsa qilinmaydi.

Oddiy akkauntlar (push)
Fan-out navbatiObunachilar tasmasiga yoziladi

Foydalanuvchilarning 99.99% i shu yo'ldan o'tadi.

Mashhur akkauntlar (pull)
Faqat o'z postlar ro'yxatiga yoziladi

Tarqatish yo'q — o'qishda qo'shiladi.

Tasma o'qilganda
Tayyor tasma (push qismi)Mashhurlarning postlari (pull qismi)Birlashtirish va tartiblash

Bu yerda qo'shimcha ish bor, lekin u kichik va bashoratli.

Hisob · Gibrid yechimning o'qish narxi
O'rtacha foydalanuvchi 200 kishiga obuna. Ulardan mashhur (chegaradan yuqori) — o'rtacha 5 tasi. Tasma o'qilganda: 1 ta so'rov: tayyor tasma (195 oddiy akkaunt) -> 50 ta ID 5 ta so'rov: mashhurlarning oxirgi postlari -> 5 x 50 = 250 ta ID -------------------------------------------------------------- 6 ta so'rov, 300 ta nomzod Birlashtirish: 300 elementni ID bo'yicha tartiblash -> ilovada mikrosoniyalar Yozish tomonida esa mashhurlar uchun fan-out YO'Q: 1 157 000 yozuv/s yo'qoladi (5.3-bo'limdagi hisob)
Natija: Har bir tasma uchun 6 ta so'rov va 300 elementni tartiblash. Bu sof pull'dagi 200 so'rovdan 33 barobar arzon
▸Chuqurroq: Chegarani qanday tanlash: optimallashtirish masalasi

Chegara T — obunachilar soni, undan yuqorisi pull rejimiga o‘tadi.

Yozish narxi T oshgani sari o‘sadi (ko‘proq akkaunt push qiladi):

Yozish = Σ (obunachilar soni)  [obunachilari T dan kam bo'lgan akkauntlar bo'yicha]

O‘qish narxi T oshgani sari kamayadi (kamroq akkaunt pull rejimida):

O'qish = tasma_so'rovlari x (1 + o'rtacha_mashhur_obunalar_soni)

Ikkalasining yig‘indisi minimal bo‘ladigan nuqta izlanadi. Amalda bu nuqta 10 000 – 1 000 000 oralig‘ida bo‘ladi va u tizimning haqiqiy taqsimotiga bog‘liq — formuladan emas, o‘lchovdan topiladi.

Qo‘shimcha nozik jihat: chegara ikki tomonlama bo‘lishi kerak (gisterezis). Aks holda chegara atrofidagi akkaunt push va pull orasida tebranib, ikkala rejimning ham kamchiligini oladi.

▸Chuqurroq: Birlashtirish algoritmi: k ta tartiblangan ro'yxatni qo'shish

Gibrid yechimda o‘qish paytida bir nechta tartiblangan ro‘yxat birlashtiriladi: tayyor tasma (50 ta) va har bir mashhur akkauntning postlari (5 × 50).

Bu klassik k-way merge. Sodda yo‘l — hammasini bitta massivga qo‘yib tartiblash:

300 element, O(n log n) = 300 x 8.2 = ~2500 taqqoslash

Uyum (heap) bilan esa faqat kerakli 50 tasi olinadi:

O(n log k) = 300 x log2(6) = 300 x 2.6 = ~780 taqqoslash

Amalda 300 element uchun farq mikrosoniyalarda va oddiy tartiblash yetarli — lekin tamoyil muhim: kerakli qismini olish, hammasini tartiblash emas. Nomzodlar soni o‘sganda (masalan 5000 ta) bu farq sezilarli bo‘ladi.

Birlashtirishdan keyin ikki bosqich majburiy: deduplikatsiya (post ID va repost holatida asl post ID si bo‘yicha) va kesish (kursordan keyingi 50 tasi). Va faqat shundan keyin hidratsiya qilinadi — u eng qimmat bosqich va uni faqat yakuniy ro‘yxatga qo‘llash kerak.

Nazorat savoli · javobni ko‘rishFoydalanuvchi mashhur akkauntga obuna bo'ldi. Uning eski postlari tasmada ko'rinishi kerakmi?

Push rejimida bu masala umuman tug‘ilmaydi — obuna bo‘lgandan keyingi postlargina tasmaga tushadi, eskilarini ko‘rish uchun profilga kirish kerak.

Pull rejimidagi mashhur akkauntlarda esa avtomatik ko‘rinadi, chunki ular o‘qish paytida qo‘shiladi. Ya’ni bir xil mahsulotda ikki xil xatti-harakat paydo bo‘ladi: oddiy odamga obuna bo‘lsangiz tasma o‘zgarmaydi, mashhurga obuna bo‘lsangiz — darhol to‘ladi.

Buni tekislash uchun ikki yo‘l bor: (a) obuna bo‘lganda oxirgi N ta postni tasmaga orqadan to‘ldirish (backfill) — qimmat, lekin izchil; (b) ikkala holatda ham faqat yangi postlarni ko‘rsatish — pull natijalarini obuna vaqti bo‘yicha filtrlash.

Ko‘p tizimlar (b) ni tanlaydi: u arzon va foydalanuvchi kutganiga mos.

6. Evolyutsiya: o‘n to‘rt qadam

Qadamlar mantiqiy tartibda: 1–5 — tasma keshi, tarqatish, gibrid, hidratsiya va o‘chirish; 6–8 — shardlash, ID va obunalar grafi; 9–12 — reyting, real vaqt, qidiruv va media; 13–14 — ko‘p mintaqa va cho‘qqidan himoya.

1

Tasma keshi: ID lar ro'yxati

Oddiy tilda: har o‘quvchining pochta qutisi — unda maqolaning o‘zi emas, faqat raqami. Raqam kichik, maqola esa bir joyda turadi.

Tasma postlarning o‘zi emas, ularning ID lari ro‘yxati sifatida saqlanadi. Bu muhim qaror: ID 8 bayt, postning o‘zi esa yuzlab bayt.

LPUSH  timeline:42  1712345678901234567
LTRIM  timeline:42  0 799           # faqat oxirgi 800 ta
LRANGE timeline:42  0 49            # tasmani o'qish
Hisob · Tasma keshining xotira byudjeti
Faol foydalanuvchilar (oxirgi 30 kunda kirgan): 200 000 000 Tasmada saqlanadigan post: 800 ta Bitta ID: 8 bayt Sof ma'lumot: 200e6 x 800 x 8 = 1.28 TB Redis quicklist ustama xarajati (~25%): ~1.6 TB 30 ta tugun x 64 GB = 1.9 TB -> sig'adi
Natija: ~1.6 TB. Ko'p ko'rinadi, lekin bu butun mahsulotning yuragi va u Redis klasteriga taqsimlanadi

Nega aynan 800 ta? Foydalanuvchilar tasmani kamdan-kam 100 tadan pastga varaqlaydi. 800 ta post o‘rtacha foydalanuvchi uchun bir necha kunlik tarixni qamrab oladi. Undan narigisi kerak bo‘lsa — bu allaqachon “arxivni ko‘rish”, va u boshqa yo‘l bilan (sekinroq, bazadan) beriladi.

Faol bo‘lmagan foydalanuvchilar uchun tasma umuman saqlanmaydi: ular kirganda tasma qayta quriladi. Bu xotirani ikki-uch barobar tejaydi.

▸Chuqurroq: Sahifalash: nega OFFSET ishlamaydi

Foydalanuvchi tasmani pastga varaqlaydi. Ikkinchi sahifani qanday so‘raymiz?

Xato yo‘l — ofset:

LRANGE timeline:42 0 49      -> 1-sahifa
LRANGE timeline:42 50 99     -> 2-sahifa

Muammo: shu oraliqda 10 ta yangi post keldi va ro‘yxat boshiga qo‘shildi. Endi 50–99 pozitsiyalar siljigan va foydalanuvchi birinchi sahifada ko‘rgan 10 ta postni yana ko‘radi. Aksincha ham bo‘ladi — postlar tushib qoladi.

To‘g‘ri yo‘l — kursor:

1-sahifa: oxirgi 50 ta, oxirgisining ID si = 1712345678901234567
2-sahifa: shu ID dan KICHIK bo'lgan keyingi 50 ta

Snowflake ID vaqt bo‘yicha tartiblangani uchun kursor barqaror nuqta beradi: ro‘yxat boshiga nima qo‘shilsa ham, “shu postdan keyingilari” aniq bir xil qoladi.

Redis ro‘yxatida bu ozgina noqulay (LPOS bilan pozitsiya topiladi), shuning uchun ba’zi tizimlar tasmani ZSET sifatida saqlaydi — ball sifatida tweet ID bilan. Unda ZREVRANGEBYSCORE timeline:42 (cursor -inf LIMIT 0 50 to‘g‘ridan-to‘g‘ri ishlaydi. Narxi: ZSET ro‘yxatdan ~2 barobar ko‘p xotira yeydi.

Yutuq: Tasma o'qish O(1) ga tushdi — bitta LRANGE

Narxi: Terabaytlab RAM; kesh va manba orasida izchillik masalasi

2

Fan-out xizmati va navbat

Oddiy tilda: muallif maqolasini pochtaga topshiradi va uyiga ketadi. Tarqatishni pochtachilar keyin, o‘z navbati bilan qiladi.

Post yozilganda 200 ta yozuvni sinxron bajarish kutish vaqtini oshiradi. Shuning uchun tarqatish navbat orqali bajariladi:

Post yozildi
tweets bazasiga saqlandi
Navbatga hodisa
Fan-out ishchilari
Tasma keshlari
Foydalanuvchi 2-qadamda javob oladi; qolgani fonda bajariladi.

Muhandislik tafsilotlari:

  • Idempotentlik — ishchi qayta urinsa, bir xil ID tasmaga ikki marta tushmasligi kerak. LPUSH dan oldin tekshirish poyga holatiga olib keladi; to‘g‘riroq yechim — o‘qishda dublikatlarni filtrlash yoki ID bo‘yicha ZADD (to‘plam sifatida)
  • Tartib — ikki post deyarli bir vaqtda yozilsa, ular tasmaga teskari tartibda tushishi mumkin. Vaqt bo‘yicha tartiblanadigan ID bu muammoni o‘qish paytida hal qiladi (7-qadam)
  • Bo‘laklash — 200 000 obunachili akkaunt uchun ish 1000 tadan bo‘lakka bo‘linadi, aks holda bitta vazifa ishchini daqiqalarga band qiladi
  • Prioritet — kam obunachili akkauntlar alohida navbatda ketadi, aks holda ular yirik akkauntlar orqasida navbatda qoladi (head-of-line blocking)
▸Chuqurroq: Fan-out ishchisining ichki tuzilishi

Ishchi shunchaki siklda LPUSH chaqirmaydi — bu tarmoqni bo‘g‘adi va Redis‘ni navbatga soladi.

def process(tweet_id, author_id):
    for chunk in graph.followers_chunked(author_id, size=1000):
        pipe = redis.pipeline()
        for follower in chunk:                 # 1000 ta obunachi
            key = f"timeline:{follower}"
            pipe.lpush(key, tweet_id)
            pipe.ltrim(key, 0, 799)
        pipe.execute()                          # BITTA tarmoq borish-kelishi
        checkpoint(tweet_id, chunk.cursor)      # to'xtasa shu yerdan davom etamiz

Uchta muhim detal:

DetalNima uchun
Pipelining (1000 tadan)2000 komanda bitta paketda — RTT 2000 marta emas, 1 marta
CheckpointIshchi tushsa, 100 000 obunachining 60 000 tasiga yuborilgan bo‘lishi mumkin; qaytadan boshlash isrof
Bo‘lak hajmiKatta bo‘lsa xotira va bloklash, kichik bo‘lsa RTT ko‘payadi — 500–2000 optimal

Orqa bosim (backpressure): Redis sekinlashsa, ishchi tezligini o‘zi kamaytirishi kerak. Aks holda navbat to‘lib, xotira tugaydi. Amaliy usul — pipe.execute() kechikishini o‘lchab, chegaradan oshsa ishchilar sonini kamaytirish.

Qayta urinish semantikasi: LPUSH + LTRIM idempotent emas — ikki marta bajarilsa, ID ikki marta tushadi. Ikki yechim: bo‘lak darajasidagi checkpoint (yuqoridagi) yoki o‘qishda deduplikatsiya. Amalda ikkalasi ham qilinadi, chunki checkpoint ham 100% ishonchli emas.

Yutuq: Post yozish 5 ms da tugaydi — tarqatish fonda ketadi

Narxi: Tarqatish kechikadi; navbat to'lsa postlar 'yo'qoladi'

3

Dinamik chegara: kim push, kim pull

Oddiy tilda: oddiy muallifning maqolasi qutilarga tarqatiladi, mashhurniki esa e’lonlar taxtasiga osiladi. Qaysi muallif “mashhur” ekanini obunachilar soni hal qiladi.

5.4-bo‘limdagi gibrid yechimning amalga oshirilishi:

CELEBRITY_THRESHOLD = 100_000       # konfiguratsiyada, kodda emas

def on_new_tweet(tweet):
    n = graph.follower_count(tweet.author_id)      # keshlangan son
    if n < CELEBRITY_THRESHOLD:
        queue.publish("fanout", tweet.id)          # push
    # aks holda hech narsa — o'qishda qo'shiladi (pull)

Chegara konfiguratsiyadan o‘qiladi va yukka qarab o‘zgartiriladi: klaster bo‘g‘ilganda uni pasaytirish darhol yengillik beradi. Bu — degradatsiya tutqichlaridan biri (10.3-bo‘lim).

▸Chuqurroq: Sovuq start: yangi foydalanuvchining tasmasi

Yangi foydalanuvchi ro‘yxatdan o‘tdi. Obunalari yo‘q — tasmasi bo‘sh. Va bo‘sh tasma — mahsulotdan ketishning eng katta sababi.

Bu texnik emas, mahsulot masalasi, lekin u arxitekturaga tegadi:

StrategiyaQanday ishlaydiKamchiligi
Majburiy obuna (onboarding)Ro‘yxatdan o‘tishda 10 ta akkaunt tanlatiladiFoydalanuvchi tashlab ketishi mumkin
Avtomatik obunaMashhur akkauntlarga avtomatik obunaTasma bir xil bo‘lib qoladi
Qiziqish bo‘yicha nomzodlarTil, mintaqa, kontaktlar bo‘yicha tanlashMa’lumot yig‘ish kerak
Global “eng yaxshi” tasmaObunasiz ham qiziqarli postlarFan-out bilan bog‘liq emas — alohida quvur

Oxirgisi arxitektura nuqtai nazaridan eng qiziq: u obunalarga bog‘liq bo‘lmagan tasma degani. Ya’ni tizimda ikkinchi, butunlay boshqacha tasma turi paydo bo‘ladi: mintaqa/til bo‘yicha oldindan hisoblangan “eng yaxshi postlar” ro‘yxati.

Va bir marta shunday quvur qurilgach, u faol foydalanuvchilarga ham qo‘llana boshlaydi (“sizga qiziq bo‘lishi mumkin”) — 6-bo‘limning 9-qadamidagi reyting shundan o‘sib chiqqan.

Yutuq: Klaster sig'imining yarmi bo'shaydi

Narxi: Ikki xil kod yo'li; chegara atrofidagi akkauntlar bilan ehtiyot bo'lish kerak

4

Hidratsiya: ID lardan to'liq postgacha

Oddiy tilda: qutida faqat raqamlar bor. Uni o‘qish uchun raqamlar bo‘yicha arxivdan maqolalarni olib kelish kerak — va bu ishni bitta katta buyurtma bilan qilish kerak, raqamma-raqam emas.

Tasma ID lardan iborat, foydalanuvchiga esa to‘liq post kerak: matn, muallif, statistika, media. Bu bosqich hidratsiya deb ataladi.

1. LRANGE timeline:42 0 49          -> 50 ta ID
2. MGET tweet:<id1> ... tweet:<id50> -> 50 ta post (bitta komanda)
3. MGET user:<a1> ... user:<aN>      -> mualliflar (odatda 20-40 noyob)
4. Filtrlash: o'chirilganlar, bloklanganlar, yashirilganlar
Hisob · Post keshi hajmi
Kuniga 300 000 000 post Bitta post keshda (matn + metama'lumot): ~300 bayt Kunlik: 300e6 x 300 = 90 GB Oxirgi 3 kun (tasmalarning ~95% i shu oraliqda): 270 GB Solishtiring: bazadagi to'liq arxiv yiliga 110 milliard post x 300 bayt = 33 TB / yil
Natija: Oxirgi 3 kunlik postlar 270 GB — bu tasma keshidan 6 barobar kichik va tasmalar undan foydalanadi. Eski postlar bazadan olinadi (kamdan-kam kerak bo'ladi)

Bu qadamning muhim yon foydasi: post tahrirlansa yoki o‘chirilsa, uni millionlab tasmadan qidirib topish shart emas — hidratsiya paytida yangi holat olinadi.

▸Chuqurroq: Repost va iqtibos: fan-out ichida fan-out

Repost (retweet) — bu yangi post, lekin o‘z matni yo‘q, u boshqasiga ishora qiladi:

tweet { id: 999, author: B, repost_of: 123 }

Fan-out nuqtai nazaridan bu oddiy post: B ning obunachilariga 999 tarqatiladi. Hidratsiya paytida esa 999 ochilib, ichidan 123 ning kontenti olinadi va “B repost qildi” degan sarlavha bilan ko‘rsatiladi.

Uchta nozik holat:

  1. Zanjir — kimdir repostni repost qilsa, u har doim asl postga ishora qiladi (zanjir tekislanadi), aks holda hidratsiya rekursiv bo‘lib ketardi
  2. Asl post o‘chirilsa — repost ham ko‘rinmaydi (tombstone filtri asl postga qo‘llanadi)
  3. Dublikat — foydalanuvchi bir postni ikki xil odamdan repost sifatida ko‘rishi mumkin. Shuning uchun aralashtirishda asl post ID si bo‘yicha ham deduplikatsiya qilinadi, faqat post ID si bo‘yicha emas

Iqtibos (quote) esa boshqacha: u o‘z matniga ega mustaqil post va ichiga boshqasini joylaydi. Ya’ni hidratsiya ikkita postni oladi — bu MGET hajmini oshiradi.

Yutuq: Tasma keshi 40 barobar kichik; post bir joyda yangilanadi

Narxi: Har tasma uchun qo'shimcha bir marta ommaviy o'qish

5

O'chirish: tombstone va o'qishda filtrlash

Oddiy tilda: maqola qaytarib olindi. Million qutini ochib uni olib chiqish o‘rniga, arxivda “bekor qilingan” deb belgilanadi va qutini ochgan odamga ko‘rsatilmaydi.

Post o‘chirilganda uni 100 million tasmadan olib tashlash — 5.3-bo‘limdagi bilan bir xil imkonsiz masala. Yechim: umuman olib tashlamaslik.

DELETE /tweet/123  ->  tweets jadvalida deleted = true
                   ->  tweet:123 keshi yangilanadi (yoki o'chiriladi)

Tasmalarda ID qoladi. Hidratsiya paytida:
  - post topilmadi yoki deleted = true -> ro'yxatdan tashlanadi

Yutuq: O'chirish O(1) — bitta yozuv

Narxi: Tasmalarda 'o'lik' ID lar qoladi; ular o'qishda filtrlanadi

6

Shardlash: uch xil ma'lumot, uch xil kalit

Oddiy tilda: arxiv uch xil javonga bo‘linadi: maqolalar raqam bo‘yicha, qutilar egasi bo‘yicha, obunalar o‘quvchi bo‘yicha. Har javon o‘zining eng ko‘p so‘raladigan savoliga moslab tartiblanadi.

Ma’lumotShard kalitiNega
tweetstweet ID (Snowflake)Yozish vaqt bo‘yicha tekis tarqaladi; ID bo‘yicha o‘qish to‘g‘ridan-to‘g‘ri
timeline:<user>foydalanuvchi IDBitta tasma bitta tugunda — LRANGE bitta so‘rov
followsfoydalanuvchi IDBir odamning obunalari birga yotadi

Diqqat: tweets ni author ID bo‘yicha shardlash jozibali ko‘rinadi (“bir odamning postlari birga”), lekin bu mashhur akkaunt shardini yondiradi — 5.3-bo‘limdagi hot key muammosining aynan o‘zi. Tweet ID bo‘yicha shardlash yukni tekis taqsimlaydi.

Buning narxi: “falonchining barcha postlari” so‘rovi endi barcha shardlarga boradi. Shuning uchun profil sahifasi uchun alohida indeks yuritiladi: user_tweets:<author> — ID lar ro‘yxati, tasma keshiga o‘xshash.

Yutuq: Har bir tur o'z kirish naqshiga mos taqsimlanadi

Narxi: Shardlararo JOIN yo'q — birlashtirish ilovada bajariladi

7

Snowflake ID: vaqt bo'yicha tartiblanadigan taqsimlangan identifikator

Oddiy tilda: har maqola raqamining boshida vaqt yozilgan, oxirida esa qaysi pochta bo‘limi bergani. Shunda mingta bo‘lim bir-biridan so‘ramasdan raqam beradi va raqamlar vaqt bo‘yicha tartiblanadi.

4.4-bo‘limdagi tartib muammosining yechimi. ID ning o‘zida vaqt bo‘lsa, ORDER BY id avtomatik ravishda xronologik tartib beradi va sahifalash barqaror bo‘ladi.

64 bitli butun son:

 1 bit  | 41 bit              | 10 bit      | 12 bit
 ishlatilmaydi | millisekundlar   | mashina ID  | ketma-ketlik
Hisob · Snowflake nima beradi
41 bit millisekund: 2^41 = 2.2e12 ms = 69.7 yil (boshlang'ich nuqtadan hisoblanadi) 10 bit mashina ID: 2^10 = 1024 ta generator 12 bit ketma-ketlik: 2^12 = 4096 ta ID / millisekund / mashina Umumiy sig'im: 1024 x 4096 x 1000 = 4.2e9 ID / soniya
Natija: Har bir mashina millisekundiga 4096 ta ID, jami 4.2 million ID/soniya — koordinatsiyasiz. Bizga kerak bo'lgani 10 400/s, ya'ni 400 barobar zaxira bor
▸Chuqurroq: Snowflake'ning uchta nozik joyi

1. Soat orqaga ketishi. NTP sinxronizatsiyasi soatni orqaga sursa, allaqachon berilgan ID lar takrorlanishi mumkin. Standart yechim: generator soat orqaga ketganini sezsa, javob berishni to‘xtatadi (soat quvib yetguncha kutadi). Bu to‘g‘ri qaror — takroriy ID ma’lumot buzilishiga olib keladi, qisqa to‘xtash esa faqat noqulaylik.

2. Ma’lumot sizishi. ID dan post aniq qachon yozilgani chiqariladi va ketma-ketlik raqamidan tizim yuki taxmin qilinadi. Ba’zi tizimlar shu sababli ID ni tashqariga chiqarishdan oldin aralashtiradi (2-darsdagi enumeration muammosining qarindoshi).

3. Mashina ID ni taqsimlash. 1024 ta slot qandaydir tarzda taqsimlanishi kerak: ZooKeeper/etcd orqali ijaraga berish, yoki konteyner nomidan hisoblash. Ikki generator bir xil ID olsa — to‘qnashuv kafolatlanadi.

Yutuq: Koordinatsiyasiz, tartiblanadigan, shardlanadigan ID

Narxi: Soat siljishiga sezgir; 64 bit chegarasi

8

Graf xizmati

Oddiy tilda: “kim kimning o‘quvchisi” degan ulkan ma’lumotnoma. Har maqola tarqatilganda undan so‘raladi, shuning uchun u doim qo‘l ostida bo‘lishi kerak.

Fan-out har bir postda “menga kim obuna?” ro‘yxatini so‘raydi — sekundiga 3500 marta. Bu ro‘yxatlar bazadan olinsa, baza bo‘g‘iladi.

followers:<user>   -> ID lar to'plami (shardlangan)
following:<user>   -> ID lar to'plami
follower_count:<user> -> son (tez tekshirish uchun, 3-qadam)

Mashhur akkauntning obunachilar ro‘yxati 100 million element — uni bir butun sifatida saqlash mumkin emas (Redis darsidagi “katta kalit” muammosi). U bo‘laklarga bo‘linadi va fan-out ishchilari bo‘lak-bo‘lak o‘qiydi. Lekin pull rejimidagi akkauntlar uchun bu ro‘yxat umuman kerak emas — yana bitta sabab, nega gibrid yechim to‘g‘ri.

Yutuq: 'Kim kimga obuna' savoli millisekundlarda

Narxi: Yana bitta katta kesh qatlami; mashhur akkauntlarning ro'yxati juda katta

9

Xronologiyadan reytingga

Oddiy tilda: qutingizga kuniga 500 ta maqola tushadi, siz esa 50 tasini o‘qiysiz. Qaysi 50 tasi — tasodifmi yoki sizni yaxshi biladigan kotib tanlaganmi?

Xronologik tasma sodda, lekin muammosi bor: kuniga 200 ta post o‘qiydigan odam 500 ta akkauntga obuna bo‘lsa, u ko‘p narsani ko‘rmaydi — va aynan qaysi biri ko‘rinmasligi tasodifiy.

Reyting shu tanlovni ongli qiladi:

Nomzodlar (300 ta ID)
  -> Xususiyatlar: muallif bilan aloqa, post yoshi, media bormi,
                   erta reaksiyalar, o'xshash postlarga munosabat
  -> Model bal beradi
  -> Yuqori 50 tasi
Hisob · Reytingning hisob narxi
Tasma so'rovlari: 347 000 / soniya Har birida nomzodlar: ~300 Baholashlar: 347 000 x 300 = 104 000 000 / soniya Agar bitta baholash 1 mikrosoniya bo'lsa: 104 CPU-yadro doimiy band (faqat baholash uchun) Agar 10 mikrosoniya bo'lsa: 1040 yadro — bu allaqachon jiddiy klaster
Natija: Sekundiga 100 million baholash. Shuning uchun model juda arzon bo'lishi va xususiyatlar OLDINDAN hisoblangan bo'lishi shart

Shuning uchun amalda ikki bosqich bo‘ladi: arzon filtr (nomzodlarni 300 dan 100 ga tushiradi) va qimmatroq model (qolganini baholaydi) — bu ChatGPT darsidagi RAG reranker naqshining aynan o‘zi.

▸Chuqurroq: Reyting o'zgarishini qanday o'lchaysiz

Yangi reyting modeli “yaxshiroq” ekanini qanday bilamiz? Bu texnik emas, o‘lchash masalasi va u yerda ko‘p xato qilinadi.

Yomon metrika: sahifada o‘tkazilgan vaqt. Uni oshirish oson — chalkash, g‘azablantiruvchi yoki cheksiz aylanadigan kontent ko‘rsatish yetarli. Model buni tez o‘rganadi (ChatGPT darsidagi “reward hacking” bilan bir xil).

Yaxshiroq metrikalar to‘plami:

SignalNimani ko‘rsatadiEhtiyot
Mazmunli reaksiya (javob, ulashish)Post qiymatli bo‘ldiJanjal ham reaksiya keltiradi
Qaytish chastotasi (ertasi kuni)Uzoq muddatli qiymatSekin o‘lchanadi
“Qiziq emas” bosishlariTo‘g‘ridan-to‘g‘ri salbiy signalKam ishlatiladi
Tasmani tashlab ketishYomon tartibBoshqa sabablar ham bor

A/B tajribasining tuzoqlari: tarmoq effekti (bir foydalanuvchi tajribasi boshqasiga ta’sir qiladi — repostlar orqali), yangilik effekti (har qanday o‘zgarish qisqa vaqt ijobiy ko‘rinadi), va uzoq muddatli zarar (bir hafta yaxshi, uch oy yomon).

Shuning uchun jiddiy tizimlarda tajribalar haftalar davom etadi va bir necha metrika birgalikda kuzatiladi — bittasini oshirib boshqasini tushirish oson.

Yutuq: Foydalanuvchi vaqti ortadi; yangi akkauntlar ham ko'rinadi

Narxi: Hisob qimmatlashadi; 'nega bu postni ko'rmadim?' shikoyatlari boshlanadi

10

Real vaqtda yetkazish

Oddiy tilda: yangi maqola kelganda qo‘ng‘iroq chalinishi. Har o‘quvchiga alohida qo‘ng‘iroq ulash qimmat, shuning uchun ba’zan “har 30 soniyada qutiga qarab qo‘yish” yetarli.

Foydalanuvchi tasmani ochib o‘tirgan bo‘lsa, yangi post kelganini bilishi kerak. Ikki yondashuv:

Polling (so'rab turish)
  • Har 15-30 soniyada 'yangilik bormi?' so'rovi
  • Oddiy, hech qanday holat yo'q
  • Kechikish o'rtacha yarim interval
  • Bo'sh so'rovlar ko'p — lekin ular juda arzon
Doimiy ulanish (WebSocket)
  • Server o'zi xabar beradi, kechikish ~0
  • Har bir ulanish xotira va fayl deskriptori yeydi
  • Uzilishlarni qayta tiklash mantiqi kerak
  • Mobil tarmoqda ulanish tez-tez uziladi

Amalda ko‘p tizimlar aralash ishlatadi: mobil ilovada push bildirishnoma (tizim darajasida), veb-sahifada ochiq turgan bo‘lsa — polling yoki SSE. To‘liq WebSocket faqat haqiqatan real vaqt kerak bo‘lganda (to‘g‘ridan-to‘g‘ri xabarlar, jonli efir).

Yutuq: Tasma o'zi yangilanadi, 'yangi postlar' tugmasi paydo bo'ladi

Narxi: Millionlab ochiq ulanish; ularning har biri xotira yeydi

11

Qidiruv: alohida dunyo

Oddiy tilda: kutubxonaning so‘zlar katalogi — “bu so‘z qaysi maqolalarda bor”. Bu tasmadan butunlay boshqa kartoteka.

Tasma va qidiruv — ikki xil masala. Tasma kim yozgani bo‘yicha, qidiruv esa nima yozilgani bo‘yicha ishlaydi.

Post yozildi
  -> tokenizatsiya: so'zlar, xeshteglar, eslatmalar
  -> teskari indeks: so'z -> [post ID lari]
  -> real vaqtda indekslanadigan segment (xotirada)
  -> davriy ravishda diskdagi segmentga birlashtiriladi
Hisob · Teskari indeksning hajmi
Kuniga 300 000 000 post O'rtacha 20 ta indekslanadigan token (so'z, xeshteg, eslatma) Indeks yozuvlari: 300e6 x 20 = 6e9 / kun Bitta yozuv (post ID + pozitsiya, siqilgan): ~30 bayt Kunlik indeks: 6e9 x 30 = 180 GB Haftalik (xotirada): 1.26 TB Yillik (diskda, siqilgan): ~30 TB
Natija: Kunlik indeks ~180 GB. Oxirgi hafta xotirada (1.3 TB), qolgani diskda — chunki so'rovlarning 90% i so'nggi kunlarga tegishli

Eng yangi segment xotirada turadi (natijalar soniyalar ichida ko‘rinishi uchun), eskilari siqilib diskka tushadi. Bu — Redis darsidagi “issiq va sovuq ma’lumot” ajratishning aynan o‘zi.

Yutuq: Post yozilgandan soniyalar ichida topiladi

Narxi: Butunlay boshqa saqlash va indekslash quvuri

12

Media quvuri

Oddiy tilda: maqola matni konvertga sig‘adi, rasm va video esa yo‘q. Ular alohida omborda turadi, konvertda faqat ularning manzili.

Post 280 belgi — bu 300 bayt. Rasm — 2 MB, video — 50 MB. Ular hech qachon post bilan birga saqlanmaydi:

Post: { text, media_ids: [...] }
Media: obyekt xotirada (S3 kabi), CDN orqali beriladi
Hisob · Media trafigi tasmadan necha barobar katta
Tasma javobi (50 ta post, faqat matn va metama'lumot): 50 x 300 bayt = 15 KB Shu 50 postning yarmida rasm bo'lsa (tasma uchun kichik o'lcham): 25 x 80 KB = 2 MB Kunlik media trafigi: 347 000 tasma/s x 2 MB = 694 GB/s <- CDN orqali Matn: 347 000 x 15 KB = 5.2 GB/s
Natija: Media trafigi matndan 2000 barobar katta. Shuning uchun u alohida quvurda, CDN orqali va tasma yo'lidan tashqarida yashaydi

Yuklash paytida rasm bir necha o‘lchamga qayta ishlanadi (tasma uchun kichigi, to‘liq ko‘rish uchun kattasi). Video esa YouTube darsidagi kabi transkodlash quvuridan o‘tadi. Tasma esa faqat havolalarni ko‘taradi.

Yutuq: Rasm va video tasmani sekinlashtirmaydi

Narxi: Alohida saqlash, transkodlash va CDN xarajati

13

Ko'p mintaqa

Oddiy tilda: pochta bo‘limlari bir nechta shaharda. Maqola hamma shaharga ko‘chiriladi, lekin har shahar qutilarni o‘zi to‘ldiradi.

O‘qish yo‘li mintaqaviy replikalardan xizmat qiladi. Yozish esa odatda bitta “uy” mintaqada bajariladi va boshqalarga replikatsiya qilinadi.

Nozik joy: foydalanuvchi post yozdi va tasmasini yangiladi — lekin so‘rov boshqa mintaqaga tushdi va u yerda post hali yo‘q. Bu 2-darsdagi “o‘zi yozganini o‘qish” muammosining aynan o‘zi. Yechim ham o‘sha: o‘z posti mahalliy keshga darhol qo‘yiladi yoki qisqa vaqt davomida so‘rov “uy” mintaqaga yo‘naltiriladi.

▸Chuqurroq: Nima replikatsiya qilinadi, nima qilinmaydi

Hamma narsani hamma mintaqaga ko‘chirish qimmat. Amalda tanlov qilinadi:

Ma’lumotReplikatsiyaNega
Postlar (kontent)Hamma mintaqagaO‘qish yo‘lida kerak, hajmi nisbatan kichik
Tasma keshiYo‘qHar mintaqa o‘zi quradi — hosila ma’lumot
Obunalar grafiHamma mintaqagaFan-out va o‘qish uchun kerak
MediaCDN orqaliOrigin bitta, chekkada keshlanadi
Yoqtirishlar soniTaxminiy, mahalliyAniq son kerak emas; davriy sinxronlash
SessiyalarUy mintaqadaYozish uy mintaqaga yo‘naltiriladi

Eng qiziq qatori — tasma keshi replikatsiya qilinmaydi. U 1.6 TB va uni mintaqalar orasida sinxronlashtirish fan-out yukini mintaqalar soniga ko‘paytiradi. O‘rniga har bir mintaqa o‘z fan-out ishchilarini yuritadi: post replikatsiya qilinadi, tarqatish esa mahalliy bajariladi.

Buning narxi: fan-out ishi mintaqalar soniga ko‘payadi. Foydasi: tasma o‘qish har doim mahalliy va tez, hamda bitta mintaqa tushsa boshqalari ta’sirlanmaydi.

Yutuq: Kechikish kamayadi, mintaqa tushsa tizim ishlaydi

Narxi: Repl kechikishi, konflikt va ikki barobar sig'im

14

Sig'imni himoyalash

Oddiy tilda: bayram kuni pochta to‘lib-toshadi. Nimadan voz kechish oldindan rejalashtirilgan: avval bezaklar (tavsiyalar), keyin tezlik (real vaqt), eng oxirida — asosiy ish.

Yirik voqea (sport finali, favqulodda holat) paytida yozish ham, o‘qish ham bir necha barobar oshadi. Himoya qatlamlari:

  • Fan-out chegarasini pasaytirish — ko‘proq akkaunt pull rejimiga o‘tadi, yozish yuki darhol tushadi
  • Tasma uzunligini qisqartirish — 800 dan 200 ga; xotira va yozish tejaladi
  • Reytingni o‘chirish — xronologik tartibga qaytish; 9-qadamdagi 100 million baholash yo‘qoladi
  • Real vaqt yetkazishni o‘chirish — polling intervalini uzaytirish
  • Yozishga tezlik cheklovi — bot va spam avtomatik cheklanadi
Nazorat savoli · javobni ko‘rishFan-out navbati 30 daqiqaga orqada qoldi. Nima qilasiz?

Avval sabab: yozish cho‘qqisimi, ishchilar tushganmi, yoki bitta yirik akkaunt navbatni bo‘g‘ganmi? Oxirgisi eng ko‘p uchraydi.

Choralar tartibi:

  1. Yirik ishlarni ajratish — mashhur akkauntlarning fan-out ishlari alohida navbatga o‘tkaziladi, shunda oddiy foydalanuvchilar navbatda kutmaydi
  2. Chegarani pasaytirish — masalan 100 000 dan 10 000 ga. Yangi postlar uchun yozish yuki darhol kamayadi
  3. Ishchilarni ko‘paytirish — agar tor joy Redis emas, ishchi bo‘lsa
  4. Qisman degradatsiya — eng faol foydalanuvchilarga birinchi tarqatish, faol bo‘lmaganlarga keyinroq (ular baribir tez orada kirmaydi)

Nima qilmaslik kerak: navbatni tozalash (postlar butunlay yo‘qoladi) yoki fan-out ni sinxron qilish (post yozish sekinlashadi va yuk yanada oshadi).

Yutuq: Cho'qqi va hujum paytida tizim yiqilmaydi

Narxi: Ba'zi foydalanuvchilar sekinroq xizmat oladi

Nazorat savoli · javobni ko‘rishTasma keshi 1.6 TB. Uni ikki barobar kichraytirish uchun qanday variantlar bor?

Beshta tutqich, ta’siri bo‘yicha tartiblangan:

  1. Faol bo‘lmaganlarni chiqarish — 30 kunda kirmaganlarning tasmasi saqlanmaydi. Odatda eng katta yutuq (2–3 barobar), chunki faol foydalanuvchilar ulushi kichik
  2. Tasma uzunligini qisqartirish — 800 dan 400 ga. To‘g‘ridan-to‘g‘ri 2 barobar, lekin chuqur varaqlash sekinlashadi (bazadan qayta qurish kerak bo‘ladi)
  3. ID larni siqish — tasma ID lari o‘xshash (bir vaqt oralig‘idan). Ular delta sifatida saqlansa (birinchi ID to‘liq, qolganlari farq), 8 bayt o‘rniga 2–3 bayt yetadi
  4. Kesh darajalari — eng faol 10% xotirada, qolgani SSD‘da (masalan Redis‘ning disk kengaytmalari yoki alohida qatlam)
  5. Kodlash — Redis quicklist ustama xarajatini kamaytirish uchun kalitlarni guruhlash

Amalda 1 va 2 birinchi qo‘llanadi — ular oddiy va katta yutuq beradi. 3 esa kod murakkabligini oshiradi va faqat haqiqatan chegaraga yetganda qilinadi.

7. Bitta postning hayoti

Evolyutsiyadan keyin tizim ko‘p qismli bo‘lib qoldi. Endi bitta postni yozilgan lahzadan obunachining ekraniga chiqqungacha kuzatamiz. Shunda har qism nega kerakligi va “5 soniya” va’dasi qanday bajarilishi ko‘rinadi.

7.1 Qadam-baqadam

Oddiy tilda: siz xatni pochtaga topshirdingiz va chek oldingiz. Shu lahzada xatingiz arxivga yozildi va o‘zingizning qutingizga nusxasi tushdi. Qolgan ishni pochtachilar fonda qiladi: ro‘yxatdan sizning o‘quvchilaringizni topib, minglab qutiga bir yo‘la tashlaydi.

POST /tweet
Snowflake ID
Tweet xizmati: saqlash (manba haqiqat)
Muallifning o'z tasmasi
Fan-out navbati
Graf: obunachilar, bo'lak-bo'lak
Redis tasmalari: pipelining
Obunachi: LRANGE + hidratsiya
Muallif javobni 4-qadamdan keyin oladi. 5-7-qadamlar fonda: 2012-yilda Twitter tasmalarga bir yo'la ~4 000 manzildan pipelining bilan yozgan
  1. ID — Snowflake (7-qadam): koordinatsiyasiz, vaqt bo‘yicha tartiblangan.
  2. Saqlash — post manba bazaga yoziladi. Shu paytdan u yo‘qolmaydi.
  3. O‘z tasmasi — muallif o‘z postini darhol ko‘radi (10.2 dagi yagona qat’iy talab). Bu tarqatishni kutmaydi.
  4. Navbat — tarqatish vazifasi navbatga tushadi. Muallif javobni oldi.
  5. Graf — “menga kim obuna?” ro‘yxati bo‘laklarda o‘qiladi.
  6. Tasmalar — har bo‘lakka bitta pipelined so‘rov: LPUSH + LTRIM.
  7. O‘qish — obunachi tasmani ochganda ID lar olinadi, hidratsiya va filtr qo‘llanadi, mashhurlarning postlari pull qilinib qo‘shiladi.

7.2 “5 soniya” byudjeti

Hisob · Post obunachilarga qancha vaqtda yetadi
Bitta fan-out ishchisi: bo'lak = 4 000 manzil, bitta pipelined so'rov ~10 ms -> ~400 000 tasma yozuvi / s bitta ishchida Obunachilar (= yozuvlar) 1 ishchi 100 ishchi 200 0.5 ms - 20 000 50 ms - 1 000 000 2.5 s 25 ms 100 000 000 250 s 2.5 s + butun klaster sig'imi ~2 mln yozuv/s (5.1) -> 100 mln yozuv = 50 s, qolgan HAMMA post kutadi Navbatdagi kutish (o'rtacha yuk 70% bo'lsa) qo'shiladi: oddiy post: 1-3 s -> "5 soniya" va'dasi bajariladi
Natija: Oddiy akkaunt — millisekundlar. 1 mln obunachi — ~1 soniya ish, lekin navbatdagi joyiga qarab soniyalar. 100 mln — butun klasterning 50 soniyasi: shuning uchun mashhurlar pull qilinadi

7.3 Push, pull va gibrid — o‘lchovda

2-daraja amaliyotida 8 000 foydalanuvchili darajali grafda (median — 9 obunachi, eng mashhurida 6 447) bir xil yuklama turli chegaralar bilan o‘tkaziladi. Har foydalanuvchi 2 ta post yozadi va 20 marta tasma o‘qiydi:

Hisob · Bir xil yuklama, besh xil strategiya
push pull maks jami yozuv so'rov fan-out (ming) Sof pull 16 000 3 203k 1 3 219 Chegara 200 270 000 1 525k 200 1 794 Chegara 1000 379 000 810k 999 1 189 Chegara 3000 450 000 401k 2 948 851 Sof push 504 000 0 6 448 504 Sof pull / sof push = 6.4 barobar qimmat
Natija: Amallar soni bo'yicha sof push eng arzon — o'qish yozishdan 10 barobar ko'p bo'lgani uchun. Gibrid esa eng katta fan-out'ni 6 448 dan 2 948 ga tushiradi: u NARX uchun emas, KECHIKISH dumi uchun

Bu jadval 5-bo‘limdagi Deep bilan birga o‘qilishi kerak. Real tizimda gibrid narx jihatidan ham yutadi, chunki uchta omil bu modelda yo‘q:

  1. Faol bo‘lmagan obunachilar — mashhur akkauntning obunachilari orasida hozir tasmani o‘qimaydiganlar ko‘p. Ularga yozish — sof isrof (6-bo‘lim 1-qadam).
  2. Pull arzon o‘qish — mashhur akkauntning oxirgi postlari juda issiq kalit, u keshda va bitta MGET bilan olinadi. Bu tasmaga yozish bilan bir xil narx emas.
  3. Burst — 100 mln yozuv bir lahzada tushadi va navbatni bo‘g‘adi. Narx o‘rtacha yuk bilan emas, cho‘qqi bilan to‘lanadi.
Nazorat savoli · javobni ko‘rishAmaliyotdagi simulyatsiyada sof push eng kam amal qildi. Unda nega Twitter mashhur akkauntlar uchun pull'ga o'tgan?

Chunki “jami amallar soni” yagona mezon emas. Uchta mezon bor va sof push ikkitasida yutqazadi:

  • Dum kechikishi — bitta postning fan-out’i 6 448 dan (simulyatsiyada) 100 millionga (haqiqatda) cho‘ziladi. Bu post soniyalar emas, daqiqalarda yetadi va shu paytda boshqa hamma postlar navbatda kutadi.
  • Cho‘qqi sig‘imi — tizim o‘rtacha emas, eng yomon daqiqaga qarab qurilishi kerak. Mashhur akkaunt bir post bilan cho‘qqi yaratadi.
  • Isrof — yozuvlarning katta qismi faol bo‘lmagan obunachilarga ketadi va hech qachon o‘qilmaydi.

Gibrid chegarani yuqori qo‘yadi (faqat eng mashhur ~0.01–0.1% akkaunt pull qilinadi). Shunda o‘qishdagi qo‘shimcha narx kichik bo‘ladi, dum va cho‘qqi esa cheklanadi. Bu — o‘rtacha va dum orasidagi klassik kelishuv.

8. “Sizga tavsiya”: 2023-yilgi ochiq algoritm

8.1 Oddiy tilda: shaxsiy muharrir

Oddiy tilda: xronologik tasma — qutingizga tushgan hamma xatni vaqt bo‘yicha o‘qish. “Sizga tavsiya” esa shaxsiy muharrir. U har ertalab siz obuna bo‘lganlarning xatlaridan, boshqa minglab mualliflarning xatlaridan ham bir dasta tanlaydi va sizga eng qiziq bo‘ladiganlarini tartib bilan qo‘yadi. Muharrir sizni qanchalik yaxshi bilsa, shuncha yaxshi tanlaydi — lekin u qimmat, va har ertalab yuz million odam uchun ishlaydi.

8.2 Uch bosqich

2023-yil 31-martda Twitter “Sizga tavsiya” tasmasini tuzadigan kodning katta qismini ochiq e’lon qildi va blogda uni tasvirlab berdi. Asosiy raqamlar: quvur kuniga ~5 milliard marta ishlaydi, har safar yuzlab million postdan ~1 500 ta nomzod tanlanadi, ular ~48 million parametrli neyron tarmoq bilan baholanadi. O‘rtacha foydalanuvchi tasmasining taxminan yarmi obunalaridan, yarmi esa obunadan tashqaridan keladi.

Nomzodlar: obunalardan (~50%)
Nomzodlar: obunadan tashqari (~50%) — o'xshash jamoalar, siz o'qiganlarni yoqtirganlar
~1 500 nomzod
Og'ir reyting: ~48 mln parametrli model
Evristika va filtrlar: bloklangan, takror, bitta muallifdan ko'p
Aralashtirish: reklama, tavsiya qilingan akkauntlar
Tasma
Bu darsdagi push/pull quvuri endi faqat birinchi qadam — nomzodlar manbalaridan biri
  1. Nomzodlar manbalari. Obunalardan keladiganlar — aynan shu darsda qurgan tizim (push + pull) va obunalaringiz bilan aloqangiz kuchini baholaydigan model. Obunadan tashqari nomzodlar uchun esa o‘xshash foydalanuvchilar jamoalari, siz kuzatganlar yoqtirgan postlar va embedding bo‘shliqlari ishlatiladi.
  2. Reyting. Har nomzod uchun model bir necha ehtimolni bashorat qiladi: yoqtirish, javob yozish, repost, uzoq o‘qish va salbiy reaksiyalar. Yakuniy ball — ularning og‘irlikli yig‘indisi.
  3. Evristika. Model yaxshi bo‘lsa ham, natija “inson qoidalari” bilan tuzatiladi: bitta muallifdan ketma-ket ko‘p post bo‘lmasin, bloklangan va ko‘rilgan postlar chiqmasin, obunalar va boshqalar muvozanatda bo‘lsin.

8.3 Narxi

Hisob · 'Sizga tavsiya' hisob narxi
Quvur ishga tushishi: ~5 000 000 000 / kun 5e9 / 86 400 = ~58 000 / s (o'rtacha) Nomzodlar har safar: ~1 500 Baholashlar: 58 000 x 1 500 = ~87 000 000 / s Cho'qqida (2x): ~174 000 000 / s Bitta baholash (48 mln parametr, paketlab): ~2 x 48e6 = ~1e8 amal (FLOP) 87e6 x 1e8 = ~8.7e15 FLOP/s = ~9 PFLOP/s -> o'nlab-yuzlab GPU, faqat shu bosqich uchun Taqqoslang: xronologik tasma = LRANGE + MGET -> deyarli faqat xotira o'qish
Natija: Sekundiga ~87 mln nomzodni baholash — 6-bo'lim 9-qadamdagi hisob (104 mln/s) bilan bir tartibda. Bitta baholash 10 us bo'lsa — ~870 yadro faqat reyting uchun; aslida GPU va paketlab hisoblash ishlatiladi
Hisob · Nega aynan ~1 500 nomzod
Foydalanuvchi bir seansda ko'radi: ~50-100 post Reyting tanlovni yaxshilashi uchun: ~15-30 barobar ko'p nomzod -> 50 x 30 = 1 500 Nomzodlar -> narx (chiziqli): 150 nomzod -> 0.1x (tanlov tor) 1 500 nomzod -> 1x 15 000 nomzod -> 10x (manbalar ham sekinlashadi)
Natija: Nomzodlar soni — sifat va narx orasidagi tutqich: 1 500 dan 15 000 ga oshirish reyting narxini 10 barobar oshiradi, tasmaning yaxshilanishi esa kichik bo'ladi — eng yaxshilari odatda birinchi minglikda
▸Chuqurroq: Ochiq algoritmdan muhandis uchun uch saboq
  1. Quvur — ko‘p bosqichli voronka. Arzon manbalar ko‘p nomzod beradi, qimmat model ozini baholaydi. Bu ChatGPT darsidagi RAG “retrieve → rerank” naqshi bilan bir xil. 6-bo‘lim 9-qadamdagi ikki bosqichli reyting 2023-yilda shu shaklga yetgan.
  2. Bu darsdagi tizim yo‘qolmadi. Push/pull tasma keshi endi nomzodlar manbalaridan biri: obunalaringizning postlarini tez yig‘ish uchun u hali ham kerak. Xronologik “Kuzatilayotganlar” tasmasi esa aynan shu tizimning o‘zi.
  3. Model natijasi oxirgi so‘z emas. Evristika va filtrlar qatlami (muallif xilma-xilligi, bloklar, takrorlar) model ustida turadi. Ko‘p “nega bu post chiqdi?” savollariga javob modelda emas, aynan shu qoidalarda.
Nazorat savoli · javobni ko‘rish'Sizga tavsiya' tasmasida obunadan tashqari postlar ham bor. Bu push/pull arxitekturasini qanday o'zgartiradi?

Push faqat obunalar uchun ishlaydi: post obunachilarning tasmasiga yoziladi. Obunadan tashqari post — sizga obuna bo‘lmagan muallifniki. Uni oldindan sizning tasmangizga yozib bo‘lmaydi, chunki kimga tavsiya qilishni yozish paytida bilmaysiz.

Shuning uchun obunadan tashqari nomzodlar pull qilinadi, o‘qish paytida, boshqa indekslardan: jamoalar bo‘yicha mashhur postlar, o‘xshash foydalanuvchilar yoqtirganlar, embedding qidiruvi. Ya’ni tasmaning yarmi o‘qish paytida yig‘iladi. O‘qish yo‘li esa yana qimmatlashdi: bu endi “tayyor ro‘yxatni olish” emas, balki bir nechta manbadan nomzod yig‘ish va ularni model bilan baholash.

Tarixiy kinoya: 2009-yilda ish o‘qishdan yozishga ko‘chirilgan edi (1.4). Reyting esa uning katta qismini o‘qishga qaytardi. Faqat endi bu JOIN emas, ko‘p bosqichli voronka.

9. Bugungi arxitektura

Tasma tizimining to'liq qatlamlari
Mijoz
Mobil ilovaVebPush bildirishnoma

Tasma sahifalab yuklanadi: birinchi 20 ta, keyin qo'shimchasi.

API qatlami
AuthTezlik chekloviMarshrutlash
Yozish yo'li
Tweet xizmatiFan-out navbatiFan-out ishchilari

3 500 post/s -> 700 000 tasma yozuvi/s (mashhurlarsiz).

O'qish yo'li
Tasma xizmatiAralashtirish (push + pull)ReytingHidratsiya

347 000 so'rov/s. Barcha qimmat ish shu yerda optimallashtiriladi.

Saqlash
Tasma keshi (~1.6 TB)Post keshi (~270 GB)Graf keshiShardlangan baza
Yon tizimlar
Qidiruv indeksiMedia va CDNAnalitikaModeratsiya

9.1 Tasma so‘rovining kechikish byudjeti

Hisob · 200 ms qayerga ketadi
Foydalanuvchi tasmani ochdi: -> 15 ms Tarmoq (mobil, mintaqa ichida) -> 3 ms Auth va tezlik cheklovi -> 2 ms LRANGE timeline:<user> 0 79 (push qismi) -> 8 ms Mashhurlarning postlari (5 ta parallel so'rov) -> 1 ms Birlashtirish va deduplikatsiya -> 25 ms Hidratsiya: MGET postlar + mualliflar -> 30 ms Reyting (100 nomzod) -> 5 ms Filtrlash: o'chirilgan, bloklangan -> 20 ms Javobni yig'ish va tarmoq ========================================== ~110 ms Cho'qqi yuklamada navbat kutish qo'shiladi -> 200 ms
Natija: Modelning o'zi emas, hidratsiya va reyting eng qimmat. Optimallashtirish aynan shu ikkitasidan boshlanadi

9.2 Tasma API si

Mijoz bilan shartnoma tizimning imkoniyatlarini belgilaydi — noto‘g‘ri API keyin o‘zgartirib bo‘lmaydigan cheklovlar yaratadi.

GET /v1/timeline?limit=20&cursor=1712345678901234567

{
  "items": [ { "id": "...", "author": {...}, "text": "...", "stats": {...} } ],
  "next_cursor": "1712345600000000000",
  "has_more": true
}
QarorNima uchun shunday
cursor, offset emasRo‘yxat o‘zgarganda barqaror sahifalash (6-bo‘lim, 1-qadam)
limit maksimal 100Hidratsiya narxini cheklaydi; katta so‘rov klasterni bo‘g‘adi
To‘liq muallif obyektiMijozda qo‘shimcha so‘rov bo‘lmasin (N+1 muammosi)
stats taxminiyYoqtirishlar soni aniq bo‘lishi shart emas — keshdan
has_more alohidaBo‘sh items bilan ham davom etish mumkin (hammasi filtrlangan holat)
▸Chuqurroq: Bitta API, uch xil mijoz

Veb, mobil ilova va uchinchi tomon integratsiyalari bir xil tasmani so‘raydi, lekin ehtiyojlari boshqacha:

MijozEhtiyojTa’siri
Mobil ilovaKam trafik, offline keshJavob ixcham, If-None-Match qo‘llab-quvvatlansin
VebTez birinchi ko‘rinishBirinchi 5 ta post server tomonda render qilinadi
Uchinchi tomon APIOmmaviy o‘qishQattiq tezlik cheklovi va alohida kvota

Eng ko‘p qilinadigan xato — barchasiga bir xil javob berish. Mobil ilovaga to‘liq muallif obyektini har postda yuborish trafikni 3 barobar oshiradi (bir xil muallif tasmada bir necha marta uchraydi). Yechim: items da faqat author_id, mualliflar esa alohida users xaritasida — bu normallashtirilgan javob naqshi.

10. Ishonchlilik

10.1 Nosozliklar taksonomiyasi

NosozlikBelgisiSababChora
Fan-out orqada qoldiPostlar 10+ daqiqada ko‘rinadiCho‘qqi yoki yirik akkauntChegarani pasaytirish, navbatni ajratish
Tasma keshi tuguni tushdiBa’zi foydalanuvchilarda tasma bo‘shApparat, OOMBazadan qayta qurish; replika
Hot shardBitta tugun 100% CPUMashhur akkaunt yoki viral postPost keshini replikatsiya qilish
Hidratsiya sekinlashdip99 oshdi, tasma kelmaydiPost keshi promahiKesh isitish, qisman javob
Dublikat postlarBir post ikki marta ko‘rinadiChegara kesib o‘tildi yoki retryO‘qishda deduplikatsiya
Bo‘shliq (gap)Postlar tushib qolganNavbatda yo‘qotishDavriy tekshirish va qayta qurish
Reyting modeli tushdiTasma g‘alati tartibdaModel xizmati nosozligiXronologik tartibga qaytish
▸Chuqurroq: Tasmani qayta qurish: eng muhim zaxira mexanizmi

Tasma keshi — bu hosila ma’lumot. Uni har doim manbadan (postlar + graf) qayta qurish mumkin. Bu xususiyat butun tizimning xavfsizlik to‘ri:

rebuild_timeline(user_id):
    following = graph.following(user_id)          # 200 ta
    oddiy = [u for u in following if not is_celebrity(u)]
    ids = []
    for u in oddiy:
        ids += user_tweets(u, limit=100)          # profil indeksidan
    ids.sort(reverse=True)
    redis.rpush(f"timeline:{user_id}", *ids[:800])

Bitta tasmani qayta qurish ~200 so‘rov va bir necha yuz millisekund oladi. Bu qimmat, shuning uchun u faqat kerak bo‘lganda ishlatiladi:

  • Kesh tuguni tushganda (o‘sha tugundagi tasmalar)
  • Foydalanuvchi uzoq vaqtdan keyin qaytganda (tasmasi saqlanmagan edi)
  • Bo‘shliq aniqlanganda

Muhim cheklov: hamma tasmani birdan qayta qurib bo‘lmaydi. Katta tugun tushsa, millionlab tasma kerak bo‘ladi — ular navbat orqali, tezlik cheklovi bilan, eng faol foydalanuvchilardan boshlab tiklanadi.

10.2 Izchillik kelishuvlari

Bu tizimda hech narsa kuchli izchil emas va bu ongli tanlov:

HodisaKutilgan kechikishNima bo‘lsa yomon emas
Post yozildi → obunachilarda ko‘rindi1–10 soniyaBir necha soniya kechikish sezilmaydi
Obuna bo‘ldi → tasmada ko‘rindiKeyingi postdanEski postlar kerak emas
Post o‘chirildi → tasmadan yo‘qoldiKeyingi hidratsiyadaBir marta ko‘rinib qolishi mumkin
Yoqtirishlar soni10–60 soniyaTaxminiy son yetarli

Yagona qat’iy talab: o‘z posti darhol ko‘rinsin. Foydalanuvchi post yozib, o‘z tasmasida uni ko‘rmasa — “ishlamadi” deb qayta yozadi. Shuning uchun o‘z posti mahalliy ravishda, tarqatishni kutmasdan qo‘shiladi.

10.3 Degradatsiya tartibi

1-bosqich
Reytingni o'chirish
Xronologik tartibga qaytish 100 million baholash/s ni yo'qotadi. Foydalanuvchi sezadi, lekin tasma ishlaydi.
2-bosqich
Fan-out chegarasini pasaytirish
Yozish yuki darhol kamayadi; o'qish biroz qimmatlashadi.
3-bosqich
Tasma uzunligini qisqartirish
800 -> 200. Xotira va yozish tejaladi; chuqur varaqlash sekinlashadi.
4-bosqich
Real vaqt yangilanishini o'chirish
Polling intervali uzayadi; ochiq ulanishlar yopiladi.
5-bosqich
Faol bo'lmaganlarga tarqatishni to'xtatish
Ular kirganda tasma qayta quriladi (10.1-bo'limdagi mexanizm).
6-bosqich
Yozishga qattiq tezlik cheklovi
Oxirgi chora: yangi postlar sekinlashadi, lekin o'qish ishlaydi.

10.4 Javoblar: tasmadagi eng nozik qoida

Post — bu tekis ro‘yxatdagi element emas: unga javob yoziladi, javobga yana javob. Savol: javob kimning tasmasiga tushishi kerak?

Sodda javob (“muallifning barcha obunachilariga”) yomon ishlaydi:

A -> B ga javob yozdi
A ning 5000 obunachisi B ni bilmaydi
Ular kontekstsiz javobni ko'radi: "ha, roziman"

Amaliy qoida — kesishma: javob faqat ikkalasiga ham obuna bo‘lganlarga ko‘rsatiladi.

Hisob · Kesishma qoidasining narxi
A ning obunachilari: 5 000 B ning obunachilari: 200 000 Kesishma (ikkalasiga ham obuna): eng yomon holat: 5 000 x tekshiruv Yozish paytida hisoblansa: har bir javob uchun 5 000 ta SISMEMBER javoblar postlarning ~40% i -> 1 400 javob/s 1 400 x 5 000 = 7 000 000 tekshiruv/s O'qish paytida filtr sifatida: faqat tasmaga tushgan javoblar tekshiriladi ~10 ta javob x 1 ta tekshiruv = arzon
Natija: Kesishmani yozishda hisoblash qimmat: 200 000 elementli ikki to'plamni solishtirish. Shuning uchun u odatda o'qish paytida, filtr sifatida qo'llanadi
▸Chuqurroq: Suhbat daraxti: alohida masala

Javoblar zanjiri (thread) tasmadan butunlay boshqa struktura: u daraxt, tasma esa tekis ro‘yxat.

Asl post
├── javob 1
│   ├── javob 1.1
│   └── javob 1.2
└── javob 2

Uni saqlashning uch usuli:

UsulQandayKamchilik
reply_to ko‘rsatkichiHar javob otasiga ishora qiladiButun daraxtni olish uchun rekursiv so‘rov
Materiallashtirilgan yo‘lpath = "123/456/789"Yo‘l uzunligi cheklangan; ko‘chirish qiyin
Ildiz ID si + tartibHar javob root_id ni saqlaydiBitta so‘rov, lekin daraxt shakli ilovada quriladi

Amalda uchinchisi ishlatiladi: root_id bo‘yicha barcha javoblar bitta so‘rovda olinadi (ular bitta shardda yotadi), keyin ilovada daraxt quriladi va reytinglanadi.

Nozik jihat: mashhur postda 500 000 javob bo‘lishi mumkin. Hammasini olib bo‘lmaydi — faqat “eng yaxshi” 50 tasi olinadi va bu yana reyting masalasi: qaysi javoblar ko‘rsatiladi, qaysilari “ko‘proq javoblarni ko‘rish” ostida qoladi.

10.5 Bloklash, yashirish va filtrlar

Foydalanuvchi kimnidir bloklasa yoki yashirsa (mute), uning postlari tasmada ko‘rinmasligi kerak. Savol: bu qachon qo‘llanadi?

Yozish paytida (fan-out'da)
  • Bloklangan odamga tarqatmaslik
  • O'qish tez — filtr kerak emas
  • Bloklash o'zgarsa, ESKI tasmalar tuzatilmaydi
  • Fan-out har bir obunachi uchun tekshiruv qiladi — sekin
O'qish paytida (hidratsiyada)
  • Filtr har safar joriy qoidalar bo'yicha
  • Bloklash darhol kuchga kiradi, orqaga ham
  • Har o'qishda qo'shimcha tekshiruv
  • Ortiqcha nomzod olish kerak (50 emas, 80)

To‘g‘ri javob — o‘qish paytida, va sabab 6-bo‘limning 5-qadamidagi bilan bir xil: bloklash o‘zgarganda millionlab tasmani qayta yozib bo‘lmaydi.

Hisob · Filtrlash uchun qancha ortiqcha olish kerak
Filtrlanadigan postlar ulushi (o'rtacha): o'chirilgan ~3% bloklangan/yashirilgan ~8% moderatsiya ~2% takroriy (repost) ~10% ----------------------------- Jami ~23% 50 ta ko'rsatish uchun kerak: 50 / (1 - 0.23) = 65 ta Zaxira bilan: 75-80 ta ID olinadi Agar filtrdan keyin 50 ta chiqmasa -> kursor bilan yana bir marta so'raladi (kamdan-kam)
Natija: 50 ta post ko'rsatish uchun 75 ta ID olinadi. Filtr ulushi oshsa (masalan ko'p bloklagan foydalanuvchi) bu son dinamik oshiriladi
Nazorat savoli · javobni ko‘rishBloklash o'qishda qo'llanadi. Unda bloklangan odam mening postlarimni ko'ra oladimi?

Bu ikki xil masala va ularni ajratish muhim:

Tasmadagi filtr — men bloklaganning postlari menga ko‘rinmaydi. Bu o‘qish paytida, mening kontekstimda qo‘llanadi.

Kirish nazorati — men bloklagan odam mening profilim va postlarimni ko‘ra oladimi? Bu butunlay boshqa tekshiruv va u har bir o‘qish yo‘lida (profil, qidiruv, to‘g‘ridan-to‘g‘ri havola) alohida qo‘llanishi kerak.

Ikkinchisi ko‘pincha unutiladi: tasmada filtr bor, lekin postga to‘g‘ridan-to‘g‘ri havola bilan kirish mumkin. Bu — xavfsizlik xatosi, oddiy UX kamchiligi emas.

Qat’iy talab: kirish nazorati kontent qaytariladigan har bir joyda bo‘lishi kerak, va u eng past qatlamda (hidratsiya xizmatida) amalga oshirilsa ishonchliroq bo‘ladi.

11. Suiiste’mol va xavfsizlik

Ijtimoiy tarmoqda asosiy tahdid — texnik emas, ijtimoiy:

TahdidMexanizmiChora
Spam va botOmmaviy akkaunt yaratish, avtomatik postYozishga tezlik cheklovi, xatti-harakat tahlili
Sun’iy tarqatishSotib olingan repostlar, koordinatsiyalangan guruhGraf tahlili: g‘ayritabiiy bog‘lanish naqshlari
Obunachi “fermalari”Soxta akkauntlar bilan obunachi sotishFaollik nisbati, akkaunt yoshi
Ta’qib va hujumKo‘p akkauntdan bir odamgaBloklash, filtr, sekinlashtirish
Ma’lumot yig‘ish (scraping)API yoki HTML orqali ommaviy o‘qishTezlik cheklovi, autentifikatsiya talabi

11.1 Bildirishnomalar: teskari fan-out

Tasma — “men kimni o‘qiyman”. Bildirishnomalar — “menga kim murojaat qildi”. Bu teskari yo‘nalish va u boshqacha muammo tug‘diradi.

Tasma:            1 post -> N obunachi   (fan-out)
Bildirishnoma:    N reaksiya -> 1 muallif (fan-in)
Hisob · Mashhur postning bildirishnomalari
Viral post: 1 000 000 yoqtirish, 50 000 repost, 20 000 javob Agregatsiyasiz: 1 070 000 ta bildirishnoma yozuvi Hammasi BITTA foydalanuvchining ro'yxatiga -> hot key, va ro'yxat o'qib bo'lmas darajada uzun Agregatsiya bilan: "1 000 000 kishi postingizni yoqtirdi" -> 1 ta yozuv "Ahmad va yana 49 999 kishi repost qildi" -> 1 ta yozuv Javoblar alohida (ular mazmunli)
Natija: Bitta postga million reaksiya bitta foydalanuvchiga million yozuv demak. Agregatsiyasiz bu foydalanuvchi ilovasini ishlatib bo'lmaydi

Agregatsiya oynali bo‘ladi: bir necha daqiqalik oynada bir xil turdagi reaksiyalar bitta yozuvga birlashtiriladi. Bu ham yozishni o‘qishga ko‘chirishning yana bir ko‘rinishi — faqat bu safar teskari tomonda.

Nazorat savoli · javobni ko‘rishYangi funksiya: 'do'stlaringiz yoqtirgan postlar' ni tasmaga qo'shmoqchisiz. Nima o'zgaradi?

Bu oddiy ko‘rinadi, lekin butun yozish yo‘lini o‘zgartiradi.

Hozir fan-out faqat post yozilganda ishlaydi. Yangi funksiyada yoqtirish ham tarqatilishi kerak: A postni yoqtirdi → A ning obunachilariga xabar.

Yoqtirishlar postlardan 10–20 barobar ko‘p (har post o‘rtacha 10+ yoqtirish oladi):

Postlar:      3 500/s  -> fan-out 700 000 yozuv/s
Yoqtirishlar: 50 000/s -> fan-out 10 000 000 yozuv/s

Ya’ni fan-out yuki 14 barobar oshadi. Bu sof push bilan imkonsiz.

Amaliy yechim: bunday postlarni push qilmaslik, o‘qish paytida qo‘shish — “obunalarim so‘nggi soatda nimani yoqtirdi” degan alohida so‘rov, natija esa reyting bosqichida asosiy nomzodlar bilan aralashtiriladi.

Ya’ni yana o‘sha gibrid tamoyil: qimmat fan-out — pull, arzoni — push.

12. Iqtisod

Hisob · Tasma tizimining oylik xarajati
Tasma keshi (1.6 TB RAM): 30 tugun x 64 GB, replika bilan 60 tugun 60 x ~$400/oy = $24 000 Post keshi (270 GB) + graf keshi: 20 tugun x ~$400 = $8 000 Fan-out ishchilari (700k yozuv/s): ~100 server x $150 = $15 000 O'qish yo'li (347k so'rov/s, reyting bilan): ~1000 server x $150 = $150 000 Baza (33 TB/yil, shardlangan): ~100 tugun x $500 = $50 000 Tarmoq va CDN (media): ~$50 000 ========================================= ~$300 000 / oy
Natija: Oyiga ~$300 000 tartibida. Bitta tasma yuklanishi $0.0000003 — lekin oyiga 900 milliard marta yuklanadi

Diqqat: xarajatning yarmi o‘qish yo‘liga ketadi va uning katta qismi reyting. Xronologik tasma bir necha barobar arzon — bu mahsulot qarorining to‘g‘ridan-to‘g‘ri narxi.

13. Sig‘im rejalashtirish

Hisob · Yangi mintaqa ochish uchun nima kerak
100 000 000 yangi faol foydalanuvchi: Tasma keshi: 100e6 x 800 x 8 bayt x 1.25 = 800 GB (faqat faollari saqlanadi -> ~320 GB) Yozish yuki: ular kuniga 60e6 post yozadi -> 694 post/s fan-out: 694 x 200 = 139 000 yozuv/s O'qish yuki: 100e6 x 60 / 86400 = 69 000 tasma/s cho'qqida 208 000/s Serverlar: o'qish: ~200 ta fan-out: ~20 ta
Natija: Har 100 million yangi faol foydalanuvchi uchun ~320 GB tasma keshi va ~200 qo'shimcha server
Hisob · Faol bo'lmagan obunachilarga yozmaslik qancha tejaydi
Ro'yxatdan o'tganlar: 500 mln (faraz) Oxirgi 30 kunda kirganlar: 200 mln (40%) Fan-out, hammaga yozilsa: har post x 200 obunachi = 200 yozuv Faqat faollarga: 200 x 0.4 = 80 yozuv -> yozuvlar 60% kam: 694 000/s o'rniga ~278 000/s Tasma keshi: hammaga: 500e6 x 800 x 8 x 1.25 = 4.0 TB faollarga: 200e6 x ... = 1.6 TB (6-bo'lim 1-qadam) Narxi: qaytgan "uxlagan" foydalanuvchi birinchi ochishda ~200 so'rov va bir necha yuz ms kutadi
Natija: Faqat oxirgi 30 kunda kirganlarga yozish fan-out yozuvlarini ~60% ga, tasma keshini esa ~2.5 barobar kamaytiradi. Qaytgan foydalanuvchining tasmasi bir marta qayta quriladi (10.1)
Nazorat savoli · javobni ko‘rishTasma keshini faqat faol foydalanuvchilar uchun saqlaysiz. Kimdir 3 oydan keyin qaytdi va 50 million odam bir vaqtda qaytdi (masalan, katta sport finali). Nima bo'ladi?

Bitta qaytgan foydalanuvchi uchun hammasi joyida: tasma ~200 so‘rov bilan qayta quriladi, birinchi ochish biroz sekinroq.

50 million bir vaqtda qaytsa — bu qayta qurish bo‘roni: 50 mln × 200 = 10 milliard so‘rov graf va post indekslariga. Bu baza va kesh uchun 2-darsdagi cache stampede’ning ulkan versiyasi.

Himoya:

  1. Navbat va tezlik cheklovi — qayta qurish ishlari navbatga tushadi va eng faollardan boshlab bajariladi (10.1 Deep)
  2. Arzon vaqtinchalik javob — tasma tayyor bo‘lguncha “mashhur postlar” yoki mintaqaviy “eng yaxshi” tasma ko‘rsatiladi (6-bo‘lim 3-qadam Deep)
  3. Oldindan isitish — rejalashtirilgan voqealar oldidan oxirgi 30–90 kunda faol bo‘lganlarning tasmalarini fonda qayta qurish
  4. Qisqartirilgan qayta qurish — 800 emas, 100 ta post; qolgani varaqlaganda

Bu — 10.3 dagi degradatsiya tartibining yana bir bosqichi: tizim to‘liq xizmat o‘rniga “yetarlicha yaxshi” xizmatga o‘tadi.

14. Kuzatuv

MetrikaNimani ko‘rsatadiChegara
Fan-out kechikishi (p99)Post qancha vaqtda tarqaladi10 soniyadan ko‘p
Navbat chuqurligiTarqatish orqada qolganmiDoimiy o‘sish
Tasma p99Foydalanuvchi tajribasi200 ms
Kesh urishi (tasma, post, graf)Bazaga yuk95% dan past
Bo‘sh tasma ulushiQayta qurish kerak bo‘lganlar0.1% dan ko‘p
Deduplikatsiya soniChegara muammosi bormiKeskin o‘sish
Reyting kechikishiModel xizmati holati50 ms
Qayta qurishlar soniKesh yo‘qotishlariHar qanday cho‘qqi
Nazorat savoli · javobni ko‘rishFoydalanuvchilar 'postim ko'rinmayapti' deb shikoyat qilyapti. Diagnostika tartibingiz?
  1. O‘z tasmasidami yoki boshqalarnikidami? O‘zida ko‘rinmasa — bu yozish yo‘li muammosi (post umuman saqlanmagan). Boshqalarda ko‘rinmasa — tarqatish muammosi
  2. Fan-out navbati kechikishi — p99 va navbat chuqurligi. Eng ko‘p uchraydigan sabab
  3. Akkaunt chegaradan o‘tganmi? — u pull rejimiga o‘tgan bo‘lsa, postlari faqat o‘qishda qo‘shiladi va agar aralashtirish mantiqida xato bo‘lsa, umuman tushmaydi
  4. Filtrlar — post moderatsiya, spam yoki “sezgir kontent” filtriga tushganmi
  5. Obunachi tasmasi to‘lib ketganmi — 800 ta chegara: agar obunachi juda ko‘p faol odamga obuna bo‘lsa, post bir necha daqiqada ro‘yxatdan chiqib ketishi mumkin

Oxirgisi ayniqsa nozik: bu xato emas, dizayn. Lekin foydalanuvchi uchun u xatoga o‘xshaydi — shuning uchun reyting va “sizga qiziq bo‘lishi mumkin” mexanizmlari paydo bo‘lgan.

15. Antinaqshlar

QarorNima yutamizNimani yo'qotamiz
Tasmani JOIN bilan qurishKod sodda, izchillik kuchliSekundiga milliardlab qator; shardlangandan keyin umuman ishlamaydi
Hammaga fan-out on writeO'qish juda tezBitta mashhur post butun klasterni bloklaydi
Hammaga fan-out on readYozish arzon, ma'lumot yangiSekundiga 70 million so'rov — imkonsiz
Tasmada postlarni to'liq saqlashHidratsiya kerak emasXotira 40 barobar ko'p; tahrir va o'chirish tarqalmaydi
Post o'chirilganda tasmalardan olib tashlashToza ma'lumot100 million tasmani yangilash — imkonsiz. Tombstone kerak
tweets jadvalini author_id bo'yicha shardlashProfil so'rovi tezMashhur akkaunt sharti yonadi — hot shard
Avtoinkrement IDOddiyTaqsimlangan tizimda koordinatsiya; tartib va sahifalash buziladi
Fan-out'ni sinxron qilishPost darhol tarqaladiPost yozish 200 ms dan sekundlarga cho'ziladi
Tezlik cheklovini postlar soni bo'yicha qo'yishTushunarliKo'p obunachili akkaunt bir post bilan million yozuv yaratadi
Barcha foydalanuvchilarga tasma keshini saqlashHamma uchun tezFaol bo'lmaganlar xotiraning yarmini yeydi; ular baribir kirmaydi

16. Trade-off‘lar

QarorNima yutamizNimani yo'qotamiz
Push (fan-out on write)O'qish O(1), tasma darhol tayyorYozish yuki katta, xotira ko'p, mashhurlar muammosi
Pull (fan-out on read)Yozish arzon, xotira kam, ma'lumot yangiHar o'qishda yuzlab so'rov — masshtablanmaydi
GibridIkkalasining kuchli tomoniIkki kod yo'li, chegara boshqaruvi, deduplikatsiya
Tasma uzunligi 800Bir necha kunlik tarix, chuqur varaqlash mumkin1.6 TB xotira
ID lar ro'yxati (kontent emas)40 barobar kam xotira, tahrir tarqaladiHar o'qishda hidratsiya kerak
Xronologik tartibBashoratli, arzon, tushunarliKo'p obunali foydalanuvchi ko'p narsani ko'rmaydi
Reytingli tasmaFoydalanuvchi vaqti ortadiSekundiga 100M baholash; 'nega ko'rmadim' shikoyatlari
Tombstone (o'chirishda filtrlash)O'chirish O(1)Tasmalarda o'lik ID lar; ortiqcha nomzod olish kerak
Faol bo'lmaganlarga tasma saqlamaslikXotira 2-3 barobar tejaladiUlar qaytganda tasma qayta quriladi — sekin birinchi yuklanish

Butun dars o‘nta gapda

  1. Tasma — “ishni qachon bajarish” masalasi: o‘qishda (pull) yoki yozishda (push); o‘qish yozishdan 65–100 barobar ko‘p bo‘lgani uchun asosiy yo‘l — push (1.3, 5).
  2. JOIN bilan tasma shardlashdan keyin umuman ishlamaydi: postlar va obunalar turli kalitlar bo‘yicha turli mashinalarda yotadi (4).
  3. Tasma keshi — ID lar ro‘yxati, postning o‘zi emas: 8 bayt, 800 ta chegara, faqat faol foydalanuvchilar uchun (6-bo‘lim 1-qadam).
  4. Mashhur akkaunt sof push’ni buzadi: bitta post — 100 mln yozuv va butun navbatning kechikishi (5.3, 7.2).
  5. Gibrid — dum uchun: amallar soni bo‘yicha push arzonroq bo‘lishi mumkin, lekin pull eng katta fan-out’ni va cho‘qqini cheklaydi (5.4, 7.3).
  6. O‘qishda birlashtirish — k-way merge: tayyor tasma + mashhurlar ro‘yxatlari, faqat kerakli N tasini olish, keyin deduplikatsiya va filtr (5.4 Deep, 2-daraja amaliyot).
  7. O‘chirish, bloklash, yashirish — o‘qishda filtr: millionlab tasmani qayta yozish o‘rniga tombstone va ortiqcha nomzod (6-bo‘lim 5-qadam, 10.5).
  8. Snowflake — vaqt bo‘yicha tartiblangan, koordinatsiyasiz ID: kursor bilan sahifalash va shardlash shundan oson (6-bo‘lim 7-qadam).
  9. Tasma — hosila ma’lumot: uni manbadan qayta qurish mumkin, va bu butun tizimning xavfsizlik to‘ri (10.1).
  10. “Sizga tavsiya” — ko‘p bosqichli voronka: ~1 500 nomzod, og‘ir model va evristikalar; push/pull tasma endi nomzodlar manbalaridan biri (8).

17. Intervyu savollari

17.1 Asoslar

▸Gibrid fan-out'da chegarani qanday tanlaysiz?

Ikki narx muvozanatda bo‘lishi kerak:

  • Yozish narxi va dum — chegara yuqori bo‘lsa, katta akkauntlar push qiladi: bitta postning fan-out’i katta, navbatda cho‘qqi va kechikish
  • O‘qish narxi — chegara past bo‘lsa, ko‘p akkaunt pull rejimiga o‘tadi: har tasma o‘qishida ko‘proq qo‘shimcha so‘rov

Amaliyotdagi simulyatsiya buni raqamda ko‘rsatadi. Sof pull sof push’dan 6.4 barobar ko‘p amal qiladi. Chegara 3 000 bo‘lsa, eng katta fan-out ikki barobardan ko‘p qisqaradi, jami narx esa sof pull’dan 3.8 barobar kam. Real tizimda chegara yuqori qo‘yiladi: akkauntlarning ~0.01–0.1% i pull qilinadi. Faol bo‘lmagan obunachilar ko‘p bo‘lgani uchun gibrid narx jihatidan ham yutadi.

Ikki muhim detal: chegara dinamik (cho‘qqida pasaytiriladi — degradatsiya tutqichi) va gisterezisli (chegara atrofidagi akkaunt rejimlar orasida tebranmasin).

▸'Sizga tavsiya' tasmasi qanday tuzilgan? Xronologik tasmadan farqi nima?

Uch bosqichli voronka (Twitter 2023-yilda kodini ochgan):

  1. Nomzodlar — ~1 500 ta: taxminan yarmi obunalardan (push/pull tasma va obunalar bilan aloqa kuchi modeli), yarmi obunadan tashqaridan (o‘xshash foydalanuvchilar jamoalari, siz kuzatganlar yoqtirganlar, embedding’lar)
  2. Reyting — ~48 mln parametrli neyron tarmoq har nomzod uchun yoqtirish, javob, repost va salbiy reaksiya ehtimolini bashorat qiladi; ball — og‘irlikli yig‘indi
  3. Evristika — muallif xilma-xilligi, bloklar, takrorlar, obunalar muvozanati

Xronologik tasma — LRANGE va hidratsiya, deyarli faqat xotira o‘qish. Tavsiya esa kuniga ~5 mlrd marta ishlaydi: sekundiga ~87 mln baholash, bu o‘nlab-yuzlab GPU degani. Arxitektura nuqtai nazaridan tasmaning yarmi yana o‘qish paytida yig‘iladigan bo‘ldi. Faqat endi bu JOIN emas, ko‘p bosqichli voronka.

▸Twitter tasmasini loyihalang. Birinchi savolingiz nima bo'ladi?

Birinchi savol — o‘qish va yozish nisbati. Bu son butun arxitekturani belgilaydi.

Javob taxminan 100:1 (sekundiga 3500 post, 350 000 tasma yuklanishi). Bundan darhol kelib chiqadi: ishni yozish paytiga ko‘chirish kerak, chunki yozish 100 barobar kam uchraydi.

Keyingi savollar: obunachilar taqsimoti qanday (mashhur akkauntlar bormi), tasma xronologikmi yoki reytinglimi, izchillik talabi qanday (necha soniya kechikish maqbul). Bu to‘rt javob bilan yechim deyarli aniqlanadi.

▸Nega oddiy JOIN so'rovi ishlamaydi? Raqam bilan.

O‘rtacha foydalanuvchi 200 kishiga obuna, ularning har biri so‘nggi kunlarda ~100 post yozgan. Bitta tasma so‘rovi uchun baza ~20 000 nomzod qatorni ko‘rib, tartiblab, 50 tasini qaytarishi kerak.

Sekundiga 347 000 tasma × 20 000 qator = 6.9 milliard qator/soniya. Yaxshi sozlangan baza tuguni 1–10 million qator/soniya uddalaydi — ya’ni mingdan ortiq tugun faqat o‘qish uchun.

Bundan tashqari, shardlangandan keyin tweets va follows turli mashinalarda bo‘ladi va JOIN printsipial jihatdan bajarilmaydi.

▸Fan-out on write va on read farqini tushuntiring. Qaysi birini tanlaysiz?

Push (on write): post yozilganda har bir obunachining tayyor tasmasiga ID qo‘shiladi. O‘qish bitta LRANGE — O(1). Yozish yuki: 3500 × 200 = 700 000 yozuv/s.

Pull (on read): hech narsa oldindan tayyorlanmaydi, tasma o‘qilganda obunalar bo‘yicha yig‘iladi. Yozish arzon, lekin o‘qish 347 000 × 200 = 70 million so‘rov/s — bu imkonsiz.

Tanlov: gibrid. Oddiy akkauntlar push, mashhurlar (chegaradan yuqori) pull. Sababi keyingi savolda.

▸100 million obunachili akkaunt post yozsa nima bo'ladi?

Sof push rejimida bu 100 million tasma yozuvi. Klaster sig‘imi 2 million yozuv/s bo‘lsa, bitta post butun klasterni 50 soniyaga band qiladi. Amalda fan-out uchun sig‘imning ~10% i ajratilgani uchun bu 8 daqiqadan ortiq, va shu paytda qolgan hamma postlar navbatda kutadi.

Bundan ham yomoni: 1000 ta yirik akkaunt kuniga 5 tadan post yozsa, ular 1.16 million yozuv/s yaratadi — qolgan 500 million foydalanuvchidan ko‘proq.

Yechim: bunday akkauntlarga fan-out qilinmaydi. Ularning postlari o‘qish paytida qo‘shiladi: tasma = tayyor ro‘yxat + mashhurlarning oxirgi postlari, birlashtirilib tartiblanadi. O‘qish narxi 6 ta so‘rovga oshadi — bu arzon.

17.2 Ma’lumot va saqlash

▸Tasma keshida nimani saqlaysiz — postlarnimi yoki ID larnimi?

Faqat ID larni. Uchta sabab:

  1. Xotira: ID 8 bayt, post ~300 bayt. 200M foydalanuvchi × 800 element uchun farq 1.6 TB va 64 TB orasida
  2. Yangilanish: post tahrirlansa yoki o‘chirilsa, uni millionlab tasmadan qidirish shart emas — hidratsiya paytida yangi holat olinadi
  3. Filtrlar: bloklash, yashirish, moderatsiya — bularning hammasi o‘qish paytida qo‘llanadi, ya’ni tasmada saqlangan nusxa baribir eskirgan bo‘lardi

Narxi: har bir tasma o‘qishida qo‘shimcha MGET kerak — ~25 ms. Bu arzon.

▸Post o'chirilganda uni 100 million tasmadan qanday olib tashlaysiz?

Olib tashlamaysiz. Bu fan-out bilan bir xil imkonsiz masala.

O‘rniga: postga deleted = true belgisi qo‘yiladi (tombstone) va tasmalarda ID qolib ketaveradi. Hidratsiya paytida post topilmasa yoki o‘chirilgan bo‘lsa, u ro‘yxatdan tashlanadi.

Amaliy natija: foydalanuvchiga 50 ta post kerak bo‘lsa, tasmadan 70–80 ta ID olinadi, filtrdan keyin 50 tasi qaytariladi. Bir xil mexanizm bloklangan foydalanuvchilar va moderatsiya filtrlari uchun ham ishlaydi.

Bu — umumiy naqsh: qimmat yozish operatsiyasini arzon o‘qish operatsiyasiga almashtirish.

▸Tweet ID sifatida avtoinkrement ishlatsak bo'ladimi?

Yo‘q, uch sababga ko‘ra:

  1. Koordinatsiya — taqsimlangan tizimda avtoinkrement markaziy nuqta talab qiladi, u esa tor joy va nosozlik nuqtasi
  2. Tartib — tasma ORDER BY id DESC ga tayanadi. ID vaqt bilan bog‘liq bo‘lmasa, tartiblash uchun created_at kerak, u esa taqsimlangan tizimda ishonchsiz (soatlar farq qiladi, bir xil millisekundda tartib noaniq)
  3. Sahifalash — barqaror kursorli sahifalash uchun ID monoton o‘suvchi bo‘lishi kerak

Yechim — Snowflake: 41 bit millisekund + 10 bit mashina + 12 bit ketma-ketlik. Koordinatsiyasiz, vaqt bo‘yicha tartiblanadi, mashinaga 4096 ID/ms beradi.

▸tweets jadvalini qaysi kalit bo'yicha shardlaysiz?

Tweet ID bo‘yicha (Snowflake). Sababi: yozish vaqt bo‘yicha tekis tarqaladi va ID bo‘yicha o‘qish to‘g‘ridan-to‘g‘ri kerakli shardga boradi.

author_id bo‘yicha shardlash jozibali ko‘rinadi (“bir odamning postlari birga”), lekin u mashhur akkaunt shardini yondiradi: bitta shard butun trafikning katta qismini oladi.

Buning narxi: “falonchining barcha postlari” so‘rovi barcha shardlarga boradi. Shuning uchun profil uchun alohida indeks yuritiladi — user_tweets:<author>, ID lar ro‘yxati, tasma keshiga o‘xshash.

17.3 Kelishuvlar

▸Chegara (kim mashhur hisoblanadi) qanday tanlanadi?

Bu optimallashtirish masalasi: chegara oshgani sari yozish narxi o‘sadi (ko‘proq akkaunt push qiladi), o‘qish narxi kamayadi (kamroq akkaunt pull rejimida). Ikkalasining yig‘indisi minimal bo‘ladigan nuqta izlanadi.

Amalda 10 000 – 1 000 000 oralig‘ida bo‘ladi va u formuladan emas, o‘lchovdan topiladi — obunachilar taqsimoti har bir tizimda boshqacha.

Ikki nozik jihat: chegara konfiguratsiyadan o‘qilishi kerak (yuk oshganda uni pasaytirish — degradatsiya tutqichi), va gisterezis bo‘lishi kerak, aks holda chegara atrofidagi akkaunt ikki rejim orasida tebranadi.

▸Xronologik tasma va reytingli tasma: qaysi biri va nega?

Texnik jihatdan xronologik ancha arzon: nomzodlarni tartiblash mikrosoniyalar oladi. Reyting esa sekundiga ~100 million baholashni talab qiladi — bu yuzlab yadro va xarajatning katta qismi.

Mahsulot jihatdan reyting yutadi: 500 kishiga obuna bo‘lgan odam kuniga 200 ta post o‘qiy oladi, ya’ni u baribir hammasini ko‘rmaydi. Savol — qaysi 200 tasi: tasodifiy (eng yangilari) yoki tanlangan.

Amaliy javob: ikkalasi ham bo‘lsin. Reyting standart, xronologik esa alohida rejim sifatida. Va yuk oshganda reytingni o‘chirish — degradatsiyaning birinchi qadami.

▸Foydalanuvchi post yozdi, lekin o'z tasmasida ko'rmayapti. Bu xatomi?

Fan-out asinxron bo‘lgani uchun bir necha soniya kechikish normal. Lekin o‘z posti uchun bu qabul qilinmaydi: foydalanuvchi “ishlamadi” deb o‘ylab qayta yozadi.

Shuning uchun o‘z posti darhol, tarqatishni kutmasdan, o‘z tasmasiga qo‘shiladi (yoki mijoz tomonda optimistik ko‘rsatiladi). Boshqalarga esa odatdagi yo‘l bilan yetadi.

Bu — “read your own writes” kafolatining eng sodda ko‘rinishi va u deyarli har bir ijtimoiy mahsulotda alohida ishlangan bo‘ladi.

▸Tasma keshi tuguni tushdi. Foydalanuvchilar nima ko'radi?

O‘sha tugundagi tasmalar yo‘qoladi. Lekin tasma — hosila ma’lumot, uni manbadan qayta qurish mumkin:

obunalar ro'yxati -> har birining oxirgi postlari -> birlashtirish -> kesh

Bitta tasmani qayta qurish ~200 so‘rov va bir necha yuz millisekund. Muammo shundaki, millionlab tasmani birdan qayta qurib bo‘lmaydi — bu bazani yiqitadi.

Shuning uchun tiklash navbat orqali va tezlik cheklovi bilan bajariladi: eng faol foydalanuvchilardan boshlanadi, qolganlari kirganda talab bo‘yicha quriladi. Foydalanuvchi uchun bu birinchi yuklanishning sekinlashuvi bo‘lib ko‘rinadi.

17.4 Amaliy stsenariylar

▸Fan-out navbati orqada qoldi va postlar 30 daqiqada tarqalyapti. Nima qilasiz?

Avval sabab: yozish cho‘qqisimi, ishchilar tushganmi, yoki bitta yirik akkaunt navbatni bo‘g‘ganmi (eng ko‘p uchraydigani).

Choralar tartibi:

  1. Yirik ishlarni alohida navbatga ajratish — head-of-line blocking yo‘qoladi
  2. Chegarani pasaytirish — yangi postlar uchun yozish yuki darhol kamayadi
  3. Ishchilarni ko‘paytirish — agar tor joy Redis emas, ishchi bo‘lsa
  4. Prioritet — faol foydalanuvchilarga birinchi tarqatish

Qilmaslik kerak: navbatni tozalash (postlar yo‘qoladi) yoki fan-out ni sinxron qilish (yozish sekinlashadi, yuk yanada oshadi).

▸Viral post: bitta postga sekundiga 500 000 murojaat. Tizim qanday ushlaydi?

Bu hot key muammosi (Redis va URL qisqartiruvchi darslaridagi bilan bir xil), faqat post keshida.

Qatlamlar:

  1. Chekka/CDN — post kontenti o‘zgarmas, uni chekkada keshlash mumkin
  2. Ilova serverida mahalliy kesh (L1, TTL 5–10 soniya) — 100 server bo‘lsa, markaziy keshga yuk 500 000 dan 10–20 ga tushadi
  3. Post keshini replikatsiya qilish — issiq kalitlar bir necha tugunda

Statistika (yoqtirishlar soni) esa alohida masala: uni har murojaatda aniq o‘qish shart emas — taxminiy son va bir necha soniyalik kechikish maqbul.

▸Foydalanuvchi 5000 kishiga obuna. Uning tasmasi qanday ishlaydi?

Push rejimida uning tasmasi juda tez to‘ladi: 5000 obunadan har biri kuniga bir necha post yozsa, 800 ta chegara bir necha soatda to‘lib ketadi. Ya’ni u kuniga bir marta kirsa, oldingi kunning postlarini umuman ko‘rmaydi.

Bu xato emas — dizayn cheklovi. Yechimlar: tasma uzunligini bunday foydalanuvchilar uchun oshirish (qimmat), reyting bilan eng muhimlarini yuqoriga chiqarish (amaldagi yechim), yoki “ro‘yxatlar” (lists) mexanizmi — foydalanuvchi obunalarini guruhlarga bo‘ladi va har biri alohida tasma sifatida ko‘rinadi.

Uchinchisi eng to‘g‘ri, lekin mahsulot murakkabligini oshiradi.

▸Bu tizimda qaysi ma'lumot kuchli izchil bo'lishi kerak?

Deyarli hech qaysi. Ro‘yxat qisqa:

  • Postning o‘zi — yozilgach, u yo‘qolmasligi kerak (bazaga durable yoziladi)
  • Obuna/obunani bekor qilish — foydalanuvchi bloklaganini yoki obunani bekor qilganini darhol ko‘rishi kerak
  • O‘chirish — o‘chirilgan post qayta paydo bo‘lmasligi kerak

Qolgani oxir-oqibat izchil: tarqatish (soniyalar), yoqtirishlar soni (taxminiy), obunachilar soni (keshlangan), qidiruv indeksi (soniyalar).

Bu ongli tanlov: kuchli izchillik bu masshtabda mavjudlik va kechikishni qurbon qilishni talab qiladi, foydasi esa deyarli yo‘q — hech kim tasmaning bir soniya eskirganini sezmaydi.

▸Bu darsdagi qaysi g'oyalar boshqa tizimlarda ham uchraydi?

Deyarli hammasi:

  • Ishni yozishga yoki o‘qishga ko‘chirish — har qanday kesh qarorining mohiyati
  • Hot key — URL qisqartiruvchida viral havola, Redisda issiq kalit, bu yerda mashhur akkaunt
  • Hosila ma’lumotni qayta qurish — tasma keshi ham, qidiruv indeksi ham manbadan tiklanadi
  • Tombstone va o‘qishda filtrlash — qimmat yozishni arzon o‘qishga almashtirish
  • Ikki bosqichli saralash — arzon filtr keyin qimmat model (ChatGPT darsidagi RAG reranker bilan bir xil)
  • Degradatsiya tartibi — nimadan birinchi voz kechish oldindan hal qilinadi

Shuning uchun bitta tizimni chuqur o‘rganish keyingi o‘nlab tizimni tushunishni osonlashtiradi.

▸Obunalar grafini qanday saqlaysiz? U qanchalik katta?

Ikki tomonlama: following:<user> (kimga obunaman) va followers:<user> (menga kim obuna). Ikkalasi ham kerak, chunki savollar turli yo‘nalishda beriladi: tasma o‘qishda birinchisi, fan-out da ikkinchisi.

Hajmi: 500M foydalanuvchi × 200 obuna = 100 milliard qirra, ikki marta saqlanadi = 200 milliard yozuv × ~16 bayt = 3.2 TB. Bu tasma keshidan ikki barobar katta.

Nozik joy: bu ikki ro‘yxat turli shardlarda yotadi, ya’ni obuna bo‘lish taqsimlangan yozuv va u atomik emas. Yechim: hodisalar navbati orqali yangilash + davriy tekshiruv bilan farqni tuzatish. Obunachilar soni esa alohida hisoblagichda denormallashtiriladi — SCARD 100 million elementli to‘plamda juda qimmat.

▸Tasmani sahifalashda qanday xato ko'p qilinadi?

OFFSET ishlatish. Foydalanuvchi ikkinchi sahifani so‘raguncha ro‘yxat boshiga yangi postlar qo‘shiladi va pozitsiyalar siljiydi — natijada u ba’zi postlarni ikki marta ko‘radi, ba’zilarini umuman ko‘rmaydi.

To‘g‘ri yechim — kursor: oxirgi ko‘rilgan post ID sidan kichiklarini so‘rash. Snowflake ID vaqt bo‘yicha tartiblangani uchun bu barqaror nuqta beradi: ro‘yxat boshiga nima qo‘shilsa ham, “shu postdan keyingilari” o‘zgarmaydi.

Bu 2-darsdagi kursorli sahifalash bilan bir xil tamoyil, faqat u yerda bazada, bu yerda esa keshda.

▸Repost qanday ishlaydi? U ham fan-out qilinadimi?

Ha, repost — bu oddiy post, faqat o‘z matni yo‘q, u boshqasiga ishora qiladi. Repost qiluvchining obunachilariga odatdagi yo‘l bilan tarqatiladi.

Hidratsiya paytida repost ochilib, ichidan asl postning kontenti olinadi. Uchta nozik holat: zanjir tekislanadi (repostning reposti ham asl postga ishora qiladi), asl post o‘chirilsa repost ham ko‘rinmaydi, va deduplikatsiya asl post ID si bo‘yicha ham qilinadi — aks holda foydalanuvchi bir postni bir necha odamdan ko‘radi.

Iqtibos (quote) boshqacha: u mustaqil post va hidratsiya ikkita postni oladi.

▸Bloklash va yashirish qayerda qo'llanadi — yozishdami yoki o'qishda?

O‘qishda, hidratsiya bosqichida. Sabab: bloklash o‘zgarganda millionlab tasmani qayta yozib bo‘lmaydi — bu o‘chirish muammosi bilan bir xil.

Narxi: filtrlangandan keyin 50 ta post qolishi uchun 75–80 ta ID olinishi kerak (o‘chirilgan ~3%, bloklangan ~8%, moderatsiya ~2%, takroriy ~10%).

Muhim ogohlantirish: tasmadagi filtr kirish nazorati emas. Bloklangan odam postga to‘g‘ridan-to‘g‘ri havola bilan kira olsa — bu xavfsizlik xatosi. Kirish nazorati kontent qaytariladigan har bir yo‘lda (profil, qidiruv, havola) bo‘lishi kerak.

▸Bildirishnomalar tasmadan nimasi bilan farq qiladi?

Yo‘nalishi teskari: tasma — bitta post ko‘p odamga (fan-out), bildirishnoma — ko‘p reaksiya bitta odamga (fan-in).

Muammosi ham teskari: viral post 1 million yoqtirish olsa, bu bitta foydalanuvchining ro‘yxatiga 1 million yozuv demak — hot key va o‘qib bo‘lmas ro‘yxat.

Yechim — agregatsiya: bir necha daqiqalik oynada bir xil turdagi reaksiyalar bitta yozuvga birlashtiriladi (“1 000 000 kishi yoqtirdi”). Javoblar esa alohida qoladi, chunki ular mazmunli.

▸Tasma xronologik bo'lmasa, foydalanuvchi 'postimni hech kim ko'rmadi' deydi. Bu haqiqatmi?

Qisman haqiqat va bu mahsulot qarorining oqibati.

Xronologik tasmada ham hamma postni ko‘rmaydi: 500 kishiga obuna bo‘lgan odam kuniga 1000+ post oladi, lekin 200 tasini o‘qiydi. Farqi shundaki, xronologikda qaysi 200 tasi ekanini vaqt hal qiladi (kirgan payting nima yangi bo‘lsa), reytingda esa model.

Ya’ni savol “ko‘rsatiladimi yoki yo‘q” emas, “tanlovni kim qiladi”. Reyting kichik akkauntlarga ham imkon beradi (yaxshi post yuqoriga chiqadi), lekin bashoratsizlik qo‘shadi.

Amaliy javob: ikkala rejimni ham berish va foydalanuvchiga tanlatish — ko‘p tizimlar shunga keldi.

▸Bu tizimda eng qimmat komponent qaysi va nega?

O‘qish yo‘li, va uning ichida reyting. Sekundiga 347 000 tasma so‘rovi, har birida ~300 nomzod baholanadi = 100 million baholash/soniya. Bu yuzlab, ba’zan minglab yadro demak.

Ikkinchi o‘rinda — tasma keshi (1.6 TB RAM). Fan-out esa nisbatan arzon: 700 000 yozuv/soniya bir necha o‘nlab Redis tuguni bilan hal bo‘ladi.

Shuning uchun optimallashtirish tartibi: (1) reyting nomzodlarini kamaytirish, (2) arzon filtrni yaxshilash, (3) faol bo‘lmaganlarga tasma saqlamaslik, (4) tasma uzunligini qisqartirish. Fan-out ni optimallashtirish oxirgi o‘rinda — u eng ko‘rinarli, lekin eng arzon qism.

18. Amaliyot

To‘rt daraja. Ikkinchi daraja uchun kod va avtomatik tekshiruvlar docs/amaliyot/twitter/ da: snowflake.py, timeline.py — TODO; model.py — tayyor soxta soat va darajali obunalar grafi; check.py — 13 ta tekshiruv.

Amaliyot

1-daraja: fan-out kalkulyatori

Skript yozing: kirish sifatida foydalanuvchilar soni, kunlik postlar, obunachilarning taqsimoti (o‘rtacha va mashhurlar ulushi), tasma uzunligi oladi.

Chiqishda: push rejimidagi yozuvlar/soniya, pull rejimidagi so‘rovlar/soniya, tasma keshining hajmi, va gibrid yechim uchun har bir chegara qiymatidagi umumiy narx.

Tekshiruv mezoni: chegara (10³ dan 10⁷ gacha) va umumiy narx grafigini chizing. Minimal nuqta qayerda? U darsdagi 10 000 – 1 000 000 oralig‘iga tushdimi?

Amaliyot

2-daraja: Snowflake va gibrid tasma (tayyor tekshiruvlar bilan)

Kod docs/amaliyot/twitter/ da. Ikkita faylni to‘ldirasiz, check.py esa ularni 13 ta tekshiruvda sinaydi (~12 soniya, faqat Python standart kutubxonasi):

  1. snowflake.py — next_id: vaqt, mashina va ketma-ketlik bitlari, millisekund to‘lganda kutish, soat orqaga ketganda xato; parse
  2. timeline.py — gibrid tasma xizmati: post (push yoki mashhurlar uchun pull ro‘yxati), _visible (obuna vaqti, tombstone, bloklash, bekor qilingan obuna), read (uyum bilan k-way merge, filtrdan keyin limit, kursor)

Tekshiruv mezoni: python check.py oxirida Jami: 13/13 OK. Keyin part_cost dagi chegaralar va o‘qish/yozish nisbatini o‘zgartirib, 7.3 dagi jadvalni o‘zingiz takrorlang. O‘qishlar soni 100 barobar bo‘lsa, eng arzon chegara qayerga siljiydi?

▸Chuqurroq: check.py qanday tekshiradi: JOIN — eng yaxshi test oracle

Gibrid tasmani tekshirishning qiyin joyi — to‘g‘ri javobni bilish. Bu yerda v0 (3-bo‘lim) yordamga keladi: sekin, lekin aniq JOIN. check.py dagi Naive klass har o‘qishda barcha postlarni ko‘rib chiqadi va qoidalarni so‘zma-so‘z qo‘llaydi: muallif o‘zi yoki hozir obuna bo‘lgan, post obunadan keyin yozilgan, o‘chirilmagan, muallif bloklanmagan.

  • Fuzz: 50 ta tasodifiy ketma-ketlikda (obuna, bekor qilish, qayta obuna, bloklash, post, o‘chirish) chegara 1 dan cheksizgacha o‘zgaradi. Har o‘qish natijasi JOIN natijasi bilan aynan bir xil bo‘lishi kerak. Ya’ni push, pull va ularning aralashmasi foydalanuvchiga sezilmasligi shart.
  • Sahifalash: barcha sahifalar ketma-ket o‘qiladi va ularning birlashmasi to‘liq tasmaga teng bo‘lishi kerak — takrorsiz va bo‘shliqsiz.
  • Murakkablik: 300 ta mashhur obunali foydalanuvchida har o‘qish faqat 20 ta postni olishi kerak. Hammasini yig‘ib saralash (600 000 element) vaqt chegarasidan oshadi.

Bu — katta tizimlarni tekshirishning umumiy usuli: optimallashtirilgan yo‘lni sodda va aniq yo‘l bilan solishtirish (shadow testing).

Amaliyot

3-daraja: Redis bilan ishlaydigan tasma va nosozliklar

2-darajadagi mantiqni haqiqiy Redis ustiga ko‘chiring:

  1. POST /tweet — Snowflake, saqlash, fan-out navbati. Fan-out ishchisi — 1000 tadan bo‘lak, pipelining bilan LPUSH + LTRIM 0 799
  2. GET /timeline — LRANGE + mashhurlar ro‘yxatlari + birlashtirish + MGET hidratsiya + filtrlar
  3. Tasmani qayta qurish funksiyasi (manbadan). Redis’dan tasodifiy 20% tasmani o‘chirib, tiklanishni o‘lchang
  4. Degradatsiya: navbat chuqurligi chegaradan oshsa, fan-out chegarasini avtomatik pasaytiring

Tekshiruv mezoni: 10 000 foydalanuvchi, 100 000 obuna, 1000 post bilan yuk testi: tasma p50/p99, fan-out kechikishi, xotira. Bitta grafikda ko‘rsating: nosozlik boshlangan lahza, degradatsiya yoqilgan lahza va tizim normal holatga qaytgan lahza.

Amaliyot

4-daraja: reyting va uning narxi

Tasmaga oddiy reyting qo‘shing:

  1. Xususiyatlar: post yoshi, muallif bilan aloqa chastotasi, erta reaksiyalar soni
  2. Oddiy chiziqli model yoki qo‘lda yozilgan formula
  3. Ikki bosqich: arzon filtr (300 → 100), keyin to‘liq baholash

Tekshiruv mezoni: xronologik va reytingli tasma uchun p99 kechikishni va CPU sarfini solishtiring. Reyting necha barobar qimmat? Bir foydalanuvchi uchun ikkala tasmani yonma-yon chiqarib, farqni ko‘rsating.

19. Lug‘at

AtamaMa’nosi
Tasma (timeline)Obuna bo‘lganlar postlaridan tuzilgan ro‘yxat
Fan-outPostni obunachilarga tarqatish
Fan-out on write (push)Yozish paytida tarqatish
Fan-out on read (pull)O‘qish paytida yig‘ish
Gibrid fan-outOddiylar push, mashhurlar pull
Chegara (threshold)Akkauntni mashhur deb hisoblash chegarasi
GisterezisChegara atrofida tebranishni oldini oluvchi ikki tomonlama chegara
HidratsiyaID lardan to‘liq post ma’lumotini olish
TombstoneO‘chirilgan yozuvning belgisi; o‘qishda filtrlanadi
Snowflake IDVaqt + mashina + ketma-ketlikdan tuzilgan tartiblanadigan ID
TruncationTasmani sobit uzunlikda ushlab turish (LTRIM)
Hot key / hot shardNomutanosib ko‘p murojaat qilinadigan kalit yoki shard
Head-of-line blockingKatta ish navbatdagi kichiklarni to‘xtatib qo‘yishi
Qayta qurish (rebuild)Hosila ma’lumotni manbadan tiklash
Bo‘shliq (gap)Tarqatishda yo‘qolgan postlar
DeduplikatsiyaBirlashtirishda takroriy ID larni olib tashlash
Nomzodlar (candidates)Reytinggacha bo‘lgan postlar to‘plami
Darajali taqsimotObunachilar sonining notekis tarqalishi
Read your own writesFoydalanuvchi o‘z yozganini darhol ko‘rishi
k-way mergek ta tartiblangan ro‘yxatni uyum bilan birlashtirib, faqat kerakli qismini olish
Kursor“Shu ID dan kichiklar” ko‘rinishidagi barqaror sahifalash nuqtasi
Obunadan tashqari nomzodSiz obuna bo‘lmagan muallifning tavsiya qilingan posti
Og‘ir reyting (heavy ranker)Nomzodlarni baholovchi katta neyron tarmoq (~48 mln parametr)
Voronka (funnel)Arzon bosqichlar ko‘p, qimmatlari oz element bilan ishlaydigan quvur
Evristika qatlamiModel natijasini tuzatuvchi qoidalar: xilma-xillik, filtrlar
Shadow testingOptimallashtirilgan yo‘lni sodda va aniq yo‘l bilan solishtirish

20. Raqamlar manbasi

RaqamQiymatManba
2012-yilgi tizim150 mln faol foydalanuvchi; tasma o‘qish ~300 ming / s; 400 mln+ tweet / kun (~4 600 / s); tasmada ko‘pi bilan 800 yozuv (Redis); fan-out pipelining bilan ~4 000 manzildanRaffi Krikorian, “Timelines at Scale”, QCon SF 2012; High Scalability sharhi
“5 soniyada yetkazish” maqsadiTweet obunachilarga 5 soniya ichidaO‘sha ma’ruza va sharh
Snowflake2010; 41 bit vaqt, 10 bit mashina, 12 bit ketma-ketlik; epoch 2010-11-04Twitter Engineering, “Announcing Snowflake”
Ochiq algoritm2023-yil 31-mart; kuniga ~5 mlrd ishga tushish; ~1 500 nomzod; ~50% obunalardan; og‘ir reyting ~48 mln parametrTwitter Engineering blogi (2023); TechCrunch va boshqa sharhlar
2-daraja natijalari13/13; 20 mutatsiya; sof pull 6.4x qimmat; chegara 3 000 da eng katta fan-out 2 948 (sof push’da 6 448)docs/amaliyot/twitter/, referens implementatsiya

500 mln kunlik foydalanuvchi, kuniga 300 mln post, 60 marta ochish, 200 ta o‘rtacha obuna, kesh va graf hajmlari, server soni va narxlar, kechikish byudjeti — illyustratsiya uchun taxminiy raqamlar. Ular 2012-yilgi ochiq raqamlar tartibida tanlangan (1.4 dagi hisob). Twitter (hozir X) ichki tizimi o‘sha davrdan beri ko‘p o‘zgargan va har detali ochiq emas. Asosiy xulosalar — o‘qish ustunligi, ID lar keshi, gibrid fan-out, o‘qishdagi filtrlar va ko‘p bosqichli reyting — bu raqamlarning bir necha barobarlik xatosiga ham chidamli.

21. Manbalar

  • Raffi Krikorian (2012), “Timelines at Scale”, QCon San Francisco — slaydlar va video; High Scalability: “The Architecture Twitter Uses to Deal with 150M Active Users, 300K QPS…”
  • Twitter Engineering (2010), “Announcing Snowflake”
  • Twitter Engineering (2023), “Twitter’s Recommendation Algorithm” va the-algorithm ochiq repozitoriysi
  • Martin Kleppmann (2017), Designing Data-Intensive Applications, 1-bob — Twitter tasmasi fan-out kelishuvining klassik tahlili
  • Twitter Engineering, “Earlybird: Real-Time Search at Twitter” (ICDE 2012)
  • Instagram Engineering, “Sharding & IDs at Instagram”
  • Redis hujjatlari: LPUSH, LTRIM, LRANGE, ZADD, pipelining

Ushbu sahifa dizayni Twitter/X interfeysidan ilhomlangan o‘quv materiali. Loyiha Twitter/X bilan bog‘liq emas, rasmiy logotip va shriftlardan foydalanilmagan.