93
Redis Internal and RoadMap from 2.8 to 3.2 [email protected]

Redis acc 2015

Embed Size (px)

Citation preview

Page 1: Redis acc 2015

Redis Internal and RoadMap from 2.8 to 3.2

[email protected]

Page 2: Redis acc 2015

Redis/Twemproxy Contributor

2014/02 ~ 현재 카카오 스토리 백엔드 2010/04~2012/03 네이버 메일 백엔드

Page 3: Redis acc 2015

목차

• Redis 운영

• Redis 자료구조

• Redis 주요 변화

– 2.8 부터 3.2 까지

Page 4: Redis acc 2015

Redis 운영

Page 5: Redis acc 2015

REDIS

• 심플한 인 메모리 캐시 서버

• 자료구조와 리플리케이션, 디스크 백업을 제공한다.

– 자료구조(K/V, set, sorted set, hash)

– Replication(Master/Slave, Chained 형태 가능)

– 디스크 백업(RDB/AOF)

Page 6: Redis acc 2015

싱글 스레드 #1

• Redis는 싱글 스레드.

– 긴 작업을 처리하는 동안에는 다른 작업을 처리할 수 없다.

– 긴 작업이란?

• O(N) 의 명령의 수행 대상이 아주 많을 경우. – Keys, flushall 등

• Lua Script 도 하나의 커맨드로 수행된다.

• MULTI/EXEC의 경우는 모아두었다가 EXEC가 들어오면 한번에 모두 수행한다.

Page 7: Redis acc 2015

싱글 스레드 #2

• 하나의 서버에 CPU Core 가 여러 개라면, 여러 개의 Instance를 실행하는 것이 성능상 유리하고 더 안정적.

– 메모리는 낭비, 관리는 조금 더 어려움.

• CPU 4 core, 32G Memory

Mem: 26G

Mem: 8G

Mem: 8G

Mem: 8G

Page 8: Redis acc 2015

Redis Event Loop #1

Client #1

Client #2

……

Client #N

Redis Event Loop

I/O Multiplexing

Process Command

Packet #1

Packet #2

Page 9: Redis acc 2015

Redis Event Loop #2

• 클라이언트가 보낸 하나의 패킷이 완성이 되면 바로 해당 커맨드를 수행한다.

– Redis는 싱글 스레드.

• 이 동안에는 다른 코드가 동작하지 않는다.

• 긴 작업의 경우에는 Event Loop 내에서 처리되므로 다른 명령을 받지 못한다.

• 한 루프당 여러 개의 명령이 실행 될 수 있음.

– Reactor 패턴과 유사

Page 10: Redis acc 2015

얼마나 느린가?

Command Item Count Time

flashall 1,000,000 1000ms(1 second)

Page 11: Redis acc 2015

여기서 퀴즈!!! 운영중인 서비스에서 Key *를 사용하면?

Page 12: Redis acc 2015

Persistent

• RDB/AOF

– RDB와 AOF는 서로 아무런 연관이 없다.

– 그냥 디스크에 저장하는 방식들이라는 공통점만 존재

– 동시에 사용 가능

Page 13: Redis acc 2015

RDB #1

• Redis의 메모리 내용을 디스크로 덤프하는 기능

• 어떤 때 RDB를 생성할까? – SAVE 조건이 만족할 때

– 슬레이브가 마스터에 SYNC 명령을 보냈을 때(In Replication)

– 사용자가 명시적으로 SAVE or BGSAVE 명령을 내렸을 때

• 주의하자!!! – Redis 장애의 대부분이 디폴트 옵션을 이용해서임.

– SAVE 시간(초) 변화하는 키 개수 • SAVE 900 1

• SAVE 60 10000

Page 14: Redis acc 2015

RDB #2

• Redis의 RDB는 Fork 를 이용한다.

– Write가 Heavy 한 서비스는 메모리를 최대 두배 까지도…

– 보통의 서비스는 READ:WRITE = 80:20 수준

– 그러나 Batch Job 서버는?

• 모든 키의 내용이 바뀌어야 한다면?

• 특정 시간내에 전부 바뀔 수 있다.

