Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Kolaylaştırılmış bir süreç ve düzinelerce birbirine bağlı hizmete sahip Lamoda gibi büyük bir şirketi yaklaşımını önemli ölçüde değiştirmeye ne zorlayabilir? Motivasyon tamamen farklı olabilir: yasama aşamasından tüm programcıların doğasında bulunan deneme arzusuna kadar.

Ancak bu, ek avantajlara güvenemeyeceğiniz anlamına gelmez. Sergey Zaika, olay odaklı API'yi Kafka'ya uygularsanız tam olarak ne kazanabileceğinizi size söyleyecektir (az sayıda). Ayrıca büyük çekimler ve ilginç keşifler hakkında da kesinlikle konuşulacak - deney onlarsız yapamaz.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Yasal Uyarı: Bu makale, Sergey'in Kasım 2018'de HighLoad++ üzerinde gerçekleştirdiği bir buluşmadan elde edilen materyallere dayanmaktadır. Lamoda'nın Kafka'yla çalışma konusundaki canlı deneyimi, programdaki diğer haberler kadar dinleyicilerin ilgisini çekti. Bunun, her zaman sizin gibi düşünen insanları bulabileceğiniz ve bulmanız gerektiği gerçeğinin mükemmel bir örneği olduğunu düşünüyoruz ve HighLoad++ organizatörleri buna olanak sağlayan bir atmosfer yaratmaya çalışmaya devam edecek.

Süreç hakkında

Lamoda, kendi iletişim merkezine, teslimat hizmetine (ve birçok bağlı kuruluşa), bir fotoğraf stüdyosuna, büyük bir depoya sahip olan ve tüm bunların kendi yazılımı üzerinde çalıştığı büyük bir e-ticaret platformudur. Bu hizmetlerin bir kısmını veya tamamını kullanabilen ve ürünleri hakkında güncel bilgi edinmek isteyen onlarca ödeme yöntemi, b2b iş ortağı bulunmaktadır. Ayrıca Lamoda, Rusya Federasyonu dışında üç ülkede de faaliyet gösteriyor ve orada her şey biraz farklı. Toplamda, kendi yöntemiyle işlenmesi gereken yeni bir siparişi yapılandırmanın muhtemelen yüzden fazla yolu vardır. Tüm bunlar, bazen açık olmayan yollarla iletişim kuran düzinelerce hizmetin yardımıyla çalışır. Ayrıca asıl sorumluluğu sipariş durumları olan merkezi bir sistem de bulunmaktadır. Ona BOB diyoruz, onunla çalışıyorum.

Olaylara dayalı API'ye sahip Geri Ödeme Aracı

Olaylara dayalı kelimesi oldukça basmakalıptır; biraz daha ileride bununla ne kastedildiğini daha ayrıntılı olarak tanımlayacağız. Kafka'da olay odaklı API yaklaşımını denemeye karar verdiğimiz bağlamla başlayacağım.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Herhangi bir mağazada, müşterilerin ödediği siparişlere ek olarak, ürünün müşteriye uygun olmaması nedeniyle mağazanın parayı iade etmesi gereken zamanlar vardır. Bu nispeten kısa bir süreç: Gerekirse bilgileri netleştiriyoruz ve parayı aktarıyoruz.

Ancak mevzuattaki değişiklikler nedeniyle geri dönüş daha karmaşık hale geldi ve bunun için ayrı bir mikro hizmet uygulamak zorunda kaldık.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Motivasyonumuz:

  1. Kanun FZ-54 - kısacası kanun, ister iade ister makbuz olsun her parasal işlemin birkaç dakika gibi oldukça kısa bir SLA içerisinde vergi dairesine bildirilmesini gerektirmektedir. Bir e-ticaret firması olarak oldukça fazla işlem gerçekleştiriyoruz. Teknik olarak bu, yeni sorumluluk (ve dolayısıyla yeni bir hizmet) ve ilgili tüm sistemlerde iyileştirmeler anlamına gelir.
  2. BOB bölünmesi BOB'u çok sayıda temel olmayan sorumluluktan kurtarmak ve genel karmaşıklığını azaltmak için şirketin dahili bir projesidir.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Bu diyagram ana Lamoda sistemlerini göstermektedir. Artık çoğu daha fazla küçülen bir monolitin etrafında 5-10 mikro hizmetten oluşan bir takımyıldız. Yavaş yavaş büyüyorlar ama biz onları küçültmeye çalışıyoruz çünkü ortada seçilen parçayı yerleştirmek korkutucu, düşmesine izin veremeyiz. Tüm borsaları (oklar) rezerve etmek zorunda kalıyoruz ve bunlardan herhangi birinin kullanılamayabileceğini hesaba katıyoruz.

