Mikro hizmet veritabanlarının tohumlanması


10

Bir modeli (Ürünü kontrol eden hizmet A (CMS) verildiğinde, sahip olduğu tek alanların id, başlık, fiyat) ve verilen modeli göstermek zorunda olan B (Nakliye) ve C (E-postalar) alanları olduğunu varsayalım. kaynak kullanımı yaklaşımında verilen model bilgilerini bu hizmetler arasında senkronize etmek nasıl? Ürün kataloğunun nadiren değiştiğini (ancak değiştiğini) ve gönderilerin ve e-postaların verilerine çok sık erişebilen yöneticilerin olduğunu varsayalım (örnek işlevler: B: display titles of products the order containedve C:) display content of email about shipping that is going to be sent. Hizmetlerin her birinin kendi DB'si vardır.

Çözüm 1

Ürünle ilgili tüm gerekli bilgileri etkinlik içinde gönder - bu, aşağıdaki yapı için anlamına gelir order_placed:

{
    order_id: [guid],
    product: {
        id: [guid],
        title: 'Foo',
        price: 1000
    }
}

Hizmet B ve C ürün bilgileri tablodaki productJSON özniteliğinde depolanırorders

Bu nedenle, gerekli bilgileri görüntülemek için yalnızca olaydan alınan veriler kullanılır

Sorunlar : B ve C'de hangi bilgilerin sunulması gerektiğine bağlı olarak, olaydaki veri miktarı artabilir. B ve C, Ürün hakkında aynı bilgileri gerektirmeyebilir, ancak etkinliğin her ikisini de içermesi gerekir (etkinlikleri ikiye ayırmazsak). Belirli bir olayda belirli veriler mevcut değilse, kod bunu kullanamaz - verilen Ürüne bir renk seçeneği eklersek , B ve C'deki mevcut siparişler için, etkinlikleri güncellemedikçe ve sonra yeniden çalıştırmadıkça verilen ürün renksiz olacaktır .

Çözüm 2

Etkinlik sırasında yalnızca ürün kılavuzunu gönderin - bu, aşağıdaki yapı anlamına gelir order_placed:

{
    order_id: [guid],
    product_id: [guid]
}

B ve C hizmetleri hakkında ürün bilgileri tabloda product_idöznitelikte depolanırorders

A/product/[guid]Uç noktaya bir API çağrısı yapılarak gerektiğinde ürün bilgileri B ve C servisleri tarafından alınır

Sorunlar : Bu B ve C'yi A'ya (her zaman) bağımlı kılar. Ürünün şeması A'da değişirse, bunlara bağlı tüm hizmetlerde (aniden) değişiklikler yapılmalıdır.

Çözüm 3

Etkinlik sırasında yalnızca ürün kılavuzunu gönderin - bu, order_placed için aşağıdaki yapı anlamına gelir:

{
    order_id: [guid],
    product_id: [guid]
}

Hizmetler B ve C'de ürün bilgileri productstabloda saklanır ; hala var product_idilgili orderstablo ama replikasyonu var products, A, B ve C arasında veri; B ve C, Ürün hakkında A'dan farklı bilgiler içerebilir

Hizmetler B ve C oluşturulduğunda ürün bilgileri eklenir ve ürünler hakkında bilgi her A/productuç değiştiğinde (tüm ürünler için gerekli bilgileri gösteren) veya A'ya doğrudan DB erişimi gerçekleştirerek ve verilenler için gerekli ürün bilgilerini kopyalayarak güncellenir. hizmet.

Sorunlar : Bu, B ve C'yi A'ya bağımlı hale getirir (tohumlama sırasında). Ürünün şeması A'da değişirse, bunlara bağlı tüm hizmetlerde (tohumlama sırasında) değişiklikler yapılmalıdır.


