Bagaimana cara mengatasi kurangnya transaksi di MongoDB?


139

Saya tahu ada pertanyaan serupa di sini, tetapi mereka mengatakan kepada saya untuk kembali ke sistem RDBMS biasa jika saya memerlukan transaksi atau menggunakan operasi atom atau komit dua fase . Solusi kedua sepertinya pilihan terbaik. Yang ketiga saya tidak ingin mengikuti karena tampaknya banyak hal bisa salah dan saya tidak bisa mengujinya di setiap aspek. Saya mengalami kesulitan refactoring proyek saya untuk melakukan operasi atom. Saya tidak tahu apakah ini berasal dari sudut pandang saya yang terbatas (saya hanya bekerja dengan database SQL sejauh ini), atau apakah itu sebenarnya tidak dapat dilakukan.

Kami ingin menguji coba MongoDB di perusahaan kami. Kami telah memilih proyek yang relatif sederhana - SMS gateway. Ini memungkinkan perangkat lunak kami untuk mengirim pesan SMS ke jaringan seluler dan gateway melakukan pekerjaan kotor: benar-benar berkomunikasi dengan penyedia melalui protokol komunikasi yang berbeda. Gateway juga mengelola penagihan pesan. Setiap pelanggan yang mengajukan permohonan layanan harus membeli sejumlah kredit. Sistem secara otomatis mengurangi saldo pengguna ketika pesan dikirim dan menolak akses jika saldo tidak mencukupi. Juga karena kami adalah pelanggan penyedia SMS pihak ketiga, kami mungkin juga memiliki saldo sendiri. Kita harus melacak itu juga.

Saya mulai berpikir tentang bagaimana saya bisa menyimpan data yang diperlukan dengan MongoDB jika saya mengurangi beberapa kerumitan (penagihan eksternal, pengiriman SMS antri). Berasal dari dunia SQL, saya akan membuat tabel terpisah untuk pengguna, satu lagi untuk pesan SMS, dan satu lagi untuk menyimpan transaksi mengenai saldo pengguna. Katakanlah saya membuat koleksi terpisah untuk semua yang ada di MongoDB.

Bayangkan tugas pengiriman SMS dengan langkah-langkah berikut dalam sistem yang disederhanakan ini:

  1. periksa apakah pengguna memiliki saldo yang cukup; tolak akses jika tidak ada kredit yang cukup

  2. kirim dan simpan pesan dalam koleksi SMS dengan perincian dan biaya (dalam sistem siaran langsung pesan akan memiliki statusatribut dan tugas akan mengambilnya untuk pengiriman dan mengatur harga SMS sesuai dengan keadaan saat ini)

  3. mengurangi saldo pengguna dengan biaya pesan yang dikirim

  4. catat transaksi dalam koleksi transaksi

Sekarang apa masalahnya dengan itu? MongoDB dapat melakukan pembaruan atom hanya pada satu dokumen. Dalam aliran sebelumnya, bisa terjadi beberapa jenis kesalahan masuk dan pesan disimpan dalam basis data tetapi saldo pengguna tidak diperbarui dan / atau transaksi tidak dicatat.

Saya datang dengan dua ide:

  • Buat koleksi tunggal untuk pengguna, dan simpan saldo sebagai bidang, transaksi terkait pengguna dan pesan sebagai sub dokumen dalam dokumen pengguna. Karena kami dapat memperbarui dokumen secara atom, ini sebenarnya memecahkan masalah transaksi. Kekurangan: jika pengguna mengirim banyak pesan SMS, ukuran dokumen bisa menjadi besar dan batas dokumen 4MB dapat tercapai. Mungkin saya bisa membuat dokumen sejarah dalam skenario seperti itu, tapi saya rasa ini bukan ide yang bagus. Saya juga tidak tahu seberapa cepat sistemnya jika saya mendorong lebih banyak data ke dokumen besar yang sama.

  • Buat satu koleksi untuk pengguna, dan satu untuk transaksi. Ada dua jenis transaksi: pembelian kredit dengan perubahan saldo positif dan pesan yang dikirim dengan perubahan saldo negatif. Transaksi dapat memiliki sub dokumen; misalnya dalam pesan yang dikirim rincian SMS dapat tertanam dalam transaksi. Kekurangan: Saya tidak menyimpan saldo pengguna saat ini jadi saya harus menghitungnya setiap kali pengguna mencoba mengirim pesan untuk memberi tahu apakah pesan itu bisa masuk atau tidak. Saya khawatir perhitungan ini dapat menjadi lambat karena jumlah transaksi yang tersimpan bertambah.

