Layanan Mikro: Menangani konsistensi pada akhirnya

22

Asumsikan kita memiliki fungsi yang memperbarui kata sandi Pengguna.

Setelah tombol 'Perbarui Kata Sandi' diklik, UpdatePasswordEvent dikirim ke topik tempat 3 layanan lain dilanggan:

  1. Layanan yang benar-benar memperbarui kata sandi Pengguna
  2. Layanan yang memperbarui riwayat kata sandi pengguna
  3. Layanan yang mengirimkan email yang memberi tahu pengguna bahwa kata sandinya telah diubah.

Berdasarkan dari apa yang saya mengerti tentang konsistensi akhirnya, semua layanan ini (konsumen) akan menerima acara pada saat yang sama dan memprosesnya secara terpisah yang, dalam skenario yang baik, akan menyebabkan data menjadi konsisten.

Namun, bagaimana jika layanan gagal memproses acara? mis. tiba-tiba terputus, kesalahan basis data, dll ... Apa pola / praktik yang baik untuk menangani kegagalan transaksi ini?

Saya sedang berpikir untuk membuat RollbackTopic di mana jika ada peristiwa gagal diproses, RollbackEvent akan dibuat dalam topik di mana "layanan rollback" akan melakukan tugasnya dan mengembalikan data kembali

mpmp
sumber
11
Anda tidak dapat membatalkan email yang terkirim :-)
Laiv
2
Karena semuanya harus menjadi bagian dari layanan yang sama. Layanan mikro menentang monolit, bukan berarti Anda harus mendesainnya sesedikit mungkin "secara fisik". Meskipun ini tidak terkait langsung, Anda harus membaca pertanyaan ini dan dua jawaban teratas: softwareengineering.stackexchange.com/questions/339230/…
Walfrat
1
Anda mungkin ingin mempertimbangkan memperbarui kata sandi pengguna dalam database secara serempak, sehingga Anda memberikan umpan balik langsung kepada pengguna, dan memicu layanan lain secara tidak sinkron dengan memancarkan pesan yang kata sandi diubah pada suatu topik, sehingga pesan Anda tidak harus berisi kata sandi.
cr3
Apakah email untuk memberi tahu pengguna bahwa transaksi telah selesai, atau apakah ada di sana untuk memberi tahu pengguna bahwa seseorang (semoga mereka) telah mengubah kata sandi. "Jika bukan kamu, maka kamu harus bertindak". Jika yang ke-2 maka kirim saja email sekarang, sebaik mungkin.
ctrl-alt-delor

Jawaban:

29

Berdasarkan dari apa yang saya mengerti tentang konsistensi akhirnya, semua layanan ini (konsumen) akan menerima acara pada saat yang sama dan memprosesnya secara terpisah yang, dalam skenario yang baik, akan menyebabkan data menjadi konsisten.

Tidak, belum tentu. Saat saya berkomentar, kami tidak dapat membatalkan email yang dikirim, jadi kami masih membutuhkan semacam "urutan". IPC lebih manajemen data-event tidak membebaskan dari orchestation 1 .

Misalnya, email tidak boleh dikirim kecuali transaksi sebelumnya selesai dengan sukses dan layanan email mendapatkan buktinya. 3

Namun, bagaimana jika layanan gagal memproses acara? mis. tiba-tiba terputus, kesalahan basis data, dll ... Apa pola / praktik yang baik untuk menangani kegagalan transaksi ini?

Sampaikan salam yang salah pada komputasi terdistribusi . Mereka adalah yang membuat segalanya menjadi rumit dan, seperti biasa, tidak ada peluru perak untuk berurusan dengan mereka.

Sebelum memulai perjalanan kita untuk mencari Tabut yang Hilang, kita harus mempertimbangkan untuk bertanya kepada organisasi terlebih dahulu. Seringkali solusinya adalah bagaimana organisasi menghadapi masalah ini di dunia nyata .

