ბიბლიოთეკა
00/07 · ~36 წთ
GUIDEDECK · მონაცემები მოძრაობაში

შეტყობინებების რიგები &
ნაკადები — მოვლენების გადატანა
სისტემებს შორის, რომლებიც ერთმანეთს არ ელოდებიან.

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

~36 წთმონაცემთა გუნდიKafka-ზე ფოკუსით
გადაახვიეთ
01 · რატომ არსებობს რიგი და ნაკადი 4 წთ

როცა ერთი სერვისი მეორეს პირდაპირ იძახებს,
ისინი ერთად დგებიან და ვარდებიან.

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

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

სინქრონული vs. ასინქრონული

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

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

პირდაპირი გამოძახება — შეკრული
async function placeOrder(o) {
  await save(o)
  await email.sendReceipt(o)    // blocks…
  await inventory.reserve(o)    // blocks…
  await analytics.track(o)      // if this is down, checkout fails
}
მოვლენას აქვეყნებს — გამიჯნული
async function placeOrder(o) {
  await save(o)
  await broker.publish("order.placed", o)  // one write, returns fast
}
// email, inventory, analytics each consume on their own
// one of them being down can't fail the checkout

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

02 · ბროკერის ორი ფორმა 5 წთ

რიგი სამუშაოს ერთხელ არიგებს.
ლოგს ყველაფერი ახსოვს.

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

სამუშაო რიგი — თითოეული შეტყობინება ერთ კონსიუმერს მიეწოდება და შემდეგ იშლება; ბროკერი თვალს ადევნებს, რა შესრულდა. ლოგი (მოვლენების ლოგი / commit log) მხოლოდ დამატებადი მიმდევრობაა: შეტყობინებები ინახება შენახვის ფანჯრის განმავლობაში და კონსიუმერები საკუთარ პოზიციას ოფსეტით აღრიცხავენ, ასე რომ ერთსა და იმავე შეტყობინებას ბევრი კონსიუმერი კითხულობს და მოგვიანებით ხელახლაც იკითხება.
WORK QUEUE — consume once, then gone m3 m2 m1 worker m1 acked → deleted LOG — append-only, replayable 0 1 2 3 4 5 → append A @3 B @1 each reader keeps its own offset

რიგი შლის m1-ს, როგორც კი მუშა მას ადასტურებს. ლოგი ყველა შეტყობინებას ინახავს; მკითხველები A და B სხვადასხვა ოფსეტზე დგანან და უკან დახევა შეუძლიათ.

რაში ვარგა თითოეული

  • რიგი — ამოცანების განაწილება. „შეცვალე ამ სურათის ზომა“, „გააგზავნე ეს წერილი“. ერთი სამუშაო, ერთი მუშა და დასრულდა. დაამატეთ მუშები, რომ დაგროვილი უფრო სწრაფად ამოიწუროს.
  • ლოგი — მოვლენების ისტორია, რომელიც ბევრ სისტემას აინტერესებს. ელფოსტა, მარაგები და ანალიტიკა ერთსა და იმავე order.placed ნაკადს დამოუკიდებლად კითხულობენ.
  • გამეორება ლოგის სუპერძალაა: ხვალ დაამატეთ ახალი კონსიუმერი და მიეცით საშუალება, ოფსეტ 0-დან წაიკითხოს და მდგომარეობა სრული ისტორიიდან აღიდგინოს.
  • რიგს გამეორება არ შეუძლია — დადასტურებული და წაშლილი შეტყობინება დაკარგულია. ეს ამოცანებისთვის უპირატესობაა, მოვლენებისთვის — შეზღუდვა.
ოფსეტი — შეტყობინების თანმიმდევრული პოზიცია ლოგში (0, 1, 2, …). კონსიუმერი „აკომიტებს“ იმ ოფსეტს, რომლამდეც დაამუშავა; ეს სანიშნეა ერთადერთი, რაც კონსიუმერს ლოგთან აკავშირებს. გადაწიეთ სანიშნე უკან და გაიმეორებთ; თავად ბროკერი არასოდეს იცვლება.
03 · ლოგი, მასშტაბირებული 6 წთ

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

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