• Os의 COW 때문(copy on write)

Page 15: Redis acc 2015

Copy on Write

• 부모 프로세스의 메모리 Page 에 Write 가 발생할 때 마다, 해당 메모리 Page를 복사하게 된다.

• 읽기의 경우에는 메모리를 추가로 복사할 필요가 없다.

Page 16: Redis acc 2015

Copy on Write #1

Process - Parent

Physical Memory

Page A

Page B

Page C

Page 17: Redis acc 2015

Copy on Write #2 – Fork(), 메모리 수정 전

Process - Parent

Physical Memory

Page A

Page B

Page C

Process - Child

Page 18: Redis acc 2015

Copy on Write #2 – Fork(), 메모리 수정 후

Process - Parent

Physical Memory

Page A

Page B

Page C

Copy of Page C

Process - Child

Page 19: Redis acc 2015

Copy on Write 결론

• 최악의 경우에는 메모리를 두 배 까지 사용할 수 있다.

– 모든 Page 에 write가 발생했을 경우

• 메모리가 부족해서 스왑 영역을 사용하면 엄청나게 느려지게 된다.

Page 20: Redis acc 2015

AOF #1

• Append Only File

• Redis 프로토콜을 그대로 저장.

• 한 번의 이벤트 루프가 지날 때마다 발생한 Write 관련 명령들을 디스크에 저장함 – 이로 인해, Disk에 한번에 쓰는 데이터 양이 적어서 RDB 보다 부담이 적음

• 최초 부터 모든 로그를 가지고 있으므로 update가 빈번하면 실제 데이터 보다 파일 크기가 많이 커질 수 있다 – 설정에 의해서 rewrite가 발생함

• 이것도 fork로 이루어지므로 주의가 필요.

Page 21: Redis acc 2015

AOF #2

• DB의 바이너리 로그나 WAL와 비슷하다고 할 수 있지만, 쓰는 타이밍 등에서 다름.

WAL, Binary Log 실제 데이터 반영 전에 기록. 장애시에 해당 값을 실행해서 복구한다.

AOF 한 루프가 끝난 후에, 반영한 명령어들만 저장한다.

Page 22: Redis acc 2015

AOF Sample

*3\r\n

$3\r\n

Set\r\n

$3\r\n

Abc\r\n

$3\r\n

key\r\n

Page 23: Redis acc 2015

RDB/AOF 주의 사항 #1

• RDB/AOF 가 필요하면

– Master/Slave 로 정하고 Slave 에서 메모리를 덤프하거나.

– 실제 메모리가 2배가 되더라도 실 메모리 이하만 사용하도록

• 프로세스당 메모리 사용량을 정해놓는다.

• 16GB 장비에 CPU가 4개라면 3개의 인스턴스를 실행하고 각각 3G 정도만 사용.

• RDB/AOF 등으로 인해서 사용 메모리 영역의 일부가 swap 되게 되면, 해당 메모리에 접근할 때 마다, 전체 퍼포먼스가 저하된다.

Page 24: Redis acc 2015

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.”

Page 25: Redis acc 2015

Redis on AWS

Page 26: Redis acc 2015

AWS on PV 에서 주의할 점

• Amazon AWS에서 PV 머신을 선택했을 때, Xen 의 PV 에서의 fork 성능에 이슈가 있음.

– 메모리 사이즈에 따라서 몇 초 까지 걸릴 수 있음.

• HVM을 사용하면 아무런 문제 없음.

Page 27: Redis acc 2015

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

Page 28: Redis acc 2015

PV vs HVM

• Xen 에서 PV 일 경우 fork 시에 page tables을 복사하는데 부하가 걸림…

– 왜 걸리는지는 묻지 말아주세요. PV에서 그냥 느립니다.

• Page tables의 사이즈에 영향을 받음.

• 실제 머신의 물리 메모리의 크기 보다는 레디스가 사용하는 Page 에 영향을 받음

Page 29: Redis acc 2015

fork 20x~30x 차이가 남

Page 30: Redis acc 2015

THP 도 같은 효과가 나므로 설정으 꺼야 함.

Page 31: Redis acc 2015

