5. REDIS
• 심플한 인 메모리 캐시 서버
• 자료구조와 리플리케이션, 디스크 백업을 제공한다.
– 자료구조(K/V, set, sorted set, hash)
– Replication(Master/Slave, Chained 형태 가능)
– 디스크 백업(RDB/AOF)
6. 싱글 스레드 #1
• Redis는 싱글 스레드.
– 긴 작업을 처리하는 동안에는 다른 작업을 처리할 수 없다.
– 긴 작업이란?
• O(N) 의 명령의 수행 대상이 아주 많을 경우.
– Keys, flushall 등
• Lua Script 도 하나의 커맨드로 수행된다.
• MULTI/EXEC의 경우는 모아두었다가 EXEC가 들어오면 한번에 모두 수행한다.
7. 싱글 스레드 #2
• 하나의 서버에 CPU Core 가 여러 개라면, 여러 개의 Instance를
실행하는 것이 성능상 유리하고 더 안정적.
– 메모리는 낭비, 관리는 조금 더 어려움.
• CPU 4 core, 32G Memory
Mem: 26G
Mem: 8G
Mem: 8G
Mem: 8G
9. Redis Event Loop #2
• 클라이언트가 보낸 하나의 패킷이 완성이 되면 바로 해당 커맨드를 수
행한다.
– Redis는 싱글 스레드.
• 이 동안에는 다른 코드가 동작하지 않는다.
• 긴 작업의 경우에는 Event Loop 내에서 처리되므로 다른 명령을 받
지 못한다.
• 한 루프당 여러 개의 명령이 실행 될 수 있음.
– Reactor 패턴과 유사
13. RDB #1
• Redis의 메모리 내용을 디스크로 덤프하는 기능
• 어떤 때 RDB를 생성할까?
– SAVE 조건이 만족할 때
– 슬레이브가 마스터에 SYNC 명령을 보냈을 때(In Replication)
– 사용자가 명시적으로 SAVE or BGSAVE 명령을 내렸을 때
• 주의하자!!!
– Redis 장애의 대부분이 디폴트 옵션을 이용해서임.
– SAVE 시간(초) 변화하는 키 개수
• SAVE 900 1
• SAVE 60 10000
14. RDB #2
• Redis의 RDB는 Fork 를 이용한다.
– Write가 Heavy 한 서비스는 메모리를 최대 두배 까지도…
– 보통의 서비스는 READ:WRITE = 80:20 수준
– 그러나 Batch Job 서버는?
• 모든 키의 내용이 바뀌어야 한다면?
• 특정 시간내에 전부 바뀔 수 있다.
• Os의 COW 때문(copy on write)
15. Copy on Write
• 부모 프로세스의 메모리 Page 에 Write 가 발생할 때 마다, 해당
메모리 Page를 복사하게 된다.
• 읽기의 경우에는 메모리를 추가로 복사할 필요가 없다.
16. Copy on Write #1
Process - Parent
Physical Memory
Page A
Page B
Page C
17. Copy on Write #2 – Fork(), 메모리 수정 전
Process - Parent
Physical Memory
Page A
Page B
Page C
Process - Child
18. Copy on Write #2 – Fork(), 메모리 수정 후
Process - Parent
Physical Memory
Page A
Page B
Page C
Copy of Page C
Process - Child
19. Copy on Write 결론
• 최악의 경우에는 메모리를 두 배 까지 사용할 수 있다.
– 모든 Page 에 write가 발생했을 경우
• 메모리가 부족해서 스왑 영역을 사용하면 엄청나게 느려지게 된다.
20. AOF #1
• Append Only File
• Redis 프로토콜을 그대로 저장.
• 한 번의 이벤트 루프가 지날 때마다 발생한 Write 관련 명령들을
디스크에 저장함
– 이로 인해, Disk에 한번에 쓰는 데이터 양이 적어서 RDB 보다 부담이 적음
• 최초 부터 모든 로그를 가지고 있으므로 update가 빈번하면 실제 데이
터 보다 파일 크기가 많이 커질 수 있다
– 설정에 의해서 rewrite가 발생함
• 이것도 fork로 이루어지므로 주의가 필요.
21. AOF #2
• DB의 바이너리 로그나 WAL와 비슷하다고 할 수 있지만, 쓰는 타이밍
등에서 다름.
WAL, Binary Log 실제 데이터 반영 전에 기록.
장애시에 해당 값을 실행해서 복구한다.
AOF 한 루프가 끝난 후에, 반영한 명령어들만 저장한다.
23. RDB/AOF 주의 사항 #1
• RDB/AOF 가 필요하면
– Master/Slave 로 정하고 Slave 에서 메모리를 덤프하거나.
– 실제 메모리가 2배가 되더라도 실 메모리 이하만 사용하도록
• 프로세스당 메모리 사용량을 정해놓는다.
• 16GB 장비에 CPU가 4개라면 3개의 인스턴스를 실행하고 각각 3G 정도만 사용.
• RDB/AOF 등으로 인해서 사용 메모리 영역의 일부가 swap 되게 되
면, 해당 메모리에 접근할 때 마다, 전체 퍼포먼스가 저하된다.
24. RDB/AOF 주의 사항 #2
• RDB를 master에서 한다면 꼭
– config set stop-writes-on-bgsave-error no
– 이 옵션이 YES면 RDB 저장에 실패하면, 모든 write에 대해서 금지시키고 에러를 리턴
함.
MISCONF Redis is configured to save RDB snapshots, but is
currently not able to persist on disk. Commands that may
modify the data set are disabled. Please check Redis logs
for details about the error.”
26. AWS on PV 에서 주의할 점
• Amazon AWS에서 PV 머신을 선택했을 때, Xen 의 PV 에서의
fork 성능에 이슈가 있음.
– 메모리 사이즈에 따라서 몇 초 까지 걸릴 수 있음.
• HVM을 사용하면 아무런 문제 없음.
27. PV vs HVM (m3.xlarge) - ms
메모리 PV HVM
0 0.5 0.1
608MB 143 5
1.54G 352 13
2.31G 517 20
4.62G 1208
6.16G 1600
28. PV vs HVM
• Xen 에서 PV 일 경우 fork 시에 page tables을 복사하는데 부하
가 걸림…
– 왜 걸리는지는 묻지 말아주세요. PV에서 그냥 느립니다.
• Page tables의 사이즈에 영향을 받음.
• 실제 머신의 물리 메모리의 크기 보다는 레디스가 사용하는 Page 에
영향을 받음
31. 느린 Disk IO
• EBS의 경우, Ephemeral Disk 보다는 속도가 느림.
– 그래서 Disk에 쓰기 작업(RDB/AOF) 등에서 불리함.
32. 추천 Redis 버전
• 2.8.13 이후를 사용하는게 좋음.
– Jemalloc 3.6.0을 사용한 버전
– 메모리 파편화 등에서 더 좋음
– Jemalloc 4.0.0 에서는 메모리 사용량이 더 좋아졌다지만 아직은 도입전
• 2015/08/17 일 Release
• AWS ElasticCache의 Redis 최신 버전은
– 2.8.19 선택 가능
33. 메모리 파편화 이슈 #1
• Redis의 메모리 관리는 오직 메모리 할당자에 의해서 이루어 짐
– Memcached의 경우 메모리 관리에 Slab 할당자 등을 이용하고, chunk를 이
용해서 chunk 단위의 메모리 할당만 일어남.
– Redis는 데이터가 필요할 때 마다, malloc, free 로만 처리 됨.
• 파편화는 어쩔 수 없는 이슈.
34. 메모리 파편화 이슈 #2
• Jemalloc 3.6.0 버전으로 테스트 하지는 못함.
35. Redis Monitoring 항목
항목 수집 위치(Host or Redis(info))
CPU Usage, Load Host
Network inbound,
outbound
Host
현재 클라이언트 개수,
max client 설정
Redis
키 개수, 명령어 처리 수 Redis
메모리 사용량, RSS Redis
Disk 사용량, io Host
Expired keys, Evicted keys Redis
37. Redis 자료구조
• Redis는 다음과 같은 자료 구조를 지원한다.
– K/V, list, set, sorted set, hash
• Set, sorted set, hash의 경우는 메모리 효율을 위해서 특정 지정값
이전에는 성능은 떨어지지만, 메모리를 덜 사용하는 구조를 이용한다.
– Sorted set : ziplist
– Hash: ziplist
38. Redis Dict – Redis 기본 자료 구조.
• Hash Table
typedef struct dict {
……
dictht ht[2];
……
}dict;
40. Redis Dict – Hash Table의 확장 #1
• Dict에는 Hash Table 이 두 개 존재
• 필요할 때, 2배 사이즈가 큰 해시 테이블을 ht[1]번째에 생성한다.
• 테이블 확장이 끝나면 ht[0]번째를 지우고 ht[1]번째를 ht[0]번으
로 바꾼다.
44. Redis Dict에 대한 궁금점?
• 테이블이 확장 되는 동안에는 다른 처리는 어떻게 될까?
– 레디스는 싱글 스레드
• 확장중에 검색은 어떻게 할까?
– 테이블이 두 개가 있다며?
45. Redis Dict에 대한 궁금점?
• 테이블이 확장 되는 동안에는 다른 처리는 어떻게 될까?
– 레디스는 싱글 스레드
• 확장중에 검색은 어떻게 할까?
– 테이블이 두 개가 있다며?
46. 테이블은 한 번에 확장되지 않는다.
• 테이블 확장 방법
– 먼저 두 배 사이즈의 해시 테이블을 만듬.
– 한번에 하나의 테이블 버킷만 처리…
• 새로 추가되는 것은 확장되어야 할 타켓 테이블에만 저장한다.
• 테이블 확장시 검색 방법
– ht[0] 과 ht[1]을 모두 검색한다.
55. ziplist 가 필요한 이유
• Hash 와 SkipList 는 빠르지만, 메모리 사용량이 많다.
• Collection 안에 아이템 개수가 적다면, 느린 자료구조에서도 충분히
빠르다.
– 레디스는 인 메모리라서 충분히 빠름.
Redis.conf 조절 항목
hash-max-ziplist-entries
hash-max-ziplist-value
zset-max-ziplist-entries
zset-max-ziplist-value
66. Scan 주의 사항
• Sorted Set 이나 Hash, Set의 경우에도 내부적으로 Hash Table로
구성되면 위와 같은 형태로 동작
• 그럼 ziplist 라면?
– 아이템 개수가 적다고 생각하고 한번에 모두 scan 함.
– 그러므로 개수가 많으면, 같은 이슈가 발생할 수 있음
• 다만 기본 설정은 특정 개수를 넘어가면 Hash 또는 skiplist로 변경되므로 문제가
없음.
68. Redis Replication 과정
1. Slave 가 Master로 Sync 명령을 보냄
2. Master는 Fork 하여 RDB 생성
3. RDB 생성이 끝나면 Master는 RDB를 Slave로 전송
4. 해당 시간동에 master가 받는 명령어는 memory에 저장
5. RDB 전송이 끝나면 Slave 가 해당 RDB Load
6. Slave의 RDB 로드가 끝나면 Master가 메모리에 쌓인 데이터 전
송
69. Redis Repliaction의 문제점
• Redis의 경우 마스터 슬레이브 상황에서 Master랑 연결이 잠시
라도 끊어지면, Slave는 Master의 모든 내용을 Full Sync 받는다.
– Disk IO는 비쌈
• Slave는 Master 상태를 계속 폴링으로 체크함.
70. Partial Sync
• Master와의 접속이 끊기고 다시 연결될 때, 기존과 동일한 master
라면, 그리고 master의 memory buffer 범위 내로 데이터가 변
경되었다면 해당 데이터만 전송 받아서 full sync를 피함.
71. Partial Sync 한계 회피 방법
• 모든 노드가 replication buffer와 현재 offset을 맞추고, 장애시
새로운 master의 replication buffer의 offset 을 비교 한 후 일
정 범위면 해당 데이터만 받도록 코드를 수정해야 함.
• 이슈
– Replication buffer 가 네트웍 버퍼를 그대로 이용하므로 특정 시간이 지
나면 해당 버퍼가 PING 으로 가득차게 됨., 이를 제거하는 부분이 필요.
– 실제로 위의 부분을 모두 구현해야만 가능.
– 실제 코드량이 많이 수정될 필요는 없음.
74. Redis Cluster #1
• 많은 사람들이 기다리던 기능
• 아직 실험적임
– 큰 곳에서 사용된 레퍼런스가 없음
– 관리가 귀찮음
75. Redis Cluster #2
• 최소 구동 스펙
– Master 3대
– Slave 3대
– 총 6대가 필요함
• 슬레이브가 없어도 동작은 함
– 기본 설정에서 한대의 마스터라도 장애가 나면 전체 클러스터 다운됨
• 이걸 풀어주는 옵션이 존재
76. Redis Cluster #3
• 16384의 내부 슬롯이 존재
• Sentinel 이 없이 Master 노드끼리 장애 감지 후 Slave를 자동으로
Master로 승격시킴
• Redis-trib.rb 라는 관리 도구를 이용함
– Slot migration 등은 Redis Cluster 명령을 이용하여 redis-trib을 통
해서 관리자 메뉴얼하게 이동시켜야 한다.