TCP μ†ŒμΌ“μ΄ μ—°κ²°λœ μƒνƒœλ‘œ λ‚¨μ•„μžˆλŠ” TCP 컀λ„₯μ…˜ λˆ„μˆ˜ 문제λ₯Ό κ²½ν—˜ν•˜κ³ λ‚˜μ„œ 컀λ„₯μ…˜ ν’€ κΈ°λŠ₯ κ΅¬ν˜„μ— λŒ€ν•΄μ„œ λ‹€μ‹œν•œλ²ˆ ν•™μŠ΅ν•΄λ³΄κ³  μ •λ¦¬ν•˜λŠ” κΈ€μž…λ‹ˆλ‹€.

μ•„λ§ˆλ„ κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€μ™€ 자주 μ‚¬μš©λ˜λŠ” 일뢀 λ°μ΄ν„°λ² μ΄μŠ€λ“€μ— λŒ€ν•œ 컀λ„₯μ…˜ ν’€ κΈ°λŠ₯은 직접 κ΅¬ν˜„ν•˜μ§€ μ•Šμ•„λ„ λ˜λŠ” κ²½μš°κ°€ λ§ŽμŠ΅λ‹ˆλ‹€. μ‹œμŠ€ν…œμ—μ„œ μ‚¬μš©μ€‘μΈ μ‹œκ³„μ—΄ λ°μ΄ν„°λ² μ΄μŠ€λŠ” μžλ°” ν΄λΌμ΄μ–ΈνŠΈ 라이브러리λ₯Ό μ œκ³΅ν•˜κ³  μžˆμ§€λ§Œ μ‹œκ³„μ—΄ λ°μ΄ν„°λ² μ΄μŠ€κ°€ 단일 μš”μ²­μ„ 순차적으둜 μ²˜λ¦¬ν•˜λŠ” μ‹±κΈ€ μŠ€λ ˆλ“œ λ°©μ‹μž„μ— λ”°λΌμ„œ 컀λ„₯μ…˜ ν’€ κΈ°λŠ₯은 자체적으둜 λ‚΄μž₯ν•˜κ³  μžˆμ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 컀λ„₯μ…˜ ν’€ κΈ°λŠ₯이 λ°˜λ“œμ‹œ ν•„μš”ν•œ 것은 μ•„λ‹ˆμ§€λ§Œ TCP 연결에 λŒ€ν•œ λΆ€ν•˜λ₯Ό μƒκ°ν•œλ‹€λ©΄ 자주 TCP μ†ŒμΌ“μ„ μ—°κ²°ν•˜λ―€λ‘œ λ°œμƒν•  수 μžˆλŠ” λ ˆμ΄ν„΄μ‹œλ₯Ό 및 μžμ› λ‚­λΉ„λ₯Ό λ¬΄μ‹œν•  수 μ—†μŠ΅λ‹ˆλ‹€.

μžλ°” 컀λ„₯μ…˜ ν’€ 라이브러리

μžλ°” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λŒ€λΆ€λΆ„ Apache Commons Pool2 라이브러리λ₯Ό ν™œμš©ν•΄μ„œ 컀λ„₯μ…˜ ν’€ κΈ°λŠ₯을 κ΅¬ν˜„ν•˜λŠ” κ²½μš°κ°€ λ§ŽμŠ΅λ‹ˆλ‹€. λŒ€ν‘œμ μœΌλ‘œ λ ˆλ””μŠ€ ν΄λΌμ΄μ–ΈνŠΈλ‘œ 많이 μ‚¬μš©μ€‘μΈ Lettuce의 컀λ„₯μ…˜ ν’€ 지원을 확인할 수 있으며 Apache Commons DBCP2라고 ν•˜λŠ” κ΄€κ³„ν˜• λ°μ΄ν„°λ² μ΄μŠ€μ— λŒ€ν•œ λŒ€ν‘œμ μΈ 컀λ„₯μ…˜ ν’€ λΌμ΄λΈŒλŸ¬λ¦¬λ„ Commons Pool둜 κ΅¬ν˜„λ˜μ–΄μžˆμŒμ„ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