Apa yang semua orang (departemen) lakukan ketika data tertentu hilang atau tidak lengkap?

Kami akan menyadari bahwa departemen yang berbeda memiliki solusi berbeda yang, bersama-sama, merupakan solusi yang akan diterapkan.

Bagaimanapun, di sini ada beberapa praktik yang bisa membantu kita dengan strategi untuk diikuti.

Konsistensi akhirnya

Daripada memastikan bahwa sistem dalam keadaan konsisten sepanjang waktu, alih-alih kita dapat menerima bahwa sistem akan mendapatkannya di beberapa titik di masa depan. Pendekatan ini sangat berguna untuk operasi bisnis jangka panjang.

Cara sistem untuk mencapai konsistensi bervariasi dari satu sistem ke sistem lainnya. Ini mungkin melibatkan dari proses otomatis hingga semacam intervensi manusia. Misalnya, tipikal mencobanya lagi nanti atau kontak dengan Layanan Pelanggan .

Batalkan semua operasi

Kembalikan sistem ke kondisi konsisten melalui kompensasi transaksi . Namun, kita harus memperhitungkan bahwa, transaksi ini bisa gagal juga, apa yang bisa membawa kita ke titik di mana ketidakkonsistenan bahkan lebih sulit untuk diselesaikan. Dan, sekali lagi, kami tidak dapat membatalkan email yang dikirim.

Untuk jumlah transaksi yang rendah, pendekatan ini layak, karena jumlah transaksi kompensasi juga rendah. Jika ada beberapa transaksi bisnis yang terlibat dalam IPC, menangani satu transaksi kompensasi untuk masing-masing akan menjadi tantangan.

Jika kita pergi untuk mengkompensasi transaksi , kita akan menemukan pola desain pemutus sirkuit menjadi sangat berguna - dan wajib saya berani mengatakan -

Transaksi terdistribusi

Idenya adalah untuk menjangkau beberapa transaksi dalam satu transaksi, melalui keseluruhan proses pemerintahan yang dikenal sebagai Manajer Transaksi . Algoritma umum untuk menangani transaksi terdistribusi adalah Komitmen dua fase .

Perhatian utama transaksi terdistribusi adalah bahwa mereka bergantung pada penguncian sumber daya selama masa pakainya, dan seperti yang kita tahu, ada yang salah dengan Manajer Transaksi juga.

Jika Manajer Transaksi dikompromikan, kita dapat berakhir dengan beberapa kunci di seluruh konteks terikat yang berbeda, menghasilkan perilaku yang tidak terduga karena penyampaian pesan. 2

Operasi penguraian. Mengapa?

Jika Anda membusuk sistem yang ada, dan menemukan kumpulan konsep yang benar-benar ingin berada dalam batas transaksi tunggal, mungkin biarkan mereka sampai yang terakhir.

Sam Newman

Sejalan dengan argumen di atas, Sam-dalam bukunya Building Microservices - menyatakan bahwa, jika kita benar-benar tidak mampu membayar konsistensi akhirnya, kita harus menghindari untuk membagi operasi sekarang.

Jika kita tidak mampu memisahkan operasi tertentu menjadi dua atau lebih transaksi, mungkin bisa dikatakan bahwa - kemungkinan - transaksi ini termasuk dalam konteks terikat yang sama, atau - setidaknya - untuk konteks lintas sektoral yang masih harus dimodelkan.

Misalnya, dalam kasus kami, kami menyadari bahwa transaksi # 1 dan # 2 terkait erat satu sama lain dan mungkin keduanya dapat memiliki konteks terikat yang sama Akun , Pengguna , Daftar , apa pun ...

Pertimbangkan menempatkan kedua operasi dalam batas-batas transaksi yang sama. Itu akan membuat seluruh operasi lebih mudah untuk ditangani. Juga menentukan tingkat kekritisan dari setiap transaksi. Mungkin, jika transaksi # 2 gagal, itu tidak boleh membahayakan seluruh operasi. Jika ragu, tanyakan kepada organisasi .