BOB'un ayrıca oldukça fazla borsası var: ödeme sistemleri, dağıtım sistemleri, bildirim sistemleri vb.

Teknik olarak BOB:

  • ~150 bin kod satırı + ~100 bin test satırı;
  • php7.2 + Zend 1 ve Symfony Bileşenleri 3;
  • >100 API ve ~50 giden entegrasyon;
  • Kendi iş mantığına sahip 4 ülke.

BOB'u dağıtmak pahalı ve acı vericidir, çözdüğü kod ve problemlerin miktarı o kadar fazladır ki, hiç kimse bunların hepsini aklına koyamaz. Genel olarak basitleştirmenin birçok nedeni vardır.

İade Süreci

Başlangıçta sürece iki sistem dahil oluyor: BOB ve Ödeme. Şimdi iki tane daha görünüyor:

  • Malileştirme ve dış hizmetlerle iletişim sorunlarıyla ilgilenecek Malileştirme Hizmeti.
  • BOB'u şişirmemek için sadece yeni takaslar içeren Geri Ödeme Aracı.

Şimdi süreç şöyle görünüyor:

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

  1. BOB geri ödeme talebi alır.
  2. BOB bu Geri Ödeme Aracından bahsediyor.
  3. Geri Ödeme Aracı, Ödemeye şunu söyler: "Parayı iade edin."
  4. Ödeme parayı iade eder.
  5. Geri Ödeme Aracı ve BOB durumları birbirleriyle senkronize eder çünkü şimdilik ikisinin de buna ihtiyacı vardır. BOB'un bir kullanıcı arayüzü, muhasebe raporları ve genel olarak bu kadar kolay aktarılamayan birçok verisi olduğundan Geri Ödeme Aracına tamamen geçmeye henüz hazır değiliz. İki sandalyeye oturmanız gerekiyor.
  6. Malileştirme talebi ortadan kalkar.

Sonuç olarak Kafka'da her şeyin başladığı bir tür olay otobüsü - olay otobüsü - yaptık. Yaşasın, artık tek bir başarısızlık noktamız var (alaycılık).

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Artıları ve eksileri oldukça açık. Otobüs yaptık, yani artık tüm hizmetler ona bağlı. Bu, tasarımı basitleştirir ancak sisteme tek bir arıza noktası getirir. Kafka çökecek, süreç duracak.

Olaylara dayalı API nedir?

Bu sorunun güzel bir yanıtı Martin Fowler'ın raporundadır (GOTO 2017) "Olay Odaklı Mimarinin Birçok Anlamı".

Kısaca yaptıklarımız:

  1. Tüm eşzamansız değişimleri şununla tamamlayın: olaylar depolama. İlgili her tüketiciyi ağ üzerinden bir durum değişikliği hakkında bilgilendirmek yerine, merkezi bir depolama birimine durum değişikliği hakkında bir olay yazıyoruz ve konuyla ilgilenen tüketiciler oradan görünen her şeyi okuyor.
  2. Bu durumda olay bir bildirimdir (bildirimleri) bir yerlerde bir şeylerin değiştiğini. Örneğin sipariş durumu değişti. Bildirimde yer almayan durum değişikliğine eşlik eden bazı verilerle ilgilenen tüketici, durumun durumunu kendisi öğrenebilir.
  3. Maksimum seçenek tam teşekküllü olay kaynağı kullanımıdır, devlet transferi, bu durumda işleme için gerekli tüm bilgiler bulunur: nereden geldiği ve hangi duruma gittiği, verilerin tam olarak nasıl değiştiği vb. Tek soru, fizibilite ve saklamayı karşılayabileceğiniz bilgi miktarıdır.

Geri Ödeme Aracı'nın lansmanı kapsamında üçüncü seçeneği kullandık. Bu, ayrıntılı bilgi çıkarmaya gerek olmadığından olay işlemeyi basitleştirdi, ayrıca her yeni olayın tüketicilerden açıklayıcı alım istekleri patlaması oluşturduğu senaryoyu da ortadan kaldırdı.

Geri Ödeme Aracı Hizmeti yüklü değilyani Kafka'da bir zorunluluktan ziyade kalemin tadı var. Eğer iade hizmeti yoğun bir proje haline gelirse iş dünyasının mutlu olacağını düşünmüyorum.

Asenkron değişim OLDUĞU GİBİ

Asenkron değişimler için PHP departmanı genellikle RabbitMQ'yu kullanır. İsteğe ilişkin verileri topladık, sıraya koyduk ve aynı hizmetin tüketicisi bunu okuyup gönderdi (veya göndermedi). API'nin kendisi için Lamoda, Swagger'ı aktif olarak kullanıyor. Bir API tasarlıyoruz, bunu Swagger'da tanımlıyoruz ve istemci ve sunucu kodu oluşturuyoruz. Ayrıca biraz geliştirilmiş bir JSON RPC 2.0 kullanıyoruz.

