8 dk

Jim Gray, İşlem İşleme ve Neden ACID Hâlâ Önemli

Jim Gray’in işlem işleme fikirlerine pratik bir bakış: ACID ilkelerinin bankacılık, e-ticaret ve SaaS sistemlerinde güvenilirliği nasıl sağladığını anlatır.

Jim Gray, İşlem İşleme ve Neden ACID Hâlâ Önemli

Jim Gray kimdi ve neden fikirleri sürüyor

Jim Gray, basit ama yanıltıcı derecede derin bir soruyla takıntılı olan bir bilgisayar bilimcisiydi: çok kişi aynı anda bir sistemi kullandığında — ve hatalar kaçınılmaz olduğunda — sonuçları nasıl doğru tutarsınız?

İşlem işleme üzerine yaptığı çalışmalar, veritabanlarını “şanslıysanız bazen doğru” olmaktan, gerçekten bir işe dayanacak altyapıya dönüştürmeye yardımcı oldu. Özellikle ACID ilkeleri, ürün toplantısında hiç "işlem" kelimesini duymamış olsanız bile her yerde karşınıza çıkar.

"Güvenilir bir sistem" basitçe ne demektir

Güvenilir bir sistem, kullanıcıların yalnızca ekranlara değil sonuçlara güvenebildiği sistemdir.

  • Banka bakiyeniz iki çekim yarışırken eksiye düşmez.
  • Bir sipariş ya tamamen gerçekleşir (stok ayrılır ve ödeme kaydı yapılır) ya da hiç gerçekleşmez—ara bir belirsiz durum olmaz.
  • Abonelik yükseltmeleri arka plan işi iki kez çalıştığı için rastgele erişim vermez veya geri almaz.
  • Denetim kayıtları ve makbuzlar, çökmeden sonra bile gerçekten olanla eşleşir.

Başka bir deyişle: doğru bakiyeler, doğru siparişler ve eksik kayıt yok.

Gray’in fikirlerini nerede görürsünüz

Kuyruklar, mikroservisler ve üçüncü taraf ödemeler olsa bile modern ürünler yine kritik anlarda işlem düşüncesine dayanır.

  • Bankacılık: para hareketinde hızdan çok doğruluk gerekir.
  • Ticaret: yoğunluk altında güvenli ödeme akışları—siparişler, stok, ödemeler, iadeler.
  • SaaS: tutarlı abonelikler, yetkilendirmeler ve denetim izleri; böylece müşteriler fazla ücretlendirilmez veya erişimleri kapanmaz.

Bu yazı ne yapacak (ve ne yapmayacak)

Kavramları pratik tutacağız: ACID’in neyi koruduğu, hataların nerede gizlendiği (izolasyon ve eşzamanlılık), ve günlükler ile kurtarmanın hataları nasıl yaşanılabilir kıldığı.

Ayrıca modern ödünleri ele alacağız—ACID sınırlarını nerede çizmelisiniz, dağıtık işlemler ne zaman gerekli, ve saga, retry ile idempotentlik gibi desenlerin gereksiz aşırı mühendislik yapmadan ne zaman “yeterince iyi” tutarlık sağladığı.

İşlem İşleme (Transaction) Basitçe

Bir işlem, çok adımlı bir iş eylemini tek bir "evet/hayır" birimi gibi ele almanın yoludur. Her şey başarılıysa commit edilir. Bir şey ters giderse sanki hiç olmamış gibi geri alınır.

Basit örnek: para transferi

Checking hesabından Savings hesabına 50$ taşımayı düşünün. Bu tek değişiklik değildir; en az iki adımı vardır:

  • Checking hesabından 50$ eksilt
  • Savings hesabına 50$ ekle

Sisteminiz sadece "tek adımlı güncellemeler" yapıyorsa, parayı eksiltip sonra yatırma adımı başarısız olabilir. Müşteri 50$ eksik kalır—ve destek talepleri başlar.

Checkout da tek adım değildir

Tipik bir checkout sipariş oluşturma, stok ayırma, ödeme yetkilendirme ve makbuz kaydetmeyi içerir. Her adım farklı tabloları (veya farklı servisleri) etkiler. İşlem düşüncesi yoksa, "ödenmiş" işaretli bir sipariş ama ayrılmamış stok ya da hiç oluşturulmamış bir sipariş için rezerve edilmiş stok gibi durumlar oluşabilir.

Gerçek hayatta nerede başarısız olunur

Hatalar nadiren uygun anlarda olur. Yaygın kırılma noktaları:

  • Uygulama adım 1'den sonra çöküp adım 2'den önce kapanır.
  • Uygulama ile veritabanı arasındaki ağ kopar.
  • Zaman aşımı olur, kullanıcı "Öde"ye tekrar tıklar.
  • Bir yeniden deneme veya yük dengeleyici çift istek gönderir.