1: Bukan jenis orkestrasi yang Anda pikirkan. Saya tidak berbicara tentang orkestrasi ESB. Saya berbicara tentang membuat layanan bereaksi terhadap acara yang tepat.

2: Anda mungkin menemukan pendapat Sam Newman yang menarik tentang transaksi yang didistribusikan.

3: Periksa jawaban David Parker mengenai hal ini.

Laiv
sumber
3
Jawaban yang sangat bagus Saya hanya akan menekankan pentingnya memperhitungkan risiko akun yang datang ketika menggunakan transaksi terdistribusi - terutama penguncian sumber daya menghasilkan kebuntuan dan penghentian sistem. Pada produk e-commerce yang saya kerjakan sekitar 3 tahun yang lalu kami harus mengganti DT dengan sistem pesan, karena dengan jumlah pengguna yang tersedia dalam sistem, sistem itu sangat rentan terhadap kesalahan. Masalah dengan DT sebagian besar terjadi ketika basis pengguna tumbuh.
Andy
7

Dalam kasus Anda, Anda tidak bisa hanya memproses ketiga hal sekaligus. Yang Anda butuhkan adalah sebuah proses. Berikut adalah contoh yang sangat sederhana:

Perintah dan orkestrasi acara

Penting untuk diketahui bahwa mengubah operasi negara HARUS selalu dibuat pada entitas yang konsisten. Kecuali Anda dapat menjamin konsistensi yang kuat , itu harus dibuat pada catatan master.

Sistem Anda harus menjamin bahwa sebelum peristiwa apa pun dimunculkan dalam perubahan sistem Anda, HARUS bertahan dengan keamanan transaksional terlebih dahulu. Ini untuk memastikan bahwa acara yang diangkat benar-benar merupakan konfirmasi dari apa yang sebenarnya terjadi.

Ada beberapa bagian rumit dari proses ini dan saya akan mengabaikan yang sudah jelas - seperti: Bagaimana jika server basis data Anda mati saat mempertahankan pengguna dengan kata sandi yang diubah? Anda cukup menerbitkan Kata Pembaruan lagi. Namun, beberapa bagian perlu dijaga oleh Anda, dan ini adalah:

  • menangani duplikasi pesan,
  • menangani pengiriman email.

Dalam suatu sistem, process orchestrator (PO) tidak lain adalah entitas lain, yang berisi keadaan internal - dalam istilah literal juga - dan memungkinkan transisi antar negara, yang secara efektif bertindak sebagai semacam mesin negara. Berkat keadaan internal Anda dapat menghapus pemrosesan duplikasi pesan.

Ketika PO berada dalam Newkondisi dan proses UserPasswordHasBeenUpdated, ia mengubah statusnya menjadi UserPasswordHasBeenUpdated(atau yang mana nama negara bekerja untuk Anda). Jika PO masih dalam UserPasswordHasBeenUpdateddan yang lain UserPasswordHasBeenUpdatedakan tiba, PO akan sepenuhnya mengabaikan pesan, mengetahui itu duplikasi. Mekanisme serupa juga akan diterapkan untuk negara bagian lain.

Menangani pengiriman e-mail sebenarnya sedikit lebih rumit. Di sini Anda memiliki dua opsi:

  1. kirim paling banyak sekali,
  2. kirim setidaknya satu kali.

Kirim paling banyak sekali

Dengan opsi ini, ketika PO mencapai UserPasswordHistoryHasBeenSavedstatus, perintah untuk mengirim email dikirim sebagai reaksi terhadap perubahan status. Sistem Anda akan memastikan UserPasswordHistoryHasBeenSavedkeadaan akan tetap ada sebelum mengirim email, mis. Pesan yang digandakan tidak akan memicu pengiriman email lagi. Dengan pendekatan ini Anda memastikan bahwa keadaan yang benar disimpan untuk PO tetapi tidak dapat menjamin operasi berikut.

