İyimser ve Kötümser kilitleme


571

İyimser ve kötümser kilitleme arasındaki farkları anlıyorum. Birisi bana genel olarak birini ne zaman kullanacağımı açıklayabilir mi?

Ve bu sorunun cevabı, sorguyu gerçekleştirmek için saklı bir yordam kullanıp kullanmadığımma bağlı olarak değişir mi?

Ama sadece kontrol etmek için, iyimser "okurken masayı kilitlemeyin" ve karamsar ise "okurken masayı kilitleyin" anlamına gelir.



1
Bu özellikle iyi bir soru çünkü serileştirilebilirlikte okudum At any technique type conflicts should be detected and considered, with similar overhead for both materialized and non-materialized conflicts.
Küçük Uzaylı

1
Burada , İyimser Kilitlemenin kök kavramının ne olduğu hakkında burada SO hakkında iyi bir açıklama bulabilirsiniz .
Diego Mazzaro

Yanıtlar:


812

İyimser Kilitleme , bir kaydı okuduğunuz, sürüm numarasını not ettiğiniz (bunu yapmak için diğer yöntemler tarihleri, zaman damgalarını veya sağlama toplamlarını / karmaları içerir) ve kaydı geri yazmadan önce sürümün değişip değişmediğini kontrol ettiğiniz bir stratejidir. Kaydı geri yazdığınızda, güncellemenin atomik olduğundan emin olmak için sürüme filtre uygularsınız. (örneğin, sürümü kontrol edip kaydı diske yazdığınızda arasında güncellenmedi) ve sürümü tek bir tıklamayla güncelleyin.

Kayıt kirliyse (yani sizinkinden farklı bir sürüm) işlemi iptal edersiniz ve kullanıcı kaydı yeniden başlatabilir.

Bu strateji en çok oturumunuz için veritabanıyla bağlantı kurmanız gerekmeyen yüksek hacimli sistemler ve üç katmanlı mimariler için geçerlidir. Bu durumda, istemci bağlantıları bir havuzdan alındığından veritabanı kilitlerini koruyamaz ve bir bağlantıdan diğerine aynı bağlantıyı kullanmıyor olabilirsiniz.

Kötümser Kilitleme , kaydı bitirene kadar münhasır kullanımınız için kaydı kilitlediğiniz zamandır . İyimser kilitlemeden çok daha iyi bir bütünlüğe sahiptir, ancak Deadlock'lardan kaçınmak için uygulama tasarımınıza dikkat etmenizi gerektirir . Kötümser kilitlemeyi kullanmak için veritabanına doğrudan bir bağlantıya (tipik olarak iki katmanlı bir istemci sunucu uygulamasında olduğu gibi) veya bağlantıdan bağımsız olarak kullanılabilen harici olarak kullanılabilen bir işlem kimliğine ihtiyacınız vardır.

İkinci durumda, işlemi TxID ile açar ve ardından bu kimliği kullanarak yeniden bağlanırsınız. DBMS kilitleri korur ve oturumu TxID üzerinden yedeklemenizi sağlar. İki aşamalı kesinleştirme protokollerini ( XA veya COM + İşlemleri gibi ) kullanarak dağıtılmış işlemler bu şekilde çalışır.


148
İyimser kilitleme mutlaka sürüm numarası kullanmaz. Diğer stratejiler arasında (a) bir zaman damgası veya (b) satırın kendisinin tüm durumu kullanılabilir. İkinci strateji çirkindir, ancak şemayı değiştiremediğiniz durumlarda özel bir sürüm sütununa ihtiyaç duymaz.
Andrew Swan

2
@geek - XA gibi dağıtılmış işlem protokolleri, ayrı bir işlem tanımlayıcısının bir veya daha fazla sistem etrafında retiküle edilmesine izin verir. Bu tür bir protokol, işlem tanımlayıcısı oturumlardan ayrıldığından ve açık bir şekilde sağlandığından kilitlerin birleştirilmiş bağlantılar aracılığıyla kullanılmasına izin verir. Ancak, bu işlem bazı ek yüklere neden olur ve uygulamanız bunları takip etmek konusunda titiz değilse, sızıntı kilitlerine ve işlem tanımlayıcılarına eğilimlidir. Çok daha ağır bir çözümdür.
ConcernedOfTunbridgeWells

