Skip to content

Latest commit

ย 

History

History
579 lines (426 loc) ยท 29.4 KB

File metadata and controls

579 lines (426 loc) ยท 29.4 KB

ARCUS Java Client

ARCUS Client ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ARCUS java client ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•์„ ์•Œ์•„๋ณธ๋‹ค. ์•„๋ž˜ ์˜ˆ์ œ๋Š” ARCUS cache์— key๊ฐ€ โ€œsample:testKeyโ€์ด๊ณ  value๊ฐ€ โ€œtestValueโ€์ธ cache item์„ ์ €์žฅํ•œ๋‹ค.

package com.navercorp.arcus.example; 

import java.util.concurrent.ExecutionException; 
import java.util.concurrent.Future; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.TimeoutException; 
import net.spy.memcached.ArcusClient; 
import net.spy.memcached.ConnectionFactoryBuilder; 

public class HelloArcus { 

    private static final String ARCUS_ADMIN = "10.0.0.1:2181,10.0.0.2:2181,10.0.0.3:2181"; 
    private static final String SERVICE_CODE = "test"; 
    private final ArcusClient arcusClient; 

    public static void main(String[] args) { 
        HelloArcus hello = new HelloArcus(); 
        System.out.printf("hello.setTest() result=%b", hello.setTest()); 
        hello.closeArcusConnection(); 
    } 

    public HelloArcus() { 
        arcusClient = ArcusClient.createArcusClient(ARCUS_ADMIN, SERVICE_CODE, 
                new ConnectionFactoryBuilder()); // (1) 
    } 

    public boolean setTest() { 
        Future<Boolean> future = null; 
        try { 
            future = arcusClient.set("sample:testKey", 10, "testValue"); // (2) 
        } catch (IllegalStateException e) { 
            // client operation queue ๋ฌธ์ œ๋กœ ์š”์ฒญ์ด ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜์„ ๋•Œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ. 
        } 

        if (future == null) return false; 

        try { 
            return future.get(500L, TimeUnit.MILLISECONDS); // (3) 
        } catch (TimeoutException te) { // (4) 
            future.cancel(true); 
        } catch (ExecutionException re) { // (5) 
            future.cancel(true); 
        } catch (InterruptedException ie) { // (6) 
            future.cancel(true); 
        } 

        return false; 
    } 

    public void closeArcusConnection() { 
        arcusClient.shutdown(); // (7) 
    } 
} 

(1) ArcusClient ํด๋ž˜์Šค์˜ ๊ฐ์ฒด(client ๊ฐ์ฒด)๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. Client ๊ฐ์ฒด๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๋ฏธ๋ฆฌ ํ•˜๋‚˜๋ฅผ ๋งŒ๋“ค์–ด ์žฌํ™œ์šฉํ•˜๋„๋ก ํ•œ๋‹ค. ARCUS์— ์ ‘์†ํ•  ๋•Œ, ๊ฐ์ข… ์„ค์ •์„ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด์„œ ConnectionFactoryBuilder๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

  • ์ž˜๋ชป๋œ SERVICE_CODE๋ฅผ ์ง€์ •ํ–ˆ๋‹ค๋ฉด NotExistsServiceCodeException์ด ๋ฐœ์ƒํ•œ๋‹ค.
  • SERVICE_CODE๋Š” ์˜ฌ๋ฐ”๋ฅด์ง€๋งŒ ์ ‘์† ๊ฐ€๋Šฅํ•œ cache ์„œ๋ฒ„(๋˜๋Š” ๋…ธ๋“œ)๊ฐ€ ์—†๋‹ค๋ฉด, ๋ชจ๋“  ์š”์ฒญ์€ Exception์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. Cache ์„œ๋ฒ„๊ฐ€ ๊ตฌ๋™๋˜์–ด ์ ‘์†์ด ๊ฐ€๋Šฅํ•ด์ง€๋ฉด, ์ž๋™์œผ๋กœ ํ•ด๋‹น cache ์„œ๋ฒ„๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ์ •์ƒ ์„œ๋น„์Šคํ•˜๊ฒŒ ๋œ๋‹ค.

(2) Client ๊ฐ์ฒด์˜ set ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ Boolean ๊ฐ’์„ ๊ฐ–๋Š” Future ํด๋ž˜์Šค์˜ ๊ฐ์ฒด(future ๊ฐ์ฒด)๋กœ ๋ฐ›๋Š”๋‹ค.

  • ์ €์žฅํ•  ๊ฐ’์œผ๋กœ ""(๊ธธ์ด๊ฐ€ 0์ธ ๋ฌธ์ž์—ด)์„ ๋„ฃ์œผ๋ฉด, ""์ด ๊ทธ๋Œ€๋กœ ์ €์žฅ๋œ๋‹ค. (ํ•ด๋‹น key๊ฐ€ ์‚ญ์ œ๋˜์ง€ ์•Š๋Š”๋‹ค.)
  • ์ €์žฅํ•  ๊ฐ’์œผ๋กœ null์„ ์ง€์ •ํ•  ์ˆ˜ ์—†๋‹ค. (key ์‚ญ์ œ ์˜๋„์ด๋ฉด, delete ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.)
  • ์ €์žฅํ•  ๊ฐ’์€ serializableํ•ด์•ผ ํ•œ๋‹ค. (์‚ฌ์šฉ์ž ์ •์˜ ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ Serializable ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.)

(3) Future ๊ฐ์ฒด์˜ ๊ฐ’์„ ๋ฐ›์•„์„œ result์— ๋‹ด๋Š”๋‹ค. (๋งŒ์•ฝ set ์ž‘์—…์ด ์‹คํŒจํ•˜์˜€์„ ๊ฒฝ์šฐ์—๋Š” false๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.)

  • Cache ์„œ๋ฒ„์— key๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ๋‹ค์‹œ ๋งํ•ด cache miss์ด๋ผ๋ฉด, null์ด ๋ฐ˜ํ™˜๋œ๋‹ค.
  • ๊ธธ์ด๊ฐ€ 0์ธ ๋ฌธ์ž์—ด(โ€œโ€)์€ cache miss๊ฐ€ ์•„๋‹ˆ๊ณ  โ€œโ€๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