Kirim setidaknya satu kali

Inilah yang akan saya perjuangkan.

Alih-alih menyimpan UserPasswordHistoryHasBeenSaveddan mengirim e-mail sebagai reaksi terhadapnya, Anda mencoba mengirim e-mail terlebih dahulu. Jika operasi pengiriman gagal, status PO tidak pernah berubah UserPasswordHistoryHasBeenSaveddan pesan lain dari jenis yang sama masih diproses. Jika pengiriman e-mail benar-benar berhasil tetapi sistem Anda akan gagal selama mempertahankan PO dengan status barunya UserPasswordHistoryHasBeenSaved, pesan lain UserPasswordHistoryHasBeenSavedakan sekali lagi memicu perintah untuk mengirim e-mail dan pengguna akan menerimanya beberapa kali. .

Dalam kasus Anda, Anda ingin memastikan pengguna benar-benar menerima email. Itu sebabnya saya akan memilih opsi kedua daripada yang pertama.

Andy
sumber
2

Sistem antrian tidak serapuh yang Anda kira.

Jika kami menulis ketiga proses ke db relasional, kami mungkin menggunakan transaksi untuk menangani kegagalan proses pertengahan.

Tanpa komitmen akhir, pekerjaan parsial akan dibuang.

Dalam sistem basis antrian Anda akan memiliki opsi yang sama ketika Anda membaca pesan dari antrian untuk menangani kegagalan proses tengah.

Amazon SQS misalnya hanya menyembunyikan pesan yang dibaca. kecuali jika perintah Delete terakhir dikirim, pesan akan muncul kembali atau dimasukkan ke dalam antrian huruf mati.

Anda dapat menerapkan 'transaksi' serupa dengan berbagai cara, pada dasarnya memegang salinan pesan sampai Anda menerima konfirmasi pemrosesan yang berhasil. Jika konfirmasi tidak diterima tepat waktu. Anda dapat mengirim pesan lagi atau menyimpannya untuk perhatian manual.

Secara potensial Anda dapat membuat 'layanan rollback' yang memantau pesan-pesan yang salah ini, mengetahui tentang pesan terkait dan keadaan sebelumnya dan melakukan rollback.

Namun! Biasanya lebih baik hanya mengirim ulang pesan yang salah. Bagaimanapun ini cenderung menjadi kasus tepi. Baik server gagal atau ada bug dalam menangani jenis pesan tertentu.

Setelah diperingatkan akan kesalahan, layanan dapat diperbaiki dan pesan berhasil diproses. Membawa sistem secara keseluruhan kembali ke keadaan yang konsisten.

Ewan
sumber
2

Apa yang Anda hadapi di sini adalah masalah dua jenderal . Intinya: bagaimana Anda bisa yakin pesan diterima dan respons terhadap pesan itu terjadi? Dalam banyak kasus, solusi sempurna tidak ada. Bahkan, dalam sistem terdistribusi, seringkali mustahil untuk mendapatkan pengiriman pesan yang tepat satu kali .

Komentar jelas pertama adalah bahwa layanan yang mengubah kata sandi harus mengirimkan acara perubahan kata sandi. Dengan cara ini riwayat kata sandi dan layanan pengiriman surat hanya dipicu ketika kata sandi benar-benar berubah, terlepas dari mengapa itu berubah.