22
@supercat - İyimser kilitlemenin% 100'den az doğru olduğunu kabul etmeyin - süre boyunca değiştirilmemesi gereken işlem için tüm girdi kayıtlarını kontrol ettiği sürece, bunlar üzerinde kötümser kilitleme (güncelleme stili için seçin) kadar doğru aynı kayıtlar. Temel fark, iyimser kilitlemenin yalnızca bir çatışma olması durumunda ek yüke neden olurken, karamsar kilitlemenin çatışmada ek yükü azaltmasıdır. Bu nedenle, çoğu işlemin çakışmadığı durumlarda iyimserdir - umarım çoğu uygulama için genellikle böyle olur.
RichVel

2
@Legends - İyimser kilitleme kullanmak kesinlikle bir web uygulaması için uygun bir strateji olacaktır.
ConcernedOfTunbridgeWells

2
Seçimin ayrıca okuma / yazma oranına da bağlı olduğunu belirtmelisiniz: uygulamanız çoğunlukla çok sayıda kullanıcı tarafından salt okunur bir uygulama ise ve bazen veri yazıyorsanız, iyimser kilitleme için gidin. Örneğin StackOverflow, birçok insanın sayfaları okuduğunu ve bazen de birinin birini düzenlediğini: kötümser kilitlemede kilidi kim alabilir? ilki? İyimser kilitlemede, sayfayı düzenlemek isteyen kişi, sayfanın son sürümüne sahip olduğu sürece bunu yapabilir.
jehon

177

Çok fazla çarpışma beklemediğinizde iyimser kilitleme kullanılır. Normal bir işlem yapmanın maliyeti daha azdır, ancak çarpışma gerçekleşirse, işlem iptal edildiğinde çözümü çözmek için daha yüksek bir fiyat ödersiniz.

Kötümser kilitleme, bir çarpışma beklendiğinde kullanılır. Senkronizasyonu ihlal edecek işlemler basitçe engellenir.

Doğru kilitleme mekanizmasını seçmek için okuma ve yazma miktarını tahmin etmeniz ve buna göre plan yapmanız gerekir.


Normal durumda, ifade mükemmeldir, ancak CAS operasyonunu cevapta @skaffman'ın belirttiği gibi yanlışlıklara izin verebileceğiniz özel durumlarda , gerçekten bağlı olduğunu söyleyebilirim.
1919'da

75

İyimser, siz okurken hiçbir şeyin değişmeyeceğini varsayar.

Kötümser bir şeyin olacağını ve böylece onu kilitlediğini varsayar.

Verilerin tam olarak okunması şart değilse iyimser kullanın. Garip 'kirli' okuyabilirsiniz - ancak kilitlenme ve benzeri sonuçlarla sonuçlanma olasılığı daha düşüktür.

Çoğu web uygulaması kirli okumalarla iyidir - nadir durumlarda veriler bir sonraki yeniden yüklemede tam olarak uymaz.

Kesin veri işlemleri için (birçok finansal işlemde olduğu gibi) kötümser kullanın. Verilerin, gösterilmeyen hiçbir değişiklik olmadan doğru bir şekilde okunması önemlidir - ekstra kilitleme yükü buna değer.

Oh, ve Microsoft SQL sunucusu varsayılan olarak sayfa kilitleme - temelde okuduğunuz satır ve her iki tarafı. Satır kilitleme daha doğru ancak daha yavaştır. Okurken kilitlenmeleri önlemek için işlemlerinizi okumaya kararlı veya kilitsiz olarak ayarlamaya değer.


JPA İyimser Kilitleme, okuma tutarlılığını garanti etmenizi sağlar.
Gili

4
Okuma tutarlılığı ayrı bir konudur - PostgreSQL, Oracle ve diğer birçok veritabanıyla, henüz yapılmayan güncellemelerden bağımsız olarak tutarlı bir veri görünümü elde edersiniz ve özel satır kilitlerinden bile etkilenmezsiniz.
RichVel