(4) ์ง€์ •ํ•œ ์‹œ๊ฐ„์— ๊ฒฐ๊ณผ๊ฐ€ ๋„˜์–ด ์˜ค์ง€ ์•Š๊ฑฐ๋‚˜ JVM์˜ ๊ณผ๋ถ€ํ•˜๋กœ operation queue์—์„œ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์„ ๊ฒฝ์šฐ TimeoutException์ด ๋ฐœ์ƒํ•œ๋‹ค.

  • ์˜ˆ๋ฅผ ๋“ค์–ด, timeout ์‹œ๊ฐ„์„ 500ms๋กœ ์ง€์ •ํ–ˆ๋Š”๋ฐ GC time์ด 600ms๊ฑธ๋ ธ๋‹ค๋ฉด ARCUS cache ์„œ๋ฒ„์™€ ํ†ต์‹ ์— ๋ฌธ์ œ๊ฐ€ ์—†์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  100ms๋ฅผ ์ดˆ๊ณผํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— TimeoutException์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.
  • TimeoutException์ด ์—ฐ์†ํ•ด์„œ n(๋””ํดํŠธ๋Š” 10)ํšŒ ์ด์ƒ ๋ฐœ์ƒํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์„ ๋Š๊ณ  ์žฌ์ ‘์†ํ•œ๋‹ค. ์—ฌ๊ธฐ์—์„œ n๋ฒˆ์˜ ๊ฐ’์€ ConnectionFactoryBuilder๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋˜ํ•œ, ๋ชจ๋“  Exception์ด ๋ฐœ์ƒํ•œ ์ƒํ™ฉ์—์„œ๋Š” future.cancel(true)๋ฅผ ๋ฐ˜๋“œ์‹œ ํ˜ธ์ถœํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

(5) ArcusClient์˜ operation queue์— ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๋˜ ์ž‘์—…์ด ์ทจ์†Œ๋˜์—ˆ์„ ๋•Œ, ExecutionException์ด ๋ฐœ์ƒํ•œ๋‹ค. ExecutionException์€ ์„œ๋ฒ„ ๋˜๋Š” ๋„คํŠธ์›Œํฌ ์žฅ์•  ์‹œ ๋ฐœ์ƒํ•œ๋‹ค.

(6) ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ํ•ด๋‹น ์“ฐ๋ ˆ๋“œ์˜ ์ž‘์—…์„ Interruptํ–ˆ์„ ๋•Œ InterruptedException์ด ๋ฐœ์ƒํ•œ๋‹ค. (๋ฐœ์ƒํ•  ์—ฌ์ง€๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค.)

(7) ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒํ•˜๊ธฐ ์ „์— ๋” ์ด์ƒ ArcusClient๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ๋ฐ˜๋“œ์‹œ shutdown ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์„œ๋ฒ„์™€์˜ ์—ฐ๊ฒฐ์„ ๋Š์–ด์•ผ ํ•œ๋‹ค.

  • Tomcat๊ณผ ๊ฐ™์€ WAS์—์„œ๋Š” Tomcat์ด shutdown์ด ๋  ๋•Œ shutdown ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ฒŒ ํ•˜๋ฉด ๋œ๋‹ค.
  • Spring container์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ๊ฒฝ์šฐ bean ์„ค์ •์˜ destroy-method์—์„œ shutdown ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋„๋ก ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

ARCUS Client ์ƒ์„ฑ, ์†Œ๋ฉธ, ๊ด€๋ฆฌ

ARCUS Client ์ƒ์„ฑ

ํ•˜๋‚˜์˜ ARCUS Client ๊ฐ์ฒด๋Š” ARCUS cache cloud์— ์žˆ๋Š” ๋ชจ๋“  cache server(or cache node)์™€ ์—ฐ๊ฒฐ์„ ํ•˜๋‚˜์”ฉ ์ƒ์„ฑํ•˜๋ฉฐ, ์š”์ฒญ๋˜๋Š” ๊ฐ cache item์˜ key์— ๋Œ€ํ•ด ๊ทธ key๊ฐ€ mapping๋˜๋Š” cache server์™€์˜ ์—ฐ๊ฒฐ์„ ์ด์šฉํ•˜์—ฌ request๋ฅผ ๋ณด๋‚ด๊ณ  response๋ฅผ ๋ฐ›๋Š”๋‹ค.

ARCUS Client ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค.

  • ๋‹จ์ผ ARCUS Client ์ƒ์„ฑ
  • ARCUS Client Pool ์ƒ์„ฑ

๋จผ์ €, ๋‹จ์ผ ARCUS Client ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

ArcusClient.createArcusClient(String arcusAdminAddress, String serviceCode, ConnectionFactoryBuilder cfb)
  • arcusAdminAddress: ์ ‘๊ทผํ•  cache cloud๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ARCUS zookeeper ensemble ์ฃผ์†Œ
    • IP:port ๋ฆฌ์ŠคํŠธ์ธ "ip1:port,ip2:port,ip3:port" ํ˜•ํƒœ๋กœ ์ง€์ •ํ•˜๊ฑฐ๋‚˜
    • "FQDN:port" ํ˜•ํƒœ๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. (zookeeper IP list์— ๋Œ€ํ•œ domain name์„ DNS์— ๋“ฑ๋กํ•œ ๊ฒฝ์šฐ)
  • serviceCode: ์ ‘์†ํ•  cache cloud์˜ ์‹๋ณ„์ž
  • cfb: ARCUS client์˜ ๋™์ž‘ ์„ค์ •์„ ์œ„ํ•œ ConnectionFactoryBuilder ๊ฐ์ฒด

ARCUS_ADMIN ์„œ๋ฒ„์—์„œ ๊ด€๋ฆฌ๋˜๋Š” SERVICE_CODE์— ํ•ด๋‹นํ•˜๋Š” cache cloud๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ํ•˜๋‚˜์˜ ArcusClient ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์˜ˆ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

ConnectionFactoryBuilder cfb = new ConnectionFactoryBuilder();
ArcusClient client = ArcusClient.createArcusClient(ARCUS_ADMIN, SERVICE_CODE, cfb);

ํ•˜๋‚˜์˜ ARCUS Client๋งŒ์œผ๋กœ๋Š” ์‘์šฉ์˜ requests๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ์šฉ๋Ÿ‰ ์ฆ‰, throughput์— ํ•œ๊ณ„๊ฐ€ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ํ•˜๋‚˜์˜ ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ํ•˜๋‚˜์˜ request๊ฐ€ ์ฒ˜๋ฆฌ๋˜๋Š” ์‹œ๊ฐ„์ด 1ms๋ผ ๊ฐ€์ •ํ•˜๋ฉด, ๊ทธ ์—ฐ๊ฒฐ์„ ํ†ตํ•ด ์ตœ๋Œ€ 1000 requests/second ๋ฐ–์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ, ๋งŽ์€ ์š”์ฒญ ์ฒ˜๋ฆฌ๋Ÿ‰์ด ํ•„์š”ํ•œ ์‘์šฉ์ธ ๊ฒฝ์šฐ๋Š” ๋‹ค์ˆ˜์˜ ARCUS client ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ARCUS client pool ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•„๋ž˜์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ƒ์„ฑํ•œ๋‹ค.

ArcusClient.createArcusClientPool(String arcusAdminAddress, String serviceCode, ConnectionFactoryBuilder cfb, int poolSize);

