8.1 İşlem Kimlikleri

XID veya TxID olarak belirlenir (fark varsa söyleyin). Zaman damgaları, tüm eylemleri zamanın bir noktasına geri yüklemek istiyorsak işimize yarayabilen TxID olarak kullanılabilir. Zaman damgası yeterince ayrıntılı değilse sorun ortaya çıkabilir - bu durumda işlemler aynı kimliği alabilir.

Bu nedenle, en güvenilir seçenek benzersiz UUID ürün kimlikleri oluşturmaktır. Python'da bu çok kolaydır:

>>> import uuid 
>>> str(uuid.uuid4()) 
'f50ec0b7-f960-400d-91f0-c42a6d44e3d0' 
>>> str(uuid.uuid4()) 
'd15bed89-c0a5-4a72-98d9-5507ea7bc0ba' 

Ayrıca, bir dizi işlem tanımlayıcı veriye hash oluşturma ve bu hash'i TxID olarak kullanma seçeneği de vardır.

8.2 Yeniden Denemeler

Belirli bir işlevin veya programın önemsiz olduğunu biliyorsak, bu, bir hata durumunda çağrısını tekrarlayabileceğimiz ve denememiz gerektiği anlamına gelir. Ve sadece bazı işlemlerin hata vereceği gerçeğine hazırlıklı olmalıyız - modern uygulamaların ağ ve donanım üzerinden dağıtıldığı göz önüne alındığında, hata bir istisna olarak değil, norm olarak görülmelidir. Hata, bir sunucu çökmesi, ağ hatası, uzak uygulama tıkanıklığı nedeniyle oluşabilir. Uygulamamız nasıl davranmalı? Bu doğru, işlemi tekrarlamayı deneyin.

Tek bir kod parçası bir sayfadan daha fazlasını anlatabileceğinden, saf yeniden deneme mekanizmasının ideal olarak nasıl çalışması gerektiğini anlamak için bir örnek kullanalım. Bunu Tenacity kitaplığını kullanarak göstereceğim (o kadar iyi tasarlanmış ki, kullanmayı planlamasanız bile, örnek size yineleme mekanizmasını nasıl tasarlayabileceğinizi göstermelidir):

import logging
import random
import sys
from tenacity import retry, stop_after_attempt, stop_after_delay, wait_exponential, retry_if_exception_type, before_log

logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logger = logging.getLogger(__name__)

@retry(
	stop=(stop_after_delay(10) | stop_after_attempt(5)),
	wait=wait_exponential(multiplier=1, min=4, max=10),
	retry=retry_if_exception_type(IOError),
	before=before_log(logger, logging.DEBUG)
)
def do_something_unreliable():
	if random.randint(0, 10) > 1:
    	raise IOError("Broken sauce, everything is hosed!!!111one")
	else:
    	return "Awesome sauce!"

print(do_something_unreliable.retry.statistics)

> Her ihtimale karşı şunu söyleyeceğim: \@retry(...) "dekoratör" adı verilen özel bir Python sözdizimidir. Bu, başka bir işlevi sarmalayan ve yürütülmeden önce veya sonra bir şey yapan bir retry(...) işlevidir.

Gördüğümüz gibi, yeniden denemeler yaratıcı bir şekilde tasarlanabilir:

  • Denemeleri zamana (10 saniye) veya deneme sayısına (5) göre sınırlayabilirsiniz.
  • Üstel olabilir (yani, 2 ** artan bir sayı n ). veya ayrı denemeler arasındaki süreyi artırmak için başka bir şekilde (örneğin, sabit). Üstel varyant "tıkanıklık çökmesi" olarak adlandırılır.
  • Yalnızca belirli hata türleri için yeniden deneyebilirsiniz (IOError).
  • Yeniden deneme girişimleri, günlükteki bazı özel girişlerden önce gelebilir veya tamamlanabilir.

Artık genç dövüşçü kursunu tamamladığımıza ve uygulama tarafında işlemlerle çalışmak için ihtiyaç duyduğumuz temel yapı taşlarını bildiğimize göre, işlemleri dağıtık sistemlerde uygulamamıza izin veren iki yöntemi tanıyalım.

