MongoDB'de işlemlerin olmaması konusunda nasıl çalışılır?


139

Burada benzer sorular olduğunu biliyorum ama işlemlere ihtiyacım olursa ya da atomik işlemler veya iki fazlı taahhüt kullanıyorsam normal RDBMS sistemlerine geri dönmemi söylüyorlar . İkinci çözüm en iyi seçim gibi görünüyor. Üçüncüsünü takip etmek istemiyorum çünkü birçok şey yanlış gidebilir ve her açıdan test edemiyorum. Atomik işlemler yapmak için projemi yeniden düzenlerken zorlanıyorum. Bunun sınırlı bakış açımdan gelip gelmediğini bilmiyorum (şimdiye kadar sadece SQL veritabanlarıyla çalıştım) veya gerçekten yapılamıyor mu.

Şirketimizde MongoDB'yi test etmek istiyoruz. Nispeten basit bir proje seçtik - bir SMS geçidi. Yazılımımızın hücresel şebekeye SMS mesajları göndermesine izin verir ve ağ geçidi kirli işi yapar: aslında farklı iletişim protokolleri aracılığıyla sağlayıcılarla iletişim kurmak. Ağ geçidi ayrıca mesajların faturalandırılmasını yönetir. Hizmete başvuran her müşteri bir miktar kredi almak zorundadır. Bir mesaj gönderildiğinde sistem kullanıcının bakiyesini otomatik olarak azaltır ve bakiye yetersiz olduğunda erişimi reddeder. Ayrıca üçüncü taraf SMS sağlayıcılarının müşterileri olduğumuz için, onlarla kendi dengelerimiz de olabilir. Bunları da takip etmeliyiz.

Bazı karmaşıklığı (harici faturalandırma, sıraya alınmış SMS gönderme) kesersem, gerekli verileri MongoDB ile nasıl saklayabileceğimi düşünmeye başladım. SQL dünyasından, kullanıcılar için ayrı bir tablo, SMS mesajları için başka bir tablo ve kullanıcıların dengesi ile ilgili işlemleri saklamak için bir tablo oluşturacağım. Diyelim ki MongoDB'deki herkes için ayrı koleksiyonlar oluşturuyorum.

