さまざまな部屋で 100 ~ 500 人のユーザーを処理するチャット サーバーを作成したいと考えています。
イベントベースのアーキテクチャ (私にとって非常によく知られている) のため、Netty フレームワークを使用することにしました。私は、受信したすべてのものに対して「NYA」と応答する小さなサーバーから始めました。主要:
public class ChatServer{
public static void main(String[] args) throws Exception {
ExecutorService bossExec = new OrderedMemoryAwareThreadPoolExecutor(1, 400000000, 2000000000, 60, TimeUnit.SECONDS);
ExecutorService ioExec = new OrderedMemoryAwareThreadPoolExecutor(4 /* число рабочих потоков */, 400000000, 2000000000, 60, TimeUnit.SECONDS);
ChannelFactory factory = new NioServerSocketChannelFactory(bossExec,ioExec);
ServerBootstrap bootstrap = new ServerBootstrap(factory);
bootstrap.setPipelineFactory(new ChannelPipelineFactory(){
public ChannelPipeline getPipeline(){
return Channels.pipeline(new ChatChannelHandler());
}
});
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setOption("reuseAddress", true);
bootstrap.bind(new InetSocketAddress(5555));
System.out.println("ChatServer started at last...");
}
}
ハンドラ:
public class ChatChannelHandler extends SimpleChannelUpstreamHandler {
private final ChannelBuffer messageBuffer = ChannelBuffers.dynamicBuffer();
private boolean processingMessage = false;
private short messageLength;
@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Connection from: " + e.getChannel().getRemoteAddress().toString());
}
@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
e.getChannel().write(ChannelBuffers.copiedBuffer("NYA!", "UTF-8");
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
System.out.println("Exception: " + e.getCause());
Channel ch = e.getChannel();
ch.close();
}
}
N接続を作成し、1〜5秒の一時停止でサーバーにランダムに書き込むシミュレーションプログラムを使用します。次に、Flash ベースのクライアントに接続して、その動作を確認します。問題は、接続が 10 ~ 90 未満の場合、フラッシュ クライアントがサーバーからすぐに応答を受け取ることですが、シミュレートされた接続の数が 100 を超えると、フラッシュ クライアントがサイレントのままになることです。理由がわかりません。
100以上のクライアントからのすべてのメッセージがバッファに入ることがわかりましたが、 messageReceive イベントは単にそれらに対して発生しませんでした。イベント キューが登録されたイベントの制限に達したように見えます。
もっと単純なサーバーが 1 秒あたり 1k+ のリクエストを処理することについて読んだので、本当に悲しいです。
必要に応じて、Windows 7 で作業しています。また、サーバーが 2 ~ 3% 以上の CPU を使用することはありません。
私のシミュレーションジェネレーター:
public class ClientLoadEmulation implements Runnable {
private String host;
private int port;
private static final int minStringLength = 5;
private static final int maxStringLength = 40;
private static final int minPause = (int) (1 * 1000);
private static final int maxPause = (int) (5 * 1000);
Random rand = new Random();
public ClientLoadEmulation(String host, int port, int numThreads) {
this.host = "192.168.0.100";
this.port = 5555;
for (int i = 0; i < numThreads; ++i) {
new Thread(this).start();
try {
Thread.sleep(100);
} catch (Exception ex) {
}
}
}
@Override
public void run() {
byte buffer[] = new byte[255];
try {
Socket s = new Socket(host, port);
InputStream in = s.getInputStream();
OutputStream out = s.getOutputStream();
while (true) {
String govno = "";
...STRING GENERATION STUFF CUTTED...
ByteBuffer LENGTH_BUFFER = ByteBuffer.allocate(2);
LENGTH_BUFFER.putShort((short) govno.length());
LENGTH_BUFFER.flip();
out.write(LENGTH_BUFFER.array());
out.write(govno.getBytes("UTF-8"));
//System.out.println(Thread.currentThread() + " wrote " + govno);
int pause = minPause
+ (int) (rand.nextDouble() * (maxPause - minPause));
try {
Thread.sleep(pause);
} catch (InterruptedException ie) {
}
}
} catch (IOException ie) {
System.out.println("ERROR: " + ie.getMessage());
}
}
static public void main(String args[]) throws Exception {
new ClientLoadEmulation("127.0.0.1", 5555, 100);
}
}
(私の英語力でごめんなさい)