Nettyシリーズ第二章NIO 1.1擬似非同期I/O
34638 ワード
NIO入門
擬似非同期I/O
1.擬似非同期I/Oの誕生と定義まず擬似非同期I/Oは、BIOのクライアントがサービス側のスレッド処理を行う問題を解決するために誕生した.擬似非同期I/Oはスレッドプールとタスクキューによって実現され、どれだけのクライアントがあっても、スレッドプールは柔軟にスレッドリソースを配置することができ、スレッドの最大値を設定し、大量の同時アクセスによるスレッドの消耗を防止し、新しいクライアントアクセスがある場合、クライアントのsocketをTask(Runnableインタフェースを実装するタスク)にカプセル化してバックエンドのスレッドプールに送信します.擬似非同期I/O作成TimeServerソース
ここで、クライアント処理コードはスレッドプールによって完了する、要求socketをtaskにカプセル化し、スレッドプールexecuteメソッドを呼び出して実行し、各要求に新しいスレッド3を作成することを回避する.擬似非同期I/Oによって作成されたTimeServerHandlerExecutePoolソース擬似非同期I/O作成TimtServerHandlerソース 擬似非同期I/O作成TimeClientソース
擬似非同期I/Oの利点:スレッドプールとメッセージキューは境界があるため、クライアントの同時接続数がどれだけ大きいかにかかわらず、スレッド個数の膨張やメモリオーバーフロー を招くことはない.
擬似非同期I/Oの欠点:擬似非同期下位層は依然として同期ブロックモデル である. Socket入力ストリームの読み取り時に、データが読めるまでブロックされ、利用可能なデータの読み取りが完了し、空のポインタ異常またはI/O異常が発生する .相手方の送信要求又は応答メッセージが比較的遅い又はネットワーク遅延した場合、読み出し入力ストリームの乙方の通信スレッドも長時間にわたって閉塞され、データの送信が60 sで完了すると、読み出し側のスレッドも同期して60 s閉塞され、他のアクセスメッセージは閉塞キューに しか並ぶことができない. OutputStreamのwriteメソッドを呼び出して出力ストリームを書き込むと、送信するバイトがすべて書き込まれるまで、または異常が発生するまで、メッセージ受信者の処理が遅い場合、同期ブロックI/Oはwriteメソッドが無期限にブロックされる を引き起こす.
擬似非同期I/Oは、相手の応答時間が長すぎるため、カスケード障害を引き起こす可能性があります.サービス側も応答時間 を延長する.擬似非同期I/Oを用いるスレッドは、読み出し入力ストリームがブロックするため、同期ブロック によって障害サービスノードの応答を読み出す.すべての利用可能なスレッドが障害サーバによってブロックされた場合、その後のすべてのI/Oメッセージは、 のキューに並ぶ.スレッドプールがブロッキングキューを採用することにより、キューがいっぱいになると、後続のキューに入る動作が ブロックされる.新しいクライアント要求は拒否され、タイムアウト接続 が発生する.すべての接続がすべてタイムアウトした場合、システムがクラッシュしたとみなすことができ、新しい要求メッセージ を受け入れることができない.
擬似非同期I/O
1.擬似非同期I/Oの誕生と定義まず擬似非同期I/Oは、BIOのクライアントがサービス側のスレッド処理を行う問題を解決するために誕生した.擬似非同期I/Oはスレッドプールとタスクキューによって実現され、どれだけのクライアントがあっても、スレッドプールは柔軟にスレッドリソースを配置することができ、スレッドの最大値を設定し、大量の同時アクセスによるスレッドの消耗を防止し、新しいクライアントアクセスがある場合、クライアントのsocketをTask(Runnableインタフェースを実装するタスク)にカプセル化してバックエンドのスレッドプールに送信します.
package com.carfi.netty.fakeio;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
1. @author: ll
2. @time: 2020/6/14 23:15
*/
public class TimeServer {
public static void main(String[] args) throws IOException {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
}
}
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
System.out.println("Thr rime server is start in port : " + port);
Socket socket = null;
//
TimeServerHandlerExecutePool timeServerHandlerExecutePool = new TimeServerHandlerExecutePool(50, 10000);
while (true) {
socket = serverSocket.accept();
//
timeServerHandlerExecutePool.execute(new TimtServerHandler(socket));
}
} finally {
if (serverSocket != null) {
System.out.println("The time server close");
serverSocket.close();
serverSocket = null;
}
}
}
}
ここで、クライアント処理コードはスレッドプールによって完了する、要求socketをtaskにカプセル化し、スレッドプールexecuteメソッドを呼び出して実行し、各要求に新しいスレッド3を作成することを回避する.擬似非同期I/Oによって作成されたTimeServerHandlerExecutePoolソース
package com.carfi.netty.fakeio;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
*
* @author: ll
* @time: 2020/6/14 23:20
*/
public class TimeServerHandlerExecutePool {
private ExecutorService executorService;
/**
*
* @param maxPollSize
* @param queueSize
*/
public TimeServerHandlerExecutePool(int maxPollSize, int queueSize) {
/**
* Runtime.getRuntime().availableProcessors()
* maxPollSize
* 120L corePoolSize
* TimeUnit.SECONDS
* new ArrayBlockingQueue(queueSize) , corePoolSize , ,
* , > ( workQueue ),
*/
executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),
maxPollSize, 120L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize));
}
public void execute(Runnable task) {
executorService.execute(task);
}
public static void main(String[] args) {
System.out.println(Runtime.getRuntime().availableProcessors());
}
}
package com.carfi.netty.fakeio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Date;
/**
* @author: ll
* @time: 2020/6/11 22:56
*/
public class TimtServerHandler implements Runnable {
private Socket socket;
public TimtServerHandler() {
}
public TimtServerHandler(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader in = null;
PrintWriter out = null;
try {
in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
out = new PrintWriter(this.socket.getOutputStream(), true);
String currentTime = null;
String body = null;
while (true) {
body = in.readLine();
if (body == null) {
break;
}
System.out.println("The time server receive order : " + body);
currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";
out.println(currentTime);
}
} catch (Exception e) {
if (in != null) {
try {
in.close();
} catch (IOException ex) {
ex.printStackTrace();
}
in = null;
}
if (out != null) {
out.close();
out = null;
}
if (this.socket != null) {
try {
this.socket.close();
} catch (IOException ex) {
ex.printStackTrace();
}
this.socket = null;
}
}
}
}
package com.carfi.netty.fakeio;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
/**
* @author: ll
* @time: 2020/6/11 23:26
*/
public class TimeClient {
public static void main(String[] args) {
int port = 8080;
if (args != null && args.length > 0) {
try {
port = Integer.valueOf(args[0]);
} catch (NumberFormatException e) {
//
}
}
Socket socket = null;
BufferedReader in = null;
PrintWriter out = null;
try {
socket = new Socket("127.0.0.1", port);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
out.println("QUERY TIME ORDER");
System.out.println("Send order 2 server succedd.");
String resp = in.readLine();
System.out.println("Now is : " + resp);
} catch (IOException e) {
//
} finally {
if (out != null) {
out.close();
out = null;
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
in = null;
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
socket = null;
}
}
}
}
擬似非同期I/Oの利点:
擬似非同期I/Oの欠点:
擬似非同期I/Oは、相手の応答時間が長すぎるため、カスケード障害を引き起こす可能性があります.