ბიბლიოთეკა
00/08 · ~43 წთ
GUIDEDECK · სისტემებისთვის, რომლებიც იზრდება და არ ვარდება

სისტემების დიზაინი
მასშტაბისა
და ჩავარდნისთვის.

43-წუთიანი სამუშაო სესია დიდი სისტემების მოძრავ ნაწილებზე — როგორ გავშალოთ ისინი განიერად, სად დავაქეშიროთ, როგორ უძლებს მონაცემთა ბაზა ზრდას, რატომ ვეყრდნობით რიგებს, რა კომპრომისებს გვახვევს თავს CAP თეორემა და როგორ დავინახოთ მთელი სურათი, როცა ის უკვე პროდაქშენში მუშაობს.

~43 წთშერეული გუნდიენისგან დამოუკიდებელი
გადაახვიეთ
01 · ჩარჩო 4 წთ

დღევანდელ დატვირთვაზე არ პროექტირებთ.
პროექტირებთ ზრდასა და ჩავარდნაზე.

ერთი მანქანა, რომელიც ათას მომხმარებელს ემსახურება, მარტივია. რთული მაშინ იწყება, როცა ტრაფიკი, მონაცემები და ჩავარდნილი მანქანების რაოდენობა ერთდროულად იზრდება. წინ მდგარი ყოველი გადაწყვეტილება ერთ რესურსს მეორეზე ცვლის — უფასო მოგება არ არსებობს, არსებობს მხოლოდ თქვენს ციფრებზე მორგებული სწორი კომპრომისი.

სისტემების დიზაინი — სისტემის არქიტექტურა მასშტაბზე — არის გადაწყვეტა იმისა, თუ როგორ მიედინება მოთხოვნები, მონაცემები და ჩავარდნები მრავალ მანქანაში ისე, რომ დატვირთვის ზრდისასაც მთელი სისტემა სწრაფი, ხელმისაწვდომი და ფინანსურად გონივრული დარჩეს. ეს არის ინჟინერია ერთდროულად სამი წნეხის ქვეშ: მეტი ტრაფიკი, მეტი მონაცემი და მეტი რამ, რაც ფუჭდება.
x100

ტრაფიკი ერთ წელიწადში ორი რიგით შეიძლება გაიზარდოს — დიზაინი უნდა მოიხაროს და არა გატყდეს.

p99

p99 = ყოველი 100 მოთხოვნიდან ყველაზე ნელი 1. მომხმარებელი საშუალოს კი არა, კუდს გრძნობს — ამიტომ სწორედ ის უნდა გააუმჯობესოთ.

100%?

არცერთ მანქანას არ აქვს 100% აფთაიმი. მასშტაბზე ყოველთვის რაღაც ვარდება — ეს გაითვალისწინეთ.

$$$

სიმძლავრე ფულს ღირს. იმარჯვებს ყველაზე იაფი დიზაინი, რომელიც SLO-ს აკმაყოფილებს, და არა ყველაზე მძლავრი.

სამი ციფრი, რომელიც ყოველ გადაწყვეტილებას განსაზღვრავს

წინ მდგარი თითქმის ყველა ხერხი სიღრმეში ერთი და იგივე სვლაა: დახარჯეთ მეხსიერება, ფული ან თანმიმდევრულობა, რომ სანაცვლოდ იყიდოთ შეყოვნება, გამტარუნარიანობა ან ხელმისაწვდომობა. ქეში, მაგალითად, ხარჯავს დამატებით მეხსიერებას (და ოდნავ მოძველებული მონაცემების რისკს იღებს), რომ წაკითხვები ბევრად სწრაფი გახადოს.

02 · მასშტაბირება, ბალანსირება 6 წთ

მასშტაბირეთ ვერტიკალურად, სანამ შეიძლება,
მერე კი ჰორიზონტალურად.

მეტი დატვირთვის გასაძლებად მხოლოდ ორი გზაა: გაზარდე მანქანა ან დაამატე მანქანები. პირველი მარტივია და ჭერი აქვს; მეორეს ჭერი არ აქვს, სამაგიეროდ განაწილებულობასთან შეხვედრას გაიძულებთ.

ვერტიკალური მასშტაბირება (scale up) — იყიდე უფრო დიდი მანქანა: მეტი CPU, RAM, უფრო სწრაფი დისკები. ჰორიზონტალური მასშტაბირება (scale out) — დაამატე მანქანები და გაანაწილე მათ შორის სამუშაო. ვერტიკალური მარტივია, მაგრამ ჭერს აწყდება და ჩავარდნის ერთადერთი წერტილია; ჰორიზონტალური უფრო რთულია, სამაგიეროდ ჭერი არ აქვს და მკვდარ ნოუდსაც გადაურჩება.
ერთი დიდი მანქანა
// one server does everything Server { cpu: 128, ram: "2 TB" } // + dead simple, no distribution // − hard ceiling (biggest box exists) // − single point of failure // − price climbs faster than power
მანქანების ფლოტი
// many small servers behind a balancer [ Server, Server, Server, ... ] // + no ceiling — keep adding nodes // + a dead node ≠ an outage // − needs a load balancer + statelessness // − distribution adds complexity

ბალანსერი ამოწმებს ფლოტის ჯანმრთელობას და მკვდარ ნოუდს გვერდს უვლის — კლიენტები ვერაფერს ამჩნევენ.

