For the presentation, Cassandra's behavior and structure are compressed. A light example is attached to help readers understand easily. Therefore, it is not 100% consistent with Cassandra's behavior.
A notable part of this article is Cassandra's Batch tuning using by SSTable.
- cassandra overview.
- spark to cassandra using by sstable.
3. 세미나 목적으로 만들었습니다.
간단하게 카산드라를 소개할 목적으로
아키텍쳐의 일부분을 비약적으로 축약했으며
쉬운 이해를 위해 예시 또한 가볍게 작성한 것이니
overview 형식으로 봐주시면 감사하겠습니다.
중요한 내용은 9장의 Spark to Cassandra 입니다.
4. Cassandra
- 추천 등 집계셋 마트를 저장하는 용도로 사용.
- Nosql은 Join, group by 등의 기능이 약하기 때문에 단순 select 용도로 운영.
- 실시간, 시간배치, 일배치 등 다양한 데이터가 들어가고 있음.
- 각 추천셋 마트들은 5~30G를 차지할 정도로 size가 큼.
5. Cassandra
- 추천데이터를 카산드라에 넣어놓고 사용
- 각각의 테이블 사이즈는 5~30GB
- Read/Write 속도에 중점
- Spark와 연계 가능성을 고려
어플리케이션 API 서버
6. What is Cassandra?
- No master & slaves
- distributed like a ring
- Scalability
- high availability
7. CREATE TABLE ks_nm.tbl_nm (
col1 int,
col2 text,
col3 text,
col4 map<int,text>,
col5 timestamp,
PRIMARY KEY (col1, col2, col3)
) WITH CLUSTERING ORDER BY (col2 ASC, col3 DESC)
- PRIMARY KEY (파티션키, 클러스터링 키1, 클러스터링 키2…)
- CLUSTERING ORDER BY (클러스터링 키 정렬)
- Select 할때는 반드시 partition key가 where절에 들어가야됨!
Create table & Storage
8. - Cassandra.yaml에 num_tokens을 지정하면 각 노드에 rowkey를 hash한 값, 즉 token
이 분배.
- 현재 Hash는 Murmur3Partitioner를 사용 (추후 sstable write 할 때 알고있어야함)
- Insert 중인 데이터는 create table 시 정의한 partition key을 hash하여 token을 구하
고 저장될 node를 찾아서 저장.
0~50
50~100
100~150150~200
200~250
Token number = 250
RF = 1
9. - RF(복제계수)에 따라 복제본이 다른 노드로 복사됨. (권장 3)
- 복제전략은 몇 가지가 있고 예시는 SimpleStrategy(시계방향으로 단순 복제)
- 복제본은 HA뿐만 아니라 read/write consistency 를 위한 것.
0~50
50~100
100~150150~200
200~250
RF = 3
0~50
50~100100~150
150~200
200~250
100~150
150~200
200~250
0~5050~100
Consistency level option
all 모든 복제본 고려
One(권장) 복제본 1개만 고려
quorum N/2 + 1
12. Bloom filter란?
- 존재하지 않는다는 확신만으로도 성능상 이득
- 확률적 자료구조
- Hash 사용
- False positive : 존재하지 않는
원소를 존재한다고 판단할 가
능성. (나올 수 있음.)
- (결함이 아닌데, 결함이 있다고 판정)
- False negative : 존재하는데
존재하지않는다고 판단할 가
능성. (나올 가능성 없음)
- (결함이 있는데, 결함이 아니라고 판정)
13. False positive 예시
False positive니까 필요한 데이터가 disk에 없는데 있다고 거짓말한것.
(한번 더 탐색하는거니까 성능상으로는 안좋지만 정합성측면에서는 문제없다.)
아래는 실시간 memtable에 read/write가 일어나는 테이블로 시간이 증가할수록 수치가 높아짐.
14. Cassandra delete & update
- 카산드라는 데이터를 바로 지우지 않음.
- Tombstone으로 marking함.
- Marking 데이터는 추후 compaction이라는 sstable을 1개로 모아주는 작업
에서 정리가 됨.(sstable은 immutable이라서 많이 생길 수 밖에 없는 구조.)
- Update는 내부적으로 delete & write 임.
- 자주 update가 발생하면 아무래도 bloom filter 성능에 안좋을 수 있음.
15. Cassandra compaction
- 카산드라는 데이터를 memory(memtable), sstable(disk)에 저장됨
- Insert시 memtable에 write가 일어남.
- 일정 주기, size에 의해 memtable -> sstable로 데이터를 내린다. (flush)
- 이 과정이 지속되면 sstable은 지속적으로 쌓임. 성능 하락 원인이 됨.
- 따라서 주기적으로 sstable을 정리해주는(1개로 모아주는 작업)이 필요
- Compaction은 CPU를 쓰는 작업임.
- Compaction을 안해서 sstable이 수 천개가 생기면 카산드라 재부팅 할때 후회함
sstable sstable sstable sstable sstable
17. Cassandra compaction
- 우리는 매일 배치가 끊나면 sstable을 정리하기 위해 compaction을 함.
- Fragment가 발생해서 디스크정리, 인덱스 리빌드하는 느낌
SSTable이 5개에서 1개로 줄어들었다.
매일 compaction을 하고 있기 때문에 수천개씩 쌓이지는 않는다.
18. row cache & key cache
- Row Cache
로우 캐시는 partition data의 모든 컬럼을 저장함.
따라서 disk에 왔다갔다 할 필요가 없다. 찾으면 그걸로 리턴!
단, 모든 컬럼을 저장하기 때문에 사이즈가 크다.
- Key cache
data를 저장하는게 아니라 partition index를 저장함.
인덱스만 저장하기 때문에 size는 작다.
만약 partition key가 캐시 되어있다면 compression offset map를 뒤져서 저장블록의 위치를 찾고
그 디스크 블록을 찾아감.
Partition index -> compression offset map -> sstable
캐시들은 off-heap을 사용하기 때문에 jvm gc 관리대상이 아님.
따라서 적당한 크기로 제한하고 관리해줘야함.
19. 아무튼 장점!
- node reboot, add/remove가 자유롭다.
- 샤딩 고려 안해도됨. (hash partitionor가 알아서 해줌.)
- 지금은 데이터센터(클러스터, 군집)이 1개이지만 여러 클러스터 군집을 만들 수 있어서 더 안정적이다.
- Write가 빠르다. (RDB는 정합성을 맞추려고 느리지만 카산드라는 그렇지 않다!)
단점
- 페이징 처리 불가
- 관련 서적이 별로 없음.
21. 일별 약 100억건 이상의 rows, 약 100G 이상의 데이터를 새벽시간대에 insert함.
Insert 방식은 memtable(memory)에 넣음.
데이터가 커질수록 CPU가 80, 90, 100% 찼다는 경고 알림이 옴.
CPU 사용율이 올라갈 수록 카산드라 성능이 급격히 하락함.
초기 배치 구조 및 상황
22. 작업 전 Graph -1
- memtable에 쓸 때 coordinate에 초당 write 60k씩 씀.
- 그 결과 cpu가 급격히 튀는 현상이 있음.
23. 작업 전 Graph -2
- 네트워크 처리율을 올리자니 cpu가 튀어서 애매한 상황.
- Cassandra read/write 시 pending & timeout 수치가 급격히 올라감.
24. 임시 방편
- 메모리에 쓰더라도 천천히 쓰면 되지 않을까…
Spark에서 Cassandra memtable에 write를 할 때 throuput를 조절하여 고의로 성능을 낮춤.
new SparkConf()
.set("spark.cassandra.output.concurrent.writes","1")
.set("spark.cassandra.output.batch.size.rows","1")
.set("spark.cassandra.output.batch.size.bytes","512")
.set("spark.cassandra.output.throughput_mb_per_sec","0.7")
하지만 1개의 batch에서 n개의 write process가 병렬로 수행되고, 각각의 batch들이 병렬로 수행되
기 때문에 Throuput을 완전히 낮추지 않는 이상 근본적인 해결책이 되지 못함!
25. 작전 변경
메모리에 쓰지말고 disk에 바로 쓰자. 왜냐 우리는 SSD니까!
- memtable이 아닌 sstable file을 만들어서 load 하자!
작업 순서
1. SSTable을 생성할 directory 생성. 중복안되게 uuid 활용.
2. Directory에 SSTable 생성.
3. 카산드라에 SSTable load.
4. Directory 삭제.
5. 이 모든 작업을 N개로 나눠서 병렬로 수행
28. 예시 코드 – 짚고넘어가기
카산드라는 분산형 링 구조의 DB라서 data skew를 주의.
파티셔너 종류
- Murmur3Partitioner, RandomPartitioner 등
파티셔너 종류는 Cassandra.yaml에 세팅.
- 왜 노드들 중에 한 녀석에게 보내지 않고 보낼때마다 랜덤으로 하나를 골라서 보내나?
Spark cluster, Cassandra cluster 간 물리적 네트워크 인프라 구성에 따라 해도되고 안해도 되겠지만
예를 들어 5대 중 2대는 a스위치에 물려있고, 3대는 b스위체 물려있는 경우라면
Shuffle을 통해 한쪽 카산드라에만 insert traffic이 몰리는 상황을 방지하기 위함.
Repartition은 샤딩이라고 생각하면됨.
31. 작업 후 Graph -1
- 수정된 배치들은 writes/sec 에 아무것도 안잡힘. 잡히는 것은 memtable에 쓰는 소규모 배치들뿐.
- CPU 사용율이 훨씬 줄어듦. 안정적.
32. 작업 후 Graph -2
- Cpu가 안튀기 때문에 네트워크 대역폭을 더 올릴 수 있음.
- Cassandra read/write 시 pending & timeout 이 거의 없음.(영향줄만한 곳은 only network)
33. 추가 튜닝
카산드라 네트워크 인프라를 고려해서 네트워크 트래픽을 35%로 조절함.
설명
1. 1G당 파티션을 1개로 세팅. (30G면 repartition(30)이 되고 30개를 병렬로 돌릴것.)
2. 각각의 파티션은 mapreduce.output.bulkoutputformat.streamthrottlembits에 의해 출력을 조절함.
3. 따라서 n개의 파티션 * 각각의 streamthrottlembits이 해당 카산드라 노드의 max network traffic 35%로 계산하는식으로
조절.
4. 즉 예시 코드는 max 350Mbps만 사용하도록 하는 코드.
34. Memtable -> SSTable 전환 결과
- 안정적인 CPU
(기존 100%가까이 찼던 사용율이 현재 20-30%대로 낮춤)
- 안정적인 response
(배치 시간대에 timeout/pending이 없음.)
- 네트워크 트래픽 관리만 잘하면 ok
- 속도 향상
- 운영 상황에서도 안전하게 대량의 insert 배치 수행 가능