Skip to content

Latest commit

ย 

History

History
169 lines (126 loc) ยท 7.71 KB

File metadata and controls

169 lines (126 loc) ยท 7.71 KB

Java Client ์‚ฌ์šฉ์‹œ ์ฃผ์˜์‚ฌํ•ญ

Counter ์‚ฌ์šฉ

ARCUS์—์„œ counter๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์ตœ์ดˆ์— set ๋˜๋Š” add command๋ฅผ ์ด์šฉํ•˜์—ฌ counter key๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•œ๋‹ค. ์ผ๋‹จ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ €์žฅํ•ด ๋ณด์ž.

client.set("nhn_counter", 10000, 100); // ์‚ฌ์‹ค์€ ์ ˆ๋Œ€ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค!

๋ถ„๋ช…ํžˆ ์ž˜ ์ €์žฅ๋˜์—ˆ๋‹ค๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์„ ๊ฒƒ์ด๋‹ค. ์ด๋ฒˆ์—๋Š” incr counter๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ’์„ ์ฆ๊ฐ€์‹œ์ผœ ๋ณด์ž.

Future<Long> f = client.asyncIncr("nhn_counter", 1);
Object o = f.get(1000, TimeUnit.MILLISECONDS);

๊ทธ๋Ÿฐ๋ฐ, ์ด๋ฒˆ์—๋Š” โ€œcannot increment or decrement non-numeric valueโ€ ๋ผ๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ๋ฐ›์„ ๊ฒƒ์ด๋‹ค. Cache ์„œ๋ฒ„์—์„œ ์ง์ ‘ counter ์ •๋ณด๋ฅผ ์กฐํšŒํ•ด ๋ณด๋ฉด โ€œdโ€๊ฐ€ ์ €์žฅ๋˜์–ด ์žˆ์„ ๊ฒƒ์ด๋‹ค. ์™œ ์ด๋Ÿฐ ์ผ์ด ๋ฒŒ์–ด์กŒ์„๊นŒ? ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด 2๊ฐ€์ง€๋‹ค.

  • Cache server์— ์ €์žฅํ•  ๋•Œ data type์„ ๋ณด๋‚ด์ง€ ์•Š์•˜์œผ๋‹ˆ, ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ๋•Œ byte ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์ €์žฅํ•  ๊ฒƒ์ด๋‹ค. ์ฐธ๊ณ ๋กœ 100์˜ ๋น„ํŠธ ๊ฐ’์€ โ€œ01100100โ€์ด๋‹ˆ๊นŒ ASCII code ๊ฐ’์œผ๋กœ๋Š” โ€œdโ€๋‹ค. ๊ทธ๋Ÿฌ๋ฉด counter์—์„œ๋Š” ์ด ๊ฐ’์„ int๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ๋˜์ง€ ์•Š์„๊นŒ ์ƒ๊ฐํ•˜๊ฒ ์ง€๋งŒ ์—ฌ๊ธฐ์—๋Š” ๋˜ ๋‹ค๋ฅธ ์ด์œ ๊ฐ€ ์žˆ๋‹ค.

  • Cache server๋Š” multi-platform์„ ์ง€์›ํ•ด์•ผ ํ•˜๋ฏ€๋กœ byte-ordering(endianness)์— ์ƒ๊ด€์—†์ด ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ข€ ๋” ์ž์„ธํ•˜๊ฒŒ ๋งํ•˜๋ฉด cache server์˜ counter๋Š” Integer ๊ฐ’๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ๊ฒŒ ๋˜์–ด ์žˆ๋Š”๋ฐ, platform์— ์ƒ๊ด€์—†์ด ๋™์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์€ ์˜ค์ง String์œผ๋กœ ๊ฐ’์„ ์ž…๋ ฅํ•  ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ฒƒ์ด๋‹ค. ๋งŒ์•ฝ cache server๊ฐ€ primitive๊ฐ’์„ ์ง€์›ํ•œ๋‹ค๋ฉด, ์ฆ‰ byte-ordering์ด ์„œ๋กœ ๋‹ค๋ฅธ client๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด counter๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด โ€œdโ€๊ฐ’์„ integer๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์—ˆ๋˜ ๊ฒƒ์ด๋‹ค.