느린 Disk IO

• EBS의 경우, Ephemeral Disk 보다는 속도가 느림.

– 그래서 Disk에 쓰기 작업(RDB/AOF) 등에서 불리함.

Page 32: Redis acc 2015

추천 Redis 버전

• 2.8.13 이후를 사용하는게 좋음.

– Jemalloc 3.6.0을 사용한 버전

– 메모리 파편화 등에서 더 좋음

– Jemalloc 4.0.0 에서는 메모리 사용량이 더 좋아졌다지만 아직은 도입전

• 2015/08/17 일 Release

• AWS ElasticCache의 Redis 최신 버전은

– 2.8.19 선택 가능

Page 33: Redis acc 2015

메모리 파편화 이슈 #1

• Redis의 메모리 관리는 오직 메모리 할당자에 의해서 이루어 짐

– Memcached의 경우 메모리 관리에 Slab 할당자 등을 이용하고, chunk를 이용해서 chunk 단위의 메모리 할당만 일어남.

– Redis는 데이터가 필요할 때 마다, malloc, free 로만 처리 됨.

• 파편화는 어쩔 수 없는 이슈.

Page 34: Redis acc 2015

메모리 파편화 이슈 #2

• Jemalloc 3.6.0 버전으로 테스트 하지는 못함.

Page 35: Redis acc 2015

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

Page 36: Redis acc 2015

Redis 자료구조

Page 37: Redis acc 2015

Redis 자료구조

• Redis는 다음과 같은 자료 구조를 지원한다.

– K/V, list, set, sorted set, hash

• Set, sorted set, hash의 경우는 메모리 효율을 위해서 특정 지정값 이전에는 성능은 떨어지지만, 메모리를 덜 사용하는 구조를 이용한다.

– Sorted set : ziplist

– Hash: ziplist

Page 38: Redis acc 2015

Redis Dict – Redis 기본 자료 구조.

• Hash Table

typedef struct dict { …… dictht ht[2]; …… }dict;

Page 39: Redis acc 2015

Redis Dict – Redis 기본 자료 구조.

• Hash Table

Page 40: Redis acc 2015

Redis Dict – Hash Table의 확장 #1

• Dict에는 Hash Table 이 두 개 존재

• 필요할 때, 2배 사이즈가 큰 해시 테이블을 ht[1]번째에 생성한다.

• 테이블 확장이 끝나면 ht[0]번째를 지우고 ht[1]번째를 ht[0]번으로 바꾼다.

Page 41: Redis acc 2015

Redis Dict – Hash Table의 확장 #2

Page 42: Redis acc 2015

Redis Dict – Hash Table의 확장 #3

Page 43: Redis acc 2015

Redis Dict – Hash Table의 확장 #3

Page 44: Redis acc 2015

Redis Dict에 대한 궁금점?

• 테이블이 확장 되는 동안에는 다른 처리는 어떻게 될까?

– 레디스는 싱글 스레드

• 확장중에 검색은 어떻게 할까?

– 테이블이 두 개가 있다며?

Page 45: Redis acc 2015

Redis Dict에 대한 궁금점?

• 테이블이 확장 되는 동안에는 다른 처리는 어떻게 될까?

– 레디스는 싱글 스레드

• 확장중에 검색은 어떻게 할까?

– 테이블이 두 개가 있다며?

Page 46: Redis acc 2015

테이블은 한 번에 확장되지 않는다.

• 테이블 확장 방법

– 먼저 두 배 사이즈의 해시 테이블을 만듬.

– 한번에 하나의 테이블 버킷만 처리…

• 새로 추가되는 것은 확장되어야 할 타켓 테이블에만 저장한다.

• 테이블 확장시 검색 방법

– ht[0] 과 ht[1]을 모두 검색한다.

Page 47: Redis acc 2015

Redis Hash – Hash 속에 다시 Hash 테이블이 존재

Page 48: Redis acc 2015

Redis Sorted Set

• O(log(N))

• 링크드 리스트에 급행 열차 처럼, 몇단계 뒤를 가르키는 노드 레벨이 존재 – 해당 방식으로 쉽게 데이터를 찾을 수 있다.