Apache Commons Pool2μ—μ„œλŠ” κ°„λ‹¨ν•œ PooledObjectFactory 예제λ₯Ό μ œκ³΅ν•˜κ³  μžˆμ§€λ§Œ μžμ„Έν•œ μ„€λͺ…이 μ—†μŠ΅λ‹ˆλ‹€.

컀λ„₯μ…˜ ν’€ κ΅¬ν˜„ 예제λ₯Ό 검색해보면 생각보닀 κ΄€λ ¨λœ 글이 μ—†μ—ˆκΈ°μ— μ§μ ‘μ μœΌλ‘œ 컀λ„₯μ…˜ ν’€ κΈ°λŠ₯을 κ΅¬ν˜„ν•˜λŠ” κ°œλ°œμžλŠ” λ§Žμ§€ μ•Šμ„ 것이라 μƒκ°λ©λ‹ˆλ‹€. 컀λ„₯μ…˜ μ˜€λΈŒμ νŠΈμ— λŒ€ν•œ 라이프 사이클을 κ΄€λ¦¬ν•˜λŠ” 것은 PooledObjectFactory μΈν„°νŽ˜μ΄μŠ€κ°€ λ‹΄λ‹Ήν•˜λ―€λ‘œ μ›ν•˜λŠ” 컀λ„₯μ…˜ ν’€ λ™μž‘μ„ BasePooledObjectFactoryλ₯Ό μƒμ†ν•˜μ—¬ κ΅¬ν˜„ν•˜λ©΄ λ©λ‹ˆλ‹€. λ‹€λ§Œ, μ»€λ„€μ…˜ ν’€ κ΅¬ν˜„ μ‹œ μ€‘μš”ν•˜κ²Œ 생각해야할 뢀뢄은 BasePooledObjectFactoryμ—μ„œ 기본적으둜 κ΅¬ν˜„ν•΄λ‘μ–΄μ„œ κ΅¬ν˜„μ„ κ°•μ œν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜ 쀑 컀λ„₯μ…˜ ν’€μ—μ„œ κ΄€λ¦¬ν•˜λŠ” μ˜€λΈŒμ νŠΈκ°€ μ‚­μ œλ˜λŠ” λŒ€μƒμ΄ λ˜λŠ” 경우 ν˜ΈμΆœλ˜λŠ” destoryObject ν•¨μˆ˜ λ™μž‘μ„ μƒλž΅ν•΄λ²„λ¦΄ 수 μžˆλ‹€λŠ” 점 μž…λ‹ˆλ‹€.

CPooledObjectFactory

컀λ„₯μ…˜ ν’€ κΈ°λŠ₯을 처음 κ΅¬ν˜„ν–ˆμ„ λ‹Ήμ‹œμ— κ³ λ €ν•˜μ§€ λͺ»ν•œ λ―Έν‘ν•œ 점을 μΈμ§€ν•˜κ³  KDB ν”„λ‘œμ„ΈμŠ€μ— λŒ€ν•œ 컀λ„₯μ…˜μ˜ 라이프 사이클을 κ΄€λ¦¬ν•˜λŠ” CPooledObjectFactoryλ₯Ό λ‹€μ‹œ μž‘μ„±ν•΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.

public class CPooledObjectFactory extends BasePooledObjectFactory<c> {

    private final String host;
    private final int port;

