Mengapa database sebagai antrian begitu buruk? [Tutup]

33

Saya baru saja membaca artikel ini , dan saya bingung.

Mari kita bayangkan 1 webapp dan 1 aplikasi berbeda yang bertindak sebagai "pekerja", keduanya berbagi database yang sama .

Oh, saya bilang "sharing" .. tapi apa yang diperingatkan artikel itu? :

Keempat, berbagi basis data antar aplikasi (atau layanan) adalah hal yang buruk. Terlalu menggoda untuk menempatkan keadaan berbagi amorf di sana dan sebelum Anda menyadarinya, Anda akan memiliki monster yang sangat berpasangan.

=> tidak setuju. Ada beberapa kasus di mana aplikasi yang berbeda masih menjadi bagian dari unit yang sama, dan karena itu, gagasan "masalah kopling" tidak masuk akal dalam kasus ini.

Mari kita lanjutkan: Webapp menangani permintaan HTTP klien dan dapat memperbarui kapan saja beberapa agregat (istilah DDD), menghasilkan peristiwa domain yang sesuai.
Tujuan pekerja adalah untuk menangani peristiwa domain tersebut dengan memproses pekerjaan yang dibutuhkan.

Intinya adalah:

Bagaimana seharusnya data acara diteruskan ke pekerja?

Solusi pertama, seperti yang dipromosikan artikel baca, adalah menggunakan RabbitMQ, menjadi middleware berorientasi pesan yang hebat.

Alur kerjanya akan sederhana:

Setiap kali dyno web membuat suatu acara, itu mempublikasikannya melalui RabbitMQ, yang memberi makan pekerja.
Kekurangannya adalah tidak ada yang menjamin konsistensi langsung antara komitmen pembaruan agregat dan penerbitan acara, tanpa berurusan dengan potensi kegagalan pengiriman ... atau masalah perangkat keras; itu adalah masalah utama lainnya.

Contoh: Ada kemungkinan bahwa suatu peristiwa diterbitkan tanpa keberhasilan pembaruan agregat ... menghasilkan suatu peristiwa yang mewakili representasi palsu dari model domain.
Anda bisa berargumen bahwa XA global (komit dua fase) ada, tetapi itu bukan solusi yang cocok untuk semua basis data atau middlewares.

Jadi apa yang bisa menjadi solusi yang baik untuk memastikan konsistensi langsung ini? :
IMO, menyimpan acara dalam database, dalam transaksi lokal yang sama dengan pembaruan agregat.
Penjadwal asinkron sederhana akan dibuat dan bertanggung jawab untuk menanyakan peristiwa yang tidak dipublikasikan saat ini dari basis data dan mengirimkannya ke RabbitMQ, yang pada gilirannya mengisi pekerja tersebut.

Tapi mengapa perlu penjadwal tambahan di sisi webapp dan omong-omong: mengapa membutuhkan RabbitMQ dalam kasus ini?

Dengan solusi ini, tampaknya secara logis, bahwa RabbitMQ dapat menjadi tidak perlu, terutama karena database digunakan bersama.
Memang, apa pun masalahnya, kami melihat bahwa konsistensi langsung melibatkan pemungutan suara dari database.
Jadi, mengapa pekerja tidak akan bertanggung jawab langsung atas pemungutan suara ini?

Oleh karena itu, saya bertanya-tanya mengapa begitu banyak artikel di web yang mengkritik antrian basis data, sembari mempromosikan middleware yang berorientasi pesan.

Kutipan artikel:

Sederhana, gunakan alat yang tepat untuk pekerjaan itu: skenario ini menyerukan sistem pesan. Ini memecahkan semua masalah yang dijelaskan di atas; tidak ada lagi jajak pendapat, pengiriman pesan yang efisien, tidak perlu menghapus pesan yang selesai dari antrian, dan tidak ada keadaan bersama.

Dan konsistensi langsung, diabaikan?

Singkatnya, tampaknya apa pun masalahnya, artinya database dibagikan atau tidak, kita perlu jajak pendapat database .

Apakah saya kehilangan beberapa gagasan kritis?

Terima kasih

Mik378
sumber
2
Polling adalah semacam herring merah, karena hampir semua database utama memiliki beberapa mekanisme untuk secara tidak serentak memberitahukan beberapa proses lain bahwa inilah saatnya untuk menarik beberapa pekerjaan dari sebuah tabel.
Blrfl

Jawaban:

28