Hedef: tüm adımlar ya hep uygulanır ya hiçbiri

İşlem işleme şu basit sözü garanti etmek için vardır: iş eyleminin tüm adımları birlikte etkili olur veya hiçbiri olmaz. Bu söz, para taşırken, sipariş verirken veya abonelik planı değiştirirken güvenin temelidir.

ACID Hatırlatma: Her Harf Neyi Korur

ACID, "bir işlem"i güvenilir hissettiren korumaların bir kontrol listesidir. Pazarlama terimi değildir; önemli veriler değiştirildiğinde neler olacağına dair bir dizi vaadedir.

A — Atomiklik (her şey ya da hiçbiri)

Atomiklik, bir işlemin ya tamamen tamamlanması ya da hiçbir iz bırakmaması anlamına gelir.

Bir banka transferini düşünün: Hesap A'dan 100$ düşülür, Hesap B'ye 100$ eklenir. Sistem debit yaptıktan sonra çökse atomiklik tüm transferin geri alınmasını (veya tamamen tamamlanmasını) sağlar. Sadece bir tarafın gerçekleştiği geçerli bir son durum yoktur.

C — Tutarlılık (kurallar hep doğru kalır)

Tutarlılık, verinizin kurallarının (kısıtlar ve invariantlar) her commit sonrası doğru kalması demektir.

Örnekler: ürününüz overdraft (eksi bakiye) yasaklıysa bakiye negatife düşemez; bir transfer için debit ve credit toplamlarının eşleşmesi gerekir; bir sipariş toplamı satır kalemleri ve vergiyi eşitlemelidir. Tutarlılık kısmen veritabanı işi (kısıtlar), kısmen uygulama işi (iş kuralları)dır.

I — İzolasyon (eşzamanlılık sonuçları bozmaz)

İzolasyon, aynı anda birden çok işlem olduğunda sizi korur.

Örnek: iki müşteri bir öğenin son birimini almaya çalışır. Uygun izolasyon olmazsa her iki checkout da "1 kaldı" görüp ikisi de başarılı olabilir ve stok -1 olabilir veya elle düzeltilmesi gerekir.

D — Kalıcılık (commit edilen kalıcıdır)

Kalıcılık, "commit"i gördüğünüzde sonucun çökme veya güç kaybından sonra yok olmayacağını garanti eder. Makbuz transferin başarılı olduğunu söylüyorsa, defter yeniden başlattıktan sonra da bunu göstermelidir.

Yaygın bir yanlış anlama

"ACID" tek bir açma/kapama düğmesi değildir. Farklı sistemler ve izolasyon seviyeleri farklı garantiler sağlar; hangi operasyonlara hangi korumaların uygulanacağını siz seçersiniz.

Bankacılık: Para Hareketinde Doğruluk Hızdan Önde

İşlem dediğinizde bankacılık en açık örnektir: kullanıcılar bakiyelerin her zaman doğru olmasını bekler. Bir bankacılık uygulaması biraz yavaş olabilir; yanlış olamaz. Bir yanlış bakiye overdraft ücretleri, kaçırılmış ödemeler ve uzun manuel düzeltiler zinciri başlatır.

Bir transfer, bir iş birimi

Basit bir banka transferi aslında başarılması gereken birkaç adımdır:

  • Hesap A'dan debit
  • Hesap B'ye credit
  • Kimin/ ne zaman/ neden/ ne kadar kaydını yaz

ACID düşüncesi bunu tek bir birim olarak ele alır. Herhangi bir adım başarısızsa—ağ problemi, servis çökmesi, doğrulama hatası—sistem kısmi başarıya izin vermemelidir. Aksi halde A hesabından para eksik ama B'de görünmüyor veya B'de para var ama eşleşen debit yok ya da ne olduğunu açıklayan bir denetim izi yok.

"Sonra düzeltiriz" pahalıya gelir

Birçok üründe küçük bir tutarsızlık sonraki sürümde yamalanabilir. Bankacılıkta "sonra düzeltme" itirazlara, düzenleyici risklere ve manuel operasyonlara dönüşür. Destek talepleri tırmanır, mühendisler olay çağrılarına çekilir ve ekipler uyumsuz kayıtları düzeltmek için saatler harcar.

Sayıları düzeltseniz bile geçmişi açıklamanız gerekir.

Defterler, değişmez günlükler ve mutabakat

Bankaların neden defterlere ve ekleme-yalnızca kayıtlara güvendiği bundandır: geçmişi üzerine yazmak yerine debit ve credit dizisini kaydederler. Değişmez günlükler ve net denetim izleri kurtarmayı ve incelemeyi mümkün kılar.

Mutabakat—bağımsız doğruların karşılaştırılması—bir şey ters gidince nerede ve ne zaman sapma olduğunu bulmak için geriye dönük bir emniyet ağıdır.

Kullanıcı etkisi