Bazı yerlerde ESB otobüsleri kullanılıyor, bazıları activeMQ'da yaşıyor, ancak genel olarak TavşanMQ - standart.

Asenkron değişim OLACAK

Olay veri yolu aracılığıyla alışverişi tasarlarken bir benzetme yapılabilir. Gelecekteki veri alışverişini benzer şekilde olay yapısı açıklamaları aracılığıyla açıklıyoruz. Yaml formatında, kod üretimini kendimiz yapmak zorundaydık, jeneratör spesifikasyona göre DTO'lar oluşturuyor ve istemcilere ve sunuculara bunlarla çalışmayı öğretiyor. Nesil iki dile geçiyor - golang ve php. Bu, kitaplıkların tutarlı kalmasına yardımcı olur. Jeneratör golang dilinde yazılmıştır, bu yüzden gogi adını almıştır.

Kafka'da olay kaynağı kullanmak tipik bir şeydir. Kafka Confluent'in ana kurumsal versiyonundan bir çözüm var, var nakadi, alan kardeşlerimiz Zalando'dan bir çözüm. Bizim vanilya Kafka ile başlama motivasyonu - bu, çözümü her yerde kullanıp kullanmayacağımıza karar verene kadar serbest bırakmak ve aynı zamanda manevra ve iyileştirmeler için kendimize alan bırakmak anlamına gelir: JSON RPC2.0, iki dil için jeneratörler ve bakalım başka neler var.

Böylesine mutlu bir durumda bile, kabaca benzer bir çözüm yapan Zalando adlı işletme varken, bunu etkili bir şekilde kullanamamamız ironik.

Başlangıçtaki mimari model şu şekildedir: Doğrudan Kafka'dan okuyoruz, ancak yalnızca olaylar veri yolu aracılığıyla yazıyoruz. Kafka'da okumaya hazır çok şey var: aracılar, dengeleyiciler ve yatay ölçeklendirmeye az çok hazır, bunu saklamak istedim. Kaydı bir Ağ Geçidi, diğer adıyla Events-bus aracılığıyla tamamlamak istedik ve işte nedeni bu.

Olaylar otobüsü

Veya bir etkinlik otobüsü. Bu sadece birkaç önemli rolü üstlenen durum bilgisi olmayan bir http ağ geçididir:

  • Doğrulama Üretmek — olayların spesifikasyonlarımıza uygun olup olmadığını kontrol ederiz.
  • Olay ana sistemiyani hangi olayların hangi yapılarla geçerli sayıldığı sorusuna cevap veren şirketteki ana ve tek sistemdir. Doğrulama, içeriği kesin olarak belirtmek için yalnızca veri türlerini ve numaralandırmaları içerir.
  • Özet fonksiyonu parçalama için - Kafka mesaj yapısı anahtar/değerdir ve anahtarın karması kullanılarak nereye yerleştirileceği hesaplanır.

Niye ya

Kolaylaştırılmış bir süreçle büyük bir şirkette çalışıyoruz. Neden bir şeyi değiştirelim ki? Bu bir deneyve birçok fayda elde etmeyi umuyoruz.

1:n+1 değişim (birden çoğa)

Kafka, yeni tüketicilerin API'ye bağlanmasını çok kolaylaştırıyor.

Diyelim ki aynı anda birden fazla sistemde (ve bazı yeni sistemlerde) güncel tutmanız gereken bir dizininiz var. Daha önce set-API uygulayan bir paket icat etmiştik ve ana sistem tüketici adreslerinden haberdar ediliyordu. Artık ana sistem konuya güncellemeler gönderiyor ve ilgilenen herkes onu okuyor. Yeni bir sistem ortaya çıktı - konuya kaydolduk. Evet, aynı zamanda paket, ancak daha basit.

BOB'un bir parçası olan iade aracında ise bunların Kafka üzerinden senkronize tutulması bizim için uygundur. Ödeme paranın iade edildiğini söylüyor: BOB, RT bunu öğrendi, durumlarını değiştirdi, Malileştirme Servisi bunu öğrenip çek düzenledi.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Müşteriyi siparişi/iadesi ile ilgili haberler hakkında bilgilendirecek birleşik bir Bildirim Hizmeti oluşturma planlarımız var. Artık bu sorumluluk sistemler arasında dağılmıştır. Bildirimler Hizmetine Kafka'dan ilgili bilgileri yakalayıp yanıt vermeyi (ve diğer sistemlerde bu bildirimleri devre dışı bırakmayı) öğretmemiz yeterli olacaktır. Yeni doğrudan değişim gerekmeyecek.

Veri tabanlı