ARCUS๋Š” counter ๋กœ ์‚ฌ์šฉํ•  ๋ฐ์ดํ„ฐ์˜ ์ตœ์ดˆ ๊ฐ’์€ ๋ฐ˜๋“œ์‹œ String์œผ๋กœ ์ง€์ •ํ•˜๋„๋ก ๊ฐ•์ œํ•˜๊ณ  ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๋ฐ˜๋“œ์‹œ ์ตœ์ดˆ ๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด String ๊ฐ’์œผ๋กœ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

client.set("nhn_counter", 10000, "100"); // ๋ฐ˜๋“œ์‹œ ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค!

์ฐธ๊ณ ๋กœ, ์ •๋ง ์šด์ด ์ข‹์€ ๊ฐœ๋ฐœ์ž๋Š” integer ๊ฐ’์œผ๋กœ ๋“ฑ๋กํ•ด๋„ ์—๋Ÿฌ๊ฐ€ ๋‚˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 52๋กœ ์ดˆ๊ธฐ๊ฐ’์„ ์ €์žฅํ•œ๋‹ค๊ณ  ํ•˜๋ฉด, ์ด๋ฒˆ์—๋Š” counter๋ฅผ ์‚ฌ์šฉํ•ด๋„ ์—๋Ÿฌ๊ฐ€ ๋‚˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์™œ๋ƒํ•˜๋ฉด 52์˜ ASCII code๊ฐ’์ด 4์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ทธ๋ฆฌ๊ณ , ARCUS client์—์„œ incr/decr command์˜ ์ž…๋ ฅ ๊ฐ’์„ primitive ๋˜๋Š” numeric wrapper ๊ฐ’์œผ๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ๋˜์–ด ์žˆ์œผ๋‚˜, ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” String์œผ๋กœ ๋ณ€ํ™˜ ํ›„ cache server๋กœ ์ „๋‹ฌํ•˜๋„๋ก ๋˜์–ด ์žˆ๋‹ค.

Operation Queue Block Timeout ์„ค์ •

setOpQueueMaxBlockTime(long t) ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ queue์— operation์„ ๋“ฑ๋กํ•  ๋•Œ timeout์„ ์„ค์ •ํ•œ ๊ฒฝ์šฐ, ๋ชจ๋“  operation์€ IllegalStateException์„ ๋‹ค์Œ ์ฝ”๋“œ์™€ ๊ฐ™์ด catchํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Future<Boolean> future = null;
try {
    future = client.set(key, 60 * 60 * 24, value);
} catch (IllegalStateException ise) { // operation queue๊ฐ€ full ์ƒํƒœ์—ฌ์„œ timeout ๋‚ด์— Operation์„ ๋“ฑ๋กํ•˜์ง€ ๋ชปํ•œ ๊ฒฝ์šฐ
    System.out.println("illegal state exception");
}

if (future != null) {
    try {
        boolean result = future.get(1000, TimeUnit.MILLISECONDS);
    } catch (TimeoutException e) {
        f.cancel(true);
        System.out.println("timeout exception");
    } catch (ExecutionException e) {
        f.cancel(true);
        System.out.println("execution exception");
    } catch (InterruptedException e) {
        f.cancel(true);
        System.out.println("interrupted exception");
    }
}

