İki düğüm arasındaki karşılıklı bağlantı sırasında dağıtılmış bir kilitlenmeyi nasıl önleyebilirim?


11

İki eş düğümümüz olduğunu varsayalım: ilk düğüm ikincisine bir bağlantı isteği gönderebilir, ancak ikincisi de birincisine bir bağlantı isteği gönderebilir. İki düğüm arasında çift bağlantı nasıl önlenir? Bu sorunu gidermek için, gelen veya giden TCP bağlantıları oluşturmak için gerçekleştirilen işlemleri sırayla yapmak yeterli olacaktır.

Bu, her düğümün hem gelen bağlantılar hem de giden bağlantılar için her yeni bağlantı oluşturma işlemini sırayla işlemesi gerektiği anlamına gelir. Bu şekilde, bir düğümden yeni bir gelen bağlantı kabul etmeden veya bir düğüme bir bağlantı isteği göndermeden önce, bağlı düğümlerin bir listesini tutmak, bu düğümün listede zaten mevcut olup olmadığını kontrol etmek için yeterli olacaktır.

Bağlantı oluşturma işlemlerini sırayla yapmak için , bağlı düğümler listesinde bir kilit gerçekleştirmek yeterlidir : aslında, her yeni bağlantı için, yeni bağlı düğümün tanımlayıcısı bu listeye eklenir. Ancak, bu yaklaşım dağıtılmış kilitlenmeye neden olup olmadığını merak ediyorum :

  • ilk düğüm ikincisine bir bağlantı isteği gönderebilir;
  • ikinci düğüm birincisine bir bağlantı isteği gönderebilir;
  • iki bağlantı isteğinin eşzamansız olmadığını varsayarsak, her iki düğüm de gelen bağlantı isteklerini kilitler.

Bu sorunu nasıl çözebilirim?

GÜNCELLEŞTİRME: Ancak, diğer bir iş parçacığı bu listeye erişebildiğinden, her yeni (gelen veya giden) bağlantı oluşturulduğunda listeyi kilitlemem gerekir, sonra kilitlenme sorunu hala devam edecektir.

GÜNCELLEME 2: Tavsiyenize dayanarak bir giriş talebinin karşılıklı olarak kabul edilmesini önlemek için bir algoritma yazdım. Her düğüm bir eş olduğundan, yeni bağlantı istekleri göndermek için bir istemci rutini ve gelen bağlantıları kabul etmek için bir sunucu rutini olabilir.

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
}

Örnek: A düğümünün IP: bağlantı noktası A: 7001 - B düğümünün IP: bağlantı noktası B: 8001'dir.

A düğümünün B: 8001 düğümüne bir oturum açma isteği gönderdiğini varsayalım. Bu durumda, A düğümü kendi dinleme adresini göndererek giriş rutinini çağırır (A: 7001). Sonuç olarak, A düğümünün neighbors_table'ı uzak düğümün adresini içerir (B: 8001): bu adres BAĞLANMA durumuyla ilişkilidir. A düğümü, B düğümü giriş isteğini kabul etmeyi veya reddetmeyi bekliyor.

Bu arada, B düğümü de A düğümünün (A: 7001) adresine bir bağlantı isteği göndermiş olabilir, daha sonra A düğümü B düğümünün isteğini işliyor olabilir. Bu nedenle, B düğümünün neighbors_table'ı uzaktan düğüm (A: 7001): bu adres BAĞLANMA durumuyla ilişkilendirilir. B düğümü, A düğümünün oturum açma isteğini kabul etmesini veya reddetmesini bekliyor.

A düğümünün sunucu tarafı B: 8001'den gelen isteği reddederse, B düğümünün sunucu tarafının A: 7001'den gelen isteği kabul edeceğinden emin olmalıyım. Benzer şekilde, B düğümünün sunucu tarafı A: 7001'den isteği reddederse, A düğümünün sunucu tarafının B: 8001'den isteği kabul edeceğinden emin olmalıyım.

Göre "küçük adresi" kuralı düğüm B düğümü A'dan isteği kabul ederken, bu durumda düğüm A, B düğümü tarafından giriş isteğini reddeder

Bunun hakkında ne düşünüyorsun?


Bu tür algoritmaları analiz etmek ve kanıtlamak oldukça zordur. Ancak, dağıtılmış bilgi işlemin birçok alanında uzman bir araştırmacı var. Leslie Lamport'un yayınlar sayfasına göz atın: araştırma.microsoft.com/
DeveloperDon

Yanıtlar:


3

Bir "iyimser" yaklaşım deneyebilirsiniz: önce bağlan, sonra eşzamanlı karşılıklı bağlantı tespit ederseniz bağlantıyı kes. Bu şekilde, yeni bağlantılar kurarken bağlantı isteklerini dışarıda tutmanız gerekmez: Gelen bir bağlantı kurulduğunda, listeyi kilitleyin ve aynı ana bilgisayara giden bir bağlantınız olup olmadığını görün. Bunu yaparsanız, ana bilgisayarın adresini kontrol edin. Sizinkinden daha küçükse, giden bağlantınızın bağlantısını kesin; aksi halde, gelenin bağlantısını kesin. Eş sunucunuz tam tersini yapar, çünkü adresler farklı şekilde karşılaştırılacak ve iki bağlantıdan biri bırakılacaktır. Bu yaklaşım, bağlantılarınızı yeniden denemekten kaçınmanıza olanak tanır ve potansiyel olarak birim zaman başına daha fazla bağlantı isteğini kabul etmenize yardımcı olur.