Doğruluk güven kazandırır. Ayrıca destek hacmini azaltır ve çözümü hızlandırır: bir problem olduğunda temiz bir denetim izi ve tutarlı defter kayıtları "ne oldu?" sorusuna hızlı yanıt verir ve tahmine gerek kalmadan düzeltme yapmayı sağlar.

Ticaret: Yük Altında Siparişler, Stok ve Ödemeler

E-ticaret basit görünür ta ki zirve trafiğe ulaşana kadar: aynı son ürün on sepette, müşteriler sayfayı yeniliyor ve ödeme sağlayıcı zaman aşımına uğruyor. İşte Jim Gray’in işlem işleme zihniyeti, pratik ve sıkıcı şekillerde ortaya çıkar.

Bir checkout, adımlara bölünmüş

Tipik bir checkout birden çok durumu etkiler: stok ayırma, siparişi oluşturma ve ödemeyi tahsil etme. Yüksek eşzamanlılık altında, her adım kendi başına doğru olsa bile kötü bir genel sonuç oluşturabilir.

Stoku izolasyon olmadan azaltırsanız, iki checkout "1 kaldı" okuyup her ikisi de başarılı olabilir—aşırı satış başlar. Ödemeyi alıp sonra sipariş oluşturamazsanız, müşteriyi teslimat için ücretlendirip yerine koyacak bir şeyiniz olmaz.

ACID en çok veritabanı sınırında işe yarar: sipariş oluşturma ve stok ayırmayı tek bir veritabanı işlemi içinde sarmalayın ki ya ikisi commit olsun ya da ikisi rollback olsun. Ayrıca kısıtlarla doğruluğu zorlayabilirsiniz (örneğin, "stok sıfırın altına inemez") böylece uygulama kodu yanlış davransa bile veritabanı imkansız durumları reddeder.

Ödemeler: "tam olarak bir kez" zor neden

Ağlar yanıtları kaybeder, kullanıcı çift tıklar ve arka plan işleri yeniden dener. Bu yüzden sistemler arasında "tam olarak bir kez" işleme zor iş olur. Hedef genelde: para hareketinde en fazla bir kez, ve diğer her yerde güvenli yeniden denemelerdir.

Ödeme sağlayıcınızla idempotency anahtarları kullanın ve siparişinize bağlı kalıcı bir "ödeme niyeti" kaydedin. Servisiniz yeniden denese bile çifte ücretlendirme olmaz.

İadeler ve chargeback'ler

İadeler, kısmi geri ödemeler ve chargeback'ler iş gerçeğidir, köşe olguları değil. Net işlem sınırları bunları kolaylaştırır: her düzeltmeyi bir siparişe, bir ödemeye ve bir denetim izine güvenilir şekilde bağlayabilirsiniz—böylece bir şey ters gittiğinde mutabakat açıklanabilir.

SaaS: Abonelikler, Yetkilendirmeler ve Denetim İzleri

Önce işlem sınırlarını planlayın
Planlama Modu ile kod üretmeden önce işlem sınırlarını ve invariantları eşleyin.

SaaS işletmeleri bir vaatte yaşar: müşteri ödediği şeyi hemen ve öngörülebilir şekilde kullanabilmelidir. Bu, plan yükseltmeleri, düşürmeler, dönem içi proration, iadeler ve asenkron ödeme olaylarını karıştırana kadar basittir. ACID tarzı düşünce, "faturalama gerçeği" ile "ürün gerçeğini" uyumlu tutmaya yardımcı olur.

Abonelik değişiklikleri sürpriz olmadan

Plan değişikliği genellikle bir dizi eylemi tetikler: fatura oluşturma/ayarlama, proration kaydı, ödeme denemesi ve yetkilendirmeyi güncelleme. Bunları kısmi başarının kabul edilemez olduğu tek bir iş birimi olarak ele alın.

Eğer yükseltme faturası oluşturulur ama yetkilendirmeler güncellenmezse (veya tersi), müşteriler ya ödedikleri halde erişimi kaybeder ya da erişim almalarına rağmen ücretlendirilmezler.

Pratik bir desen, faturalama kararını (yeni plan, yürürlük tarihi, proration satırları) ve yetkilendirme kararını birlikte kalıcı hale getirmek, sonra downstream süreçleri bu commit edilmiş kayıttan çalıştırmaktır. Ödeme onayı sonra gelirse, tarihçeyi yeniden yazmadan güvenle ilerleyebilirsiniz.

Çok kiracılı doğruluk

Çok kiracılı sistemlerde izolasyon akademik değildir: bir müşterinin yoğun aktivitesi başka bir müşteriyi engellememeli veya bozmemelidir. Tenant-açık anahtarlar kullanın, her tenant için net işlem sınırları belirleyin ve dikkatle seçilmiş izolasyon seviyeleri ile Tenant A'daki yenileme patlaması Tenant B için tutarsız okumalara yol açmasın.