დატვირთვის ბალანსერი და რა სჭირდება მას

  • მოთხოვნებს ანაწილებს round-robin-ით, least-connections-ით ან კლიენტის ჰეშით — და თითოეულ ნოუდს ჯანმრთელობაზე ამოწმებს, რომ მკვდარი ამოაგდოს.
  • ჰორიზონტალური მასშტაბირება მხოლოდ მაშინ მუშაობს, თუ აპლიკაციის სერვერები უმდგომარეოა — ნებისმიერ ნოუდს ნებისმიერი მოთხოვნის მომსახურება შეუძლია. სესიისა და ატვირთვების მდგომარეობა ლოკალური მეხსიერების ნაცვლად საერთო საცავში გაიტანეთ.
  • წებოვნება გჭირდებათ? სჯობს საერთო სესიის საცავი (ქეში ან ბაზა), ვიდრე წებოვანი მარშრუტიზაცია — მაშინ ნოუდის დაკარგვა მომხმარებლებს სისტემიდან არ გამოაგდებს.
  • თავად ბალანსერი არ უნდა იყოს ჩავარდნის ერთადერთი წერტილი — გაუშვით ის რეზერვირებულად (მაგ. წყვილი მცურავი მისამართის უკან).

ინსტრუმენტების ლანდშაფტი — დატვირთვის ბალანსერები

დატვირთვის ბალანსერი ფლოტის წინ მდგარი მოძრაობის ინსპექტორია, რომელიც წყვეტს, რომელ ნოუდზე წავიდეს ყოველი მოთხოვნა. შეგიძლიათ საკუთარი გაუშვათ ან ღრუბელს გააკეთებინოთ ეს თქვენ ნაცვლად.

პროგრამა · ვები

nginx

ვებ სერვერი, რომელიც ამავე დროს რევერს-პროქსი და ბალანსერია.

  • დადებითი: სწრაფი და ბრძოლაში გამოცდილი, და იმავე მანქანას სტატიკური ფაილების გაცემა და HTTPS-ის დამუშავებაც შეუძლია.
  • უარყოფითი: ყველაზე მდიდარი მარშრუტიზაცია და ცოცხალი გადატვირთვა ფასიან „Plus“ დონეს მიღმაა.
პროგრამა · პროქსი

HAProxy

პროქსი, აგებული ერთი საქმისთვის: ტრაფიკის ბალანსირება და მეტი არაფერი.

  • დადებითი: ჯანმრთელობის შემოწმებისა და დატვირთვის ალგორითმების ყველაზე ღრმა კონტროლი, და კლდესავით მდგრადი ძალიან მაღალ სიხშირეზე.
  • უარყოფითი: მხოლოდ პროქსირება — სტატიკური ფაილების გარეშე — და კონფიგურაციას სწავლის მრუდი აქვს.
მართული · ღრუბელი

ღრუბლის LB

თქვენი ღრუბლის საკუთარი ბალანსერი (AWS ELB/ALB, GCP, Azure).

  • დადებითი: სრულად მართული — თავად მასშტაბირდება, თავად იკურნება და თქვენ არაფრის დაპაჩვა არ გიწევთ.
  • უარყოფითი: ნაკლები წვრილი კონტროლი, საათობრივი პლიუს გიგაბაიტობრივი ანგარიში და მიბმა ერთ კონკრეტულ ღრუბელზე.

როგორ ავირჩიოთ: ღრუბელში დაიწყეთ მართული დატვირთვის ბალანსერით — ის თავად მასშტაბირდება და დაპაჩვა არასდროს გჭირდებათ. nginx-ზე ან HAProxy-ზე მაშინ ჩამოდით, როცა საკუთარი მარშრუტიზაციის წესები გჭირდებათ ან პროვაიდერებს შორის პორტაბელური გინდათ დარჩეთ.

ვისი მანქანები? დიდი ღრუბლოვანი პროვაიდერები

ჰორიზონტალური მასშტაბირება ნიშნავს, რომ სადღაც მანქანებს ქირაობთ. სამივე დიდი ღრუბელი აქირავებს გამოთვლას, მართულ მონაცემთა ბაზებს, რიგებსა და დატვირთვის ბალანსერებს — ისინი ძირითადად სიმწიფით, ფასითა და იმით განსხვავდებიან, თუ რომელ დამატებას აკეთებენ ყველაზე კარგად.

ღრუბელი · ფართო

AWS

Amazon Web Services — ყველაზე ძველი და ყველაზე დიდი.

  • დადებითი: სერვისების ყველაზე ფართო კატალოგი და დასაქმების ყველაზე დიდი ბაზარი — გაკვეთილების უმეტესობა სწორედ მას გულისხმობს.
  • უარყოფითი: იმდენი ერთმანეთის გადამფარავი ვარიანტია, რომ ადვილად იკარგებით, და ანგარიშის წინასწარ განჭვრეტა რთულია.
ღრუბელი · data/ml

GCP

Google Cloud — ძლიერია მონაცემებსა და Kubernetes-ში (რომელიც Google-მა შექმნა).

  • დადებითი: შესანიშნავი ანალიტიკის, მანქანური სწავლებისა და კონტეინერების ინსტრუმენტები, სუფთა დეველოპერული ერგონომიკით.
  • უარყოფითი: უფრო მცირე კატალოგი და ეკოსისტემა, და წლების განმავლობაში რამდენიმე პროდუქტი დახურეს.
ღრუბელი · ენტერპრაიზი

Azure

