Home日記コラム書評HintsLinks自己紹介
 

フィンローダのあっぱれご意見番 第112回「のんびりサイト」

← 前のをみる | 「フィンローダのあっぱれご意見番」一覧 | 次のをみる →

Code Red とかいう worm が大流行したそうだが、 実際、 インターネット上であんなにたくさんIISが動いているということに驚いた。 世の中、豪傑が思ったより多い。 もっと驚いたのは、7月にあれだけ騒ぎになったのに、 再活動開始と予言されていた 8月1日になってもまだ対策していないIISが多数存在していたという現実である。

IIS: Windows 上で動作する http server。

私も一時IISを使っていたことがあった。 CGIをpc上でチェックしたい等の理由によるもので、 別に外部からのhttpリクエストを処理したいわけではない。 ちょっとしたツールを使うのにIISのようなhttpサーバが必要になることがあるのだ。 現在は Windows 2000上で必要な時には apache か tomcat を使っているから、 IISは全く使わなくなったのだが。

§

tomcatといえば、以前紹介したCG系サイトを集める Servlet ページが稼動している。 表向きはCG系サイトの移転チェックを行う検索ページという話だ。 表向きというか、事実そうなのだが。 アイデアは単純で、 公開されているページのURLを指定すると、 移転チェックサーブレットがそこをアクセスして、 そこがリンクしているサイトの一覧を作成する。 これを移転サイト情報と照らし合わして、 移転・閉鎖したり Not Found 状態になったリンクを指摘する、というものだ。

ポイントは、このページの副作用である。 当然、インターネットにある全サイトの情報を持てるわけないが、 実際、殆どのサイトに対する情報は不明という状況である。 副作用というのは、「このサイトはどうなのか分からない」という情報だ。 今まで、CG系のサイトを探す場合、こちらからリンクページをアクセスしていたのだが、 移転チェックページを公開することで、 結果的に、 既にリンクページを持っている人が新規サイトの情報を与えてくれるのである。 この情報を使って、「らんだむCGりんく」の候補を増やそうというのだ。

我ながらアイデアはよかったのだが、 想像力の欠如というか、読みが甘すぎた。 新規サイトが集まりすぎてしまうのだ。 与えられた情報に出てくるサイトが全てCG系だという保証はないし、 それこそ移転したものかどうか分からないのだから、 実際にアクセスして内容を確認しなければならない。 100サイトをチェックする間に未確認サイトが300サイト増えてしまう、 という感じである。 こうなると個人の趣味で何とかなる数を超えている。 インターネットの裾野が思った以上に広まっているのだろうか。

§

  

とにかく、この移転チェックサーブレットを公開するだけでは、 状況不明サイトが増え続けるので、 チェックしたサイトを、状況不明サイトのリストから削除する必要がある。 そのための管理用サーブレットも用意したが、こちらは非公開である。 しかし、移転チェックのサーブレットは公開されているため、 このリストにいつサイトが追加されるか分からない。 二つのサーブレットが一つのリストを奪い合うわけだ。 というわけで、 またまた出てくるのがロックの問題である。

 

※ そんなに大騒ぎするような話ではない。 Spring でも使えば何も考えずに排他処理はできる。

基本的な技としては、全く同じサーブレットで追加も削除も処理する手がある。 一つのファイルを操作するプログラムを一つにすることで、 ロックの問題は単純化できる。 ただ、今回のサーブレットは一般公開しているものだから、 管理者用のコマンドだけ認証機能を突っ込んで別扱いにするのがちょっと面倒だし、 セキュリティ上の不安が残る。

では、候補削除の処理を別のサーブレットで行うのはどうだろう。 単純に考えれば、ファイルを読む時点から更新する時点まで、 ずっとそのファイルをロックして占有し続ければ、面倒な問題は起こらない。 移転チェックサーブレットは、数秒程度、長くても十数秒で処理が完了するから、 その間ロックしていても実用上は問題ないのである。

問題は管理サーブレットだ。 このサーブレットは、 まず状況不明リストをファイルから読み込む。 その一覧を管理者がチェックし、一部を削除する。 この処理は、少なくとも数分、長ければ数時間かかることもある。 その後、一部削除した状態でリストを上書きするのだ。 一連の処理の間、ずっとロックし続けていたら、 移転チェックサーブレットがその間使えないことになる。 これはマズい。 実際は、移転チェックサーブレットは、リクエスト毎にリストを更新しなくてもいい。 サーブレット終了時に書き出せばいいのである。 ただ、サーバが正常終了する保証もないわけで、 現在の仕様では、状態不明サイトのリストは毎回保存するようにしている。

管理サーブレットがリストから候補を削除したことを、 移転チェックサーブレットはどうやって知るだろうか? List 1 が実際に使っているコードの一部である。