๋ฉ”์†Œ๋“œ์˜ ์ธ์ž๋กœ ๋‹จ์ผ ARCUS client ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์‹œ์˜ ์ธ์ž๋“ค ์™ธ์— pool์— ๋“ค์–ด๊ฐˆ arcus client ๊ฐ์ฒด ์ˆ˜๋ฅผ ์ง€์ •ํ•˜๋Š” poolSize ์ธ์ž๊ฐ€ ์žˆ๋‹ค. pool size๊ฐ€ ๋„ˆ๋ฌด ์ž‘์œผ๋ฉด ์‘์šฉ ์š”์ฒญ๋“ค์„ ์ œ์‹œ๊ฐ„์— ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ณ , ๋„ˆ๋ฌด ํฌ๋ฉด arcus cache server๋กœ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋งŽ์€ ์—ฐ๊ฒฐ์„ ๋งบ๊ฒŒ ํ•œ๋‹ค. ์ ์ ˆํ•œ pool size๋Š” "์‘์šฉ ์„œ๋ฒ„์˜ peak arcus request ์š”์ฒญ๋Ÿ‰"์„ "ํ•˜๋‚˜์˜ arcus client์˜ ์ฒ˜๋ฆฌ๋Ÿ‰"์œผ๋กœ ๋‚˜๋ˆ„๋ฉด ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ, ํ•˜๋‚˜์˜ arcus client๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์ฒ˜๋ฆฌ๋Ÿ‰์€ ์‘์šฉ ์„œ๋ฒ„๊ฐ€ ์š”์ฒญํ•˜๋Š” arcus request ์œ ํ˜•๊ณผ ์‘์šฉ ์„œ๋ฒ„์™€ cache server ๊ฐ„์˜ ๋„คํŠธ์› ์ƒํƒœ ๋“ฑ์— ์˜ํ–ฅ๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์‹ค์ œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ด ๋ณด๊ณ  pool size๋ฅผ ๊ฒฐ์ •ํ•˜๊ธธ ๊ถŒํ•œ๋‹ค.

ํŠน์ • SERVICE_CODE์— ํ•ด๋‹นํ•˜๋Š” cache cloud๋กœ ์—ฐ๊ฒฐ๋˜๋Š” ARCUS client 4 ๊ฐœ๋ฅผ ๊ฐ€์ง€๋Š” pool์„ ์ƒ์„ฑํ•˜๋Š” ์˜ˆ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

int poolSize = 4;
ConnectionFactoryBuilder cfb = new ConnectionFactoryBuilder();
ArcusClientPool pool = ArcusClient.createArcusClientPool(ARCUS_ADMIN, SERVICE_CODE, cfb, poolSize);

ARCUS client ๊ฐ์ฒด๋ฅผ ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋ฉด, ์•„๋ž˜์˜ ๋กœ๊ทธ์™€ ๊ฐ™์ด cache cloud์™€ ์ •์ƒ ์—ฐ๊ฒฐ๋จ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

WARN net.spy.memcached.CacheManager: All arcus connections are established.

ARCUS cache cloud๋กœ ์ •์ƒ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์œผ๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋กœ๊ทธ๊ฐ€ ๋ณด์ธ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 5๋Œ€์˜ Cache server์— ์ ‘์†์„ ํ•ด์•ผ ํ•˜๋Š”๋ฐ ์ด๋“ค ์ค‘ ์ผ๋ถ€ ์„œ๋ฒ„์— ์ ‘์†ํ•˜์ง€ ๋ชปํ–ˆ๋‹ค๋ฉด ์•„๋ž˜ ๋กœ๊ทธ๊ฐ€ ๋‚จ๊ฒŒ ๋œ๋‹ค. ์ ‘์† ์‹คํŒจํ•œ cache server์— ๋Œ€ํ•ด์„œ๋Š” ARCUS client๊ฐ€ 1์ดˆ์— ํ•œ ๋ฒˆ์”ฉ ์ž๋™์œผ๋กœ ์žฌ์—ฐ๊ฒฐ์„ ์‹œ๋„ํ•œ๋‹ค.

WARN net.spy.memcached.CacheManager: Some arcus connections are not established.

ARCUS Client ์†Œ๋ฉธ

ArcusClient ๋˜๋Š” ArcusClientPool๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋‚œ ๋‹ค์Œ์—๋Š” ๋ฐ˜๋“œ์‹œ shutdown() ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ client์™€ admin, cache server๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ํ•ด์ œ์‹œ์ผœ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

client.shutdown();
pool.shutdown();

ARCUS Client ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ

Arcus์— ๋Œ€ํ•œ ๋งค ์š”์ฒญ๋งˆ๋‹ค arcus client ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์†Œ๋ฉธ์‹œํ‚ค๋Š” ๊ฒƒ์€ ์ ์ ˆํ•˜์ง€ ๋ชปํ•˜๋‹ค. ์‘์šฉ ์„œ๋ฒ„์˜ ๊ตฌ๋™ ์‹œ์— arcus client ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์ข…๋ฃŒ ์‹œ์— arcus client ๊ฐ์ฒด๋ฅผ ์†Œ๋ฉธํ•˜๋ฉด ๋œ๋‹ค.

์ผ๋ฐ˜์ ์œผ๋กœ, ์‘์šฉ์—์„œ๋Š” ArcusClient wrapper๋ฅผ ๋งŒ๋“ค์–ด ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ArcusClient์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์ˆ˜์›”ํ•ด์ง„๋‹ค. Service code๋ณ„ ArcusClient instance๋ฅผ ๊ฐ€์ง€๋Š” factory๋ฅผ singleton์œผ๋กœ ๋งŒ๋“ค์–ด๋‘๊ณ  WAS๊ฐ€ ์ดˆ๊ธฐํ™” ๋  ๋•Œ Arcus server ์™€ ์—ฐ๊ฒฐ์„ ๋งบ๋„๋ก ํ•˜์ž. WAS๊ฐ€ shutdown๋  ๋•Œ ArcusClient๋„ ํ•จ๊ป˜ shutdown๋˜๋„๋ก ์„ค์ •ํ•˜๋ฉด ๊ฐ€์žฅ ์ด์ƒ์ ์ด๋‹ค.

Cache Server List ๊ด€๋ฆฌ