Bununla birlikte, diğer bir iş parçacığı bu listeye erişebildiğinden, her yeni (gelen veya giden) bağlantı oluşturulduğunda listeyi kilitlemem gerekiyor, sonra kilitlenme sorunu hala kalacaktı.
enzom83

@ enzom83 Hayır, bu şema altında kilitlenme mümkün değildir, çünkü akran asla kilitleme gerektiren işlemi tamamlamanızı beklemek zorunda değildir. Muteks, listenizin içini korumaktır; bir kez edindikten sonra, bilinen bir süre içinde ayrılırsınız, çünkü kritik bölüm içinde başka bir kaynak beklemenize gerek yoktur.
dasblinkenlight

Tamam, ancak bağlantı isteği eşzamansız değilse ve kritik bölüm içinde gerçekleştirilirse kilitlenme oluşabilir : bu durumda düğüm, bağlantı isteği kabul edilene kadar muteksi terk edemez. Aksi takdirde listedeki kilidi sadece bir düğüm eklemek (veya kaldırmak) için yapmalıyım: bu durumda yinelenen bağlantılar vb.
enzom83

1
@ enzom83 Kritik bölüm içinden bağlantı istemediğiniz sürece dağıtılmış bir kilitlenme elde edemezsiniz. İyimser yaklaşımın ardındaki fikir budur - listede sadece bir düğüm eklemek veya kaldırmak için bir kilit gerçekleştirirsiniz ve bir düğüm eklerken karşılıklı bir bağlantı bulursanız, "küçük adres" kullanarak kritik bölümü terk ettikten sonra onu koparırsınız kuralı (cevaptan).
dasblinkenlight

4

Bir düğüm diğerine istek gönderdiğinde, rastgele bir 64 bit tam sayı içerebilir. Bir düğüm bir bağlantı isteği aldığında, zaten kendisinden birini gönderdiyse, en yüksek numaralı olanı tutar ve diğerlerini bırakır. Örneğin:

Zaman 1: A, B'ye bağlanmaya çalışır, 123 sayısını gönderir.

Zaman 2: B, A'ya bağlanmaya çalışır, 234 sayısını gönderir.

Zaman 3: B, A'nın isteğini alır. B'nin kendi isteği daha yüksek bir sayıya sahip olduğu için A'nın isteği reddedilir.

Zaman 4: A, B'nin isteğini alır. B'nin isteği daha yüksek bir sayıya sahip olduğundan, A onu kabul eder ve kendi isteğini bırakır.

Rasgele sayı üretmek için, rasgele sayı üretecinizi, genellikle duvar saati zamanına dayanan rastgele sayı üretecinizin varsayılan tohumlamasını kullanmak yerine, / dev / urandom ile eklediğinizden emin olun: iki düğümün göz ardı edilemez bir şansı var aynı tohumu alacaksınız.

Rastgele sayılar yerine, sayıları vaktinden önce dağıtabilirsiniz (yani, tüm makineleri 1'den n'ye kadar numaralandırabilir) veya bir MAC adresi kullanabilir veya çarpışma olasılığının çok küçük olduğu bir numara bulmanın başka bir yolunu kullanabilirsiniz. ardı.


3

Anlıyorsam, kaçınmaya çalıştığınız sorun şöyle:

  • Düğüm1, düğüm 2'den bağlantı istiyor
  • Düğüm1 bağlantı listesini kilitler
  • Düğüm2, düğüm 1'den bağlantı istiyor
  • Düğüm2 bağlantı listesini kilitler
  • Düğüm2, düğüm1'den bağlantı isteği alır, liste kilitli olduğu için reddedilir
  • Düğüm1, düğüm2'den bağlantı isteği alır, liste kilitli olduğu için reddedilir
  • İkisi de birbirine bağlanmaz.

Bununla başa çıkmanın birkaç farklı yolunu düşünebilirim.

  1. Bir düğüme bağlanmaya çalışırsanız ve "liste kilitli" iletisiyle isteğinizi reddederseniz, yeniden denemeden önce rasgele bir milisaniye bekleyin. (Rastgele olma kritik öneme sahiptir. Her ikisinin de aynı süre kadar beklemesi ve aynı sorunlu reklam sonsuzluğunu tekrarlaması çok daha az olasıdır .)
  2. Her iki sistemin saatini bir zaman sunucusuyla senkronize edin ve bağlantı isteği ile birlikte bir zaman damgası gönderin. Şu anda bağlanmaya çalıştığınız bir düğümden bir bağlantı isteği gelirse, her iki düğüm de hangisinin ilk bağlanmaya çalışırsa kazanır ve diğer bağlantı kapanır.

Sorun ayrıca, isteği alan düğümün bağlantıyı reddedememesi, ancak listede kilidi almak için süresiz olarak beklemesidir.
enzom83
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.