Saya sedikit bingung tentang metode mana yang harus dipilih. Apakah ada solusi lain? Saya tidak dapat menemukan praktik terbaik online tentang cara mengatasi masalah seperti ini. Saya kira banyak programmer yang mencoba mengenal dunia NoSQL menghadapi masalah yang sama pada awalnya.


61
Maafkan saya jika saya salah tetapi sepertinya proyek ini akan menggunakan penyimpanan data NoSQL terlepas dari apakah itu akan mendapat manfaat dari itu atau tidak. NoSQL bukanlah alternatif untuk SQL sebagai pilihan "mode" tetapi untuk ketika teknologi RDBMS relasional tidak sesuai dengan ruang masalah & datastore non-relasional tidak. Banyak pertanyaan Anda memiliki "Jika itu SQL lalu ..." & itu berdering lonceng peringatan kepada saya. Semua NoSQL berasal dari kebutuhan untuk memecahkan masalah yang SQL tidak bisa dan kemudian mereka agak digeneralisasi untuk membuat lebih mudah digunakan & tentu saja ikut-ikutan bergulir.
PurplePilot

4
Saya sadar bahwa proyek ini bukan yang terbaik untuk mencoba NoSQL. Namun saya khawatir jika kita mulai menggunakannya dengan proyek lain (katakanlah perangkat lunak manajemen koleksi perpustakaan karena kita masuk ke manajemen koleksi) dan tiba-tiba beberapa jenis permintaan masuk yang memerlukan transaksi (dan sebenarnya ada di sana, bayangkan ada buku dipindahkan dari satu koleksi ke koleksi lain) kita perlu tahu bagaimana kita dapat mengatasi masalah tersebut. Mungkin hanya saya yang berpikiran sempit dan berpikir selalu ada kebutuhan untuk transaksi. Tapi bisa jadi ada cara untuk mengatasi ini entah bagaimana.
NagyI

3
Saya setuju dengan PurplePilot, Anda harus memilih teknologi yang sesuai dengan solusi, bukan mencoba untuk mencangkokkan solusi yang tidak sesuai untuk suatu masalah. Memodelkan data untuk basis data grafik adalah paradigma yang sama sekali berbeda dari desain RDBMS dan Anda harus melupakan semua yang Anda ketahui dan mempelajari kembali cara berpikir yang baru.

9
Saya mengerti saya harus menggunakan alat yang sesuai untuk tugas itu. Namun bagi saya - ketika saya membaca jawaban seperti ini - tampaknya NoSQL tidak bagus untuk apa pun di mana data sangat penting. Ini bagus untuk Facebook atau Twitter di mana jika ada komentar yang hilang, dunia terus berjalan, tetapi semua yang di atas itu tidak ada hubungannya. Jika itu benar saya tidak mengerti mengapa orang lain peduli misalnya membangun. sebuah webstore dengan MongoDB: kylebanker.com/blog/2010/04/30/mongodb-and-ecommerce Bahkan menyebutkan bahwa sebagian besar transaksi dapat diatasi dengan operasi atom. Yang saya cari adalah caranya.
NagyI

