Mağazamızın saytı hər dəqiqə minlərlə hadisə yaradır: Leyla kataloqu açdı, Aysel malı səbətə qoydu, Murad ödənişə çatdı. Analitika ən çox baxılan səhifələri hesablayır, sabah isə komandaya bir həftənin bütün baxışlarına ehtiyacı olan tövsiyə servisi lazım olacaq. RabbitMQ növbəsi burada kömək etməz: mesaj ack-dan sonra yox olur, onu yenidən oxumaq olmur. Belə tapşırıqlar üçün Apache Kafka yaradılıb. Jurnalın növbədən nə ilə fərqləndiyini, topic, partition və offset-in nə olduğunu öyrənəcək, Kafka-nı Docker-də işə salacaq və Node.js-də ilk producer və consumer yazacağıq.
Növbə, yoxsa jurnal
RabbitMQ növbəsi sifariş vərəqləri dəstinə bənzəyir: aşpaz vərəqi götürdü, yerinə yetirdi və atdı. Kafka isə jurnaldır (log): qeydlərin yalnız sona əlavə olunduğu, heç nəyin silinmədiyi dəftər. Hər oxuyanın öz əlfəcini var və o, özü seçdiyi yerdən oxuyur. Oxunmuş qeyd yerində qalır: həmin səhifəni başqa oxucu da, sabah elə həmin oxucu da aça bilər.
| Meyar | Növbə (RabbitMQ) | Jurnal (Kafka) |
|---|---|---|
| Oxunandan sonra | mesaj ack-dan sonra silinir | hadisə saxlama müddəti bitənə qədər qalır |
| Oxuyanlar | mesajlara görə rəqabət aparır | hər birinin öz əlfəcini (offset) var |
| Təkrar oxuma | mümkün deyil | əlfəcini geri çəkmək kifayətdir |
| Ardıcıllıq | növbədə, consumer tək olduqda | hər partition daxilində |
| Tipik tapşırıq | tapşırıq və komandalar: məktub, fayl emalı | hadisə axınları: klik, sifariş, log |
Topic, partition və offset
Bütün Kafka dörd anlayışa söykənir:
- Hadisə (event, record) — jurnalın qeydi: açar
key, dəyərvalue(adətən JSON), vaxt və könüllü başlıqlar. Kafka üçün bunlar sadəcə baytlardır. - Topic — eyni tipli hadisələrin adlı jurnalı, məsələn,
page-views. - Partition — topic-in hissəsi: hadisələrin yalnız əlavə edildiyi müstəqil jurnal. Bu, paralellik vahidi və ardıcıllıq vahididir.
- Offset — hadisənin partition daxilindəki nömrəsi: 0, 1, 2… Nömrələr təkrar istifadə olunmur. Hadisənin ünvanı — «topic + partition + offset».
Offset hər partition-da ayrıca sayılır. Jurnal modeli JavaScript-in bir neçə sətridir:
// one partition = an array that only grows
const partition = [];
function append(event) {
partition.push(event);
return partition.length - 1; // the offset of the new event
}
append({ user: 'Leyla', page: '/home' });
append({ user: 'Aysel', page: '/cart' });
append({ user: 'Leyla', page: '/cart' });
// a reader remembers only a bookmark: the next offset to read
let offset = 0;
while (offset < partition.length) {
const { user, page } = partition[offset];
console.log(`offset ${offset}: ${user} opened ${page}`);
offset++;
}
// reading removed nothing: move the bookmark back and read again
offset = 1;
console.log(`replay from ${offset}:`, partition[offset].user);Proqramın çıxışı:
offset 0: Leyla opened /home
offset 1: Aysel opened /cart
offset 2: Leyla opened /cart
replay from 1: Aysel