Microsoft-ის ღრუბელი — ნაგულისხმევი არჩევანი, თუ უკვე Microsoft-ის სამყაროში ცხოვრობთ.

  • დადებითი: ღრმა კავშირები Windows-თან, Office-სა და Active Directory-სთან მას ბევრი დიდი კომპანიისთვის ადვილ არჩევნად აქცევს.
  • უარყოფითი: კონსოლი და დასახელებები არათანმიმდევრული შეიძლება მოგეჩვენოთ, ზოგი სერვისი კი AWS-ის ანალოგებს ჩამორჩება.

როგორ ავირჩიოთ: ძირითად საკითხებში ისინი თითქმის ტოლია, ამიტომ აირჩიეთ ის, რომელიც თქვენმა გუნდმა უკვე იცის ან სადაც თქვენი დანარჩენი ინსტრუმენტები ცხოვრობს. მძიმე მონაცემებისა და ML-ის სამუშაოსთვის გადაიხარეთ GCP-სკენ, Azure-სკენ — თუ Microsoft-ის სამყაროში ხართ, AWS-სკენ კი მაშინ, როცა ყველაზე ფართო მენიუ და დასაქმების ყველაზე მეტი ვარიანტი გინდათ.

03 · ქეშირება 6 წთ

ყველაზე სწრაფი შეკითხვა ის არის,
რომელსაც არასდროს უშვებთ.

ქეში ძვირი შედეგების ასლს იქვე ინახავს, სადაც ისინი საჭიროა, ამიტომ წაკითხვების უმეტესობა ნელ გზას საერთოდ გვერდს უვლის. ეს შეყოვნებაზე ყველაზე ძლიერი ერთი ინსტრუმენტია — და ყველაზე ადვილი, რომ შეუმჩნევლად არასწორად გამოიყენოთ.

ქეში არის ძვირი შედეგების სწრაფი, დროებითი საცავი, რომელიც მკითხველთან ახლოს დგას. მოხვედრა პასუხს ქეშიდან გასცემს (სწრაფად); აცდენა ჭეშმარიტების წყარომდე ჩავარდება (ნელა) და უკან დაბრუნებისას ჩვეულებრივ ქეშსაც ავსებს. მიზანი მაღალი მოხვედრის კოეფიციენტია — მთელი ღირებულება სწორედ ეს კოეფიციენტია.
სად · კლიენტი

ბრაუზერი / CDN

სტატიკური რესურსები და საჯარო პასუხები, დაქეშირებული edge-ზე, მომხმარებელთან ახლოს. ყველაზე იაფი შესაძლო მოხვედრა — მოთხოვნა თქვენს სერვერებამდე საერთოდ არ აღწევს.

სად · აპი

მეხსიერებაში / Redis

ცხელი ობიექტები და შეკითხვების შედეგები საერთო ქეშში (Redis, Memcached) აპლიკაციასა და ბაზას შორის. სამუშაო ცხენივით შრე, რომელსაც უმეტესობა „ქეშში“ გულისხმობს.

სად · ბაზა

ბაზისა & შეკითხვების ქეში

ბაზის საკუთარი ბუფერული პული და მატერიალიზებული ხედები. სასარგებლოა, მაგრამ თქვენ არ აკონტროლებთ — და ქსელის გადასვლებს არ ამცირებს.

cache-aside: ჯერ ქეშს ჰკითხეთ; აცდენისას წაიკითხეთ ბაზა და პასუხი TTL-ით დაწერეთ უკან.

cache-aside — ნაგულისხმევი პატერნი

async function getUser(id: string) {
  let u = await cache.get(`user:${id}`)
  if (u) return u            // hit — done
  u = await db.findUser(id)  // miss — slow path
  await cache.set(`user:${id}`, u, { ttl: 300 })
  return u                   // backfill for next time
}

თითქოს  ყოველდღიურად საჭირო ფაილებს მაგიდაზე ინახავთ და ყოველ ჯერზე არქივის ოთახში არ დადიხართ.

ორი რთული ნაწილი: ინვალიდაცია & TTL

მოძველება

ინვალიდაცია

ქეშს ასლი უჭირავს; როცა წყარო იცვლება, ასლი ტყუილად იქცევა. ჩაწერისას წაშალეთ (ან განაახლეთ) გასაღები, რომ შემდეგმა წაკითხვამ ხელახლა წამოიღოს. „მხოლოდ ორი რთული რამ არსებობს… ერთი ქეშის ინვალიდაციაა.“

ვადა

TTL — სიცოცხლის ხანგრძლივობა

უსაფრთხოების ბადე: ყოველ ჩანაწერს N წამში ვადა გასდის, მაშინაც კი, თუ ინვალიდაცია დაგავიწყდათ. მოკლე TTL = უფრო ახალი, სამაგიეროდ მეტი აცდენა; გრძელი TTL = უფრო სწრაფი, სამაგიეროდ უფრო ძველი. მოარგეთ მონაცემს.

ჩავარდნა

ხროვა

როცა პოპულარულ გასაღებს ვადა გასდის, ათასი მოთხოვნა ერთსა და იმავე წამს აცდება და ხროვად ეცემა მონაცემთა ბაზას. თავი დაიცავით მოკლე ჩაკეტვით, იმით, რომ მხოლოდ ერთი მოთხოვნა წამოიღებს მონაცემს და დანარჩენები დაელოდებიან („გაერთიანება“), ან TTL-ში მცირე შემთხვევითობის („jitter“) ჩამატებით, რომ გასაღებებს ერთდროულად არ გაუვიდეს ვადა.

ინსტრუმენტების ლანდშაფტი — ქეშები

