5. 인메모리 키-값 형태의 저장소
고성능
각종 모니터링 및 알림 기능
관리형 서비스
Redis와 Memcached 지원
Amazon
ElastiCache
6. 관리형 서비스 = 자동화된 운영이 가능
EC2상에서 Redis/Memcached 직접 운영하는 경우 ElastiCache 사용하는 경우
7. Memcached vs Redis
• 수평적인 문자열 캐시
• 멀티스레드
• 디스크에 저장 안함
• 단순한 관리
• 수평적 확장이 쉬움
• 싱글 스레드
• 원자적 연산 지원
• 다양한 자료 구조 지원
• Pub/Sub 기능 지원
• 읽기 복제본 지원
• Failover 지원
17. Redis 특징 요약
다양한 명령어 제공
~200 commands
메모리 기반 키-값 저장소
다양한 종류의 자료구조
strings, lists, hashes, sets, sorted sets, bit
maps & HyperLogLogs
싱글 스레드 구조
원자적 연산 제공
supports transactions
has ACID properties
무진장 빠름!
<1ms latency for most commands
읽기 복제본 지원
데이터 영속성 지원
snapshots or append-only log
Pub/sub 기능 제공
18. Amazon
ElastiCache
Multi-AZ 기능 사용 가능
CloudWatch를 통한 모니터링
완전 관리형 서비스
향상된 Redis 엔진 적용
바로 시작 가능 및 손쉬운 사용
Redis 직접 운용 vs ElastiCache Redis
AZ간 데이터 전송 비용 없음
19. PrimaryReplica
Replica
writes
Use Primary Endpoint
reads
Use Read Replicas
Auto-Failover
복제 지연이 가장 적은 복
제본이 선택됨
DNS endpoint 변화 없음
Multi-AZ 자동 Failover
ElastiCache
for Redis
ElastiCache
for Redis
ElastiCache
for Redis
Primary node 실패시 읽기 복제본으로 자동 Failover
주기적으로
스냅샷 저장
25. 일반적인 사용 구조
ELB App
External APIs
Replication Group
ReadsWrites
26. Redis 읽기/쓰기용 연결 구성
# Ruby example
redis_write = Redis.new(
'mygame-dev.z2vq55.ng.0001.usw2.cache.amazonaws.com')
redis_read = Redis::Distributed.new([
'mygame-dev-002.z2vq55.ng.0001.usw2.cache.amazonaws.com',
'mygame-dev-003.z2vq55.ng.0001.usw2.cache.amazonaws.com'
])
redis_write.zset("leaderboard", “player_aa", 1997)
top_10 = redis_read.zrevrange("leaderboard", 0, 10)
27. Endpoint 자동 감지가 필요한 경우
• 클러스터 엔드포인트 확인
aws elasticache describe-cache-clusters
--cache-cluster-id mycluster
--show-cache-node-info
• 읽기 복제본 엔드포인트 확인
aws elasticache describe-replication-groups
--replication-group-id myredisgroup
• SNS 이벤트를 통해 노드 상태 변경 감지
• http://bit.ly/elasticache-sns
28. 목적/역할에 따라 클러스터 분리
ELB App
External APIs
Reads
Writes
Leaderboards
특히, 리더보드의 경우에는
등수나 등급(골드, 실버, …)에
따라 분리하는 경우도 많음
User Profiles
Reads
35. 캐싱을 적용하기도 쉬움 – Lazy Caching
# Python
def get_user(user_id):
record = cache.get(user_id)
if record is None:
# Run a DB query
record = db.query("select * from users where id = ?", user_id)
cache.set(user_id, record)
return record
# App code
user = get_user(17)
36. 캐싱을 적용하기도 쉬움 – Write-through
# Python
def save_user(user_id, values):
record = db.query("update users ... where id = ?", user_id, values)
cache.set(user_id, record)
return record
# App code
user = save_user(17, {"name": “Jeff Bezos"})
37. TTL도 적용해보자!
def save_user(user_id, values):
record = db.query("update users ... where id = ?", user_id, values)
cache.set(user_id, record, 300) # TTL
return record
def get_user(user_id):
record = cache.get(user_id)
if record is None:
record = db.query("select * from users where id = ?", user_id)
cache.set(user_id, record, 300) # TTL
return record
# App code
save_user(17, {"name": "Nate Diddy"})
user = get_user(17)
38. 마이 프
레셔스!골룸!
• Redis Sorted Sets 활용
• Uniqueness + Ordering
• 데이터 양이 아주 많은 경우
• 그룹(등급, 랭킹 범위)별로 분리
ZADD "leaderboard" 1201 "Gollum”
ZADD "leaderboard" 963 "Sauron"
ZADD "leaderboard" 1092 "Bilbo"
ZADD "leaderboard" 1383 "Frodo”
ZREVRANGE "leaderboard" 0 -1
1) "Frodo"
2) "Gollum"
3) "Bilbo"
4) "Sauron”
ZREVRANK "leaderboard" "Sauron"
(integer) 3
사용 패턴 #2 – 실시간 랭킹 보드
39. 사용 패턴 #3 – PUB/SUB을 통한 메시지 전달
• Redis PUBLISH / SUBSCRIBE 기능
• 특정 그룹간 채팅으로 활용 가능
• 서버간 통신에 활용 가능
• (참고) 넥슨의 듀랑고
• 단발성 Queue로도 사용할 수 있음
SUBSCRIBE chat_channel:114
PUBLISH chat_channel:114 "Hello all"
>> ["message", "chat_channel:114", "Hello all"]
UNSUBSCRIBE chat_channel:114
40. • 추천 엔진 및 게시판 랭킹에 활용 가능
• Redis counters – 좋아요/싫어요 카운팅
• Redis hashes – 사용자들의 별점 기록
• 자카드 계수(Jaccardian similarity)를 활용하여 평균 별점 계산
https://github.com/davidcelis/recommendable
사용 패턴 #4 – 추천(별점 표시) 기능
INCR item:38927:likes
HSET item:38927:ratings "Susan" 4
INCR item:38927:dislikes
HSET item:38927:ratings "Tommy" 2
41. • API 요청에 대한 스로틀링 처리
• 게임 bot(매크로)의 burst한 요청 제한
• Redis 카운터 및 TTL 활용
ELB
Externally
Facing A
PI
Reference: http://redis.io/commands/INCR
FUNCTION LIMIT_API_CALL(APIaccesskey)
limit = HGET(APIaccesskey, “limit”)
time = CURRENT_UNIX_TIME()
keyname = APIaccesskey + ":” + time
count = GET(keyname)
IF current != NULL && count > limit THEN
ERROR ”API request limit exceeded"
ELSE
MULTI
INCR(keyname)
EXPIRE(keyname,10)
EXEC
PERFORM_API_CALL()
END
사용 패턴 #5 - Rate Limiting
43. Redis 운영중 주로 겪는 문제
• 증상은 다양
• [Memory] 풀 나서 인스턴스 죽었어요
• [CPU] 쳐묵쳐묵 버벅버벅
• [Network] Master/Slave 연결이 자꾸 끊겨요
• 주요 원인은 간단
• Fork()를 통한 백업 및 Master/Slave 복제
• Client-Output-Buffer 스로틀링
• Failover 후 full-resync
ElastiCache용 Redis 엔진은 많은 부분을 수정해서 적용
44. 향상된 Redis 엔진
• Amazon ElastiCache에서만 사용가능
• Forkless Replication 구현
• 스냅샷 또는 복제 수행시 메모리 사용 최소화
• 메모리 용량이 충분하다면, 그냥 Fork 사용 (빠르기 때문)
• 동적으로 Client-Output-Buffer (COB) 스로틀링 제어
• 부드러운(?) Failover 지원
• PSYNC
45. Forkless Replication
• RDB (BGSAVE): 내부적으로 자식 프로세스를 fork()해서 스냅샷 작업
• Replication: fork()된 자식 프로세스가 복제본으로 데이터를 전달
• Fork로 인한 메모리 사용이 최대 2배가 될 수 있음
• 물리 메모리 부족시 Swap 발생
• reserved-memory 파라미터를 설정해서 메모리 확보 가능
46. Dynamic Client Output Buffer
• Client Output Buffer
• 결과 데이터 또는 복제 데이터를 버퍼링 한 후에 Flush해서 전달
• Redis.conf에서 soft/hard limit 설정 가능
• limit 도달시 클라이언트 접속 종료
• “버퍼 크기 x 클라이언트 수(복제본 포함)” 만큼 메모리 할당
• 순식간에 메모리 수 GB를 먹어버릴 수 있음
메모리 부족으로 인한 각종 증상 (eviction, disk swap, …)
• 크기를 작게 잡으면 클라이언트가 자주 종료
재접속, 재요청, 동기화 증가로 인한 CPU 사용률 증가
• 동적 쓰기 제어
• COB에 쓰기 작업을 CPU 및 메모리 사용 상황에 따라 동적으로 제어
47. Redis Cluster
• Redis에도 드디어 (수평적 분할) 클러스터 기능 도입
• Redis 3.0의 클러스터 기능 우선 적용
• Multiple Shard!
• Redis Cluster 명령어 모두 지원 예정
• AWS 관리 콘솔 업데이트