레이블이 Cassandra인 게시물을 표시합니다. 모든 게시물 표시
레이블이 Cassandra인 게시물을 표시합니다. 모든 게시물 표시

RDB vs NoSQL 비교 분석

참고 자료
XML 데이터 형식 메서드 http://technet.microsoft.com/ko-kr/library/ms190798.aspx
MySQL http://www.mysql.com/products/community/
MongoDB http://www.mongodb.org/
Cassandra http://cassandra.apache.org/
CAP 이론 http://blog.nahurst.com/visual-guide-to-nosql-systems
Consistency(일관성) : 모든 노드들은 동시에 같은 데이터를 일관되게 유지해야 함
Availability(유효성) : 모든 노드들은 항상 읽기와 쓰기를 할수 있어야 함
Partition Tolerance(파티션 허용) : 시스템은 물리적인 네트워크 파티션을 넘어서도 잘 동작해야 함


MS-SQL 2005
- 상용 라이센스
- Windows
- SQL Server Management Studio(SSMS) 툴 사용
- ODBC API 지원
- 대중적인 RDB로 Table Row(Record) 기반
- MS-SQL2005 부터 XML 지원
- 컬럼내용에 xml 이 저장
- xml 값을 select, update, delete, modify 가능
- xml 의 element 별로 index 처리 가능
- 장점
 : CAP 이론 중 C와A 충족
 : XML 로 데이터를 표현하면 친숙한 RDB 내에서 현재 대용량처리를 위해 주목받고 NoSQL like 기능을 제공
 : Oracle XML 에 비해 API 가 간단하며 직관적이여서 편리하고, 사용 비용이 좀 더 저렴
- 단점
CAP 이론 중 P 불충족
 : 게임 데이터가 급격하게 늘어날 경우 인해 확장이 어려움
 : MySQL XML 은 아직 성능이 현저하게 떨어지고, XML 기능의 범위 또한 제한적(예로, MySQL 은 ExtractValue() / UpdateXML() 하는데 extractvalue 사용시 XML 의 xpath 를 사용하지 못함)
 : 상용으로 비용 발생
 : 리눅스 지원 안함

MySQL 5.1 (Community Edition)
- GPL 상용(Enterprise), 무료(Community)
- Windows / Linux / Solaris / OS X
- SQLyog 툴 지원
- ODBC / MySQL Client API(C/C++/Java...etc)
- 대중적인 RDB로 Table Row(Record) 기반
- XML set / get api 지원
- 장점
 : CAP 이론 중 C와A 충족
 : 무료버전 사용 가능
 : 대중적인 RDB 환경 제공
 : MS-SQL 에 비해 리눅스환경에서 사용가능
- 단점
 : CAP 이론 중 P 불충족(데이터가 급격하게 늘어날 경우 확정이 어려움)
 : Oracle 이나 MS-SQL 에 비해 XML 에 대한 지원 기능이 떨어짐

MongoDB 2.0.2
- MongoDB : AGPL , 커넥터 드라이버는 Apache 2.0 라이센스
- Windows / Linux / Solaris / OS X
- mongo CLI(Command Line Interface) 툴 가능
- mongodb API(C/C++/Java...etc)
- RDBMS 의 대부분 index 지원
- C++ 로 개발됨
- MapReduce 방식의 분산 병렬 처리
- memory mapped db
 : db 의 모든 내용을 OS virtual memory 로 구성하여 paging 여부에 따라 memory <-> disk
 : 32bit mongodb 는 2^32 = 4,294,967,296(4GigaByte) 실제 2.5GB 정도의 데이터 사용가능
 : 64bit mongodb 는 2^64 = 18,446,744,073,709,551,616(18ExaByte) 데이터 사용가능
- disk fragment 방지를 위해 64MB, 128MB, 256MB, .. 1GB, 2GB 등으로 디스크 공간 할당
- 삭제된 데이터 공간은 자동으로 반환하지 않음
 : 예를 들어 100GB 중 50GB 데이터를 삭제해도 100GB 공간을 차직 하고 있음
 : db.repairDatabse() 를 수행하여 정리해야함
- 문서(Document)
 : 문서는 여러개의 필드,필드값 쌍을 가진 단위로 저장,삭제,수정 할 수 있음, JSON 을 바이너리로 인코딩한 BSON 포맷으로 데이터 크기는 4MiB 로 제한
- 컬렉션(Collection)
 : RDB 의 테이블과 유사 개념으로, 네임스페이스로만 의미가 있음