მეხსიერება · მდიდარი

Redis

მეხსიერებაში მომუშავე საცავი, რომელიც მონაცემებს RAM-ში ინახავს მიკროწამიანი წაკითხვისთვის.

  • დადებითი: ქეშზე ბევრად მეტი — სიები, სიმრავლეები, მთვლელები, pub/sub და დისკზე შენახვის ვარიანტი, რომ გადატვირთვას გადაურჩეს.
  • უარყოფითი: ერთნაკადიანი ბირთვი და მეტი მოძრავი ნაწილი; ერთი გიგანტური ინსტანცია თავადვე შეიძლება გახდეს ვიწრო ყელი.
მეხსიერება · მარტივი

Memcached

ყველაზე მინიმალური ვარიანტი: სწრაფი გასაღები → მნიშვნელობის სტრიქონული ქეში.

  • დადებითი: უკიდურესად მარტივი და მრავალნაკადიანი — ძალიან სწრაფია უბრალო „დაიმახსოვრე ეს სტრიქონი“ ქეშირებისთვის.
  • უარყოფითი: მხოლოდ სტრიქონები, არც პერსისტენტულობა, არც რეპლიკაცია — ნოუდს კარგავთ და მთელ ქეშსაც კარგავთ.
მართული · edge

CDN & მართული

edge-ქეშები (Cloudflare, Fastly, CloudFront) და ჰოსტირებული Redis (ElastiCache, Upstash).

  • დადებითი: სხვა უვლის — ქეშირება მომხმარებლის გვერდით (CDN) ან სერვერები, რომელთა დაპაჩვაც არ გიწევთ (მართული Redis).
  • უარყოფითი: ყოველთვიური ანგარიში და ნაკლები კონტროლი; CDN მხოლოდ საჯარო, დასაქეშირებელ პასუხებს შველის.

როგორ ავირჩიოთ: ნაგულისხმევად მიმართეთ Redis-ს — მისი მონაცემთა ტიპები და არჩევითი პერსისტენტულობა მაშინვე ამართლებს, როგორც კი უბრალო ძებნაზე მეტი დაგჭირდებათ. Memcached აირჩიეთ მხოლოდ მაშინ, როცა ყველაზე მარტივი სტრიქონული ქეში გინდათ, სტატიკური და საჯარო კონტენტი კი CDN-ზე გაიტანეთ, რომ თქვენს სერვერებს საერთოდ არ შეეხოს.

04 · ბაზები მასშტაბზე 7 წთ

წაკითხვები ასლებით მასშტაბირდება.
ჩაწერები & ზომა — დანაწევრებით.

ჩვეულებრივ პირველი, რაც ტყდება, მონაცემთა ბაზაა — რადგან მას მდგომარეობა უჭირავს, მდგომარეობის განაწილება კი რთულია. ორი სვლა შორს მიგიყვანთ: რეპლიკაცია წაკითხვის დატვირთვისა და ხელმისაწვდომობისთვის, და დანაწილება ჩაწერის დატვირთვისა და სუფთა ზომისთვის.

რეპლიკაცია — მონაცემების სრული ასლების შენახვა მრავალ ნოუდზე (მთავარი იღებს ჩაწერებს; რეპლიკები ემსახურება წაკითხვებს). დანაწილება / შარდინგი — მონაცემების გასაღებით ნაწილებად დაყოფა, სადაც ყოველი ნაწილი სხვა ნოუდზე ცხოვრობს. რეპლიკაცია პასუხობს „ძალიან ბევრ წაკითხვას“; შარდინგი — „ძალიან ბევრ ჩაწერას / ძალიან ბევრ მონაცემს“.

რეპლიკაცია — ერთი მთავარი, მრავალი წამკითხავი რეპლიკა

ჩაწერები მთავარზე მიდის; იქიდან ისინი რეპლიკებზე მიედინება, რომლებიც წაკითხვებს ემსახურება. წაკითხვის სიმძლავრეს ამრავლებთ და ცხელ სარეზერვოსაც იღებთ — თუ მთავარი მოკვდა, რეპლიკა მის ადგილს იკავებს (failover).

მთავარი ჩაწერებს წამკითხავ რეპლიკებზე გადასცემს; რეპლიკები წაკითხვებს ემსახურება და failover-ისას მთავრის ადგილს იკავებს.

  • წაკითხვის მასშტაბირება — რეპორტინგი და წაკითხვებით დატვირთული ტრაფიკი რეპლიკებზე მიმართეთ.
  • ხელმისაწვდომობა — თუ მთავარი ჩავარდა, რეპლიკა ხდება ახალი მთავარი.
  • ხაფანგი — რეპლიკაციის ჩამორჩენა. ასინქრონული რეპლიკები წამით ჩამორჩებიან, ამიტომ ჩაწერისთანავე გაკეთებულმა წაკითხვამ შეიძლება ვერ დაინახოს იგი (read-your-writes პრობლემა).

შარდინგი — სტრიქონების ნოუდებზე დაყოფა გასაღებით

აირჩიეთ შარდის გასაღები (მაგ. user_id); მისი ჰეში ან დიაპაზონი წყვეტს, რომელ ნოუდს ეკუთვნის თითოეული სტრიქონი. ყოველ შარდს მონაცემების ნაწილი უჭირავს და საკუთარ ჩაწერებს იღებს — ამიტომ ჩაწერის გამტარუნარიანობა და საერთო ზომა შარდების რაოდენობასთან ერთად იზრდება.