თემა — დასახელებული ნაკადი (order.placed). დანაწილება — ერთი თემა იყოფა N დალაგებულ ლოგად, და სწორედ დანაწილებები აძლევს თემას მანქანებზე მასშტაბირების საშუალებას. ოფსეტი — პოზიცია დანაწილების შიგნით. კონსიუმერთა ჯგუფი — კონსიუმერების ერთობლიობა, რომლებიც თემის სამუშაოს ინაწილებენ, სადაც თითოეულ დანაწილებას ჯგუფის ზუსტად ერთი წევრი კითხულობს.
P0 P1 P2
დანაწილება = ერთი დალაგებული ლოგი
პროდიუსერი
გასაღები→ჰეში
0
1
2
0
1
კონსიუმერი 1
კონსიუმერი 2
0
1
2
კონსიუმერი 3
თემა: order.placed
ჯგუფი: billing
ერთი დანაწილება → ჯგუფის ერთი კონსიუმერი

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

როგორ ეწყობა ნაწილები

  • თანმიმდევრობა დანაწილების დონეზეა, არა თემის. ერთი დანაწილების შიგნით შეტყობინებები მკაცრად დალაგებულია; დანაწილებებს შორის — არანაირი გარანტია.
  • გასაღები წყვეტს დანაწილებას. ერთი გასაღები (მაგალითად, customer_id) → ერთი დანაწილება → ამ კლიენტისთვის თანმიმდევრობა დაცულია. გასაღების გარეშე → რიგრიგობით.
  • დანაწილება პარალელიზმის ერთეულია. ექვსი დანაწილება ნიშნავს, რომ ჯგუფში მაქსიმუმ ექვსი კონსიუმერი მუშაობს პარალელურად — ზედმეტები უსაქმოდ დგანან.
  • ჯგუფები ორივე პატერნს გაძლევთ. ერთი ჯგუფი = სამუშაო რიგი (სამუშაო იყოფა). ბევრი ჯგუფი ერთ თემაზე = pub/sub (თითოეული ჯგუფი ყველა შეტყობინებას იღებს).
// producer — the key pins related events to one partition
await producer.send({
  topic: "order.placed",
  messages: [{ key: order.customerId, value: JSON.stringify(order) }],
})

// consumer — joins a group; Kafka assigns it partitions
await consumer.subscribe({ topic: "order.placed" })
await consumer.run({
  groupId: "billing",
  eachMessage: async ({ message }) => charge(message),
})

ორი ჯგუფი ერთ თემაზე: billing და analytics თითოეული სრულ ნაკადს იღებს, დამოუკიდებლად.

04 · მნიშვნელოვანი გარანტიები 6 წთ

შეტყობინებები იკარგება, ან
შეტყობინებები ორმაგდება. აირჩიეთ.

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

მიწოდების სემანტიკა — გარანტია, რომელსაც სისტემა იძლევა იმაზე, რამდენჯერ მუშავდება შეტყობინება: at-most-once (0 ან 1 — შეიძლება დაიკარგოს), at-least-once (1 ან მეტი — შეიძლება გაორმაგდეს) ან exactly-once (ზუსტად 1 — ყველაზე რთული და უფრო ვიწრო, ვიდრე ჟღერს).
წაკითხვა
კომიტი @5
კრახი
წაკითხვა
დამუშავება
კრახი
კომიტი სამუშაომდე → at-most-once
სამუშაო არ გაშვდა;
დაიკარგა ✕
კომიტი სამუშაოს მერე → at-least-once
ოფსეტი არ დაკომიტდა →
ხელახლა მიიტანს → ორჯერ დამუშავდა ✕
გამოსავალი: სამუშაო იდემპოტენტური → effectively exactly-once