Page 49: Redis acc 2015

Redis Sorted Set – Find Item #1

Page 50: Redis acc 2015

Redis Sorted Set – Find Item #2

Page 51: Redis acc 2015

Redis Sorted Set – Find Item #3

Page 52: Redis acc 2015

Redis Sorted Set – Find Item #4

Page 53: Redis acc 2015

숨겨진 자료구조

Page 54: Redis acc 2015

ziplist

Page 55: Redis acc 2015

ziplist 가 필요한 이유

• Hash 와 SkipList 는 빠르지만, 메모리 사용량이 많다.

• Collection 안에 아이템 개수가 적다면, 느린 자료구조에서도 충분히 빠르다.

– 레디스는 인 메모리라서 충분히 빠름.

Redis.conf 조절 항목

hash-max-ziplist-entries

hash-max-ziplist-value

zset-max-ziplist-entries

zset-max-ziplist-value

Page 56: Redis acc 2015

Ziplist 구조

zlbytes zltail zllen entry entry zlend

Page 57: Redis acc 2015

Ziplist의 단점

• 적은 데이터를 목표로 설계 됨

• 선형 검색

– 즉 개수가 많아지면, 메모리의 효율은 생기지만, 탐색 속도는 점점 늦어진다.

• 변경시마다 메모리 resizing이 필요.

Page 58: Redis acc 2015

Redis ROadmap

Page 59: Redis acc 2015

Redis 2.8

Page 60: Redis acc 2015

Redis 2.8

• Scan

• Partial Sync

Page 61: Redis acc 2015

Scan

Page 62: Redis acc 2015

Scan

• 2.8.x 부터 도입

– KEY * 명령의 대체가 가능

• Scan의 기본 구조는 Hash Table의 Bucket 단위로 순회하는 것.

• Cursor 다음 bucket의 index를 역으로 취한 것

– 값이 점점 감소하는 형태로 만들기 위해서

Page 63: Redis acc 2015

Scan 구조 #1

Page 64: Redis acc 2015

Scan 구조 #2

Page 65: Redis acc 2015

Scan 구조 #3

Page 66: Redis acc 2015

Scan 주의 사항

• Sorted Set 이나 Hash, Set의 경우에도 내부적으로 Hash Table로 구성되면 위와 같은 형태로 동작

• 그럼 ziplist 라면?

– 아이템 개수가 적다고 생각하고 한번에 모두 scan 함.

– 그러므로 개수가 많으면, 같은 이슈가 발생할 수 있음

• 다만 기본 설정은 특정 개수를 넘어가면 Hash 또는 skiplist로 변경되므로 문제가 없음.

Page 67: Redis acc 2015

Partial Sync

Page 68: Redis acc 2015

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가 메모리에 쌓인 데이터 전송

Page 69: Redis acc 2015

Redis Repliaction의 문제점

• Redis의 경우 마스터 슬레이브 상황에서 Master랑 연결이 잠시라도 끊어지면, Slave는 Master의 모든 내용을 Full Sync 받는다.

– Disk IO는 비쌈

• Slave는 Master 상태를 계속 폴링으로 체크함.

Page 70: Redis acc 2015

Partial Sync

• Master와의 접속이 끊기고 다시 연결될 때, 기존과 동일한 master 라면, 그리고 master의 memory buffer 범위 내로 데이터가 변경되었다면 해당 데이터만 전송 받아서 full sync를 피함.

Page 71: Redis acc 2015

Partial Sync 한계 회피 방법

• 모든 노드가 replication buffer와 현재 offset을 맞추고, 장애시 새로운 master의 replication buffer의 offset 을 비교 한 후 일정 범위면 해당 데이터만 받도록 코드를 수정해야 함.

• 이슈

– Replication buffer 가 네트웍 버퍼를 그대로 이용하므로 특정 시간이 지나면 해당 버퍼가 PING 으로 가득차게 됨., 이를 제거하는 부분이 필요.

– 실제로 위의 부분을 모두 구현해야만 가능.

– 실제 코드량이 많이 수정될 필요는 없음.