Destek sorularını yanıtlayan denetim izleri

Destek talepleri genelde "Neden bana ücret kesildi?" veya "Neden X'e erişemiyorum?" ile başlar. Kim neyi ne zaman (kullanıcı, admin, otomasyon) değiştirdiğinin append-only bir denetim günlüğünü tutun ve bunu faturalar ile yetkilendirme geçişlerine bağlayın.

Bu sessiz sürüklenmeyi—faturalar "Pro" derken yetkilendirmeler hala "Basic" göstermesi gibi—önler ve mutabakatı bir sorgu haline getirir, soruşturma değil.

İzolasyon ve Eşzamanlılık: Hataların Çoğunun Gizlendiği Yer

İzolasyon ACID'in "I"sidir ve sistemlerin genellikle ince, maliyetli şekillerde başarısız olduğu yerdir. Temel fikir basittir: birçok kullanıcı aynı anda hareket eder, ancak her işlem tek başına çalışmış gibi davranmalıdır.

Günlük bir benzetme: iki kasiyer, bir ürün

Bir mağaza hayal edin: iki kasiyer ve rafta son bir ürün. Eğer her iki kasiyer aynı anda stoğu kontrol edip "1 mevcut" görürse, ikisi de satabilir. Hiçbir şey "çökmedi" ama sonuç yanlıştır—çifte satış gibi.

Veritabanları da aynı sorunu yaşar; iki işlem aynı satırı eşzamanlı okuyup güncellemek istediğinde.

İzolasyonun önlemek istediği yaygın anormallikler

  • Kirli okumalar: commit edilmemiş bir işlemin değişikliğini görürsünüz (ve bu işlem rollback olabilir).
  • Kaybolan güncellemeler: iki işlem aynı kaydı günceller ve sonraki yazma önceki yazmayı sessizce ezer.
  • Çifte harcama tarzı hatalar: iki işlem aynı kıt kaynağı (stok, bakiye, koltuk) "ayırır".

İzolasyon seviyeleri basitçe

Çoğu sistem güvenlik ile verim arasında bir izolasyon seviyesi seçer:

  • Read committed: sadece commit edilmiş verileri okur. Kirli okumaları önlemeye yardımcı olur ama bazı anormallikler yine olabilir.
  • Repeatable read: aynı satırı yeniden okursanız aynı sonucu alırsınız. "Hareket eden hedef" davranışını azaltır ama her tür çatışmayı engellemez.
  • Serializable: en güçlüsü—sonuçlar işlemler tek tek çalışmış gibi olur. En güvenlisi ama genelde en yavaşıdır.

İş riskine göre seçin, yalnızca performansa göre değil

Bir hata finansal kayıp, yasal maruz kalma veya müşteri görünür tutarsızlık yaratıyorsa daha güçlü izolasyona (veya açık kilitlemeye/kısıtlamalara) eğilin. En kötü durum geçici bir UI hatasıysa daha zayıf seviye kabul edilebilir.

Daha yüksek izolasyon, veritabanının daha fazla koordinasyon yapmasını gerektirdiği için verimi düşürebilir—bekleme, kilitleme veya işlem abort/yeniden deneme gibi. Maliyet gerçek, ama yanlış veri maliyeti de öyledir.

Günlükler, Kalıcılık ve Çökmeden Sonra Kurtarma

Tasarım gereği idempotentlik ekleyin
Koder.ai, riskli işlemler için idempotency anahtarları, dedupe tabloları ve unique constraint'ler taslak halinde oluşturur.

Bir sistem çöktüğünde en önemli soru "neden çöktü?" değil, "yeniden başlatmadan sonra hangi durumda olmalıyız?" olmalıdır. Jim Gray'in işlem işleme çalışmaları bu sorunun pratik yanıtını verdi: kalıcılık disiplinli günlükleme ve kurtarma ile sağlanır.

İşlem günlüğü: sistemin belleği

İşlem günlüğü (genellikle WAL olarak anılır) değişikliklerin ekleme-yalnızca kaydıdır. Kurtarmada kritiktir çünkü veritabanı dosyaları yazılırken güç kesilmiş olsa bile niyeti ve güncelleme sırasını korur.

Yeniden başlatma sırasında veritabanı şunları yapabilir:

  • Redo: commit edilmiş ama veri dosyalarına tam yansımamış değişiklikleri tekrar uygular.
  • Undo: tamamlanmamış işlemleri geri alır, böylece yarım kalmış güncellemeler son duruma sızmaz.

Bu yüzden "commit ettik" demek, sunucu temiz kapanmamış olsa bile doğru kalmaya devam edebilir.

Write-ahead logging (WAL) ve kalıcılığı nasıl sağlar

Write-ahead logging demek: veri sayfaları yazılmadan önce log kalıcı depolamaya flush edilir. Pratikte, "commit", ilgili log kayıtlarının güvenli şekilde diske (veya başka dayanıklı bir yere) yazıldığından emin olmakla bağlıdır.