დააკომიტეთ ოფსეტი ჯერ და კრახი შეტყობინებას დაკარგავს. დააკომიტეთ ბოლოს და კრახი მას ხელახლა მოიტანს. სატრანსპორტო შრეზე მესამე ვარიანტი არ არსებობს.

რატომ არის exactly-once დახვეწილი საკითხი

  • at-least-once გონივრული ნაგულისხმევია. დაკარგული მონაცემები ჩვეულებრივ დუბლირებულზე უარესია, დუბლიკატები კი გამოსწორებადია.
  • ნამდვილი exactly-once მოითხოვს, რომ ბროკერმა და თქვენმა დამუშავებამ ერთი ტრანზაქცია გაიზიარონ. Kafka მას Kafka-დან Kafka-ში ნაკადების დამუშავებისთვის გთავაზობთ — და არა იმ წერილისთვის, გარე სამყაროში რომ აგზავნით.
  • პრაქტიკული პასუხი არის at-least-once მიწოდება პლუს იდემპოტენტური კონსიუმერი: დაამუშავეთ ორჯერ და იმავე მდგომარეობაში აღმოჩნდებით. ეს არის „effectively-once“.
იდემპოტენტური კონსიუმერი — ისეთი, სადაც ერთი და იმავე შეტყობინების ორჯერ დამუშავებას იგივე ეფექტი აქვს, რაც ერთხელ დამუშავებას. ჩვეული ხრიკი: დედუპლიკაცია შეტყობინების სტაბილური id-ით, ან ჩაწერა upsert-ით ბიზნეს-id-ზე მიბმულად — იგივე იდემპოტენტურობის იდეა ETL & ELT პაიპლაინების დეკიდან, ახლა თითო შეტყობინებაზე გამოყენებული.
ბრმა ჰენდლერი — დუბლი აფუჭებს მდგომარეობას
eachMessage(msg) {
  const o = JSON.parse(msg.value)
  ledger.addCharge(o.amount)   // redelivery ⇒ charged twice
}
// at-least-once + non-idempotent = double billing
იდემპოტენტური — გამეორება უვნებელია
eachMessage(msg) {
  const o = JSON.parse(msg.value)
  ledger.upsertCharge({
    id: o.orderId,            // dedupe key
    amount: o.amount,
  })                          // same id ⇒ same single row
}
05 · რა კბენს პროდაქშენში 6 წთ

ბროკერი მარტივია.
ტკივილი კიდეებშია.

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

O
რიგითობა
თანმიმდევრობა დანაწილების დონეზეა — დაიცავით გასაღებით.
+

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

გასაღების გარეშე — არევა
producer.send({ topic: "order.events",
  messages: [{ value: evt }] })   // round-robin partition
// paid & shipped may land in different partitions
გასაღები ერთეულზე — რიგი დაცულია
producer.send({ topic: "order.events",
  messages: [{ key: evt.orderId, value: evt }] })
// same orderId ⇒ same partition ⇒ ordered
B
ჩამორჩენა და უკუწნევა
პროდიუსერებმა შეიძლება კონსიუმერებს გაასწრონ.
+

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

  • თვალი ადევნეთ ჩამორჩენას — ეს ნაკადის ჯანმრთელობის საუკეთესო ერთადერთი მეტრიკაა; დააყენეთ გაფრთხილება, როცა ის იზრდება და აღარ ბრუნდება.
  • დაამატეთ კონსიუმერები დანაწილებების რაოდენობამდე — მის მიღმა ჯერ დანაწილებები დაამატეთ.
  • ჩუმად ნუ დაკარგავთ. ლოგი აფეთქებებს შენახვის ბუფერში იწოვს; ეს ბუფერი ამორტიზატორია და არა ადგილი, სადაც ბოლოდან უნდა გადავარდეთ.
D
dead-letter რიგი
იზოლირეთ შეტყობინება, რომელიც ყოველთვის ვარდება.
+