2
Anda mengatakan "tampaknya NoSQL tidak baik untuk apa pun di mana data sangat penting" tidak benar di mana tidak baik (mungkin) adalah pemrosesan transaksional ACID tipe transaksional. Juga NoSQL dirancang untuk penyimpanan data terdistribusi dimana toko tipe SQL bisa sangat sulit untuk dicapai ketika Anda masuk ke dalam skenario replikasi master slave. NoSQL memiliki strategi untuk konsistensi akhirnya dan memastikan hanya set data terbaru yang digunakan tetapi tidak ACID.
PurplePilot

Jawaban:


23

Pada 4.0, MongoDB akan memiliki transaksi multi-dokumen ACID. Rencananya adalah untuk memungkinkan orang-orang dalam penyebaran set replika terlebih dahulu, diikuti oleh kelompok yang terbengkalai. Transaksi dalam MongoDB akan terasa seperti transaksi yang akrab bagi pengembang dari basis data relasional - mereka akan multi-pernyataan, dengan semantik dan sintaksis yang sama (seperti start_transactiondan commit_transaction). Yang penting, perubahan pada MongoDB yang memungkinkan transaksi tidak memengaruhi kinerja untuk beban kerja yang tidak memerlukannya.

Untuk lebih jelasnya lihat di sini .

Setelah transaksi terdistribusi, tidak berarti Anda harus memodelkan data Anda seperti di database relasional tabular. Rangkullah kekuatan model dokumen dan ikuti praktik pemodelan data yang baik dan direkomendasikan .


1
Transaksi telah tiba! 4.0 GA'ed. mongodb.com/blog/post/…
Grigori Melnik

Transaksi MongoDB masih memiliki batasan pada ukuran transaksi 16 MB, baru-baru ini saya memiliki use case di mana saya perlu memasukkan 50k catatan dari file ke mongoDB, jadi untuk menjaga properti atom saya berpikir untuk menggunakan transaksi tetapi karena 50k json mencatat melebihi batas ini, ia melempar kesalahan "Ukuran total semua operasi transaksi harus kurang dari 16793600. Ukuran aktual adalah 16793817". untuk lebih jelasnya Anda dapat membuka tiket jira
Gautam Malik

MongoDB 4.2 (saat ini dalam versi beta, RC4) mendukung transaksi besar. Dengan merepresentasikan transaksi di beberapa entri oplog, Anda akan dapat menulis lebih dari 16MB data dalam satu transaksi ACID (tergantung pada waktu eksekusi maksimum default 60 detik yang ada). Anda dapat mencobanya sekarang - mongodb.com/download-center/community
Grigori Melnik

MongoDB 4.2 sekarang GA dengan dukungan penuh dari transaksi yang didistribusikan. mongodb.com/blog/post/…
Grigori Melnik

83

Hidup Tanpa Transaksi

Transaksi mendukung properti ACID tetapi meskipun tidak ada transaksi MongoDB, kami memiliki operasi atom. Nah, operasi atom berarti bahwa ketika Anda mengerjakan satu dokumen, pekerjaan itu akan diselesaikan sebelum orang lain melihat dokumen itu. Mereka akan melihat semua perubahan yang kami lakukan atau tidak satupun dari mereka. Dan menggunakan operasi atom, Anda sering dapat mencapai hal yang sama seperti yang kita lakukan dengan menggunakan transaksi dalam basis data relasional. Dan alasannya adalah bahwa, dalam database relasional, kita perlu membuat perubahan di beberapa tabel. Biasanya tabel yang perlu digabung jadi kami ingin melakukannya sekaligus. Dan untuk melakukannya, karena ada beberapa tabel, kita harus memulai transaksi dan melakukan semua pembaruan itu dan kemudian mengakhiri transaksi. Tetapi denganMongoDB, kita akan menanamkan data, karena kita akan pra-gabung dalam dokumen dan mereka adalah dokumen kaya yang memiliki hierarki. Kita sering dapat mencapai hal yang sama. Misalnya, dalam contoh blog, jika kami ingin memastikan bahwa kami memperbarui posting blog secara atomis, kami dapat melakukannya karena kami dapat memperbarui seluruh posting blog sekaligus. Sedangkan seolah-olah itu adalah sekelompok tabel relasional, kita mungkin harus membuka transaksi sehingga kita dapat memperbarui koleksi posting dan koleksi komentar.