Çökme tam commit sonrası olursa, kurtarma logu yeniden oynatıp commit edilmiş durumu yeniden kurar. Çökme commit öncesiyse log yarıda kalan işlemleri geri almaya yardımcı olur.

Yedekler vs loglar: her ikisine de ihtiyacınız var

Yedek bir anlık görüntüdür. Loglar ise bir geçmiştir. Yedekler felaket kurtarma (hatalı deploy, silinmiş tablo, fidye yazılımı) için gereklidir. Loglar ise son commit edilmiş işleri kurtarmanızı ve point-in-time recovery sağlamanızı sağlar: yedeği geri yükleyin, sonra logları istenen ana kadar oynatın.

Operasyonel hatırlatma: geri yüklemeleri test edin

Hiç geri yüklemediğiniz bir yedek umut, plan değil. Düzenli geri yükleme tatbikatları planlayın, veri bütünlüğünü doğrulayın ve kurtarma süresinin gerçekte ne kadar sürdüğünü ölçün. Eğer RTO/RPO ihtiyaçlarını karşılamıyorsa, saklama, log gönderimi veya yedek sıklığını olay olmadan önce ayarlayın.

Dağıtık Sistemler: ACID Sınırları ve Pratik Alternatifler

ACID en iyi tek bir veritabanının "gerçek kaynağı" olarak hareket edebildiği durumda çalışır. Bir iş eylemini birden çok servise (ödeme, stok, e-posta, analiz) yaydığınız anda dağıtık sistemler sahasına girersiniz—burada hatalar temiz "başarılı" veya "hata" gibi görünmez.

Neden dağıtık işlemler zor

Dağıtık kurulumda kısmi hataları kabul etmelisiniz: bir servis commit ederken başka bir servis çökeltebilir, veya ağ gecikmesi gerçek sonucu gizleyebilir. Zaman aşımı belirsizliği—karşı taraf mı başarısız oldu yoksa sadece yavaş mı—çifte ücretlendirme, aşırı satış ve eksik yetkilendirmelerin doğduğu yerdir.

İki fazlı commit (2PC) basitçe

2PC birden çok veritabanının "bir" gibi commit etmesini sağlamaya çalışır.

  • Faz 1 (hazırla): her katılımcı commit edebileceğini vaat eder ve ihtiyaç duyduğu kaynakları kilitler.
  • Faz 2 (commit/abort): koordinatör herkese finalize etmesini veya geri almasını söyler.

Ekipler genellikle 2PC'den kaçınır çünkü yavaştır, kilitleri daha uzun süre tutar (verimi düşürür) ve koordinatör bir darboğaz olabilir. Ayrıca sistemleri sıkıca bağlar: tüm katılımcıların protokolü konuşması ve yüksek erişilebilir olması gerekir.

Ölçeklenen pratik alternatifler

Yaygın yaklaşım, ACID sınırlarını küçük tutmak ve servisler arası işi açıkça yönetmektir:

  • Sagas: büyük bir süreci adımlara ayırın; her adımın kendi yerel işlemi olsun.
  • Telafi edici eylemler: adım 4 başarısız olursa ödeme iadesi, stok serbest bırakma gibi "geri al" adımları çalıştırın.
  • Outbox deseni: veritabanı değişikliğini ve yayınlanacak olayı aynı yerel işlemde yazın, sonra güvenilir şekilde gönderin.

Pratik kural

En güçlü garantileri (ACID) mümkün olduğunca tek bir veritabanı içinde tutun ve bu sınırın ötesindeki her şeyi yeniden denemeler, mutabakat ve "bu adım başarısız olursa ne olur?" davranışıyla koordine edin.

Yeniden Denemeler, Idempotentlik ve Yinelenen İstekler

Hatalar nadiren "hiç olmadı" şeklinde görünür. Daha sık olan: bir istek kısmen başarılı olur, istemci zaman aşımına uğrar ve birisi (tarayıcı, mobil uygulama, job runner veya partner sistem) yeniden dener.

Koruma yoksa, yeniden denemeler en kötü türden hatayı yaratır: doğru görünen kod ara sıra çifte ücret, çift gönderim veya çift erişim verir.

Idempotentlik pratikte ne demek

Idempotentlik, aynı işlemi birden çok kez yapmak, tek kez yapmakla aynı sonuca yol açması özelliğidir. Kullanıcıya dönük sistemlerde bu "çift denemelere karşı güvenli" olmak demektir.

Yararlı kural: GET doğal olarak idempotent olmalı; birçok POST eylemi tasarlanmadıkça idempotent değildir.

Çoğaltmaları önleyen araçlar