@RichVel ile anlaşmak zorundayım. Bir yandan, eğer işlem yalıtım seviyeniz OKUYUNSUZ OKUYUN, karamsar kilitlemenin kirli okumaları nasıl önleyebileceğini görebiliyorum. Ancak iyimser kilitlemenin, çoğu veritabanının (görünüşte MS SQL Server da dahil olmak üzere) varsayılan bir "READ COMMITTED" yalıtım düzeyine sahip olduğunu ve kirli okumaları engellediğini ve iyimser kilitlemenin aynı derecede doğru olmasını sağlayan kirli okumalara duyarlı olduğunu söylemek yanıltıcıdır. kötümser.
antinome

Eric Brower, bankacıların diğerlerinden farklı olarak kirli işlemleri tercih ettiğini söylüyor. Gurularınız kesinlikle arabaların dışında görünüyor.
Little Alien

1
Eric Brewer CAP teoremini veren guru , bankacılıkta tutarlılık olduğunu söylüyor . Sizin için onurlandırdığınız şeyin tam tersidir.
Little Alien

50

Zaten söylenenlere ek olarak:

  • optimisticKilitlemenin öngörülebilirlik pahasına eşzamanlılığı geliştirme eğiliminde olduğu söylenmelidir .
  • Pessimistickilitleme eşzamanlılığı azaltma eğilimindedir, ancak daha tahmin edilebilir. Paranızı ödersiniz, vb ...

3
Kötümser kilitleme ile öngörülebilirliğin nasıl geliştiğini göremiyorum - 'işlem kilitler alındığında tamamlanabilir' demek istiyorsanız haklısınız, ancak işlem gerekli tüm kilitlere sahip olana kadar, almak için bir gecikme yaşayabilir kalan kilitler ve aslında DB kilitlenme algılama + çözünürlük mantığı nedeniyle iptal edilebilir. Kötümser kilitleme kullanan uygulamalar oldukça öngörülemeyen yürütme sürelerine sahip olabilir - klasik örnek, bir kişinin X kaydını kilitledikten sonra öğle yemeğine gitmesi, daha sonra bir kullanıcı X ve Y kaydını, ardından başka bir Y ve Z'yi kilitler ve çoğu kullanıcı engellenene kadar devam eder. ..
RichVel

40

Çatışmalarla uğraşırken iki seçeneğiniz vardır:

  • Çatışmayı önlemeye çalışabilirsiniz, Kötümser Kilitlemenin yaptığı da budur.
  • Ya da, çatışmanın gerçekleşmesine izin verebilirsiniz, ancak işlemlerinizi gerçekleştirdikten sonra bunu tespit etmeniz gerekir ve bu da İyimser Kilitlemenin yaptığı şeydir.

Şimdi, aşağıdaki Kayıp Güncelleme anomalisini ele alalım :

Kayıp Güncelleme

Kayıp Güncelleme anormalliği Okunan Taahhütlü yalıtım düzeyinde olabilir.

Yukarıdaki şemada Alice'in 40'ı ondan çekebileceğine inandığını accountancak Bob'un hesap bakiyesini yeni değiştirdiğini fark etmediğini görebiliyoruz ve şimdi bu hesapta sadece 20 tane kaldı.

Kötümser Kilitleme

Kötümser kilitleme, bu hedefe hesap üzerinde paylaşılan veya okunan bir kilit alarak ulaşır, böylece Bob'un hesabı değiştirmesi önlenir.

Kayıp Güncelleme Kötümser Kilitleme

Yukarıdaki şemada, hem Alice hem de Bob, her accountiki kullanıcının da okuduğu tablo satırında bir okuma kilidi edinecek . Veritabanı, Tekrarlanabilir Okuma veya Serileştirilebilir kullanırken SQL Server'da bu kilitleri alır.

Hem Alice hem de Bob account, PK değeri ile okuduğu için 1, ikisi de bir kullanıcı okuma kilidini bırakana kadar değiştiremez. Bunun nedeni, bir yazma işleminin bir yazma / özel kilit edinimi gerektirmesidir ve paylaşılan / okuma kilitleri yazma / özel kilitleri önler.

