Apache Cassandra ํบ์๋ณด๊ธฐ - 3ํธ
Apache Cassandra ํบ์๋ณด๊ธฐ - 3ํธ ๊ด๋ จ
1. ๋ค์ด๊ฐ๊ธฐ์ ์์
์๋ ํ์ธ์. NHN์ํฐํ ์ธ๋จผํธ ์์ธ์ง์ ๋๋ค.
๋๋์ด ๋ง์ง๋ง 3ํธ์ผ๋ก ๋ค์ ์ฐพ์๋ต๊ฒ ๋์์ต๋๋ค. ์ง๋ 1, 2ํธ์ ํตํ์ฌ Cassandra๊ฐ ์ด๋ป๊ฒ ๋ถ์ฐํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ ์ถ๋ ฅํ๋์ง๋ฅผ ์ค์ฌ์ผ๋ก ์์๋ณด์์ผ๋ ๊ทธ๋ ๋ค๋ฉด ์ด์ ๋ ํ์ธํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก Cassandra๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ ์ง์ ๋ํ ๊ณ ๋ฏผ์ ํ ์ฐจ๋ก๊ฐ ๋์์ต๋๋ค. ๋ฐ๋ผ์ Cassandra๊ฐ ์ง์ํ๋ ๊ธฐ๋ฅ๊ณผ Cassandra๋ฅผ ์ฌ์ฉํ ๋ ์ ์ฉํ๊ฒ ์ฐ์ด๋ Pattern ๊ทธ๋ฆฌ๊ณ ๋๋๋ก์ด๋ฉด ํผํด์ผํ Anti-Pattern, ๊ทธ๋ฆฌ๊ณ ์ค์ํ ๋ด์ฉ๋ค์ ์ค๋ช ํ๋๋ผ ๋ฏธ์ฒ ๋ค๋ฃจ์ง ๋ชปํ๊ณ ๋์ด๊ฐ์๋ ๋ด์ฉ๋ค์ ๋ํด ๋ช๊ฐ์ง ์ ๋ฆฌํด๋๋ฆฌ๊ณ ์ ํฉ๋๋ค. ์ญ์ ์ด๋ฒ ํธ๋ ๋ง์ฐฌ๊ฐ์ง๋ก, ๋ด์ฉ์ ์ค๋ช ํ๋ค๋ณด๋ฉด ๋์์ด ๊ธธ์ด์ง ์ ์๊ธฐ ๋๋ฌธ์, ๋๋ต์ ์ธ ๋ด์ฉ๊ณผ ์๋ฆฌ๋ฅผ ์ค์ฌ์ผ๋ก ์ต๋ํ ๋ค์ํ๊ฒ ๋ค๋ฃฐ ์ ์๋๋ก ๊ธ์ ๊ตฌ์ฑํ์์ผ๋ ์ ๋ ํ์ฌ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. ๋ง๋ถ์ฌ ์ด๋ฒ ํธ์ ์ดํดํ๊ธฐ ์ํด์๋ Cassandra ์ ๋ฐ์ ์ธ ๊ตฌ์กฐ๋ฅผ ์๊ณ ์๋ ํธ์ด ์ข์ผ๋ฏ๋ก ์ด ๊ธ์ ์ฒ์ ๋ณด๋ ๋ถ์ด์๋ผ๋ฉด ๋๋๋ก 1, 2ํธ์ ๋จผ์ ์ฝ์ด๋ณด์๊ธฐ๋ฅผ ๊ถํฉ๋๋ค.
2. Cassandra๊ฐ ์ง์ํ๋ ๊ธฐ๋ฅ๋ค
Cassandra๋ Gossip ํ๋กํ ์ฝ์ ํตํ์ฌ ๋ชจ๋ ๋ ธ๋๊ฐ ๋๋ฑํ Ring ๊ตฌ์กฐ๋ฅผ ์ด๋ฃจ๊ณ ์๊ณ , ์ด๋ก ์ธํ์ฌ ํจ๊ณผ์ ์ธ ๋ฐ์ดํฐ ๋ถ์ฐ ๋ฐ ๋์ Scalability ๊ทธ๋ฆฌ๊ณ High Availability๋ฅผ ์คํํ ์ ์์์ง๋ง ์์๋ค์ํผ Cassandra๊ฐ ๋ชจ๋ ์ ์์ ์๋ฒฝํ ์๋ฃจ์ ์ ์๋๋๋ค. ๋ง์ NoSQL ์ ํ๋ค์ด ๊ทธ๋ ๋ฏ์ด Cassandra ์ญ์ Join์ด๋ Transaction์ ์ง์ํ์ง ์๊ณ , ๋์ ์์ค์ Index ์ญ์ ์ ๊ณตํ์ง ์์ต๋๋ค. Cassandra๊ฐ ์ง์ํ๋ Index๋ ์์ ๋งํ๋ Row Key๋ฅผ ๊ฒ์ํ๊ธฐ ์ํ ๊ธฐ๋ณธ์ ์ธ Index ์ 0.7๋ฒ์ ๋ถํฐ ์ถ๊ฐ๋ Secondary Index๋ผ๋ ์กฐ์ดํ ๊ธฐ๋ฅ์ ๊ฐ์ง๊ณ ์์ ๋ฟ์ด์ฃ .(Secondary Index๋ ์กฐ๊ธ ํ์ ์ค๋ช ํ๊ฒ ์ต๋๋ค.) ๊ทธ๋ ๋ค๋ฉด Cassandra์ ํน์ง์ ์ธ ๊ธฐ๋ฅ๋ค์ ๋ช๊ฐ์ง ์์๋ณด๊ณ , ์ด๋ฌํ ๊ธฐ๋ฅ๋ค์ด ์ด๋ค ํน์ง์ ๊ฐ์ง๊ณ ์๋์ง ์ง์ด๋ณด๊ฒ ์ต๋๋ค.
(1) Light-Weight Transaction.
์ด๋ฆ์์๋ ์ง์ํ ์ ์๋ฏ์ด, Light-Weight Transaction์ ์์ฃผ ๊ฐ๋จํ๊ฒ๋๋ง ๊ฐ๋ณ๊ฒ ์ง์ํ๋ ์์ ๋ฒ์ฃผ์ Transaction ๊ธฐ๋ฅ์ ๋๋ค. ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๋ค ๋ณด๋ฉด ์ค๋ณต๋๋ฉด ์ ๋๊ฑฐ๋ ์ผ๊ด์ฑ์ ์ ์งํด์ผํ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ค์ผํ ๋๊ฐ ์์ต๋๋ค. Light-Weight Transaction์ ์ด๋ด ๋ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ ๊ธฐ๋ฅ์ผ๋ก, ํน์ ์กฐ๊ฑด์ ๋ง์ถ์ด ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ ์ ์๋๋ก ํด์ค๋๋ค. ์ฆ, Compare and Set ์ ํ์ ๋ Transaction์ธ ๊ฒ์ด์ฃ . ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋น๊ต์ ๊ฐ๋จํ๋ฐ, Insert์ Update ๊ตฌ๋ฌธ์์ IF ๊ตฌ๋ฌธ์ ์ด์ฉํ๋ ๊ฒ์ผ๋ก ์ธ ์ ์์ต๋๋ค. ๊ฐ๋จํ ์๋ฅผ ๋ค์ด๋ณด๊ฒ ์ต๋๋ค. ๋จผ์ ์๋์ ๊ฐ์ Table์ด ์๋ค๊ณ ๊ฐ์ ํ๊ณ ํ๋์ ๋ฐ์ดํฐ๋ฅผ Insert ํด๋ด ์๋ค.
CREATE TABLE test_keyspace.test_table_ex_1 ( id text PRIMARY KEY, name text, descript text );
INSERT INTO test_keyspace.test_table_ex_1 (id, name , descript ) VALUES ( 'id_1', 'name_1', 'test_data');
SELECT * FROM test_keyspace.test_table_ex_1;
์ด์ ๊ธ์์ ๋ง์๋๋ ธ๋ฏ, ๊ธฐ๋ณธ์ ์ผ๋ก Cassandra๋ Insert์ Update๊ฐ ๋ด๋ถ์ ์ผ๋ก๋ ์ฌ์ค์ ๋์ผํ๊ฒ ๋์ํ๊ธฐ ๋๋ฌธ์, ์ด๋ ์๋์ ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ ๊ฒฝ์ฐ, RDBMS์๋ ๋ฌ๋ฆฌ ๋ฌธ์ ์์ด ๋ฐ์ดํฐ๊ฐ ์์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
INSERT INTO test_keyspace.test_table_ex_1 (id, name , descript ) VALUES ( 'id_1', 'name_1', 'test_data_2');
SELECT * FROM test_keyspace.test_table_ex_1;
์ด๋ฐ Cassandra์ ํน์ง์ ์ฌ๋ฌ๊ฐ์ง ๋ฌธ์ ๋ฅผ ๋ฐ์์ํฌ ์ ์์ต๋๋ค. ์ฃ๋ถ๋ฆฌ Insertํ๋ค๊ฐ ๊ธฐ์กด ๋ฐ์ดํฐ๊ฐ ์์ค๋์ด๋ฒ๋ฆฌ๋๊น์. ํนํ ์ค๋ณต๋์ด ์กด์ฌํด์๋ ์๋๋ ์ข ๋ฅ์ ๋ฐ์ดํฐ๋ผ๋ฉด ๋์ฑ ๋ฌธ์ ๊ฒ ์ฃ . ๊ทธ๋ ๋ค๋ฉด ์ด์ ๋๊ฐ์ ์ฟผ๋ฆฌ๋ฌธ์ IF NOT EXISTS๋ฅผ ๋ถ์ฌ ์คํํด๋ด ์๋ค.
INSERT INTO test_keyspace.test_table_ex_1 (id, name , descript ) VALUES ( 'id_1', 'name_1', 'test_data_3') IF NOT EXISTS;
์ง๊ธ์ ๊ฒฝ์ฐ, ์ด๋ฏธ ์กด์ฌํ๋ ๊ฐ์ด ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ์ง ์๊ณ ์ฟผ๋ฆฌ ๋์์ด ์คํจํ์ ์ ์ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ฌ์ค์ Insert์ ๋์ผํ Update๋ Light-Weight Transaction์ ์ ๊ณตํ์ง ์์๊น์? ๋ง์ต๋๋ค. ๋ค๋ง Update๋ Insert์๋ ์กฐ๊ธ ๋ค๋ฅธ ํํ๋ก, ์๋์ ๊ฐ์ ๊ตฌ๋ฌธ์ ์ด์ฉํ์ฌ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
UPDATE test_keyspace.test_table_ex_1 SET descript='test_data_3' WHERE id = 'id_1' IF name = 'name_1';
์ด๋ ๋ฏ Insert์ Update์ ํํ์ฌ ์ ๊ณต๋๋ Light-Weight Transaction์ Transaction์ ์ ๊ณตํ์ง ๋ชปํ๋ Cassandra์์ ๋๋๋ก ์ ์ฉํ๊ฒ ์ธ ์ ์๋ ๊ธฐ๋ฅ์ ๋๋ค. ํ์ง๋ง ์๋ฌด๋๋ ๋ฌธ๋ฒ์ ์ผ๋ก ์ ๊ณตํ๋ Query์ ์์ ๋๋ ์ฌ์ ํ ๋ฎ์ ์์ค์ด๋ฉฐ, Light-Weight Transaction ์์ฒด๊ฐ ์ฌ์ฉ์ ๋จ์ฉํ ๊ฒฝ์ฐ ํ์ฐ์ ์ผ๋ก ์ฑ๋ฅ์ ์ ํ๋ฅผ ๋ถ๋ฌ์ฌ ์ ์๊ธฐ ๋๋ฌธ์ ๊ผญ ํ์ํ ๊ณณ์ ์ ๋นํ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
(2) Secondary Index
Secondary Index๋ Cassnadra 7.0 ์ดํ์ ๊ฒ์์ ์ํ์ฌ ์ถ๊ฐ๋ ๊ฐ๋จํ ๊ธฐ๋ฅ์ ๋๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก Cassandra๋ Partition Key(Row Key)๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ์ฐํ๊ณ Cluster Key(ํน์ Column Name)๋ก Row ๋ด ๋ฐ์ดํฐ ์ ๋ ฌ์ ๊ธฐ๋ณธ์ ์ผ๋ก ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด ๋ ๊ฐ์ง Key๋ก ์ง์ ๋ CQL Column์ ๋ํ Data๋ CQL์ Where ๊ตฌ๋ฌธ์ ์ด์ฉํ ๊ฒ์์ด ๊ฐ๋ฅํ์ง๋ง, ๊ทธ๋ ์ง ์์ CQL Column์ ๋ํด์๋ ๊ฒ์ ๋ฐฉ๋ฒ์ด ์์์ต๋๋ค. ๋๋ฌธ์ ๋ง์ Cassandra ์ฌ์ฉ์๋ค์ด ๋ฐ์ดํฐ์ ๋น์ ๊ทํ๋ฅผ ํตํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ์์์ฃ .
ํ์ง๋ง Secondary Index๋ฅผ ์์ฑํ ํ ๊ฐ์ Query๋ฅผ ์คํํ๋ค๋ฉด ์ด๋ฌํ ๋ฌธ์ ๋ ๊ฐ๋จํ ํด๊ฒฐ๋ฉ๋๋ค.
๋ง์ฝ Secondary Index๊ฐ ์๋ค๋ฉด, ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ป๊ธฐ ์ํด์๋ ๋ฐ๋์ Partition Key์ Cluster Key๋ฅผ ์๊ณ ์ ๊ฒ์ํด์ผ ํ์ง๋ง, ํน์ CQL Column์ Secondary Index๋ฅผ ์์ฑํ์ฌ ์ฌ์ฉํ๋ค๋ฉด ํด๋น CQL Column์ ๋ํ์ฌ ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ์ผ๋ง๋ ์ง ๊ฒ์์ด ๊ฐ๋ฅํ๊ฒ ๋ ๊ฒ์ด์ฃ .
๋ฌผ๋ก ๋ง์ ๋ถ๋ค์ด ์์ํ์๋ค์ํผ ์ด ์ญ์ ๋ง๋ฅ ์ด์ ๋ ์๋๋๋ค. ๊ตฌ์กฐ์ ๊ตฌํํ๊ธฐ ํ๋ ๊ธฐ๋ฅ์ ๋ฐ๋์ Trade Off๋ฅผ ๋๋ฐํ๋ ๋ฒ์ด๋๊น์. Secondary Index๋ Range Query๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์ '='์ Contains์ ๊ฐ์ ๋ฌธ๋ฒ์ ์ด์ฉํ ํ์ ์ ์ธ ๊ฒ์๋ง ๊ฐ๋ฅํ ๋ฐ๋ค๊ฐ ๋จ์ฉํ์ง ๋ง์์ผํ ์ฑ๋ฅ์์ ์ด์ ๊ฐ ๋ถ๋ช ํ ์กด์ฌํฉ๋๋ค. ์ด๋ ๋ฏ ์ Secondary Index๋ฅผ ๋จ์ฉํด์๋ ์๋๋์ง, ์ฌ์ ํ ๋น์ ๊ทํ ๊ธฐ๋ฒ์ด ์ ์ฉํ๊ฒ ์ฌ์ฉ๋๊ณ ์๋์ง์ ๋ํด์๋ ์กฐ๊ธ ํ์ ์ด์ผ๊ธฐํ๊ฒ ์ต๋๋ค.
(3) Batch
Cassandra๋ฅผ ์ฌ์ฉํ๋ค ๋ณด๋ฉด, ๋๋๋ก ํ ๋ฒ์ ๋๊ฐ ์ด์์ ๋์์ ํ ๋ฒ์ ์ํํด์ผํ ํ์์ฑ์ ๋๋ผ๊ฒ ๋ฉ๋๋ค. ๋ฌผ๋ก ์ด ๋์๋ค์ ๋ํ Transaction์ด ๋ณด์ฅ๋๋ค๋ฉด ๋ํ ๋์ ์์ด ์ข๊ฒ ์ง๋ง, ์์๋ค์ํผ Cassandra๋ Transaction์ ์ง์ํ์ง ์์ฃ . ๋์ Transaction์ ๋ค๊ฐ์ง ์์(ACID) ์ค์์ Atomic์ ๋ํ ๋์๋ง์ ๋ณด์ฅํด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋๋ฐ, ๊ทธ๊ฒ์ด ๋ฐ๋ก Batch๋ผ๋ ๊ธฐ๋ฅ์ ๋๋ค.
Batch๋ ์ฌ๋ฌ๊ฐ์ Query๋ฌธ์ ํ ๋ฒ์ ๋ฌถ์ด์ ํ๋ฒ์ ์ํํ ์ ์์ผ๋ฉฐ ํด๋น ๋์์ ๋ํด ๋ฐ๋์ All or Noting์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์ฅํฉ๋๋ค. ๋ค๋ง, Batch์ ์ฑ๋ฅ์ ๋ค์ ๋๋ฆฐ ํธ์ด๋ฉฐ Transaction์ ๋ณด์ฅํ๋ ๊ธฐ๋ฅ์ด ์๋๋ผ๋ ์ ๋ค์ ๋ช ํํ ์๊ณ ์ฌ์ฉํ์ง ์์ผ๋ฉด ๋ญํจ๋ฅผ ๋ณด๊ธฐ ์ฝ๋ค๋ ์ ์ ์ฃผ์ํด์ผํฉ๋๋ค.
(4) Collection
์ด์ฐฝ๊ธฐ Cassandra์๋ Super Column๊ณผ Super Column Family๋ผ๋ ๊ฐ๋ ์ด ์์์ต๋๋ค. Cassandra์ Column Value์ ๋๋ค์ Column ๋ฐ์ดํฐ๊ฐ ๋ค์ด๊ฐ ์ ์์๊ณ , ์ด๋ฅผ Super Column์ด๋ผ๊ณ ๋ถ๋ ์ผ๋ฉฐ, ์ด๋ฌํ Supser Column ํ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ Column Family๋ฅผ Super Column Family๋ผ๊ณ ๋ถ๋ ๋ ๊ฒ์ด์ฃ . ์ด๋ ์คํค๋ง๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐ์ ์์ด์ ์๋นํ ํธ๋ฆฌํ ๋ฉด์ด ์์์ง๋ง ๋ค์ ์ฌ์ฉํ๊ธฐ์๋ ๋ณต์กํ ๊ฐ๋ ์ด์๋๋ฐ, ๋คํ์ค๋ฝ๊ฒ๋ ์ด ๋ ๊ฐ๋ ์ Cassandra 1.2 ๋ถํฐ๋ ํ๊ธฐ๋์ด ์ฌ๋ผ์ก๊ณ ๊ทธ ์๋ฆฌ๋ Collection์ด๋ผ๋ ๊ฒ์ผ๋ก ๋์ฒด๋์์ต๋๋ค. (๋ฌผ๋ก ๊ธฐ์กด ๋ฒ์ ๊ณผ ํธํ์ฑ์ ์ํ์ฌ Super Column ๋ฐ Super Column Family์ ์ฌ์ฉํ ๊ฒฝ์ฐ์, ๋ด๋ถ์ ์ผ๋ก Collection์ผ๋ก ์ ์ฅ๋๋ ํ์์ผ๋ก ๋ณ๊ฒฝ๋์์ต๋๋ค.)
Collection์ ์ด๋ฆ์์๋ถํฐ ์ ์ ์๋ฏ์ด Set, List Map ์ธ๊ฐ์ง ํ์ ์ผ๋ก ๋๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ค์ ๋ฐ์ดํฐ๊ฐ ์ ๋ ฅ๋ Value ๊ฐ๋ค์ ์ฌ์ด์ฆ๋ 64KB๋ก ํฌ๊ธฐ๊ฐ ์ ํ๋์ด์์ฃ . ํ์ง๋ง ์ด๋ณด๋ค ๋์ฑ ์ฃผ๋ชฉํด์ผํ ๋ถ๋ถ์, ์ด๋ฐ ์ธ ๊ฐ์ง ํ์ ์ ๋ฐ์ดํฐ๊ฐ ์ค์ Cassandra Data Layer์์๋ ๊ฐ๊ฐ ์ด๋ค ๋ฐฉ์์ผ๋ก ์ ์ฅ๋๋๋๋ ์ ์ ๋๋ค. ์ฐจ๋ก๋๋ก ์ดํด๋ณด๊ฒ ์ต๋๋ค.
CREATE TABLE test_keyspace.test_table_set (name text PRIMARY KEY , data set);
INSERT INTO test_keyspace.test_table_set (name, data ) VALUES ( 'eom', {'1', '1', '1'} );
SELECT * FROM test_keyspace.test_table_set;
๋จผ์ Set์ Column์ผ๋ก ๊ฐ์ง๋ Table์ ๋ง๋ค๊ณ ๋ฐ์ดํฐ๋ฅผ Insertํ ๋ค์ Select๊ตฌ๋ฌธ์ผ๋ก ์ดํด๋ณด๋ฉด ์์ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค. CQL ์์์ Set ํ์ ์ ์๋ฃ๋ ์ง๊ทนํ ์์์ ์ผ๋ก ์ ์ฅ๋์์์ ์ ์ ์์ฃ . ๊ทธ๋ ๋ค๋ฉด ์ค์ ๋ฐ์ดํฐ์ ํํ๋ก ๋ณด์ฌ์ฃผ๋ cli ์ ํธ๋ฆฌํฐ์์ ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ฉด ์ด๋ป๊ฒ ํํ๋ ๊น์?
USE test_keyspace;
LIST test_table_set;
Set ํ์ ์ผ๋ก ์ง์ ๋ CQL Column์ ์ด๋ฆ์ ":"๋ฌธ์๋ฅผ ๋ถ์ธ ๋ค ์ค์ ๋ฐ์ดํฐ์ 16์ง์๋ก ๋ณํํ ๊ฐ์ ๋ถ์ฌ Column Name์ผ๋ก ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ํด๋นํ๋ Column์ Value๋ ๋น์ด์๋ค๋ ๊ฑธ ์ ์ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ฒ์ List๋ ์ด๋จ๊น์?
CREATE TABLE test_keyspace.test_table_list (name text PRIMARY KEY , data list);
INSERT INTO test_keyspace.test_table_list (name, data ) VALUES ( 'eom', ['1', '1', '1']);
SELECT * FROM test_keyspace.test_table_list;
USE test_keyspace;
LIST test_table_list;
์ค๋ณต ๋ฐ์ดํฐ๋ฅผ ํฌํจํ ์ ์๋ List์ ํน์ฑ์, Set๊ณผ๋ ๋ฌ๋ฆฌ Column Name์๋ Cassandra๊ฐ ๋ฐ๊ธํ UUID๊ฐ ๋์ ์๋ฆฌ๋ฅผ ์ฐจ์งํ๊ฒ ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ค์ List์ ์ฝ์ ํ๋ ๋ฐ์ดํฐ๋ค์ Column์ Value์ ๋ค์ด๊ฐ ์๋ ๊ฑธ ํ์ธํ ์ ์์ฃ . ์ด๋ ๊ฒ Set๊ณผ List๋ฅผ ์ดํด ๋ณด๊ณ ๋๋ Map์ ์ด๋ป๊ฒ ์ ์ฅ๋ ๊ฒ์ธ์ง ๋์ถฉ ์ ๊ฒ ๊ฐ์ต๋๋ค. ํ์ง๋ง ์ ํํ ํ์ธ์ ์ํ์ฌ Map ์ญ์ ํ ๋ฒ ํ ์คํธํด๋ด ์๋ค.
CREATE TABLE test_keyspace.test_table_map (name text PRIMARY KEY , data map);
INSERT INTO test_keyspace.test_table_map (name, data ) VALUES ( 'eom', {'1':'sejin', '1':'sejin', '2':'duron'});
SELECT * FROM test_keyspace.test_table_map;
USE test_keyspace;
LIST test_table_map;
Set๊ณผ ๊ฐ์ ํน์ฑ์ ๊ฐ์ง Map์ Key๋ Column Name์ ":"๋ฌธ์์ ํจ๊ป ์ ์ฅ๋์๊ณ , List์ ๊ฐ์ ํน์ฑ์ ๊ฐ์ง Map์ Value๋ Column Value์ ์ ์ฅ๋์์์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ ๋ฏ Cassandra ๋ด๋ถ์์ Collection์ด ์ค์ ๋ก ์ด๋ป๊ฒ ์ ์ฅ๋๋๊ฐ๋ฅผ ๊ฐ๋จํ ์ดํด๋ณด์์ต๋๋ค. ์ด๋ฌํ ๋ด์ฉ๋ค์ ๋ฐ๋์ ์ดํด์ผํ๋ ์ด์ ๋ ์ค์ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐฉ์์ ๊ณ ๋ คํ์ง ์์ ์ฑ Cassandra Table์ ์คํค๋ง๋ฅผ ์์ฑํ ๊ฒฝ์ฐ, ๋๋๋ก ์ฑ๋ฅ์์ ๋ฌธ์ ๋ฅผ ์ผํฌ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์์ ๋ด์ฉ์์ ์ถ์ธกํ ์ ์๋ฏ, Collection์ ๋ฐ์ดํฐ๋ฅผ ๋์์์ด ์ฝ์ ํ๊ฒ ๋๋ค๋ฉด Cassandra์ ์ ์ฅ๋๋ Row์ ๊ธธ์ด๋ง ๊ณ์ ๋์ด๋๊ฒ ๋ ๋ฟ, Cassandra ์ต๋์ ์ฅ์ ์ธ ๋ฐ์ดํฐ ๋ถ์ฐ์ ์ด๋ฃจ์ด์ง์ง ์์ Hotspot์ด ๋ฐ์ํ ์ํ ๋์์ง๊ธฐ ๋ฑ, ์ฌ๋ฌ๊ฐ์ง ๋ฆฌ์คํฌ๊ฐ ์๊ธธ ์ ์๊ฒ ์ฃ . ๋ฐ๋ผ์ ์ค์ ๋ก ๋ฐ์ดํฐ๊ฐ ์ด๋ป๊ฒ ์ ์ฅ๋๋๊ฐ์ ๋ํ ๋ถ๋ถ์ ์๋ ๊ฒ์ ์๊ฐ๋ณด๋ค ์ค์ํ ์ผ์ ๋๋ค.
3. Cassandra Pattern
์ง๋ ๊ธ๋ค์ ์ฐจ๋ถํ ๋์ด์ผ ์๊ฐํด๋ณด๋ฉด Cassandra์ ํฐ ํน์ง์ ๋ชจ๋ ๋ ธ๋๊ฐ ๋๋ฑํ Ring ํํ์ ๋ถ์ฐ์์คํ ์ด๋ฉฐ, ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ณ ์ฝ๋๋ฐ ํ์ํ ์ฅ์ ์ ๊ฐ์ง๊ณ ์๋ ์์คํ ์ด๋ผ๋ ์ฌ์ค๋ก ์์ฝํด๋ณผ ์ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด Cassandra๋ฅผ ์ฌ๋ฐ๋ฅด๊ฒ, ํน์ ์ฌ๋ฐ๋ฅด์ง ์๊ฒ ์ฌ์ฉํ๋ค๋ ๊ฒ์ ์๋ฌด๋๋ ์ด๋ฌํ Cassandra์ ๊ตฌ์กฐ์ ๋ง๋๋ก ์คํค๋ง๋ฅผ ์ค๊ณํ๊ณ ์ฌ์ฉํ๋๊ฐ์ ๋ฐ์ ํ ์ฐ๊ด์ด ์๊ฒ ์ฃ . ์ตํ ๋๋ฆฌ ์๋ ค์ง ๋ด์ฉ๋ค์ ์ค์ฌ์ผ๋ก Cassandra๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํด์ผํ๋์ง, ์ด๋ป๊ฒ ์ฌ์ฉํ๋ฉด ์๋๋์ง ํ๋์ฉ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
(1) Time Sequencial Data
์ฐ๋ฆฌ๋ Cassandra๋ Partition Key (Row Key) ๋จ์๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ์ฐํ๊ณ , ํ๋์ Partition Key ์์์ ๋ฐ์ดํฐ๋ SSTable์ด๋ผ๋ ์ ์ฅ์์ ์ด๋ฏธ ์ ๋ ฌ๋ ์ํ๋ก ๊ธฐ๋ก๋๋ค๋ ์ฌ์ค์ ์๊ณ ์์ต๋๋ค. ๋ํ Cassandra๋ ํ๋ฅญํ ๋ถ์ฐํ ๊ตฌ์กฐ๋ฅผ ํตํด ๋ง์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๊ณ , ์ฝ๋๋ฐ ์ ํฉํ์ง๋ง, Tombstone์ด๋ผ๋ ๋ฐฉ์์ผ๋ก ์ธํ์ฌ ๋๋์ Data์ ๋ํ Delete์๋ ๋ค์ ๋ถ์ ํฉ๋ ์ฌ์ค ์ญ์ ์ด๋ฏธ ์ด๋์ ๋ ์ดํด๋ณธ ๋ฐ ์์ฃ . ๊ทธ๋ฌ๋ฉด Cassandra๋ ์ด๋์ ์ฌ์ฉํ๋ฉด ์ข์๊น์? ์๋ฌด๋๋ SNS๋ผ๋๊ฐ Log Data๋ฑ ์ ์ฅํ๋ ๋ฐ์ ์ข์ง ์์๊น์? ๊ทธ๋ฆฌ๊ณ ์ด๋ฌํ ๋ฐ์ดํฐ๋ค์ ํ๊ฐ์ง ํน์ง์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์๊ฐ ์์๋๋ก ์์ธ๋ค๋ ์ ์ด์ฃ .
ํ๊ฐ์ง ์๋น์ค๋ฅผ ๊ฐ์ ํด๋ด ์๋ค. 5๋ถ ๊ฐ๊ฒฉ์ผ๋ก ๊ฐ ์๋ฒ๋ค์ ์ค์ ์ฌ์ฉ์ ์ซ์์ ์๋ฒ์ ์ํ๋ฅผ ๊ธฐ๋กํด์ผํ๋ ์๋น์ค๊ฐ ์๋ค๊ณ ๋ง์ด์ฃ . ๊ทธ๋ ๋ค๋ฉด ์ด๋ฌํ ๊ธฐ๋ก์ฑ ๋ฐ์ดํฐ๋ ์ด๋ค ํ์์ผ๋ก ์ ์ฅํ๋ฉด ์ข์๊น์? ๋ถ์ฐ์ํฌ ๋ฐ์ดํฐ๋ ์๋ฒ๋จ์๋ก ๋๋๋ฉด ์ข์ ๊ฒ ๊ฐ์ผ๋ Partition key๋ ์๋ง๋ Server์ ID๊ฐ ์ ํฉํ ๊ฒ์ด๊ณ , ๊ฐ ๋ฐ์ดํฐ๋ 5๋ถ ๊ฐ๊ฒฉ์ผ๋ก ์ผ์ ํ๊ฒ ์ ์ฅ๋๋ Timestamp๊ฐ Cluster Key๋ก ์ ํฉํ์ง ์์๊น์? ๊ฐ๋จํ Table์ ์์ฑํ ๋ค์ 5๋ถ ๊ฐ๊ฒฉ์ผ๋ก 4๋ฒ์ ๋ฐ์ดํฐ๊ฐ ์์ง๋์๋ค๊ณ ๊ฐ์ ํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด๋ด ์๋ค.
CREATE TABLE test_keyspace.test_ts ( serverId TEXT, timestamp INT, data TEXT, PRIMARY KEY ( serverId, timestamp ) );
INSERT INTO test_keyspace.test_ts ( serverId, timestamp, data ) VALUES ( 'server_1', 1455194927, '{ "userNumber" : 100, "serverStatus" : "STABLE" }' );
INSERT INTO test_keyspace.test_ts ( serverId, timestamp, data ) VALUES ( 'server_1', 1455195227, '{ "userNumber" : 105, "serverStatus" : "STABLE" }' );
INSERT INTO test_keyspace.test_ts ( serverId, timestamp, data ) VALUES ( 'server_1', 1455195527, '{ "userNumber" : 100, "serverStatus" : "STABLE" }' );
INSERT INTO test_keyspace.test_ts ( serverId, timestamp, data ) VALUES ( 'server_1', 1455195827, '{ "userNumber" : 95, "serverStatus" : "STABLE" }' );
SELECT * FROM test_keyspace.test_ts;
์ ์ด๋ ๊ฒ ๋ค์ด๊ฐ ๋ฐ์ดํฐ๋ CQL๋ก๋ง ๋ณด๋๋ผ๋ ์ฌ์ฉํ๊ธฐ ๋งค์ฐ ํธํ ๊ฒ ๊ฐ์ต๋๋ค. ์๋ฒ์ ID๋ฅผ ๊ธฐ์ค์ผ๋ก Cassandra ๋ ธ๋๋ณ๋ก ๋ฐ์ดํฐ๊ฐ ๋ถ์ฐ๋ ๊ฒ์ด๊ณ , ๋ถ์ฐ๋ ๋ฐ์ดํฐ ์์์๋ Cluster Key ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ ์ด์ ์ ๋ ฌ๋์ด ์ ์ฅ๋ ํ ๋ WHERE๋ฌธ๊ณผ timestamp๋ฅผ ์ด์ฉํด Range query๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋๊น์. ์ ํํ ํ์ธ์ ์ํด์ cli ์ ํธ๋ฆฌํฐ๋ฅผ ํตํด ๋ฐ์ดํฐ๊ฐ ์ค์ ๋ก๋ ์ด๋ป๊ฒ ์ ์ฅ๋์ด์๋์ง ๋ด ์๋ค.
USE test_keyspace;
LIST test_ts;
๋ชจ๋ Column์ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ถ์ด๋ timestamp์ด๋ฏ๋ก ํผ๋ํ์ง ๋ง์์ผ ํ๋ค.)
์ญ์ ๊ธฐ๋๋๋ก Server์ ID๋ Row Key๊ฐ ๋์๊ณ Cluseter Key๋ก ์ง์ ํ๋ timestamp์ value๊ฐ๋ค์ ๋จ์ CQL Column ์ด๋ฆ์ด ":"๋ฌธ์์ ๋ถ์ด Cassandra Data Layer์ Column Name์ด ๋ ๊ฒ์ ์ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ data CQL Column์ ์ ์ฅํ๋ ๋ฐ์ดํฐ๋ค์ 16์ง์ byte array๋ก ๋ณํ๋์ด ์ ์ฅ๋ ๊ฒ์ ํ์ธํ ์ ์๊ตฐ์. ์ฐ๋ฆฌ๊ฐ ์ํ๋ ์กฐ๊ฑด์ ๋๋ถ๋ถ ๋ง์กฑํ ๊ฒ ๊ฐ์ต๋๋ค๋ง... ๊ณผ์ฐ ๊ทธ๋ด๊น์?
์ด๋ฐ ๋ฐฉ์์ ์คํค๋ง๋ ํ ๊ฐ์ง ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๋๋ก๋ผ๋ฉด ์๊ฐ์ด ์ง๋ ์๋ก ์๋น์ค๊ฐ ์ ์ฅํ๋ ๋ฐ์ดํฐ๊ฐ ๊ณ์ ๋์ด๋์ง ์์๊น์? ๋ฐ์ดํฐ๋ฅผ ๋ถ์ฐํ๋ ๊ธฐ์ค์ Partition Key(Row Key)์ด๋ฏ๋ก ํ๋์ Server Id์ ๋์๋๋ ๋ชจ๋ ์๊ฐ์ ๋ํ ๋ฐ์ดํฐ๋ค์ ๋จ ํ๋์ Partition Key๋ฅผ ๊ธฐ์ค์ผ๋ก ์ ์ฅ๋ ๊ฒ๋๋ค. ์ด๋ ๊ฒฐ๊ตญ ํด๋น Partition Key๋ฅผ ๋ด๋นํ๊ณ ์๋ ๋ ธ๋๊ฐ Hotspot์ด ๋ ๊ฐ๋ฅ์ฑ๋ ๋์์ง ๊ฒ์ด๊ณ , Row์ ๊ธธ์ด๊ฐ ๊ธธ์ด์ง๋ฉด ๊ธธ์ด์ง๋ ๋งํผ ๊ฒ์, ์ญ์ ์ ๋ํ ์ฑ๋ฅ ์ ํ๋ก ์ด์ด์ง ๊ฒ ๋ถ๋ช ํฉ๋๋ค. ์ด๋ Cassandra์ ๋ํ์ ์ธ Anti-Pattern์ค ํ๋๋ก, Row๊ฐ ๋ฌดํ์ ๊ธธ์ด์ง๋ ์ด๋ฐ ๋ฐฉ์์ ์คํค๋ง ๊ตฌ์ฑ์ ํผํด์ผํฉ๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ด๋ค ๋ฐฉ์์ผ๋ก ์คํค๋ง๋ฅผ ์ค๊ณํ๋ฉด ๋ ๊น์? ๋ฌผ๋ก 100% ์ฌ๋ฐ๋ฅธ ์ ๋ต์ด๋ผ๋ ๊ฒ์ ์๊ฒ ์ง๋ง, ์ผ๋จ ์๋์ ๊ฐ์ ํ ์ด๋ธ์ ์์ฑํ๊ณ ๊ฐ์ ํ์์ ๋ฐ์ดํฐ๋ฅผ ๋ฃ์ด๋ด ์๋ค. ๋จ, ์ด๋ timeboundery์๋ ๋งค ์๊ฐ๋ณ ์ ๊ฐ์ ๋ํ timestamp ๊ฐ์ ๋ฃ๋๋ก ํฉ๋๋ค. (๋ง : 1455192000 = 2016. 2. 11. ์คํ 9:00:00, 1455195600 = 2016. 2. 11. ์คํ 10:00:00)
CREATE TABLE test_keyspace.test_ts_2 ( serverId TEXT, timeboundery INT, timestamp INT, data TEXT, PRIMARY KEY( (serverId, timeboundery), timestamp ) );
INSERT INTO test_keyspace.test_ts_2 ( serverId, timeboundery, timestamp, data ) VALUES ( 'server_1', 1455192000, 1455194927, '{ "userNumber" : 100, "serverStatus" : "STABLE" }' );
INSERT INTO test_keyspace.test_ts_2 ( serverId, timeboundery, timestamp, data ) VALUES ( 'server_1', 1455192000, 1455195227, '{ "userNumber" : 105, "serverStatus" : "STABLE" }' );
INSERT INTO test_keyspace.test_ts_2 ( serverId, timeboundery, timestamp, data ) VALUES ( 'server_1', 1455192000, 1455195527, '{ "userNumber" : 100, "serverStatus" : "STABLE" }' );
INSERT INTO test_keyspace.test_ts_2 ( serverId, timeboundery, timestamp, data ) VALUES ( 'server_1', 1455195600, 1455195827, '{ "userNumber" : 95, "serverStatus" : "STABLE" }' );
SELECT * FROM test_keyspace.test_ts_2;
USE test_keyspace;
LIST test_ts_2;
์ด์ ๋ 1์๊ฐ ๊ฐ๊ฒฉ์ผ๋ก timeboundery๋ฅผ ์ง์ ํ์ฌ Partition Key๋ก ์ฌ์ฉํ๋๋ก ํ์์ผ๋ฏ๋ก ๋ฐ์ดํฐ๋ ServerId์ timeboundery์ ์กฐํฉ์ผ๋ก ๋ถ์ฐ๋๋ค๋ ๊ฒ์ ์์ ๊ฒฐ๊ณผ๋ก ์ ์ ์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด๋ฌํ ๊ตฌ์กฐ์์๋ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ ๊ฒ๋๋ค. server_1 ์๋ฒ์ 2016๋ 2์ 11์ผ ์คํ 9์๋ถํฐ ์คํ 10์ ์ด์ ๊น์ง์ ๊ธฐ๋ก์ ๊ฒ์ํด๋ด ์๋ค.
SELECT * FROM test_keyspace.test_ts_2 WHERE serverId='server_1' AND timeboundery = 1455192000;
์ข ๋ ์์ธํ๊ฒ server_1 ์๋ฒ์ 2016๋ 2์ 11์ผ ์คํ 9์๋ถํฐ ์คํ 9์ 50๋ถ ์ด์ ๊น์ง์ ๊ธฐ๋ก์ ๊ฒ์ํ๋ฉด ์๋์ ๊ฐ์ต๋๋ค.
SELECT * FROM test_keyspace.test_ts_2 WHERE serverId='server_1' AND timeboundery = 1455192000 AND timestamp < 1455195000;
์ด์ ์ผ ๋น๋ก์ Time Sequencialํ ๋ฐ์ดํฐ๋ฅผ ์ผ์ ๊ธธ์ด๋ก ์๋ผ ๋ชจ๋ ๋ ธ๋์ ๊ณ ๋ฃจ ๋ถ์ฐํ ์ ์๊ณ , ๋ ์ํ๋ ๋ฐ์ดํฐ๋ฅผ ํฐ ์ ์ฝ ์์ด ๊ฒ์ํด ๊ฐ์ ธ์ฌ ์ ์์์ ํ์ธํ ์ ์์ต๋๋ค. ์ด๋ ๋ฏ ๋ฐ์ดํฐ์ ๊ธธ์ด๊ฐ ๋ฌดํ์ ๊ธธ์ด์ง๋ ๊ฒ์ ์ ๋นํ ๋๋ ์ ์๋๋ก Partition key๋ฅผ ์ง์ ํ๋ ๊ฒ์ ์คํค๋ง๋ฅผ ์ค๊ณํ ๋ ์์ด์ ๊ณ ๋ คํด์ผํ๋ ๋งค์ฐ ์ค์ํ ์์ ์ค ํ๋์ ๋๋ค.
(2) Denormalize
Cassandra๋ Join์ ์ง์ํ์ง ์๊ณ , ๊ณ ์์ค์ Index๋ ์ง์ํ์ง ์์ต๋๋ค. ๋๋ฌธ์ ๋ฐ์ดํฐ๋ฅผ ์ํ๋ ๋ฐฉ์์ผ๋ก ๊ฐ์ ธ์ค๋ ๋ฐ ๋ง์ ์ ์ฝ์ด ์์ ์ ๋ฐ์ ์์์ฃ . ๋ฐ๋ผ์ ์ด๋์ ๋ ์ฌ์ฉ์ฑ์ ๋ง์กฑํ๊ธฐ ์ํด์ ๋ง์ ์ฌ๋๋ค์ ๋ฐ์ดํฐ๋ฅผ ๋น์ ๊ทํํ์ฌ ๊ด๋ฆฌํด์์ต๋๋ค. ๋ฌผ๋ก 0.7 ๋ฒ์ ์ดํ๋ก Secondary Index๋ฅผ ํตํ์ฌ ์ด๋์ ๋ ๊ฒ์์ ๋ํ ์์ ๋๋ฅผ ๋์ผ ์ ์์์ง๋ง, ๊ทผ๋ณธ์ ์ธ ํด๊ฒฐ์ฑ ์ด ๋์ง๋ ๋ชปํ์ต๋๋ค. ๋ฐ๋ผ์ Cassandra์์์ ๋น์ ๊ทํ๋ ์ฌ์ ํ ๋ง์ ์ฌ๋๋ค์ด ์ฆ๊ฒจ ์ฐ๋ ๊ธฐ๋ฒ์ผ๋ก ๋จ์์ต๋๋ค. ์์ฃผ์์ฃผ ๊ฐ๋จํ ์๋ฅผ ๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
CREATE TABLE test_keyspace.test_worker (
name TEXT PRIMARY KEY
, job TEXT
);
Secondary Index๋ ์ผ๋จ ๋ ผ์ธ๋ก ๋์์ ๋, ์์ ๊ฐ์ ํ ์ด๋ธ์์๋ name์ ๊ธฐ์ค์ผ๋ก job ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์๋ ์์ง๋ง job์ ์ด์ฉํ์ฌ name๋ค์ ๊ฒ์ํ๋ ๊ฒ์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ด ๋ Cassandra๋ ๋ค์๊ณผ ๊ฐ์ด ํ ์ด๋ธ์ ์์ฑํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ค๋ฉด ๊ธ๋ฐฉ ํด๊ฒฐํ ์ ์์ ๊ฒ๋๋ค.
CREATE TABLE test_keyspace.test_job (
job TEXT PRIMARY KEY
, name TEXT
);
๋ฌผ๋ก ๊ฒฐ๊ณผ์ ์ผ๋ก ๋์ผํ ๋ฐ์ดํฐ๊ฐ ์ค๋ณต์ผ๋ก ์ ์ฅ๋์ด ๊ด๋ฆฌ๋๋ ๊ฒ์ด์ง๋ง, ์ด๋ Join์ด๋ Index๋ฅผ ์ ๋๋ก ์ง์ํ์ง ์๋ Cassandra์์๋ ๋งค์ฐ ์ผ์์ ์ธ ์ผ์ ๋๋ค. Cassandra์๊ฒ ์์ด์ scale out์ ๋ค๋ฅธ ์ผ์ ๋นํ๋ฉด ๋๋จํ ์ฌ์ด ์ผ์ด๋๊น์. ๋๊ตฌ๋ Disk์ ๋ค์ด๊ฐ๋ ๋น์ฉ์ Memory๋ CPU๊ฐ์ ๋ค๋ฅธ ์์์ ๋นํ๋ฉด ๊ฐ์ฅ ์ ๋ ดํ๋ค๋ ๊ฒ์ ์๊ฐํด ๋ณด์์ ๋, ์ด๋ ์ด์ฉ๋ฉด ๋น์ฐํ ๊ฒฐ๊ณผ๋ผ๊ณ ๋ ํ ์ ์๊ฒ ์ต๋๋ค. ๋ฐ๋ผ์ Cassandra๋ฅผ ์ฌ์ฉํ ๋์๋ RDBMS์๋ ๋ค๋ฅด๊ฒ ๋น์ ๊ทํ ์ญ์ ์ถฉ๋ถํ ๊ณ ๋ คํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ ๊ฒ์ธ์ง ์ฉ๋์ ๋ง๋ ์คํค๋ง๋ฅผ ๊ฒฐ์ ํ์ฌ ์ฌ์ฉํด์ผํ ๊ฒ์ ๋๋ค.
(3) Paging
์ฌ์ค Cassandra์๊ฒ ํ์ด์ง์ ์ฐธ ๊ณค๋ํ ๋ฌธ์ ์ค ํ๋์ ๋๋ค. ๋น๋ก Limit๋ผ๋ CQL ๊ตฌ๋ฌธ์ด ์๊ธฐ๋ ํ์ง๋ง ๋ง ๊ทธ๋๋ก ๊ฐ์ ธ์ฌ ๋ฐ์ดํฐ์ ๊ฐ์๋ฅผ ์ ํํด์ฃผ๋ ์ญํ ์ผ ๋ฟ, MySQL์ Limit ์ฒ๋ผ Offset๊น์ง ์ฒ๋ฆฌํด์ฃผ์ง ์๋๋ฐ๋ค ๊ทธ๋ ๋ค๊ณ ROW NUMBER์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ์ ๋๋ฒ๋ง์ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๋ ๊ฒ๋ ์๋๋๋ค. ์ฌ์ ์ด ์ด๋ ๋ค ๋ณด๋, ์๋ฌด๋๋ Cassandra์์ Paging์ ๊ตฌํํ๋ ๊ฒ์ ์๊ฐ๋ณด๋ค ์ฝ์ง ์์ ์ผ์ด์ฃ . ๊ทธ๋๋ง ํ๋์ Partition Key(Row Key) ์ ์ํ Column๋ค์ ๋ํ ๋ฐ์ดํฐ๋ ์ด๋ฏธ ์ ๋ ฌ๋์ด์๋ค๋ ํน์ฑ์ ์ด์ฉํ์ฌ Paging์ด ๊ฐ๋ฅํ๊ฒ ์ง๋ง, Partition Key(Row Key) ๋จ์์ ํ์ด์ง์ ๊ตฌํํ๋ ๊ฒ์ ์ฌ์ค์ ๋ถ๊ฐ๋ฅํฉ๋๋ค. ์ด์ ์ธ ์ฆ, Cassandra์ Partition Key๋ค์ ๋ชจ๋ Hashing๋ ๊ฒฐ๊ณผ๊ฐ์ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ถ์ฐํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
๊ณผ๊ฑฐ ByteOrderedPartitioner๋ฅผ ์ฌ์ฉํ๋ ์์ ์๋ ๊ทธ๋๋ Partition Key์ ๋ํ Paging์ด ๊ฐ๋ฅํ์์ต๋๋ค. ๋ชจ๋ ๋ ธ๋์ ๋ํ์ฌ Partition Key์ 16์ง์ byte ๊ฐ ์์๋๋ก ๋ฐ์ดํฐ๊ฐ ๋ถ์ฐ๋์์ผ๋๊น์. ํ์ง๋ง ์์๋ค์ํผ BOP๋ Hotspot์ด ์๊ธธ ์ ์๋ ๊ฐ์ฅ ํฐ ์ํ์์์๊ณ ๋ํ์ ์ธ Anti-Pattern์ผ๋ก ์๋ ค์ ธ ํ์ฌ๋ Murmur3Partitioner๊ฐ ๊ธฐ๋ณธ Partitioner๋ก ์ฌ์ฉ๋จ์ ๋ฐ๋ผ ๋ชจ๋ Partition Key๋ค์ Hashing ๋ ๊ฒฐ๊ณผ๊ฐ์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ๋์ด ์ ์ฅ๋๊ณ ์์ต๋๋ค. ๋ฐ๋ผ์ Cassandra์์ ์ ๊ณตํ๋ Token()๋ผ๋ ํน๋ณํ ํจ์๋ฅผ ์ด์ฉํ์ฌ, Hashing๋ ๊ฐ์ ์์๋๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๊ฐ๋ฅํฉ๋๋ค๋ง, ๊ณ์ ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ, ์์ , ์ญ์ ๋ ๋๋ง๋ค ๋ฐ์ดํฐ์ ์ ๋ ฌ ์ํ๊ฐ ๋ฐ๋๊ฒ ๋ ํ ๋ ์ฌ์ฉ์ฑ์ ๊ทธ๋ค์ง ๋์ง ์๋ค๋ ๋ฌธ์ ๊ฐ ๋ํ๋๊ฒ ๋ ๊ฒ์ด์ฃ .
์ด์จ๊ฑฐ๋, Keyspace - Table - Row - Column ์ผ๋ก ๊ณ์ธตํ ๋์ด์๋ Cassandra ๊ณ ๋ คํ์ ๋ Paging์ ๊ตฌํํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง๋ก ์์ฝํ ์ ์์ ๊ฒ๋๋ค.
์ฒซ์งธ, ํ๋์ Partition Key์ ์ํ๋ Column๋ค์ ๋ํ ํ์ด์ง.
๋์งธ, ์ฌ๋ฌ ๊ฐ์ Partition Key(Row Key)์ ๋ํ ๋ฐ์ดํฐ ํ์ด์ง.
ํ๋์ฉ ์์๋ณด๊ฒ ์ต๋๋ค.
- ํ๋์ Partition Key์ ์ํ๋ Column๋ค์ ๋ํ ํ์ด์ง.
์ฌ์ค ์ด ๊ฒฝ์ฐ๋ ์ด๋ ต์ง ์๊ฒ ๊ตฌํ์ด ๊ฐ๋ฅํฉ๋๋ค. ์ฐ์ , ์๋์ ๊ฐ์ Table์ ์์ฑํ๊ณ ํ๋์ 'junior'๋ผ๋ Partition Key์ a๋ถํฐ z๊น์ง๋ก ์์ํ๋ ์ฌ๋์ ์ด๋ฆ์ด ํ๋์ฉ ์ด 26๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋์ด์๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค.
CREATE TABLE test_keyspace.test_paging_1 ( class TEXT , name TEXT, description TEXT, PRIMARY KEY (class, name) );
INSERT INTO test_keyspace.test_paging_1 ( class, name, description ) VALUES ( 'junior', 'aron', 'developer' );
INSERT INTO test_keyspace.test_paging_1 ( class, name, description ) VALUES ( 'junior', 'baker', 'developer' );
-- ...
INSERT INTO test_keyspace.test_paging_1 ( class, name, description ) VALUES ( 'junior', 'zena', 'developer' );
SELECT * FROM test_keyspace.test_paging_1;
ํ๋์ Partition Key(Row Key) ๊ธฐ์ค์ผ๋ก ๋ด๋ถ์ ๋ฐ์ดํฐ๋ค์ ์ด๋ฏธ ์ ๋ ฌ๋ ์ํ๋ก ์กด์ฌํ๊ธฐ ๋๋ฌธ์ ์ฐ๋ฆฌ๋ Limit ๊ตฌ๋ฌธ์ ์ด์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
SELECT * FROM test_keyspace.test_paging_1 WHERE class = 'junior' LIMIT 5;
๊ทธ๋ ๋ค๋ฉด ๊ทธ ๋ค์์ด ๋ฌธ์ ์ ๋๋ค. ๊ฐ์ฅ ์ฒ์ 5๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผ๋ ๊ทธ ๋ค์ ๋ฐ์ดํฐ 5๊ฐ๋ ์ด๋ป๊ฒ ๊ฐ์ ธ์์ผํ ๊น์? ์ํ๊น๊ฒ๋, Cassnadra์ Limit์ ์ ์งํ๊ฒ ๋ง ๊ทธ๋๋ก ๊ฐ์ ธ์ฌ ๋ฐ์ดํฐ์ ๊ฐ์๋ง์ ์ ํํ ๋ฟ ๋ค๋ฅธ ๊ธฐ๋ฅ์ด ์์ต๋๋ค. ๋ฐ๋ผ์ ์ด๋ฏธ ์ฐ๋ฆฌ๊ฐ ํ์ธํ ์ 5๊ฐ์ ๋ฐ์ดํฐ ์ค ๊ฐ์ฅ ๋ง์ง๋ง ๋ฐ์ดํฐ๋ฅผ ๊ธฐ์ค์ผ๋ก Query๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค.
SELECT * FROM test_keyspace.test_paging_1 WHERE class = 'junior' AND name < 'elen' LIMIT 5;
์ด๋ฌํ ๋ฐฉ์์ Paging ๋ฐฉ์์ ๋ช๋ช ๋จ์ ์ด ์์ต๋๋ค. ๋ง์ฝ RDBMS๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๋ด๋ถ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฌํ๊ณ ๊ฒฐ๊ณผ์ id๋ offset์ ๊ณ์ฐํ์ฌ ์ํ๋ ์์น์ ๋ฐ์ดํฐ๋ง ์๋ผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ํ์ง๋ง Cassandra์ ๊ฒฝ์ฐ ์ด๋ฌํ ๊ธฐ๋ฅ์ด ์๊ธฐ ๋๋ฌธ์ ์ํ๋ ์์น์ ๋๋ฌํ ๋๊น์ง Application์ด ์ง์ Cassandra์๊ฒ ๊ณ์ ์ง์๋ฅผ ํด์ผํ๋ ๊ฒ์ด์ฃ . ์๋ฅผ ๋ค์ด ๋น์ฅ ์ฒซ๋ฒ์งธ ํ์ด์ง์์ ํ ๋ฒ์ 10ํ์ด์ง ๋ค์ ์ ๋ณด๋ฅผ ์๊ณ ์ถ๋ค๋ฉด, ์ฌ์ฉํ์ง๋ ์์ 9ํ์ด์ง ๋ถ๋์ ์ฐจ๋ก๋ก ์ฝ์ด์จ ๋ค์์์ผ ๋ง์ง๋ง 10๋ฒ์งธ ํ์ด์ง์ ๋ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ๋๊ตฐ๋ค๋ ์ด๋ฌํ ๋ฐฉ์์ Paging ๋์์ด ๋๋ ๋ฐ์ดํฐ ์งํฉ์ ๋ณํ์ ์ ์ฐํ๊ฒ ๋์ฒํ๊ธฐ ํ๋ค๊ธฐ ๋๋ฌธ์, ์ ํํ Paging์ ๊ตฌํํ๊ณ ์ ํ๋ค๋ฉด ๋งค๋ฒ ๋ฐ์ดํฐ๋ฅผ ์ฒ์๋ถํฐ ์๋ก ์ฝ์ด์ค๋ ๊ฒ์ ๋ฐ๋ณตํด์ผํ ๊ฒ์ ๋๋ค.
- ์ฌ๋ฌ๊ฐ์ Partition Key์ ๋ํ ๋ฐ์ดํฐ์ ๋ํ ํ์ด์ง.
ํ์ง๋ง ์ง๊ธ ์ดํด๋ณผ ๋ด์ฉ์ ๋นํ๋ฉด ๊ทธ๋๋ง ํ๋์ Partition Key์ ๋ํ ๋ฐ์ดํฐ๋ค์ Paging์ ๊ทธ๋๋ง ๋์๋ค๋ ์๊ฐ์ด ๋ค์ง๋ ๋ชจ๋ฆ ๋๋ค. ์์ ๋ง์๋๋ ธ๋ฏ์ด ํ๋์ Partition Key์ ์ํ ๋ฐ์ดํฐ๋ ์ด๋ฏธ ์ ๋ ฌ๋์ด ์ ์ฅ๋์ด์๊ธฐ๋ผ๋ ํ์ง๋ง, Cassandra์ ์ํ ์๋ง์ ๋ ธ๋๋ค์ ํฉ๋ฟ๋ ค์ง Partition Key(Row Key)๋ค์ Hashing์ ํตํ์ฌ ๋๋คํ Token๋ค๋ก ๋ณํ์ด ๋ ์ฑ ๋ถ์ฐ๋์๊ธฐ ๋๋ฌธ์, ์๋ฐํ ๋งํ์๋ฉด Token์ ๊ธฐ์ค์ผ๋ก ์ ๋ ฌ๋ ๊ฒ์ด๋ ๋ค๋ฆ์๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ง์ฝ ์ ๋ง์ ๋ง ํ์ํ์ฌ ์ ๋ ฌ๋ ๋ฐ์ดํฐ๋ฅผ ์ป๊ณ ์ถ๋ค๊ณ ํ๋ค๋ฉด, Cassandra์ ์ ์ฅ๋ ๋ชจ๋ Partition Key๋ค์ ๊ฐ์ ธ์์ Application์ด ์ง์ ์ ๋ ฌ์ ํ๊ณ ๊ทธ ์์์ ์ํ๋ ๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ถ์ถํด์ผํ ํ ๋ฐ, ์ด๋ ์์๋งํด๋ ๋์ฐํ ์ผ์ด ์๋ ์ ์๊ฒ ์ฃ .
์ด๋ ๋ฏ Partitioner์ ์ํด Partition Key๋ Hashing๋์ด ์ ์ฅ๋๋ฏ๋ก ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋ฐ์ดํฐ๋ ์ป์ ๋ฐฉ๋ฒ์ด ์์ง๋ง, Cassandra๋ Hashing๋ Token์ ๋ํ Range Query๋งํผ์ ๊ฐ๋ฅํ ์ ์๊ฒ ํด์ฃผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๊ณ ์์ต๋๋ค. Token() ํจ์๊ฐ ๊ทธ๊ฒ์ ๋๋ค. ์ผ๋จ ์์ ๊ตฌํ์ ์ํ์ฌ ์๋์ ๊ฐ์ด Table์ ์์ฑํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํด๋ณด๋๋ก ํฉ์๋ค. ์ด๋ฒ์ class์ name์ ๋ฐ๊พธ๋๋ก ํ๊ฒ ์ต๋๋ค.
CREATE TABLE test_keyspace.test_paging_2 ( name TEXT, class TEXT ,description TEXT, PRIMARY KEY (name, class) );
INSERT INTO test_keyspace.test_paging_2 ( name, class, description ) VALUES ( 'aron', 'junior', 'developer' );
INSERT INTO test_keyspace.test_paging_2 ( name, class, description ) VALUES ( 'baker', 'junior', 'developer' );
-- ...
INSERT INTO test_keyspace.test_paging_2 ( name, class, description ) VALUES ( 'zena', 'junior', 'developer' );
๊ทธ๋ผ ์ฐ์ ์ํ์ผ์ ์๋์ ๊ฐ์ Query๋ฅผ ์ํํด๋ด ์๋ค.
SELECT * FROM test_keyspace.test_paging_2 WHERE name < 'elen' LIMIT 5;
๋น์ฐํ ์ด์ผ๊ธฐ์ง๋ง Query๋ ์คํจํฉ๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์๋์ ๊ฐ์ด Token() ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋จ๊น์?
SELECT * FROM test_keyspace.test_paging_2 WHERE token(name) < token('elen') LIMIT 5;
๋น๋ก ์ ๋ ฌ๋ ๋ฐ์ดํฐ๋ ์๋์ง๋ง, ์ด์จ๊ฑด ์ํ๋ 5๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฎ์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ ๋ฏ ๊ต์ฅํ ์ ํ์ ์ด๊ณ ๋น์ฝํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ Cassandra์ด์ง๋ง, ๋ง์ ์ฌ๋๋ค์ ์ด ์ํฉ์์๋ ์ด๋ป๊ฒ๋ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ํ ๋๋ฆ์ ๋ฐฉ๋ฒ์ ์ง๋ด๊ณ ๋ ํฉ๋๋ค. ์ฌ์ ํ ์ ํ์ ์ผ์ง๋ผ๋ ์์ ๋ ๋ฐฉ์์์ด ์กฐ๊ธ ๋ ๋์ Paging์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ๋ฐ๋ก Prefix๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋๋ค. ์ผ์ข ์ ํธ๋ฒ์ธ ์ ์ด์ฃ . ์ฐ์ ์๋์ ๊ฐ๋จํ Table์ ๋ณด๊ฒ ์ต๋๋ค.
CREATE TABLE test_keyspace.test_paging_3 ( prefix text, remain text, name text, description text PRIMARY KEY ( prefix, body,) );
INSERT INTO test_keyspace.test_paging_3 ( prefix , remain , name, class, description ) VALUES ( 'a', 'ron', 'aron', 'junior', 'developer' );
INSERT INTO test_keyspace.test_paging_3 ( prefix , remain , name, class, description ) VALUES ( 'b', 'aker', 'baker', 'junior', 'developer' );
-- ...
INSERT INTO test_keyspace.test_paging_3 ( prefix , remain , name, class, description ) VALUES ( 'z', 'ena', 'zena', 'junior', 'developer' );
SELECT * FROM test_keyspace.test_paging_3 ;
์ด Table์ ๊ธฐ์ค์ผ๋ก ์๊ฐํด๋ณด๋ฉด, Prefix๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ฐ์ดํฐ๊ฐ ๋ถ์ฐ๋๊ณ ํด๋น Prefix ์์์๋ remain ๊ฐ์ผ๋ก ๋ฐ์ดํฐ๊ฐ ์ ๋ ฌ๋์ด ์ ์ฅ๋๋ ๊ฒ์ด์ฃ . ๊ฒฝ์ฐ์ ๋ฐ๋ผ ์ ์ฉํ๊ฒ ์ธ ์ ์์ ๋ฒ๋ ํฉ๋๋ค. ํ์ง๋ง Sharding์ ๊ณ ๋ คํ์ง ์์ผ๋ฉด์ ๋ฐ์ดํฐ๋ฅผ ๊ณ ๋ฅด๊ฒ ๋ถ์ฐํ๊ธฐ ์ํด Partitioner๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์์๋ ๋ถ๊ตฌํ๊ณ Prefix๋ผ๋ ํธ๋ฒ์ ์ฌ์ฉํจ์ผ๋ก์จ Hotspot์ด ์๊ธธ ์ ์๋ ์ํ์ ์ด๋ํ ์ ์๋ค๋ ์ ์ ์ถฉ๋ถํ ๊ณ ๋ คํด์ผํ ๊ฒ์ ๋๋ค.
4. Cassandra Anti-Pattern
์ง๊ธ๊น์ง Cassandra์์ ์ผ๋ฐ์ ์ผ๋ก ์ฐ์ด๊ฑฐ๋ ์ ์ฉํ๊ฒ ์ธ ์ ์๋ ์์ ํ๋ค์ ์์๋ณด์์ต๋๋ค. ๊ทธ๋ ๋ค๋ฉด ์ด์ ๋ง์ง๋ง์ผ๋ก ์์๋ณผ ๊ฒ์ ๋๋๋ก์ด๋ฉด ํผํด์ผํ Cassandra์ ์ฌ์ฉ ๋ฐฉ์์ ์ง์ด๋ณผ ์ฐจ๋ก๊ฐ ๋์์ต๋๋ค. ๋ช๋ช ๋ถ๋ถ๋ค์ ์ด๋ฏธ ์์์๋ ์ด์ผ๊ธฐํ ๋ฐ๊ฐ ์์ผ๋ฏ๋ก, ๋ค์ ๊ฒน์น๋ ๋ด์ฉ๋ค์ ๊ฐ๋ตํ ์ค๋ช ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
(1) Unbounded Data
์ ์ ์์ Time Sequencial Data์ Cassandra ์ฌ์ฉ๋ฒ์ ๋ํด ์์๋ณด๋ฉด์ ๊ฐ๋จํ ์ง๊ณ ๋์ด๊ฐ ๋ด์ฉ์ ๋๋ค. ๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด ํ๋์ Partition Key(Row Key)์ด ๋ฌดํํ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ง ๋ง๋ผ๋ ๊ฒ์ด์ฃ . ์ด๋ฌํ ๋ฐฉ์์ ํน์ ๋ ธ๋์ Hotsopt์ ๋ฐ์์ํฌ ์ํ์ ๋ง๋ค๊ณ ๋ ํ๋์ Partition Key์ ์ํ ๋ฐ์ดํฐ๊ฐ ๊ณผ๋คํ๊ฒ ๊ธธ์ด์ง๋ฉด ๊ฒ์ ์ฑ๋ฅ์ด๋ ์ ์ ํ Query ๊ตฌํ์๋ ๋ถ์ด์ต์ด ์๊ธฐ๋ ๊ฒ์ ๋น์ฐํ ์ด์ผ๊ธฐ์ผ ๊ฒ์ ๋๋ค.
(2) Secondary Index
๋๋์ด Secondary Index์ ๋ํ ์ด์ผ๊ธฐ๋ฅผ ํ ์ฐจ๋ก๊ฐ ๋ ๊ฒ ๊ฐ์ต๋๋ค. Secondary Index๋ Cassandra์๊ฒ ๋ถ์กฑํ ๋ถ๋ถ์ ์ฑ์์ฃผ๋ ์๋นํ ํธ๋ฆฌํ ๊ธฐ๋ฅ๋ค ์ค ํ๋์ ๋๋ค. ํ์ง๋ง ์ด๋ ๊ฒ ์ ์ฉํ๊ฒ ์ธ ์ ์์ ๊ฒ ๊ฐ์ ์ด ๊ธฐ๋ฅ์ ๋ด๋ถ์ ์ผ๋ก ์ด๋ป๊ฒ ๋์ํ๊ณ ์๋์ง ์์๋ณผ ํ์๊ฐ ์์ต๋๋ค. Secondary Index์ ๋จ์ฉ์ ํํ Anti-Pattern์ผ๋ก ๋๋ฆฌ ์๋ ค์ ธ์๊ธฐ ๋๋ฌธ์ด์ฃ . ์ด์ ๋ ๊ทธ๋ฆฌ ๋ณต์กํ์ง ์์ต๋๋ค.
Cassandra๋ Secondery Index๋ฅผ ์ํ์ฌ ๋ด๋ถ์ ์ธ Table(ColumnFamily) ์ ๋ณด๋ฅผ ๋ฐ๋ก ๊ด๋ฆฌํ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ํน์ Table์ ํน์ Column์ ๋ํด Secondary Index๋ฅผ ์ง์ ํ๊ฒ ๋๋ค๋ฉด, ํด๋น Column์ Value๋ค์ Partition Key(Row Key)๋ก ๋ง๋ค์ด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ตฌ์กฐ์ ๋๋ค. ๊ฐ๋จํ ์๋ฅผ ๋ค์ด๋ด ์๋ค. ์๋์ ๊ฐ์ Table๊ณผ Index๋ฅผ ์์ฑํ ๋ค์ 3๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ ฅํด๋ณด๊ฒ ์ต๋๋ค.
CREATE TABLE test_keyspace.test_user (
id TEXT PRIMARY KEY
, name TEXT
, location TEXT
);
CREATE INDEX test_user_idx ON test_keyspace.test_user (location);
INSERT INTO test_keyspace.test_user (id, name, location) VALUES ( 'test_id_1', 'duron', 'seoul');
INSERT INTO test_keyspace.test_user (id, name, location) VALUES ( 'test_id_2', 'frank', 'busan');
INSERT INTO test_keyspace.test_user (id, name, location) VALUES ( 'test_id_3', 'jack', 'seoul');
SELECT * FROM test_keyspace.test_user;
Partition Key๋ก id๊ฐ ์ง์ ๋์์ผ๋ฏ๋ก ์์ ์ธ ๋ฐ์ดํฐ๋ ์ธ ๊ฐ์ Row๋ก ๋๋์ด ๋ฐ์ดํฐ๊ฐ ์ ์ฅ๋์์ ๊ฒ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๋ Secondary Index๋ Cassandra ๋ด๋ถ์ ์ผ๋ก ๋๋ต ์๋์ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ ๊ฐ์ ํํ๋ก ์ ์ฅ๋ฉ๋๋ค.
-- RowKey: busan
-- =< (name=test_id_2:, value=)
-- -------------------
-- RowKey: seoul
-- =< (name=test_id_1:, value=)
-- =< (name=test_id_3:, value=)
์ฆ, Index๋ก ์ง์ ํ ๋ฐ์ดํฐ๋ฅผ Cassandra Data Layer์ Row Key๋ก ๊ฐ์ง๊ณ ํด๋น ๋ฐ์ดํฐ์ ์ค์ Row Key(์ ์์ ์์๋ id)๋ค์ Column์ผ๋ก ๋ชฉ๋ก์ฒ๋ผ ๋ค๊ณ ์๋ ๊ฒ์ด์ฃ . ์ด๋ฐ ๋ฐฉ์์ ์ด์ฉํด Cassandra๋ Secondary Index๋ก ์ง์ ๋ Column์ ๊ฐ์ ๊ฐ์ ธ์ ํด๋น ๊ฐ์ ์ํ ์ค์ Row Key๋ค์ ์๊ณ ๊ฐ ๋ ธ๋์ ์ ๊ทผํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋ฉ๋๋ค.
์ด๋ฐ ๊ตฌ์กฐ๋ก ๋๋ฌธ์, Secondary Index๋ก ์ง์ ๋ Column์ด๋ผ ํ๋๋ผ๋ Range Query๋ ์ฌ์ฉํ ์ ์๊ณ , '='์ ์ด์ฉํ ๋จ์ ๊ฒ์์ด๋ CONTAINS์ ๊ฐ์ ๋ฌธ๋ฒ์ ํตํด Multi-get ํ์์ผ๋ก ํ๋ฒ์ ์ฌ๋ฌ Column Value์ ๋ํ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์ค๋ ์ ๋์ ํ์ ์ ์ธ ๊ธฐ๋ฅ๋ง ์ฌ์ฉํ ์ ์๋ ๊ฒ์ด์ฃ .
๊ทธ๋ฌ๋ ์ ์ ๊ฐ์ฅ ํฐ ๋ฌธ์ ๋ ๋ฐ๋ก ์์ต๋๋ค. ๋ง์ฝ Secondary Index๋ก ์ง์ ๋ Column์ ์ค๋ณต๋๋ ๊ฐ์ด ์์ฒญ๋๊ฒ ๊ธธ๋ค๊ณ ๊ฐ์ ํด๋ด ์๋ค. ๋ฐฉ๊ธ ์ ์์ ๋ฅผ ๊ธฐ์ค์ผ๋ก ํ๋ค๋ฉด, 'seoul'์ ์ฌ๋ ์ฌ์ฉ์์ ์๊ฐ ์์ฒญ๋๊ฒ ๋ง์ ๊ฒฝ์ฐ์ผ ๊ฒ๋๋ค. Secondary Index์ 'seoul'์ด๋ผ๋ Row Key ์๋์ ์๋ง์ ์ฌ์ฉ์๋ค์ id๋ค์ด ์ฃผ๋ ์ฃผ๋ ๋งค๋ฌ๋ ค์๋ค๋ ์ด์ผ๊ธฐ๊ฒ ์ฃ . ๊ทธ๋ ๋ค๋ฉด ์ด ๋ 'seoul'์ ๋ํ Query๋ฅผ ํ๊ฒ ๋๋ค๋ฉด? ๋ค. 'seoul'์ ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ฒ์ํ๊ธฐ ์ํด ๊ทธ ๋ง์ id๋ค์ด ์ ์ฅ๋ Cassandra์ ์๋ง์ ๋ ธ๋๋ค์ ์ ๋ถ ์ ๊ทผํ๊ฒ ๋ฉ๋๋ค. ๋ง์ฝ 'seoul'์ ์ํ id๊ฐ ์ ๋ง ๋ง๋ค๊ณ ํ๋ค๋ฉด, ์ต์ ์ ๊ฒฝ์ฐ์ Cassandra์ ์ํ ๋ ธ๋ ์ ๋ถ๊ฐ ๊ต์ฅํ ๋ฐ๋น ์ง๊ฒ ๋๊ฒ ์ฃ . ๋๊ตฐ๋ค๋ Consistancy Level์ ๋ง์ถ์ด ๊ฐ ๋ฐ์ดํฐ ๋ณ Replication๋ค๋ ํ์ธํด์ผํ๋ค๋ ์ ์ ๊ฐ์ํ๋ค๋ฉด... ์ด๋ ์ ๋ ์ฆ๊ฑฐ์ด ์ํฉ์ ์๋ ๊ฒ๋๋ค.
๋ฐ๋ผ์ Secondary Index์ ์ฌ์ฉ์ ์ ์คํ ๊ฒฐ์ ๋์ด์ผํ๊ณ , ๋น์ ๊ทํ๋ ์ฌ์ ํ ๋ง์ ์ฌ๋๋ค์๊ฒ ์ฌ๋๋ฐ๋ Cassnadra Data Modeling ๊ธฐ๋ฒ ์ค ํ๋๋ก ๋จ์์ต๋๋ค. ์ด์ฐจํผ Cassandra์ ๋ ธ๋๋ฅผ ์ถ๊ฐํ๋ ๊ฒ ์ ๋์ผ ํฐ ๋ฌธ์ ๋ ์๋๋๊น์.
(3) Delete Data
Tombstone์ Cassandra๊ฐ ๊ฐ์ง๊ณ ์๋ ๊ฝค๋ ํน์ง์ ์ธ ๋ถ๋ถ๋ค ์ค ํ๋์ ๋๋ค. ์ด์ ๊ธ์์ ์ค๋ช ํ ์ ์ด ์๋ฏ์ด, Cassandra๋ ๊ธฐ๋ณธ์ ์ผ๋ก Data์ Delete๋ฅผ ๋ฐ๋ก ์ํํ์ง ์๊ณ ์ Tombstone์ด๋ผ ๋ถ๋ฆฌ๋ marker์ ํ์๋ฅผ ํด๋ ๋ค, ์๊ฐ์ด ์ง๋ SSTable๋ค์ compaction์ด ์งํ๋ ๋ ๋น๋ก์ ๋ฐ์ดํฐ๊ฐ ์ ๋ง๋ก ์ญ์ ๋๋ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ผ๋จ ์ด๊ฒ๋ง ๋ณด๊ธฐ์ ๋๋ฆ ์ผ๋ฆฌ๊ฐ ์์ด ๋ณด์ด๋ ํจ์จ์ ์ด๊ณ ํฉ๋ฆฌ์ ์ธ ๊ตฌ์กฐ๋ผ๊ณ ํ ์ ์๊ฒ ์ง๋ง, ์ค์๊ฐ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ์ง ์๋๋ค๋ ์ด ์์น์ผ๋ก ์ธํ์ฌ ๋ช๊ฐ์ง ์์ํ์ง ๋ชปํ ํน์ดํ ๋ถ์์ฉ์ด ๋ฐ์ํ๊ฒ ๋์์ฃ .
์ฒซ๋ฒ์งธ๋ ์ญ์ ๋ ๋ฐ์ดํฐ๊ฐ ๋ถํํ๋ ๊ฒฝ์ฐ์ ๋๋ค. ์ ๋ง ๋ฌด์๋ฌด์ํ ๋ง์ด ์๋ ์ ์์ต๋๋ค. ์ญ์ ํ๋ ๋ฐ์ดํฐ๊ฐ ์ด์๋๋ค๋์. ํ์ง๋ง ์๋ ๋๋ ์์ด ๋ฐ์ดํฐ๊ฐ ๋ถํํ๋ค๋ ๊ทธ๋ฐ ๋ง์ ์๋๋๋ค. ๊ทธ๋ผ ์ด๋จ ๋ ์ญ์ ๋ ๋ฐ์ดํฐ๊ฐ ์ข๋น๋ง๋ฅ ๋ถํํ๋ ๊ฑธ๊น์?
์ด ๋ฌธ์ ๋ ์ฅ์ ๊ฐ ๋ฐ์ํ ๋ ธ๋๊ฐ ์ ์ํ๋์ด Ring์ ๋ณต๊ทํ ๋ ๋ฐ์ํ ์ ์์ต๋๋ค.
Cassandra์ ๋ ธ๋ ์ค ํ๋๊ฐ ์ฅ์ ๊ฐ ๋ฐ์ํ์ ๊ฒฝ์ฐ๋ฅผ ๊ฐ์ ํด๋ด ์๋ค. ์ฅ์ ๋ ธ๋๋ ๋ค์ด๋์ด ์ฌ์ฉํ ์ ์์ง๋ง ๋ค๋ฅธ ๋ ธ๋๋ค์ ์ ์์ ์ผ๋ก ๋์ํ๊ฒ ์ฃ . ๊ทธ ์์ค์ ๋ง์ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ์ด ์ผ์ด๋ ํ ๋ฐ, ๊ทธ์ค์ ์ญ์ ํด์ผํ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ๋ค๋ฅธ ์ ์ ์ํ์ ๋ ธ๋๋ค์์๋ ์ด๋ฏธ ์ ์์ ์ผ๋ก ์ญ์ ๋ ํ์ผ ๊ฒ๋๋ค. ๊นจ๋ํ๊ฒ ์ฃ . ์๋ฌด๋ฐ ํ์ ์ด ๋จ์ง ์์์ ๊ฒ๋๋ค. ์ด๋ ์ฅ์ ๋ ธ๋๊ฐ ์ฅ์ ์์ ๋ฒ์ด๋ Ring์ ๋ณต๊ทํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ์ฅ์ ๋ ธ๋๋ ๊ทธ๋์ ์์๋ ๋ฐ์ดํฐ์ ๋ณ๊ฒฝ์ ์ ๋ฐ์ํ๊ธฐ ์ํ์ฌ ๋ค๋ฅธ ๋ ธ๋์ Gossip Protocol์ ํตํด ๋ฐ์ดํฐ๋ฅผ ๋ณต๊ตฌํ๊ธฐ ์์ํ ๊ฒ๋๋ค. ๋ณ๊ฒฝ๋ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ์ต์ ์ผ๋ก ๊ฐฑ์ ํด์ฃผ๊ณ , ์๋ก์ด ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ๋ณต์ฌํด์ ๊ฐ์ ธ์ต๋๋ค. ๋ฌธ์ ๋ ์ด ๊ณผ์ ์์ ์๊ธฐ๊ฐ ๋ค๊ณ ์๋, ๋ค๋ฅธ ๋ ธ๋๋ค์์ ์ด๋ฏธ ์ญ์ ๋ ๋ฐ์ดํฐ๋ฅผ ๋๋ก ๋ณต๊ตฌ์์ผ๋ฒ๋ฆฌ๋ ์ํฉ์ด ๋ฐ์ํ๋ ๊ฒ์ด์ฃ . ์ด๋ฏธ ๋ค๋ฅธ ๋ ธ๋๋ค์๋ ์กด์ฌํ์ง ์๋ ๋ฐ์ดํฐ์ธ๋ฐ ๋ ผ๋ฆฌ์ ์ผ๋ก ๋ดค์ ๋ ๋๋ง ๊ฐ์ง๊ณ ์๋๋ผ๋ ์ด๋ ์ ์์ ์ธ ๋ฐ์ดํฐ๋ฏ๋ก Replication์ ๋ง์กฑ์ํค๊ธฐ ์ํด์ ๋ค๋ฅธ ๋ ธ๋๋ค์ ๋ค์ ๋ฐ์ดํฐ๋ฅผ Write ํด๋ฒ๋ฆฌ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ ๊ฒ ์ฃฝ์ ๋ฐ์ดํฐ๊ฐ ๋ค์ ์ด์๋๊ฒ ๋ฉ๋๋ค.
Cassandra์ conf/cassandra.yaml์ ํ์ธํ์๋ฉด gc_grace_seconds๋ผ๋ ์ต์ ์ ํ์ธํ์ค ์ ์๋๋ฐ, ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด ์ด๋ ์ฌ๋ฌ ๊ฐ์ ๋ ธ๋๋ก ๊ตฌ์ฑ๋ Ring ๊ตฌ์กฐ์์ ์๋ก ๊ฐ์ ๋ฐ์ดํฐ์ ์ญ์ ์ฌ๋ถ์ ๋ํ ์ํ๋ฅผ ์ถฉ๋ถํ ์์ ํ๊ฒ ์ ํํ๊ธฐ ์ํ tomstone์ garbage collecting ์ฃผ๊ธฐ๋ฅผ ์ค์ ํ๋ ์ต์ ์ ๋๋ค. ์ฃฝ์ ๋ฐ์ดํฐ๊ฐ ๋ค์ ์ด์๋๋ ์ด๊ฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ํ๊ธฐ ์ํด์๋ gc_grace_seconds์ ์ต์ ์ ์ ์คํ๊ฒ ๊ฒฐ์ ํ๊ณ , ์ฅ์ ๋ ธ๋์ ๋ณต๊ตฌ ์์ ์ gc_grace_seconds๋ฅผ ๋๊ธฐ์ง ์๋๋ก ๋ ธ๋ ฅํด์ผํฉ๋๋ค. ๋ง์ฝ gc_grace_seconds ์ฃผ๊ธฐ๊ฐ ์ง๋ ์์ ์์ ์ฅ์ ๋ ธ๋๊ฐ ๋ณต๊ตฌ๋์๋ค๋ฉด, ๋ค๋ฅธ ์ ์ ๋ ธ๋๋ค์ ๋์ ํ๋ฅ ๋ก compaction์ ํตํ์ฌ ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์ญ์ ํด๋ฒ๋ ธ์ ํ ๋๊น์.
๋๋ฒ์งธ๋ก๋ Read ์ฑ๋ฅ์ด์์ ๋๋ค.
Cassandra๋ Tombstone์ ์ด์ฉํ์ฌ ๋ฐ์ดํฐ์ ์ญ์ ๋ฅผ ๊ด๋ฆฌํ๋ค๋ ํน์ง ์ธ์, ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ Sequencialํ๊ฒ ์ ์ฅํ๋ค๋ ํน์ง ์ญ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด๋ฅผ ์์ฝํ๋ฉด ๋น๋ก Memtable์ด๋ SSTable์ ์์ ์ ์ฅ๋ ๋ฐ์ดํฐ๊ฐ Delete์ํ๊ฐ ๋์๋๋ผ๋ Tombstone์ด marking๋์ด์๋ ๊ฒ์ผ ๋ฟ ์ค์ ๋ก๋ compaction์ด ์ผ์ด๋์ง๊ธฐ ์ ๊น์ง๋ ์ฌ์ ํ Disk์ ์กด์ฌํ๋ ์ํ๋ผ๋ ๊ฒ์ด์ฃ . ๋ฐ๋ผ์ SSTable์ ๋ฐ์ดํฐ๋ฅผ Sequencialํ๊ฒ ์ฝ์ด์ผํ๋ Cassandra์ ์ ์ฅ์์ ์ด๋ฏธ Tombstone์ marking ๋์ด์๋ ๋ฐ์ดํฐ๋ผ ํ ์ง๋ผ๋ ์ผ๋จ์ ์ฝ๊ณ ๋์ด๊ฐ๊ฒ ๋ฉ๋๋ค. ์ด๊ฒ์ ์๋นํ ์ค์ํ ๋ถ๋ถ์ธ๋ฐ, Cassandra๋ฅผ ์ ๋ Queue์ ๊ฐ์ ๋ฐฉ์์ผ๋ก๋ ์ฌ์ฉํด์ ์๋๋ค๋ ๊ทผ๊ฑฐ๊ฐ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
๋ง์ฝ ํ๋์ Row๋ฅผ Queue๋ก ๋ณด๊ณ , ํด๋น Row์ Column์ Message์ฒ๋ผ ์ฐจ๋ก๋๋ก Writeํ๋ ์ํฉ์ ๊ฐ์ ํด๋ด ์๋ค. ๊ทธ๋ฌ๋ฉด Message๋ฅผ ์๋นํ๊ณ ๋๋ฉด ์์ ๋ฐ์ดํฐ๋ค์ ์ฐจ๋ก๋๋ก Tombstone์ด ๊ธฐ๋ก๋๊ฒ ์ฃ . ๊ทธ๋ฐ๋ฐ Compaction์ ํตํด ๋ฐ์ดํฐ๊ฐ ์ฑ ์ฌ๋ผ์ง๊ธฐ๋ ์ ์ ์์ฒญ๋ ์์ Message๊ฐ ๋ค์ด์๋ค๊ฐ ์๋น๋์๋ค๋ฉด? ์๋น๋ Message Data๋ค์ ๋จ์ง Tombstone์ด ๊ธฐ๋ก๋์ด์์ ๋ฟ ์ฌ์ ํ ๋จ์์๋ ์ํ์ผ ๊ฒ๋๋ค. ์ด๋ ์๋ก์ด ๋ฉ์์ง๋ฅผ ๊ฐ์ ธ๊ฐ๋ คํ๋ค๋ฉด ์์ง ๋จ์์๋ Message Data๊ฐ ์๋ ๊ณณ๊น์ง ์์ Tombstone Data๋ค์ ๋ชจ๋ ๊ฑฐ์ณ์ผํ๋ ์ํฉ์ด ๋ฐ์ํฉ๋๋ค. ๋น์ฐํ ์๋๋ ๋๋ ค์ง๊ฒ ์ฃ .
์ด๋ ๋จ์ง Queue๋ก ์ฌ์ฉํ์ ๋๋ง ๊ตญํ๋๋ ๊ฒ์ ์๋๋๋ค. ๋๋์ ๋ฐ์ดํฐ๋ฅผ ๋น๋ฒํ๊ฒ ์ฐ๊ณ ์ง์ด๋ค๋ฉด, ๋น์ฐํ ํด๋น Row์ ๋ํ ์ฝ๊ธฐ ์ฑ๋ฅ์ ๋จ์ด์ง๊ฒ ์ฃ . ๋ฐ๋ผ์ Cassandra์ ์คํค๋ง๋ฅผ ์ค๊ณํ๊ธฐ ์ํด์๋ ํด๋น ๋ฐ์ดํฐ๋ฅผ ์ด๋ค ๋ฐฉ์์ผ๋ก ์ฌ์ฉํ ๊ฒ์ธ์ง ์ถฉ๋ถํ ๊ฒํ ํ ํ ์ด๋ฅผ ๋ฐ์ํ ์ ์๋๋ก ๋ ธ๋ ฅํด์ผํ ๊ฒ์ ๋๋ค.
(4) Memory Orverflow
์ง๊ธ ๋ง์๋๋ฆด ๋ด์ฉ์ ์์ฃผ ์ ์ ๋ด์ฉ์ด์ง๋ง ๋งค์ฐ ์ค์ํ ๋ถ๋ถ์ด๊ธฐ๋ ํฉ๋๋ค. Cassandra๋ ๋งค๋ฒ Hashing์ ํตํด ๊ณ์ฐ๋๋ Row Key์๋ ๋ฌ๋ฆฌ, ๋ชจ๋ Keyspace์ Table์ ๋ํ Metadata๋ฅผ JVM ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ ค๋๊ณ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. ์ด๊ฒ์ ๋ถ์ฐ๋์ง ์๊ณ , Ring์ ๊ตฌ์ฑํ๋ ๋ชจ๋ ๋ ธ๋๊ฐ ๋์ผํ๊ฒ ๊ฐ์ง๊ณ ์๋ ๋ฐ์ดํฐ์ ๋๋ค. ์ฆ, ๋๋ฌด ๋ง์ Keyspace์ Table์ ์์ฑํ ๊ฒฝ์ฐ Memory๊ฐ ๊ธ๊ฒฉํ๊ฒ ์์ง๋ ์ ์์ต๋๋ค. ์ด๋ ๊ฒฐ๊ตญ ํ์์ ๋ฐ๋ผ ๋งค๋ฒ Table ํน์ Keyspace๋ฅผ ์์ฑํ๋ ๋ฐฉ์์ผ๋ก Cassandra๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ Memory Orverflow๋ก ์ธํ์ฌ Cassandra ๋ ธ๋๋ค์ด ์ฃฝ์ด๋ฒ๋ฆฌ๋ ํ์์ด ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก ์ด์ ๊ฐ์ ์ฌ์ฉ๋ฐฉ์์ ๋ฐ๋์ ํผํด์ผํ๋ค๋ ์ ์ ๋ช ์ฌํด์ผํ ๊ฒ์ ๋๋ค.
5. ๋ง์น๋ฉฐ
์ด๋ ๊ฒ Cassandra ํบ์๋ณด๊ธฐ๋ฅผ 3ํธ์ผ๋ก ๋ง๋ฌด๋ฆฌ์ง์์ต๋๋ค. ์ฌ์ค ํบ์๋ณด๊ธฐ๋ผ๋ ์ ๋ชฉ์ด ๋ฌด์ํ ์ ๋๋ก ๋ฏธ์ฒ ๋ค๋ฃจ์ง ๋ชปํ ๋ด์ฉ๋ค์ด ๋ง์ง๋ง, ๋ชจ๋ ๋ด์ฉ์ ๋ค ๋ค๋ฃจ๊ธฐ์๋ ์๊ฐ๋ ์ญ๋๋ ๋ถ์กฑํ ํฐ๋ผ ๊ฐ์ธ์ ์ผ๋ก Cassandra๋ฅผ ์ด๋ค๋ฉด ์ด๊ฒ๋งํผ์ ์๊ณ ์ฐ๋ฉด ์ข๊ฒ ๋ค๋ ๋ด์ฉ๋ค์ ์์ฃผ๋ก ๊ธ์ ์์ฑํ์์ต๋๋ค. ๋ค์ ์ง๋ฃจํ ๋ด์ฉ์ด์์ง๋ง ์ด ๊ธ์ ํตํด ๋จ ํ๋ถ์ด๋ผ๋ ์กฐ๊ธ์ด๋๋ง ๋์์ด ๋์์ผ๋ฉด ํ๋ ๋ฐ๋์ ๋๋ค. ๊ฐ์ฌํฉ๋๋ค.