Operation queue block timeout ์˜ต์…˜์„ ์„ค์ •ํ•˜์ง€ ์•Š์œผ๋ฉด, ์ž‘์—… ์š”์ฒญ์„ ํ•˜๋Š” client ํ•จ์ˆ˜๋“ค์€ ๋ชจ๋‘ blocking์„ ๋‹นํ•  ์ˆ˜๊ฐ€ ์žˆ๋‹ค. ๋ฌผ๋ก , ์‹ค์ œ๋กœ future.get ์ˆ˜ํ–‰์‹œ ์ •์ƒ ์ฒ˜๋ฆฌ๊ฐ€ ๋˜๋“  exception์ด ๋‚˜์„œ ์ทจ์†Œ๊ฐ€ ๋˜๋“  operation queue์— ๋“ฑ๋ก๋œ ์ž‘์—…์€ ์ง€์†์ ์œผ๋กœ ๋น ์ ธ๋‚˜๊ฐ€ operation queue์— ์ž‘์—…์„ ๋“ฑ๋กํ•  ๊ณต๊ฐ„์€ ๋А๋ฆฌ์ง€๋งŒ ์ƒ๊ธธ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, request ์š”์ฒญ ์†๋„๊ฐ€ operation queue์— ๋“ฑ๋ก๋œ ์ž‘์—…์˜ ์ฒ˜๋ฆฌ ์†๋„๋ณด๋‹ค ๋งค์šฐ ๋น ๋ฅด๋‹ค๋ฉด, ํ•ด๋‹น request๋ฅผ ์š”์ฒญํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์ฐจ๋ผ๋ฆฌ ๋ฐ”๋กœ ์‹คํŒจ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ , back-end ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด ๋” ์ข‹์€ ์„ ํƒ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

Expiretime ์„ค์ •

Expiretime์€ ์ดˆ ๋‹จ์œ„๋กœ ์ง€์ •๋œ ์‹œ๊ฐ„๋งŒํผ ๋ฏธ๋ž˜์˜ ์‹œ๊ฐ„์ธ Unix Time์œผ๋กœ ๋ณ€๊ฒฝ๋˜์–ด ์ €์žฅ๋œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, '''expire time์ด 30์ผ์„ ์ดˆ๊ณผํ•˜๋ฉด 1970๋…„ ๊ธฐ์ค€์˜ Unix time์œผ๋กœ ๋ณ€๊ฒฝ๋œ๋‹ค.''' ์˜ˆ๋ฅผ ๋“ค์–ด, expiretime์„ 1000 * 60 * 60๊ณผ ๊ฐ™์€ ์‹์œผ๋กœ ๋“ฑ๋ก์„ ํ•˜๊ฒŒ ๋˜๋ฉด ๋Œ€๋žต 40์ผ ์ •๋„๊ฐ€ ๋˜๋Š”๋ฐ, ์ด๋Š” 1970๋…„ ๊ธฐ์ค€์˜ unix time์œผ๋กœ ์ธ์‹๋˜์–ด ์•„์ฃผ ์˜›๋‚  ์‹œ๊ฐ„์ด ๋˜์–ด ๋ฒ„๋ฆฌ๊ณ  ์ฆ‰๊ฐ expireํ•˜๊ฒŒ ๋œ๋‹ค. '''๋”ฐ๋ผ์„œ client์—์„œ๋Š” ๋ถ„๋ช…ํžˆ ์ €์žฅํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์—ฌ retrieval command(get, gets)๋ฅผ ์ˆ˜ํ–‰ํ–ˆ์„ ๊ฒฝ์šฐ์— cache data๊ฐ€ ์ „ํ˜€ ๋‚˜์˜ค์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.'''

Operation timeout ์„ค์ •

ARCUS Client์˜ ๋ชจ๋“  ๋น„๋™๊ธฐ๋ฐฉ์‹์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ timeout์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ timeout ๊ฐ’์„ ๋ฐ˜๋“œ์‹œ ์ง€์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

Future<Boolean> setResult = client.set("sample:testKey", 10, "testValue");
boolean result = setResult.get(300L, TimeUnit.MILLISECONDS);

์œ„ ์˜ˆ์ œ๋Š” ARCUS cache server์— โ€œtestValueโ€๋ฅผ ์ €์žฅํ•  ๋•Œ timeout๊ฐ’์„ 300ms๋กœ ์ง€์ •ํ•œ ์ฝ”๋“œ์ด๋‹ค.