Sistemler arasındaki bilgiler şeffaf hale gelir; ne kadar "kanlı bir işletmeye" sahip olursanız olun ve birikmiş iş yükünüz ne kadar dolgun olursa olsun. Lamoda, sistemlerden veri toplayan ve bunları hem iş hem de akıllı sistemler için yeniden kullanılabilir bir forma sokan bir Veri Analitiği departmanına sahiptir. Kafka, onlara hızlı bir şekilde çok sayıda veri vermenize ve bu bilgi akışını güncel tutmanıza olanak tanır.

Çoğaltma günlüğü

RabbitMQ'da olduğu gibi mesajlar okunduktan sonra kaybolmaz. Bir olay işlenmek üzere yeterli bilgi içerdiğinde, nesnede yapılan son değişikliklerin geçmişine ve istenirse bu değişiklikleri uygulama yeteneğine sahip oluruz.

Çoğaltma günlüğünün saklanma süresi bu konuya yazma yoğunluğuna bağlıdır; Kafka, depolama süresi ve veri hacmine ilişkin sınırları esnek bir şekilde belirlemenize olanak tanır. Yoğun konular için, kısa süreli çalışamama durumunda bile tüm tüketicilerin bilgiyi kaybolmadan önce okuyabilecek zamana sahip olması önemlidir. için veri depolamak genellikle mümkündür. gün birimleriBu destek için oldukça yeterli.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Daha sonra, Kafka'ya aşina olmayanlar için dokümantasyonun küçük bir yeniden anlatımı (resim de dokümantasyondan alınmıştır)

AMQP'nin kuyrukları vardır: mesajları tüketici için bir kuyruğa yazıyoruz. Tipik olarak bir kuyruk, aynı iş mantığına sahip bir sistem tarafından işlenir. Birden fazla sistemi bilgilendirmeniz gerekiyorsa, uygulamaya birkaç kuyruğa yazmayı öğretebilir veya bunları kendi kendine klonlayan fanout mekanizmasıyla değişimi yapılandırabilirsiniz.

Kafka'nın da benzer bir soyutlaması var konuMesaj yazdığınız ancak okuduktan sonra kaybolmadıkları. Varsayılan olarak Kafka'ya bağlandığınızda tüm mesajları alırsınız ve kaldığınız yerden kaydetme seçeneğine sahip olursunuz. Yani, sırayla okursunuz, mesajı okundu olarak işaretlemeyebilirsiniz, ancak daha sonra okumaya devam edebileceğiniz kimliği kaydedebilirsiniz. Kararlaştırdığınız kimliğe ofset denir ve mekanizma taahhüt ofsetidir.

Buna göre farklı mantık uygulanabilir. Örneğin, farklı ülkeler için 4 örnekte BOB'umuz var - Lamoda Rusya, Kazakistan, Ukrayna ve Beyaz Rusya'da. Ayrı olarak dağıtıldıkları için biraz farklı yapılandırmalara ve kendi iş mantıklarına sahiptirler. Hangi ülkeye atıfta bulunduğunu mesajda belirtiyoruz. Her ülkedeki her BOB tüketicisi farklı bir grup kimliğiyle okur ve mesaj kendileri için geçerli değilse atlar, yani. hemen +1 ofsetini taahhüt eder. Aynı konu Ödeme Servisimiz tarafından okunuyorsa bunu ayrı bir grupla yapar ve bu nedenle mahsuplar kesişmez.

Etkinlik gereksinimleri:

  • Veri bütünlüğü. Etkinliğin işlenebilmesi için yeterli veriye sahip olmasını istiyorum.

  • Bütünlüğü. Olayın tutarlı olduğunun ve olayı işleyebildiğinin doğrulanmasını Events-bus'a devrediyoruz.
  • Sıra önemlidir. Geri dönüş durumunda tarihle çalışmak zorunda kalıyoruz. Bildirimlerde sıra önemli değildir, eğer homojen bildirimlerse, hangi siparişin önce geldiğine bakılmaksızın e-posta aynı olacaktır. Para iadesi durumunda net bir süreç vardır; siparişi değiştirirsek istisnalar ortaya çıkar, geri ödeme oluşturulmaz veya işleme alınmaz - farklı bir duruma düşeriz.
  • Tutarlılık. Bir mağazamız var ve artık API yerine etkinlikler oluşturuyoruz. Yeni etkinlikler ve mevcut etkinliklerde yapılan değişiklikler hakkındaki bilgileri hızlı ve ucuz bir şekilde hizmetlerimize aktarmanın bir yoluna ihtiyacımız var. Bu, ayrı bir git deposunda ve kod oluşturucularda ortak bir spesifikasyon aracılığıyla gerçekleştirilir. Bu nedenle farklı servislerdeki istemciler ve sunucular koordine edilir.

Lamoda'da Kafka

