Kesalahan penanganan dalam sistem terdistribusi

8

Ini adalah urutan umum dari dua komponen terdistribusi dalam aplikasi Java kami:

1  A sends request to B
2      B starts some job J in parallel thread
3      B returns response to A
4  A accepts response
5      Job finishes after some time
6      Job sends information to A
7  A receives response from a Job and updates

Ini adalah skenario yang ideal, dengan asumsi semuanya berfungsi. Tentu saja, kehidupan nyata penuh dengan kegagalan. Misalnya, salah satu kasus terburuk mungkin jika #6gagal hanya karena jaringan: pekerjaan telah dijalankan dengan benar, tetapi Atidak tahu apa-apa tentang itu.

Saya mencari pendekatan ringan tentang cara mengelola kesalahan dalam sistem ini. Perhatikan bahwa kami memiliki banyak komponen, jadi mengelompokkannya hanya karena penanganan kesalahan tidak masuk akal. Selanjutnya, saya membuang penggunaan memori / repo yang didistribusikan yang akan diinstal lagi pada setiap komponen dengan alasan yang sama.

Pikiranku menuju ke arah memiliki satu keadaan absolut pada huruf B dan tidak pernah memiliki keadaan yang tetap pada huruf a A. Ini berarti yang berikut:

  • sebelum #1kita tandai Abahwa unit kerja yaitu perubahan akan segera dimulai
  • hanya Bdapat menghapus tanda negara ini.
  • Adapat mengambil info tentang Bkapan saja, untuk memperbarui keadaan.
  • tidak ada perubahan baru pada unit yang sama dapat dipanggil A.

Bagaimana menurut anda? Apakah ada cara ringan untuk menjinakkan kesalahan dalam sistem semacam ini?

igor
sumber
Ini pertanyaan lama. Apakah Anda menemukan solusi yang baik? ... Jika demikian, dapatkah Anda membagikannya?
svidgen

Jawaban:

2

Menambahkan ke log persisten A harus cukup. Ini mengatasi dengan reboot dan partisi jaringan untuk mencapai konsistensi akhirnya, atau untuk kerusakan sinyal yang mencegah konvergensi tersebut. Dengan komit kelompok yang diamortisasi , dibutuhkan waktu kurang dari satu tulisan untuk bertahan dalam entri log.

Anda menyarankan agar B bertanggung jawab atas status yang tidak ditandai. Saya tidak setuju. Hanya A yang menyadari pekerjaan baru, dan hanya A yang harus bertanggung jawab untuk melacaknya dan melaporkan kesalahan seperti batas waktu. B mengirimkan pesan idempoten ke A, dan A memperbarui status, menanyakan ulang secara berkala sesuai kebutuhan.

Pada langkah 0, A menyadari permintaan baru dan mencatatnya. Itu merupakan kewajiban yang harus dilepaskan oleh A setelah batas waktu tertentu - A akan terus melakukan, dan mengulangi, langkah-langkah selanjutnya sampai A mengetahui bahwa pemrosesan permintaan telah selesai.

Beberapa permintaan akan lebih lama dari yang lainnya. Perkiraan waktu pemrosesan akan tersedia pada A dan B, mungkin direvisi sebagai proses yang berlanjut. Perkiraan tersebut dapat diumpankan kembali ke A sehingga jarang menghasilkan batas waktu positif palsu. Anggap saja sebagai pesan tetap hidup yang mengatakan "masih bekerja, masih bekerja"

J_H
sumber
1

Gunakan tarikan alih-alih strategi dorong. Buat setiap bagian menarik perubahan dari yang lain dan perbarui catatannya sendiri.

  • A mencatat hal-hal yang harus dilakukan B ke antrian
  • B menarik dari antrian A dan melakukan pekerjaan
  • B mencatat hal-hal yang telah dilakukan ke antrian
  • Tarik dari antrian B untuk mengetahui apa hasil pekerjaan itu

(Saya menggunakan kata antrian, tetapi Anda dapat mengganti log atau topik.)

Anda dapat memanggang antrian ke dalam layanan, atau Anda dapat memiliki pialang pesan terpisah. Implementasi yang dimasukkan ke dalam layanan dapat sesederhana GET /jobrequests?from=<timestamp>(dengan B mencatat cap waktu permintaan pekerjaan yang diproses terbaru).

Bagian rumit dari arsitektur semacam itu adalah memutuskan semantik paling tidak satu kali vs semantik paling banyak. Konkret: jika B menarik item dari antrian dan kemudian crash saat melakukan itu, apa yang harus terjadi? Ada dua kemungkinan, dan mana yang paling tepat tergantung pada kasus penggunaan Anda:

  • At-least-once: B hanya melakukan titik antrian yang mana setelah menyelesaikan suatu tindakan, ada risiko melakukan tindakan dua kali. Jika Anda mendesain tindakan menjadi idempoten, Anda dapat mencapai perilaku tepat sekali menggunakan pendekatan ini. (Saya menggunakan kafka untuk skenario ini.)
  • Paling banyak sekali: B hanya mengkonsumsi setiap item antrian sekali. Jika crash saat menjalankannya, maka item tidak akan pernah dieksekusi.

Manfaat dari pendekatan ini:

  • Layanan yang memakan antrian tidak perlu siap untuk mendorong antrian untuk muncul. Ini berarti bahwa Anda bebas untuk memulai ulang B saat A sedang bekerja atau memulai kembali A saat B sedang bekerja. Redundant hosting layanan latar belakang hanya diperlukan untuk memastikan waktu respons keseluruhan, bukan operasi yang andal.
  • Kecepatan menarik item antrian dapat dikontrol oleh konsumen, yang memungkinkan Anda untuk sementara buffer puncak beban dalam antrian.
Joeri Sebrechts
sumber