Ancak Alice işlemi gerçekleştirdikten ve accountsatırdaki okuma kilidi serbest bırakıldıktan sonra , Bob UPDATEdeğişikliği sürdürecek ve uygulayacaktır. Alice okuma kilidini bırakana kadar Bob'un GÜNCELLEME bloke eder.

Veri erişim çerçevelerinin temel veritabanı kötümser kilitleme desteğini nasıl kullandığı hakkında daha fazla bilgi için bu makaleye göz atın .

İyimser Kilitleme

İyimser Kilitleme, çatışmanın gerçekleşmesine izin verir, ancak sürüm değiştikçe Alice'in UPDATE'ini uyguladıktan sonra algılar.

Uygulama düzeyinde işlemler

Bu sefer ek bir versionsütun daha var. versionSütun her seferinde bir UPDATE artırılır veya DELETE yürütüldüğünde ve ayrıca UPDATE ve DELETE deyimleri WHERE cümleciği kullanılır. Bunun çalışması için, versionGÜNCELLEME veya SİL'i çalıştırmadan önce SELECT'i seçmeli ve akımı okumalıyız, aksi halde WHERE yan tümcesine veya artışına hangi sürüm değerinin geçeceğini bilemeyiz.

Veri erişim çerçevelerinin iyimser kilitlemeyi nasıl uyguladığı hakkında daha fazla bilgi için bu makaleye göz atın .

Uygulama düzeyinde işlemler

İlişkisel veritabanı sistemleri, bir müşterinin tipik olarak bir terminal aracılığıyla bir ana kareye bağlanacağı 70'li yılların sonlarında ortaya çıktı. Bu yüzden hala veritabanı sistemlerinin OTURUM ayarı gibi terimler tanımladığını görüyoruz.

Günümüzde, internet üzerinden artık aynı veritabanı işlemi bağlamında okuma ve yazma işlemleri gerçekleştirmiyoruz ve ACID artık yeterli değil.

Örneğin, aşağıdaki kullanım durumunu göz önünde bulundurun:

resim açıklamasını buraya girin

İyimser kilitleme olmadan, veritabanı işlemleri Serializable kullansa bile bu Kayıp Güncellemenin yakalanmasının bir yolu yoktur. Bunun nedeni, okuma ve yazma işlemlerinin ayrı HTTP isteklerinde, dolayısıyla farklı veritabanı işlemlerinde yürütülmesidir.

Bu nedenle, iyimser kilitleme, kullanıcı düşünme süresini de içeren uygulama düzeyinde işlemleri kullanırken bile Kayıp Güncellemeleri önlemenize yardımcı olabilir.

Uygulama düzeyinde veya mantıksal işlemler hakkında daha fazla bilgi için bu makaleye göz atın .

Sonuç

İyimser kilitleme çok kullanışlı bir tekniktir ve Okuma Taahhütlü gibi daha az katı yalıtım düzeyleri kullanıldığında veya sonraki veritabanı işlemlerinde okuma ve yazma yürütüldüğünde bile iyi çalışır.

İyimser kilitlemenin dezavantajı, yakalama üzerine veri erişim çerçevesi tarafından bir geri dönüşün tetiklenmesidir OptimisticLockException, bu nedenle daha önce yürütülmekte olan işlem tarafından daha önce yaptığımız tüm işleri kaybeder.

Daha fazla çekişme, daha fazla çatışma ve işlemleri iptal etme şansı artar. Geri almalar, hem tablo satırlarını hem de dizin kayıtlarını içerebilecek tüm geçerli bekleyen değişiklikleri geri alması gerektiğinden veritabanı sistemi için maliyetli olabilir.

Bu nedenle, çatışmalar sık ​​sık meydana geldiğinde kötümser kilitleme cevheri uygun olabilir, çünkü işlemlerin geri alınma şansını azaltır.


Hangi senaryolar için OptimisticLocking ve PessimisticLocking'i seçmenizi önerirsiniz? OptimisticLockException'ın ne sıklıkta gerçekleştiğine bağlı mı?
Stimpson Cat

1
Kullanım durumuna bağlıdır. Bazen, iyimser kilitleme tek çözümdür (örneğin, çoklu talep işlemleri). Diğer zamanlarda kötümser kilitleme tek çözümdür (örn. PostgreSQL tavsiye kilitleri ). Bazen, onları olduğu gibi birleştirmeniz gerekir PESSIMISTIC_FORCE_INCREMENT.
Vlad Mihalcea