์ฒซ์งธ, ์ด ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋Š” ์‹œ์ ์—์„œ full GC(garbage collection)๊ฐ€ ๋ฐœ์ƒํ–ˆ๊ณ , full GC time์ด 500ms์˜€๋‹ค๋ฉด ์ด ์š”์ฒญ์€ timeout์ด ๋˜๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ, timeout๊ฐ’์€ JVM full GC time์„ ๊ณ ๋ คํ•˜์—ฌ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค. ๋Œ€๋ถ€๋ถ„ ๋ช‡์‹ญ ๊ฐœ์˜ timeout์ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋Š” full GC time์ด ๊ธธ์–ด์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ด๋‹ค.

๋‘˜์งธ, burst traffic, small packet buffer size ๋“ฑ์˜ ์ด์œ ๋กœ cache client์™€ cache server ์‚ฌ์ด์— packet retransmission์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. Linux ํ™˜๊ฒฝ์—์„œ ์ตœ์†Œ retransmission timeout์€ 200ms์ด๋ฉฐ, ๊ทธ ๋‹ค์Œ์˜ retransmission timeout์€ 400ms, 800ms, ... ํ˜•ํƒœ๋กœ ๋‘ ๋ฐฐ์”ฉ ๊ธธ์–ด์ง€๊ฒŒ ๋œ๋‹ค. Packet retransmission์€ ์ œ๋ฒ• ํ”ํ•˜๊ฒŒ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ, ์ด๋Ÿฌํ•œ packet retransmission์— ๋Œ€ํ•ด ๊ฒฌ๋”œ ์ˆ˜ ์žˆ์„ ์ •๋„๋กœ timeout์„ ์„ค์ •ํ•˜๊ธธ ๊ถŒ์žฅํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, 300ms, 700ms ์ •๋„๊ฐ€ ๊ถŒ์žฅ๋˜๋Š” timeout ๊ฐ’์ด๋‹ค.

์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ

ARCUS Client๊ฐ€ ์ง€์›ํ•˜๋Š” ์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ์€ UTF-8์ด๋‹ค. UTF-8 ์ด์™ธ์˜ UTF-16๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์ธ์ฝ”๋”ฉ ํƒ€์ž…์„ ์ง€์›ํ•˜์ง€ ์•Š์•„, ๋งŒ์•ฝ ์‹œ์Šคํ…œ์—์„œ UTF-16๊ณผ ๊ฐ™์€ ์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ๋ฐ˜๋“œ์‹œ UTF-8 ํƒ€์ž…์œผ๋กœ ๋ณ€๊ฒฝํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ๋ฆฌ๋ˆ…์Šค ๊ธฐ์ค€์œผ๋กœ ์‹œ์Šคํ…œ์˜ ๊ธฐ๋ณธ ์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ ํ™•์ธ ๋ฐ ๋ณ€๊ฒฝ ๋ฐฉ๋ฒ•์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค. ๋ฆฌ๋ˆ…์Šค ๋ฐฐํฌํŒ, ๋ฒ„์ „๋งˆ๋‹ค ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฐธ๊ณ ๋กœ๋งŒ ํ™œ์šฉํ•œ๋‹ค.

์‹œ์Šคํ…œ ์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ ํ™•์ธ (Linux ๊ธฐ์ค€)

$ echo $LANG
en_US.UTF-8
$ locale
LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

์‹œ์Šคํ…œ ์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ ๋ณ€๊ฒฝ (Linux ๊ธฐ์ค€)

$ localectl set-locale LANG=en_US.UTF-8

JVM ์ธ์ฝ”๋”ฉ ๋ณ€๊ฒฝ

์‹œ์Šคํ…œ์˜ ์บ๋ฆญํ„ฐ ์ธ์ฝ”๋”ฉ์„ ๋ณ€๊ฒฝํ•˜๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๋ฉด, JVM์—์„œ ๋ณ€๊ฒฝํ•ด์ฃผ์–ด๋„ ๊ดœ์ฐฎ๋‹ค. JVM์˜ Property(-D) ์˜ต์…˜ ์ค‘ file.encoding ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

-Dfile.encoding=UTF-8