mysql의 jdbc driver url의 connectTimeout과 socketTimeout에 대한 개념을 정리한다.
이 개념은 굳이 mysql driver뿐 아니라 http 나 간단한 소켓 프로그래밍에 대해서도 적용될 수 있다.
1) Socket Timeout
socketTimeout은 클라이언트(웹 서버)에서 mysql 서버에 대한 Connection에 대해서 데이터를 받는 것 까지의 timeout을 의미한다.
즉, client->server까지는 포함하지 않고, server->client 까지의 timeout을 의미한다고 봐야한다. 내가 마지막으로 받을 것으로 기대하고 대기하고 있는 timeout이라고 하면 된다. 소켓이 올 때까지 라는 의미는 Blocking socket operation이라는 전제가 깔려 있다는 의미이다..
다음의 메소드들처럼 blocking method가 있다는 것.
* ServerSocket.accept();
* SocketInputStream.read();
* DatagramSocket.receive();
timeout시 socket은 끊어지지 않고 사용가능합니다. 단순히 java.io.InterruptedIOException만 발생합니다.
/**
* Constructor: Connect to the MySQL server and setup a stream connection.
*
* @param host the hostname to connect to
* @param port the port number that the server is listening on
* @param props the Properties from DriverManager.getConnection()
* @param socketFactoryClassName the socket factory to use
* @param conn the Connection that is creating us
* @param socketTimeout the timeout to set for the socket (0 means no
* timeout)
*
* @throws IOException if an IOException occurs during connect.
* @throws SQLException if a database access error occurs.
*/
public MysqlIO(String host, int port, Properties props,
String socketFactoryClassName, MySQLConnection conn,
int socketTimeout, int useBufferRowSizeThreshold) throws IOException, SQLException {
this.connection = conn;
if (this.connection.getEnablePacketDebug()) {
this.packetDebugRingBuffer = new LinkedList();
}
this.traceProtocol = this.connection.getTraceProtocol();
this.useAutoSlowLog = this.connection.getAutoSlowLog();
this.useBufferRowSizeThreshold = useBufferRowSizeThreshold;
this.useDirectRowUnpack = this.connection.getUseDirectRowUnpack();
this.logSlowQueries = this.connection.getLogSlowQueries();
this.reusablePacket = new Buffer(INITIAL_PACKET_SIZE);
this.sendPacket = new Buffer(INITIAL_PACKET_SIZE);
this.port = port;
this.host = host;
this.socketFactoryClassName = socketFactoryClassName;
this.socketFactory = createSocketFactory();
this.exceptionInterceptor = this.connection.getExceptionInterceptor();
try {
this.mysqlConnection = this.socketFactory.connect(this.host,
this.port, props);
if (socketTimeout != 0) {
try {
this.mysqlConnection.setSoTimeout(socketTimeout);
} catch (Exception ex) {
/* Ignore if the platform does not support it */
}
}
this.mysqlConnection = this.socketFactory.beforeHandshake();
if (this.connection.getUseReadAheadInput()) {
this.mysqlInput = new ReadAheadInputStream(this.mysqlConnection.getInputStream(), 16384,
this.connection.getTraceProtocol(),
this.connection.getLog());
} else if (this.connection.useUnbufferedInput()) {
this.mysqlInput = this.mysqlConnection.getInputStream();
} else {
this.mysqlInput = new BufferedInputStream(this.mysqlConnection.getInputStream(),
16384);
}
this.mysqlOutput = new BufferedOutputStream(this.mysqlConnection.getOutputStream(),
16384);
this.isInteractiveClient = this.connection.getInteractiveClient();
this.profileSql = this.connection.getProfileSql();
this.autoGenerateTestcaseScript = this.connection.getAutoGenerateTestcaseScript();
this.needToGrabQueryFromPacket = (this.profileSql ||
this.logSlowQueries ||
this.autoGenerateTestcaseScript);
if (this.connection.getUseNanosForElapsedTime()
&& Util.nanoTimeAvailable()) {
this.useNanosForElapsedTime = true;
this.queryTimingUnits = Messages.getString("Nanoseconds");
} else {
this.queryTimingUnits = Messages.getString("Milliseconds");
}
if (this.connection.getLogSlowQueries()) {
calculateSlowQueryThreshold();
}
} catch (IOException ioEx) {
throw SQLError.createCommunicationsException(this.connection, 0, 0, ioEx, getExceptionInterceptor());
}
}
내부적으로는 Socket 클래스의 setSoTimeout 을 호출합니다.
void |
setSoTimeout(int timeout) |
내부적으로 ReadAheadInputStream 클래스 에서 read하는 작업이 들어가 있다.
보통 중간에 문제가 되면, read하다가 IOException이 나게 된다. 여기서 Socket timeout을 잘 주면 좋을 것이다.
그러나 Query Timeout(statement 단에서 지정)보다 적게 주면 문제가 되니. 항상 query timeout보다 socket timeout이 길어야 한다.
2. connect timeout
connectTimout은 connect 메소드를 호출했을 때의 connection timeout을 의미한다.
connection 이 TCP/UDP 연결이 완료(established)될 까지의 timeout이다. 즉 connect(최초 또는 retry)할 때. client->server->client 까지 되돌아오는 시간을 의미한다.
내부적으로 Socket 클래스의 connect 메소드를 호출한다.
void |
connect(SocketAddress endpoint, int timeout) |
3. 운영
운영할 때는 너무 길게 주지 않고, 적당히 주고 있다.. DOS에 잘 방어하면서도.. 그것때문에 side effect는 적게.하는 정책을 두고 있다.
jdgc:mysql://alpha.google.com/server?useUnicode=true&characterEncoding=euckr&connectTimeout=5000&socketTimeout=5000
'java core' 카테고리의 다른 글
jdk(java) 7 update 1 버그 (0) | 2011.11.08 |
---|---|
자바(java)와 리눅스(linux)의 zero copy 기법 (0) | 2011.09.09 |
How to start and shutdown (or stop) RMI Server (1) | 2011.09.02 |
concurrency bug patterns for multicore systems 중요내용 내 맘 요약 (0) | 2011.08.04 |
jdk7 loop predicate 버그 관련 내용 (0) | 2011.08.02 |