Bu basitleştirilmiş sistemde aşağıdaki adımlarla bir SMS gönderme görevi düşünün:

  1. kullanıcının dengesinin yeterli olup olmadığını kontrol edin; yeterli kredi yoksa erişimi reddet

  2. mesajı SMS koleksiyonuna ayrıntılar ve maliyetle birlikte gönderip saklayın (canlı sistemde mesajın bir statusniteliği olacaktır ve bir görev teslim için alıp SMS'in mevcut durumuna göre ayarlayacaktır)

  3. kullanıcıların bakiyesini gönderilen mesajın maliyetine göre azaltmak

  4. işlemi işlem koleksiyonuna kaydet

Şimdi bunun sorunu ne? MongoDB atom güncellemelerini sadece bir belgede yapabilir. Önceki akışta, bir tür hatanın içeri girmesi ve mesajın veritabanında depolanması, ancak kullanıcının bakiyesi güncellenmemesi ve / veya işlem günlüğe kaydedilmemesi olabilir.

İki fikir buldum:

  • Kullanıcılar için tek bir koleksiyon oluşturun ve bakiyeyi alan olarak, kullanıcıyla ilgili işlemleri ve mesajları kullanıcının belgesinde alt belgeler olarak saklayın. Belgeleri atomik olarak güncelleyebildiğimiz için bu işlem sorununu çözer. Dezavantajları: kullanıcı çok sayıda SMS mesajı gönderirse, dokümanın boyutu büyüyebilir ve 4 MB doküman sınırına ulaşılabilir. Belki böyle senaryolarda tarih belgeleri oluşturabilirim, ama bunun iyi bir fikir olacağını düşünmüyorum. Aynı büyük belgeye giderek daha fazla veri aktarırsam sistemin ne kadar hızlı olacağını da bilmiyorum.

  • Kullanıcılar için bir işlem ve işlemler için bir koleksiyon oluşturun. İki tür işlem olabilir: pozitif bakiye değişikliği ile kredi alımı ve negatif bakiye değişikliği ile gönderilen mesajlar . İşlemin bir alt belgesi olabilir; örneğin gönderilen mesajlarda SMS'in detayları işleme dahil edilebilir. Dezavantajları: Geçerli kullanıcı bakiyesini saklamıyorum, bu yüzden bir kullanıcı mesajın geçip geçemeyeceğini söylemek için her mesaj göndermeye çalıştığında hesaplamam gerekiyor. Korkarım depolanan işlemlerin sayısı arttıkça bu hesaplama yavaşlayabilir.

Hangi yöntemi seçeceğime biraz kafam karıştı. Başka çözümler var mı? Bu tür sorunların nasıl çözüleceğine dair çevrimiçi olarak en iyi uygulamaları bulamadım. Sanırım NoSQL dünyasına aşina olmaya çalışan birçok programcı başlangıçta benzer sorunlarla karşılaşıyor.


61
Yanılıyorsam beni affet ama bu proje faydalanıp faydalanmayacağından bağımsız olarak bir NoSQL veri deposu kullanacak gibi görünüyor. NoSQL'ler, SQL'e "moda" seçeneği olarak bir alternatif değildir, ancak ilişkisel RDBMS'lerin teknolojisi sorun alanına uymadığında ve ilişkisel olmayan bir veri deposu için uygun değildir. Sorunuzun birçoğunda "SQL olsaydı ..." vardı ve bana uyarı zilleri çalıyor. Tüm NoSQL'ler, SQL'in yapamadığı bir sorunu çözme ihtiyacından geldi ve daha sonra kullanımı kolaylaştırmak için biraz genelleştirildi ve elbette bandwagon yuvarlanmaya başladı.
PurplePilot

4
Bu projenin NoSQL'i denemek için tam olarak iyi olmadığının farkındayım. Ancak diğer projelerle kullanmaya başladığımızdan korkuyorum (diyelim ki toplama yönetimi içerisine girdiğimiz için bir kütüphane koleksiyonu yönetim yazılımı diyelim) ve aniden işlem gerektiren bir tür istek geliyor (ve aslında orada bir kitap hayal edin bir koleksiyondan diğerine aktarılır) sorunun üstesinden nasıl gelebileceğimizi bilmemiz gerekir. Belki dar görüşlü ve her zaman işlemlere ihtiyaç olduğunu düşünen benim. Ama bunların üstesinden gelmenin bir yolu olabilir.
NagyI

3
PurplePilot ile hemfikirim, bir soruna uyan bir teknoloji seçmelisiniz, bir soruna uygun olmayan bir çözüm hazırlamaya çalışmamalısınız. Grafik veritabanları için verileri modellemek, RDBMS tasarımından tamamen farklı bir paradigmadır ve bildiğiniz her şeyi unutmanız ve yeni düşünme biçimini yeniden öğrenmeniz gerekir.

9
Görev için uygun aracı kullanmam gerektiğini anlıyorum. Ancak benim için - böyle cevapları okurken - NoSQL, verilerin kritik olduğu herhangi bir şey için iyi görünmüyor. Bazı yorumlar kaybolursa dünyanın devam ettiği Facebook veya Twitter için iyidir, ancak bunun üstündeki herhangi bir şey iş dışıdır. Eğer bu doğruysa anlamıyorum neden diğer bina hakkında umurumda eg. MongoDB'li bir web mağazası: kylebanker.com/blog/2010/04/30/mongodb-and-ecommerce Hatta çoğu işlemin atomik işlemlerle aşılabileceğinden bahsediyor. Aradığım şey nasıl.
NagyI

2
"Veri kritik olduğunda hiçbir şey için iyi görünmüyor" diyorsunuz, iyi olmadığı yerde (belki) işlemsel ACID tipi işlemsel işlem doğru değildir. Ayrıca NoSQL'ler, ana bağımlı çoğaltma senaryolarına girdiğinizde SQL tipi depoların elde edilmesinin çok zor olabileceği dağıtılmış veri depoları için tasarlanmıştır. NoSQL'in nihai tutarlılık için stratejileri vardır ve yalnızca en son veri kümesinin kullanılmasını sağlar, ancak ACID değil.
PurplePilot

Yanıtlar:


23

4.0 itibariyle MongoDB'nin çoklu belge ASİT işlemleri olacaktır. Plan, önce çoğaltılmış küme dağıtımlarını, ardından parçalanmış kümeleri etkinleştirmektir. MongoDB'deki işlemler, geliştiricilerin ilişkisel veritabanlarından aşina olduğu işlemler gibi hissedecektir - benzer anlambilim ve sözdizimiyle ( start_transactionve gibi commit_transaction) çok ifadeli olacaktır . Daha da önemlisi, işlemleri mümkün kılan MongoDB'deki değişiklikler, bunları gerektirmeyen iş yükleri için performansı etkilemez.

Daha fazla ayrıntı için buraya bakın .

Dağıtılmış işlemlere sahip olmak, verilerinizin tablo şeklinde ilişkisel veritabanlarında olduğu gibi modellenmesi gerektiği anlamına gelmez. Belge modelinin gücünü benimseyin ve veri modellemenin iyi ve önerilen uygulamalarını takip edin .


1
İşlemler geldi! 4.0 GA'ed. mongodb.com/blog/post/…
Grigori Melnik

MongoDB işlemleri hala 16 MB işlemin boyutunda sınırlama var, son zamanlarda ben bir dosyadan 50k kayıtları mongoDB içine koymak gerekir bir kullanım durumu vardı, bu yüzden atomik özelliği korumak için işlemleri kullanmayı düşündüm ama 50k json kayıtları bu sınırı aşarsa "Tüm işlem işlemlerinin toplam boyutu 16793600'den küçük olmalıdır. Gerçek boyut 16793817" hatası veriyor. daha fazla bilgi için mongoDB'de açık olan resmi jira biletinden geçebilirsiniz jira.mongodb.org/browse/SERVER-36330
Gautam Malik

MongoDB 4.2 (şu anda beta sürümünde, RC4) büyük işlemleri desteklemektedir. Birden fazla oplog girişindeki işlemleri temsil ederek, tek bir ACID işleminde 16MB'den fazla veri yazabilirsiniz (mevcut 60 saniyelik varsayılan maksimum yürütme süresine bağlı olarak). Bunları şimdi deneyebilirsiniz - mongodb.com/download-center/community
Grigori Melnik

MongoDB 4.2 artık dağıtılmış işlemlerin tam desteğiyle GA'dır. mongodb.com/blog/post/…
Grigori Melnik

83

İşlemsiz Yaşam

İşlemler ASİT özelliklerini destekler, ancak hiçbir işlem olmamasına rağmen MongoDBatomik işlemlerimiz vardır. Atomik işlemler, tek bir belge üzerinde çalıştığınızda, bu belgenin başkasını görmeden tamamlanacağı anlamına gelir. Yaptığımız tüm değişiklikleri görecekler veya hiçbirini görmeyecekler. Atomik işlemleri kullanarak, ilişkisel bir veritabanındaki işlemleri kullanarak başardığımızla aynı şeyi başarabilirsiniz. Bunun nedeni, ilişkisel bir veritabanında birden çok tabloda değişiklik yapmamız gerektiğidir. Genellikle birleştirilmesi gereken tablolar ve bu yüzden hepsini bir kerede yapmak istiyoruz. Bunu yapmak için, birden fazla tablo olduğu için, bir işleme başlamalı ve tüm bu güncellemeleri yapmalı ve ardından işlemi sonlandırmalıyız. FakatMongoDB, verileri belgelere ekleyeceğiz, çünkü bunları belgelere önceden katılacağız ve bunlar hiyerarşisi olan bu zengin belgeler. Sık sık aynı şeyi başarabiliriz. Örneğin, blog örneğinde, bir blog gönderisini atomik olarak güncellediğimizden emin olmak istiyorsak, bunu yapabiliriz çünkü blog gönderisinin tamamını bir kerede güncelleyebiliriz. Bir grup ilişkisel tablo gibiyse, muhtemelen post collection ve yorumlar koleksiyonunu güncelleyebilmemiz için bir işlem açmamız gerekir.

Peki MongoDB, işlem eksikliğinin üstesinden gelmek için kullanabileceğimiz yaklaşımlarımız nelerdir?

  • yeniden yapılandırma - kodu yeniden yapılandırın, böylece tek bir belge içinde çalışırız ve bu belge içinde sunduğumuz atomik işlemlerden yararlanırız. Ve eğer bunu yaparsak, o zaman genellikle hepimiz hazırız.
  • yazılımda uygulamak - kritik bir bölüm oluşturarak yazılımda kilitleme uygulayabiliriz. Bul ve değiştir özelliğini kullanarak bir test oluşturabilir, test edebilir ve ayarlayabiliriz. Gerekirse semafor oluşturabiliriz. Ve bir bakıma, daha büyük dünya bu şekilde çalışır. Bunu düşünürsek, bir bankanın başka bir bankaya para aktarması gerekiyorsa, aynı ilişkisel sistemde yaşamıyorlar. Ve her birinin sıklıkla kendi ilişkisel veritabanları vardır. Ve bu veritabanı sistemlerinde, yalnızca bir banka içindeki tek bir sistem içinde işleme başlayıp işlemi bitiremesek de, bu işlemi koordine edebilmeleri gerekir. Yani yazılımda problemin üstesinden gelmenin kesinlikle yolları var.
  • tolere etmek - modern web uygulamalarında ve muazzam miktarda veri alan diğer uygulamalarda çalışan son yaklaşım, biraz tutarsızlığı tolere etmektir. Bir örnek, Facebook'taki bir arkadaş özet akışından bahsediyorsak, duvar güncellemenizi aynı anda herkesin görüp görmediği önemli değil. Tamamsa, bir kişi birkaç saniye geride kalırsa birkaç saniye yakalar ve yetişir. Çoğu sistem tasarımında her şeyin mükemmel bir şekilde tutarlı tutulması ve herkesin mükemmel bir şekilde tutarlı ve aynı veritabanı görünümüne sahip olması çoğu zaman kritik değildir. Bu nedenle, biraz geçici olan biraz tutarsızlığa tahammül edebiliriz.

Update, findAndModify, $addToSet(Bir güncelleştirme içinde) ve $push(bir güncelleştirme içinde) işlemler tek bir doküman içinde atomik yapmaktadır.


2
Ben ilişkisel DB geri gitmek gerekir sorgulama tutmak yerine, bu cevabın yaptığı gibi seviyorum. Teşekkürler @xameeramir!
DonnyTian

3
1'den fazla sunucunuz varsa, harici dağıtılmış kilitleme hizmeti kullanmak zorundaysanız kodun kritik bir bölümü çalışmaz
Alexander Mills

@AlexanderMills Lütfen biraz ayrıntı verebilir misiniz?
Zameer

Cevap şu video transkripti gibi görünüyor: youtube.com/watch?v=_Iz5xLZr8Lw
Fritz

Tek bir koleksiyonda çalışmak zorunda kalmayıncaya kadar bu iyi görünüyor. Ancak, çeşitli nedenlerden dolayı (doküman boyutu veya referanslar kullanıyorsanız) her şeyi tek bir belgeye koyamıyoruz. Sanırım işlemlere ihtiyacımız olabilir.
user2488286

24

Kontrol bu Tokutek tarafından dışarı. Mongo için sadece işlemler değil, aynı zamanda performans artışı da vaat eden bir eklenti geliştiriyorlar.


@Giovanni Bitliner. Tokutek o zamandan beri Percona tarafından satın alındı ​​ve verdiğiniz bağlantıda, postadan bu yana olan herhangi bir bilgi hakkında hiçbir referans görmüyorum. Çabalarına ne olduğunu biliyor musun? Öğrenmek için o sayfadaki e-posta adresini e-postayla gönderdim.
Tyler Collier

Özellikle neye ihtiyacınız var? Eğer mongodb uygulanan toku teknolojiyi gerekiyorsa deneyin github.com/Tokutek/mongo belki MySQL sürümü gerekiyorsa onlar genellikle ile sağladıkları Mysql kendi standart sürüme eklendi,
Giovanni Bitliner

Tokutek'i nodej'lerle nasıl birleştirebilirim.
Manoj Sanjeewa

11

Bu noktaya getirin: işlemsel bütünlük bir zorunluluksa , MongoDB'yi kullanmayın, yalnızca işlemleri destekleyen sistemdeki bileşenleri kullanın. ACID uyumlu olmayan bileşenler için ACID benzeri işlevler sağlamak amacıyla bileşenin üzerine bir şey oluşturmak son derece zordur. Bireysel kullanımlara bağlı olarak, eylemleri bir şekilde işlemsel ve işlemsel olmayan eylemlere ayırmak mantıklı olabilir ...


1
Sanırım NoSQL klasik RDBMS ile yardımcı bir veritabanı olarak kullanılabilir demek. Aynı projede NoSQL ve SQL'i karıştırma fikrinden hoşlanmıyorum. Karmaşıklığı artırır ve muhtemelen önemsiz olmayan bazı problemleri de beraberinde getirir.
NagyI

1
NoSQL çözümleri nadiren tek başına kullanılır. Belge depoları (mongo ve kanepe) muhtemelen bu kuralın tek uygulamasıdır.
Karoly Horvath

7

Şimdi bunun sorunu ne? MongoDB atom güncellemelerini sadece bir belgede yapabilir. Önceki akışta, bir tür hatanın içeri girmesi ve mesajın veritabanında saklanması ancak kullanıcının bakiyesinin azalmaması ve / veya işlemin kaydedilmemesi olabilir.

Bu gerçekten bir sorun değil. Bahsettiğiniz hata mantıklı (hata) veya IO hatasıdır (ağ, disk hatası). Bu tür bir hata hem işlemsiz hem de işlemsel depoları tutarlı olmayan durumda bırakabilir. Örneğin, önceden SMS gönderdiyse ancak mesaj hatası saklanırken - SMS göndermeyi geri alamaz, bu da günlüğe kaydedilmeyeceği, kullanıcı bakiyesinin azalmayacağı vb.

Buradaki asıl sorun, kullanıcı yarış koşulundan yararlanabilir ve dengesinin izin verdiğinden daha fazla mesaj gönderebilir. Denge alanı kilitleme (büyük bir darboğaz olurdu) içinde SMS gönderme işlemi yapmazsanız, bu RDBMS için de geçerlidir. MongoDB için olası bir çözüm olarak findAndModify, dengeyi azaltmak ve kontrol etmek için ilk önce kullanmak gerekir, eğer negatif göndermeye izin vermiyor ve miktarı iade ediyorsa (atomik artış). Olumlu ise, göndermeye devam edin ve başarısız olması durumunda tutarı iade edin. Denge geçmişi koleksiyonu, denge alanının düzeltilmesine / doğrulanmasına yardımcı olmak için de korunabilir.


Bu harika cevap için teşekkürler! Ben iĢlem yetenekli depolar kullanırsanız veri i kontrol yok SMS sistemi nedeniyle bozulabilir biliyorum. Ancak Mongo ile veri hatasının kurum içinde de meydana gelme ihtimali vardır. Kodun findAndModify ile kullanıcının dengesini değiştirdiğini, bakiye negatif gittiğini ancak hatayı düzeltmeden önce bir hata oluştuğunda ve uygulamanın yeniden başlatılması gerektiğini varsayalım. Sanırım işlem toplama dayalı iki aşamalı taahhüt benzer bir şey uygulamak gerekir ve veritabanında düzenli düzeltme denetimi yapmak demek.
NagyI

9
Doğru değil, son bir taahhütte bulunmazsanız işlemsel mağazalar geri dönecektir.
Karoly Horvath

9
Ayrıca, SMS göndermez ve DB'ye giriş yaparsınız, bu sadece yanlıştır. Önce her şeyi DB'de saklayın ve son bir taahhütte bulunun, sonra mesajı gönderebilirsiniz. Bu noktada hala bir şey başarısız olabilir, bu yüzden göndermeye çalışmadıysanız mesajın gerçekten gönderildiğini kontrol etmek için bir cron işine ihtiyacınız vardır. Belki de bunun için özel bir mesaj kuyruğu daha iyi olurdu. Ama her şey işlemsel bir şekilde SMS gönderip gönderemeyeceğinize bağlı ...
Karoly Horvath

Evet, demek istediğim buydu. Ölçeklenebilirlik kolaylığı için işlemlerin faydalarından faydalanmak gerekir. Temel olarak uygulama, farklı koleksiyonlardaki iki belgenin tutarsız bir durumda olmasını ve bunu işlemeye hazır olmasını beklemek zorundadır. @yi_H geri dönecek, ancak durum artık gerçek olmayacak (mesajla ilgili bilgiler kaybolacak). Bu sadece kısmi veriye sahip olmaktan daha iyi değildir (denge azalmış gibi ama mesaj bilgisi yok veya tam tersi).
pingw33n

Anlıyorum. Bu aslında kolay bir kısıtlama değildir. Belki RDBMS sistemlerinin nasıl işlem yaptığı hakkında daha fazla bilgi edinmeliyim. Bunları okuyabileceğim bir tür çevrimiçi materyal veya kitap önerebilir misiniz?
NagyI

6

Proje basit, ancak her şeyi zorlaştıran ödeme işlemlerini desteklemelisiniz. Örneğin, yüzlerce koleksiyona (forum, sohbet, reklamlar, vb.) Sahip karmaşık bir portal sistemi bir bakıma daha basittir, çünkü bir forumu veya sohbet girişini kaybederseniz, kimse gerçekten umursamaz. Öte yandan, ciddi bir sorun olan ödeme işlemini kaybederseniz.

Yani, gerçekten MongoDB için bir pilot proje istiyorsanız, bu açıdan basit olanı seçin .


Açıkladığınız için teşekkürler. Bunu duyduğuma üzgünüm. NoSQL'in sadeliğini ve JSON kullanımını seviyorum. ORM'ye bir alternatif arıyoruz, ancak bir süre buna bağlı kalmalıyız gibi görünüyor.
NagyI

Bu görev için MongoDB'nin SQL'den daha iyi olmasının iyi bir nedenini verebilir misiniz? Pilot proje biraz aptalca geliyor.
Karoly Horvath

MongoDB'nin SQL'den daha iyi olduğunu söylemedim. SQL + ORM'den daha iyi olup olmadığını bilmek istiyoruz. Ancak şimdi, bu tür projelerde rekabetçi olmadıkları netleşiyor.
NagyI

6

MongoDB'de geçerli nedenlerle işlemler yoktur. Bu MongoDB'yi hızlandıran şeylerden biri.

Sizin durumunuzda, işlem bir zorunluluksa, mongo iyi bir uyum gibi görünmüyor.

RDMBS + MongoDB olabilir, ancak bu karmaşıklık katacak ve uygulamayı yönetmeyi ve desteklemeyi zorlaştıracaktır.


1
Şimdi MonuDB'nin TokuMX adında 50 kat performans iyileştirmesi sağlamak için fraktal teknolojisini kullanan ve aynı zamanda tam ACID işlem desteği veren bir dağıtımı var: tokutek.com/tokumx-for-mongodb
OCDev

9
Bir işlem nasıl "olmazsa olmaz" olamaz. 2 tabloyu güncellemeniz gereken 1 basit vakaya ihtiyaç duyduğunuz anda mongo aniden artık uygun değil mi? Bu çok fazla kullanım durumu bırakmaz.
Mr_E

1
@Mr_E katılıyorum, bu yüzden MongoDB biraz aptal :)
Alexander Mills

