6

次のコード スニペットは JVM クラッシュを引き起こします: ロックの取得後にネットワーク停止が発生した場合

    while (true) {

       //file shared over nfs
       String filename = "/home/amit/mount/lock/aLock.txt";
       RandomAccessFile file = new RandomAccessFile(filename, "rws");
       System.out.println("file opened");
       FileLock fileLock = file.getChannel().tryLock();
       if (fileLock != null) {
          System.out.println("lock acquired");
       } else {
          System.out.println("lock not acquired");
       }

       try {
          //wait for 15 sec
          Thread.sleep(30000);
       } catch (InterruptedException e) {
          e.printStackTrace();
       }
       System.out.println("closing filelock");
       fileLock.close();
       System.out.println("closing file");
       file.close();
    }

観察: JVM は KILL(9) シグナルを受信し、終了コード 137(128+9) で終了します。

おそらく、ネットワーク接続が再確立された後、ファイル記述子テーブルで何か問題が発生します。この動作は、システム コール flock(2) およびシェル ユーティリティ flock(1) で再現できます。

提案/回避策はありますか?

PS: NFSv4 で Oracle JDK 1.7.0_25 を使用

EDIT : このロックは、分散された高可用性クラスターでアクティブなプロセスを識別するために使用されます。終了コードは 137 です。問題を検出する方法。ファイルを閉じて、再取得を試みてください。

4

3 に答える 3

5

終了コード 138 は SIGKILL を示唆するものではありません。これはシグナル 10 であり、SIGBUS (solaris の場合) または SIGUSR1 (linux の場合) の可能性があります。残念ながら、どちらを使用しているかは教えていただけません。

理論的には、nfs はすべてを透過的に処理する必要があります。つまり、マシンがクラッシュし、再起動し、ロックが解除されます。実際には、これが NFS3 でうまく機能するのを見たことがありません。(あなたが使用している) NFS4 では、個別の lockd() と statd() がないため、さらに困難になります。

Java プロセスで truss (solaris) または strace (linux) を実行してから、ネットワーク プラグを抜いて、実際に何が起こっているのかを調べることをお勧めします。しかし正直なところ、NFS ファイル システムのロックは、私が Unix を使用している限り (今では 25 年以上) 人々が反対することを推奨してきました。誰が何をする」ということ。クライアントがサーバーに接続し、「X で開始」および「X を停止する」というメッセージをサーバーに送信し、クライアントが応答しない場合、サーバーが正常に接続をタイムアウトするようにします。たとえば、 5分。これは、NFS ロックを修正しようとするよりも時間がかからないことを 99% 確信しています。

于 2013-12-12T14:53:19.547 に答える
3

NFS サーバーの再起動後、アクティブなファイル ロックを持つすべてのクライアントは、いわゆる「猶予期間」 (単なる定数) を超えないロック再利用手順を開始します。猶予期間中に再利用手順が失敗した場合、NFS クライアント (通常はカーネル スペース ビースト) は、ロックを回復できなかったプロセスに SIGUSR1 を送信します。それがあなたの問題の根源です。

サーバー側でロックが成功すると、クライアント システムの rpc.lockd は別のデーモン rpc.statd に、ロックを実装する NFS サーバーを監視するように要求します。サーバーに障害が発生してから回復すると、rpc.statd に通知されます。次に、すべてのアクティブなロックを再確立しようとします。NFS サーバーが失敗して回復し、rpc.lockd がロックを再確立できない場合、ロックを要求したプロセスにシグナル (SIGUSR1) を送信します。

http://menehune.opt.wfu.edu/Kokua/More_SGI/007-2478-010/sgi_html/ch07.html

おそらく、これを回避する方法を知りたいと思うでしょう。いくつかの方法がありますが、理想的な方法はありません。

  1. 猶予期間を延長します。AFAIR、Linuxでは/proc/fs/nfsd/nfsv4leasetimeで変更できます。
  2. コードで SIGUSR1 ハンドラーを作成し、そこでスマートなことを行います。たとえば、シグナル ハンドラーで、ロックの回復が失敗したことを示すフラグを設定できます。このフラグが設定されている場合、プログラムは (必要な限り) NFS サーバーの準備が整うのを待ち、その後、ロック自体の回復を試みることができます。あまり実りがない…
  3. 二度と NFS ロックを使用しないでください。可能であれば、以前に提案されたように Zookeeper に切り替えます。
于 2013-12-17T22:40:53.300 に答える
1

この動作は、システム コール flock(2) およびシェル ユーティリティ flock(1) で再現できます。

Javaの外部で再現できるため、インフラストラクチャの問題のように聞こえます。NFS サーバーまたはクライアント OS に関する情報はあまり提供されていませんが、NFS で奇妙な動作を引き起こす原因の 1 つは、DNS 構成が正しくないことです。

クライアントの「uname -n」および「hostname」からの出力が DNS レコードと一致することを確認します。NFS サーバーが DNS を正しく解決していることを確認します。

Guntram と同様に、私もこの種の目的で NFS を使用しないことをお勧めします。Hazlecast (サーバーなし、インスタンスは動的にクラスター化) またはZooKeeper (サーバーのセットアップが必要) のいずれかを使用します。

Hazlecast を使用すると、これを実行してクラスター全体の排他ロックを取得できます。

import com.hazelcast.core.Hazelcast;
import java.util.concurrent.locks.Lock;

Lock lock = Hazelcast.getLock(myLockedObject);
lock.lock();
try {
    // do something here
} finally {
    lock.unlock();
} 

タイムアウトもサポートしています。

if (lock.tryLock (5000, TimeUnit.MILLISECONDS)) {
    try {  
       // do some stuff here..  
   } 
    finally {  
      lock.unlock();  
    }   
} 
于 2013-12-17T21:23:05.010 に答える