Anladığım kadarıyla, doğru yaklaşım çözüm 1 ile gitmek ve ya belirli bir mantık başına olay geçmişini güncellemek olacaktır (Ürün kataloğu değişmediyse ve görüntülenecek renk eklemek istiyorsak, mevcut durumu almak için geçmişi güvenli bir şekilde güncelleyebiliriz Ürünlerin ve etkinliklerde eksik verileri doldurun) veya verilen verilerin mevcut olmamasını sağlayın (Ürün kataloğu değiştiyse ve görüntülenecek renk eklemek istiyorsak, o zamana kadar belirtilen Ürünün zamanında renkli olsun ya da olmasın - önceki katalogdaki tüm Ürünlerin siyah olduğunu ve etkinlikleri veya kodu güncelleyerek hitap ettiğini varsayabiliriz)


İle ilgili olarak updating event history- Olay kaynağı olay tarih gerçeğin kaynağıdır ve asla değiştirilmemeli, sadece ilerlemelidir. Olaylar değişirse, olay sürümlendirmesini veya benzer çözümleri kullanabilirsiniz, ancak olaylarınızı belirli bir zamana kadar tekrar oynatırken verilerin durumu o noktadaki gibi olmalıdır.
Hayır

Sorgulama için verilerin (şemalar, vb.) Saklanması ve eklenmesi / kaldırılması vb. Alanlarla ilgili olarak, kendimizi o anda olduğu gibi JSON'da veri depolamak için cosmosDB'yi kullandık. Sürümleme gerektiren tek şey olaylar ve / veya komutlardır. Ayrıca, bir istemciden gelen sorgulara yanıt veren verileri (web, mobil vb.) İçeren uç nokta sözleşmelerini ve değer nesnelerini güncellemeniz gerekir. Bir alanı olmayan eski verilerin varsayılan bir değeri veya boş değeri vardır, bu da işletmeye uygundur ancak etkinlik geçmişi tutarsız kalır ve yalnızca ilerler.
Hayır

@Hayır updating event historydemek istediğim: tutarlı olay şemasını korumak için tüm olayları gözden geçirin, bunları bir akıştan (v1) başka bir akışa (v2) kopyalayın.
eithed

Bir yana, ticaret / e-ticaret alanında, fiyatlandırmanın sık sık değiştiği göz önüne alındığında fiyatı yakalamak isteyebilirsiniz. Kullanıcıya görüntülenen bir fiyat, gerçek siparişin alındığı andan farklı olabilir. Sorunu çözmek için herhangi bir yol vardır, ancak dikkate alınması gereken bir şeydir.
CPerson

@CPerson yup - fiyat, etkinliğin kendisinde geçirilen özelliklerden biri olabilir. Öte yandan, resmin URL'si etkinlik içinde (niyetini temsil eden display image at the point when purchase was made) var olamaz veya olamaz (niyetini temsil eder display current image as it within catalog)
eithed

Yanıtlar:


3

3. çözüm gerçekten doğru fikre çok yakın.

