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.
| Savol | Javob shu darsda | Bo‘lim |
|---|---|---|
Nega oddiy JOIN bilan bo‘lmaydi? | v0 va uning hisobi | 3–4 |
| Fan-out on write yoki on read? | Ikki strategiyaning narxi | 5 |
| 100 million obunachili akkaunt tweet yozsa nima bo‘ladi? | Mashhur akkaunt muammosi | 5.3 |
| Tasma keshi qancha xotira yeydi? | Kesh byudjeti hisobi | 6-bo‘lim, 1-qadam |
| Tweet ID nega shunchaki avtoinkrement emas? | Snowflake | 6-bo‘lim, 7-qadam |
| Bitta post 5 soniyada qanday tarqaladi? | Bitta postning hayoti | 7 |
| “Sizga tavsiya” tasmasi qanday tuziladi? | 2023-yilgi ochiq algoritm | 8 |
| Tasma yangilanmay qolsa nima qilamiz? | Degradatsiya tartibi | 10.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
- Foydalanuvchi qisqa post (tweet) yozadi
- Foydalanuvchi boshqalarga obuna bo‘ladi (bir tomonlama — do‘stlik emas)
- Foydalanuvchi tasma ko‘radi: obuna bo‘lganlari yozgan postlar
- Post yoqtiriladi, repost qilinadi, javob yoziladi
- Qidiruv va xeshteglar
Bizni asosan 3-punkt qiziqtiradi. Qolgan hammasi shunga xizmat qiladi.
1.2 Nofunksional talablar
| Talab | Ko‘rsatkich | Nega |
|---|---|---|
| Tasma yuklanishi | p99 ≤ 200 ms | Foydalanuvchi 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 |
| Izchillik | Oxir-oqibat (eventual) | Bir necha soniya kechikish maqbul |
| Masshtab | 500M kunlik faol foydalanuvchi | Yirik ijtimoiy tarmoq tartibi |
1.3 Konvert orqasidagi hisob
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.
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.
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:
| Savol | Indeks | Kim 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:
- 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
- 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.
▸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:
- Hodisalar navbati — obuna hodisasi navbatga yoziladi va ikkala tomon shundan yangilanadi. Kechikish bor, lekin yo‘qotish yo‘q
- Davriy tekshiruv — fon jarayoni ikki ro‘yxatni solishtiradi va farqni tuzatadi
- Bitta manba haqiqat — masalan faqat
followingsaqlanadi,followersesa 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,))
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
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
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.
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.
Bundan ham yomoni — bu bitta post emas:
5.4 Gibrid yechim
Amaliy tizimlar ikkalasini birlashtiradi:
Chegaradan kam bo'lsa — push; ko'p bo'lsa — hech narsa qilinmaydi.
Foydalanuvchilarning 99.99% i shu yo'ldan o'tadi.
Tarqatish yo'q — o'qishda qo'shiladi.
Bu yerda qo'shimcha ish bor, lekin u kichik va bashoratli.
▸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.
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
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
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:
Muhandislik tafsilotlari:
- Idempotentlik — ishchi qayta urinsa, bir xil ID tasmaga ikki marta tushmasligi
kerak.
LPUSHdan oldin tekshirish poyga holatiga olib keladi; to‘g‘riroq yechim — o‘qishda dublikatlarni filtrlash yoki ID bo‘yichaZADD(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:
| Detal | Nima uchun |
|---|---|
| Pipelining (1000 tadan) | 2000 komanda bitta paketda — RTT 2000 marta emas, 1 marta |
| Checkpoint | Ishchi tushsa, 100 000 obunachining 60 000 tasiga yuborilgan bo‘lishi mumkin; qaytadan boshlash isrof |
| Bo‘lak hajmi | Katta 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'
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:
| Strategiya | Qanday ishlaydi | Kamchiligi |
|---|---|---|
| Majburiy obuna (onboarding) | Ro‘yxatdan o‘tishda 10 ta akkaunt tanlatiladi | Foydalanuvchi tashlab ketishi mumkin |
| Avtomatik obuna | Mashhur akkauntlarga avtomatik obuna | Tasma bir xil bo‘lib qoladi |
| Qiziqish bo‘yicha nomzodlar | Til, mintaqa, kontaktlar bo‘yicha tanlash | Ma’lumot yig‘ish kerak |
| Global “eng yaxshi” tasma | Obunasiz ham qiziqarli postlar | Fan-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
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
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:
- Zanjir — kimdir repostni repost qilsa, u har doim asl postga ishora qiladi (zanjir tekislanadi), aks holda hidratsiya rekursiv bo‘lib ketardi
- Asl post o‘chirilsa — repost ham ko‘rinmaydi (tombstone filtri asl postga qo‘llanadi)
- 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
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
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’lumot | Shard kaliti | Nega |
|---|---|---|
tweets | tweet ID (Snowflake) | Yozish vaqt bo‘yicha tekis tarqaladi; ID bo‘yicha o‘qish to‘g‘ridan-to‘g‘ri |
timeline:<user> | foydalanuvchi ID | Bitta tasma bitta tugunda — LRANGE bitta so‘rov |
follows | foydalanuvchi ID | Bir 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
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
▸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
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
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
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:
| Signal | Nimani ko‘rsatadi | Ehtiyot |
|---|---|---|
| Mazmunli reaksiya (javob, ulashish) | Post qiymatli bo‘ldi | Janjal ham reaksiya keltiradi |
| Qaytish chastotasi (ertasi kuni) | Uzoq muddatli qiymat | Sekin o‘lchanadi |
| “Qiziq emas” bosishlari | To‘g‘ridan-to‘g‘ri salbiy signal | Kam ishlatiladi |
| Tasmani tashlab ketish | Yomon tartib | Boshqa 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
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:
- 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
- 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
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
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
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
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
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’lumot | Replikatsiya | Nega |
|---|---|---|
| Postlar (kontent) | Hamma mintaqaga | O‘qish yo‘lida kerak, hajmi nisbatan kichik |
| Tasma keshi | Yo‘q | Har mintaqa o‘zi quradi — hosila ma’lumot |
| Obunalar grafi | Hamma mintaqaga | Fan-out va o‘qish uchun kerak |
| Media | CDN orqali | Origin bitta, chekkada keshlanadi |
| Yoqtirishlar soni | Taxminiy, mahalliy | Aniq son kerak emas; davriy sinxronlash |
| Sessiyalar | Uy mintaqada | Yozish 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
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:
- Yirik ishlarni ajratish — mashhur akkauntlarning fan-out ishlari alohida navbatga o‘tkaziladi, shunda oddiy foydalanuvchilar navbatda kutmaydi
- Chegarani pasaytirish — masalan 100 000 dan 10 000 ga. Yangi postlar uchun yozish yuki darhol kamayadi
- Ishchilarni ko‘paytirish — agar tor joy Redis emas, ishchi bo‘lsa
- 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:
- Faol bo‘lmaganlarni chiqarish — 30 kunda kirmaganlarning tasmasi saqlanmaydi. Odatda eng katta yutuq (2–3 barobar), chunki faol foydalanuvchilar ulushi kichik
- 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)
- 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
- Kesh darajalari — eng faol 10% xotirada, qolgani SSD‘da (masalan Redis‘ning disk kengaytmalari yoki alohida qatlam)
- 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.
- ID — Snowflake (7-qadam): koordinatsiyasiz, vaqt bo‘yicha tartiblangan.
- Saqlash — post manba bazaga yoziladi. Shu paytdan u yo‘qolmaydi.
- O‘z tasmasi — muallif o‘z postini darhol ko‘radi (10.2 dagi yagona qat’iy talab). Bu tarqatishni kutmaydi.
- Navbat — tarqatish vazifasi navbatga tushadi. Muallif javobni oldi.
- Graf — “menga kim obuna?” ro‘yxati bo‘laklarda o‘qiladi.
- Tasmalar — har bo‘lakka bitta pipelined so‘rov:
LPUSH+LTRIM. - O‘qish — obunachi tasmani ochganda ID lar olinadi, hidratsiya va filtr qo‘llanadi, mashhurlarning postlari pull qilinib qo‘shiladi.
7.2 “5 soniya” byudjeti
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:
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:
- Faol bo‘lmagan obunachilar — mashhur akkauntning obunachilari orasida hozir tasmani o‘qimaydiganlar ko‘p. Ularga yozish — sof isrof (6-bo‘lim 1-qadam).
- Pull arzon o‘qish — mashhur akkauntning oxirgi postlari juda issiq
kalit, u keshda va bitta
MGETbilan olinadi. Bu tasmaga yozish bilan bir xil narx emas. - 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 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.
- 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.
- 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
▸Chuqurroq: Ochiq algoritmdan muhandis uchun uch saboq
- 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.
- 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.
- 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 sahifalab yuklanadi: birinchi 20 ta, keyin qo'shimchasi.
3 500 post/s -> 700 000 tasma yozuvi/s (mashhurlarsiz).
347 000 so'rov/s. Barcha qimmat ish shu yerda optimallashtiriladi.
9.1 Tasma so‘rovining kechikish byudjeti
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
}
| Qaror | Nima uchun shunday |
|---|---|
cursor, offset emas | Ro‘yxat o‘zgarganda barqaror sahifalash (6-bo‘lim, 1-qadam) |
limit maksimal 100 | Hidratsiya narxini cheklaydi; katta so‘rov klasterni bo‘g‘adi |
| To‘liq muallif obyekti | Mijozda qo‘shimcha so‘rov bo‘lmasin (N+1 muammosi) |
stats taxminiy | Yoqtirishlar soni aniq bo‘lishi shart emas — keshdan |
has_more alohida | Bo‘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:
| Mijoz | Ehtiyoj | Ta’siri |
|---|---|---|
| Mobil ilova | Kam trafik, offline kesh | Javob ixcham, If-None-Match qo‘llab-quvvatlansin |
| Veb | Tez birinchi ko‘rinish | Birinchi 5 ta post server tomonda render qilinadi |
| Uchinchi tomon API | Ommaviy o‘qish | Qattiq 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
| Nosozlik | Belgisi | Sabab | Chora |
|---|---|---|---|
| Fan-out orqada qoldi | Postlar 10+ daqiqada ko‘rinadi | Cho‘qqi yoki yirik akkaunt | Chegarani pasaytirish, navbatni ajratish |
| Tasma keshi tuguni tushdi | Ba’zi foydalanuvchilarda tasma bo‘sh | Apparat, OOM | Bazadan qayta qurish; replika |
| Hot shard | Bitta tugun 100% CPU | Mashhur akkaunt yoki viral post | Post keshini replikatsiya qilish |
| Hidratsiya sekinlashdi | p99 oshdi, tasma kelmaydi | Post keshi promahi | Kesh isitish, qisman javob |
| Dublikat postlar | Bir post ikki marta ko‘rinadi | Chegara kesib o‘tildi yoki retry | O‘qishda deduplikatsiya |
| Bo‘shliq (gap) | Postlar tushib qolgan | Navbatda yo‘qotish | Davriy tekshirish va qayta qurish |
| Reyting modeli tushdi | Tasma g‘alati tartibda | Model xizmati nosozligi | Xronologik 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:
| Hodisa | Kutilgan kechikish | Nima bo‘lsa yomon emas |
|---|---|---|
| Post yozildi → obunachilarda ko‘rindi | 1–10 soniya | Bir necha soniya kechikish sezilmaydi |
| Obuna bo‘ldi → tasmada ko‘rindi | Keyingi postdan | Eski postlar kerak emas |
| Post o‘chirildi → tasmadan yo‘qoldi | Keyingi hidratsiyada | Bir marta ko‘rinib qolishi mumkin |
| Yoqtirishlar soni | 10–60 soniya | Taxminiy 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
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.
▸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:
| Usul | Qanday | Kamchilik |
|---|---|---|
reply_to ko‘rsatkichi | Har javob otasiga ishora qiladi | Butun daraxtni olish uchun rekursiv so‘rov |
| Materiallashtirilgan yo‘l | path = "123/456/789" | Yo‘l uzunligi cheklangan; ko‘chirish qiyin |
| Ildiz ID si + tartib | Har javob root_id ni saqlaydi | Bitta 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?
- Bloklangan odamga tarqatmaslik
- O'qish tez — filtr kerak emas
- Bloklash o'zgarsa, ESKI tasmalar tuzatilmaydi
- Fan-out har bir obunachi uchun tekshiruv qiladi — sekin
- 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.
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:
| Tahdid | Mexanizmi | Chora |
|---|---|---|
| Spam va bot | Ommaviy akkaunt yaratish, avtomatik post | Yozishga tezlik cheklovi, xatti-harakat tahlili |
| Sun’iy tarqatish | Sotib olingan repostlar, koordinatsiyalangan guruh | Graf tahlili: g‘ayritabiiy bog‘lanish naqshlari |
| Obunachi “fermalari” | Soxta akkauntlar bilan obunachi sotish | Faollik nisbati, akkaunt yoshi |
| Ta’qib va hujum | Ko‘p akkauntdan bir odamga | Bloklash, filtr, sekinlashtirish |
| Ma’lumot yig‘ish (scraping) | API yoki HTML orqali ommaviy o‘qish | Tezlik 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)
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
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
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:
- Navbat va tezlik cheklovi — qayta qurish ishlari navbatga tushadi va eng faollardan boshlab bajariladi (10.1 Deep)
- Arzon vaqtinchalik javob — tasma tayyor bo‘lguncha “mashhur postlar” yoki mintaqaviy “eng yaxshi” tasma ko‘rsatiladi (6-bo‘lim 3-qadam Deep)
- Oldindan isitish — rejalashtirilgan voqealar oldidan oxirgi 30–90 kunda faol bo‘lganlarning tasmalarini fonda qayta qurish
- 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
| Metrika | Nimani ko‘rsatadi | Chegara |
|---|---|---|
| Fan-out kechikishi (p99) | Post qancha vaqtda tarqaladi | 10 soniyadan ko‘p |
| Navbat chuqurligi | Tarqatish orqada qolganmi | Doimiy o‘sish |
| Tasma p99 | Foydalanuvchi tajribasi | 200 ms |
| Kesh urishi (tasma, post, graf) | Bazaga yuk | 95% dan past |
| Bo‘sh tasma ulushi | Qayta qurish kerak bo‘lganlar | 0.1% dan ko‘p |
| Deduplikatsiya soni | Chegara muammosi bormi | Keskin o‘sish |
| Reyting kechikishi | Model xizmati holati | 50 ms |
| Qayta qurishlar soni | Kesh yo‘qotishlari | Har qanday cho‘qqi |
Nazorat savoli · javobni ko‘rishFoydalanuvchilar 'postim ko'rinmayapti' deb shikoyat qilyapti. Diagnostika tartibingiz?
- O‘z tasmasidami yoki boshqalarnikidami? O‘zida ko‘rinmasa — bu yozish yo‘li muammosi (post umuman saqlanmagan). Boshqalarda ko‘rinmasa — tarqatish muammosi
- Fan-out navbati kechikishi — p99 va navbat chuqurligi. Eng ko‘p uchraydigan sabab
- 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
- Filtrlar — post moderatsiya, spam yoki “sezgir kontent” filtriga tushganmi
- 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
| Qaror | Nima yutamiz | Nimani yo'qotamiz |
|---|---|---|
| Tasmani JOIN bilan qurish | Kod sodda, izchillik kuchli | Sekundiga milliardlab qator; shardlangandan keyin umuman ishlamaydi |
| Hammaga fan-out on write | O'qish juda tez | Bitta mashhur post butun klasterni bloklaydi |
| Hammaga fan-out on read | Yozish arzon, ma'lumot yangi | Sekundiga 70 million so'rov — imkonsiz |
| Tasmada postlarni to'liq saqlash | Hidratsiya kerak emas | Xotira 40 barobar ko'p; tahrir va o'chirish tarqalmaydi |
| Post o'chirilganda tasmalardan olib tashlash | Toza ma'lumot | 100 million tasmani yangilash — imkonsiz. Tombstone kerak |
| tweets jadvalini author_id bo'yicha shardlash | Profil so'rovi tez | Mashhur akkaunt sharti yonadi — hot shard |
| Avtoinkrement ID | Oddiy | Taqsimlangan tizimda koordinatsiya; tartib va sahifalash buziladi |
| Fan-out'ni sinxron qilish | Post darhol tarqaladi | Post yozish 200 ms dan sekundlarga cho'ziladi |
| Tezlik cheklovini postlar soni bo'yicha qo'yish | Tushunarli | Ko'p obunachili akkaunt bir post bilan million yozuv yaratadi |
| Barcha foydalanuvchilarga tasma keshini saqlash | Hamma uchun tez | Faol bo'lmaganlar xotiraning yarmini yeydi; ular baribir kirmaydi |
16. Trade-off‘lar
| Qaror | Nima yutamiz | Nimani yo'qotamiz |
|---|---|---|
| Push (fan-out on write) | O'qish O(1), tasma darhol tayyor | Yozish yuki katta, xotira ko'p, mashhurlar muammosi |
| Pull (fan-out on read) | Yozish arzon, xotira kam, ma'lumot yangi | Har o'qishda yuzlab so'rov — masshtablanmaydi |
| Gibrid | Ikkalasining kuchli tomoni | Ikki kod yo'li, chegara boshqaruvi, deduplikatsiya |
| Tasma uzunligi 800 | Bir necha kunlik tarix, chuqur varaqlash mumkin | 1.6 TB xotira |
| ID lar ro'yxati (kontent emas) | 40 barobar kam xotira, tahrir tarqaladi | Har o'qishda hidratsiya kerak |
| Xronologik tartib | Bashoratli, arzon, tushunarli | Ko'p obunali foydalanuvchi ko'p narsani ko'rmaydi |
| Reytingli tasma | Foydalanuvchi vaqti ortadi | Sekundiga 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 saqlamaslik | Xotira 2-3 barobar tejaladi | Ular qaytganda tasma qayta quriladi — sekin birinchi yuklanish |
Butun dars o‘nta gapda
- 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).
JOINbilan tasma shardlashdan keyin umuman ishlamaydi: postlar va obunalar turli kalitlar bo‘yicha turli mashinalarda yotadi (4).- Tasma keshi — ID lar ro‘yxati, postning o‘zi emas: 8 bayt, 800 ta chegara, faqat faol foydalanuvchilar uchun (6-bo‘lim 1-qadam).
- Mashhur akkaunt sof push’ni buzadi: bitta post — 100 mln yozuv va butun navbatning kechikishi (5.3, 7.2).
- 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).
- 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).
- O‘chirish, bloklash, yashirish — o‘qishda filtr: millionlab tasmani qayta yozish o‘rniga tombstone va ortiqcha nomzod (6-bo‘lim 5-qadam, 10.5).
- Snowflake — vaqt bo‘yicha tartiblangan, koordinatsiyasiz ID: kursor bilan sahifalash va shardlash shundan oson (6-bo‘lim 7-qadam).
- Tasma — hosila ma’lumot: uni manbadan qayta qurish mumkin, va bu butun tizimning xavfsizlik to‘ri (10.1).
- “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):
- 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)
- Reyting — ~48 mln parametrli neyron tarmoq har nomzod uchun yoqtirish, javob, repost va salbiy reaksiya ehtimolini bashorat qiladi; ball — og‘irlikli yig‘indi
- 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:
- Xotira: ID 8 bayt, post ~300 bayt. 200M foydalanuvchi × 800 element uchun farq 1.6 TB va 64 TB orasida
- Yangilanish: post tahrirlansa yoki o‘chirilsa, uni millionlab tasmadan qidirish shart emas — hidratsiya paytida yangi holat olinadi
- 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:
- Koordinatsiya — taqsimlangan tizimda avtoinkrement markaziy nuqta talab qiladi, u esa tor joy va nosozlik nuqtasi
- Tartib — tasma
ORDER BY id DESCga tayanadi. ID vaqt bilan bog‘liq bo‘lmasa, tartiblash uchuncreated_atkerak, u esa taqsimlangan tizimda ishonchsiz (soatlar farq qiladi, bir xil millisekundda tartib noaniq) - 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:
- Yirik ishlarni alohida navbatga ajratish — head-of-line blocking yo‘qoladi
- Chegarani pasaytirish — yangi postlar uchun yozish yuki darhol kamayadi
- Ishchilarni ko‘paytirish — agar tor joy Redis emas, ishchi bo‘lsa
- 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:
- Chekka/CDN — post kontenti o‘zgarmas, uni chekkada keshlash mumkin
- Ilova serverida mahalliy kesh (L1, TTL 5–10 soniya) — 100 server bo‘lsa, markaziy keshga yuk 500 000 dan 10–20 ga tushadi
- 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.
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?
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):
snowflake.py—next_id: vaqt, mashina va ketma-ketlik bitlari, millisekund to‘lganda kutish, soat orqaga ketganda xato;parsetimeline.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
JOINnatijasi 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).
3-daraja: Redis bilan ishlaydigan tasma va nosozliklar
2-darajadagi mantiqni haqiqiy Redis ustiga ko‘chiring:
POST /tweet— Snowflake, saqlash, fan-out navbati. Fan-out ishchisi — 1000 tadan bo‘lak, pipelining bilanLPUSH+LTRIM 0 799GET /timeline—LRANGE+ mashhurlar ro‘yxatlari + birlashtirish +MGEThidratsiya + filtrlar- Tasmani qayta qurish funksiyasi (manbadan). Redis’dan tasodifiy 20% tasmani o‘chirib, tiklanishni o‘lchang
- 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.
4-daraja: reyting va uning narxi
Tasmaga oddiy reyting qo‘shing:
- Xususiyatlar: post yoshi, muallif bilan aloqa chastotasi, erta reaksiyalar soni
- Oddiy chiziqli model yoki qo‘lda yozilgan formula
- 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
| Atama | Ma’nosi |
|---|---|
| Tasma (timeline) | Obuna bo‘lganlar postlaridan tuzilgan ro‘yxat |
| Fan-out | Postni obunachilarga tarqatish |
| Fan-out on write (push) | Yozish paytida tarqatish |
| Fan-out on read (pull) | O‘qish paytida yig‘ish |
| Gibrid fan-out | Oddiylar push, mashhurlar pull |
| Chegara (threshold) | Akkauntni mashhur deb hisoblash chegarasi |
| Gisterezis | Chegara atrofida tebranishni oldini oluvchi ikki tomonlama chegara |
| Hidratsiya | ID lardan to‘liq post ma’lumotini olish |
| Tombstone | O‘chirilgan yozuvning belgisi; o‘qishda filtrlanadi |
| Snowflake ID | Vaqt + mashina + ketma-ketlikdan tuzilgan tartiblanadigan ID |
| Truncation | Tasmani sobit uzunlikda ushlab turish (LTRIM) |
| Hot key / hot shard | Nomutanosib ko‘p murojaat qilinadigan kalit yoki shard |
| Head-of-line blocking | Katta ish navbatdagi kichiklarni to‘xtatib qo‘yishi |
| Qayta qurish (rebuild) | Hosila ma’lumotni manbadan tiklash |
| Bo‘shliq (gap) | Tarqatishda yo‘qolgan postlar |
| Deduplikatsiya | Birlashtirishda takroriy ID larni olib tashlash |
| Nomzodlar (candidates) | Reytinggacha bo‘lgan postlar to‘plami |
| Darajali taqsimot | Obunachilar sonining notekis tarqalishi |
| Read your own writes | Foydalanuvchi o‘z yozganini darhol ko‘rishi |
| k-way merge | k ta tartiblangan ro‘yxatni uyum bilan birlashtirib, faqat kerakli qismini olish |
| Kursor | “Shu ID dan kichiklar” ko‘rinishidagi barqaror sahifalash nuqtasi |
| Obunadan tashqari nomzod | Siz 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 qatlami | Model natijasini tuzatuvchi qoidalar: xilma-xillik, filtrlar |
| Shadow testing | Optimallashtirilgan yo‘lni sodda va aniq yo‘l bilan solishtirish |
20. Raqamlar manbasi
| Raqam | Qiymat | Manba |
|---|---|---|
| 2012-yilgi tizim | 150 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 manzildan | Raffi Krikorian, “Timelines at Scale”, QCon SF 2012; High Scalability sharhi |
| “5 soniyada yetkazish” maqsadi | Tweet obunachilarga 5 soniya ichida | O‘sha ma’ruza va sharh |
| Snowflake | 2010; 41 bit vaqt, 10 bit mashina, 12 bit ketma-ketlik; epoch 2010-11-04 | Twitter Engineering, “Announcing Snowflake” |
| Ochiq algoritm | 2023-yil 31-mart; kuniga ~5 mlrd ishga tushish; ~1 500 nomzod; ~50% obunalardan; og‘ir reyting ~48 mln parametr | Twitter Engineering blogi (2023); TechCrunch va boshqa sharhlar |
| 2-daraja natijalari | 13/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-algorithmochiq 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