8.3 İşlem sevenler için gelişmiş araçlar

Bu konu ayrı bir büyük makaleyi hak ettiğinden, yalnızca oldukça genel tanımlar vereceğim.

İki fazlı taahhüt (2 adet) . 2pc'nin iki aşaması vardır: bir hazırlık aşaması ve bir taahhüt aşaması. Hazırlama aşamasında, tüm mikro hizmetlerden atomik olarak yapılabilecek bazı veri değişikliklerine hazırlanmaları istenecektir. Hepsi hazır olduğunda, taahhüt aşaması gerçek değişiklikleri yapacaktır. Süreci koordine etmek için, gerekli nesneleri kilitleyen - yani koordinatör kilidini açana kadar değişiklikler için erişilemez hale gelen küresel bir koordinatöre ihtiyaç vardır. Belirli bir mikro hizmet değişikliklere hazır değilse (örneğin yanıt vermiyorsa), koordinatör işlemi iptal eder ve geri alma sürecini başlatır.

Bu protokol neden iyi? Atomiklik sağlar. Ayrıca yazarken ve okurken izolasyonu garanti eder. Bu, bir işlemde yapılan değişikliklerin, koordinatör değişiklikleri taahhüt edene kadar diğerleri tarafından görülmediği anlamına gelir. Ancak bu özelliklerin bir dezavantajı da vardır: Bu protokol senkronize (engelleme) olduğundan, sistemi yavaşlatır (RPC çağrısının kendisi oldukça yavaş olmasına rağmen). Ve yine karşılıklı engelleme tehlikesi vardır.

efsane _ Bu modelde, ilişkili tüm mikro hizmetler genelinde eşzamansız yerel işlemler tarafından dağıtılmış bir işlem yürütülür. Mikro hizmetler, bir olay veri yolu aracılığıyla birbirleriyle iletişim kurar. Herhangi bir mikro hizmet yerel işlemini tamamlayamazsa, diğer mikro hizmetler değişiklikleri geri almak için telafi edici işlemler gerçekleştirir.

Saga'nın avantajı, hiçbir nesnenin engellenmemesidir. Ama elbette olumsuz yanları da var.

Özellikle çok sayıda mikro hizmet söz konusu olduğunda Saga'nın hatalarını ayıklamak zordur. Saga modelinin diğer bir dezavantajı, okuma izolasyonunun olmamasıdır. Yani ACID'de belirtilen özellikler bizim için önemliyse Saga bizim için pek uygun değil.

Bu iki tekniğin açıklamasından ne görüyoruz? Dağıtık sistemlerde atomikliğin ve izolasyonun sorumluluğu uygulamaya aittir. ASİT garantisi sağlamayan veritabanları kullanıldığında da aynı şey olur. Yani, çakışma çözümü, geri almalar, taahhütler ve alan boşaltma gibi şeyler geliştiricinin omuzlarına düşer.

8.4 ACID garantilerine ihtiyacım olduğunu nasıl anlarım?

Belirli bir kullanıcı veya süreç kümesinin aynı veriler üzerinde aynı anda çalışma olasılığı yüksek olduğunda .

Sıradanlık için özür dilerim, ancak tipik bir örnek finansal işlemlerdir.

İşlemlerin gerçekleştirilme sırasının ne zaman önemli olduğu.

Şirketinizin FunnyYellowChat messenger'dan FunnyRedChat messenger'a geçmek üzere olduğunu hayal edin, çünkü FunnyRedChat gif göndermenize izin verir, ancak FunnyYellowChat bunu yapamaz. Ancak sadece haberciyi değiştirmiyorsunuz - şirketinizin yazışmalarını bir haberciden diğerine taşıyorsunuz. Bunu yaparsınız çünkü programcılarınız programları ve süreçleri merkezi bir yerde belgelemek için çok tembeldi ve bunun yerine her şeyi habercide farklı kanallarda yayınladılar. Evet ve satış görevlileriniz müzakerelerin ve anlaşmaların ayrıntılarını aynı yerde yayınladı. Kısacası, şirketinizin tüm hayatı orada ve hiç kimsenin her şeyi bir belgeleme hizmetine aktaracak vakti olmadığından ve anlık mesajlaşma araması iyi çalıştığından, enkazı temizlemek yerine tümünü kopyalamaya karar verdiniz. mesajlar yeni bir konuma. Mesajların sırası önemlidir