Genelde birkaç mekanizmanın birleşimini kullanırsınız:

  • Idempotency anahtarları: istemci her niyet için benzersiz bir anahtar gönderir (ör. Idempotency-Key: ...). Sunucu sonucu bu anahtarla saklar ve tekrarlarda aynı sonucu döner.
  • Unique constraint'ler: veritabanı düzeyinde "sadece bir" kuralı uygular (ör. order_id başına bir ödeme).
  • Dedupe tabloları: işlenmiş istek ID'lerini/olayları saklar (webhook ve kuyruklar için yaygın), genellikle TTL ile.

Bunlar, benzersiz kontrolü ve etkinin aynı veritabanı işleminde yaşadığında en iyi çalışır.

Yeniden denemeler vs. işlemler ve zaman aşımı

Bir zaman aşımı, işlemin rollback olduğu anlamına gelmez; commit edilmiş olabilir ama yanıt kaybolmuştur. Bu yüzden retry mantığı sunucunun başarılı olabileceğini varsaymalıdır.

Yaygın desen: önce bir idempotency kaydı yazın (veya kilit uygulayın), yan etkileri gerçekleştirin, sonra tamamlandı olarak işaretleyin—mümkünse hepsini bir işlem içinde. Her şeyi tek bir işlem içinde sığdıramıyorsanız (örneğin, bir ödeme ağ geçidine çağrı), kalıcı bir "niyet" kaydedin ve sonrasında mutabakat yapın.

Günlük örnekler

  • Çift tıkla "Ödemeyi gönder": iki aynı istek gelir. Idempotency yoksa çift ücret riski vardır.
  • Webhook tekrar gönderimi: sağlayıcılar onaylanana kadar olayları yeniden yollar. Dedupe yoksa çift fatura oluşturabilir veya erişimi iki kez verebilirsiniz.

Güvenilir Veri İçin Tasarım ve Test Kontrol Listesi

Geri alma ile değişiklikleri test edin
İzolasyon seviyelerini ve şema değişikliklerini deneyin, ardından anlık görüntülerle güvenle geri alın.

Sistemler "güvenilmez" hissettiğinde, kök neden genellikle bozuk işlem düşüncesidir. Tipik belirtiler: karşılık gelen ödeme olmayan hayalet siparişler, eşzamanlı checkout'lardan sonra negatif stok ve defter, faturalar ve analizler arasında uyuşmayan toplamlar.

Tasarım kontrol listesi (kodu yazmadan önce)

Önce invariantlarınızı yazın—her zaman doğru olması gerekenler. Örnekler: "stok asla sıfırın altına düşmez", "bir sipariş ya ödenmemiştir ya da ödenmiştir (ikisi değil)", "her bakiye değişikliğinin eşleşen bir defter kaydı vardır."

Sonra bu invariantları koruyacak en küçük atomik işlem sınırlarını tanımlayın. Tek bir kullanıcı eylemi birden çok satırı/tabloyu etkiliyorsa, nelerin birlikte commit edilmesi gerektiğine ve nelerin güvenle ertelenebileceğine karar verin.

Son olarak, yük altında çatışmaları nasıl idare edeceğinizi seçin:

  • Kilitleme vs iyimser eşzamanlılık (sürüm sütunları)
  • Yinelenenleri önlemek için unique constraint'ler (ör. bir sipariş için bir ödeme)
  • Deadlock/zaman aşımı durumda açık yeniden deneme kuralları

Gerçek dünya hatalarını yakalayan test fikirleri

Eşzamanlılık hataları mutlu yol testlerinde nadiren görünür. Baskı yaratan testler ekleyin:

  • Eşzamanlılık testleri: aynı işlemi birçok iş parçacığı/processten çalıştırın; tamamlandıktan sonra invariantları doğrulayın.
  • Hata enjeksiyonu: bir işlemin ortasında servisi öldürün, DB bağlantılarını düşürün veya zaman aşımı zorlayın; kurtarmanın yarım kalmış durum bırakmadığını doğrulayın.
  • Üretim benzeri trafiği tekrar oynatma: (anonimleştirilmiş) istek dizilerini yeniden kullanarak kenar vakaları üretebilir ve düzeltmeleri doğrulayabilirsiniz.

İzlenecek sinyaller (alarm kurulmaya değer)

Koruyamadığınız şeyi ölçemezsiniz. Yararlı sinyaller: deadlock sayısı, kilit bekleme süreleri, rollback oranları (özellikle deploylardan sonra ani artışlar) ve kaynak-of-truth tabloları arasındaki mutabakat farkları (defter vs bakiyeler, siparişler vs ödemeler). Bu metrikler genelde müşterilerin "para/ürün eksik" demesinden haftalar önce sizi uyarır.

ACID Düşüncesini Aşırı Mühendislik Yapmadan Uygulamak