Page 72: Redis acc 2015

Redis 3.0

Page 73: Redis acc 2015

Redis 3.0

• Redis Cluster

• Diskless Replication(Experimental)

Page 74: Redis acc 2015

Redis Cluster #1

• 많은 사람들이 기다리던 기능

• 아직 실험적임

– 큰 곳에서 사용된 레퍼런스가 없음

– 관리가 귀찮음

Page 75: Redis acc 2015

Redis Cluster #2

• 최소 구동 스펙

– Master 3대

– Slave 3대

– 총 6대가 필요함

• 슬레이브가 없어도 동작은 함

– 기본 설정에서 한대의 마스터라도 장애가 나면 전체 클러스터 다운됨

• 이걸 풀어주는 옵션이 존재

Page 76: Redis acc 2015

Redis Cluster #3

• 16384의 내부 슬롯이 존재

• Sentinel 이 없이 Master 노드끼리 장애 감지 후 Slave를 자동으로 Master로 승격시킴

• Redis-trib.rb 라는 관리 도구를 이용함

– Slot migration 등은 Redis Cluster 명령을 이용하여 redis-trib을 통해서 관리자 메뉴얼하게 이동시켜야 한다.

Page 77: Redis acc 2015

Redis Cluster #4

• Java/Ruby/Python 등이 존재

– Cluster 지원 라이브러리가 계속 추가되는 중

Page 78: Redis acc 2015

Redis Cluster 동작 #1

Page 79: Redis acc 2015

Redis Cluster 동작 #2

Page 80: Redis acc 2015

Redis Cluster 동작 #3

Page 81: Redis acc 2015

Redis Cluster 동작 #4

Page 82: Redis acc 2015

Redis Cluster 동작 #5

Page 83: Redis acc 2015

Redis Cluster 의 단점

• Library의 동작에 의존

• 각 key에 적용되는 slot의 위치를 라이브러리가 알고 있어야 함.

• Migration이 자동으로 되지 않으므로 관리자가 지속적으로 확인하고 이동시켜줘야 함.

Page 84: Redis acc 2015

Diskless Replication

• RDB 덤프를 디스크에 저장하면 disk io가 발생하므로, 디스크에 쓰지 않고, 바로 Slave로 전송

– AWS의 EBS는 느리다.

– 일반 서버의 디스크도 많이 쓰면 느리다.

Page 85: Redis acc 2015

Redis 3.2

Page 86: Redis acc 2015

Redis 3.2

• Sds 구조체 메모리 사이즈 최적화

• GEO Command

Page 87: Redis acc 2015

Sds 구조체 메모리 사이즈 최적화 #1

• Sds 구조체의 Pointer 는 64 bit에서는 8byte, 이를 가변적으로 변경하는 작업.

• Jemalloc 에 24byte 할당 클래스도 추가

Page 88: Redis acc 2015

Sds 구조체 메모리 사이즈 최적화 #2

• Sds 구조체의 Pointer 는 64 bit에서는 8byte, 이를 가변적으로 변경하는 작업.

• Jemalloc 에 24byte 할당 클래스도 추가

String 길이 SDS 헤더 사이즈

8bit length 3 bytes

16bit length 5 bytes

32bit length 9 bytes

64 bit length 17 bytes

Page 89: Redis acc 2015

Sds 구조체 메모리 사이즈 최적화 #3

원래는 24가 없음

2^LG_QUANTUM 만큼 증가함으로 #define LG_QUANTUM 3 으로 설정(기존에 4)

Page 90: Redis acc 2015

Sds 구조체 메모리 사이즈 최적화 #4

• 메모리 사용량 변화

– 백만개의 아이템으로 테스트.

적용 메모리 사용량

오리지널 115.57M

SDS 헤더 변경 92.69M

Jemalloc new classes 77.43M

Page 91: Redis acc 2015

GEO Command

Page 92: Redis acc 2015

GEO Command

• GEO 관련 커맨드 추가

– GEOADD

– GEOHASH

– GEOPOS

– GEODIST

– GEORADIUS

– GEORADIUSBYMEMBER

Page 93: Redis acc 2015

감사합니다.