Bunu düşünmenin bir yolu: B ve C'nin her biri ihtiyaç duydukları verilerin "yerel" kopyalarını önbelleğe alır . B'de (ve benzer şekilde C'de) işlenen iletiler, yerel olarak önbelleğe alınan bilgileri kullanır. Benzer şekilde, raporlar yerel olarak önbelleğe alınan bilgiler kullanılarak üretilir.

Veriler, kararlı bir API aracılığıyla kaynaktan önbelleklere çoğaltılır. B ve C'nin aynı API'yi kullanmasına bile gerek yok - ihtiyaçları için uygun olan getirme protokolünü kullanıyorlar. Aslında, sağlayıcıyı ve tüketiciyi sınırlayan bir sözleşme - protokol ve mesaj şeması tanımlarız. Daha sonra bu sözleşme için herhangi bir tüketici herhangi bir tedarikçiye bağlanabilir. Geriye dönük uyumsuz değişiklikler yeni bir sözleşme gerektirir.

Hizmetler, ihtiyaçları için uygun önbellek geçersizleştirme stratejisini seçer. Bu, değişikliklerin düzenli bir programda veya bir şeyin değişmiş olabileceğine dair bir bildirime yanıt olarak veya hatta "istek üzerine" - yani önbellek olarak okuma, verilerin depolanan kopyasına geri düşme anlamına geldiği anlamına gelebilir. kaynak mevcut değil.

Bu, B ve C'nin A geçici olarak kullanılamadığında iş değeri sağlamaya devam edebilmesi açısından size "özerklik" kazandırır.

Önerilen Kaynaklar: Dış Veri, İç Veri , Pat Helland 2005.


Evet, burada yazdıklarınızı tamamen kabul ediyorum ve çözüm 3 uyguladığım goto çözümü, ancak bu olay kaynak bulma yaklaşımı değil, çünkü olayları tekrar oynatacaksak, Ürünün mevcut durumunu kullanmak; devleti olay yerinde olduğu gibi kullanmak istiyoruz. Tabii ki, bu iyi olabilir (iş gereksinimine bağlı olarak). Bununla birlikte, katalogdaki değişiklikleri takip etmek istiyorsak, bu da olayların kaynaklanmasını gerektirir ve ne kadar veriye bağlı olursa, çözüm 1'e geri
düşebiliriz

1
Bence çözüm # 3. Tekrar katalog tutarlılığı gerekiyorsa, olay kaynağı da. Muhtemelen başlangıçta olan yeniden tohumlama sırasında tekrar oynamanız gerekir - bir kez kalktığınızda sadece yeni olaylara bakmanız gerekir, bu nedenle veri miktarı muhtemelen gerçek bir sorun değildir. Ancak, daha sonra (gerekirse) "burada yani kontrol noktaları kullanma seçeneği devlet bunu almak böylece, olayın 1000 tarihi itibariyle" ve şimdi sadece olayı 1,001-akım tamamı yerine tarihin yeniden zorunda .
Mike B.

2

İki zor şey varBilgisayar Bilimlerinde vardır ve bunlardan biri önbellek geçersiz kılmadır.

Çözüm 2 kesinlikle varsayılan konumumdur ve genellikle yalnızca aşağıdaki senaryolardan birinde karşılaşırsanız önbelleğe almayı düşünmelisiniz:

  1. Hizmet A'ya yapılan API çağrısı performans sorunlarına neden oluyor.
  2. Hizmet A'nın düşük olması ve verileri alamamasının maliyeti iş için önemlidir.

Performans sorunları gerçekten ana itici güçtür. Önbellekleme içermeyen # 2'yi çözmenin birçok yolu vardır, örneğin Hizmet A'nın yüksek düzeyde kullanılabilir olmasını sağlamak gibi.

Önbellekleme bir sisteme önemli bir karmaşıklık katar ve akıl yürütmesi zor olan uç durumlar ve çoğaltılması çok zor olan hatalar oluşturabilir. Yeni veri olduğu sürece Ayrıca, hangi bayat verilerin sağlanması riskini azaltmak zorunda can da, iş açısından bakıldığında (örneğin) "Hizmet A kapalı - lütfen daha sonra tekrar deneyin" iletisini görüntülemekten çok daha kötü .

Gönderen bu mükemmel makalede Udi Dahan tarafından:

Bu bağımlılıklar sizi yavaşça yukarı doğru kaydırır, ayakkabı bağlarınızı birbirine bağlar, yavaş yavaş geliştirme hızını yavaşlatır, sistemin bir bölümündeki değişikliklerin diğer bölümleri kırdığı kod tabanınızın kararlılığını azaltır. Bin kesintiyle yavaş bir ölüm ve sonuç olarak kimse, her şeyin bu kadar kötü gitmesine neden olan hangi büyük kararı verdiğimizden tam olarak emin değil.

Ayrıca, ürün verilerinin zamanında sorgulanması gerekiyorsa, bu, verilerin Ürün veritabanında depolanma biçiminde ele alınmalıdır (örn. Başlangıç ​​/ bitiş tarihleri), API'da açıkça gösterilmelidir (yürürlük tarihi verileri sorgulamak için API çağrısı için bir girdi olabilir).


1
@ SavavKleanthous "Ağ güvenilirdir" dağıtılmış bilgi işlemin yanlışlarından biridir. Ancak bu yanılgının yanıtı "diğer hizmetlerde her hizmetten her veriyi önbelleğe al" olmamalıdır (bunun biraz hiperbolik olduğunun farkındayım). Bir hizmetin mevcut olmayabileceğini ve bir hata koşulu olarak bununla ilgilenebileceğini düşünün. Hizmet A'nın düşmesinin önemli bir ticari etkisi olduğu nadir bir durum varsa, o zaman (dikkatlice!) Diğer seçenekleri göz önünde bulundurun.
Phil Sandler

1
@ SavvasKleanthous ayrıca (cevabımda bahsettiğim gibi), çoğu durumda eski verilerin döndürülmesinin bir hata atmaktan çok daha kötü olabileceğini düşünmektedir .
Phil Sandler

1
@eithed Bu yoruma atıfta bulunuyordum: "Bununla birlikte, katalogdaki değişiklikleri takip etmek istiyorsak, bu olayları da kaynak olarak gerektirir". Her durumda, doğru fikre sahipsiniz - ürün hizmeti, aşağı yönlü hizmetleri değil, zaman içindeki değişiklikleri izlemekle sorumlu olmalıdır.
Phil Sandler

1
Ayrıca, gözlemlediğiniz verilerin depolanması, önbelleğe almayla bazı benzerlikleri olsa da, aynı sorunları göstermez. Daha spesifik olarak, geçersiz kılma gerekli değildir; gerçekleştiğinde verilerin yeni sürümünü alırsınız. Yaşadığınız şey gecikmiş tutarlılıktır. Bununla birlikte, web isteği kullanıldığında bile (küçük olsa da) bir tutarsızlık penceresi vardır.
Savvas Kleanthous

1
@SavvasKleanthous Her durumda, asıl amacım henüz mevcut olmayan sorunları, özellikle de kendi sorunlarını ve risklerini getiren çözümlerle çözmeye çalışmak değil. Seçenek 2 en basit çözümdür ve iş gereksinimlerini karşılamadığı zamana kadar varsayılan seçim olmalıdır . Eğer işe yarayabilecek en basit çözümü seçmeyi düşünüyorsanız (bunu koyduğunuz gibi) "gerçekten kötü", o zaman ben sadece aynı fikirde değiliz.
Phil Sandler

2

Bir çözümün diğerinden daha iyi olduğunu söylemek çok zordur. Çözüm # 2 ve # 3 arasından birini seçmek diğer faktörlere bağlıdır (önbellek süresi, tutarlılık toleransı, ...)

2 sentim:

Önbellek geçersiz kılma zor olabilir, ancak sorun bildirimi ürün kataloğunun nadiren değiştiğinden bahseder. Bu gerçek, ürün verilerini önbellekleme için iyi bir aday yapar

Çözüm # 1 (NOK)

  • Veriler birden fazla sistemde çoğaltılır

Çözüm # 2 (Tamam)

  • Güçlü tutarlılık sunar
  • Yalnızca ürün hizmeti yüksek oranda kullanılabilir olduğunda çalışır ve iyi performans sunar
  • E-posta hizmeti bir özet hazırlarsa (birçok ürünle birlikte), genel yanıt süresi daha uzun olabilir

Çözüm # 3 (Karmaşık ancak tercih edilen)

  • Ürün bilgilerini almak için doğrudan DB erişimi yerine API yaklaşımını tercih edin
  • Dayanıklı - tüketen hizmetler, ürün hizmeti kapalı olduğunda etkilenmez
  • Tüketici uygulamaları (nakliye ve e-posta hizmetleri) bir etkinlik yayınlandıktan hemen sonra ürün ayrıntılarını alır. Bu birkaç milisaniyede ürün hizmetinin düşme olasılığı çok uzak.

1

Genel olarak konuşursak, bu iki hizmet arasındaki geçici bağlantı nedeniyle seçenek 2'ye şiddetle tavsiye ederim (bu hizmetler arasındaki iletişim süper kararlı ve çok sık olmadığı sürece). Geçici bağlanma, tanımladığınız şeydir this makes B and C dependant upon A (at all times)ve A, B veya C'den aşağı veya ulaşılamıyorsa, B ve C'nin işlevlerini yerine getiremeyeceği anlamına gelir.

Şahsen ben hem 1. hem de 3. seçeneklerin geçerli seçenek olduğu durumlar olduğuna inanıyorum.

A ve B & C arasındaki iletişim çok yüksekse veya etkinliğe girmek için gereken veri miktarı onu endişelendirecek kadar büyükse, seçenek 3 en iyi seçenektir, çünkü ağ üzerindeki yük çok daha düşüktür ve mesaj boyutu azaldıkça işlemlerin gecikmesi azalacaktır. Burada dikkate alınması gereken diğer endişeler:

  1. Sözleşmenin istikrarı: A mesajından ayrılan mesaj sözleşmesi sık sık değiştiyse, mesaja çok fazla özellik koymak tüketicilerde çok fazla değişikliğe neden olacaktır. Ancak, bu durumda bunun büyük bir sorun olmadığına inanıyorum çünkü:
    1. A sisteminin bir CMS olduğunu söylemiştiniz. Bu, kararlı bir alan üzerinde çalıştığınız anlamına gelir ve bu nedenle sık sık değişiklikler göreceğinize inanmıyorum
    2. B ve C gönderi ve e-posta olduğundan ve A'dan veri aldığınızdan, bunları kırmak yerine ek değişiklikler yaşayacağınıza inanıyorum; bunlar, yeniden çalışma olmadan keşfettiğinizde eklemek güvenlidir.
  2. Kuplaj: Burada kuplaj çok azdır veya hiç yoktur. Birincisi, iletişim mesajlar yoluyla olduğu için, verinin tohumlanması sırasında kısa bir geçici hizmet dışında hizmetler ile bu işlemin sözleşmesi (bu, kaçınmaya çalışabileceğiniz veya kaçınmaya çalışmanız gereken bir bağlantı değildir) arasında bir bağlantı yoktur.

Seçenek 1 olsa da reddettiğim bir şey değil. Aynı miktarda bağlantı var, ancak geliştirme açısından yapılması kolay olmalı (özel eylemlere gerek yok) ve alanın istikrarı, bunların daha önce değişmeyeceği anlamına gelmelidir (daha önce de belirttiğim gibi).

Önerebileceğim başka bir seçenek de, başlatma sırasında işlemi yürütmek değil, bunun yerine ürün kataloğunda bir değişiklik olduğunda B ve C'de "Product Added ve" ProductDetailsChanged "etkinliğini gözlemlemek olan 3'e hafif bir varyasyon. Bu, dağıtımlarınızı daha hızlı hale getirir (ve bulursanız bir sorunu / hatayı düzeltmeyi çok daha kolay hale getirir).


Düzenle 2020-03-03

Entegrasyon yaklaşımını belirlerken belirli bir öncelik sırasına sahibim:

  1. Tutarlılığın maliyeti nedir? A'da değiştirilen ve B & C'ye yansıtılan şeyler arasında milisaniye tutarsızlık kabul edebilir miyiz?
  2. Zamanında sorgulara (geçici sorgular da denir) ihtiyacınız var mı?
  3. Veriler için herhangi bir hakikat kaynağı var mı? Onlara sahip olan ve yukarı doğru kabul edilen bir hizmet mi?
  4. Bir sahip / tek hakikat kaynağı varsa bu istikrarlı mıdır? Yoksa sık sık kırılma değişiklikleri görmeyi mi bekliyoruz?

Tutarsızlık maliyeti yüksekse (temel olarak A'daki ürün verilerinin B ve C'de önbelleğe alınan ürünle mümkün olan en kısa sürede tutarlı olması gerekir), o zaman kullanılamazlığı kabul etmek ve senkronize bir istek (web gibi) yapmaktan kaçınamazsınız. / rest request) veri almak için B & C'den A'ya. Farkında olmak! Bu hala işlemsel olarak tutarlı anlamına gelmez, ancak pencereleri tutarsızlık için en aza indirir. Kesinlikle, pozitif olarak hemen tutarlı olmanız gerekiyorsa, hizmet sınırlarınızı zorlamanız gerekir. Ancak, ben çok güçlü bu bir problem olmamalı inanıyoruz. Deneyimden, aslında şirketin birkaç saniye tutarsızlığı kabul edememesi çok nadirdir, bu nedenle senkron talepler yapmanız bile gerekmez.