Jadi, apa pendekatan kami yang dapat kami ambil MongoDBuntuk mengatasi kurangnya transaksi?

  • restrukturisasi - merestrukturisasi kode, sehingga kami bekerja dalam satu dokumen dan mengambil keuntungan dari operasi atom yang kami tawarkan di dalam dokumen itu. Dan jika kita melakukan itu, maka biasanya kita sudah siap.
  • implementasikan dalam perangkat lunak - kita dapat menerapkan penguncian dalam perangkat lunak, dengan membuat bagian penting. Kita dapat membangun tes, uji dan set menggunakan find dan modifikasi. Kami dapat membangun semaphores, jika diperlukan. Dan dengan cara tertentu, itulah cara dunia yang lebih besar bekerja. Jika kita pikirkan, jika satu bank perlu mentransfer uang ke bank lain, mereka tidak hidup dalam sistem relasional yang sama. Dan mereka masing-masing memiliki basis data relasional sendiri. Dan mereka harus dapat mengoordinasikan operasi itu meskipun kita tidak dapat memulai transaksi dan mengakhiri transaksi di seluruh sistem basis data itu, hanya dalam satu sistem dalam satu bank. Jadi ada cara pasti dalam perangkat lunak untuk mengatasi masalah tersebut.
  • tolerate - pendekatan terakhir, yang sering bekerja di aplikasi web modern dan aplikasi lain yang menerima banyak data adalah dengan hanya mentolerir sedikit ketidakkonsistenan. Contohnya adalah, jika kita berbicara tentang umpan teman di Facebook, tidak masalah jika semua orang melihat pembaruan dinding Anda secara bersamaan. Jika okey, jika satu orang beberapa ketukan di belakang selama beberapa detik dan mereka mengejar ketinggalan. Seringkali tidak penting dalam banyak desain sistem yang semuanya dijaga agar tetap konsisten dan bahwa setiap orang memiliki pandangan yang konsisten dan sama tentang database. Jadi kita bisa mentolerir sedikit ketidakkonsistenan yang agak sementara.

Update, findAndModify, $addToSet(Dalam update) & $push(dalam update) operasi beroperasi atom dalam satu dokumen.


2
Saya suka cara jawaban ini, daripada terus bertanya apakah kita harus kembali ke DB relasional. Terima kasih @ xameeramir!
DonnyTian

3
bagian kritis kode tidak akan berfungsi jika Anda memiliki lebih dari 1 server, harus menggunakan layanan penguncian terdistribusi eksternal
Alexander Mills

@AlexanderMills Bisakah Anda jelaskan?
Zameer

jawabannya sepertinya transkrip video dari sini: youtube.com/watch?v=_Iz5xLZr8Lw
Fritz

Saya pikir ini tampaknya baik sampai kita dibatasi harus beroperasi pada satu koleksi. Tetapi kami tidak dapat meletakkan semuanya dalam satu dokumen karena berbagai alasan (ukuran dokumen atau jika Anda menggunakan referensi). Saya pikir maka kita mungkin perlu transaksi.
user2488286

24

Lihat ini , oleh Tokutek. Mereka mengembangkan plugin untuk Mongo yang tidak hanya menjanjikan transaksi tetapi juga meningkatkan kinerja.


@Giovanni Bitliner. Sejak itu Tokutek telah diakuisisi oleh Percona, dan pada tautan yang Anda berikan, saya tidak melihat referensi ke informasi apa pun yang terjadi sejak pos. Apakah Anda tahu apa yang terjadi pada upaya mereka? Saya mengirim email ke alamat email di halaman itu untuk mencari tahu.
Tyler Collier

Apa yang Anda butuhkan secara khusus? Jika Anda memerlukan teknologi yang diterapkan pada Mongodb, coba github.com/Tokutek/mongo , jika Anda memerlukan versi mysql, mungkin mereka menambahkannya ke versi standar Mysql yang biasanya mereka sediakan
Giovanni Bitliner

