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๋ก ์ ๋ฌํ๋๋ก ๋์ด ์๋ค.
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์ ์ด ๋จ์๋ก ์ง์ ๋ ์๊ฐ๋งํผ ๋ฏธ๋์ ์๊ฐ์ธ Unix Time์ผ๋ก ๋ณ๊ฒฝ๋์ด ์ ์ฅ๋๋ค. ๊ทธ๋ฌ๋, '''expire time์ด 30์ผ์ ์ด๊ณผํ๋ฉด 1970๋ ๊ธฐ์ค์ Unix time์ผ๋ก ๋ณ๊ฒฝ๋๋ค.''' ์๋ฅผ ๋ค์ด, expiretime์ 1000 * 60 * 60๊ณผ ๊ฐ์ ์์ผ๋ก ๋ฑ๋ก์ ํ๊ฒ ๋๋ฉด ๋๋ต 40์ผ ์ ๋๊ฐ ๋๋๋ฐ, ์ด๋ 1970๋ ๊ธฐ์ค์ unix time์ผ๋ก ์ธ์๋์ด ์์ฃผ ์๋ ์๊ฐ์ด ๋์ด ๋ฒ๋ฆฌ๊ณ ์ฆ๊ฐ expireํ๊ฒ ๋๋ค. '''๋ฐ๋ผ์ client์์๋ ๋ถ๋ช ํ ์ ์ฅํ๋ค๊ณ ์๊ฐํ์ฌ retrieval command(get, gets)๋ฅผ ์ํํ์ ๊ฒฝ์ฐ์ cache data๊ฐ ์ ํ ๋์ค์ง ์๋ ํ์์ด ๋ฐ์ํ ์ ์๋ ๊ฒ์ด๋ค.'''
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 ํ์ ์ผ๋ก ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค. ๋ฆฌ๋ ์ค ๊ธฐ์ค์ผ๋ก ์์คํ ์ ๊ธฐ๋ณธ ์บ๋ฆญํฐ ์ธ์ฝ๋ฉ ํ์ธ ๋ฐ ๋ณ๊ฒฝ ๋ฐฉ๋ฒ์ ์๋์ ๊ฐ๋ค. ๋ฆฌ๋ ์ค ๋ฐฐํฌํ, ๋ฒ์ ๋ง๋ค ๋ค๋ฅผ ์ ์์ผ๋ฏ๋ก ์ฐธ๊ณ ๋ก๋ง ํ์ฉํ๋ค.
$ 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=$ localectl set-locale LANG=en_US.UTF-8์์คํ
์ ์บ๋ฆญํฐ ์ธ์ฝ๋ฉ์ ๋ณ๊ฒฝํ๊ธฐ๊ฐ ์ด๋ ต๋ค๋ฉด, JVM์์ ๋ณ๊ฒฝํด์ฃผ์ด๋ ๊ด์ฐฎ๋ค. JVM์ Property(-D) ์ต์
์ค file.encoding ์ต์
์ ์ฌ์ฉํ์ฌ ๋ณ๊ฒฝํ ์ ์๋ค.
-Dfile.encoding=UTF-8