LLM WikiAccess-protected knowledge portal

WIKI

Redis 8.8: Array 자료구조·INCREX·XNACK — 운영자가 알아야 할 기능 확장과 성능 변화

왜 지금 Redis 8.8을 봐야 하나 Redis 8.8이 2026년 6월에 출시됐다. Redis 8.0 2025년 5월 이 I/O 스레딩 개선과 8개 새 자료구조를 한꺼번에 가져왔다면, 8.8은 그 토대 위에서 하나의 큰 구조적 추가와 두 개의 운영 관련 명령, 그리고 확실한 성능 수치를 가져왔다. 이번 글에서 다룰 세 가지 핵심 변화 1. Array 자료구조 Salvatore Sanfilippo가 직접 기여한 새로운 원시

경로human/study/content/database-frontier/22-redis-8-8-array-increx-xnack-streams.md
카테고리Study
태그#array #increx #mysql #redis #streams #study #xnack

왜 지금 Redis 8.8을 봐야 하나

Redis 8.8이 2026년 6월에 출시됐다. Redis 8.0(2025년 5월)이 I/O 스레딩 개선과 8개 새 자료구조를 한꺼번에 가져왔다면, 8.8은 그 토대 위에서 하나의 큰 구조적 추가와 두 개의 운영 관련 명령, 그리고 확실한 성능 수치를 가져왔다.

이번 글에서 다룰 세 가지 핵심 변화:

  1. Array 자료구조: Salvatore Sanfilippo가 직접 기여한 새로운 원시 자료구조. List, Set과 다른 용도.
  2. INCREX 명령: 레이트 리미터 구현을 단일 원자 연산으로 줄이는 window counter.
  3. XNACK 명령: Streams의 미결 메시지(PEL)를 더 세밀하게 제어하는 NACK 메커니즘.

성능 측면에서는 동기 복제(full synchronization)가 최대 60% 빨라지고, 핵심 명령 처리량이 최대 83% 향상됐다. 이 두 수치는 Redis를 복제 기반으로 운영하는 환경에서 체감 가능한 변화다.

이 글은 Valkey 9(Redis 포크, 2026년 5월 기준 별도 진화)가 아닌 Redis 오픈소스 8.8에 관한 내용이다.


Redis 8.0~8.8 맥락: 누적된 기반

Redis 8.8을 이해하려면 8.0에서 추가된 것을 먼저 알아야 한다.

Redis 8.0 (2025년 5월) 주요 추가 사항:

Redis 8.8은 이 위에서 Array 자료구조, INCREX, XNACK을 추가하고 복제와 핵심 명령 성능을 다시 한 번 끌어올렸다.


새 자료구조: Array (AR*)

Array란 무엇인가

Array는 Redis 8.8에서 처음 도입된 원시(native) 자료구조다. Salvatore Sanfilippo가 직접 기여했다. 인덱스로 직접 접근 가능한 문자열 값의 모음으로, 희소(sparse) 배열을 허용한다. 즉, 인덱스 0과 인덱스 1000에만 값을 저장하고 중간은 비워둘 수 있다.

Redis List
구조
양방향 연결 리스트
LPUSH/RPUSH/LRANGE
적합한 사용
큐, 스택, 최근 N개 항목
순서 보장, 양단 연산 O(1)
한계
인덱스 접근 O(N)
임의 위치 삽입 비효율
Redis Array (8.8 신규)
구조
희소 인덱스 배열
AR* 명령 패밀리
적합한 사용
센서 슬롯, 임베딩 벡터
고정 인덱스로 직접 읽기
강점
인덱스 접근 O(1)
희소 저장 → 낮은 메모리
Redis Set
구조
해시테이블 기반 집합
SADD/SMEMBERS/SISMEMBER
적합한 사용
중복 없는 컬렉션
멤버십 검사, 교집합/합집합
한계
순서 없음
인덱스 위치 없음
Array vs List vs Set — 언제 어느 것을 쓰는가

Array 핵심 명령 패밀리 (AR*)

명령설명
ARSET key index value인덱스에 값 저장
ARGET key index인덱스에서 값 읽기 (O(1))
ARGETRANGE key start stop범위 조회
ARMSET key index value [index value ...]다중 인덱스 일괄 저장
ARMGET key index [index ...]다중 인덱스 일괄 읽기
ARINSERT key index value인덱스에 삽입 (기존 이동)
ARDEL key index인덱스 값 삭제
ARDELRANGE key start stop범위 삭제
ARLEN key배열 끝 인덱스 + 1
ARCOUNT key비어있지 않은 요소 수
ARRING key size value링 버퍼에 삽입 (오래된 것 자동 제거)
ARGREP key pattern패턴 일치 요소 검색
ARLASTITEMS key count마지막 N개 요소 조회