ARCUS๋Š” cache server list๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค. Cache server๋“ค ์ค‘์— ์ผ๋ถ€ ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ ๋ถˆ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ARCUS admin์ด ์ž๋™์œผ๋กœ ์ƒํ™ฉ์„ ์ธ์ง€ํ•˜๊ณ  ํ•ด๋‹น ์„œ๋ฒ„๋ฅผ cache server list์—์„œ ์ œ๊ฑฐํ•˜๋ฉฐ, ๋ณ€๊ฒฝ๋œ cache server list๊ฐ€ ์žˆ์Œ์„ ๊ฐ arcus client์— ์•Œ๋ฆผ์œผ๋กœ์จ ๊ฐ arcus client๊ฐ€ ์ตœ์‹ ์˜ cache server list๋ฅผ ์œ ์ง€ํ•˜๊ฒŒ ํ•œ๋‹ค. ๋ฐ˜๋Œ€๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ cache server๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ์—๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ, ARCUS admin์˜ ๋„์›€์œผ๋กœ ARCUS client๋Š” ์ตœ์‹ ์˜ cache server list๋ฅผ ์œ ์ง€ํ•˜๊ณ , cache key์™€ cache server์™€์˜ mapping์„ ๊ฐฑ์‹ ํ•˜๊ฒŒ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, ARCUS client๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ cache server ๋Œ€์ˆ˜์˜ ๋ณ€ํ™”์— ๋Œ€ํ•œ ๋ฐฉ์–ด ๋กœ์ง์€ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

ARCUS Client ์„ค์ •

Key-Value์—์„œ ๋ฐ์ดํ„ฐ ์••์ถ• ์„ค์ •

ARCUS client๋Š” key-value item์˜ ๋ฐ์ดํ„ฐ ์••์ถ• ๋ฐ ํ•ด์ œ ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์ฆ‰, ์ผ์ • ํฌ๊ธฐ ์ด์ƒ์˜ ๋ฐ์ดํ„ฐ์ด๋ฉด ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์••์ถ•ํ•˜์—ฌ cache server์— ๋ณด๋‚ด์–ด ์ €์žฅํ•˜๊ณ , cache server๋กœ ๋ถ€ํ„ฐ ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๊ฐ€ ์••์ถ• ๋ฐ์ดํ„ฐ์ด๋ฉด, ํ•ด์ œํ•˜์—ฌ ์‘์šฉ์— ์ „๋‹ฌํ•œ๋‹ค.

ARCUS client๋Š” ์ €์ •ํ•  ๊ฐ’์˜ ํฌ๊ธฐ๊ฐ€ 16KB ์ด์ƒ์ผ ๊ฒฝ์šฐ์— ์••์ถ•ํ•˜์—ฌ cache server์— ์ €์žฅํ•˜๋„๋ก ๋˜์–ด ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐ์ดํ„ฐ ์••์ถ• ์ž„๊ณ„๊ฐ’์€ ConnectionFactoryBuilder์˜ setTranscoder๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค์Œ์€ 4KB ์ด์ƒ์˜ ๋ฐ์ดํ„ฐ๋Š” ๋ชจ๋‘ ์••์ถ•ํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ์˜ˆ์ œ์ด๋‹ค.

ConnectionFactoryBuilder cfb = new ConnectionFactoryBuilder();

SerializingTranscoder trans = new SerializingTranscoder();
trans.setCharset(โ€œUTF-8โ€);
trans.setCompressionThreshold(4096);

cfb.setTranscoder(trans);

ArcusClient client = ArcusClient.createArcusClient(SERVICE_CODE, cfb);

Logger ์„ค์ •

ARCUS client ์‚ฌ์šฉ ์‹œ์— default(DefaultLogger), log4j(Log4JLogger), slf4j(SLF4JLogger), jdk(SunLogger) ๋“ฑ 4๊ฐ€์ง€ ์ข…๋ฅ˜์˜ Logger๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉํ•  logger๋ฅผ ์ง€์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ArcusClient๋Š” DefaultLogger๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ฉฐ, DefaultLogger๋Š” INFO level ์ด์ƒ์˜ ๋กœ๊ทธ๋ฅผ stderr (System.err) ๋กœ ์ถœ๋ ฅํ•œ๋‹ค. (๋ณ€๊ฒฝ ๋ถˆ๊ฐ€)

log4j๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ArcusClient ๋กœ๊ทธ๋ฅผ ๊ด€๋ฆฌํ•˜๋ ค๋ฉด, ์•„๋ž˜ ์˜ต์…˜์„ WAS๋‚˜ ์ž๋ฐ” ํ”„๋กœ์„ธ์Šค ์˜ต์…˜์— ์ถ”๊ฐ€ํ•˜์—ฌ JVM ๊ตฌ๋™์‹œ System property๋ฅผ ์ง€์ •ํ•œ๋‹ค.

-Dnet.spy.log.LoggerImpl=net.spy.memcached.compat.log.Log4JLogger

๋˜๋Š”, ์†Œ์Šค ์ฝ”๋“œ์—์„œ ArcusClient / ArcusClientPool์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์ง์ ‘ System property๋ฅผ ์„ค์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. (programmatic configuration)

System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.Log4JLogger");
...
ConnectionFactoryBuilder cfb = new ConnectionFactoryBuilder();
ArcusClient client = ArcusClient.createArcusClient(SERVICE_CODE, cfb);

ARCUS Java client์—์„œ๋Š” Log๋ฅผ ๊ธฐ๋กํ•  ๋•Œ Class์˜ ์ด๋ฆ„(clazz.getName())์„ ๊ธฐ์ค€์œผ๋กœ Logger๋ฅผ ๊ตฌ๋ถ„ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉฐ, class์˜ ์ด๋ฆ„๊ณผ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๋กœ๊ฑฐ๊ฐ€ ์—†๋‹ค๋ฉด logger tree ์ƒ์˜ ์ƒ์œ„ logger ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์•„๋ž˜์˜ ์˜ˆ์ œ๋Š” root logger ์˜ level์„ WARN์œผ๋กœ ์„ค์ •ํ•˜์—ฌ WARN level ์ด์ƒ์˜ ๋กœ๊ทธ๋Š” ํ•ญ์ƒ ๊ธฐ๋กํ•˜๊ณ , net.spy.memcached.protocol.ascii.CollectionUpdateOperationImpl class์˜ ๋กœ๊ทธ๋งŒ DEBUG level ์ด์ƒ์˜ ๋กœ๊ทธ๋ฅผ ๊ธฐ๋กํ•˜๋„๋ก ํ•œ ์˜ˆ์ œ์ด๋‹ค.

<Root level="WARN">
    <AppenderRef ref="console" />
</Root>
<Logger name="net.spy.memcached.protocol.ascii.CollectionUpdateOperationImpl" additivity="false" level="DEBUG">
    <AppenderRef ref="console" />
</Logger>

Application์„ ๋””๋ฒ„๊น…ํ•ด์•ผ ํ•  ๋•Œ ARCUS client์—์„œ Arcus server๋กœ ์ „์†กํ•˜๋Š” ascii protocol ๋ฌธ์ž์—ด์ด ๊ถ๊ธˆํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ARCUS Java Client์—์„œ ARCUS server๋กœ ์ „์†กํ•˜๋Š” protocol์„ ๋กœ๊ทธ๋กœ ์‚ดํŽด๋ณด๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด logger๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค. ์˜ˆ์ œ์— ๋‚˜์—ด๋œ logger๋ฅผ ๋ชจ๋‘ ์„ค์ •ํ•˜๋ฉด ์š”์ฒญ(get, set ๋“ฑ..)๋ณ„๋กœ ๋ชจ๋“  ๋กœ๊ทธ๊ฐ€ ๋‚จ๊ฒŒ ๋˜๋‹ˆ ํ•„์š”ํ•œ ์š”์ฒญ์— ํ•ด๋‹นํ•˜๋Š” logger๋งŒ ์„ค์ •ํ•˜๋ฉด ํŽธ๋ฆฌํ•˜๋‹ค. Ascii Protocol์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ARCUS ์„œ๋ฒ„ ๋ช…๋ น ํ”„๋กœํ† ์ฝœ ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