6

Bu muhtemelen mongodb özelliği gibi işlem gerçekleştirme ile ilgili bulduğum en iyi blog.!

Senkronizasyon Bayrağı: sadece ana dokümandan veri kopyalamak için en iyisi

İş Kuyruğu: Çok genel amaçlı, vakaların% 95'ini çözüyor. Çoğu sistemin yine de en az bir iş kuyruğu olması gerekir!

İki Fazlı Taahhüt: Bu teknik, her bir işletmenin tutarlı bir duruma ulaşmak için gereken tüm bilgilere sahip olmasını sağlar

Log Mutabakatı: finansal sistemler için ideal, en sağlam teknik

Versiyonlama: izolasyon sağlar ve karmaşık yapıları destekler

Daha fazla bilgi için bunu okuyun: https://dzone.com/articles/how-implement-robust-and


Lütfen soruyu yanıtınıza cevaplamak için gerekli kaynağın ilgili kısımlarını ekleyin. Olduğu gibi, cevabınız bağlantı çürümesine karşı çok hassastır (yani bağlantılı web sitesi kapanırsa veya cevabınızı değiştirirse cevabınız potansiyel olarak işe yaramaz).
mech

Öneri için teşekkürler mech
Vaibhav

4

Bu geç oldu ama bunun gelecekte yardımcı olacağını düşünün. Redis'i bu sorunu çözmek için kuyruk oluşturmak için kullanıyorum .

  • Gereksinim:
    Aşağıdaki resim 2 eylemin eşzamanlı olarak yürütülmesi gerektiğini, ancak eylem 2'nin faz 2 ve faz 3'ün, eylem 2'nin 2 veya tersi faz 2 başlamadan önce bitmesi gerektiğini gösteriyor (Bir faz, REST api, veritabanı isteği veya javascript kodu yürütme ... ). resim açıklamasını buraya girin

  • Bir kuyruk size nasıl yardımcı olur?
    Kuyruk , birçok işlev arasındaki lock()ve release()birçok işlevdeki her blok kodunun aynı anda çalışmadığından emin olun, ayırın.

    function action1() {
      phase1();
      queue.lock("action_domain");
      phase2();
      phase3();
      queue.release("action_domain");
    }
    
    function action2() {
      phase1();
      queue.lock("action_domain");
      phase2();
      queue.release("action_domain");
    }
  • Bir kuyruk nasıl oluşturulur
    Sadece arka uç sitesinde bir kuyruk oluştururken yarış koşullarından kaçınmaya odaklanacağım . Temel kuyruk fikrini bilmiyorsanız buraya gelin .
    Aşağıdaki kod sadece kavramı gösterir, doğru şekilde uygulamanız gerekir.

    function lock() {
      if(isRunning()) {
        addIsolateCodeToQueue(); //use callback, delegate, function pointer... depend on your language
      } else {
        setStateToRunning();
        pickOneAndExecute();
      }
    }
    
    function release() {
      setStateToRelease();
      pickOneAndExecute();
    }