// route by a hash of the shard key
function shardFor(userId: string, n: number): number {
  return hash(userId) % n     // → which node owns this user
}
// all of one user's rows live together on one shard
// → single-user queries stay on a single node
  • გასაღები ფრთხილად აირჩიეთ — მისი შეცვლა ძვირია. ცუდი გასაღები ცხელ შარდებს ქმნის (ერთი ნოუდი ტრაფიკის უმეტესობას იღებს).
  • შარდებს შორის შეკითხვები მტკივნეულია — join-ები და „ყველას დათვლა“ ახლა ყველა ნოუდზე იშლება. დააპროექტეთ ისე, რომ ჩვეულებრივი შეკითხვა ერთ შარდზე დარჩეს.
  • თანმიმდევრული ჰეშირება გაძლევთ საშუალებას ნოუდები დაამატოთ ან მოაშოროთ ისე, რომ გასაღებების მხოლოდ მცირე ნაწილი გადაიტანოთ.

აირჩიეთ საცავი წვდომის პატერნის მიხედვით

რელაციური (SQL)

მკაცრი თანმიმდევრულობა, ტრანზაქციები, მოქნილი ad-hoc შეკითხვები და join-ები. სწორი ნაგულისხმევი არჩევანი — აპლიკაციების უმეტესობა კარგად მორგებულ, რეპლიცირებულ SQL ბაზას ვერასდროს გადაასწრებს.

NoSQL (KV / დოკუმენტური / ფართო-სვეტიანი)

აგებულია ჰორიზონტალური შარდინგისთვის, უზარმაზარი ჩაწერის მოცულობისა და მარტივი, წინასწარ ცნობილი წვდომის პატერნებისთვის. join-ებსა და (ხშირად) მკაცრ თანმიმდევრულობას სუფთა მასშტაბზე ცვლით.

ცერის წესი: დაიწყეთ რელაციურით. NoSQL-ს მაშინ მიმართეთ, როცა კონკრეტულ მასშტაბზე კონკრეტული წვდომის პატერნი ამას ითხოვს — და არა ნაგულისხმევად.

05 · ასინქრონი და რიგები 5 წთ

ნუ ალოდინებთ მომხმარებელს
იმ სამუშაოს, რომელიც მას არ სჭირდება.

როცა მოთხოვნა ნელ სამუშაოს იწვევს — ელფოსტის გაგზავნა, ვიდეოს კოდირება, ბარათიდან თანხის ჩამოჭრა — მისი იქვე შესრულება მომხმარებელს აჩერებს და ორი სერვისის აფთაიმს ერთმანეთზე აბამს. რიგი გაძლევთ საშუალებას სამუშაო ახლა მიიღოთ და მალე შეასრულოთ.

შეტყობინებების რიგი არის მდგრადი ბუფერი პროდიუსერსა და კონსიუმერს შორის. პროდიუსერი შეტყობინებას რიგში აყენებს და მაშინვე ბრუნდება; მუშა მას იღებს და მოგვიანებით, საკუთარი ტემპით ამუშავებს. ეს ორ მხარეს ერთმანეთისგან ხსნის — მათ აღარ სჭირდებათ იყვნენ სწრაფები, ხელმისაწვდომები ან თუნდაც ერთდროულად ჩართულები.
სინქრონული — შეკრული და ნელი
async function signup(req) {
  const u = await db.createUser(req)
  await email.sendWelcome(u)   // 800ms, may fail
  await billing.provision(u)  // 2s, may be down
  return ok(u)                // user waits for ALL of it
}
// email outage → signup outage
ასინქრონული — გახსნილი და სწრაფი
async function signup(req) {
  const u = await db.createUser(req)
  await queue.publish("user.created", u)  // instant
  return ok(u)                           // user is done now
}
// workers handle email + billing independently
// email outage → a delay, not an outage

დაამატეთ მუშები, რომ რიგი უფრო სწრაფად დაიცალოს; რიგი პიკებს შთანთქავს, ამიტომ პროდიუსერები არასდროს იბლოკება.

რას ყიდულობს რიგი — და რას მიაქციოთ ყურადღება

  • ბუფერიზაცია & პიკები — ტრაფიკის ტალღა რიგს ავსებს და მუშებს არ ახრჩობს; ისინი შემდეგ ეწევიან.
  • უკუწნევა — თუ რიგი უფრო სწრაფად იზრდება, ვიდრე მუშები ცლიან, სწორედ ეს სიღრმეა სიგნალი, რომ მუშები დაამატოთ, პროდიუსერები შეანელოთ ან დატვირთვა ჩამოიშოროთ. აკვირდით რიგის სიღრმეს, როგორც პირველი რიგის მეტრიკას.
  • ხელახალი მცდელობები & მკვდარი წერილები — ჩავარდნილი შეტყობინებები ხელახლა სცდის, შემდეგ კი გაქრობის ნაცვლად dead-letter რიგში ხვდება შესამოწმებლად.
  • at-least-once მიწოდება — შეტყობინება ორჯერ შეიძლება მოვიდეს, ამიტომ კონსიუმერები იდემპოტენტური უნდა იყოს (ორჯერ დამუშავება == ერთხელ დამუშავება).

ინსტრუმენტების ლანდშაფტი — შეტყობინებების რიგები

ლოგი · ნაკადი

Apache Kafka