<!-- collection update -->
<Logger name="net.spy.memcached.protocol.ascii.CollectionUpdateOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

<!-- collection piped exist -->
<Logger name="net.spy.memcached.protocol.ascii.CollectionPipedExistOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

<!-- set attributes -->
<Logger name="net.spy.memcached.protocol.ascii.SetAttrOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

<!-- collection insert -->
<Logger name="net.spy.memcached.protocol.ascii.CollectionInsertOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

<!-- collection get -->
<Logger name="net.spy.memcached.protocol.ascii.CollectionGetOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

<!-- collection update -->
<Logger name="net.spy.memcached.protocol.ascii.CollectionUpdateOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

<!-- collection count -->
<Logger name="net.spy.memcached.protocol.ascii.CollectionCountOperationImpl" level="DEBUG" additivity="false">
    <AppenderRef ref="console" />
</Logger>

๊ธฐํƒ€ log4j์˜ ์ž์„ธํ•œ ์„ค์ • ๋ฐฉ๋ฒ•์€ log4j ์„ค์ • ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

Log4JLogger ์‚ฌ์šฉ์‹œ ์œ ์˜์‚ฌํ•ญ

log4j 1.2 ์ดํ•˜ ๋ฒ„์ „์—์„œ ๋ณด์•ˆ ์ทจ์•ฝ์ ์ด ์กด์žฌํ•˜์—ฌ, ARCUS client์˜ 1.11.5 ๋ฒ„์ „๋ถ€ํ„ฐ Log4JLogger๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด log4j2 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์š”๊ตฌ๋œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์‘์šฉ ์˜์กด์„ฑ์— ์•„๋ž˜์™€ ๊ฐ™์ด log4j2 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.8.2</version>
</dependency>

๋งŒ์•ฝ ์•„๋ž˜์™€ ๊ฐ™์€ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒ๋˜๋ฉด, log4j2 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํด๋ž˜์ŠคํŒจ์Šค์— ์กด์žฌํ•˜์ง€ ์•Š์€ ๊ฒƒ์ด๋‹ค. log4j2 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์‘์šฉ ์˜์กด์„ฑ์— ์ œ๋Œ€๋กœ ์ถ”๊ฐ€๊ฐ€ ๋๋Š”์ง€ ํ™•์ธํ•˜๋„๋ก ํ•œ๋‹ค.

Warning:  net.spy.memcached.compat.log.Log4JLogger not found while initializing net.spy.compat.log.LoggerFactory
java.lang.NoClassDefFoundError: org/apache/logging/log4j/spi/ExtendedLogger
    at java.base/java.lang.Class.forName0(Native Method)
    at java.base/java.lang.Class.forName(Class.java:315)
    at net.spy.memcached.compat.log.LoggerFactory.getConstructor(LoggerFactory.java:134)
    at net.spy.memcached.compat.log.LoggerFactory.getNewInstance(LoggerFactory.java:119)
    at net.spy.memcached.compat.log.LoggerFactory.internalGetLogger(LoggerFactory.java:100)
    at net.spy.memcached.compat.log.LoggerFactory.getLogger(LoggerFactory.java:89)
    at net.spy.memcached.ArcusClient.<clinit>(ArcusClient.java:183)
    at Main.main(Main.java:10)

SLF4JLogger ์‚ฌ์šฉ์‹œ ์œ ์˜ ์‚ฌํ•ญ

slf4j๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ARCUS client์˜ SLF4JLogger ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. ์ด ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด slf4j๋ฅผ ๊ตฌํ˜„ํ•œ ๋กœ๊น… ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์‘์šฉ ์˜์กด์„ฑ์— ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•œ๋‹ค. ๋งŒ์•ฝ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ์•„๋ž˜์˜ ์˜ˆ์™ธ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

log4j, logback๊ณผ ๊ฐ™์€ ๋Œ€ํ‘œ์ ์ธ ์ž๋ฐ”์˜ ๋กœ๊ทธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ slf4j api๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค. ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์‘์šฉ ์˜์กด์„ฑ์— ์ถ”๊ฐ€ํ•˜๋„๋ก ํ•œ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ slf4j ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•œ๋‹ค.