Ama isRunning() setStateToRelease() setStateToRunning()kendini izole etmen gerekiyor ya da tekrar yarış koşuluyla karşı karşıyasın. Bunu yapmak için ACID amaçlı ve ölçeklenebilir olarak Redis'i seçiyorum .
Redis belge bu konuda konuşmak işlem var:

Bir işlemdeki tüm komutlar serileştirilir ve sırayla yürütülür. Bir Redis işleminin ortasında başka bir istemci tarafından verilen bir isteğin sunulması asla gerçekleşemez. Bu, komutların tek bir yalıtılmış işlem olarak yürütülmesini garanti eder.

P / s:
Hizmetimi zaten kullandığı için Redis kullanıyorum, bunu yapmak için başka bir destek izolasyonu kullanabilirsiniz. Benim kodunda diğer kullanıcı engellenir yok, kullanıcı A'nın kullanıcı bir blok eylemi 2 sadece eylem 1 çağrı gerektiğinde için üzerindedir. Fikir, her kullanıcının kilidi için benzersiz bir anahtar koymaktır.
action_domain


Puanınız daha yüksek olsaydı daha fazla oy alırsınız. Burada çoğu böyle düşünüyor. Cevabınız soru bağlamında faydalıdır. Seni oyladım.
Mukus

3

