Misalkan kita memiliki dua node peer: node pertama dapat mengirim permintaan koneksi ke yang kedua, tetapi juga yang kedua dapat mengirim permintaan koneksi ke yang pertama. Bagaimana cara menghindari koneksi ganda antara kedua node? Untuk mengatasi masalah ini, cukup berurutan untuk operasi yang dilakukan untuk membuat koneksi TCP masuk atau keluar.
Ini berarti bahwa setiap node harus memproses secara berurutan setiap operasi pembuatan koneksi baru, baik untuk koneksi masuk maupun untuk koneksi keluar. Dengan cara ini, mempertahankan daftar node yang terhubung, sebelum menerima koneksi masuk baru dari suatu node atau sebelum mengirim permintaan koneksi ke sebuah node, itu akan cukup untuk memeriksa apakah node ini sudah ada dalam daftar.
Untuk membuat sekuensial operasi pembuatan koneksi, cukup dengan melakukan kunci pada daftar node yang terhubung: pada kenyataannya, untuk setiap koneksi baru, pengidentifikasi dari node yang terhubung baru ditambahkan ke daftar ini. Namun, saya bertanya-tanya apakah pendekatan ini dapat menyebabkan kebuntuan terdistribusi :
- simpul pertama dapat mengirim permintaan koneksi ke simpul kedua;
- simpul kedua bisa mengirim permintaan koneksi ke yang pertama;
- dengan asumsi bahwa dua permintaan koneksi tidak sinkron, kedua node mengunci setiap permintaan koneksi yang masuk.
Bagaimana saya bisa menyelesaikan masalah ini?
UPDATE: Namun, saya masih harus mengunci daftar setiap kali koneksi baru (masuk atau keluar) dibuat, karena utas lain dapat mengakses daftar ini, maka masalah kebuntuan masih akan tetap ada.
UPDATE 2: Berdasarkan saran Anda, saya menulis sebuah algoritma untuk mencegah saling menerima permintaan login. Karena setiap node adalah peer, itu bisa memiliki rutin klien untuk mengirim permintaan koneksi baru dan rutin server untuk menerima koneksi masuk.
ClientSideLoginRoutine() {
for each (address in cache) {
lock (neighbors_table) {
if (neighbors_table.contains(address)) {
// there is already a neighbor with the same address
continue;
}
neighbors_table.add(address, status: CONNECTING);
} // end lock
// ...
// The node tries to establish a TCP connection with the remote address
// and perform the login procedure by sending its listening address (IP and port).
boolean login_result = // ...
// ...
if (login_result)
lock (neighbors_table)
neighbors_table.add(address, status: CONNECTED);
} // end for
}
ServerSideLoginRoutine(remoteListeningAddress) {
// ...
// initialization of data structures needed for communication (queues, etc)
// ...
lock(neighbors_table) {
if(neighbors_table.contains(remoteAddress) && its status is CONNECTING) {
// In this case, the client-side on the same node has already
// initiated the procedure of logging in to the remote node.
if (myListeningAddress < remoteListeningAddress) {
refusesLogin();
return;
}
}
neighbors_table.add(remoteListeningAddress, status: CONNECTED);
} // end lock
}
Contoh: IP: port node A adalah A: 7001 - IP: port node B adalah B: 8001.
Misalkan node A telah mengirim permintaan login ke node B: 8001. Dalam hal ini, simpul A memanggil rutin masuk dengan mengirim dengan mengirimkan alamat pendengarannya sendiri (A: 7001). Sebagai konsekuensinya, neighbor_table dari node A berisi alamat dari remote node (B: 8001): alamat ini dikaitkan dengan keadaan CONNECTING. Node A sedang menunggu node B menerima atau menolak permintaan login.
Sementara itu, simpul B juga mungkin telah mengirim permintaan koneksi ke alamat simpul A (A: 7001), kemudian simpul A dapat memproses permintaan dari simpul B. Jadi, neighbor_table dari simpul B berisi alamat dari jarak jauh simpul (A: 7001): alamat ini dikaitkan dengan keadaan CONNECTING. Node B sedang menunggu simpul A menerima atau menolak permintaan masuk.
Jika sisi server dari simpul A menolak permintaan dari B: 8001, maka saya harus yakin bahwa sisi server dari simpul B akan menerima permintaan dari A: 7001. Demikian pula, jika sisi server dari simpul B menolak permintaan dari A: 7001, maka saya harus yakin bahwa sisi server dari simpul A akan menerima permintaan dari B: 8001.
Menurut aturan "alamat kecil" , dalam hal ini simpul A akan menolak permintaan masuk oleh simpul B, sedangkan simpul B akan menerima permintaan dari simpul A.
Apa pendapatmu tentang itu?
sumber
Jawaban:
Anda dapat mencoba pendekatan "optimis": sambungkan terlebih dahulu, lalu putuskan sambungan jika Anda mendeteksi koneksi bersama secara bersamaan. Dengan cara ini Anda tidak perlu menahan permintaan koneksi saat Anda membuat koneksi baru: ketika koneksi masuk dibuat, kunci daftar, dan lihat apakah Anda memiliki koneksi keluar ke host yang sama. Jika ya, periksa alamat host. Jika lebih kecil dari milik Anda, putuskan koneksi keluar Anda; jika tidak, putuskan sambungan yang masuk. Rekan host Anda akan melakukan yang sebaliknya, karena alamat akan membandingkan secara berbeda, dan salah satu dari dua koneksi akan terputus. Pendekatan ini memungkinkan Anda menghindari mencoba kembali koneksi Anda, dan berpotensi membantu Anda menerima lebih banyak permintaan koneksi per unit waktu.
sumber
Ketika satu node mengirim permintaan ke yang lain, itu bisa menyertakan integer 64-bit acak. Ketika sebuah node mendapat permintaan koneksi, jika sudah mengirimkan salah satu dari itu sendiri, itu membuat satu dengan nomor tertinggi dan menjatuhkan yang lain. Sebagai contoh:
Waktu 1: A mencoba terhubung ke B, mengirimkan nomor 123.
Waktu 2: B mencoba untuk terhubung ke A, mengirimkan nomor 234.
Waktu 3: B menerima permintaan A. Karena permintaan B sendiri memiliki angka yang lebih tinggi, permintaan B menolak.
Waktu 4: A menerima permintaan B. Karena permintaan B memiliki angka yang lebih tinggi, A menerimanya dan menjatuhkan permintaannya sendiri.
Untuk menghasilkan angka acak, pastikan Anda menaburkan generator nomor acak Anda dengan / dev / urandom, daripada menggunakan seeding default generator nomor acak Anda, yang sering didasarkan pada waktu jam dinding: ada peluang yang tidak dapat diabaikan bahwa dua node akan mendapatkan benih yang sama.
Alih-alih angka acak, Anda juga dapat mendistribusikan angka sebelumnya (yaitu hanya memberi nomor semua mesin dari 1 ke n), atau menggunakan alamat MAC, atau cara lain untuk menemukan nomor di mana probabilitas tabrakan sangat kecil sehingga menjadi dapat diabaikan.
sumber
Jika saya mengerti, masalah yang ingin Anda hindari adalah seperti ini:
Saya dapat memikirkan beberapa cara berbeda untuk menangani hal ini.
sumber