    public CPooledObjectFactory(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public c create() throws Exception {
        return new c(host, port);
    }

    @Override
    public PooledObject<c> wrap(c c) {
        return new DefaultPooledObject<>(c);
    }

    @Override
    public boolean validateObject(PooledObject<c> p) {
        try {
            c c = p.getObject();
            if(c.s == null || !c.s.isConnected()) {
                return false;
            }
            c.k("1");
        } catch (c.KException | IOException e) {
            return false;
        }
        return true;
    }

    @Override
    public void destroyObject(PooledObject<c> p) throws Exception {
        close(p.getObject());
    }

    private void close(c c) {
        if (c != null) {
            try {
                c.close();
            } catch (IOException e) {
                // ignored
            }
        }
    }
}

더 μžμ„Έν•˜κ²Œ PooledObjectFactory κ΅¬ν˜„μ— λŒ€ν•΄μ„œ κ³ λ―Όν•˜κ³  싢은 뢄듀이라면 μ•„λž˜μ˜ μ˜€ν”ˆμ†ŒμŠ€λ“€μ„ μ°Έκ³ ν•΄λ³΄μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

CObjectPool

μ΄μ œλŠ” 컀λ„₯μ…˜ 였브젝트λ₯Ό 관리할 방식에 λŒ€ν•΄μ„œ μ„€μ •ν•˜λŠ” 것을 고민해보아야 ν•©λ‹ˆλ‹€. Apache Commons Poolμ—μ„œ 컀λ„₯μ…˜ 였브젝트 라이프사이클에 따라 μ–΄λ–»κ²Œ 관리할지 κ²°μ •ν•˜κΈ° μœ„ν•΄μ„œλŠ” GenericObjectPoolConfigλ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

public class CObjectPoolConfig extends GenericObjectPoolConfig<c> {
    public CObjectPoolConfig() {
        this.setMaxTotal(8);
        this.setMaxIdle(5);
        this.setMinIdle(1);
        this.setMaxWait(Duration.ofMinutes(3));
        this.setTimeBetweenEvictionRuns(Duration.ofMinutes(5));
        this.setTestWhileIdle(true);
        this.setJmxEnabled(false);
    }
}

컀λ„₯μ…˜ ν’€ λΌμ΄λΈŒλŸ¬λ¦¬μ—μ„œ μ œκ³΅ν•˜λŠ” κΈ°λ³Έκ°’ μ€‘μ—μ„œ JMX λͺ¨λ‹ˆν„°λ§ κΈ°λŠ₯을 μ‚¬μš©ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ λΉ„ν™œμ„±ν™” ν•΄λ‘μ—ˆμœΌλ©° 유휴 μƒνƒœλ‘œ 관리쀑인 컀λ„₯μ…˜μ— λŒ€ν•΄μ„œλ„ 미리 컀λ„₯μ…˜ μƒνƒœλ₯Ό 확인할 수 μžˆλ„λ‘ TestWhileIdle μ˜΅μ…˜μ„ ν™œμ„±ν™”ν•˜μ˜€μŠ΅λ‹ˆλ‹€. MaxWait의 경우 μ‚¬μš©μ€‘μΈ 각 컀λ„₯μ…˜μ΄ μ΅œλŒ€λ‘œ μ†Œμš”ν•  수 μžˆλŠ” μž„κ³„μΉ˜μ— 따라 3λΆ„ κΉŒμ§€ 기닀릴 수 μžˆλ„λ‘ ν•΄λ‘μ—ˆμŠ΅λ‹ˆλ‹€.

By default, kdb+ is single-threaded, and processes incoming queries sequentially.

컀λ„₯μ…˜ 라이프 사이클에 λ”°λΌμ„œ 컀λ„₯μ…˜ ν’€μ—μ„œ 컀λ„₯μ…˜ μ˜€λΈŒμ νŠΈκ°€ μ‚­μ œλ˜λŠ” μ‚¬μœ μ—λŠ” λŒ€ν‘œμ μœΌλ‘œ 두가지가 μžˆλŠ”λ°μš”. ν•˜λ‚˜λŠ” 유휴 μƒνƒœμ— μžˆλŠ” 컀λ„₯μ…˜μ΄ λ²¨λ¦¬λ°μ΄μ…˜ 쿼리λ₯Ό μˆ˜ν–‰ν•˜λŠ” κ³Όμ •μ—μ„œ μ†ŒμΌ“ 톡신 였λ₯˜κ°€ λ°œμƒν•˜κ±°λ‚˜ λ„ˆλ¬΄ μ˜€λž¬λ™μ•ˆ 컀λ„₯μ…˜μ΄ μ‚¬μš©λ˜μ§€ μ•Šμ•„μ„œ 버렀지고 μƒˆλ‘œμš΄ 컀λ„₯μ…˜μ„ λ§Œλ“€μ–΄μ„œ 풀을 μœ μ§€ν•˜λŠ” μƒν™©μž…λ‹ˆλ‹€. μœ„ 문ꡬ λ‚΄μš©μ²˜λŸΌ μ‹œκ³„μ—΄ λ°μ΄ν„°λ² μ΄μŠ€λŠ” λΉ λ₯΄κ²Œ μš”μ²­μ„ μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄μ„œ μ‹±κΈ€ μŠ€λ ˆλ“œ 방식을 ν†΅ν•΄μ„œ 단일 μš”μ²­μ„ 순차적으둜 μ²˜λ¦¬ν•˜λŠ”κ²Œ 기본적인 기술 κ΄€μ μž…λ‹ˆλ‹€. μ΄λŠ” λ ˆλ””μŠ€μ—μ„œ λ™μ‹œμ„±μ„ κ΅¬ν˜„ν•˜κΈ° μœ„ν•΄μ„œ μ±„νƒν•œ 방법이기도 ν•˜λ―€λ‘œ λ‹¨μˆœνžˆ μ‹±κΈ€ μŠ€λ ˆλ“œμ—¬μ„œ λ¬Έμ œκ°€ μžˆλ‹€κ³  바라보면 μ•ˆλ©λ‹ˆλ‹€.

exec 0 ms (481900 ns)

μ‹œκ³„μ—΄ λ°μ΄ν„°λ² μ΄μŠ€κ°€ 아무리 λΉ λ₯΄λ‹€κ³  해도 κΈ΄ λ²”μœ„μ˜ μ‹œκ³„μ—΄ 데이터λ₯Ό μ‘°νšŒν•˜κ³  연산을 ν•œλ‹€κ±°λ‚˜ TCP μ†ŒμΌ“μ„ 톡해 전달해야할 데이터가 μƒλ‹Ήνžˆ λ§Žμ€ 경우라면 μ‹±κΈ€ μŠ€λ ˆλ“œμ˜ λ‹¨μ μœΌλ‘œ μΈν•˜μ—¬ μ„ ν–‰ μš”μ²­μ— μ˜ν•΄ ν›„ν–‰ μš”μ²­μ΄ κΈ°λ‹€λ¦¬λŠ” μ‹œκ°„μœΌλ‘œ 인해 병λͺ© ν˜„μƒμ΄ λ°œμƒν•  수 μžˆλ‹€λŠ” 점을 κ³ λ €ν•΄μ•Όν•©λ‹ˆλ‹€. λ§Œμ•½, κ·ΈλŸ¬ν•œ 상황이 자주 λ°œμƒν•œλ‹€λ©΄ λΉ λ₯Έ μ„±λŠ₯을 μœ„ν•΄ μ‹±κΈ€ μŠ€λ ˆλ“œλ₯Ό μ±„νƒν•œ μ‹œκ³„μ—΄ λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό ν™œμš©ν•˜λŠ” 방법이 잘λͺ»λœ 것일 수 μžˆμŠ΅λ‹ˆλ‹€.

KDB μ‹œκ³„μ—΄ λ°μ΄ν„°λ² μ΄μŠ€μ™€ 컀λ„₯μ…˜ ν’€ λ™μž‘μ— λŒ€ν•΄μ„œ ν™•μΈν•˜κ³  μ‹Άλ‹€λ©΄ μ•„λž˜μ˜ 링크듀을 μ°Έκ³ ν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€.