Zamanında sorgulara ihtiyacınız varsa (ki bu, sorunuzda fark etmedim ve dolayısıyla yukarıdakileri dahil etmedi, belki yanlış), aşağı akış hizmetlerinde bunu sürdürmenin maliyeti çok yüksektir (çoğaltmanız gerekir) tüm aşağı akış hizmetlerinde dahili olay projeksiyon mantığı) kararı açıklığa kavuşturur: A'nın sahipliğini bırakmalı ve web isteği (veya benzeri) üzerinden bir ad-hoc sorgusu sormalı ve A, bildiğiniz tüm olayları almak için olay kaynağı kullanmalıdır o zaman devlete yansıtma ve geri verme. Sanırım bu seçenek 2 (doğru anladım?) Olabilir, ama maliyeti öyle ki zamansal eşleştirme, duplciated olayların ve projeksiyon mantığının bakım maliyetinden daha iyidir.

Zamanında bir noktaya ihtiyacınız yoksa ve verilerin açık ve tek bir sahibi yoksa (ki bu benim ilk cevabımda bunu sorunuza dayanarak varsaydım), o zaman temsilleri tutmak çok makul bir model olacaktır. her bir servisteki ürünün ayrı ayrı. Ürünler için verileri güncellediğinizde, her birine paralel web istekleri yaparak A, B ve C'yi paralel olarak güncelleştirirsiniz veya A, B ve C'nin her birine birden fazla komut gönderen bir komut API'niz vardır. işlerini yapmak için verilerin yerel sürümü olabilir; bunlar eski olabilir veya olmayabilir. A, B ve C'deki veriler farklı olabileceğinden ve ürünün "bütünü" üç verinin bir bileşimi olabileceğinden, bu yukarıdaki seçeneklerden herhangi biri değildir (seçenek 3'e yakın olabilmesine rağmen). kaynaklar.

Gerçeğin kaynağının istikrarlı bir sözleşmeye sahip olup olmadığını bilmek yararlıdır, çünkü A ve B ve C hizmetleri arasında entegrasyon için etki alanı / dahili olayları (veya etkinliğinizde A'da depolama deseni olarak depoladığınız olayları) kullanmak için kullanabilirsiniz. Sözleşme istikrarlıysa, alan adı etkinlikleri aracılığıyla entegre edebilirsiniz. Bununla birlikte, değişikliklerin sık olduğu veya mesaj sözleşmesinin taşımayı bir endişe haline getirecek kadar büyük olduğu durumlarda ek bir endişeniz vardır.

İstikrarlı olması beklenen bir sözleşmeyle net bir sahibiniz varsa, en iyi seçenekler seçenek 1 olacaktır; bir sipariş gerekli tüm bilgileri içerecek ve ardından B ve C olaydaki verileri kullanarak işlevlerini yerine getirecektir.

Sözleşme, 3. seçeneğinizi izleyerek değiştirmek veya sık sık kırmakla yükümlü ise, ürün verilerini almak için web isteklerine geri dönmek aslında daha iyi bir seçenektir, çünkü birden çok sürümü korumak çok daha kolaydır. B ürün v3'ü için bir talepte bulunacaktır.


Evet, katılıyorum. Ürün kataloğu değişikliklerini izlemenin karmaşıklığını artırırken ProductAddedveya ProductDetailsChangedeklerken, olayların yeniden oynatılması ve geçmişten katalog verilerine erişmemiz gerekiyorsa, verilerin bir şekilde veritabanları arasında senkronize kalmasını sağlamalıyız.
eithed

@eithed Yaptığım bazı varsayımları genişletmek için cevabı güncelledim.
Savvas Kleanthous
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.