Bu arada, bir habercideki yazışmalar için sıra genellikle önemlidir, ancak aynı sohbette iki kişi aynı anda bir şeyler yazdığında, o zaman genel olarak kimin mesajının önce görüneceği o kadar önemli değildir. Dolayısıyla, bu özel senaryo için ASİT gerekli olmayacaktır.

Başka bir olası örnek biyoinformatiktir. Bunu hiç anlamıyorum ama insan genomunun şifresini çözerken sıralamanın önemli olduğunu varsayıyorum. Bununla birlikte, biyoinformatikçilerin genellikle bazı araçlarını her şey için kullandıklarını duydum - belki de kendi veritabanlarına sahipler.

Bir kullanıcıya veremediğiniz veya eski verileri işleyemediğiniz zaman.

Ve yine - finansal işlemler. Dürüst olmak gerekirse, aklıma başka bir örnek gelmiyordu.

Bekleyen işlemler önemli maliyetlerle ilişkilendirildiğinde. Bir doktor ve bir hemşire hem bir hasta kaydını güncellerken hem de birbirlerinin değişikliklerini aynı anda sildiğinde ortaya çıkabilecek sorunları düşünün, çünkü veritabanı işlemleri izole edemez. Sağlık sistemi, finansın yanı sıra ACID garantilerinin kritik olma eğiliminde olduğu başka bir alandır.

8.5 Ne zaman ACID'e ihtiyacım olmaz?

Kullanıcılar özel verilerinin yalnızca bir kısmını güncellediğinde.

Örneğin, bir kullanıcı bir web sayfasına yorumlar veya yapışkan notlar bırakır. Veya kişisel verileri herhangi bir hizmet sağlayıcısı ile kişisel bir hesapta düzenler.

Kullanıcılar verileri hiç güncellemediğinde, ancak yalnızca yenileriyle tamamladığında (ekleme).

Örneğin, koşularınızdaki verileri kaydeden çalışan bir uygulama: ne kadar koştuğunuz, ne zaman koştuğunuz, rota vb. Her yeni çalıştırma yeni verilerdir ve eskileri hiç düzenlenmez. Belki de verilere dayanarak analitik elde edersiniz ve bu senaryo için yalnızca NoSQL veritabanları iyidir.

İş mantığı, işlemlerin gerçekleştirildiği belirli bir sıra ihtiyacını belirlemediğinde.

Muhtemelen bir sonraki canlı yayında yeni materyal üretimi için bağış toplayan bir Youtube blog yazarı için kimin, ne zaman ve hangi sırayla ona para attığı o kadar önemli değil.

Kullanıcılar aynı web sayfasında veya uygulama penceresinde birkaç saniye hatta dakika kaldıklarında ve bu nedenle bir şekilde eski veriler göreceklerdir.

Teorik olarak, bunlar herhangi bir çevrimiçi haber medyası veya aynı Youtube'dur. Veya "Habr". Tamamlanmayan işlemlerin geçici olarak sistemde saklanabilmesi sizin için önemli değilken zarar görmeden yok sayabilirsiniz.

Birçok kaynaktan gelen verileri ve yüksek sıklıkta güncellenen verileri bir araya getiriyorsanız - örneğin, bir şehirdeki park yerlerinin doluluğuna ilişkin veriler en az 5 dakikada bir değişir, o zaman teoride bu büyük bir sorun olmayacaktır. Bir noktada otoparklardan biri için işlem gerçekleşmezse sizin için. Tabii ki, bu verilerle tam olarak ne yapmak istediğinize bağlı.