grep

Engineering

레디스 버전6 뉴피처와 주요 기능 테스트

NHN

2020년 7월 16일

원문에서 보기 ↗

안녕하세요. 데이터운영팀 김가림입니다. 얼마 전 4월 30일에 레디스 뉴 피처가 발표됐습니다. 레디스 오픈소스의 창시자인 Antirez는 이번 6버전이 그동안의 릴리즈중 가장 큰 변화라고 공식적으로 말했고, 도대체 얼마나 큰 변화인가! 궁금해져서 언능 알아보았습니다.

Redis 6 is the biggest release of Redis *ever*, so even if it is stable, handle it with care, test it for your workload before putting it in production. ( http://antirez.com/news/132 )

Client side caching

데이터베이스 성능도 최적화했고, 레디스같이 빠른 캐시서버를 사용하고 있음에도 만족할만한 성능이 나오지 않는다면? 클라이언트 사이드 캐시 의 도입을 고려해 볼 수 있겠죠. 레디스 버전 6에서는 이 기능을 아주 쉽고 간단하게 사용할 수 있습니다. 1.png 기본적으로 데이터베이스에서 데이터를 가지고 오는 방법은 위 그림과 같습니다. 여기서 데이터베이스는 오라클, 레디스 등으로 생각할 수 있습니다. 하지만 클라이언트 사이드 캐시를 추가하면 어플리케이션이 네트워크를 타고 가서 데이터베이스에 질의하는 시간 을 줄일 뿐더러, 데이터베이스에서 이 요청을 받아 처리하는 비용을 줄일 수 있습니다.

2.png 하지만 캐시의 단점은 역시 데이터의 정합성에 있습니다. 다른 클라이언트에서 user:1234의 값을 변경시켰을 때 로컬에 저장되어있는 데이터는 없어져야 합니다. 이를 위해 레디스는 각각 장단점이 존재하는 두 가지 모드를 제공합니다.

기본 모드에서 레디스 서버는 어떤 클라이언트가 어떤 키를 저장하고 있는지를 기억하는 Invalidation Table을 생성합니다. 한 클라이언트에서 여기에 저장된 키를 변경하면 레디스는 그 키를 저장하고 있는 다른 클라이언트 모두에게 캐싱된 값을 삭제하라는 메시지를 보냅니다. 이 과정에서 레디스 서버의 메모리 사용량은 다소 증가할 수 있습니다.

Invalidation Table이 메모리를 과도하게 사용하지 않도록 레디스 6에서는 tracking-table-max-keys 라는 파라미터를 도입했습니다. 이 값은 Invalidation Table이 저장할 수 있는 키의 개수이며, 기본적으로 백만개까지 저장할 수 있습니다.

3.png

또 다른 모드는 브로드캐스팅 모드입니다. 이 모드에서 레디스 서버는 키에 대한 값은 저장하지 않습니다. 대신 키의 앞부분 프리픽스와, 매칭되는 키를 가지고 있는 클라이언트를 저장합니다. 프리픽스에 해당하는 클라이언트는 해당하는 키가 변경될 때마다 서버로부터 알림을 받고, 매칭되는 키가 있다면 캐싱되어있는 그 데이터를 삭제합니다. 이 방법은 기본 모드보다 메모리는 더 적게 사용하지만, 해당 키가 없는 클라이언트도 이 값을 수신할 수 있기 떄문에 네트워크 사용량이 더 증가할 수 있습니다.

저는 이 내용을 블로그에 공유하고, 아래와 같은 질문을 받았습니다.

Q. HGET / HSET 명령에도 client side cache 적용이 가능한가요?

A. 네! 관련된 공식 문서는 없지만 테스트 했을 때 HGET, HSET을 포함한 다양한 커맨드에 적용되는 것 같아요. HLEN으로 길이만 가져온 다음에 다른 클라이언트에서 HSET으로 해시 내의 아이템을 수정해도 invalid 메시지를 보내더라구요.

Q. 그러면 1000만개 아이템이 들어있는 Hash를 지우면 invalid 노티가 엄청 쏟아질지도 모르겠네요? 그런 일이 생기면 퍼포먼스에 꽤 충격이 클텐데요🤔 우려하는 식대로 동작하는지는 테스트해봐야겠네요

이 질문에 답변을 하기 위해, 아래와 같은 테스트를 진행했습니다.

1. 클라이언트에서 myhash 읽어옴 (hlen으로 해시 크기만) --> 클라이언트에 데이터 해싱됨
2. 다른 클라이언트에서 myhash 수정

위시나리오에서 notification 메시지는 몇번 갈 것인가?! 수정한 아이템 개수만큼?! 아니면 키 하나당 한개?

4.png

테스트 결과는 위와 같았습니다. 여러 아이템이 들어있는 해시키가 삭제/변경되어도 invalidate 노티 메시지는 단 한번 발생했습니다. 다행히 위의 질문자분이 걱정했던 노티 폭탄이 발생하지는 않겠네요.

이와 관련한 레디스6의 클라이언트 사이드 캐싱에 대해서 더 궁금하시다면 여기를 참고해주세요.

Threaded I/O

레디스는 그동안 싱글 스레드로 동작해왔습니다. 복잡성을 줄여 Atomic하게 데이터를 처리할 수 있다는 장점을 가지고 있죠. 하지만 싱글 스레드이기 때문에 발생하는 명확한 단점이 존재했습니다. 오래 걸리는 한 개의 작업이 다른 많은 작업을 대기하게 만들었으며, 사용자가 잘못 날린 커맨드 하나가 장애를 일으키는 사례도 많이 발생했었습니다.

이번 버전부터 레디스는 클라이언트에 대해 read/write 쓰레드를 구성할 수 있게 되었습니다. 이 기능은 io-threads 라는 파라미터로 제어되며 디폴트는 1, 즉 이전처럼 한 개의 스레드만 사용합니다. 공식 문서는 이 기능을 조심히 사용할 것을 권장합니다.

Antirez는 복잡성을 줄이기 위해 그동안 스레드를 도입하지 않았던 이유를 설명하며, 이 기능의 도입은 디자인 관점에서 보았을 때 엄청난 희생이라고 트윗에서 언급했습니다. 그래도 200줄 정도의 코드를 추가하여 2.5배 정도의 성능 향상을 일으킬 수 있었다고 합니다. 5.png

이 내용을 실제로 테스트해 본 사례 를 찾아봤는데, 실제로는 성능이 5~10%정도 떨어진다고 합니다. 쓰레드를 사용해서 원하는 결과를 얻기 위해서는 조금 더 테스트가 필요할 것 같습니다.

ACL

데이터베이스를 운영하는 입장에서 그동안 레디스에 꼭 필요하다고 생각했던 기능이 이번 버전에 도입되었습니다. MySQL이나 Oracle에는 유저가 존재하고, 그 유저가 사용할 수 있는 커맨드와, 접근 가능한 테이블을 지정할 수 있었지만 레디스는 아예 유저라는 개념이 존재하지 않았었습니다. 그나마 rename-command 를 통해 특정 커맨드를 사용할 수 없도록 우회하는 방법이 있었지만 말 그대로 우회 방법 이었던거죠.

레디스6에서 user는 아래와 같이 정의할 수 있습니다.

6.png

6버전부터 패스워드는 SHA256을 통해 해시되어 저장됩니다. 또한 ACL GENPASS 커맨드를 통해 강력한 암호를 생성할 수도 있습니다.

레디스6의 ACL에 대해서 더 궁금하시다면 여기 를 참고해주세요.

기타 자잘한 업그레이드

출처