İyimser kilitleme çalışmadığında ne yapmalıyım?


11

Aşağıdaki senaryo var:

  1. Bir kullanıcı bir hale getirir GET isteği /projects/1ve aldığı ETag .
  2. Kullanıcı 1. adımdan ETag ile PUT isteği yapar /projects/1.
  3. Kullanıcı, /projects/1adım # 1'den ETag ile başka bir PUT isteği yapar .

Normalde, ETag artık eski olduğu için ikinci PUT isteği 412 yanıtı alır - ilk PUT isteği kaynağı değiştirdi, böylece ETag artık eşleşmiyor.

Ancak, iki PUT isteği aynı anda gönderilirse (veya tam olarak birbiri ardına)? İlk PUT isteğinin, PUT # 2 gelmeden önce kaynağı işlemek ve güncellemek için zamanı yoktur, bu da PUT # 2'nin PUT # 1'in üzerine yazmasına neden olur. İyimser kilitlemenin bütün amacı bunun olmamasıdır ...


3
Esben'in açıkladığı gibi, işletme düzeyinde işlemlerde faaliyetlerinizi canlandırın.
Robert Harvey

İşlemlerimi işlemleri kullanarak atomize etsem ne olur? PUT # 2, PUT # 1 tamamen işlenene kadar işlenmeyecek mi?
maximedupre

7
Kötümser olmak mı?
jpmc26

iyi kilitleme bunun için.
Fattie

Doğru, tabii ki Put # 2 işlenmemelidir - benzersiz olmaları gerekir.
Fattie

Yanıtlar:


21

ETag mekanizması yalnızca iyimser kilitleme için iletişim protokolünü belirtir. İyimser kilidi uygulamak için eşzamanlı güncellemeleri tespit etme mekanizmasını uygulamak uygulama hizmetinin sorumluluğundadır.

Veritabanı kullanan tipik bir uygulamada, bunu genellikle bir PUT isteği işlenirken bir işlem açarak yaparsınız. Normalde söz konusu işlemin içindeki veritabanının mevcut durumunu okurdunuz (okuma kilidi elde etmek için), Etag geçerliliğinizi kontrol edersiniz ve verilerin üzerine yazarsınız (uyumsuz eşzamanlı işlem olduğunda yazma çakışmasına neden olacak şekilde), sonra taahhüt. İşlemi doğru şekilde ayarlarsanız, her ikisi de aynı verileri aynı anda güncellemeye çalışacağından taahhütlerden biri başarısız olmalıdır. Daha sonra bu işlem hatasını, uygulama için mantıklıysa, 412 döndürmek veya isteği yeniden denemek için kullanabilirsiniz.


Sunucunun şu anda eşzamanlı güncellemeleri algılama mekanizmasını uygulama şekli, kaynağın karmaları karşılaştırmaktır. Sunucu ayrıca tüm işlemler için işlemleri kullanır, ancak herhangi bir kilit almıyorum, bu da soruna neden olan şey olabilir. Ancak örneğinizde, işlemler kilit kullanıyorsa işlemlerden birinde nasıl bir hata olabilir? İlk işlem çözülene kadar, durumu okurken ikinci işlemin beklemede olması gerekir.
maximedupre

1
@maximedupre: Eğer işlem kullanıyorsanız, örtük kilitler olsa da, bir çeşit kilitleriniz vardır (kilitler, açıkça istenen yerine alanları okuduğunuzda / güncellediğinizde otomatik olarak alınır). Yukarıda tarif ettiğim mekanizma sadece örtük kilitleme kullanılarak uygulanabilir. Diğer sorunuz olarak, kullandığınız veritabanına bağlıdır, ancak birçok modern veritabanı, birden fazla okuyucu ve yazarın birbirlerini gereksiz yere engellemeden aynı alanlarda çalışmasına izin vermek için MVCC'yi (çoklu sürüm eşzamanlılık kontrolü) kullanır.
Yalan Ryan