მოვლენების მდგრადი, მხოლოდ-დამატებადი ლოგი, რომლის გამეორებაც ბევრ მკითხველს შეუძლია.

  • დადებითი: უზარმაზარი გამტარუნარიანობა და გამეორებადი ისტორია — ახალ კონსიუმერებს ძველი მოვლენების თავიდან წაკითხვა შეუძლიათ.
  • უარყოფითი: უფრო მძიმეა გასაშვებად და გასააზრებლად; რამდენიმე მარტივი ფონური სამუშაოსთვის ზედმეტია.
ბროკერი · მარშრუტი

RabbitMQ

კლასიკური შეტყობინებების ბროკერი მოქნილი მარშრუტიზაციის წესებით.

  • დადებითი: მდიდარი მარშრუტიზაცია და თითოეული შეტყობინების დადასტურება მომწიფებული ინსტრუმენტებით — შესანიშნავია ამოცანების რიგებისთვის.
  • უარყოფითი: გამტარუნარიანობა Kafka-ზე ბევრად ადრე ამოიწურება და ბროკერს თავად უშვებთ და მასშტაბირებთ.
მართული · მარტივი

AWS SQS

სრულად მართული რიგი — გასაშვები სერვერები არ არსებობს.

  • დადებითი: ნულოვანი ოპერაციები, ავტომატური მასშტაბირება და იაფია მცირე მოცულობაზე.
  • უარყოფითი: მხოლოდ AWS და გამეორების გარეშე; დალაგებული (FIFO) ვარიანტი გამტარუნარიანობის ნაწილს კარგავს.

როგორ ავირჩიოთ: ჩვეულებრივი ფონური სამუშაოებისთვის ყველაზე ნაკლებ შრომას მართული რიგი (SQS) ან RabbitMQ მოითხოვს. Kafka მაშინ აირჩიეთ, როცა მოვლენების უზარმაზარი ნაკადი გაქვთ, რამდენიმე დამოუკიდებელი კონსიუმერი, ან ისტორიის გამეორება გჭირდებათ — და მისი მართვის საშუალება გაქვთ.

06 · CAP და მთავარი კომპრომისი 5 წთ

როცა ქსელი იხლიჩება,
ირჩევთ თანმიმდევრულობას ან ხელმისაწვდომობას.

აქამდე ყოველი ხერხი მანქანებს ამატებდა, მანქანები კი ქსელით საუბრობენ, რომელიც აუცილებლად დაკარგავს შეტყობინებებს. CAP თეორემა გვეუბნება, რაზე უნდა თქვათ უარი, როცა ეს მოხდება — და ეს არჩევითი არაა.

CAP არის აკრონიმი იმ სამი თვისებისა, რომელსაც განაწილებული საცავი ერთდროულად ატარებს: Consistency, Availability, Partition-tolerance. თეორემა ამბობს: ქსელის გახლეჩისას (P) შეგიძლიათ შეინარჩუნოთ C ან A — ორივე არა. რადგან გახლეჩა ცხოვრების ფაქტია, რეალური არჩევანია CP (პასუხის გაცემაზე უარი, ვიდრე არასწორი პასუხი) თუ AP (პასუხი, შესაძლოა მოძველებული მონაცემებით).
C
Consistency
ყოველი წაკითხვა უახლეს ჩანაწერს ხედავს
A
Availability
ყოველი მოთხოვნა პასუხს იღებს
P
Partition-tolerance
უძლებს დაკარგულ შეტყობინებებს
ნოუდი A
x = 5 · ჩაწერა მოვიდა
ნოუდი B
x = 4 · ძველი
გახლეჩა
შეტყობინებები ქრება
CP: უარი · AP: პასუხი 5
CP: უარი · AP: პასუხი 4

B ვერ იგებს A-ს ჩანაწერს. CP პასუხზე უარს ამბობს; AP მოძველებული 4-ით პასუხობს.

კომპრომისების ცხრილი

  • CP — აირჩიეთ თანმიმდევრულობა. გახლეჩისას უმცირესობის მხარე მოთხოვნებზე უარს ამბობს, ვიდრე მოძველებულ მონაცემებს გასცემს. გამოიყენეთ ფულის, მარაგებისა და ჯავშნებისთვის — არასწორი პასუხი უარესია, ვიდრე პასუხის უქონლობა.
  • AP — აირჩიეთ ხელმისაწვდომობა. ყოველთვის უპასუხეთ, შემდეგ კი შეათანხმეთ. გამოიყენეთ ლენტების, მოწონებების, ონლაინ სტატუსებისა და კალათებისთვის — ოდნავ მოძველებული პასუხი აქ ნორმალურია.
  • საბოლოო თანმიმდევრულობა — AP-ის დაპირება: შეწყვიტეთ ჩაწერა და ყველა რეპლიკა ერთსა და იმავე მნიშვნელობამდე დაიყრება. ეს არასწორი არაა, უბრალოდ მყისიერი არაა.

"CA" მხოლოდ მაშინ არსებობს, როცა გახლეჩა არ არსებობს — ანუ ერთი ნოუდია. როგორც კი გაანაწილებთ, P სავალდებულო ხდება, ამიტომ ყოველი რეალური განაწილებული სისტემა CP ან AP-ია. თანამედროვე საცავები არჩევანს თითოეულ ოპერაციაზეც კი გაძლევენ (აქ ძლიერი წაკითხვები, იქ სწრაფი).

07 · დაკვირვებადობა და მონიტორინგი 5 წთ

ჩავარდნისთვის დააპროექტეთ.
ახლა ის უნდა დაინახოთ კიდეც.