შხამიანი შეტყობინება — დაზიანებული ან ისეთი, რომელიც ყოველთვის შეცდომას აგდებს — უსასრულოდ განმეორდება და დაბლოკავს ყველაფერს, რაც მის უკან დგას. შეზღუდეთ ხელახალი მცდელობები, შემდეგ კი გადაიტანეთ dead-letter რიგში (DLQ), რომ ნაკადის დანარჩენი ნაწილი დინებას აგრძელებდეს და უარყოფილი შეტყობინება ადამიანმა მოგვიანებით შეამოწმოს.

eachMessage(msg) {
  try { handle(msg) }
  catch (e) {
    if (msg.attempts >= 5) await dlq.send(msg)  // quarantine
    else throw e                                 // retry
  }
}
R
გამეორება და დამუშავება
გადაწიეთ ოფსეტი უკან, რომ მდგომარეობა აღადგინოთ.
+

ტრანსფორმაციის ბაგი გაუშვით პროდაქშენში? რადგან ლოგი ისტორიას ინახავს, შეგიძლიათ ჯგუფის ოფსეტი დააბრუნოთ და ხელახლა წაიკითხოთ. ახალი კონსიუმერი, რომელსაც სრული წარსული სჭირდება? დაიწყეთ ოფსეტ 0-დან. გამეორება მხოლოდ მაშინ მუშაობს, თუ თქვენი კონსიუმერები იდემპოტენტურია (ნაწილი 4) — თორემ დუბლიკატებსაც გაიმეორებთ.

# analytics ჯგუფის დაბრუნება თემის დასაწყისში kafka-consumer-groups --reset-offsets --to-earliest \ --group analytics --topic order.placed --execute
S
სქემის დრიფტი
შეცვლილი შეტყობინების ფორმა ყველა კონსიუმერს ტეხს.
+

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

რამდენიმე წარუმატებელი მცდელობის შემდეგ შხამიანი შეტყობინება dead-letter რიგში გადაინაცვლებს — ნაკადის დანარჩენი ნაწილი არასოდეს იბლოკება.

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

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

ბაზარი სუფთად იყოფა მე-2 ნაწილის რიგი-vs-ლოგი ხაზზე, რომელსაც ჯვარედინად ედება ის, თუ რამდენის ოპერირება გსურთ თავად. აი, წამყვანი სისტემები — თითოეული ერთსტრიქონიანი ძლიერი მხარითა და ხაფანგით.

გამეორებადი ლოგი

Apache Kafka

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

სამუშაო რიგი

RabbitMQ

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

მართული · AWS

SQS & Kinesis

დადებითი — სრულად მართული, თითქმის ნულოვანი ოპერაციებით: SQS მარტივი რიგებისთვის, Kinesis ლოგის/ნაკადის ფორმისთვის.
უარყოფითი — AWS-ზე მიბმა; Kafka-ზე ნაკლები ფუნქციონალი და ეკოსისტემა, ღირებულება კი მოხმარებასთან ერთად იზრდება.

ლოგი + რიგი

Apache Pulsar

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

Kafka-თავსებადი

Redpanda

დადებითი — Kafka-ს API-ზე საუბრობს, მაგრამ ერთი ბინარია (არც JVM, არც ცალკე კოორდინატორი); უფრო მარტივი გასაშვები, ნაკლები შეყოვნებით.
უარყოფითი — ახალგაზრდა პროექტი და პატარა ეკოსისტემა; ბირთვი ღიაა, ზოგი ფუნქციონალი კომერციული.

მარტივი წესი

ნაგულისხმევი არჩევანი

უკვე AWS-ზე ხართ და ოპერაციები არ გინდათ? SQS / Kinesis. გჭირდებათ ნამდვილი მოვლენების ლოგი და თქვენივე ინფრასტრუქტურა? Kafka (ან Redpanda უფრო მსუბუქი გაშვებისთვის). კლასიკური ამოცანების რიგი მდიდარი მარშრუტიზაციით? RabbitMQ.