1
Uyarı: Birçok DBMS'de (PostgreSQL, Oracle, SQL Server vb.), Varsayılan işlem yalıtım düzeyi "okundu" şeklindedir; burada yaklaşımınız OP'nin yarış durumunu önlemek için yeterli değildir . Böyle DMBSes, siz de dahil bunu düzeltebilirsiniz AND ETag = ...sizin de UPDATEifadenin WHEREmaddede ve sonrasında güncellenen-satır-sayımını kontrol ediyor. (Ya da daha katı bir işlem yalıtım düzeyi kullanarak, ama gerçekten tavsiye etmiyorum.)
ruakh

1
@ruakh: sorgunuzu nasıl yazdığınıza bağlıdır, evet varsayılan yalıtım düzeyi tüm sorgular için otomatik olarak bu davranışı sağlamaz, ancak işleminizi iyimser kilitleme uygulamak için yeterli olacak şekilde yapılandırmak genellikle mümkündür. Çoğu durumda, uygulamada işlem tutarlılığı önemliyse, yine de varsayılan yalıtım düzeyi olarak tekrarlanabilir okuma öneririm; MVCC kullanan veritabanlarında, tekrarlanabilir okuma yükü oldukça azdır ve uygulamayı önemli ölçüde basitleştirir.
Yalan Ryan

1
@ruakh: tekrarlanabilir okumanın ana dezavantajı, eşzamanlı işlem varsa yeniden denemeye veya başarısız olmaya hazır olmanızdır. Bu normalde bir sorundur, ancak eşzamanlılık stratejisi olarak İyimser kilitleme sağlayan uygulamalar zaten bu işlemeyi gerektirecektir, bu nedenle tekrarlanabilir okuma hataları iyimser kilitleme hatalarına doğal olarak eşlenir ve bu aslında yeni dezavantajlar eklemez.
Yalan Ryan

13

Aşağıdaki çifti atomik olarak yürütmelisiniz:

  • etiketin geçerliliğini kontrol etme (yani güncel)
  • kaynağı güncelleme (etiketinin güncellenmesini içerir)

Diğerleri buna bir işlem diyorlar - ama temel olarak, bu iki işlemin atomik olarak yürütülmesi, zamanlama kazasıyla birinin diğerinin üzerine yazmasını engelleyen şeydir; bu olmadan bir yarış durumunuz var, belirttiğiniz gibi.

Büyük resme bakarsanız, bu yine de iyimser kilitleme olarak kabul edilir: kaynağın kendisinin, herhangi bir Kullanıcı veya veriye bakan herhangi bir Kullanıcı tarafından, güncelleme amaçlı olsun ya da olmasın, ilk okuma (GET) tarafından kilitlenmediği.

Bazı atomik davranışlar gereklidir, ancak bu, birden çok ağ etkileşimi üzerinde bir kilit tutmaya çalışmak yerine tek bir istek (PUT) içinde gerçekleşir; bu iyimser kilitlemedir: nesne GET tarafından kilitlenmemiştir ancak yine de PUT tarafından güvenli bir şekilde güncellenebilir.

Bu iki işlemin atomik yürütülmesini sağlamanın birçok yolu vardır - kaynağı kilitlemek tek seçenek değildir; örneğin, hafif bir iş parçacığı veya nesne kilidi yeterli olabilir ve uygulamanızın mimarisine ve yürütme içeriğine bağlıdır.


4
Önemli olan atomik olduğunu belirttiğiniz için +1. Güncellenmekte olan kaynağa bağlı olarak, bu işlem veya kilitlenme olmadan gerçekleştirilebilir. Örneğin, bir bellek içi kaynağın atomik karşılaştırma ve takas etme veya kalıcı verilerin olay kaynağı oluşturma.
Aaron M. Eshbach

@ AaronM.Eshbach, kabul etti ve onları çağırdığın için teşekkürler.
Erik Eidt