22

Kötümser kilitlemenin daha iyi bir seçim olacağı bir durum daha düşünürdüm.

İyimser kilitleme için veri modifikasyonundaki her katılımcı bu tür bir kilitleme kullanmayı kabul etmelidir. Ancak birisi sürüm sütununa dikkat etmeden verileri değiştirirse, bu iyimser kilitleme fikrini bozacaktır.


İyimser ve kötümser kilitleme kullanmaya çalışan insanlar, aynı zamanda, birbirlerinin ayaklarına da basabilirler. İyimser bir oturumun bir kaydı okuduğu ve kötümser bir oturum kaydı güncellediğinde bazı hesaplamalar yaptığının, daha sonra iyimser oturumun geri döndüğünü ve yapılan değişiklikleri kaydetmeden aynı kaydı güncellediği bir senaryo düşünün. Güncelleme için ... seçeneğini belirleyin, yalnızca her oturum aynı sözdizimini kullanıyorsa çalışır.
Temmuz

İyi Açıklama, Benden oy ver
Dulaj Kulathunga

15

Temel olarak en popüler iki cevap vardır. İlki temelde diyor

İyimser, oturumunuz için veritabanıyla bağlantı kurmanız gerekmediği üç katmanlı bir mimariye ihtiyaç duyarken, Kötümser Kilitleme, kaydı bitirene kadar özel kullanımınız için kaydı kilitlediğiniz zamandır. Veritabanına doğrudan bağlantıya ihtiyacınız olan iyimser kilitlemeden çok daha iyi bir bütünlüğe sahiptir.

Başka bir cevap

iyimser (versiyonlama) kilitleme olmadığı için daha hızlıdır ancak çekişme yüksek olduğunda (kötümser) kilitleme daha iyi performans gösterir ve işi atmak ve baştan başlamak yerine önlemek daha iyidir.

veya

İyimser kilitleme, nadiren çarpıştığınızda en iyi sonucu verir

O koymak gibi bu sayfada.

Cevabımı, "bağlantıyı sürdür" ün "düşük çarpışmalar" ile nasıl ilişkili olduğunu açıklamak için oluşturdum.

Hangi stratejinin sizin için en iyi olduğunu anlamak için DB'nizin Saniyedeki İşlemleri değil, tek bir işlemin süresini düşünün. Normalde, işlem, performans işlemi açar ve işlemi kapatırsınız. Bu ANSI'nin kilitleme ile kurtulmak için akılda tuttuğu kısa ve klasik bir işlemdir. Ancak, birçok müşterinin aynı oda / koltuğu aynı anda ayırdığı bir bilet rezervasyon sistemini nasıl uygularsınız?

Tekliflere göz atıyorsunuz, formu birçok seçenek ve mevcut fiyatlarla dolduruyorsunuz. Çok fazla zaman alıyor ve seçenekler eskimiş olabilir, aranızdaki geçersiz tüm fiyatlar formu doldurmaya ve "Kabul ediyorum" düğmesine basmaya başladı, çünkü eriştiğiniz veriler üzerinde kilit yoktu ve başka biri daha çevik, etkileşime girdi tüm fiyatları değiştirmek ve yeni fiyatlar ile yeniden başlatmanız gerekir.

Bunun yerine tüm seçenekleri okurken kilitleyebilirsiniz. Bu karamsar bir senaryodur. Neden berbat olduğunu görüyorsun. Sisteminiz basitçe rezervasyon yapmaya başlayan ve sigara içen tek bir palyaço tarafından kaldırılabilir. Kimse bitmeden hiçbir şey ayıramaz. Nakit akışınız sıfıra düşer. Bu yüzden gerçekte iyimser çekinceler kullanılıyor. Çok uzun sürenlerin rezervasyonlarına daha yüksek fiyatlarla yeniden başlaması gerekir.

