Querydsl์ transform ์ฌ์ฉ์ HikariCP Connection Leak
๐ญ ์ด์ ๋ฐ์
์ด๋ ๋ ํ์๋ถ์ด PinPoint ๋ชจ๋ํฐ๋ง ์ค ๋ณ๋ชฉ์ด ๋ฐ์ํ๋ค๊ณ ๋ง์์ ํด์ฃผ์ จ๋๋ฐ, ์ผ๋จ ๊ตฌ์ฒด์ ์ธ ์์ธ์ ๋ชจ๋ฅด๋ ์ํฉ์ ์กฐ๊ธ ๋ ์ง์ผ๋ณด๊ธฐ๋ก ํ์ต๋๋ค. ๋ณ๋ชฉ์ด ๋ฐ์ํ ํ์ด๋ฐ์ด ํ์๊ฐ RabbitMQ ์ค์ ์ ์ถ๊ฐ์ ์ผ๋ก ์ค์ ํ ํ์ ๋ฐ์ํ ๊ฑด๊ฐ?๋ผ๋ ์๊ฐ์ ํ์๋๋ฐ ์ถํ์ RabbitMQ ์ค์ ์ ์๋๋๋ก ์ค์ ์ ํ๊ณ ๋ฐฐํฌ๋ฅผ ํ๋๋ฐ๋ ๋ถ๊ตฌํ๊ณ ๊ณ์ํ์ฌ ๋ฌธ์ ๊ฐ ๋ฐ์์ ํ์์ต๋๋ค.
RabbitMQ์ ๊ด๋ จ์ด ์๊ตฌ๋ ์๊ฐํ ํ aws Cloudwatch์ ๋ก๊ทธ๋ฅผ ๋ณด๋ ์ค ํน์ API ํธ์ถ ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ ๊ฐ์ ๋๋์ ๋ฐ์ ํน์ API์ ์์ค์ฝ๋๋ฅผ ๋ณด์๋๋ฐ QueryDSL์ ๋ฉ์๋ ์ค transform ๋ฉ์๋๋ฅผ ํ์ธํ๊ณ ์ด๊ฒ ์ด๋ค ์ญํ ์ ํ๋์ง๋ถํฐ ์ฐพ์๋ณด๊ฒ ๋์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ ์์ด ๋ฌธ์ ์๊ตฌ๋ ์๊ฒ๋ ๊ณผ์ ์ ๊ณต์ ํ๊ฒ ์ต๋๋ค.
๐ก ๋ฒ์ ์ ๋ณด
querydsl-jpa: 5.0.0 version
hibernate-core: 5.6.14 final version
๐ก HikariCP ๋ก๊น ํ์ฑํ
- application.yml์ DB Connection์ ๋ณด๊ธฐ ์ํด ๋ค์์ ์ถ๊ฐํฉ๋๋ค.
logging:
level:
com.zaxxer.hikari: trace
com.zaxxer.HikariConfig: DEBUG
๋ก์ง์ ์ดํด๋ณด์.
์๋ ๋ก์ง์ ๋ณด๋ฉด QueryDSL์ ์ฌ์ฉ์ค์ด๊ณ ํ๋์ ๋ฉ์๋๋ fetch ๋ฉ์๋๋ฅผ ๋ค๋ฅธ ํ๋์ ๋ฉ์๋๋ transform ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. ๋ ์ค์ํ ์ ์ ๋ฐ๋ก ํด๋น ํด๋์ค ์ด๋์๋ @Transactional ์ด๋ ธํ ์ด์ ์ด ์ ์ธ๋์ด ์์ง ์๋ค๋ ์ ์ ๋๋ค.
๐ก transform ๋ฉ์๋์ fetch ๋ฉ์๋์ ์ฐจ์ด
- transform ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก iterate๋ฅผ ๋ฐํํฉ๋๋ค.
- fetch ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก getResultList๋ฅผ ๋ฐํํฉ๋๋ค.
- ํ์ง๋ง ๋ ๋ฉ์๋ ๋ชจ๋ this.createQuery() ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ์์ต๋๋ค.
fetch ๋ฉ์๋๋ฅผ ์ดํด๋ณด์.
fetch ๋ฉ์๋๋ AbstractJPAQuery ํด๋์ค์ createQuery ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ๋ด๋ถ์ ์ผ๋ก ์์ ํด๋์ค์ createQuery ๋ฉ์๋๋ฅผ ํธ์ถํ๊ณ ์์ต๋๋ค. ์ด๋ this.entityManager๋ก SharedEntityManagerCreator ํด๋์ค์ ๋ด๋ถ ํด๋์ค์ธ SharedEntityManagerInvocationHandler ํด๋์ค์ invoke ๋ฉ์๋๊ฐ ํธ์ถ๋ฉ๋๋ค.
์์์ entityManager์ ํธ์ถ๋ก ์ธํด SharedEntityManagerCreator ํด๋์ค์ ๋ด๋ถ ํด๋์ค์ธ SharedEntityManagerInvocationHandler ํด๋์ค๊ฐ ํธ์ถ๋๋ค๊ณ ํ์์ต๋๋ค. ์ฌ๊ธฐ์ ์ค์ํ ๋ช๊ฐ์ง๊ฐ ๋์ค๋๋ฐ ์ดํด๋ด ์๋ค.
- ํ์ฌ ํธ๋์ญ์ ์ ์ฐธ์ฌํ๊ณ ์๋ค๋ฉด target์ null์ด ์๋๊ฒ ๋ฉ๋๋ค. ๋ค๋ง ํธ๋์ญ์ ์ ์ฐธ์ฌํ๊ณ ์์ง ์๋ค๋ฉด null์ด ๋ฉ๋๋ค. ์ฐ๋ฆฌ๋ ์ง๊ธ ํธ๋์ญ์ ์ ์ฐธ์ฌํ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ target์ null์ด ๋ฉ๋๋ค.
- target์ null์ด๋ฏ๋ก if ์กฐ๊ฑด๋ฌธ์ ํด๋นํ์ฌ target์๋ ์๋ก์ด entityManager๊ฐ ์์ฑ๋๊ณ isNewEm ๋ณ์๋ true๊ฐ ๋ฉ๋๋ค.
- isNewEm ๋ณ์๊ฐ true์ด๊ธฐ ๋๋ฌธ์ if ์กฐ๊ฑด๋ฌธ์ ํด๋นํ์ฌ result๋ DeferredQueryInvocationHandler ํ๋ก์๋ฅผ ๋ฐํํ๊ฒ ๋ฉ๋๋ค.
์ง๊ธ๊น์ง createQuery ๋ฉ์๋์ ์ํด entityManager๊ฐ ์์ฑ๋๋ ๊ณผ์ ์ ์ดํด๋ดค์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด์ fetch ๋ฉ์๋๊ฐ ๋ฐํํ๋ getResultList ๋ฉ์๋์ ๋ํด ์ดํด๋ณด๊ฒ ์ต๋๋ค.
- DeferredQueryInvocationHandler ํด๋์ค์ invoke ๋ฉ์๋์ finally ๋ฉ์๋์์ if๋ฌธ์ ๋ง์กฑํ๋ ๋ฉ์๋์ ์ด๋ฆ์ธ ๊ฒฝ์ฐ ์ต์ข ์ ์ผ๋ก ์์ ์ด ์ฌ์ฉํ entityManager๋ฅผ closeํ๊ณ null ์ฒ๋ฆฌ๋ฅผ ํ๊ณ ์๋ ๊ณผ์ ์ ์ดํด๋ณผ ์ ์์ต๋๋ค. ๊ทผ๋ฐ ์ด๋ค ๋ฉ์๋์ ์ด๋ฆ์ธ ๊ฒฝ์ฐ์๋ง ํด๋น if ๋ฌธ์ ํด๋นํ๋ ๊ฑธ๊น?
๐ก ์๋์ผ๋ก closeํด์ฃผ๋ ๋ฉ์๋์ ์ข ๋ฅ
transform ๋ฉ์๋๋ฅผ ์ดํด๋ณด์.
transform ๋ฉ์๋๋ ๋ด๋ถ์ ์ผ๋ก iterate๋ฅผ ๋ฐํํ๋ค๊ณ ํ์์ต๋๋ค. ๋ํ ์๋ ๋ก์ง์ ๋ณด๋ฉด iterate๋ฅผ ์ฌ์ฉํ์ฌ Tuple์ ๋ง๋ ํ ๊ฒฐ๊ณผ๊ฐ์ ๋ฐํํ๋ ๋ก์ง์ ๋ณผ ์ ์์ต๋๋ค. ๋ํ transform์ ๋ด๋ถ์ ์ผ๋ก SharedEntityManagerCreator ํด๋์ค์ queryTerminationMethods๊ฐ ์คํ๋์ง ์๊ธฐ ๋๋ฌธ์ entityManager๊ฐ close ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ์์ ์ด ์ฌ์ฉํ entityManager๋ ์ธ์ ๊ฐ close ๋๋ฉฐ Leak์ด ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
๊ฒฐ๋ก .
@Transactional ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ transform ๋ฉ์๋ ํธ์ถ ์ ํธ๋์ญ์ ์ ์ฐธ์ฌํ๋๋ก ํ์ฌ entityManager๋ฅผ closeํ ์ ์๋๋ก ํด์ฃผ์ ์ ๋๋ค.
์ฐธ๊ณ ์๋ฃ