Redis 프로토콜의 변화 - RESP2 & RESP3

Spark Kim·2021년 9월 11일
0

잘 돌아가던 코드가 뱉은 에러 폭탄

나는 여러가지 용도로 Redis를 적극적으로 사용하고 있다.
Redis에서는 여러가지 자료형 형태의 적재를 지원하고 있는데, 내가 가장 많이 사용하는 자료형은 단연 Hashes 자료형일 것이다.

Hashes 자료형은 아래와 같은 구조를 가지기에, 동일한 기준으로 구분하여 여러 값을 저장/관리하기에는 Hashes 만한 게 없다.

Key - Field - Value

가령, 사람 별 선호하는 과일에 대해서 데이터를 저장하고자 하면 다음과 같이 Key, Field Value를 저장할 수 있을것이다.

Key : Favorites
Field : Spark
Value : Strawberry

Redis 버전 5.X.X 대까지만 해도 Hashes와 같은 여러개의 자료형을 하나의 키에 관리하는 경우, 조회시 Array 형태의 결과값을 출력했었다.

즉, Array의 홀수번째 값은 Field, 짝수번째 값은 Value 인 형태의 결과값을 출력하는 것이다.

기존의 결과값이 저런형태이다 보니, Array 자료형에 맞게 모든 코드가 개발되어 있었다.
그런데 팀 내 개발 서버 Redis 버전을 6.X대로 업그레이드 한 어느 날, 내 코드는 에러를 가득 뿜어내기 시작했다.
로그 파일에 줄줄이 기재된 Exception, Exception, Exception.....
Redis Hashes 조회 명령을 실행하는 코드에서 에러가 발생하고 있었고,
디버깅을 진행한 결과, 조금은 당황스러운 원인이 드러났다.

조회한 데이터의 출력 형태가 Array 가 아닌 것이다.

현재 Redis 6.x 버전에 대해서 조회를 하면 아래와 같은 결과값을 볼 수 있다.

데이터의 형태가 Array가 아니라, Map 형태로 변경된 것을 확인할 수 있다.

도대체 왜 출력 형태가 변한걸까? 지금부터 내가 아는대로 변화하게 된 원인, 이유에 대해 설명해보려 한다.

RESP란?

설명하기에 앞서, 변화를 만든 장본인, RESP의 정체에 대해 간략히 소개하려 한다.
RESP (REdis Serialization Protocol)은 Redis에 데이터를 Read/Write하는 클라이언트가, Redis Server와 데이터를 주고 받을 때 사용하는 프로토콜이다.
RESP에는 명시적으로 현재 Read/Write하는 데이터가 어떤 형태로 표출되는지 대한 정보도 포함되어 있다. (데이터의 첫번째 byte에 구분자 형태로 담기게 된다.)

과거 RESP2에서 Redis Server에 적재된 데이터를 표출하는 형태는 5가지가 제공되었다.

종류첫 byte
Simple Strings+
Errors-
Integers:
Bulk Strings$
Arrays*

그렇다보니 대부분 여러개의 결과가 나올 수 있는 Lists, Sets, Hashes 등의 자료형은 별다른 구분 없이 Arrays 형태로 표현되는 게 당연한 일이었다.

그러나 RESP2 기준으로 표출을 하는 경우 Double 형태, boolean 형태 등에 대해서는 미지원이다보니, 부득이하게 문자열로 저장이 되어야 하는 등 여러 측면에서 한정적인 표출 결과가 아쉬울 수밖에 없었다.

그래서 Redis 6.X 버전 부터는 RESP를 좀더 확장하여, RESP3 라는 발전된 프로토콜을 선보이게 되었으며, RESP3로 업그레이드가 되면서 아래와 같은 출력형태를 추가로 지원하게 되었다.

종류첫 byte
Null_
Double,
Boolean#
Blob Error!
Verbatim String=
Map%
Set~
Attribute|
Push>
Big Number(

위의 변화를 기준으로 RESP3 기준으로 여러개의 데이터를 동시에 표출하는 방식이 다음과 같이 달라졌다.

자료형조회 명령어RESP2RESP3
ListsLRANGEArraysArrays
SetsSMEMBERSArraysSet
HashesHGETALLArraysMap

그렇게 RESP3 기준으로 코드를 변경하면서 다 잘 해결된 줄 알았다.

Redis Enterprise, 아직 RESP3를 미지원한다고...?

현업에서 사용 중인 Dev 환경의 Redis 버전이 community 버전이고, Live 환경의 Redis 버전이 Enterprise 버전이라는 차이가 또 에러 파티에 빠뜨릴 줄은 예상하지 못했다.

Dev 환경에서 테스트까지 마친 모듈을 Live 환경에 배포하고, 로그 모니터링을 하자, 에러가 줄줄이 쏟아지기 시작했다. 기껏 Map 형태로 처리하도록 수정한 소스코드에서 다시 문제가 발생한 것이다.

이번에는 표출 형태가 다시 Arrays가 되어있었다.

우선은 긴급히 소스를 Arrays 형태로 처리하도록 원상복구 시키는 조치를 하고서 모듈을 다시 배포했다.
원인이 뭔지 찾아야 하는 상황이다보니, Redis Enterprise 한국 공식 공급사에 문의를 하게 되었다.

"현재 Redis Enterprise 는 RESP3를 지원하지 않습니다."

버전의 차이인지는 모르겠으나, 7.x 버전의 Redis Enterprise 버전이었음에도 불구하고 RESP3를 지원하지 않는다는 소식에 아쉬웠다. 결국 소스코드를 이원화 처리를 하지 않으려면, 6.x community 버전의 dev 환경 Redis에서도 RESP2로 회귀하는 방법을 찾아야 했다.

HELLO Redis

Redis 공식 Documentation에서 찾은 방법은 connection 시 HELLO 명령어를 이용하여 RESP 버전을 전환하는 방법이었다.
HELLO 명령은 Redis의 현재 버전 정보, Mode, role 등 현재 Redis 의 기본 정보를 보여줌과 동시에 RESP 프로토콜을 전환할 수 있는 명령어이다.

사용법은 다음과 같다.

127.0.0.1:6379> hello 2
127.0.0.1:6379> hello 3

hello 2 를 입력하게 되면 RESP2 로 전환이 되고, hello 3 를 입력하게 되면 RESP3로 전환된다.

  • hello 2 예시

  • hello 3 예시

주의해야할 점은 hello 명령어 자체가 Redis 6.x 버전부터 생긴 명령어이다 보니, 이전 버전에서는 실행 불가한 명령어라는 점이다.

그리고 현업에서 쓰는 Redis Enterprise 버전도 hello 명령어를 지원하지 않았다.

결국 Dev 환경 배포 시 Application 단에서 connection 후 hello 2 명령을 실행하도록 configuration 화하는 소스코드를 추가 개발하는 것으로 일은 마무리가 되었다.

이미 잘 만들어진 Redis Client 라이브러리를 사용하다보니 프로토콜에 대해서는 신경을 쓰지 않다가, 뜻밖의 현상에 의해 RESP 프로토콜에 대해서 알게 되었던 흥미로운 경험이었다.

profile
성장 지향 백엔드 개발자

0개의 댓글