Jim Gray’in kalıcı katkısı sadece bir özellikler kümesi değil—"ne yanlış gitmemeli" için ortak bir sözlüktü. Ekipler ihtiyaç duydukları garantiyi (atomiklik, tutarlılık, izolasyon, kalıcılık) adlandırabildiğinde, doğrulukla ilgili tartışmalar belirsiz "güvenilir olmalı" ifadelerinden eyleme geçirilebilir maddelere dönüşür ("bu güncelleme şu ücretle atomik olmalı").

ACID konusunda ısrar edilecek yerler

Tam işlemleri kullanın; bir kullanıcının tek, kesin bir sonuç bekleyeceği ve hatanın maliyetli olacağı durumlarda:

  • Para hareketi: ücretlendirmeler, iadeler, bakiye güncellemeleri, ödemeler
  • Sipariş taahhüdü: sipariş oluşturma + stok ayırma + ödeme niyeti kaydı
  • Erişim ve yetkilendirmeler: abonelik değişiklikleri, rol atamaları, lisans koltukları
  • Denetim gereksinimleri: müşteriye, finans veya güvenliğe daha sonra açıklamanız gereken her şey

Burada garantileri zayıflatıp verimi iyileştirmek genelde maliyeti destek biletlere, manuel mutabakata ve kaybedilen güvene kaydırır.

Zayıf garantilerin kabul edilebilir olduğu yerler

Geçici tutarsızlığın kabul edilebilir ve kolayca iyileştirilebilir olduğu yerlerde gevşetin:

  • Okuma modelleri ve analizler (dakikalar gecikmeli raporlama genelde sorun değil)
  • Kritik olmayan sayaçlar (görüntülenme, beğeni) — yinelenmeler önemli değilse
  • Asenkron yan etkiler (e-postalar, webhooklar) — idempotent oldukları sürece

Püf nokta: "gerçek kaynağın" etrafında net bir ACID sınırı tutmak ve her şeyi onun arkasında geciktirmektir.

Hafif ama yüksek etkili pratik adımlar

  1. Kritik akışlarınızı listeleyin: para, siparişler, erişim ve müşteriyle yapılan sözleşmeyi değiştiren her şey.
  2. Invariantları açık İngilizce yazın (ve koda yakın tutun): "Bir sipariş en fazla bir kez ödenir", "Bir koltuk iki kere atanamaz", "Bakiye negatif olamaz."
  3. Her invariantı bir mekanizmaya eşleyin: işlem kapsamı, unique constraint'ler, idempotency anahtarları, ekleme-yalnızca denetim günlüğü.
  4. Çirkin yolları test edin: yeniden denemeler, zaman aşımı, çift tıklamalar ve kısmi hatalar.

Özellikle bu akışları prototipliyorsanız veya eski bir hattı yeniden inşa ediyorsanız, işlemleri ve kısıtları birinci sınıf yapan bir yığını tercih etmek işe yarar. Örneğin, Koder.ai basit bir sohbete dayalı olarak bir React ön yüz ve Go + PostgreSQL arka uç üretebilir; bu, idempotency kayıtları, outbox tabloları ve rollback-güvenli iş akışları dahil olmak üzere gerçek işlem sınırlarını erken kurmak için pratik bir yoldur.

Eğer daha fazla desen ve kontrol listesi isterseniz, bu beklentileri /blog üzerinden bağlayın. Eğer katmanlara göre güvenilirlik beklentileri sunuyorsanız, müşterilerin hangi doğruluk garantilerini aldığını bilmesi için bunları /pricing üzerinde açıkça belirtin.

SSS

Jim Gray kimdi ve neden fikirleri hâlâ önemli?

Jim Gray, işlem işleme konusunu pratik ve anlaşılır hale getiren bir bilgisayar bilimcisiydi. Mirası, para transferi, ödeme süreci, abonelik değişiklikleri gibi çok adımlı önemli eylemlerin eşzamanlılık ve hatalar altında doğru sonuçlar üretmesi gerektiği anlayışıdır.

Ürün açısından: daha az “gizemli durum”, daha az mutabakat yangını ve "taahhüt edilmiş" in gerçekte ne demek olduğu konusunda net garantiler sağlar.

Bir işlem (transaction) basitçe nedir?

Bir işlem, birden çok güncellemeyi tek bir tamamen-ya-da-hiçbiri birim olarak gruplayandır. Tüm adımlar başarılıysa commit edilir; herhangi biri başarısız olursa rollback yapılır.

Tipik örnekler:

  • Banka transferi: debit + credit + denetim kaydı
  • Ödeme tamamlaması: sipariş oluşturma + stok ayırma
  • Abonelik değişikliği: faturalama kararı + yetkilendirme değişikliği
ACID özellikleri gerçekte neyi korur?

ACID, işlemleri güvenilir kılan garantiler kümesidir:

  • Atomicity: tüm adımlar olur veya hiçbiri olmaz
  • Consistency: kurallar/invariantlar commit sonrası doğru kalır
  • Isolation: eşzamanlı etkinlik yanlış sonuçlar üretmez
  • Durability: commit edilmiş sonuçlar çökmelerden sonra kalır

