{"componentChunkName":"component---src-templates-post-template-jsx","path":"/works/posts/2022-12-09--001","result":{"data":{"site":{"siteMetadata":{"title":"Blog by Eunyoung","subtitle":"작업 기록 블로그","copyright":"© All rights reserved.","author":{"name":"EunYoung","twitter":"#"},"disqusShortname":"","url":"https://ssongey.github.io"}},"markdownRemark":{"id":"d606e371-7c41-59f1-b177-5c85985f9034","html":"<p>현재글)</p>\n<ul>\n<li><strong>Unable to acquire JDBC Connection 에러 오답노트1</strong></li>\n</ul>\n<p>다음글)</p>\n<ul>\n<li><a href=\"https://ssongey.github.io/devHistoryBlog/works/posts/2022-12-09--002\">Unable to acquire JDBC Connection<strong>(DHCP lease lost)</strong> 에러 오답노트2</a></li>\n</ul>\n<br/>\n<br/>\n<p>내가 담당하고 있는 서비스에서 간헐적으로 DB Connection이 끊기는 현상이 발생했다.<br>\n처음에는 단순히 DB Connection Pool 의 개수가 모자른가? 라고 생각했었지만, 생각치도 못했던 여러 문제를 접하였고, 그에 대한 오답노트를 적어보려고 한다.  </p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">📢 환경\n- Ubuntu 18.04.5 LTS\n- SpringBoot 2.5.12\n- MySQL 5.7.28</code></pre></div>\n<hr>\n<h2>✔️ 1. 문제 확인</h2>\n<p>DB에서 데이터를 꺼내기 위해 커넥션을 사용하려고 하는데, 설정된 timeout 시간까지 커넥션 풀에서 사용 가능한 커넥션을 못찾아 에러가 발생하였다.\nstack trace 를 보면 아래와 같다.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">DataAccessResourceFailureException\n\nUnable to acquire JDBC Connection; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection\n\n\nJDBCConnectionException\n\nUnable to acquire JDBC Connection\n\n\nSQLTransientConnectionException\n\nHikariPool-1 - Connection is not available, request timed out after 15016ms.\n\n\nSQLNonTransientConnectionException\n\nNo operations allowed after connection closed.\n\n...</code></pre></div>\n<br/>\n<br/>\n<p>처음 저 에러를 접했을때, 오잉? <strong>Connection Pool Size 가 작은가??</strong> 해당 서버에 요청이 많아졌나..?? 라고 생각했고, 단순하게 Pool Size만 늘리는 조치를 취했지만… 해당 에러는 계속 발생했다.  </p>\n<br>\n<p>그래서 열심히 구글에 검색을 해보니, 아래와 같은 키워드를 발견하였다.</p>\n<h3><strong>✔️ MySQL - wait_time</strong></h3>\n<ul>\n<li>jdbc, odbc, php 등을 통한 커넥션 중 요청이 없는 커넥션(non-interactive 세션) 의 최대 수명시간</li>\n<li>기본값은 28800s (8시간) 이다.</li>\n</ul>\n<h3><strong>✔️ Hikari - max-lifetime</strong></h3>\n<ul>\n<li>커넥션 풀에서 사용하지 않은 커넥션의 최대 수명시간</li>\n<li>사용 후 반환 됐을때부터 wait 시간을 측정하게 된다.</li>\n<li>풀 전체가 아닌 커넥션 별로 적용이 되는 이유는 풀에서 한번에 많은 커넥션들이 제거되는 것을 방지하기 위함이라고 한다.</li>\n<li>0으로 설정하면 infinite lifetime이 적용된다.</li>\n<li>기본값은 1800000ms (30분) 이다.</li>\n</ul>\n<br/>\n<p>만약, <strong>wait_time &#x3C; max-lifetime</strong> 일 경우 커넥션 풀에 존재하는 모든 커넥션이 <strong>유효한 커넥션이 아닐 수도 있게된다</strong>.<br>\n왜냐면, wait_time 시간이 지난 커넥션들은 <strong>DB서버에서 먼저 연결을 끊기 때문</strong>이다.<br>\n때문에 풀은 이걸 모르고 계속 가지고 있다가 어플리케이션에서 요청하면 유효하지 않은 커넥션을 계속 주게 될 수도 있다는거다.</p>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/098c1/001-01.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 960px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 106.25%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAYAAABG1c6oAAAACXBIWXMAABYlAAAWJQFJUiTwAAABwklEQVQ4y6WU607CQBCFfW0VfRp+kBD+Eokx0WiMLwAJpCLQlt7pDWih7R5nFjRAAGndZLPJ7ubszJxv5woHQwgh1zzPYds21MkEvj+T+2Ln/HD9GVenBJMkged5ME0LtjtDQQ/wKIoccRwfFftTMI4jGKYJL1ogTDK5ryifaDQaMAxj+0BxmWCapgiCAJOJCieI4S3WCGj/4eUdtzfX6Ha75QXDMMRoPIbpzxGmOVZ01KcIO50OXNctV8PlcilN8X0fYRRtayiO3r1IkNfVaiWFsyzbc5nTLO0yY8NpaaqKkGopBcU/sXEdB5o+3cNGiEJGXQGbVPJmEjYuYRMQNuwnm1Kv18tjwxGyy5quwyZsfMImJhQfn19xV6tVw4Y5HI9GiBwb85mH0DKhDvpot9vVsLEsCw7VkVNnfDRNQ7KtX+kaciqMy+5cr9fIyJxK2PD6YwrX89y9i1PWKcXhcIipYe50m+L3gdLdJqIvp0+nsIINNiw5/PpCs9mU37I02CzI0dnbbrOg/ae3D9zf1dDr9apxqBOHi/kcebbph4N+H61WS9a2UrdRFOX3V4gTdy8SZEzYZU6beeQHeHLk57D5BnldZRwCaMR0AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"001 01\"\n        title=\"\"\n        src=\"/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/d9199/001-01.png\"\n        srcset=\"/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/8ff5a/001-01.png 240w,\n/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/e85cb/001-01.png 480w,\n/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/d9199/001-01.png 960w,\n/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/07a9c/001-01.png 1440w,\n/devHistoryBlog/static/1f1bddb41e04d59da99d449fa7d5bf7e/098c1/001-01.png 1578w\"\n        sizes=\"(max-width: 960px) 100vw, 960px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>\n<hr>\n<br/>\n<h2>✔️ 2. 문제를 확인 했으니, 조치를 해보자</h2>\n<h3>1. 각 설정값 확인</h3>\n<p>MySQL의 wait_timeout 을 확인해보니 <strong>기본값인 8시간</strong>이다.</p>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">show</span> <span class=\"token keyword\">global</span> variables <span class=\"token operator\">like</span> <span class=\"token string\">'wait_timeout'</span><span class=\"token punctuation\">;</span></code></pre></div>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/devHistoryBlog/static/e834e19eebd2da39b46dc59b0b91ead3/f213e/001-02.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 960px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 31.25%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAAA8ElEQVQY04WRu4qEQBBFfYIgKqggGpiZGIqfYOALERVN/ALBP1dBI8Xg7lbD7M4ws2zD7VtUFae6KQ7f57ouTNOEJEmQpinKskRRFMwpV1UVE9VIeZ4jyzLWQ3nyfd8JBY6u8zwRhiE4joMsyxBFkbkgCCwmp9pfop51XV+BURRBVVU4jgPTNGFZFjRNg23bMAwDkiSB53kGJz1iAuq6/g6M45gBCea6LmtSFAW+78PzvJ+XP4uGEJAGbtv2CgyC4ONX/vvuQ8uy/ALv+8Y8z6jrGl3XMfV9j3EcMQwDmqZhS6BlPIuWQUtq2xbHcTDgFzen4UnQvlPQAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"001 02\"\n        title=\"\"\n        src=\"/devHistoryBlog/static/e834e19eebd2da39b46dc59b0b91ead3/d9199/001-02.png\"\n        srcset=\"/devHistoryBlog/static/e834e19eebd2da39b46dc59b0b91ead3/8ff5a/001-02.png 240w,\n/devHistoryBlog/static/e834e19eebd2da39b46dc59b0b91ead3/e85cb/001-02.png 480w,\n/devHistoryBlog/static/e834e19eebd2da39b46dc59b0b91ead3/d9199/001-02.png 960w,\n/devHistoryBlog/static/e834e19eebd2da39b46dc59b0b91ead3/f213e/001-02.png 1192w\"\n        sizes=\"(max-width: 960px) 100vw, 960px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>\n<br/>\n<p>오잉??<br>\napplication.yaml 파일에도 max-lifetime을 설정하지 않았는데.. 그럼 <strong>기본값이니 30분일 텐데</strong>.. 충분히 작은데..?<br>\n그럼 max-lifetime을 10분으로 설정해서 max-lifetime에 새로 연결을 맺는지 한번 확인해보자.</p>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/891d5/001-03.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 960px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 39.166666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAABYlAAAWJQFJUiTwAAABfElEQVQoz3WSzW7aQBSF8xgVQg0EYxxmxsY2DuanRjEuKnThn5JWfQPeCAUWlbrohrcDlsDXMVVTtQ0jHd0Zaea75+jOzfF4pFw/vn9j7Fl8HAeMwgDX9fC86/J9HyEEaZqy3+8vjPP5zM1v4OZ5hai/IXJNfGkiWw2UZWAYBo1G4z81m02q1SpxHLPb7S6M0+n0B/i83mA175j0Hd6HirinGHQdpFIIKZH/yLZtTNNkPp+/DtxsNry9rdHzbCYPgnGgUEo/Fm1sKVA6ntJV6iqkujQq3c9ms2sO19RrtcvlgSd4DASx1sgXuoEkdAVRV9L3FF74Dsf1MXT0q8C1Bt7V6zqKw8CXTHTk0mWkVZ5LWPLQJvLv6XRcwniGdAMN/PAylL+Aq9WKSqWC2bIYOiajjknfNhnq+uiXg2rR6fYIogQ7GGLdt7nViZIked3hdrtlOp2S5zlPRcoi/6Vy/+VTRpFnZMWC4vNXisUTWZYy13GXyyWHw+Hl2/wER2xo6rOHf6oAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"001 03\"\n        title=\"\"\n        src=\"/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/d9199/001-03.png\"\n        srcset=\"/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/8ff5a/001-03.png 240w,\n/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/e85cb/001-03.png 480w,\n/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/d9199/001-03.png 960w,\n/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/07a9c/001-03.png 1440w,\n/devHistoryBlog/static/f446da8155c52e665344adbf5b71522d/891d5/001-03.png 1520w\"\n        sizes=\"(max-width: 960px) 100vw, 960px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>\n<br/>\n<h3>2. 설정 내용 실제 동작 확인</h3>\n<p>참고) Hikari Pool 로그를 보기 위해 logback-spring.xml 를 아래와 같이 설정해야 한다. (logback 기준)</p>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/a878e/001-04.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 960px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 10.416666666666668%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAYAAABYBvyLAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAgUlEQVQI11WKTQrCMBSEe54uNH9GEitu3FbwvYBdiUXwCNZbFOp16j63Gl+zEFx8fDPMVO9pRH+94NEvdLjfOnBiEJ1BTGL6OaX0lxeYWSC0pxY5Z1TD6wlrNfbR4HhwaHYBG++g7RrGKbEqNvIJIZSujSo5xgi/9bJr1Ksa82fGFxYqTIaf0hNEAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"001 04\"\n        title=\"\"\n        src=\"/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/d9199/001-04.png\"\n        srcset=\"/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/8ff5a/001-04.png 240w,\n/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/e85cb/001-04.png 480w,\n/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/d9199/001-04.png 960w,\n/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/07a9c/001-04.png 1440w,\n/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/29114/001-04.png 1920w,\n/devHistoryBlog/static/d5938c8cd4d2f167a99b7fc19fca64d9/a878e/001-04.png 2048w\"\n        sizes=\"(max-width: 960px) 100vw, 960px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>\n<h4>커넥션 max-lifetime 로그 확인</h4>\n<ul>\n<li><strong>23:55분</strong>에 <code class=\"language-text\">connection adder</code> 스레드로 <strong>커넥션이 풀에 추가</strong>가 되었고, <strong>00:05분</strong>에(10분 후) 해당 커넥션을 사용하지 않아 <code class=\"language-text\">connection closer</code> 스레드로 <strong>Closing</strong> 되었다.</li>\n<li>그리고 바로 새로운 커넥션이 추가된 것을 볼 수 있다.</li>\n<li><strong>즉, 이건 아주 잘 작동이 되고 있다…</strong></li>\n</ul>\n<p>\n  <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/9b1e2/001-05.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n  \n  <span\n    class=\"gatsby-resp-image-wrapper\"\n    style=\"position: relative; display: block;  max-width: 960px; margin-left: auto; margin-right: auto;\"\n  >\n    <span\n      class=\"gatsby-resp-image-background-image\"\n      style=\"padding-bottom: 31.666666666666664%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAs0lEQVQY05VQWw7CMAzr/Y/FafgYrI/1FbSZuKxQKn6o5LaJHMuOSSnDhw3OecSU2ut9gFME7Vut7/cVWwg4jgP7fuL8kxOGecOrCUyCvgtah5sKhi02wRld0DqHGFWwVgFdErVW5FKQ8wcpZxTtfbkb0Hk0Q47BH+eXw/mYnp9IZ/wxMt91tViWi0a6qhtpPMaj8/cOva4sRhgRQdGopVSIPFpsroH1669rGGLPILfzOf8EsKrUSyB6NocAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n    >\n      <img\n        class=\"gatsby-resp-image-image\"\n        style=\"width: 100%; height: 100%; margin: 0; vertical-align: middle; position: absolute; top: 0; left: 0; box-shadow: inset 0px 0px 0px 400px white;\"\n        alt=\"001 05\"\n        title=\"\"\n        src=\"/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/d9199/001-05.png\"\n        srcset=\"/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/8ff5a/001-05.png 240w,\n/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/e85cb/001-05.png 480w,\n/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/d9199/001-05.png 960w,\n/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/07a9c/001-05.png 1440w,\n/devHistoryBlog/static/6af868c8a73a5530b086f68e386f3b13/9b1e2/001-05.png 1880w\"\n        sizes=\"(max-width: 960px) 100vw, 960px\"\n      />\n    </span>\n  </span>\n  \n  </a>\n    </p>\n<br/>\n<br/>\n<p>아니 그럼 대체 뭐가 문제인 것인가?? 뷁!</p>\n<br/>\n<p><strong>다음 페이지로 ></strong> <a href=\"https://ssongey.github.io/devHistoryBlog/works/posts/2022-12-09--002\">Unable to acquire JDBC Connection<strong>(DHCP lease lost)</strong> 에러 오답노트2</a></p>","fields":{"tagSlugs":null,"slug":"/works/posts/2022-12-09--001"},"frontmatter":{"title":"Unable to acquire JDBC Connection 에러 오답노트1","tags":null,"date":"2022-12-09","description":"Connection is not available, request timed out after 5000ms"}}},"pageContext":{"slug":"/works/posts/2022-12-09--001"}},"staticQueryHashes":[]}