์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- ์์ดํ 15
- ์๋ฐ์ฐ๋ ๋
- ์์
- ์ธ๋ฑ์ค์คํต์ค์บ
- Hikari Connection Pool
- enum ์์ฑ์ ์ ๊ทผ ์ ํ์
- ์๋ฐ๋ผ์ด๋ธ์คํฐ๋
- mysql์ํคํ ์ฒ
- SVN
- InnoDB์ํคํ ์ฒ
- ์๋ฐ์์์ฐ๋ ๋๋ฅผ ์ฌ์ฉํ๋ ์ด์
- index skip scan
- index full scan
- ์ํฐ๋ ๊ฐ๋ฐ์ํ์ฌ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฒฉ๋ฆฌ์์ค
- Item6
- ์ธ๋ฑ์คํ์ค์บ
- ์๋ฐ์์
- ๋น์ผ๊ฐ์ฒด์์ฑ
- builder null
- effectiveJava
- ์ํฐ๋ ๋ณ์ข ๊ฐ๋ฐ์
- item15
- assert.notnull
- ์๋ผ์คํฑ์์น๋ฉ์ธ์ง์ฉ๋
- ์ดํํฐ๋ธ์๋ฐ
- ๋ฐ์ฉ๋ ์ค๊ตญ์ด
- ์๋ฐ
- hikari cp ์ค์
- mysql
- Today
- Total
โ๐ป๊ธฐ๋กํ๋ ๋ธ๋ก๊ทธ
Hikari ์ต์ ์ Connection Pool Size๋ฅผ ์ฐพ์์! ๋ณธ๋ฌธ
Hikari ์ต์ ์ Connection Pool Size๋ฅผ ์ฐพ์์!
์ฉ์ํด 2023. 11. 13. 20:26vuser 200์ผ๋ก 5๋ถ๊ฐ ์ฑ๋ฅํ ์คํธ ์ 25๋ฒ์ HikariPool-1 - Connection is not available, request timed out after 30000ms. SQLTransientConnectionException์ ๋ง์ฃผํ์ต๋๋ค. ์ Exception์ด ๋ฐ์ํ๊ณ , ์ด๋ป๊ฒ ํด๊ฒฐํ๋์ง ์์๋ด ์๋ค.
์ด ๊ธ์ ์๋ ๋ชฉ์ฐจ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค.
- Hikari Connection Pool ๋์ ๋ฐฉ์
- Hikari CP Connection ํ๋ ๊ณผ์
- Hikari CP Connection ๋ฐ๋ฉ ๊ณผ์
- ๋ฌธ์ ์์ธ ๋ถ์
- ๋ฌธ์ ํด๊ฒฐ ๋ฐฉ๋ฒ
์์ธ ๋ถ์ ์ ์ Hikari Connection pool ํ๋ ๋ฐ ๋ฐํ ๊ณผ์ ์ ๋ํด ์์๋ณด๊ฒ ์ต๋๋ค.
Hikari Connection Pool ๋์ ๋ฐฉ์
์์์ Hikari Connection Pool๋ก๋ถํฐ connection์ ํ๋ํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ดค์ต๋๋ค. ํ์ง๋ง ์ด๋ค ๋ฐฉ๋ฒ์ผ๋ก connection ์๋ฅผ ์ ์งํ๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
Hikari Connection Pool์ด ์ด๋ป๊ฒ pool์ ์ ์งํ๋์ง๋ Hikari ํ ์คํธ ์ฝ๋์์ ์ ์ ์์์ต๋๋ค.
try (HikariDataSource ds = new HikariDataSource(config)) {
getUnsealedConfig(ds).setIdleTimeout(3000);
System.clearProperty("com.zaxxer.hikari.housekeeping.periodMs");
SECONDS.sleep(1);
HikariPool pool = getPool(ds);
assertEquals("Total connections not as expected", 5, pool.getTotalConnections());
assertEquals("Idle connections not as expected", 5, pool.getIdleConnections());
try (Connection connection = ds.getConnection()) {
Assert.assertNotNull(connection);
MILLISECONDS.sleep(1500);
assertEquals("Second total connections not as expected", 6, pool.getTotalConnections());
assertEquals("Second idle connections not as expected", 5, pool.getIdleConnections());
}
assertEquals("Idle connections not as expected", 6, pool.getIdleConnections());
MILLISECONDS.sleep(3000);
assertEquals("Third total connections not as expected", 5, pool.getTotalConnections());
assertEquals("Third idle connections not as expected", 5, pool.getIdleConnections());
HikariPool์ด ์์ฑ๋๋ฉด HikariConfig ์ธํ ๊ฐ์ ์ฝ์ด TotalConnection์์ IdleConnection ์๋ฅผ ์ ์งํฉ๋๋ค.
์ดํ, dataSource๋ก๋ถํฐ 1๊ฐ์ ์ถ๊ฐ connection์ ์ป์ผ๋ฉฐ, IN USE ์ํ๋ก ๋งํนํฉ๋๋ค.
connection์ด ์ถ๊ฐ๋์ด๋ TotalConnection์ ๋ณ๊ฒฝ๋์ง๋ง, IdleConnection์ ๋ฐ๋ก ์ฆ๊ฐํ์ง ์์ต๋๋ค. Timeout์๊ฐ๋งํผ InUSE์ํ์๋ค๊ฐ Idle ์ํ๋ก ๋ณ๊ฒฝํฉ๋๋ค. ๋๋ค์ Timeout ์๊ฐ๋งํผ ์ฒดํฌํ๋ค๊ฐ ๋ ์ด์ ์ฌ์ฉํ์ง ์์ ๊ฒฝ์ฐ connection์ ๋ฐ๋ฉํ๊ฒ ๋ฉ๋๋ค.
HikariConfig์๋ Timeout ์๊ฐ์ด 30์ด๋ก ์ค์ ๋์ด ์์ต๋๋ค.
private static final long CONNECTION_TIMEOUT = SECONDS.toMillis(30);
Hikari CP Connection ํ๋ ๊ณผ์
HikariPool.getConnection()์ ํ๋ ์ suspendResumeLock์ ํ๋ ํ Database์์ ์ปค๋ฅ์ ์ ํ๋ํฉ๋๋ค. connection์ ์ป์ด์ค๋ฉด suspendResumeLock์ ํด์ ํฉ๋๋ค.
connection์ ์ป๋ ๊ณผ์ ์ ์ค๋ ๋๋ค์ด ๋ด๊ฒจ์๋ ConcurrentBag์ผ๋ก๋ถํฐ connection Wrapperํด๋์ค bagEntry๋ฅผ ์ป์ต๋๋ค.
connectionBag.borrow()๋ 3๋จ๊ณ๋ฅผ ๊ฑฐ์ณ ์ฌ์ฉ ๊ฐ๋ฅํ(idle) Connection์ ๋น๋ ค์ค๊ฒ ๋ฉ๋๋ค.
borrow() ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด ์๋์ ๊ฐ์ ์์์ ์กฐ๊ฑด์์ ๊ฑฐ์น๊ฒ ๋ฉ๋๋ค. ์กฐ๊ฑด์์ ํด๋นํ ๊ฒฝ์ฐ connection ๊ฐ์ฒด๋ฅผ ์ป์ด์ค๊ฒ ๋ฉ๋๋ค.
var poolEntry = connectionBag.borrow(timeout, MILLISECONDS);
- ์์ฒญํ ์ค๋ ๋๊ฐ threadList(ThreadLocal)์ ์ด๋ฏธ ์ฌ์ฉํ connection์ด ์๋์ง ํ์ธ. ์ด๋ ThreadLocalํ์ ์ด๋ฏ๋ก ๊ฐ ์ค๋ ๋๋ณ ์ ์ฅ๊ณต๊ฐ์ ๊ฒ์ฌ.
- Hikari Pool ์ ์ฒด ์ปค๋ฅ์ ํ์ ํด๋นํ๋ sharedList(CopyOnWriteArrayList)์ STATE_NOT_IN_USE์ํ์ ์ปค๋ฅ์ ์ด ์๋์ง ํ์ธ.
- ๋น๋ฆด ์ ์๋ ์ปค๋ฅ์ ์ด ์์ ๊ฒฝ์ฐ headoffQueue(SynchronouseQueue)์ ๋ค์ด๊ฐ ๋๊ธฐ -> ์ด๋ ๊ฒฝ๊ณผ์๊ฐ์ด ์ค์ ์๊ฐ๋ณด๋ค ์ง๋ ๊ฒฝ์ฐ SQLTransientConnectionException ๋ฐ์.
โ์ threadList์ ์์๋ค์ ๋์์๋ถํฐ ๊ฒ์ฌํ ๊น์?
final var list = threadList.get();
for (int i = list.size() - 1; i >= 0; i--) {
final var entry = list.remove(i);
@SuppressWarnings("unchecked")
final T bagEntry = weakThreadLocals ? ((WeakReference<T>) entry).get() : (T) entry;
if (bagEntry != null && bagEntry.compareAndSet(STATE_NOT_IN_USE, STATE_IN_USE)) {
return bagEntry;
}
}
- ๊ฐ์ฅ ์ต๊ทผ์ ์ฌ์ฉํ connection์ ๊ฒ์ฌํ๊ธฐ ์ํด์
- list ํ์ ์๊ฐ์ ์ค์ด๊ธฐ ์ํด์
threadList๋ Listํ์ ์ด๋ฏ๋ก remove()๋ฅผ ์ฒซ ๋ฒ์งธ ์์๋ถํฐ ์์ํ๋ค๋ฉด ๋ค์ ์์๋ค์ ์์ผ๋ก ๋ฐ์ด์ผ ํ๋ O(N) ์๊ฐ๋ณต์ก๋๊ฐ ๋ฐ์ํฉ๋๋ค. ๋์์๋ถํฐ ์ฒดํฌํ๋ฉด์ ์๊ฐ ๋ณต์ก๋๋ฅผ O(1)๋ก ์ค์ผ ์ ์์ต๋๋ค.
Hikari CP Connection ๋ฐ๋ฉ ๊ณผ์
- connection์ ํ๋ํ ์ค๋ ๋๊ฐ commit, exception์ ์ํด rollback์ด ๋๋ฉด ์ค๋ ๋๋ ์ค๋ ๋ ํ์ ๋ฐ๋ฉ๋๋ ๊ณผ์ ์ ๊ฑฐ์นฉ๋๋ค.
- STATE _NOT_IN_USE๋ก ํ์๋๋ฉฐ, handOffQUeue์์ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๊ฐ ์๋์ง ํ์ธ ํ, ๋๊ธฐ์ํ์ ์ค๋ ๋๊ฐ ์กด์ฌ ์ handOffQueue๋ก ๋ฐ๋ฉํฉ๋๋ค.
- ๋๊ธฐ ์ค์ธ ์ค๋ ๋๊ฐ ์๋ค๋ฉด, threadLocal๋ด์ list value์ ํ์ฌ connection ์ ๋ณด๋ฅผ ์ถ๊ฐํฉ๋๋ค.
์์์ Hikari Connection Pool์ด ์ด๋ป๊ฒ ๋์ํ๋์ง ์์๋ณธ ๋ด์ฉ์ ํ ๋๋ก, Exception์ด ๋ฐ์ํ ์์ธ์ ๋ถ์ํด ๋ณด๊ฒ ์ต๋๋ค.
๋ฌธ์ ์์ธ ๋ถ์
Connection pool์ ๋ค ์ฐจ์งํ ์ํ์์ ๋ง์ ๋ถํ๋ก ๋ฐ์ํ ๋ค๋ฅธ ์ค๋ ๋๋ค์ด getConnection์ ์์ฒญํ๋ค๊ฐ, ๋ ์ด์ ํ๋ํ connection์ด ์์ด ๋ง์ง๋ง ๋๊ธฐ ์์น์ธ handOffQueue์์ ๋ ์ด์ connection์ ํ๋ํ์ง ๋ชปํ๊ณ SQLTransientConnectionException์ด ๋ฐ์ํ๋ ๊ฒ์ ๋๋ค.
๋ํ ๋ฉ๋ชจ๋ฆฌ ์์์ ๋นํด CPU์ฌ์ฉ๋์ด 100%๋ฅผ ๋๋ ์ํฉ์ด ๋ฐ์ํ์ต๋๋ค. ์ด๋ ๋ถํ๊ฐ ๋ฐ์ํ๋ ์ํฉ์์ tomcat ์ค๋ ๋ ๊ฐ HikariPool์ connection์ ํ๋ํ๊ณ ์ race condition์ด ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
heeverse๋ ํฐ์บฃ ์ค๋ ๋ ์๋ฅผ 10๊ฐ (default)๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ํฐ์บฃ ์ค๋ ๋ ์๊ฐ 10๊ฐ์ด๊ณ , hikari Connection Pool Size๋ 10๊ฐ๋ฉด ์ถฉ๋ถํ ๊ฒ์ด๋ผ ์์ํ์ต๋๋ค.
Hikari wiki๋ฅผ ์ฐธ๊ณ ํ๋ฉด ํ๋์ ์ค๋ ๋์์ ์ํํ๋ ๋ค์์ connection์ ์ํด Pool-Locking์ด ๋ฐ์ํ ์ ์๋ค๊ณ ํฉ๋๋ค.
"Pool-locking"
The prospect of "pool-locking" has been raised with respect to single actors that acquire many connections.
Exception์ ๋ฐ์์ํจ API ์ํ ์ ์ด๋ค ํธ๋์ญ์ ์ด ์ํ๋๋์ง ์ดํด๋ณด๊ฒ ์ต๋๋ค.
ํ๋์ ํฐ์ผ ์๋งคํ๊ธฐ API๋ฅผ ์ํํ๊ธฐ ์ํด์๋ ๋ ๊ฐ์ง ์ข ๋ฅ์ ํธ๋์ญ์ ์ด ๋ฐ์ํฉ๋๋ค.
- ๋ก๊ทธ์ธ - ๋จ๊ธฐ ํธ๋์ญ์
- ํฐ์ผ ์๋งค - ์ฅ๊ธฐ ํธ๋์ญ์
(ํ๋์ ์ค๋ ๋์์ 5๋ฒ์ ํธ๋์ญ์
๋ฐ์)
- JWTํ ํฐ ๊ฒ์ฌ
- ticket order ์์ฑ
- ํฐ์ผ ์๋งค๋ฅผ ์ํ lock
- ๋น๋๊ธฐ ๋ก๊ทธ ์์ฑ
- ๊ฒฐ๊ณผ ํฐ์ผ ์กฐํ
์ฅ๊ธฐ ํธ๋์ญ์ ์ค ํฐ์ผ ์๋งค๋ฅผ ์ํ Lock์ ์์ฑ ์, Record Lock์ ์ํํ๊ธฐ ์ํด, ๋น๊ด์ ๋ฝ์ ์ํํ๊ณ ์์ต๋๋ค. ํ๋์ ์ค๋ ๋์ ์ฌ๋ฌ ์ปค๋ฅ์ ์ ์ป๋ ์์ + Lock์ํ๊น์ง ๊ฒน์น๊ฒ ๋๋ ์ํฉ์ด ๋์์ต๋๋ค.
๋ฌธ์ ํด๊ฒฐ ๋ฐฉ๋ฒ
๊ทธ๋ผ ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ ์ ์์๊น์? ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๋ฌธ์ ํด๊ฒฐ์ ์๋ํด ๋ณด์์ต๋๋ค.
1. data source ๋ถ๋ฆฌ๋ฅผ ํตํ ์ค๋ ๋ ๊ฒฝํฉ ๊ฐ์์ํค๊ธฐ
For example, systems with a mix of long running transactions and very short transactions are generally the most difficult to tune with any connection pool. In those cases, creating two pool instances can work well
์๋ฅผ ๋ค์ด, ์ฅ๊ธฐ ์คํ ํธ๋์ญ์ ๊ณผ ๋งค์ฐ ์งง์ ํธ๋์ญ์ ์ด ํผํฉ๋ ์์คํ ์ ์ผ๋ฐ์ ์ผ๋ก ์ฐ๊ฒฐ ํ์ ์กฐ์ ํ๊ธฐ๊ฐ ๊ฐ์ฅ ์ด๋ ต์ต๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ ๋ ๊ฐ์ ํ ์ธ์คํด์ค๋ฅผ ๋ง๋๋ ๊ฒ์ด ์ ์๋ํ ์ ์์ต๋๋ค.
์ฅ๊ธฐ ํธ๋์ญ์ ์๋ ticket, ticket-orderํ ์ด๋ธ์์ ์์ ์ด ์ํ๋ฉ๋๋ค. ๋ ์ค select for update๋ฅผ lock์ผ๋ก ์ธํ ๋ณ๋ชฉ์ง์ ์ ๋ฐ์์ํค๋ ticket๊ณผ ๊ทธ ์ด์ธ ํ ์ด๋ธ์ datasource๋ฅผ ๋ถ๋ฆฌํด ๋ดค์ต๋๋ค. ํ์ง๋ง data source๋ฅผ ๋ถ๋ฆฌํ๋ ์๊ฐ ํธ๋์ญ์ ๊ณต์ ๊ฐ ๋์ง ์์ dabasae lock์ด ๊ณต์ ๋์ง ์์์ต๋๋ค.
2. ์ต์ ์ hikari Pool size ์ฐพ๊ธฐ
Hikari wiki์ ๋ฐ๋ฅด๋ฉด Pool-locking์ ํผํ๊ธฐ ์ํ ์ต์ ์ pool size ๊ณต์์ ์ ์ํ๊ณ ์์ต๋๋ค.
pool size = Tn x (Cm - 1) + 1
Tn : ์ต๋ ์ค๋ ๋ ์, Cm : ์ฑ๊ธ ์ค๋ ๋์์ ๋์์ ์ํ๋๋ ์ปค๋ฅ์ ์
heeverse์์๋ tomcat ์ต๋ ์ค๋ ๋ ์ = 100, ์ฑ๊ธ ์ค๋ ๋์์ ๋์์ ์ํ๋๋ ์ปค๋ฅ์ ์ = 5๋ฅผ ๋์ ํ์ฌ 41์ pool size๋ฅผ ์ค์ ํ์ต๋๋ค.
์ต์ ์ pool size ์ค์ ์ ํตํด Hikari Connection Pool-locking์ ํผํ ์ ์์์ต๋๋ค.
์ด๋ฒ์๋ connection pool size ์กฐ์ ์ผ๋ก ํด๊ฒฐํ์ง๋ง, hikari wiki์ ๋ฐ๋ฅด๋ฉด ํ๋์ ์ค๋ ๋์์ ์ฌ๋ฌ ์ปค๋ฅ์ ์ ๋งบ์ง ์๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ์์ ์กฐ์ ํ๋ ๊ฒ์ ๊ฒํ ํ๋ผ๊ณ ํฉ๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ์์ ํ๋์ ์ค๋ ๋์์ ์ต์ํ์ ํธ๋์ญ์ ์ผ๋ก ํฐ์ผ ์๋งค๋ฅผ ํ ์ ์์์ง ๋ถ์ํด ๋ด์ผ๊ฒ ์ต๋๋ค.
[์ฐธ๊ณ ]
https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing
'ํ๋ก์ ํธ > Heeverse' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ฑ๋ฅํ๋] ๋ฐ๋ณต์ ์ธ vault ์๋ฒ ํธ์ถ ์ ๊ฑฐํ๊ธฐ (0) | 2023.10.26 |
---|---|
Heeverse ์ฑ๋ฅํ ์คํธ ์ค๋นํ๊ธฐ (0) | 2023.10.20 |
@Builder๋ฅผ ํตํด ์์ ํ๊ฒ ๊ฐ์ฒด ์์ฑํ๊ธฐ (0) | 2023.07.21 |