Bagaimana saya bisa memadukan tokutek dengan nodejs.
Manoj Sanjeewa

11

Bawa ke titik: jika integritas transaksional adalah suatu keharusan maka jangan gunakan MongoDB tetapi hanya menggunakan komponen dalam sistem yang mendukung transaksi. Sangat sulit untuk membangun sesuatu di atas komponen untuk menyediakan fungsionalitas yang mirip dengan ACID untuk komponen yang tidak sesuai dengan ACID. Bergantung pada masing-masing penggunaan kata, masuk akal untuk memisahkan tindakan menjadi tindakan transaksional dan non-transaksional dalam beberapa cara ...


1
Saya kira maksud Anda NoSQL dapat digunakan sebagai database sidekick dengan RDBMS klasik. Saya tidak suka ide untuk menggabungkan NoSQL dan SQL dalam proyek yang sama. Ini meningkatkan kompleksitas dan mungkin memperkenalkan beberapa masalah yang tidak sepele juga.
NagyI

1
Solusi NoSQL jarang digunakan sendirian. Penyimpanan dokumen (mongo dan sofa) mungkin merupakan satu-satunya eksekusi dari aturan ini.
Karoly Horvath

7

Sekarang apa masalahnya dengan itu? MongoDB dapat melakukan pembaruan atom hanya pada satu dokumen. Dalam aliran sebelumnya, bisa terjadi beberapa jenis kesalahan masuk dan pesan disimpan dalam database tetapi saldo pengguna tidak berkurang dan / atau transaksi tidak dicatat.

Ini sebenarnya bukan masalah. Kesalahan yang Anda sebutkan adalah kesalahan logis (bug) atau IO (jaringan, kegagalan disk). Kesalahan semacam itu dapat membuat toko transaksi dan transaksi tidak dalam keadaan tidak konsisten. Misalnya, jika sudah mengirim SMS tetapi ketika terjadi kesalahan pesan - tidak dapat mengembalikan pengiriman SMS, yang berarti tidak akan dicatat, keseimbangan pengguna tidak akan berkurang dll.

Masalah sebenarnya di sini adalah pengguna dapat mengambil keuntungan dari kondisi balapan dan mengirim lebih banyak pesan daripada yang dibolehkan keseimbangannya. Ini juga berlaku untuk RDBMS, kecuali jika Anda melakukan pengiriman dalam transaksi SMS dengan penguncian bidang saldo (yang akan menjadi hambatan besar). Sebagai solusi yang mungkin untuk MongoDB akan menggunakan findAndModifypertama untuk mengurangi saldo dan memeriksanya, jika negatif melarang pengiriman dan kembalikan jumlahnya (kenaikan atom). Jika positif, terus mengirim dan jika gagal mengembalikan jumlah. Pengumpulan riwayat saldo juga dapat dipertahankan untuk membantu memperbaiki / memverifikasi bidang keseimbangan.


Terima kasih atas jawaban yang bagus ini! Saya tahu bahwa jika saya menggunakan data penyimpanan yang mampu transaksi dapat rusak karena sistem SMS yang saya tidak punya kontrol. Namun dengan Mongo ada kemungkinan kesalahan data dapat terjadi di rumah juga. Katakanlah kode mengubah saldo pengguna dengan findAndModify, saldo menjadi negatif tetapi sebelum saya dapat memperbaiki kesalahan terjadi kesalahan dan aplikasi harus memulai kembali. Saya kira maksud Anda saya harus menerapkan sesuatu yang mirip dengan komit dua fase berdasarkan pada kumpulan transaksi dan melakukan pemeriksaan koreksi reguler pada database.
NagyI

9
Tidak benar, toko transaksional akan gulung balik jika Anda tidak melakukan komitmen akhir.
Karoly Horvath