განაწილებული სისტემა ნაწილ-ნაწილ, ჩუმად და ღამის სამ საათზე ვარდება. თუ გარედან ვერ ხვდებით, რა გაფუჭდა და სად, ყოველი ინციდენტი გამოცნობის თამაშად იქცევა. დაკვირვებადობა სწორედ ის სამართავი პანელია ყველაფრისთვის, რაც ახლა ავაწყეთ.

მონიტორინგი პასუხობს კითხვას "გაფუჭდა თუ არა ის, რაც წინასწარ ვიცოდით?" — ეს დაშბორდები და გაფრთხილებებია, რომლებსაც წინასწარ აწყობთ. დაკვირვებადობა კი არის შესაძლებლობა, მომუშავე სისტემას ახალი კითხვები დაუსვათ ახალი კოდის გამოშვების გარეშე, და იგი სამ სახის ტელემეტრიას ეყრდნობა: მეტრიკებს, ლოგებს და ტრეისებს.
საყრდენი · მეტრიკები

მეტრიკები

იაფი დროითი მწკრივები — მოთხოვნების სიხშირე, შეცდომების %, p99 შეყოვნება, რიგის სიღრმე, CPU. მათ აჯამებთ, ტენდენციებს უყურებთ და გაფრთხილებებს აწყობთ. Prometheus + Grafana კანონიკური სტეკია.

საყრდენი · ლოგები

ლოგები

სტრუქტურირებული ჩანაწერები მოვლენებზე — თითო სტრიქონი თითო მომხდარზე, საკმარისი კონტექსტით, რომ შემდეგ მოძებნოთ. Loki, ELK სტეკი ან მართული ლოგების საცავი.

საყრდენი · ტრეისები

ტრეისები

ერთი მოთხოვნის სრული გზა სერვისებს შორის, თითოეული გადასვლის დროით — ერთადერთი გზა იმის დასადგენად, რომელმა სერვისმა შეჭამა შეყოვნება. OpenTelemetry → Jaeger, ან APM, როგორიც Dynatrace-ია.

სერვისები სამ ნაკადს კოლექტორს აწვდიან, ის კი დაშბორდებსა და გაფრთხილებებს კვებავს; გარე შემმოწმებელი აფთაიმს ფლოტის გარედან ამოწმებს.

გაფრთხილება სიმპტომზე — ოთხი ოქროს სიგნალი

  • შეყოვნება — რამდენ ხანს გრძელდება მოთხოვნა (უყურეთ p99-ს და ცალკე გაზომეთ წარმატებულისა და შეცდომის შეყოვნება).
  • ტრაფიკი — რამდენს ითხოვენ სისტემისგან, მაგალითად მოთხოვნა წამში.
  • შეცდომები — ჩავარდნილი მოთხოვნების წილი.
  • გაჯერება — რამდენად სავსეა სისტემა (CPU, მეხსიერება, რიგის სიღრმე).
// გამოიძახეთ მომხმარებლისთვის ხილულ სიმპტომზე, SLO-ზე მიბმულით alert HighErrorRate { when errors / requests > 1% // ოქროს სიგნალი for 5m // ერთჯერად ხტუნვაზე არ აწკმუტუნდეს then page("on-call") // შეცდომების ბიუჯეტი იწვის }

როგორც  მანქანის სამართავი პანელი: სიჩქარე, საწვავი, ძრავის ნათურა — სიმპტომები, რომლებზეც მოქმედებთ, და არა ათასი სენსორი მათ უკან. გამოძახება სიმპტომზე მოდის, არა ისეთ მიზეზზე, როგორიც „CPU 80%“-ია.

ინსტრუმენტების ლანდშაფტი

დაშბორდები · მეტრიკა

Grafana

ღია დაშბორდების შრე. მიმართეთ Prometheus-ზე (მეტრიკები), Loki-ზე (ლოგები) ან ტრეისებზე და ააწყეთ ის ერთი ეკრანი, რომელსაც მორიგე უყურებს — ოქროს სიგნალები, SLO-ს წვა, რიგის სიღრმე — და იქვე მიაბით გაფრთხილების წესები.

APM · ტრეისები

Dynatrace

სრული სტეკის, ძირითადად ავტომატური დაკვირვებადობა: აგენტს დებთ, ის სერვისებს თავად აღმოაჩენს და განაწილებულ ტრეისებს ერთმანეთს უკავშირებს, ძირეული მიზეზის AI-დახმარებით ძიებით. ეს არის „იყიდე და ნუ ააგებ“ პოლუსი — Datadog და New Relic მისი თანატოლებია.

აფთაიმი · სინთეტიკა

აფთაიმის მონიტორინგი

შემოწმებები თქვენი ქსელის გარედან — ყოველ წუთს ჯანმრთელობის ენდპოინტს აკითხავს, გაფრთხილებას აგზავნის, როცა ის მიუწვდომელია ან ნელია, და საჯარო სტატუსის გვერდს კვებავს. Pingdom, UptimeRobot, Better Stack. პასუხობს ერთადერთ კითხვას, რომელიც მომხმარებელს აინტერესებს: მუშაობს?

08 · სრული მაგალითი და შეჯამება 5 წთ

შევკრათ ერთად:
დააპროექტეთ ბმულის შემმოკლებელი.

მოტყუებით პატარა ამოცანა, რომელიც ყველა შრეს ეხება, რაზეც ვისაუბრეთ — POST-ით გრძელ URL-ს აგზავნით და მოკლე კოდს იღებთ; GET /code კი გადამისამართებას აკეთებს. წაკითხვებით დატვირთული, შეყოვნებაზე მგრძნობიარე და არასდროს უნდა დაკარგოს ერთი შესაბამისობაც.