1

E-Tag'i kontrol etmek ve bu mantığı sağlamak uygulama geliştiricisinde. Web sunucusunun sizin için yaptığı sihir değildir, çünkü yalnızca E-Tagstatik içerik için başlıkların nasıl hesaplanacağını bilir . Öyleyse yukarıdaki senaryoyu ele alalım ve etkileşimin nasıl olması gerektiğine bakalım.

GET /projects/1

Sunucu isteği alır, kaydın bu sürümü için E-Etiketi belirler ve bunu gerçek içerikle döndürür.

200 - OK
E-Tag: "412"
Content-Type: application/json
{modified: false}

İstemci artık E-Tag değerine sahip olduğundan, PUTisteği şu şekilde içerebilir :

PUT /projects/1
If-Match: "412"
Content-Type: application/json
{modified: true}

Bu noktada başvurunuz aşağıdakileri yapmak zorundadır:

  • E-Tag'in hala doğru olduğunu doğrulayın: "412" == "412"?
  • Öyleyse, güncellemeyi yapın ve yeni bir E-Tag hesaplayın

Başarı yanıtını gönderin.

204 No Content
E-Tag: "543"

Başka bir istek gelirse ve PUTyukarıdaki isteğe benzer bir işlem yapmaya çalışırsa , sunucu kodunuz ikinci kez değerlendirdiğinde, hata iletisini sağlamaktan sorumlusunuz.

  • E-Tag'in hala doğru olduğunu doğrulayın: "412"! = "543"

Hata durumunda, hata yanıtını gönderin.

412 Precondition Failed

Bu aslında yazmak zorunda olduğunuz koddur. E-Tag aslında herhangi bir metin olabilir (HTTP spesifikasyonunda tanımlanan sınırlar dahilinde). Bir sayı olmak zorunda değil. Bu bir karma değer de olabilir.


Bu, burada kullandığınız standart bir HTTP notasyonu değildir. Standart uyumlu HTTP'de, yanıt başlığında yalnızca ETag kullanırsınız. ETag'i hiçbir zaman istek üstbilgisine göndermezsiniz, bunun yerine önceden alınan ETag değerini bir If-Match veya If-None-Match üstbilgisinde istek başlıklarında kullanırsınız.
Yalan Ryan

-2

Diğer cevapların bir tamamlayıcısı olarak, ZeroMQ belgelerinde temel meseleyi sadakatle açıklayan en iyi alıntılardan birini yayınlayacağım:

Tamamen mükemmel MT programları yapmak (ve tam anlamıyla), ZeroMQ soketleri üzerinden gönderilen mesajlar dışında mutekslere, kilitlere veya başka bir iletişim arası iletişime ihtiyacımız yok.

"Mükemmel MT programları" ile, yazması ve anlaması kolay, herhangi bir programlama dilinde ve herhangi bir işletim sisteminde aynı tasarım yaklaşımıyla çalışan ve sıfır bekleme durumuna sahip ve hiçbir noktaya sahip olmayan çok sayıda CPU arasında ölçeklenen kodu kastediyorum azalan getiriler.

MT kodunuzu hızlı bir şekilde, kilitler ve semaforlar ve kritik bölümlerle çalışmak için hileler öğrenmek için yıllarca harcadıysanız, bunun hiçbir şey için olmadığını anladığınızda tiksinmiş olacaksınız. 30 yıldan fazla eşzamanlı programlamadan öğrendiğimiz bir ders varsa, bu: sadece durumu paylaşmayın. Bir bira paylaşmaya çalışan iki ayyaş gibi. İyi dostlar olup olmadıkları önemli değil. Er ya da geç, kavgaya girecekler. Ve masaya ne kadar fazla sarhoş eklerseniz, bira üzerinde birbirleriyle o kadar fazla savaşırlar. MT uygulamalarının trajik çoğunluğu sarhoş bar dövüşlerine benziyor.

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.