링 버퍼 모드(ARRING) 는 실용적 사용 예가 명확하다. 최근 N개의 센서 측정값, 슬라이딩 윈도우 내 이벤트 로그, 순환 버퍼가 필요한 시계열 데이터에 바로 쓸 수 있다.

# 센서 슬롯 1000번에 최신 온도 저장
ARSET sensor:rack-A 1000 "24.5"

# 인덱스 직접 읽기
ARGET sensor:rack-A 1000
# "24.5"

# 링 버퍼: 최근 100개 이벤트만 유지
ARRING event:login 100 "user:42:2026-06-15T10:30:00Z"

어디에 쓰는가

Array가 기존 자료구조보다 명확히 유리한 경우:


레이트 리미터: INCREX 명령

레이트 리미터를 Redis로 구현할 때 기존 방법은 Lua 스크립트나 MULTI/EXEC 트랜잭션이었다. 여러 명령을 조합하는 구조라 원자성과 성능 사이에서 타협이 필요했다.

INCREX는 이 용도를 위한 단일 원자 명령이다.

INCREX — 원자적 window counter 레이트 리미터 API 요청 user:42 INCREX INCREX rate:user:42 1 MAX 100 EX 60 단일 원자 연산: INCR + 한도 + TTL Redis Counter 현재 값: 83 / 100 TTL: 47초 남음 허용 (84 ≤ 100) 현재 값 반환, 요청 처리 거부 (100 초과 시) ERR 반환 + 남은 TTL 기존 방법 vs INCREX 기존: INCR + EXPIRE (2 RTT, 원자성 없음) 또는 MULTI/EXEC + Lua 스크립트로 원자성 확보 INCREX: 단일 명령, 1 RTT, 완전 원자적 음수 증분(DECR 효과), float 지원, 하한/상한 모두 설정 가능
INCREX 동작 흐름 — window counter 레이트 리미터

INCREX 시그니처

INCREX key increment [MAX max-val] [MIN min-val] [EX seconds | PX ms | EXAT timestamp | PXAT ms-timestamp | KEEPTTL] [GET]

TTL 60초 윈도우에서 최대 100회 허용하는 고정 윈도우 레이트 리미터를 단 한 줄로 구현한다.


Streams NACK: XNACK 명령

Redis Streams의 소비자 그룹(Consumer Group)은 메시지를 처리한 뒤 XACK으로 확인하거나, 처리하지 못하면 PEL(Pending Entry List)에 남긴다. Redis 8.8 이전에는 명시적 거부(NACK) 방법이 없었다.

문제: 처리할 수 없는 메시지(poison message)를 소비자가 받았을 때, XACK으로 삭제하거나 PEL에 그냥 방치하는 것 외에 선택지가 없었다. 다른 소비자가 빠르게 재처리하도록 하려면 PEL을 수동으로 조작해야 했다.

XNACK: 소비자가 메시지를 명시적으로 거부(NACK)하면 즉시 다른 소비자가 처리할 수 있도록 PEL 앞쪽(head)으로 이동시킨다.

ACK 흐름 (기존)
Stream
메시지 생산
Consumer A
XREADGROUP
처리 성공
XACK
PEL에서 제거
완료
NACK 흐름 (Redis 8.8 신규)
Stream
메시지 생산
Consumer A
XREADGROUP
처리 불가
XNACK
PEL head로
우선 이동
Consumer B가
즉시 재처리
XNACK 메시지 처리 흐름

PEL 내 우선순위 규칙

XNACK된 메시지는 PEL head(맨 앞)에 FIFO 순서로 배치된다. PEL 내 순서:

  1. NACK된 메시지들 (head, FIFO 순)
  2. ACK도 NACK도 되지 않은 일반 pending 메시지 (기존 순서 유지)
# XNACK 사용 예
XNACK mystream mygroup consumer-A msg-id-1234

# XPENDING으로 PEL 상태 확인
XPENDING mystream mygroup - + 10

이 메커니즘은 DLQ(Dead Letter Queue)와 구분된다. XNACK은 재처리 우선순위 제어이고, DLQ 패턴은 별도로 구현해야 한다. 메시지를 완전히 포기하려면 여전히 XACK 후 DLQ로 이동시키는 별도 로직이 필요하다.


성능 변화: 60% 빠른 복제, 83% 처리량 향상

두 수치 모두 실제 운영에 영향을 주는 영역이다.

동기 복제(Full Synchronization) 60% 빠름

Full sync는 Primary가 Replica에게 전체 데이터셋을 전송하는 과정이다. 발생하는 경우:

이 과정이 느리면:

Redis 8.8의 Full Sync 개선은 이 시간을 60% 단축한다. 구체적 메커니즘은 복제 스트림의 데이터 직렬화 방식과 전송 효율 개선이다.

핵심 명령 처리량 83% 향상

Redis 8.8 성능 개선 블로그에서 MGET, MSET, Streams 관련 명령, SCAN 등 주요 명령에서 최대 83% 처리량 향상을 측정했다.