Bu iyimser yaklaşımda, okuduğunuz tüm verileri kaydetmelisiniz ( benimki Tekrarlanan Okuma'da olduğu gibi ) ve veri sürümünüzle birlikte taahhüt noktasına gelmelisiniz (Mevcut fiyatta değil, bu fiyatta görüntülediğiniz fiyattan hisse satın almak istiyorum ). Bu noktada, DB'yi kilitleyen, hiçbir şeyin değiştirilip değiştirilmediğini kontrol eder ve işleminizi iptal eder / iptal eder. IMO, bu aynı zamanda Optimistic CC ile de ilişkili olan MVCC'nin etkili emülasyonudur ve ayrıca iptal durumunda işleminizin yeniden başladığını varsayar, yani yeni bir rezervasyon yaparsınız. Buradaki bir işlem, bir kullanıcı kullanıcı kararını içerir.

MVCC'yi manuel olarak nasıl uygulayacağımı anlamaktan çok uzakım, ancak yeniden başlatma seçeneğiyle uzun süren işlemlerin konuyu anlamanın anahtarı olduğunu düşünüyorum. Herhangi bir yerde yanılıyorsam beni düzeltin. Cevabım bu Alex Kuznecov bölümü tarafından motive edildi .


12

Çoğu durumda, iyimser kilitleme daha verimlidir ve daha yüksek performans sunar. Kötümser ve iyimser kilitleme arasında seçim yaparken aşağıdakileri göz önünde bulundurun:

  • Kötümser kilitleme, aynı anda verileri güncellemeye çalışan çok sayıda güncelleme ve nispeten yüksek kullanıcı şansı varsa yararlıdır. Örneğin, her işlem aynı anda çok sayıda kaydı güncelleyebiliyorsa (banka her ayın sonunda her hesaba faiz kazancı ekleyebilir) ve iki uygulama aynı anda bu işlemleri gerçekleştiriyorsa, çakışmalar olacaktır .

  • Kötümser kilitleme, sıklıkla güncellenen küçük tablolar içeren uygulamalarda da daha uygundur. Sözde sıcak noktalar söz konusu olduğunda, çatışmalar o kadar olasıdır ki, iyimser kilitleme, çatışan işlemleri geri alma çabalarını boşa harcar.

  • İyimser kilitleme, çakışma olasılığı çok düşükse yararlıdır - çok sayıda kayıt var, ancak nispeten az kullanıcı veya çok az güncelleme ve çoğunlukla okuma tipi işlemler var.


3

İyimser kilitleme için bir kullanım örneği, uygulamanızın iş parçacıklarınızdan / ana bilgisayarlarınızdan birinin bir görevi 'talep etmesine' izin vermek için veritabanını kullanmasını sağlamaktır. Bu benim için düzenli olarak kullanışlı bir teknik.

Düşünebileceğim en iyi örnek, aynı anda birden çok iş parçacığı olduğunu iddia eden bir veritabanı kullanılarak uygulanan bir görev kuyruğudur. Bir görevin durumu 'Kullanılabilir', 'Hak Talebinde Bulunuldu', 'Tamamlandı' durumundaysa, bir db sorgusu "Durum = 'Kullanılabilir" olarak ayarlayın Durum = "Kullanıldı" gibi bir şey söyleyebilir. Birden çok iş parçacığı durumu bu şekilde değiştirmeye çalışırsa, ilk iş parçacığı hariç tümü kirli veriler nedeniyle başarısız olur.

Bunun yalnızca iyimser kilitlemeyi içeren bir kullanım durumu olduğunu unutmayın. Bu nedenle, "Çok fazla çarpışma beklemediğinizde iyimser kilitleme kullanılır" demeye alternatif olarak, çarpışmalar beklediğiniz ancak tam olarak bir işlemin başarılı olmasını istediğiniz yerde de kullanılabilir.


3

Yukarıda iyimser ve kötümser kilitleme hakkında pek çok iyi şey söylendi. Dikkate alınması gereken önemli bir nokta şudur:

İyimser kilitlemeyi kullanırken, uygulamanın bu hatalardan nasıl kurtulacağı konusunda dikkatli olmalıyız.

Özellikle asenkron mesaj güdümlü mimarilerde, bu durum bozuk mesaj işleme veya kayıp güncellemelere yol açabilir.

Hata senaryoları üzerinde düşünülmelidir.

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.