ダメプログラマの技術メモ

プログラミングの技術メモや駄文など

高負荷時に「java.net.NoRouteToHostException: 要求アドレスに割り当てられません」が発生した場合の対応方法

Javaで作成したWebAPIの負荷試験を行っている最中に次のようなExceptionが発生しました。

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
	at sun.reflect.GeneratedConstructorAccessor1475.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:408)
	at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1137)
	at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:356)
	at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2504)
	at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2541)
	at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2323)
	at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:832)
	at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:46)
	at sun.reflect.GeneratedConstructorAccessor1288.newInstance(Unknown Source)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:408)
	at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:417)
	at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:344)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:247)
	at core.dts.mysql.MysqlConnection.Open(MysqlConnection.java:120)
	at core.dts.mysql.MysqlConnection.Query(MysqlConnection.java:203)
	at core.dts.mysql.MysqlShard.Query(MysqlShard.java:174)
	at core.dts.mysql.MysqlShard.Query(MysqlShard.java:190)
	at core.mdl.record.Record.RecordRead(Record.java:186)
	at core.mdl.record.RecordManager.GetRecord(RecordManager.java:135)
	at app.mdl.record.usr.UserAccount.GetInstance(UserAccount.java:292)
	at app.ctrl.BaseAction.InitUserData(BaseAction.java:210)
	at app.ctrl.BaseAction._Execute(BaseAction.java:106)
	at core.ctrl.Action._OnExecute(Action.java:475)
	at core.ctrl.Action.Execute(Action.java:660)
	at core.Application.Execute(Application.java:370)
	at core.ctrl.Let.OnRequest(Let.java:66)
	at core.ctrl.Let.doPost(Let.java:32)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
	at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
	at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1517)
	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1474)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.NoRouteToHostException: 要求アドレスに割り当てられません
	at java.net.PlainSocketImpl.socketConnect(Native Method)
	at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:345)
	at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
	at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
	at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
	at java.net.Socket.connect(Socket.java:589)
	at java.net.Socket.connect(Socket.java:538)
	at java.net.Socket.<init>(Socket.java:434)
	at java.net.Socket.<init>(Socket.java:244)
	at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:258)
	at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:306)
	... 51 more

The last packet sent successfully to the server was 0 milliseconds ago.
java.net.NoRouteToHostException: 要求アドレスに割り当てられません

(´(ェ)`)・・・
(´(ェ)`)?

普通にアクセスする分には問題ないのですが、JMeterによる高負荷をかけると1分経過したぐらいからエラーが発生して、それ以降はDBアクセスができない状態になります。
しかし暫くするとまたDBアクセスできるようになる謎の現象に見舞われました。

MySQLにエラーログが出てないことから当初はTomcatJDBC周りを疑ったのですが、実はOS(CentOS 6.6)の問題でした。
どうやらローカルポートを食いつぶしているのが原因だったようです。

■ 参考サイト
ローカルポートを食いつぶしていた話

上記サイトを参考にしてOSの設定を弄ってみました。

/etc/sysctl.confの末尾に次の3行を追加します。

net.ipv4.ip_local_port_range = 32768 65000
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_fin_timeout = 10

sysctl.conf修正後は次のコマンドで設定を反映します。

sysctl -p

設定後はエラーが出なくなりました( ・´ー・`)b