Bu tek bir anahtar değildir—hangi garantilere ihtiyaç duyduğunuzu ve ne kadar güçlü olmaları gerektiğini seçersiniz.

Neden izolasyon bu kadar çok eşzamanlılık hatasının kaynağı?

Üretimde nadiren görülen hataların çoğu zayıf izolasyondan doğar.

Yaygın başarısızlık desenleri:

  • Kaybolan güncellemeler: iki yazıcı birbirini ezer
  • Çifte harcama/taşma: iki ödeme aynı son ürünü ayırır
  • Kirli okumalar: sonradan rollback olacak bir işlemin verisini görmek

Pratik çözüm: iş riski temelinde izolasyon seviyesini seçin ve gerektiğinde constraint/locking ile destekleyin.

İnvariantları nasıl tanımlar ve iyi işlem sınırları nasıl seçerim?

Önce açık ve basit İngilizce invariantlar yazın (her zaman doğru olması gerekenler), sonra bunları koruyacak en küçük atomik işlem sınırlarını belirleyin.

Birlikte iyi çalışan mekanizmalar:

  • Veritabanı kısıtları (ör. “stok sıfırın altına düşemez”)
  • Unique kısıtlar (ör. “bir sipariş için bir ödeme”)
  • İyimser eşzamanlılık (sürüm sütunları) veya açık kilitleme

Kısıtları, uygulama kodu eşzamansız davranış yaptığında güvenlik ağı olarak düşünün.

WAL ve işlem günlüğü nedir, neden önemlidir?

Write-ahead logging (WAL), veritabanlarının “commit”i çökmelerden sonra korumasını sağlayan yöntemdir.

Operasyonel olarak:

  • DB değişiklikleri bir ekleme-yalnızca günlüke yazılır
  • Yeniden başlatmada redo ile commit edilmiş işler tamamlanır, yarıda kalan işlemler undo ile geri alınır

Bu yüzden temiz bir tasarım: commit edildiyse, güç kaybından sonra da kalır.

Eğer işlem günlüklerim (WAL) varsa yedeklere ihtiyacım var mı?

Snapshot yani yedekler nokta-zaman görüntüleridir; loglar ise o görüntüden sonraki değişikliklerin geçmişidir.

Pratik kurtarma duruşu:

  • Periyodik yedekler alın
  • Point-in-time kurtarma için logları saklayın/gönderin
  • Düzenli olarak restore tatbikatları yapın ve gerçek RTO/RPO'yu ölçün

Hiç geri yüklemediğiniz bir yedek, plan değil umuttur.

Neden dağıtık işlemler (2PC gibi) genelde kaçınılıyor?

Dağıtık işlemler birden çok sistemi tek bir atomik işlem gibi göstermeye çalışır; ancak kısmi hatalar ve belirsiz zaman aşım durumları bunu zorlaştırır.

İki fazlı commit (2PC) genellikle:

  • Uzun sürebilen kilitler getirir (verim düşer)
  • Servisler arası sıkı bağlanma oluşturur
  • Koordinatör darboğazı/erişilebilirlik sorunları yaratır

Gerçekten çapraz-sistem atomikliği gerekiyorsa ve operasyonel karmaşıklığı kaldırabiliyorsanız kullanın.

Servisler arası dağıtık ACID yerine hangi pratik alternatifler var?

Küçük yerel ACID sınırları tutup servisler arası koordinasyonu açıkça yönetmek genelde daha ölçeklenir.

Yaygın desenler:

  • Sagas: büyük bir süreci yerel işlemlere bölme
  • Telafi edici eylemler: adım başarısızsa geri alma (iade, stok bırakma)
  • Outbox pattern: DB değişikliği ile yayınlanacak olayı aynı işlemde yaz, sonra güvenilir gönder

Böylece retry ve hatalar altında öngörülebilir davranış elde edilir, her akışı global kilit haline getirmeden.

Retry ve idempotentlik çift ücretlendirme ve yinelenen siparişleri nasıl önler?

Bir zaman aşımı “başarısız oldu” anlamına gelmeyebilir; sunucu aslında başarılı olmuş ama cevap kaybolmuş olabilir. Bu yüzden retry mantığı başarı olabileceğini varsaymalıdır.

Teknikler:

  • Idempotency anahtarları: istemci her eylem için benzersiz anahtar gönderir; sunucu sonucu bu anahtara bağlayıp tekrar aynı sonucu döner
  • Unique constraint'ler: veritabanı düzeyinde “en fazla bir” etkisi zorla
  • Dedupe tabloları: webhook ve kuyruk olayları için işlenmiş ID'leri sakla (TTL ile)

En iyi uygulama: dedupe kontrolü ile durum değişikliğini mümkünse aynı veritabanı işlemi içinde yapın.

Related posts