როგორ ავირჩიოთ — დაიწყეთ მე-2 ნაწილიდან: გჭირდებათ გამეორება და ერთი და იმავე ისტორიის რამდენიმე დამოუკიდებელი მკითხველი? მაშინ ეს ლოგია — Kafka, Redpanda, Kinesis ან Pulsar. უბრალოდ ცალკეული ამოცანების მუშებისთვის გადაცემა გინდათ? მაშინ ეს რიგია — RabbitMQ ან SQS. შემდეგ აწონეთ ოპერაციები: მართული სერვისი (SQS, Kinesis ან ჰოსტირებული Kafka/Redpanda) ფულსა და ვენდორზე მიბმას ცვლის გაცილებით ნაკლებ სამართავზე; თვითჰოსტინგი ძალისხმევას ცვლის კონტროლსა და პორტაბელურობაზე. გამტარუნარიანობასა და გამეორებაზე მხოლოდ მაშინ გაამახვილეთ ყურადღება, როცა დატვირთვას ისინი ნამდვილად სჭირდება — გუნდების უმეტესობა Kafka-ს იმ შემთხვევაშიც სწვდება, როცა რიგიც საკმარისი იქნებოდა.
07 · ყველაფერი ერთად 4 წთ

ერთი მოვლენა შედის,
ბევრი რეაქცია გამოდის.

მივყვეთ ერთადერთ order.placed მოვლენას ყველაფერში, რაც განვიხილეთ: ერთხელ გამოქვეყნებული, კლიენტის მიხედვით დანაწილებული, დამოუკიდებელი ჯგუფების მიერ წაკითხული, თითოეული იდემპოტენტური, უარყოფილებისთვის კი DLQ.

Checkout producer order.placed P0 ▸▸▸ P1 ▸▸▸ key = customerId billing email inventory analytics dead-letter each group: own offset, idempotent, replayable

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

1ჩასვით ბროკერი სერვისებს შორის, რომ ისინი დროში გამიჯნოთ — პროდიუსერი კონსიუმერთან ერთად არ უნდა დგებოდეს და ვარდებოდეს.
2რიგი ამოცანებისთვის, ლოგი მოვლენებისთვის. გჭირდებათ გამეორება და ბევრი დამოუკიდებელი მკითხველი? ეს ლოგია (Kafka). ერთი სამუშაო, ერთი მუშა? რიგი.
3თანმიმდევრობა დანაწილებაში ცხოვრობს. გასაღებად აიღეთ ის ერთეული, რომლის თანმიმდევრობაც გჭირდებათ; დანაწილება ამავე დროს პარალელიზმის ერთეულია.
4დაუშვით at-least-once; ააგეთ იდემპოტენტური კონსიუმერები. ეს კომბინაცია „effectively-once“-ს გაძლევთ exactly-once-ის წვრილი შრიფტის გარეშე.
5გაითვალისწინეთ კიდეები. აკონტროლეთ ჩამორჩენა, შხამიანი შეტყობინებები DLQ-ში გაიტანეთ, სქემები თავსებადად განავითარეთ და გამეორება უსაფრთხო შეინარჩუნეთ.

გააგრძელეთ

  • Kafka: The Definitive Guide — Narkhede, Shapira & Palino
  • Designing Data-Intensive Applications — Kleppmann (თავი 11, ნაკადების დამუშავება)
  • ETL & ELT პაიპლაინები — პარტიული vs ნაკადური დამუშავება და იდემპოტენტურობა მონაცემთა ნაკადში
  • სისტემების დიზაინი — სად ჯდება ასინქრონული შეტყობინებები დიდ სურათში

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

„მოვლენა ერთხელ გამოაქვეყნეთ; დაე, ყველამ თავის საათზე წაიკითხოს.“

— მთელი მოხსენება, შეკუმშული

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

დაგამახსოვრდათ?

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

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

ნავიგაცია ← → ღილაკებით ან სქროლით · უკან ბიბლიოთეკაში