9
Juga, Anda tidak mengirim SMS dan kemudian masuk ke DB, itu salah besar. Pertama-tama simpan segala sesuatu di DB dan lakukan komit terakhir, kemudian Anda dapat mengirim pesan. Pada titik ini ada sesuatu yang masih bisa gagal, jadi Anda perlu tugas cron untuk memeriksa apakah pesan itu benar-benar dikirim, jika tidak coba kirim. Mungkin antrian pesan khusus akan lebih baik untuk ini. Tapi semuanya bermuara pada apakah Anda dapat mengirim SMS dengan cara transaksional ...
Karoly Horvath

@ Nagy, ya, itu yang saya maksud. Kita harus memperdagangkan manfaat transaksi untuk kemudahan skalabilitas. Pada dasarnya aplikasi harus mengharapkan dua dokumen dalam koleksi yang berbeda dapat dalam keadaan tidak konsisten dan siap untuk menangani ini. @yi_H itu akan mengembalikan tetapi negara tidak akan aktual lagi (informasi tentang pesan akan hilang). Ini tidak jauh lebih baik daripada hanya memiliki data parsial (seperti saldo dikurangi tetapi tidak ada informasi pesan atau sebaliknya).
pingw33n

Saya melihat. Ini sebenarnya bukan kendala yang mudah. Mungkin saya harus belajar lebih banyak tentang bagaimana sistem RDBMS melakukan transaksi. Bisakah Anda merekomendasikan beberapa jenis materi online atau buku di mana saya dapat membaca tentang ini?
NagyI

6

Proyek ini sederhana, tetapi Anda harus mendukung transaksi pembayaran, yang membuat semuanya menjadi sulit. Jadi, misalnya, sistem portal yang kompleks dengan ratusan koleksi (forum, obrolan, iklan, dll ...) dalam beberapa hal lebih sederhana, karena jika Anda kehilangan entri forum atau obrolan, tidak ada yang benar-benar peduli. Jika Anda, di sisi lain, kehilangan transaksi pembayaran yang merupakan masalah serius.

Jadi, jika Anda benar-benar ingin proyek percontohan untuk MongoDB, memilih salah satu yang sederhana dalam bahwa rasa hormat.


Terima kasih telah menjelaskan. Sedih mendengarnya. Saya suka kesederhanaan NoSQL dan penggunaan JSON. Kami sedang mencari alternatif untuk ORM tetapi sepertinya kami harus tetap menggunakannya untuk sementara waktu.
NagyI

Bisakah Anda memberikan alasan bagus mengapa MongoDB lebih baik dari SQL untuk tugas ini? Proyek percontohan terdengar agak konyol.
Karoly Horvath

Saya tidak mengatakan bahwa MongoDB lebih baik dari SQL. Kami hanya ingin tahu apakah itu lebih baik daripada SQL + ORM. Tetapi sekarang menjadi lebih jelas bahwa mereka tidak kompetitif dalam proyek semacam ini.
Nagyi

6

Transaksi tidak ada dalam MongoDB untuk alasan yang sah. Ini adalah salah satu hal yang membuat MongoDB lebih cepat.

Dalam kasus Anda, jika transaksi adalah suatu keharusan, mongo sepertinya tidak cocok.

Mungkin RDMBS + MongoDB, tetapi itu akan menambah kerumitan dan akan membuatnya lebih sulit untuk mengelola dan mendukung aplikasi.


1
Sekarang ada distribusi MongoDB yang disebut TokuMX yang menggunakan teknologi fraktal untuk memberikan peningkatan kinerja 50x dan memberikan dukungan transaksi ACID penuh pada saat yang sama: tokutek.com/tokumx-for-mongodb
OCDev

9
Bagaimana mungkin suatu transaksi tidak menjadi "keharusan". Segera setelah Anda membutuhkan 1 kasing sederhana di mana Anda perlu memperbarui 2 tabel, mongo tiba-tiba tidak lagi cocok? Itu tidak meninggalkan banyak kasus penggunaan sama sekali.
Mr_E