Üç Kafka enstalasyonumuz var:

  1. Kütükler;
  2. Ar-Ge;
  3. Olaylar otobüsü.

Bugün sadece son noktadan bahsediyoruz. Event-bus'ta çok büyük kurulumlarımız yok - 3 broker (sunucu) ve yalnızca 27 konu. Kural olarak, bir konu bir süreçtir. Ancak bu ince bir noktadır ve şimdi ona değineceğiz.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Yukarıda rps grafiği var. Geri ödeme süreci turkuaz bir çizgiyle (evet, X eksenindeki) işaretlenmiştir ve pembe çizgi ise içerik güncelleme sürecidir.

Lamoda kataloğu milyonlarca ürün içermektedir ve veriler her zaman güncellenmektedir. Bazı koleksiyonların modası geçiyor, onların yerine yenileri çıkıyor ve katalogda sürekli yeni modeller çıkıyor. Yarın müşterilerimiz için neyin ilginç olacağını tahmin etmeye çalışıyoruz, bu yüzden sürekli yeni şeyler satın alıyoruz, fotoğraflarını çekiyoruz ve vitrini güncelliyoruz.

Pembe zirveler ürün güncellemeleri, yani ürünlerdeki değişikliklerdir. Adamların fotoğraf çektiği, fotoğraf çektiği ve sonra tekrar çekildiği görülüyor! — bir dizi etkinlik yüklendi.

Lamoda Events kullanım örnekleri

Oluşturulan mimariyi aşağıdaki işlemler için kullanıyoruz:

  • İade durumu takibi: İlgili tüm sistemlerden harekete geçirici mesaj ve durum takibi. Ödeme, durumlar, malileştirme, bildirimler. Burada yaklaşımı test ettik, araçlar hazırladık, tüm hataları topladık, belgeler yazdık ve meslektaşlarımıza onu nasıl kullanacaklarını anlattık.
  • Ürün kartlarının güncellenmesi: konfigürasyon, meta veriler, özellikler. Bir sistem okur (görüntüleyen) ve birkaçı yazar.
  • E-posta, push ve sms: Sipariş toplandı, sipariş geldi, iade kabul edildi vb. bir sürü var.
  • Stok, depo yenileme — öğelerin niceliksel güncellemesi, yalnızca sayılar: depoya varış, iade. Mal rezervasyonu ile ilgili tüm sistemlerin en güncel verilerle çalışması gerekmektedir. Şu anda stok güncelleme sistemi oldukça karmaşık; Kafka bunu basitleştirecek.
  • Veri Analizi (Ar-Ge departmanı), makine öğrenimi araçları, analizler, istatistikler. Bilginin şeffaf olmasını istiyoruz; Kafka bunun için çok uygun.

Şimdi son altı ayda meydana gelen büyük darbeler ve ilginç keşiflerle ilgili daha ilginç kısım var.

Tasarım sorunları

Diyelim ki yeni bir şey yapmak istiyoruz; örneğin tüm teslimat sürecini Kafka'ya aktarmak. Artık sürecin bir kısmı BOB'daki Sipariş İşleme'de uygulanıyor. Bir siparişin teslimat servisine aktarılmasının, ara depoya taşınmasının vb. arkasında bir durum modeli vardır. Tam bir monolit, hatta iki tane ve ayrıca teslimata adanmış bir sürü API var. Teslimat hakkında çok daha fazlasını biliyorlar.

Bunlar benzer alanlar gibi görünse de BOB'daki Sipariş İşleme ve Gönderi Sisteminin farklı durumları vardır. Örneğin, bazı kurye hizmetleri ara durumları göndermez, yalnızca son durumları gönderir: "teslim edildi" veya "kayboldu". Diğerleri ise tam tersine, malların hareketi hakkında çok detaylı raporlar veriyor. Herkesin kendi doğrulama kuralları vardır: Bazıları için e-posta geçerlidir, bu da işleme alınacağı anlamına gelir; diğerleri için geçerli değil, ancak iletişim için bir telefon numarası olduğu için sipariş yine de işleme koyulacak ve birisi böyle bir siparişin hiç işleme alınmayacağını söyleyecektir.

Veri akışı

Kafka örneğinde veri akışının düzenlenmesi sorunu ortaya çıkıyor. Bu görev birkaç noktaya dayalı bir strateji seçmeyi içeriyor; hadi hepsini gözden geçirelim.

Tek bir konuda mı yoksa farklı konularda mı?

Bir etkinlik spesifikasyonumuz var. BOB'da şu veya bu siparişin teslim edilmesi gerektiğini yazıyoruz ve şunu belirtiyoruz: sipariş numarası, bileşimi, bazı SKU'lar ve barkodlar vb. Mallar depoya ulaştığında teslimat durumu, zaman damgaları ve ihtiyaç duyulan her şeyi alabilecek. Ancak daha sonra bu verilerle ilgili güncellemeleri BOB'da almak istiyoruz. Teslimattan veri alma konusunda ters bir sürecimiz var. Bu aynı olay mı? Yoksa bu kendi konusunu hak eden ayrı bir borsa mı?