ნაბიჯი 1 · ბირთვი

დააგენერირეთ კოდი, შეინახეთ შესაბამისობა

აიღეთ უნიკალური 64-ბიტიანი id (მრიცხველიდან ან id-სერვისიდან) და base62-ით დააკოდეთ მოკლე სტრიქონად. შეინახეთ code → longUrl ბაზაში — ეს არის ჭეშმარიტების წყარო.

function shorten(longUrl: string): string {
  const id = ids.next()       // unique 64-bit
  const code = base62(id)    // "3Bk9" — short & unique
  db.put(code, longUrl)
  return `short.ly/${code}`
}
ნაბიჯი 2 · წაკითხვის გზა

გადამისამართებაზე წაკითხვები 100:1-თან — დააქეშირეთ

ძებნა შექმნას მრავალჯერ აღემატება. ბაზის წინ დააყენეთ cache-aside შრე code-ზე; შესაბამისობები უცვლელია, ამიტომ ქეშირებული ჩანაწერები არასდროს ძველდება. გადამისამართება მეხსიერებიდან გასცით.

async function resolve(code: string): Promise<string | null> {
  return await cache.get(code)
      ?? await db.get(code)   // miss → backfill
}
// immutable mapping → no invalidation problem

როგორ უკავშირდება ყოველი ნაწილი საუბარს

  • მასშტაბირება — უმდგომარეო ამომხსნელი ნოუდები ბალანსერის უკან; ტრაფიკის ზრდასთან ერთად ნოუდებს ამატებთ.
  • ქეშირება — ქეში code-ზე გადამისამართებების უმეტესობას მეხსიერებიდან გასცემს; უცვლელობა ამას სრულიად მარტივს ხდის.
  • მონაცემთა ბაზები — რეპლიკები წაკითხვების ნიაღვარს იწოვს; დაშარდეთ code-ით მაშინ, როცა ერთი ნოუდი გასაღებების სივრცეს ვეღარ იტევს.
  • ასინქრონი — კლიკების დათვლა რიგზე გადაიტანეთ; ანალიტიკამ გადამისამართება არასდროს უნდა შეანელოს.
  • CAP — ამოხსნა მშვიდად AP-ია (თუ ახლადშექმნილი ბმული წამით ვერ მოიძებნა, ეს ნორმალურია); id-გენერატორი კი CP რჩება, რომ კოდები არასდროს განმეორდეს.

წაიკითხეთ მთელი ნაკადი

მოხვდით ქეშში (მწვანე) და დააბრუნეთ; აცდენა რეპლიკამდე ჩადის; კლიკები ასინქრონულად რიგში მიდის.

ექვსი წესი, რომელიც თან უნდა წაიღოთ

1დააპროექტეთ ზრდისა და ჩავარდნისთვის. გააუმჯობესეთ კუდის შეყოვნება და იმას დაეყრდნონ, რომ რაღაც ყოველთვის მწყობრიდანაა.
2გაიზარდეთ განიერად, დარჩით უმდგომარეო. ბევრი პატარა ყუთი ბალანსერის უკან სჯობს ერთ დიდს, რომლის ჩანაცვლებაც არ შეგიძლიათ.
3დააქეშირეთ წაკითხვები, გახსოვდეთ ინვალიდაცია. ყველაზე სწრაფი შეკითხვა ის არის, რომელსაც არასდროს უშვებთ — მაგრამ მოძველებული ქეში ბაგია.
4წაკითხვისთვის დაარეპლიცირეთ, ჩაწერისთვის დაშარდეთ და ნელი სამუშაო რიგის მიღმა გაიტანეთ.
5იცოდეთ თქვენი CAP-არჩევანი. CP ფულისთვის, AP ლენტებისთვის. უფასო სადილი არ არსებობს — მხოლოდ სწორი გაცვლა.
6ვერ გაასწორებთ იმას, რასაც ვერ ხედავთ. გაზომეთ ოქროს სიგნალები, გატრეისეთ სერვისებს შორის და გაფრთხილება მომხმარებლისთვის ხილულ სიმპტომებზე დააყენეთ — Grafana, APM, აფთაიმის შემოწმება.

გააგრძელეთ

  • Designing Data-Intensive Applications — Martin Kleppmann (კანონიკური საცნობარო წიგნი)
  • The System Design Primer — ღია კოდი GitHub-ზე, უფასოდ
  • Site Reliability Engineering — Google (SLO-ები, შეცდომების ბიუჯეტები)
  • High Scalability — რეალური არქიტექტურების შემთხვევების გარჩევა

ერთი წინადადება დასამახსოვრებლად

"მასშტაბირება არ არსებობს, არსებობს მხოლოდ კომპრომისები — დაასახელეთ ის, რომელსაც თქვენ დებთ."

— მთელი საუბარი, შეკუმშული

ცოდნის შემოწმება

კომპრომისები დაგამახსოვრდათ?

ხუთი სწრაფი კითხვა მასშტაბირებაზე, ქეშირებაზე, მონაცემთა ბაზებსა და CAP-არჩევანზე — მყისიერი პასუხი, ავტორიზაციის გარეშე.

შეაფასეთ ეს დასტა
იყავით პირველი

ნავიგაცია ← → ღილაკებით ან სქროლით · ნაწილი 2: მოწინავე სისტემური დიზაინი → · უკან ბიბლიოთეკაში