- PR -

Socket アクセス集中による処理の遅延

投稿者投稿内容
葉月要
会議室デビュー日: 2006/06/02
投稿数: 11
投稿日時: 2006-06-06 19:02
お世話になります

現在SocketChannel を用いて、データを配信するサービスを構築しているのですが
アクセスが集中すると処理が追いつかず、後続が詰まってしまうほか、
too many files open という Socket を開きすぎというエラーが出てしまいます
一応ソケット接続数50と限定はしているのですが、それをオーバーしてしまいます。
ソケットを使い終えたサービスはきちんと socket#close() ほかshutdownInput()、shutdownOutpu() も実行し、ソケットリークを行っているつもりです

とりあえず、現状で行いたいことは、短時間でアクセスが集中しても
なるべくディレイなく、応答を返し、なおかつエラーが起きないようなプログラムにしたいのです。

どうぞご教授願えますか?


while(true){
try {
//一応ここで50を越えている場合は新しい接続を受け付けない
//しかし50になる前に too many files open のエラーが出る、且後続の処理が間に合わずに詰まってしまいます
if(!acw.isActive()){
continue;
}
SocketChannel socketChannel = serverSocketChannel.accept();
/**
* 接続があった場合、新しいスレッドの起動+配信開始
*/
HorrorConnect relay=new HorrorConnect(socketChannel,acw);
relay.init();
relay.start();
//スレッドがある程度起動するまで待つ
if(!relay.getNextConnect()){

}
} catch (IOException ex) {
System.out.println("メインクラスでエラーが起きました");
System.out.println(ex.getMessage());
return;
}
}
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2006-06-06 20:01
Too many open files については、そのプロセスを起動する前に「ulimit -n 100」とか「limit openfiles 100」とかでしょうか。

「短時間でアクセスが集中してもなるべくディレイなく、応答を返し」というのは、1アクセスあたりの処理時間を短くするようにチューニングするしかないですよね。チューニングしても、さらに多くのアクセスがあれば遅くなるでしょうから、無理な相談です。そのプロトコルに「混雑してるから後で接続してね」というリプライが定義されていればそれを使いましょう。

ついでですが、「ソケットリーク」ってどういう意味で使ってますか?
葉月要
会議室デビュー日: 2006/06/02
投稿数: 11
投稿日時: 2006-06-06 20:07
ご返答有難うございます

>Too many open files については、そのプロセスを起動する前に「ulimit -n 100」とか
>「limit openfiles 100」とかでしょうか。
有難うございます参考にしてみます

>ソケットリーク
急いでいたので適当な言葉になってしまいました。どう見ても間違っています。リリースのほうですね・・
Socketをきちんとクローズしていますということです

後付けとなってしまいますが
この接続処理がちょっと面倒で

1. ソケットオープン
2. クライアントがHTTPDリクエストメッセージを送信
3. サーバーがHTTPDレスポンスメッセージを送信
4.なぜかここで一度ソケットクローズ(仕様)
5. 再度ソケットオープン
6.データ通信開始

となっています。
込み合っているときに後で接続してね
と出すことは簡単なんですが、それをやってしまうと、何時までも接続できないという状態になってしまうのです。
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2006-06-07 10:28
葉月要さん、こんにちは。

この接続処理は、待ち受けソケット(ServerSocket)と通信用の
ソケット(acceptされたソケット)の役割は、明確になってい
るのでしょうか?

引用:

1. ソケットオープン
2. クライアントがHTTPDリクエストメッセージを送信
3. サーバーがHTTPDレスポンスメッセージを送信
4.なぜかここで一度ソケットクローズ(仕様)
5. 再度ソケットオープン
6.データ通信開始


は通常の HTTPとはちがいますが、
そういう特殊(変)な仕様が指定されているのか、
あるいは(失礼ながら)葉月要さんの理解が
誤っている要に思えるのですが…。
Gio
ぬし
会議室デビュー日: 2003/11/28
投稿数: 350
お住まい・勤務地: 都内から横浜の間に少量発生中
投稿日時: 2006-06-07 10:49
引用:

葉月要さんの書き込み (2006-06-06 20:07) より:

4.なぜかここで一度ソケットクローズ(仕様)



この仕様が悪さしていませんか?

TCP ソケットをクローズするとしばらくタイムアウト状態になり、その直後にサーバソケットが accept してもそのソケットはアロケートされなくなります。
現在の仕様では、直後のソケットオープンにも失敗し、最初の 50 コネクションを accept した段階であとのコネクションがすべて拒否されている可能性すら考えられます。

クローズする意味はわかりませんが、Kissinger さんが書かれたとおり通常の HTTP シーケンスにする方法を、私からもお勧めいたします。

HTTP でない一般の通信であればソケットに対して Socket#setReuseAddress(true) する方法もありますが、これはソケットが bind される前に実行する必要があります。
つまり、SocketChannel をベースとする現在の方法から Socket を直接操作する方法への大幅な書き換えが必要です。
葉月要
会議室デビュー日: 2006/06/02
投稿数: 11
投稿日時: 2006-06-07 10:52
Kissingerさん
ご返答ありがとうございます

確かに明確には分かっておりません
推測で作っていますので・・・

えーと、今やっているのは Windows Media Encoderのデータをそのまま
リレーするプログラムを作成しております

もう少し明確に言いますと
1.ソケットオープン
  普通にaccept
1.クライアントから ストリームデータにアクセスするための
   GET / HTTP/1.0
   Accept: */*
   User-Agent: ・・・・

というリクエストメッセージが サーバーに向けて発信されます

2.サーバーが現在の状況に合わせて
   a. レスポンスメッセージを送信
   b. もしサーバー状態がビジー(503)を送信していなければデータヘッダーを送信

この後に挙動を見ていると
クライアント(Windows Media Player側)から通信終了のメッセージが送信されます
これが 3.なぜかここで一度ソケットクローズ

この直後にまたアクセスがあり、新たなソケットがAcceptされた時点で
Windows Media Encoderが吐き出したデータを送信します
という風になっております

個人的にもなんか変だなぁ?と思うのですが・・・
Kissinger
ぬし
会議室デビュー日: 2002/04/30
投稿数: 428
お住まい・勤務地: 愛知県
投稿日時: 2006-06-07 12:58
そういうことですか。

一度切断するのには理由があると思います。

たとえば(憶測ですが)、リクエストを受け付けるサー
バとコンテンツを配信するサーバを分離可能にするとか。

通常の Web/HTTPサーバだと、クライアントに気づかれな
いようにロードバランサが調整してくれたりしますが、
HTTPを流用したサービスではオリジナルの設計に由来し
ているのかも知れませんね。
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2006-06-07 14:55
クライアントはHTTP/1.0でサーバにアクセスしているようですが、
HTTP/1.0 ではTCPコネクションの再利用(永続的接続)はデフォルトではありませんから、
もしクライアントのリクエストヘッダに「Connection: keep-alive」が含まれていなければ、
通常はサーバ側がレスポンス送信完了後にTCPコネクションを切断すると思います。

これが原因ではないでしょうか?

参考:
インターネット興隆の立役者「HTTP〜後編」
[Studying HTTP] Persistent Connections
[Studying HTTP] HTTP Header Fields

スキルアップ/キャリアアップ(JOB@IT)