명령 유형개선 방향
MGET / MSET다중 키 배치 처리 최적화
Streams (XADD, XREAD)내부 직렬화 경로 개선
SCAN키 공간 순회 효율 향상
문자열 명령인코딩 경로 단축

이 수치는 최적 조건(다중 코어, I/O 스레딩 활성화)에서 측정된 것이다. 단일 코어 환경이나 I/O 스레딩이 비활성화된 경우 개선 폭이 다를 수 있다.


추가 변경 사항

Redis 8.8이 함께 가져온 작은 변화들:

Hash 서브키 알림(Subkey Notifications)

기존 keyspace notification은 키 전체 단위로 이벤트를 발행했다. Redis 8.8부터 Hash의 특정 필드(서브키) 변경만 구독할 수 있다.

# 특정 Hash 필드 변경 알림 구독
SUBSCRIBE __keyevent@0__:hset:user:42:email

사용자 프로필 Hash에서 이메일 필드만 변경됐을 때 알림을 받아 관련 캐시를 무효화하는 패턴이 가능해진다.

Time Series 쿼리 개선

단일 TS.RANGE / TS.MRANGE 쿼리에서 여러 집계 함수를 동시에 요청할 수 있다. 기존에는 집계 함수 하나당 쿼리 하나가 필요했다.

Sorted Set UNION/INTERSECT COUNT

ZUNIONSTORE, ZINTERSTORE에 COUNT 집계 옵션이 추가됐다. 결과 키를 별도로 저장하지 않고 교집합/합집합의 원소 수만 반환받을 수 있다.


업그레이드와 호환성

Redis 8.0 → 8.8

마이너 버전 업그레이드다. 주요 Breaking Change는 없다. 새 명령(INCREX, XNACK, AR* 패밀리)은 추가 사항이므로 기존 코드에 영향 없다.

Redis 7.x → 8.8

Redis 8.0 변경 사항(I/O 스레딩 설정, 모듈 통합 방식 변화)을 먼저 확인해야 한다. 일부 모듈 기반 기능(RedisJSON, RedisTimeSeries 등)이 8.x에서 기본 통합됐으므로 별도 모듈 로드 설정이 필요 없어졌다. 오히려 기존 loadmodule 설정이 충돌할 수 있어 정리가 필요하다.

Valkey와의 관계

Redis 8.8은 Redis Ltd.가 관리하는 오픈소스다. Valkey는 Linux Foundation 산하 커뮤니티 포크다. 두 프로젝트는 명령 수준 호환성을 유지하고 있지만 내부 구현과 기능 추가 방향이 다르다. 운영 환경에서 Redis 8.8을 선택했다면 Valkey 마이그레이션은 별도 검토가 필요한 결정이다.


운영자 도입 체크리스트

Array 도입 전 확인
List로 충분한지 먼저 확인
Array는 인덱스 직접 접근이 필요할 때만 도입
희소도(sparsity) 파악
인덱스 간격이 크면 메모리 절약 효과 확인
클라이언트 라이브러리 버전 확인
AR* 명령 지원 여부 (redis-py, go-redis 최신 버전 필요)
INCREX 도입 전 확인
고정 윈도우 vs 슬라이딩 윈도우
INCREX는 고정 윈도우 카운터. 슬라이딩 윈도우는 별도 로직 필요
TTL 갱신 방지
기존 키에 EX 옵션 주면 TTL 갱신 없음. KEEPTTL 기본값 확인
XNACK 도입 전 확인
DLQ 정책과 구분
XNACK은 재처리 우선순위 제어. 최종 폐기는 XACK + DLQ 별도 구현
재처리 루프 주의
처리 불가 메시지를 XNACK만 반복하면 무한 루프 발생 가능
복제 성능 개선 활용
Full Sync 60% 개선은 Replica 추가 시 자동 적용된다. 별도 설정 없음.
대규모 데이터셋에서 Replica 추가 시 Primary 메모리 스파이크 모니터링은 계속 필요.
I/O 스레딩(io-threads 설정) 활성화 여부가 처리량 83% 개선의 전제다.
Redis 8.8 도입 체크리스트

이 릴리스를 한 문장으로 요약하면

Redis 8.8은 구조적 추가(Array)와 운영 편의 명령(INCREX, XNACK), 그리고 실측 가능한 성능 개선(복제 60%, 처리량 83%)을 한 번에 가져온 릴리스다.

대규모 레이트 리미터를 Lua 스크립트로 구현해왔다면 INCREX로 교체할 이유가 충분하다. Streams 기반 메시지 파이프라인에서 poison message 처리에 머리를 썼다면 XNACK이 그 복잡도를 줄여준다. Array는 기존 패턴이 List로도 충분했던 경우엔 도입 필요성이 낮지만, 고정 인덱스 기반 희소 데이터가 있다면 살펴볼 가치가 있다.

References