Untuk benar-benar menyelesaikan masalah Anda, saya tidak akan mempertimbangkan transaksi terdistribusi, tetapi melihat ke arah pengiriman pesan setidaknya-sekali dan pemrosesan idempoten.

  • Setidaknya sekali

    Untuk memastikan acara penggantian kata sandi benar-benar dilihat oleh semua konsumen, Anda perlu menggunakan saluran komunikasi yang tahan lama di mana pesan dapat dikonsumsi dalam gaya "setidaknya sekali". Konsumen hanya mengakui pesan yang dikonsumsi ketika mereka telah sepenuhnya memprosesnya. Jika, misalnya, layanan riwayat kata sandi macet saat menulis entri riwayat, ia akan membaca ulang acara penggantian kata sandi yang sama setelah dimulai ulang dan coba lagi, mengakui peristiwa itu sebagai hanya-baca setelah telah ditulis sendiri ke riwayat. Anda harus memilih solusi antrian pesan berdasarkan kemampuannya untuk mengirim ulang pesan sampai mereka dikenali.

  • Idempotensi

    Setelah mencapai pengiriman minimal satu kali, ada masalah tindakan duplikat yang terjadi ketika pesan diproses sebagian sebelum konsumen terganggu dan kemudian diproses ulang di kemudian hari. Itu harus diselesaikan dengan merancang setiap layanan sehingga idempoten. Entah menulis yang dilakukan dapat terjadi beberapa kali tanpa efek samping, atau menyimpan sendiri tindakan yang diambilnya dan menghindari melakukan tindakan lebih dari sekali. Dalam hal pengiriman surat, Anda mungkin menemukan bahwa itu mungkin tidak pantas untuk membuatnya berperilaku idempoten dan baik-baik saja dengan sesekali surat yang dikirim dua kali.

Bagaimanapun, berhati-hatilah bagaimana Anda membuat layanan mikro. Apakah layanan riwayat kata sandi Anda benar-benar harus independen dari layanan perubahan kata sandi?

Joeri Sebrechts
sumber
1

Saya tidak setuju dengan banyak jawaban.

  1. Kirim email sekarang “Seseorang telah mengubah kata sandi Anda. Jika itu kamu maka kamu tidak perlu melakukan apa-apa. Jika tidak panik. ”Ini akan tiba ketika tiba.
  2. Ubah kata sandi. Meskipun Anda akhirnya memiliki konsistensi. Anda ingin memastikan bahwa sesi ini melihat perubahan yang dilakukan oleh pengguna.

Ada janji konsistensi lain yang dapat Anda tambahkan.

  • Pastikan bahwa perubahan terjadi dalam urutan waktu.
  • Pastikan bahwa pengguna tidak pernah melihat kemunduran, tetapi pengguna lain mungkin masih tidak melihat perubahan.
  • Ada yang lain

Konsistensi tambahan ini perlu diterapkan tergantung pada tindakan aplikasi.


Saya tidak tahu apa yang Anda maksud dengan "memperbarui sejarah" tetapi tolong jangan pernah mengubah sejarah. Jika Anda hanya memperpanjang DAG, maka ini akan menyebabkan perubahan pada kondisi saat ini. Mereka tidak mandiri. Jika demikian maka Anda tidak dapat mengandalkan sejarah yang mencerminkan apa yang terjadi. (dan yang tak kalah pentingnya, jangan menyimpan kata sandi melihat bagaimana tidak menyimpan kata sandi )

ctrl-alt-delor
sumber
Jika Anda dapat mengirim email di awal maka pendekatan Anda baik-baik saja. Jika Anda harus mengirim sesuatu bersama dengan email. Mungkin semacam tautan / data yang hanya bisa diperoleh setelah konsistensi tercapai, maka Anda tidak bisa mengirim email terlebih dahulu. Itulah yang saya komentari consider asking the organization first.. Anda mungkin benar. Namun, saya merasa penting untuk mengkondisikan peristiwa yang tidak dapat kami batalkan. Misalnya pemberitahuan kepada pengguna akhir. Pemberitahuan yang berbohong tentang keadaan sebenarnya dari data pengguna mungkin memberi kesan buruk.
Laiv
Yang mengatakan, untuk skenario khusus ini (pemberitahuan perubahan kata sandi), saya setuju dengan pendekatan ini. Segera setelah memenuhi persyaratan.
Laiv