1
@ Mr_E setuju, itu sebabnya MongoDB agak bodoh :)
Alexander Mills

6

Ini mungkin blog terbaik yang saya temukan tentang menerapkan fitur transaksi seperti untuk mongodb.!

Menyinkronkan Bendera: terbaik untuk hanya menyalin data dari dokumen master

Antrian Pekerjaan: tujuan umum, menyelesaikan 95% kasus. Sebagian besar sistem perlu memiliki setidaknya satu antrian pekerjaan!

Two Phase Commit: teknik ini memastikan bahwa setiap entitas selalu memiliki semua informasi yang diperlukan untuk mencapai kondisi yang konsisten

Rekonsiliasi Log: teknik yang paling kuat, ideal untuk sistem keuangan

Versi: menyediakan isolasi dan mendukung struktur yang kompleks

Baca ini untuk info lebih lanjut: https://dzone.com/articles/how-implement-robust-and


Harap sertakan bagian relevan dari sumber daya tertaut yang diperlukan untuk menjawab pertanyaan dalam jawaban Anda. Seperti apa adanya, jawaban Anda sangat rentan terhadap pembusukan tautan (yaitu jika situs web tertaut turun atau mengubah jawaban Anda berpotensi tidak berguna).
mech

Terima kasih @mech atas saran
Vaibhav

4

Ini sudah terlambat tetapi berpikir ini akan membantu di masa depan. Saya menggunakan Redis untuk membuat antrian untuk menyelesaikan masalah ini.

  • Persyaratan:
    Gambar di bawah ini menunjukkan 2 tindakan perlu dijalankan bersamaan tetapi fase 2 dan fase 3 tindakan 1 harus diselesaikan sebelum memulai fase 2 tindakan 2 atau berlawanan (Fase dapat berupa permintaan REST api, permintaan basis data, atau jalankan kode javascript ... ). masukkan deskripsi gambar di sini

  • Bagaimana antrian membantu Anda
    Mengantri memastikan bahwa setiap kode blok antara lock()dan release()dalam banyak fungsi tidak akan berjalan sebagai waktu yang sama, buat mereka mengisolasi.

    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");
    }
  • Bagaimana membangun antrian
    Saya hanya akan fokus pada bagaimana menghindari bagian kondisi lomba ketika membangun antrian di situs backend. Jika Anda tidak tahu ide dasar antrian, datang ke sini .
    Kode di bawah ini hanya menunjukkan konsep, Anda perlu menerapkan dengan cara yang benar.

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

Tetapi Anda perlu isRunning() setStateToRelease() setStateToRunning()mengisolasinya sendiri atau Anda menghadapi kondisi balapan lagi. Untuk melakukan ini saya memilih Redis untuk tujuan ACID dan scalable.
Redis dokumen berbicara tentang transaksi itu:

Semua perintah dalam transaksi adalah serial dan dieksekusi berurutan. Tidak pernah dapat terjadi bahwa permintaan yang dikeluarkan oleh klien lain dilayani di tengah pelaksanaan transaksi Redis. Ini menjamin bahwa perintah dijalankan sebagai operasi tunggal yang terisolasi.

P / s:
Saya menggunakan Redis karena layanan saya sudah menggunakannya, Anda dapat menggunakan isolasi dukungan cara lain untuk melakukan itu.
Di action_domaindalam kode saya di atas untuk ketika Anda hanya perlu tindakan 1 panggilan oleh pengguna A memblokir tindakan 2 dari pengguna A, jangan memblokir pengguna lain. Idenya adalah meletakkan kunci unik untuk mengunci setiap pengguna.


Anda akan menerima lebih banyak suara jika skor Anda sudah lebih tinggi. Begitulah cara berpikir kebanyakan orang di sini. Jawaban Anda bermanfaat dalam konteks pertanyaan. Saya telah mengangkat Anda.
Mukus

3

Transaksi tersedia sekarang di MongoDB 4.0. Contoh di sini

// 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();
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.