<!-- slf4j + log4j ์‚ฌ์šฉ์‹œ -->
<dependency>
    <groupId>com.navercorp.arcus</groupId>
    <artifactId>arcus-java-client</artifactId>
    <version>${arcus-java-client.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>${log4j.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>${log4j.version}</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j-impl</artifactId>
    <version>${log4j.version}</version>
</dependency>
<!-- slf4j + logback ์‚ฌ์šฉ์‹œ -->
<dependency>
    <groupId>com.navercorp.arcus</groupId>
    <artifactId>arcus-java-client</artifactId>
    <version>${arcus-java-client.version}</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>${logback.version}</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-core</artifactId>
    <version>${logback.version}</version>
</dependency>

๋˜ํ•œ 2๊ฐœ ์ด์ƒ์˜ slf4j์˜ ๊ตฌํ˜„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(log4j-slf4j-impl, logback-classic, ...)๋“ค์ด ๊ฐ™์€ ํด๋ž˜์ŠคํŒจ์Šค์— ์กด์žฌํ•  ๊ฒฝ์šฐ, SLF4J์—์„œ multiple binding error๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ ๋ฐ˜๋“œ์‹œ exclusion ํ‚ค์›Œ๋“œ๋ฅผ ์ด์šฉํ•ด slf4j ๊ตฌํ˜„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๋„๋ก ํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

Transparent Front Cache ์‚ฌ์šฉ

ARCUS๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์›๊ฒฉ Cache ์‹œ์Šคํ…œ์ด๋ฏ€๋กœ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒดํ™”ํ•ด์•ผ ํ•˜๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค. ์ด๋Š” ๊ฒฐ๊ตญ JVM์˜ Garbage Collector์— ๋ถ€๋‹ด์œผ๋กœ ์ž‘์šฉํ•  ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ๋งŒ์•ฝ ์‹ค์ œ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฑฐ์˜ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๊ณ , ๋ณ€๊ฒฝ์ด ์žˆ๋”๋ผ๋„ ์•„์ฃผ ์งง์€ ์‹œ๊ฐ„ ๋‚ด์—๋Š” ์ด์ „ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค˜๋„ ์ƒ๊ด€์—†๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด Front Cache๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ณ ๋ คํ•ด ๋ณผ ๋งŒ ํ•˜๋‹ค.

Front cache๋ฅผ ์ด์šฉํ•˜๋ ค๋ฉด Remote Cache์—์„œ Hit๊ฐ€ ๋˜์—ˆ์„ ๊ฒฝ์šฐ ๋ณ„๋„๋กœ Front Cache ์ €์žฅ์†Œ์— ๊ธฐ๋ก์„ ํ•ด ์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ฝ”๋“œ๊ฐ€ ์ƒ๋‹นํžˆ ์ง€์ €๋ถ„ํ•ด ์ง€๋Š” ๊ฒฝํ–ฅ์ด ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ๋„ ์•„๋ž˜ ๊ทธ๋ฆผ์— ๋‚˜์˜จ ๊ฒƒ์ฒ˜๋Ÿผ ์ œ์ผ ๋จผ์ € Front Cache๋ฅผ ํ™•์ธํ•˜๊ณ  ๋‹ค์Œ์— Remote Cache๋ฅผ ํ™•์ธํ•œ๋‹ค๋ฉด ์ด ๋˜ํ•œ ํ”„๋กœ๊ทธ๋žจ์ด ๋ณต์žกํ•ด์ ธ ๋ฒ„๋ฆฐ๋‹ค.

Alt Text

๋”ฐ๋ผ์„œ Transparentํ•˜๊ฒŒ ์ฆ‰, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—์„œ ์•Œ์•„์„œ Front Cache๋ฅผ ํ™œ์„ฑํ™”ํ•˜์—ฌ JVM์—์„œ ์ผ์ • ์‹œ๊ฐ„ Item์„ ๋ณด๊ด€ํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค๋ฉด ํŽธ๋ฆฌํ•˜๋ฉด์„œ๋„ ๋ณด๋‹ค ๋น ๋ฅธ ์‘์šฉ์„ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ARCUS์—๋Š” Ehcache๋ผ๋Š” Local cache ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์ถ”๊ฐ€๋˜์–ด ๋ณต์žกํ•œ ํ”„๋กœ๊ทธ๋žจ ์ž‘์—… ์—†์ด ๋ฐ”๋กœ Front cache๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋˜์–ด ์žˆ๋‹ค. ์‚ฌ์šฉ์ž๋Š” ๊ฐ„๋‹จํ•œ ์˜ต์…˜๋งŒ ์„ค์ •ํ•˜๋ฉด 2๋ฒˆ๊ณผ 3๋ฒˆ ์ž‘์—…์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋‚ด์—์„œ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•œ๋‹ค.

๋‹ค์Œ์€ Front cache๋ฅผ ์‚ฌ์šฉ์„ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋กœ ConnectionFactoryBuilder ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ ์šฉํ•œ๋‹ค.

  • setMaxFrontCacheElements(int to) (Required)

    ์—ฌ๊ธฐ์— ์ ์šฉ๋˜๋Š” ๊ฐ’์€ Front Cache์—์„œ ์‚ฌ์šฉํ•  ์ตœ๋Œ€ Item์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 0์ธ๋ฐ, 0์ด๋ฉด Front Cache๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๋œป์ด๋‹ค. ๋”ฐ๋ผ์„œ Front Cache๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ์–‘์˜ ์ •์ˆ˜๊ฐ’์„ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค. ๋งŒ์•ฝ ์ตœ๋Œ€ Item ์ˆ˜๋ฅผ ์ดˆ๊ณผํ•˜๋ฉด LRU ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด ๊ฐ€์žฅ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” Item์„ ์ œ๊ฑฐํ•˜๊ณ  ์ƒˆ๋กœ์šด Item์„ ๋“ฑ๋กํ•˜๊ฒŒ ๋œ๋‹ค.

  • setFrontCacheExpireTime(int to) (Optional, default 5)

    Front Cache item์˜ expire time์ด๋‹ค. Front cache๋Š” item๋ณ„ expire time์„ ์„ค์ •ํ•˜์ง€ ์•Š๊ณ , ๋“ฑ๋ก๋œ ๋ชจ๋“  item์— ๋™์ผํ•œ expire time์ด ์ ์šฉ๋œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 5์ด๋ฉฐ ๋‹จ์œ„๋Š” second์ด๋‹ค. ์„ค์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ๊ธฐ๋ณธ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋“ฑ๋ก๋œ ์ง€ 5์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์‚ฌ๋ผ์ง€๊ฒŒ ๋œ๋‹ค.

  • setFrontCacheCopyOnRead(boolean copyOnRead) (Optional, default false)

    Front Cache ์—์„œ Copy Cache ๊ธฐ๋Šฅ์˜ copy on read ์˜ต์…˜์„ ํ™œ์„ฑํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•œ ์„ค์ •์ด๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ false ์ด๋‹ค.

  • setFrontCacheCopyOnWrite(boolean copyOnWrite) (Optional, default false)

    Front Cache ์—์„œ Copy Cache ๊ธฐ๋Šฅ์˜ copy on write ์˜ต์…˜์„ ํ™œ์„ฑํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•œ ์„ค์ •์ด๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ false ์ด๋‹ค.

    EhCache ์˜ Copy Cache ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐ ๋ฐ”๋žŒ.

Front cache ์‚ฌ์šฉ ์ƒ์˜ ์ฃผ์˜ ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Transparent Front Cache๋Š” ํ˜„์žฌ Key-Value get/set์— ๋Œ€ํ•ด์„œ๋งŒ ์ ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Front cache๋Š” remote ARCUS์™€ sync๋ฅผ ๋งž์ถ”์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ๋กœ read-only data๋ฅผ cachingํ•˜๋Š”๋ฐ ์ ํ•ฉํ•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  front caching expire time๋„ remote cache entry update์ฃผ๊ธฐ์— ๋”ฐ๋ผ sync๊ฐ€ ๋งž์ง€ ์•Š๋Š” ๊ธฐ๊ฐ„์„ ์ž˜ ํŒŒ์•…ํ•˜์—ฌ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.
  • Front Cache ๋ฐ์ดํ„ฐ๋Š” flush ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด์„œ flush ๋˜์ง€ ์•Š๋Š”๋‹ค

์•„๋ž˜๋Š” Front cache๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ์ด๋‹ค. setMaxFrontCacheElements๋งŒ 0๋ณด๋‹ค ํฐ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•˜๋ฉด Front Cache๊ฐ€ ํ™œ์„ฑํ™”๋œ๋‹ค. (setFrontCacheExpireTime ๋„ ์‚ฌ์šฉ ์šฉ๋„์— ๋งž๋„๋ก ๋ช…์‹œ์ ์ธ ๊ฐ’์„ ์„ค์ •ํ•ด ์ฃผ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•จ)

ConnectionFactoryBuilder factory = new ConnectionFactoryBuilder();

/* Required to use transparent front cache */
factory.setMaxFrontCacheElements(10000);

/* Optional settings */
factory.setFrontCacheExpireTime(5);
factory.setFrontCacheCopyOnRead(true);
factory.setFrontCacheCopyOnRead(true);

ArcusClient client = new ArcusClient(SERVICE_CODE, factory);

์‘์šฉ์—์„œ ARCUS์— ๋Œ€ํ•ด front cache๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ๋ถ€๋ถ„๊ณผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ๋ถ„๋œ๋‹ค๋ฉด, ๊ฐ ์šฉ๋„์— ๋งž๋Š” ARCUS client ๊ฐ์ฒด๋ฅผ ๋ณ„๋„๋กœ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•œ๋‹ค.

ConnectionFactoryBuilder ํด๋ž˜์Šค์˜ ์ฃผ์š” ๋ฉ”์†Œ๋“œ

  • setFailureMode(FailureMode fm)

    FailureMode๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค. Cancel, Redistrubute, Retry์˜ 3๊ฐœ FailureMode๊ฐ€ ์žˆ์œผ๋ฉฐ, ๊ฐ๊ฐ์˜ ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

    • Cancel : ๋‹ค์šด(down)๋œ ๋…ธ๋“œ์— ์š”์ฒญํ•˜๋Š” ๋ชจ๋“  ์ž‘์—…์„ ์ž๋™์œผ๋กœ ์ทจ์†Œํ•œ๋‹ค.
    • Redistribute : ์—ฌ๋Ÿฌ ๊ฐœ์˜ Node๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ, Request๊ฐ€ ์‹คํŒจํ•˜๋ฉด ๋‹ค์Œ Node์—๊ฒŒ ํ•ด๋‹น Request๋ฅผ ๋‹ค์‹œ ์š”์ฒญํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•ด์„œ Timeout์ด ๋‚  ๋•Œ๊นŒ์ง€ ์ˆ˜ํ–‰ํ•œ๋‹ค. ๋งŒ์•ฝ Node๊ฐ€ ํ•œ ๊ฐœ๋ผ๋ฉด ๋‹ค์Œ Node๋Š” ์ž๊ธฐ ์ž์‹ ์ด ๋œ๋‹ค.
    • Retry : Timeout์ด ๋‚  ๋•Œ๊นŒ์ง€ Request๊ฐ€ ์‹คํŒจํ•˜๋ฉด ๊ณ„์† ํ˜„์žฌ Node์— ์š”์ฒญ์„ ์‹œ๋„ํ•œ๋‹ค

    ARCUS๋Š” Cancel ๋ชจ๋“œ๋ฅผ ๋””ํดํŠธ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. Redistribute๋‚˜ Retry๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, ๋ฐ˜๋ณต์ ์ธ ์š”์ฒญ์— ์˜ํ•ด ์‘์šฉ ์„œ๋ฒ„์— ๋ถ€ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด ์ด๋Ÿฌํ•œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์˜ ์‚ฌ์šฉ์„ ๊ธˆ์ง€ํ•˜๊ณ  ์žˆ๋‹ค.

  • setOpTimeout(long t)

    SpyThread๊ฐ€ ARCUS Cache Server๋กœ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›๋Š” ๋™์•ˆ์˜ ์˜คํผ๋ ˆ์ด์…˜ ํƒ€์ž„์•„์›ƒ์„ ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„๋กœ ์„ค์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์€ 1,000 ๋ฐ€๋ฆฌ์ดˆ์ด๋‹ค. ์ฐธ๊ณ ๋กœ, ์‘์šฉ์ด Callback์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ์„ค์ •ํ•˜๋Š” Timeout์€ โ€œ์˜คํผ๋ ˆ์ด์…˜ ํƒ€์ž„์•„์›ƒ + ๋ช…๋ น์–ด ์ƒ์„ฑ์‹œ๊ฐ„ + ๋ช…๋ น์–ด ๋“ฑ๋ก์‹œ๊ฐ„โ€์„ ํฌํ•จํ•˜๋Š” Timeout์œผ๋กœ ์ด๊ฒƒ๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค.

  • setProtocol(ConnectionFactoryBuilder.Protocol prot)

    ARCUS client์™€ server ์‚ฌ์ด์— ์‚ฌ์šฉํ•  ํ”„๋กœํ† ์ฝœ์„ ์ง€์ •ํ•œ๋‹ค. Text์™€ Binary์˜ ๋‘ ํ”„๋กœํ† ์ฝœ์ด ์žˆ์œผ๋‚˜, ARCUS์—์„œ๋Š” Text ํ”„๋กœํ† ์ฝœ๋งŒ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

  • setMaxReconnectDelay(long to)

    ARCUS์™€ ์—ฐ๊ฒฐ์ด ๋Š๊ฒผ์„ ๊ฒฝ์šฐ ๋‹ค์‹œ ์—ฐ๊ฒฐ์„ ๋งบ๊ธฐ ์œ„ํ•ด์„œ ๋Œ€๊ธฐํ•˜๋Š” ์ตœ๋Œ€ ์‹œ๊ฐ„์„ ์ดˆ ๋‹จ์œ„๋กœ ์ง€์ •ํ•œ๋‹ค. ARCUS๋Š” ๊ธฐ๋ณธ 1์ดˆ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

  • setOpQueueFactory(OperationQueueFactory q)

    ๋ช…๋ น์–ด์˜ ๋‚ด์šฉ์„ ๋‹ด๋Š” operation ํ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ํฌ๊ธฐ๊ฐ€ 16,384์ธ ํ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ํ์˜ ํฌ๊ธฐ๋ฅผ 1000์œผ๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด setOpQueueFactory(new ArrayOperationQueueFactory(1000))์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค.

  • setTranscoder(Transcoder t)

    ์บ์‹œ์˜ ๋ฐ์ดํ„ฐ ์˜์—ญ์— ๋Œ€ํ•œ character set๊ณผ ์••์ถ• ๊ธฐ์ค€์„ ์„ค์ •ํ•œ๋‹ค. GZip ์••์ถ•์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ UTF-8๊ณผ 16,384 byte์ด๋‹ค. ์ฆ‰, ๋ชจ๋“  ์š”์ฒญ์˜ data ์˜์—ญ์€ UTF-8๋กœ encoding/decoding ๋˜๊ณ  data ์˜์—ญ์˜ ํฌ๊ธฐ๊ฐ€ 16,384byte ์ด์ƒ์ด๋ฉด ์••์ถ•ํ•˜์—ฌ ARCUS์™€ ํ†ต์‹ ํ•˜๊ฒŒ ๋œ๋‹ค.

    ๋งŒ์•ฝ, character set์„ EUC-KR๋กœ ์„ค์ •ํ•˜๊ณ  ์••์ถ• ๊ธฐ์ค€์„ 4,096byte๋กœ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•œ๋‹ค.

    SerializingTranscoder trans = new SerializingTranscoder();
    trans.setCharset(โ€œEUC-KRโ€);
    trans.setCompressionThreshold(4096);
    setTranscoder(trans);
  • setShouldOptimize(boolean o)

    ์ตœ์ ํ™” ๋กœ์ง ์‚ฌ์šฉ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•œ๋‹ค. ์ตœ์ ํ™” ๋กœ์ง์€ Operation Queue์— ์ˆœ์„œ๋Œ€๋กœ ์žˆ๋Š” get ์—ฐ์‚ฐ๋“ค์„ multi-get๊ณผ get ์—ฐ์‚ฐ์œผ๋กœ ์กฐํ•ฉํ˜•์œผ๋กœ ํ•œ๊บผ๋ฒˆ์— ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. ARCUS์—์„œ๋Š” optimize ๋กœ์ง ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

  • setReadBufferSize(int to)

    ARCUS server socket๊ณผ ํ†ต์‹ ํ•  ๋•Œ ์‚ฌ์šฉ๋˜๋Š” ์ „์—ญ ByteBuffer ํฌ๊ธฐ๋ฅผ ์„ค์ •ํ•œ๋‹ค. (์ด๋ฆ„์€ Read์ด์ง€๋งŒ ์ฝ๊ธฐ/์“ฐ๊ธฐ ๋ฒ„ํผ์˜ ํฌ๊ธฐ๋Š” ์ด ๊ฐ’์„ ๋”ฐ๋ฅธ๋‹ค) ๋งŒ์•ฝ ByteBuffer ํฌ๊ธฐ๋ฅผ ๋„˜์–ด์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ๋„˜์–ด์˜ค๋ฉด ์žฌ ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ByteBuffer ํฌ๊ธฐ๋งŒํผ ์ฒ˜๋ฆฌํ•œ ํ›„ ByteBuffer์˜ ๋‚ด์šฉ์„ ๋น„์šฐ๊ณ , ๋‹ค์‹œ ์‚ฌ์šฉํ•˜๋„๋ก ๋˜์–ด ์žˆ๋‹ค. ํฌ๊ธฐ์˜ ๋‹จ์œ„๋Š” byte์ด๋ฉฐ, ๊ธฐ๋ณธ๊ฐ’์€ 16,384์ด๋‹ค.

  • setDaemon(boolean d)

    ๊ธฐ๋ณธ๊ฐ’์ด true์ด๋‹ค.

  • setTimeoutExceptionThreshold(int to)

    Timeout์ด ์—ฐ์†์œผ๋กœ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ ํ•ด๋‹น Connection์— ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ Connection์„ ๋Š๊ณ  ์žฌ์ ‘์†์„ ์‹œ๋„ํ•œ๋‹ค. ARCUS์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์—ฐ์† Timeout ํ•œ๊ณ„๊ฐ’์€ 10์ด๋‹ค.

  • setTimeoutRatioThreshold(int to)

    Client request๊ฐ€ ์–ด๋–ค ์ด์œ ๋กœ ์˜ค๋žซ๋™์•ˆ ์ฒ˜๋ฆฌ๋˜์ง€ ๋ชปํ•˜๋ฉด, ARCUS client๋Š” continuous timeout ๋ฐฉ๋ฒ•์œผ๋กœ ์ด๋ฅผ ํƒ์ง€ํ•˜๊ณ  ์‘์šฉ์—๊ฒŒ ๋น ๋ฅธ ์‹คํŒจ ์‘๋‹ต์„ ์ „๋‹ฌํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, ์‘์šฉ์€ ์‹คํŒจํ•œ request ์„ฑ๊ฒฉ์— ๋”ฐ๋ผ DB ์กฐํšŒํ•  ์ง€ ์•„๋‹ˆ๋ฉด ARCUS์— ์žฌ์š”์ฒญํ•  ์ง€๋ฅผ ๊ฒฐ์ •ํ•˜์—ฌ ์›€์ง์ผ ์ˆ˜ ์žˆ๋‹ค.

    Client request๊ฐ€ ์˜ค๋žซ๋™์•ˆ ์ฒ˜๋ฆฌ๋˜์ง€ ๋ชปํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ๊ทธ ์ฒ˜๋ฆฌ ์†๋„๊ฐ€ ๋งค์šฐ ๋А๋ ค์ง„ ๊ฒฝ์šฐ์—๋Š” ์ผ๋ถ€ request์— ๋Œ€ํ•ด operation timeout์ด ๋ฐœ์ƒํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ์ผ๋ถ€ requests๋Š” ์ •์ƒ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฒฝ์šฐ, client request๊ฐ€ ์ •์ƒ ์ฒ˜๋ฆฌ๋˜ ์•Š์ง€๋งŒ continuous timeout์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ƒํƒœ๋ฅผ ํƒ์ง€ํ•˜๊ธฐ ์œ„ํ•˜์—ฌ, ์ตœ๊ทผ 100๊ฐœ requests์— ๋Œ€ํ•ด timeout ratio๋ฅผ ๊ณ„์‚ฐํ•˜์—ฌ ํŠน์ • threshold ์ด์ƒ์ด๋ฉด ํ˜„์žฌ connection์„ ๋Š๊ณ  ์žฌ์ ‘์†์„ ์‹œ๋„ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋‹ค.

    Timeout ratio threshold์˜ default ๊ฐ’์€ 0์œผ๋กœ disabled๋œ ์ƒํƒœ์ด๋ฉฐ, 1 ~ 99 ์‚ฌ์ด์˜ ๊ฐ’์„ ์ฃผ๋ฉด ๊ทธ ๊ฐ’์œผ๋กœ timeout ratio threshold๊ฐ€ ์„ค์ •๋˜์–ด ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค.

  • setOpQueueMaxBlockTime(long t)

    Operation์„ ์š”์ฒญํ•  ๋•Œ ๋น„๋™๊ธฐ์‹์œผ๋กœ Operation queue์— ๋“ฑ๋กํ•˜์—ฌ ์ž‘์—…์„ ์š”์ฒญํ•˜๊ฒŒ ๋˜์–ด ์žˆ๋Š”๋ฐ, ์ด ์˜ต์…˜์€ Queue๊ฐ€ ๋ชจ๋‘ ๊ฝ‰ ์ฐฌ ์ƒํƒœ๊ฐ€ ๋˜์—ˆ์„ ๋•Œ ์ตœ๋Œ€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์‹œ๊ฐ„์„ ์˜๋ฏธํ•œ๋‹ค. ๋‹จ์œ„๋Š” millisecond ์ด๊ณ , ๊ธฐ๋ณธ๊ฐ’์€ 10000ms์ด๋‹ค.