Büyük olasılıkla, çok benzer olacaklar ve tek bir konu oluşturmanın cazibesi temelsiz değil, çünkü ayrı bir konu, ayrı tüketiciler, ayrı yapılandırmalar, tüm bunların ayrı bir nesli anlamına gelir. Ama bu bir gerçek değil.

Yeni alan mı, yeni etkinlik mi?

Ancak aynı olayları kullanırsanız başka bir sorun ortaya çıkar. Örneğin, tüm dağıtım sistemleri BOB'un üretebileceği türden DTO'yu üretemez. Onlara id gönderiyoruz ama ihtiyaç duymadıkları için kaydetmiyorlar ve event-bus sürecinin başlatılması açısından bu alan gerekli.

Olay veri yolu için bu alanın gerekli olduğunu belirten bir kural eklersek, BOB'da veya başlangıç ​​olay işleyicisinde ek doğrulama kuralları ayarlamak zorunda kalırız. Doğrulama hizmetin geneline yayılmaya başlar - bu pek uygun değildir.

Diğer bir sorun ise artan gelişmenin cazibesidir. Etkinliğe bir şeyler eklenmesi gerektiği söylendi, belki de düşünürsek ayrı bir etkinlik olması gerekirdi. Ancak bizim programımızda ayrı bir etkinlik ayrı bir konudur. Ayrı bir konu yukarıda anlattığım sürecin tamamıdır. Geliştirici, JSON şemasına başka bir alan ekleyip onu yeniden oluşturma eğilimindedir.

Geri ödeme durumunda, altı ay içinde olayların gerçekleşmesine ulaştık. Bu güncellemenin gerçekte ne olduğunu açıklayan bir tür alanına sahip olan, geri ödeme güncellemesi adı verilen bir meta etkinliğimiz vardı. Bu nedenle, bu olayı bu türle nasıl doğrulayacağımızı bize anlatan doğrulayıcıların bulunduğu "harika" anahtarlarımız vardı.

Etkinlik sürümü oluşturma

Kafka'daki mesajları doğrulamak için kullanabilirsiniz Avro, ancak hemen üzerine uzanıp Confluent'i kullanmak gerekiyordu. Bizim durumumuzda versiyonlama konusunda dikkatli olmamız gerekiyor. Model "solda" olduğundan, çoğaltma günlüğündeki mesajları yeniden okumak her zaman mümkün olmayacaktır. Temel olarak, modelin geriye dönük olarak uyumlu olmasını sağlayacak sürümler oluşturmak ortaya çıkıyor: örneğin, bir alanı geçici olarak isteğe bağlı hale getirmek. Farklılıklar çok güçlüyse yeni bir konu yazmaya başlıyoruz ve müşterilerimiz eski konuyu okumayı bitirdikten sonra transfer ediyoruz.

Bölümlerin garantili okuma sırası

Kafka'nın içindeki konular bölümlere ayrılmıştır. Varlıkları ve borsaları tasarlarken bu çok önemli değil, ancak onu nasıl tüketeceğimize ve ölçeklendireceğimize karar verirken önemlidir.

Genellikle Kafka'da bir konu yazarsınız. Varsayılan olarak bir bölüm kullanılır ve bu konudaki tüm iletiler bu bölüme gider. Tüketici de dolayısıyla bu mesajları sırayla okuyor. Diyelim ki mesajların iki farklı tüketici tarafından okunabilmesi için sistemi genişletmemiz gerekiyor. Örneğin SMS gönderiyorsanız, Kafka'ya ek bir bölüm oluşturmasını söyleyebilirsiniz ve Kafka mesajları iki parçaya bölmeye başlayacaktır - yarısı burada, yarısı burada.