Jika Anda sedang membangun aplikasi sederhana dengan lalu lintas rendah, ada sesuatu yang bisa dikatakan tentang menjaga komponen lain dari sistem Anda. Sangat mungkin bahwa tidak menggunakan bus pesan adalah jawaban yang tepat untuk Anda. Namun, saya akan menyarankan membangun sistem Anda dengan cara Anda bisa menukar sistem antrian berbasis database untuk solusi middleware. Saya setuju dengan artikel itu. Basis data bukanlah alat yang tepat untuk sistem berbasis antrian, tetapi mungkin cukup baik untuk Anda.

Sistem berbasis antrian seperti RabbitMq dibangun dengan skala besar pada perangkat keras sedang. Arsitektur mereka mampu mencapai hal ini dengan menghindari proses yang membuat sistem basis data ACID yang patuh menurut sifatnya. Karena bus pesan hanya perlu memastikan pesan disimpan dan berhasil diproses, tidak perlu repot dengan mengunci dan menulis log transaksi. Kedua konsep ini mutlak diperlukan untuk sistem ACID tetapi seringkali menjadi penyebab pertikaian.

Kinerja-bijaksana turun ke: Anda memiliki tabel SQL. Banyak membaca dan banyak menulis. Keduanya membutuhkan semacam penguncian untuk memperbarui baris, halaman, dan indeks. Mekanisme pemungutan suara Anda terus-menerus mengunci indeks untuk melakukan pencarian. Ini mencegah penulisan terjadi; paling-paling mereka antri. Kode yang melakukan pemrosesan juga dikunci untuk memperbarui status pada antrian saat mereka selesai atau gagal. Ya, Anda dapat melakukan optimasi kueri setelah optimasi untuk membuatnya berfungsi, atau Anda dapat menggunakan sistem yang dirancang khusus untuk beban kerja yang Anda minta. A RabbitMq memakan jenis pekerjaan ini tanpa berkeringat; selain itu, Anda bisa menyimpan database Anda dari beban kerja sehingga memberikan lebih banyak ruang untuk melakukan hal-hal lain.

Satu hal yang perlu dipertimbangkan adalah kebanyakan sistem antrian biasanya tidak menggunakan teknik polling (beberapa mengizinkan untuk HTTP, tetapi merekomendasikan untuk menghindari menggunakan untuk sisi penerima). RabbitMq menggunakan protokol jaringan yang dirancang khusus untuk bus pesan seperti AMPQ .

Edit: Menambahkan kasus penggunaan.

Cara saya menggunakan Rabbit adalah saya memiliki titik akhir API yang menerima perubahan yang membutuhkan tabel database yang banyak digunakan. Tabel ini berada di bawah pertentangan konstan dan kadang-kadang tidak akan dapat menyimpan perubahan secara tepat waktu dari API. Yang saya lakukan sebagai gantinya adalah menulis permintaan perubahan ke antrian dan kemudian memiliki layanan yang menangani pesan-pesan ini sebagaimana mereka mampu. Jika pertikaian basis data terjadi, antrian bertambah dan pemrosesan pesan tertunda. Biasanya memproses waktu turun dalam kisaran 14 ms, tetapi pada saat pertengkaran tinggi kita mendapatkan hingga 2-3 detik.

brianfeucht
sumber
Bagaimana Anda bisa menangani konsitensi langsung dalam kasus ini? Jika penerbitan dibuat tetapi segera setelah itu, transaksi yang bertanggung jawab untuk memperbarui rollback model domain ... middleware akan sama sekali tidak sadar dan akan memproses acara tersebut.
Mik378
Anda menulis: "tidak perlu repot dengan penguncian". Tapi pasti ada semacam penguncian untuk memastikan urutan naik (tepat waktu) dari peristiwa yang dialihkan (terhadap pekerja), bukan?
Mik378
@ Mik378 Lihatlah artikel ini tentang idempotensi pesan . Ya secara teknis Anda kehilangan beberapa janji konsistensi, tetapi saya yakin Anda akan menemukan apa yang Anda peroleh dalam hal keandalan waktu operasi dan kinerja aplikasi yang sepadan. Juga cukup mudah untuk mengubah cara Anda memproses pesan untuk membuat kerugiannya tidak menyakitkan.
brianfeucht
2
Ya, Anda perlu mengunci untuk menjamin pesanan. Beberapa sistem antrian dapat menyediakan ini dengan harga kinerja. Jika Anda dapat menerima kenyataan bahwa kadang-kadang operasi akan rusak dan mencari cara untuk menanganinya di sisi prosesor, Anda akan memperoleh secara eksponensial dari titik kinerja.
brianfeucht
1
@ Mik378 - Saya menambahkan use case ke jawaban saya. Saya harap ini membantu!
brianfeucht