---- List 1 移転チェックサーブレットの一部 ----

    // 他のプログラムで更新された場合があるので、必要なら読み直しておく
    // unknown_list = searchTreeSet.reload();

    // (ここで検索を行う)

    searchTreeSet.update(); // 更新情報があればファイルを更新する

---- List 1 end ----

リクエスト毎にリストに対応しているファイルの更新時刻を確認すれば、 ファイルが更新されている時だけ再読み込みすることができる。 このリストには出てこないが、searchTSというクラスを定義してあって、 searchTreeSet というのはそのクラスに対応したオブジェクトである。 タイムスタンプを比較する処理は、 このクラスの reload() というメソッドに埋め込まれている。 reload() は、対応するファイルが前回読み込んだ時よりも新しくなければ、 何もせずにそのまま同じオブジェクトを返すようにしてあるのだ。

ところで、List 1 を見ると、reload() がコメントアウトされている。 どういうことかというと、状況不明サイトを確認する作業はそんなに頻繁に行わない。 タイムスタンプは滅多に変わらないのである。 仮に変わったとしても、不明サイトが減っただけではあまり意味がない。 ということで、reload() を呼び出すまでもないと判断したわけだ。 重要なのは、移転したサイトのリストに候補が追加された場合だが、 それには別の処理が必要になる。

§

問題は、管理サーブレットがリストを読み込んだ後、 移転チェックサーブレットがリストを更新した場合だ。 その後、管理サーブレットが手持ちの情報だけでリストを更新したら、 移転チェックサーブレットが追加した情報は消滅する。 これを防ぐために、例えば管理サーブレットの作業中、 ロックし続けるという手もある。 このアイデアは本質的に安全だが、 管理サーブレットが数十分も書き込みをロックするのは、いくら何でも面白くない。

そこで、管理サーブレットの内部処理では 削除したいサイトを別に用意した削除候補リストに追加するようにした。 ファイルを更新する時点で、初めてロックをかけるのだ。 ロックに成功したら、まず必要に応じて現状のリストを再度読み込む。 これで手持ちの情報も最新の状態になる。 これに対して削除候補のリストにあるサイトを削除し、 その結果をファイルに書き出してから、ロックを解除する。 これなら、ロックする時間は数秒程度なので、実用上問題ないはずだ。

実際は、 ファイルロックの処理は TreeSet を書き込むメソッドの中に埋め込んであるから、 メインのプログラムからは何も考えず save() を呼び出すだけで済む。 このメソッドは List 2 のようになっている。

  
---- List 2 ----

  // TreeSet の書き込み
  public boolean save() {
    boolean result = true;

    lock();
    long lm = getLastModified(); // 一応 lock 後に…

    synchronized (ts) { // 他スレッドの更新を避けるために必要?
      if (lm != last_modified) {
        // もう一度読み直す
        load_without_lock();
      }

      updateTreeSet(); // 状態更新

      FileOutputStream fos = null;
      ObjectOutputStream oos = null;
      try {
        fos = new FileOutputStream(filename);
        oos = new ObjectOutputStream(fos);
        oos.writeObject(ts);
        result = false;
      } catch (IOException ioe) {
        System.out.println("saveUnknownList failed");
      } finally {
        IOUtils.closeQuietly(fos);
        IOUtils.closeQuietly(oos); // 前行が成功していたら多分無駄
      }
    }

    last_modified = getLastModified();

    unlock();

    return result;
  }

---- List 2 end ----
 

※ 最初のコードはひどかったので、ちょっとこっそり直した。

updateTreeSet() というメソッドが、 それまでに追加・削除するために蓄えていた情報を使って、 本体のリストの状態を更新する処理である。 ts は、そのリストの実体となる TreeSet である。 synchronized を指定してあるが、 ts を static で定義すればサーブレット全体で実体が一つになるから、 移転チェックサーブレット内でスレッドセーフにできると思ったらしいのだが、 よく考えてみればファイルロックしているのだから意味ないのか。

§

  

もしこれが本格的なサービスだったら、 何秒もロックし続けるというだけでも、とんでもないことかもしれない。 たまに誰かアクセスする程度の趣味の個人サイトだから許されるのだ。 それに、このサイト、 このご時世に64kbpsという低速で繋がっている。 アクセスが集中するとしても、たかが知れているのである。 Code Redが大流行している背景には、ブロードバンド化の影響があるといわれている。 サイトアタックも高速化しているのだ。 のんびりしたサイトにも、多少はメリットがあるのかもしれない。

 

※ フレッツ ISDN で接続してあった。

(C MAGAZINE 2001年10月号掲載)
内容は雑誌に掲載されたものと異なることがあります。

修正情報:
2006-03-03 裏ページに転載。

(C) Phinloda 2001-2006, All rights reserved.