Kafka onları nasıl bölüyor? Her mesajın bir gövdesi (içinde JSON'u sakladığımız) ve bir anahtarı vardır. Bu anahtara, mesajın hangi bölüme gideceğini belirleyecek bir karma işlevi ekleyebilirsiniz.

Bizim iade durumumuzda bu önemli, iki bölüm alırsak paralel bir tüketicinin ikinci olayı birinciden önce işlemesi ve sorun yaşama ihtimali var. Karma işlevi, aynı anahtara sahip mesajların aynı bölümde yer almasını sağlar.

Olaylar ve komutlar

Bu da karşılaştığımız bir diğer sorun. Etkinlik belirli bir olaydır: Bir yerde bir şeyin gerçekleştiğini (bir şey_olduğunu) söyleriz, örneğin bir öğenin iptal edilmesi veya para iadesinin gerçekleşmesi. Birisi bu olayları dinlerse, "öğe iptal edildi"ye göre iade varlığı oluşturulacak ve kurulumların bir yerinde "geri ödeme gerçekleşti" yazacaktır.

Ancak genellikle etkinlikleri tasarlarken bunları boşuna yazmak istemezsiniz; birisinin bunları okuyacağı gerçeğine güvenirsiniz. Bir şeyin gerçekleştiğini (öğe_iptal edildi, geri ödeme_geri ödendi) değil, yapılması gereken bir şeyin yazılması yönünde büyük bir istek var. Örneğin ürün iade edilmeye hazır.

Bir yandan olayın nasıl kullanılacağını gösteriyor. Öte yandan, normal bir etkinlik adına çok daha az benziyor. Ayrıca do_something komutu buradan çok uzakta değil. Ancak birisinin bu olayı okuyacağının garantisi yok; ve eğer okursanız başarılı bir şekilde okudunuz demektir; ve eğer onu başarılı bir şekilde okursanız, o zaman bir şey yapmışsınızdır ve o şey başarılı olmuştur. Bir olay bir şey yapmaya başladığı anda geri bildirim gerekli hale gelir ve bu bir sorundur.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

RabbitMQ'daki eşzamansız değişimde, mesajı okuduğunuzda http'ye gidin, bir yanıt alırsınız - en azından mesajın alındığına dair. Kafka'ya yazdığınızda Kafka'ya yazdığınız bir mesaj var ama bunun nasıl işlendiğine dair hiçbir şey bilmiyorsunuz.

Bu nedenle, bizim durumumuzda, bir yanıt olayı eklemek ve izlemeyi ayarlamak zorundaydık, böylece bu kadar çok olay gönderilirse, şu kadar süre sonra aynı sayıda yanıt olayının gelmesi gerekir. Eğer bu olmazsa, bir şeyler ters gitmiş gibi görünüyor. Örneğin “item_ready_to_refund” etkinliğini göndermişsek geri ödeme oluşturulmasını, paranın müşteriye iade edilmesini ve “money_refunded” olayının bize gönderilmesini bekliyoruz. Ancak bu kesin değil, dolayısıyla izlemeye ihtiyaç var.

nüansları

Oldukça bariz bir sorun var: Bir konuyu sırayla okursanız ve kötü bir mesajınız varsa, tüketici düşecek ve daha ileri gidemeyeceksiniz. ihtiyacın var tüm tüketicileri durdur, okumaya devam etmek için ofseti daha da taahhüt edin.

Bunu biliyorduk, güvenmiştik ama yine de oldu. Ve bu gerçekleşti çünkü olay, olay veriyolu açısından geçerliydi, olay uygulama doğrulayıcısı açısından geçerliydi, ancak PostgreSQL açısından geçerli değildi çünkü tek sistemimizde UNSIGNED INT ile MySQL ve yeni yazılan sistemde sadece INT ile PostgreSQL vardı. Boyutu biraz daha küçük ve kimlik uymuyordu. Symfony bir istisna dışında öldü. Biz elbette istisnayı yakaladık çünkü ona güvendik ve bu dengelemeyi gerçekleştirecektik, ancak bundan önce mesaj başarısız bir şekilde işlendiğinden sorun sayacını artırmak istedik. Bu projedeki sayaçlar da veritabanında yer alıyor ve Symfony zaten veritabanıyla iletişimi kapatmış durumda ve ikinci istisna, dengeleme gerçekleştirme şansı olmadan tüm süreci sonlandırdı.

Hizmet bir süreliğine ertelendi - neyse ki Kafka için durum o kadar da kötü değil çünkü mesajlar kalıyor. Çalışmanız geri yüklendiğinde bunları okumayı bitirebilirsiniz. O konforlu.

Kafka, takımlama yoluyla keyfi bir ofset belirleme yeteneğine sahiptir. Ancak bunu yapmak için, tüm tüketicileri durdurmanız gerekir - bizim durumumuzda, tüketicilerin, yeniden dağıtımların olmayacağı ayrı bir sürüm hazırlayın. Daha sonra Kafka'da ofseti takımlama yoluyla değiştirebilirsiniz ve mesaj iletilecektir.

Başka bir nüans - çoğaltma günlüğü vs rdkafka.so - projemizin özellikleriyle ilgilidir. PHP kullanıyoruz ve PHP'de kural olarak tüm kütüphaneler Kafka ile rdkafka.so deposu aracılığıyla iletişim kurar ve sonra bir tür sarmalayıcı vardır. Belki bunlar bizim kişisel zorluklarımızdır, ancak daha önce okuduklarımızın bir kısmını yeniden okumanın o kadar da kolay olmadığı ortaya çıktı. Genel olarak yazılım sorunları vardı.

Bölümlerle çalışmanın ayrıntılarına dönersek, bu doğrudan belgelerde yazılmıştır. tüketiciler >= konu bölümleri. Ama bunu istediğimden çok daha sonra öğrendim. Ölçeklendirmek ve iki tüketiciye sahip olmak istiyorsanız en az iki bölüme ihtiyacınız vardır. Yani 20 bin mesajın biriktiği bir bölümünüz varsa ve yeni bir bölüm oluşturduysanız mesaj sayısı yakın zamanda eşitlenmeyecektir. Bu nedenle iki paralel tüketiciye sahip olmak için bölümlerle uğraşmanız gerekir.

İzleme

Sanırım bunu izleme şeklimiz mevcut yaklaşımda ne gibi sorunların olduğunu daha da netleştirecek.

Örneğin veri tabanındaki son zamanlarda kaç ürünün durumunun değiştiğini ve buna göre olayların bu değişikliklere göre oluşması gerektiğini hesaplıyoruz ve bu sayıyı izleme sistemimize gönderiyoruz. Daha sonra Kafka'dan ikinci sayıyı alıyoruz, gerçekte kaç olayın kaydedildiği. Açıkçası, bu iki sayı arasındaki fark her zaman sıfır olmalıdır.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Ayrıca üreticinin ne durumda olduğunu, event-bus mesaj alıp almadığını, tüketicinin ne durumda olduğunu da takip etmeniz gerekiyor. Örneğin, aşağıdaki grafiklerde Geri Ödeme Aracı iyi performans gösteriyor ancak BOB'un bazı sorunları olduğu açık (mavi zirveler).

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

Tüketici grubu gecikmesinden daha önce bahsetmiştim. Kabaca söylemek gerekirse, bu okunmamış mesajların sayısıdır. Genel olarak tüketicilerimiz hızlı çalıştığından gecikme genellikle 0 olur ancak bazen kısa süreli bir zirve de yaşanabilir. Kafka bunu alışılmışın dışında yapabilir ancak belli bir aralık belirlemeniz gerekir.

Bir proje var Yuvabu size Kafka hakkında daha fazla bilgi verecektir. Bu grubun ne durumda olduğunun durumunu vermek için yalnızca tüketici grubu API'sini kullanır. Tamam ve Başarısız'a ek olarak bir uyarı var ve tüketicilerinizin üretim hızıyla baş edemediklerini - yazılanları yeniden okumak için zamanları olmadığını öğrenebilirsiniz. Sistem oldukça akıllı ve kullanımı kolaydır.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

API yanıtı böyle görünüyor. İşte bob-live-fifa grubu, bölüm iadesi.update.v1, durum tamam, gecikme 0 - son son dengeleme falan.

Kafka üzerinde eşzamansız API ile Geri Ödeme Aracı hizmetini geliştirme deneyimi

İzleme update_at SLA (takıldı) Zaten bahsetmiştim. Örneğin ürün iadeye hazır duruma geldi. Bu nesnenin 5 dakika içinde iade edilmemesi durumunda (ödeme sistemleri aracılığıyla parayı çok hızlı bir şekilde iade ediyoruz), o zaman kesinlikle bir şeylerin ters gittiğini ve bunun kesinlikle destek gerektiren bir durum olduğunu söyleyen Cron'u yüklüyoruz. Bu nedenle, bu tür şeyleri okuyan Cron'u alıyoruz ve eğer 0'dan büyükse uyarı gönderiyor.

Özetlemek gerekirse, olayları kullanmak şu durumlarda uygundur::

  • birçok sistemin bilgiye ihtiyacı vardır;
  • işlemenin sonucu önemli değil;
  • az sayıda olay veya küçük olay var.

Görünüşe göre makalenin çok özel bir konusu var - Kafka'da eşzamansız API, ancak bununla bağlantılı olarak aynı anda birçok şeyi tavsiye etmek istiyorum.
İlk, sonraki Yüksek Yük++ Kasım ayına kadar beklememiz gerekiyor, Nisan ayında St.Petersburg versiyonu çıkacak ve Haziran ayında Novosibirsk'teki yüksek yüklerden bahsedeceğiz.
İkinci olarak, raporun yazarı Sergei Zaika, bilgi yönetimi konulu yeni konferansımızın Program Komitesi üyesidir. BilgiKonf. Konferans bir gün sürecek, 26 Nisan'da gerçekleşecek ama programı oldukça yoğun.
Ve mayıs ayında olacak PHP Rusya и RIT++ (DevOpsConf dahil) - ayrıca orada konunuzu önerebilir, deneyiminiz hakkında konuşabilir ve doldurulmuş külahlarınız hakkında şikayette bulunabilirsiniz.

Kaynak: habr.com

Yorum ekle