- 데이터베이스(Database)
 : 컬레션을 관리하는 단위
- 장점
 : CAP 이론 중 C와P 충족(master/slave 로 분산 복제로 싱크되어 slave 에서 master 데이터를 똑같이 읽수 있음, Auto-sharding 기능으로 으로 분할 저장 가능)
 : 다양한 클라이언트 라이브러리(C,C++,C#,Java,Javascript,PHP,Perl,Ruby,Python...)를 제공
 : JSON(내부적으로 document 로 불리며, BSON으로 저장) 프토토콜을 사용
 :XML 비해 통신이나 기타 데이터 처리에 있어 빠름
 : XML 은 DOM tree 나 <> 태그등의 오버헤드로 취급될 수 있음
 : 테이블하나에 아주 많은 문서스타일의 데이터를 사용하는 경우에 좋음(예, Log 기록)
- 단점
 : CAP 이론 중 A 불충족 (master 에만 write 할 수 있어 master 에 부하 증가로 write 가 지연될 수 있고 master 장애 발생시 전체 db 를 사용할 수 없음)
 : 메모리와 매핑되는 데이터파일을 사용한다. (즉 main memory 크기를 넘어서는 데이터는 virtual memory (OS가 관리)를 증가시킨다.)
 : 데이터가 머신의 메인 메모리 보다 클 수록 가상메모리를 증가시켜 성능 저하가 발생한다.
큰 데이터를 Insert, Delete 시 성능 저하

Cassandra 1.0.7
- Apache 2.0 라이센스
- Windows / Linux / Solaris / OS X /  기타 JVM 환경
- cassandra-CLI, nodetool 등 제공
- cassandra thrift API(C/C++/Java...etc)
- 구글 bigtable 과 아마존 Dynamo 특징을 토대로 Java 로 개발됨
- Read replica count, write replica count를 설정하여 Availability(유효성)과 Consistency(일관성) 사이의 균형을 사용자가 선택해 사용
 : Write 과정
  1. commitlog -> memtable(memory) -> 일정 threadhold 를 넘어서면 SSTable 로 flush -> SSTable(Disk, 구글의 BigTable 컨셉)
  2. Compaction : SSTable 데이터(key, colunms)를 머지하여 새로운 정렬된 데이터 및 새 인덱스를 생성하는 작업
- Rowkey(1차인덱스), Column(2차인덱스) 을 기본적으로 인덱싱
- 클러스터(Cluster)
 : 여러대의 서버로 구성된 카산드라 클러스터 자체
- 키스페이스(KeySpace)
 : RDB 의 스키마에 해당하는 개념으로 하나의 카산드라 클러스터는 여러개의 키 스페이스를 가질 수 있음
- 칼럼패밀리(ColumnFamily)
 : RDB 의 테이블에 대응하는 개념으로 키 스페이스는 여러개의 칼럼 패밀리를 가질 수 있음
칼럼(Column) : 카산드라에서 저장되는 데이터의 최소 단위이며, 이름, 값, 타임스탬프를 가짐(이름이 키역할을 함)
- 슈퍼칼럼(SuperColumn)
 : 여러 개의 칼럼을 묶어 관리하는 단위이며, 칼럼 패밀리 정의 시 ColumnType=Super 로 명시해야함
- 장점
 : 머지로 인해 여유 공간을 만들어냄
 : disk io 탐색을 줄일 수 있음
 : CAP 이론 중 A와P 충족
 : 현재까지 기존의 RDB 를 대체하는데 가장 적합하여 사용하는 곳이 많음
 : RDB 에 비해 유동적인 데이터 크기를 가져 효율적(Compaction 기능)
 : SSTable(Sorted String Table)에 데이터를 추가후 SSTable 단위로 저장하기 때문에 Write 빠름
 : Column 을 모아 저장하는 Column oriented DB 라서 연관된 데이터를 읽기에 적합
 : 장비추가의 과정이 단순 (새로운 장비를 추가하고 설정을 바꾼 후 cassandra 재시작)
- 단점
 : SuperColumn 안의 컬럼은 인덱스 지원 안됨
 : CAP 이론 중 C 불충족 (성능을 높이면 Consistency 가 낮아짐)
 : thrift 와 같은 rpc frame work 를 사용해서 클라이언트 개발
 : 조금 생소한 컬럼베이스
 : Java 로 만들어져 JVM 이 설치되어 있어야함

Cassandra thrift 사용하기

/////////////////////////////////////////////////////////////
// ysoftman
// Cassandra Client Test (Java + thrift)
// thrift 는 Cassandra 배포(Cassandra/lib/*.jar) 에 포함되어 있음
// 컴파일 및 실행
// export CLASSPATH=/Users/ysoftman/workspace/test_code/CassandraTest/apache-cassandra-1.2.5/lib/*:.
// javac CassandraTest.java
// java CassandraTest
/////////////////////////////////////////////////////////////
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Random;
import java.lang.Math;


import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
import org.apache.cassandra.thrift.ColumnParent;
import org.apache.cassandra.thrift.ColumnPath;
import org.apache.cassandra.thrift.SuperColumn;
import org.apache.cassandra.thrift.Mutation;
import org.apache.cassandra.thrift.ConsistencyLevel;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.thrift.NotFoundException;
import org.apache.cassandra.thrift.SlicePredicate;
import org.apache.cassandra.thrift.SliceRange;
import org.apache.cassandra.thrift.KeyRange;
import org.apache.cassandra.thrift.KeySlice;
import org.apache.cassandra.thrift.TimedOutException;
import org.apache.cassandra.thrift.UnavailableException;
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TFramedTransport;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;

/*
cassandra 0.7 이상 API 를 사용함
# 컬럼패밀리(cf) 생성;
create column family game2 with comparator=UTF8Type and subcomparator=UTF8Type and column_type=Super and key_validation_class=UTF8Type and default_validation_class=UTF8Type;
*/
public class CassandraTest
{
public static ByteBuffer toByteBuffer(String value) throws UnsupportedEncodingException
{
return ByteBuffer.wrap(value.getBytes("UTF-8"));
}

public static String toString(ByteBuffer buffer) throws UnsupportedEncodingException
{
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
return new String(bytes, "UTF-8");
}
public static void main(String[] args) throws TException, InvalidRequestException, UnavailableException, UnsupportedEncodingException, NotFoundException, TimedOutException
{
InsertData("127.0.0.1", 9160, "testdb", "col1");
// Search1("127.0.0.1", 9160, "testdb", "col1");
// Search2("127.0.0.1", 9160, "testdb", "col1");
// Search3("127.0.0.1", 9160, "testdb", "col1");
}

// 대량의 Data Insert
public static void InsertData(String ip, int port, String keyspace, String columnfamily) throws TException, InvalidRequestException, UnavailableException, UnsupportedEncodingException, NotFoundException, TimedOutException
{
long timebefore = 0;
long timeafter = 0;
long timeinsert = 0;

// cassandra db 접속하기
TSocket socket = new TSocket(ip, port);
socket.setTimeout(10000);
TTransport tr = new TFramedTransport(socket);
TProtocol proto = new TBinaryProtocol(tr);
Cassandra.Client client = new Cassandra.Client(proto);
tr.open();

// keyspace 사용
client.set_keyspace(keyspace);

// 반복적으로 데이터 넣기
String key_UserNo = "1";
//ColumnParent parent = new ColumnParent();
//parent.setColumn_family(columnfamily);
for (int i=1; i<=100; i++)
{
// 키값 자동적으로 증가
key_UserNo = Integer.toString(i, 10);

SuperColumn supercol = new SuperColumn();
supercol.setName("Map".getBytes("UTF-8"));
// MapID 와 Score 컬럼을 반복적으로 저장
for (int j=1; j<=1000; j++)
{
Column colMapID = new Column();
colMapID.setName(("MapID_"+j).getBytes("UTF-8"));
colMapID.setValue(toByteBuffer(Long.toString(j, 10)));
colMapID.setTimestamp(System.currentTimeMillis());
//client.insert(toByteBuffer(key_UserNo), parent, colMapID, ConsistencyLevel.ONE);

// 랜덤 넘버 생성
Random r = new Random(System.currentTimeMillis());
long num = Math.abs((r.nextLong()%1000));

Column colScore = new Column();
colScore.setName(("Score_"+j).getBytes("UTF-8"));
colScore.setValue(toByteBuffer(Long.toString(num, 10)));
colScore.setTimestamp(System.currentTimeMillis());
//client.insert(toByteBuffer(key_UserNo), parent, colScore, ConsistencyLevel.ONE);

supercol.addToColumns(colMapID);
supercol.addToColumns(colScore);
}
// supercolumn -> mutation 에 추가
Mutation mutation = new Mutation();
ColumnOrSuperColumn columnOrsupercolumn = new ColumnOrSuperColumn();
columnOrsupercolumn.setSuper_column(supercol);
mutation.setColumn_or_supercolumn(columnOrsupercolumn);

// mutation -> list 에 추가
List<Mutation> mutationlist = new ArrayList<Mutation>();
mutationlist.add(mutation);

// list -> map 에 추가
Map<String, List<Mutation>> mutationlistmap = new HashMap<String, List<Mutation>>();
// column family 와 mutation list 추가
mutationlistmap.put(columnfamily, mutationlist);

// map -> map 에 추가
Map<ByteBuffer, Map<String, List<Mutation>>> data = new HashMap<ByteBuffer, Map<String, List<Mutation>>>();
// rowkey 와 mutationlistmap 추가
data.put(toByteBuffer(key_UserNo), mutationlistmap);

timebefore = System.currentTimeMillis();
client.batch_mutate(data, ConsistencyLevel.ONE);
timeafter = System.currentTimeMillis();
timeinsert = (timeafter-timebefore)/1000;

// insert 시간이 오랜 걸린 경우
if (timeinsert > 5)
{
System.out.println("Data Count:"+i+"   insert time: "+timeinsert+"sec");
}

// 진행상황 파악을 위해
if (i%10 == 0)
{
System.out.println("Data Count:"+i);
}
}

tr.close();
}

// rowkey 와 컬럼을 주고 값 찾기
public static void Search1(String ip, int port, String keyspace, String columnfamily) throws TException, InvalidRequestException, UnavailableException, UnsupportedEncodingException, NotFoundException, TimedOutException
{
// cassandra db 접속하기
TSocket socket = new TSocket(ip, port);
socket.setTimeout(10000);
TTransport tr = new TFramedTransport(socket);
TProtocol proto = new TBinaryProtocol(tr);
Cassandra.Client client = new Cassandra.Client(proto);
tr.open();

// keyspace 사용
client.set_keyspace(keyspace);

// rowkey 를 알경우, 해당 로우의 컬럼의 패스 설정하여 조회
ColumnPath path = new ColumnPath();
path.setColumn_family(columnfamily);
path.setSuper_column(toByteBuffer("Map"));
path.setColumn(toByteBuffer("MapID_1"));

System.out.println(path.getColumn_family());
ColumnOrSuperColumn result1 = client.get(toByteBuffer("1"), path, ConsistencyLevel.ONE);
System.out.println(toString(result1.getColumn().value));

tr.close();
}

// rowkey 를 주고 특정범위의 컬럼에 대한 값 찾기
public static void Search2(String ip, int port, String keyspace, String columnfamily) throws TException, InvalidRequestException, UnavailableException, UnsupportedEncodingException, NotFoundException, TimedOutException
{
// cassandra db 접속하기
TSocket socket = new TSocket(ip, port);
socket.setTimeout(10000);
TTransport tr = new TFramedTransport(socket);
TProtocol proto = new TBinaryProtocol(tr);
Cassandra.Client client = new Cassandra.Client(proto);
tr.open();

// keyspace 사용
client.set_keyspace(keyspace);

// rowkey 를 알경우, 해당 로우의 전체 데이터 조회
ColumnParent parent = new ColumnParent();
parent.setColumn_family(columnfamily);
parent.setSuper_column(toByteBuffer("Map"));

SlicePredicate predicate = new SlicePredicate();
// 검색할 컬럼 범위 지정
// 모든 컬럼
//SliceRange sliceRange = new SliceRange(toByteBuffer(""), toByteBuffer(""), false, 10000);
// 특정 범위의 컬럼
SliceRange sliceRange = new SliceRange(toByteBuffer("Score_1"), toByteBuffer("Score_1000"), false, 10000);
predicate.setSlice_range(sliceRange);

List<ColumnOrSuperColumn> result2 = client.get_slice(toByteBuffer("1"), parent, predicate, ConsistencyLevel.ONE);
int i = 0;
for (i=0; i<result2.size(); i++)
{
Column column = result2.get(i).column;
System.out.println(toString(column.name) + " -> " + toString(column.value));
}
System.out.println("Count Column: "+i);

tr.close();
}

// 전체 row 에서 특정 컬럼의 값을 찾기
// 찾은 값들 중에서 조건이상 컬럼 카운트하기
public static void Search3(String ip, int port, String keyspace, String columnfamily) throws TException, InvalidRequestException, UnavailableException, UnsupportedEncodingException, NotFoundException, TimedOutException
{
// cassandra db 접속하기
TSocket socket = new TSocket(ip, port);
// 데이터가 많으면 시간이 오래 걸려 timeout 을 넉넉하게 준다.
socket.setTimeout(1000000);
TTransport tr = new TFramedTransport(socket);
TProtocol proto = new TBinaryProtocol(tr);
Cassandra.Client client = new Cassandra.Client(proto);
tr.open();

// keyspace 사용
client.set_keyspace(keyspace);

// 전체 로우를 대상으로 데이터 조회
ColumnParent parent = new ColumnParent();
parent.setColumn_family(columnfamily);
parent.setSuper_column(toByteBuffer("Map"));

SlicePredicate predicate = new SlicePredicate();
// 검색할 컬럼 범위 지정
// 모든 컬럼
//SliceRange sliceRange = new SliceRange(toByteBuffer(""), toByteBuffer(""), false, 10000);
// 특정 범위의 컬럼
SliceRange sliceRange = new SliceRange(toByteBuffer("Score_1000"), toByteBuffer("Score_1000"), false, 10000);
predicate.setSlice_range(sliceRange);

KeyRange kr = new KeyRange();
kr.setCount(100000);
// 모든 키에 대해서
//kr.start_key = toByteBuffer("");
//kr.end_key = toByteBuffer("");
kr.setStart_key(toByteBuffer(""));
kr.setEnd_key(toByteBuffer(""));

long timebefore = 0;
long timeafter = 0;
long timefetch = 0;
long timesearch = 0;
timebefore = System.currentTimeMillis();
List<KeySlice> rows = client.get_range_slices(parent, predicate, kr, ConsistencyLevel.ONE);
timeafter = System.currentTimeMillis();
timefetch = (timeafter-timebefore)/1000;
int i = 0;
int cntCol = 0;
timebefore = System.currentTimeMillis();
for (i=0; i<rows.size(); i++)
{
KeySlice ks = rows.get(i);
// 각 로우의 컬럼 출력
List<ColumnOrSuperColumn> temp = ks.getColumns();
//System.out.print("rowkey["+i+"]"  );
int j;
for (j=0; j<temp.size(); j++)
{
Column column = temp.get(j).column;
String colname = toString(column.name);
System.out.println("Column name : " + colname);
long colvalue = Long.parseLong(toString(column.value));
//System.out.print(colname + " -> " + colvalue + "    ");

// 컬럼 값이 500 인상이면 카운트
if (colvalue >= 500)
{
cntCol++;
//System.out.print("checked    ");
}
}
//System.out.print("\n");
}

timeafter = System.currentTimeMillis();
timesearch = (timeafter-timebefore)/1000;

System.out.println("all rows: "+rows.size() +", colvalue>=500 : "+cntCol);
System.out.println("Elapsed Time -> fetch:"+ timefetch + "sec + search: "+timesearch+"sec");

tr.close();
}
}

Cassandra 설치 및 쿼리

# 구글의 Bigtable과 아마존 Dynamo 의 특징을 합쳐서 만듦
# 장비추가의 과정이 단순(새로운 장비를 추가하고 설정을 바꾼 후 cassandra 재시작)
# 어떤 노드에 장애가 발생하더라도 전체 시스템이 멈추지 않음
# Availability(유효성)과 Consistency(일관성) 사이의 균형을 사용자가 선택해 사용(Read replica count, write replica count를 설정하여)
# Column 을 모아 저장하는 Column oriented DB 라사 연관된 데이터를 읽기에 적합
# SSTable(Sorted String Table)에 데이터를 추가후 SSTable 통째로 저장하기 때문에 데이터를 넣을 위치를 찾을 필요가 없어 Write 가 빠름
# 사용방법 : CLI(Command Line Interface) 쉘을 이용하거나 카산드라 쓰리프트(interface/thrift)를 이용한 프로그램 개발
# 데이터모델
# 클러스터(Cluster) : 여러대의 서버로 구성된 카산드라 클러스터 자체
# 키스페이스(KeySpace) : RDB 의 스키마에 해당하는 개념으로 하나의 카산드라 클러스터는 여러개의 키 스페이스를 가질 수 있음
# 칼럼패밀리(ColumnFamily) : RDB 의 테이블에 대응하는 개념으로 키 스페이스는 여러개의 칼럼 패밀리를 가질 수 있음
# 칼럼(Column) : 카산드라에서 저장되는 데이터의 최소 단위이며, 이름, 값, 타임스탬프를 가짐(이름이 키역할을 함)
# 슈퍼칼럼(SuperColumn) : 여러 개의 칼럼을 묶어 관리하는 단위이며, 칼럼 패밀리 정의 시 ColumnType=Super 로 명시해야함

# 다운로드
wget http://mirror.apache-kr.org/cassandra/1.2.5/apache-cassandra-1.2.5-bin.tar.gz
tar zxvf apache-cassandra-1.2.5-bin.tar.gz
cd apache-cassandra-1.2.5

# 설정 수정
vi conf/cassandra.yaml
data_file_directories:
    - /home/ysoftman/apache-cassandra-1.2.5/ysoftman_db/data
commitlog_directory: /home/ysoftman/apache-cassandra-1.2.5/ysoftman_db/commitlog
saved_caches_directory: /home/ysoftman/apache-cassandra-1.2.5/ysoftman_db/saved_caches

vi conf/log4j-server.properties
log4j.appender.R.File=/home/ysoftman/apache-cassandra-1.2.5/ysoftman_db/log/system.log

# Cassandra 구성 하기
# JDK 설치(http://www.oracle.com/technetwork/java/javase/downloads/index.html)

# 다음 처럼 set
set CASSANDRA_HOME=/home/ysoftman/apache-cassandra-1.2.5

# Cassandra node tool
# 디스크 강제 쓰기
bin/nodetool -h localhost flush

# 요청 작업 상태 보기
bin/nodetool -h localhost tpstats

# thrift 상태 보기
bin/nodetool -h localhost statusthrift

# cfg 상태 보기(db 크기등..)
bin/nodetool -h localhost cfstats

#Cassandra 실행
bin/cassandra -f > null &

# Cassandra 쿼리하기
# Cassandra-cli (Command Line Interface) 실행하고 접속하기(포트 30000 사용)
bin/cassandra-cli
connect localhost/30000;

# 또는 한번에 시작하면서 접속하기
bin/cassandra-cli --host localhost --port 30000

# 클러스터 목록 보기
show cluster name;

# 키스페이스 목록 보기
show keyspaces;

# 키스페이스 생성
create keyspace testdb;

# 키스페이스 제거
drop keyspace testdb;

# 키스페이스 선택
use testdb;

# 컬럼패밀리(cf) 생성
create column family col1 with comparator=UTF8Type and subcomparator=UTF8Type and column_type=Super and key_validation_class=UTF8Type and default_validation_class=UTF8Type;

# cf 의 rows_cache 크기 변경
update column family col1 with rows_cached=5000;

# cf 의 keys_cache 크기 변경
update column family col1 with keys_cached=2000;

# cf 의 secondary index 설정
# rowkey 가 첫번째 인덱스
# super column 에 인덱스 지원 안됨
update column family col1 with column_metadata= [{column_name:temp, validation_class:UTF8Type, index_type:KEYS}];

# cf=col1에 rowkey=1234, super컬럼=Map, MapID_100컬럼=1000 저장
set col1[1234][Map][MapID_100]='1000';

# cf=col1에 rowkey=1234, super컬럼=Map, Score_100컬럽=100 저장
set col1[1234][Map][Socre_100]=100;

# cf=col1에 rowkey=1234, 모든 컬럼 조회
get col1[1234];

# cf=col1에 rowkey=1234, 컬럼 10개 까지만 조회
get col1[1234] limit 10;

# cf=col1에 rowkey=1234, Map의 Score_100 컬럼 삭제
del col1[1234][Map][Score_100];

# cf=col1에 rowkey=1234, 데이터의 모든 컬럼 삭제
del col1[1234];

# cf col1 모든 데이터 1000 개까지 조회
list col1 limit 1000

# cf=col1에 rowkey=1234, 컬럼 개수
count col1[1234];

Linux Cassandra timestamp 단위

Cassandra 는 timestamp 를 기준으로 요청을 처리하기 때문에 시간 단위가 맞지 않으면 request 를 무시할수 있다.
Cassandra-cli 에서는 set, get,... 등의 작업을 할때 내부적으로 microsecond 단위의 timestamp 를 사용한다.
때문에 thrift api 를 사용할때도 millisecond 를 microsecond 단위로 맞춰줘야 한다.

// Cassandra thrift  Java 일 경우
Column col = new Column();
col.setName(("aaa").getBytes("UTF-8"));
col.setValue(toByteBuffer(Long.toString(100, 10)));

// cassandra-cli 는 microsecond 단위를 사용함으로 맞춰줘야 한다.
col.setTimestamp(System.currentTimeMillis()*1000);