İşlemler artık MongoDB 4.0'da yapılabilmektedir. Buradan örnek alın

// Runs the txnFunc and retries if TransientTransactionError encountered

function runTransactionWithRetry(txnFunc, session) {
    while (true) {
        try {
            txnFunc(session);  // performs transaction
            break;
        } catch (error) {
            // If transient error, retry the whole transaction
            if ( error.hasOwnProperty("errorLabels") && error.errorLabels.includes("TransientTransactionError")  ) {
                print("TransientTransactionError, retrying transaction ...");
                continue;
            } else {
                throw error;
            }
        }
    }
}

// Retries commit if UnknownTransactionCommitResult encountered

function commitWithRetry(session) {
    while (true) {
        try {
            session.commitTransaction(); // Uses write concern set at transaction start.
            print("Transaction committed.");
            break;
        } catch (error) {
            // Can retry commit
            if (error.hasOwnProperty("errorLabels") && error.errorLabels.includes("UnknownTransactionCommitResult") ) {
                print("UnknownTransactionCommitResult, retrying commit operation ...");
                continue;
            } else {
                print("Error during commit ...");
                throw error;
            }
       }
    }
}

// Updates two collections in a transactions

function updateEmployeeInfo(session) {
    employeesCollection = session.getDatabase("hr").employees;
    eventsCollection = session.getDatabase("reporting").events;

    session.startTransaction( { readConcern: { level: "snapshot" }, writeConcern: { w: "majority" } } );

    try{
        employeesCollection.updateOne( { employee: 3 }, { $set: { status: "Inactive" } } );
        eventsCollection.insertOne( { employee: 3, status: { new: "Inactive", old: "Active" } } );
    } catch (error) {
        print("Caught exception during transaction, aborting.");
        session.abortTransaction();
        throw error;
    }

    commitWithRetry(session);
}

// Start a session.
session = db.getMongo().startSession( { mode: "primary" } );

try{
   runTransactionWithRetry(updateEmployeeInfo, session);
} catch (error) {
   // Do something with error
} finally {
   session.endSession();
}
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.