JAVA/JPA

Querydsl์˜ transform ์‚ฌ์šฉ์‹œ HikariCP Connection Leak

realizers 2023. 4. 29. 18:44
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ˜ญ ์ด์Šˆ ๋ฐœ์ƒ


์–ด๋Š ๋‚  ํŒ€์›๋ถ„์ด 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 ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

 

AbstractJPAQuery.class์˜ ์ผ๋ถ€

 

์œ„์—์„œ entityManager์˜ ํ˜ธ์ถœ๋กœ ์ธํ•ด SharedEntityManagerCreator ํด๋ž˜์Šค์˜ ๋‚ด๋ถ€ ํด๋ž˜์Šค์ธ SharedEntityManagerInvocationHandler ํด๋ž˜์Šค๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค๊ณ  ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๋ช‡๊ฐ€์ง€๊ฐ€ ๋‚˜์˜ค๋Š”๋ฐ ์‚ดํŽด๋ด…์‹œ๋‹ค.

 

  1. ํ˜„์žฌ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜๊ณ  ์žˆ๋‹ค๋ฉด target์€ null์ด ์•„๋‹ˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š๋‹ค๋ฉด null์ด ๋ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ง€๊ธˆ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜๊ณ  ์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— target์€ null์ด ๋ฉ๋‹ˆ๋‹ค. 
  2. target์€ null์ด๋ฏ€๋กœ if ์กฐ๊ฑด๋ฌธ์— ํ•ด๋‹นํ•˜์—ฌ target์—๋Š” ์ƒˆ๋กœ์šด entityManager๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  isNewEm ๋ณ€์ˆ˜๋Š” true๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.
  3. isNewEm ๋ณ€์ˆ˜๊ฐ€ true์ด๊ธฐ ๋•Œ๋ฌธ์— if ์กฐ๊ฑด๋ฌธ์— ํ•ด๋‹นํ•˜์—ฌ result๋Š” DeferredQueryInvocationHandler ํ”„๋ก์‹œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

SharedEntityManagerInvocationHandler class์˜ ์ผ๋ถ€

 

์ง€๊ธˆ๊นŒ์ง€ createQuery ๋ฉ”์„œ๋“œ์— ์˜ํ•ด entityManager๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ณผ์ •์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด์ œ fetch ๋ฉ”์„œ๋“œ๊ฐ€ ๋ฐ˜ํ™˜ํ•˜๋Š” getResultList ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

  1. DeferredQueryInvocationHandler ํด๋ž˜์Šค์˜ invoke ๋ฉ”์„œ๋“œ์˜ finally ๋ฉ”์„œ๋“œ์—์„œ if๋ฌธ์— ๋งŒ์กฑํ•˜๋Š” ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์ธ ๊ฒฝ์šฐ ์ตœ์ข…์ ์œผ๋กœ ์ž์‹ ์ด ์‚ฌ์šฉํ•œ entityManager๋ฅผ closeํ•˜๊ณ  null ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ์žˆ๋Š” ๊ณผ์ •์„ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทผ๋ฐ ์–ด๋–ค ๋ฉ”์„œ๋“œ์˜ ์ด๋ฆ„์ธ ๊ฒฝ์šฐ์—๋งŒ ํ•ด๋‹น if ๋ฌธ์— ํ•ด๋‹นํ•˜๋Š” ๊ฑธ๊นŒ?

 

๐Ÿ’ก ์ž๋™์œผ๋กœ closeํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์˜ ์ข…๋ฅ˜

 

 

transform ๋ฉ”์„œ๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž.


transform ๋ฉ”์„œ๋“œ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ iterate๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๊ณ  ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์•„๋ž˜ ๋กœ์ง์„ ๋ณด๋ฉด iterate๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Tuple์„ ๋งŒ๋“  ํ›„ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋กœ์ง์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ transform์€ ๋‚ด๋ถ€์ ์œผ๋กœ SharedEntityManagerCreator ํด๋ž˜์Šค์˜ queryTerminationMethods๊ฐ€ ์‹คํ–‰๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— entityManager๊ฐ€ close ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ž์‹ ์ด ์‚ฌ์šฉํ•œ entityManager๋Š” ์–ธ์  ๊ฐ„ close ๋˜๋ฉฐ Leak์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

GroupByMap class์˜ ์ผ๋ถ€

 

๊ฒฐ๋ก .


@Transactional ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ transform ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ ํŠธ๋žœ์žญ์…˜์— ์ฐธ์—ฌํ•˜๋„๋ก ํ•˜์—ฌ entityManager๋ฅผ closeํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์ž ์ž…๋‹ˆ๋‹ค.

 

 

 

์ฐธ๊ณ ์ž๋ฃŒ

 

 

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•