TTL·파이프라이닝·트랜잭션 — Redis 명령어

2026-05-02AWS SAA-C03 스터디

Redis 핵심 정리 시리즈 3편. TTL 만료·SCAN 안전 탐색·MULTI/EXEC 트랜잭션·낙관적 잠금·파이프라이닝·SORT 외부 키 정렬·Lua 스크립트까지 — 운영 명령어를 유통 기한·책장 순서·주문 묶음 비유로 풀어가며 처음 보는 사람도 따라올 수 있게 친절하게 정리한 글.

📚 Redis 핵심 정리 · 3편 / 14편 — Redis 명령어

이 글은 Redis 핵심 정리 시리즈의 세 번째 편입니다. 2편에서 7가지 데이터 구조의 자리를 잡았으니, 이번에는 그 위에서 도는 운영 명령어들을 풀어 갈 차례예요. TTL·SCAN·트랜잭션·파이프라이닝·SORT·Lua — 이 여섯 가지가 Redis를 실제 시스템에서 안전하고 빠르게 돌리는 도구입니다.

명령어 심화는 면접·시험에서 가장 자주 나오는 영역이에요. 데이터 구조는 외우면 끝인데, 명령어는 언제 쓰면 안 되는지를 알아야 진짜 운영에서 사고를 안 냅니다. 이번 편의 핵심은 그 안전선이에요.

왜 명령어 단원이 처음엔 어렵게 느껴질까요

이유는 세 가지예요.

첫째, 이름이 비슷한 명령어가 너무 많아요. KEYS·SCAN·HSCAN·SSCAN·ZSCAN 같이 접두사만 다른 명령어들이 줄지어 나옵니다. 게다가 EXPIRE·PEXPIRE·EXPIREAT·PEXPIREAT — 비슷하면서 단위만 다른 친구들이 또 있어요.

둘째, 트랜잭션이 SQL과 다른 듯 비슷합니다. MULTI·EXEC·DISCARD·WATCH 같은 단어를 보면 SQL 트랜잭션이 떠오르는데, 롤백이 없다는 결정적 차이가 있어요. 이걸 모르면 운영에서 데이터 일관성이 깨지는 사고가 납니다.

셋째, 파이프라이닝과 트랜잭션이 헷갈려요. "여러 명령을 한 번에 보낸다"는 면에서 비슷한데 보장하는 게 달라요. 이 차이가 면접 단골 질문입니다.

해결법은 한 가지예요. 명령어를 일상 비유로 한 번씩 잡고 가는 겁니다. TTL은 봉투에 적힌 유통 기한, SCAN은 책장을 한 칸씩 천천히 살피기, 파이프라이닝은 주문을 묶어서 한 번에 보내기, 트랜잭션은 묶음 처리 — 이 비유가 잡히면 명령어 한도와 안전선이 자연스럽게 보여요.

모든 데이터 타입에 통하는 공통 명령어

먼저 데이터 구조와 무관하게 모든 키에 쓸 수 있는 공통 명령어들을 정리합니다.

키 관리 — DEL·EXISTS·RENAME·TYPE

# 삭제
DEL key                    # 단일 키
DEL key1 key2 key3         # 여러 키 한 번에

# 존재 확인
EXISTS key                 # 1(있음) / 0(없음)
EXISTS key1 key2           # 존재하는 키 개수 반환

# 이름 변경
RENAME oldkey newkey       # 그냥 변경
RENAMENX oldkey newkey     # newkey가 없을 때만 (덮어쓰기 방지)

# 데이터 타입 확인
TYPE key                   # string·list·set·zset·hash·stream

# 총 키 개수
DBSIZE

RENAMENXNX 접미사 — Redis 곳곳에서 보이는 패턴이에요. "None eXists" — 없을 때만이라는 약속입니다. 같은 패턴이 SET ... NX·ZADD NX·HSETNX에서도 반복돼요.

데이터베이스 관리 — FLUSHDB·INFO·PING

# 위험 명령어 — 운영 환경 절대 금지
FLUSHDB    # 현재 DB의 모든 데이터 삭제
FLUSHALL   # 모든 DB의 모든 데이터 삭제

# 서버 정보
INFO              # 전체
INFO server       # 서버 정보
INFO memory       # 메모리 사용량
INFO clients      # 클라이언트 연결
INFO stats        # 통계
INFO persistence  # 영속성 상태 (4편에서 자세히)

# 연결 테스트
PING              # PONG
PING "hello"      # "hello"

여기서 시험 함정이 하나 있어요. FLUSHDB·FLUSHALL은 운영에서 절대 금지예요. 한 번 실행하면 회복이 거의 불가능합니다. 운영 환경에서는 rename-command FLUSHALL "" 같은 설정으로 명령어 자체를 꺼 두는 게 안전해요.

TTL — 봉투에 적힌 유통 기한

운영 명령어 중 가장 자주 등장하는 게 TTL(Time To Live) 예요. 봉투 위에 적힌 유통 기한 같은 거예요. 정해진 시간이 지나면 Redis가 알아서 봉투를 버립니다.

회사 비유로 — 사물함 안 봉투에 "이 자료는 1시간 후 폐기"라는 라벨을 붙이는 거예요. 한 시간이 지나면 자동으로 버려져 사물함이 깨끗하게 유지됩니다. 메모리 기반 시스템이라 이 자동 정리가 정말 중요해요.

TTL 설정·조회

# 만료 시간 설정
EXPIRE key 60               # 60초 후 만료
PEXPIRE key 60000           # 60000ms(60초) 후 만료
EXPIREAT key 1700000000     # Unix 타임스탬프
PEXPIREAT key 1700000000000 # 밀리초 Unix 타임스탬프

# TTL 조회
TTL key      # 남은 초 (-1=만료없음, -2=키없음)
PTTL key     # 남은 밀리초

# 만료 취소 (영구화)
PERSIST key

# 저장과 동시에 TTL 설정
SET cache:data "value" EX 3600        # 1시간
SET cache:data "value" PX 3600000     # 1시간(밀리초)
SET cache:data "value" EXAT 1700000000  # 특정 시점
SET cache:data "value" KEEPTTL        # 기존 TTL 유지하며 값만 변경

Redis 7.0+ 새 옵션 — NX·XX·GT·LT

Redis 7.0부터 EXPIRE에 조건부 옵션이 추가됐어요.

EXPIRE key 60 NX   # TTL이 없을 때만 설정
EXPIRE key 60 XX   # TTL이 있을 때만 설정
EXPIRE key 60 GT   # 현재 TTL보다 클 때만 (만료 늦춤만 가능)
EXPIRE key 60 LT   # 현재 TTL보다 작을 때만 (만료 앞당김만 가능)

GT·LT가 흥미로운 옵션이에요. 세션 갱신 시 TTL을 항상 더 늦추는 흐름은 GT 옵션 한 줄이면 깔끔하게 처리됩니다.

TTL의 흔한 실수 — GET은 TTL을 갱신 안 한다

여기서 정말 중요한 시험 함정 — GET을 호출해도 TTL이 갱신되지 않습니다. 세션 활동을 감지해 만료를 미루고 싶으면 GETEX로 명시 갱신해야 해요.

SET session "data" EX 3600
GET session            # TTL 변화 없음 (그대로 카운트다운)
GETEX session EX 3600  # 조회 + TTL 리셋 (활동 감지 패턴)

TTL이 필수인 자리

  • 세션 데이터 — 일정 시간 무활동 후 자동 로그아웃
  • OTP·인증 코드 — 5분 후 자동 만료
  • API 응답 캐시 — 짧게는 수 초, 길게는 1시간
  • 분산 락 — 락이 풀리지 않고 영원히 잠기는 상황 방지
  • 레이트 리밋 카운터 — 1분 윈도 카운터

TTL 없이 무한정 쌓는 임시 데이터는 메모리 고갈로 서비스를 죽이는 가장 흔한 사고 원인이에요. 임시성이 있는 모든 키에는 반드시 TTL을 박는 게 원칙입니다. 더 자세한 명령 레퍼런스는 Redis 명령어 문서에서 확인할 수 있어요.

한 줄 정리 — TTL = 자동 청소부. 임시 데이터에는 반드시 TTL을 붙인다.

SCAN — 책장을 한 칸씩 살피는 안전한 탐색

운영에서 가장 자주 발생하는 사고 한 가지 — **KEYS * 한 줄로 서비스 전체를 멈추는 일**이에요. Redis는 단일 스레드라 KEYS *가 도는 동안 다른 모든 요청이 블로킹돼요. 100만 개 키가 있으면 그 동안 어떤 요청도 못 받습니다.

대안이 SCAN이에요. 커서 기반 페이지네이션으로 책장을 한 칸씩 천천히 살피는 방식입니다. 한 번에 100개씩 보다가 다음 커서로 넘어가는 흐름이에요. 한 번에 다 보는 건 아니지만 서비스를 멈추지 않아요.

SCAN 기본 사용

# 커서 기반 탐색 (0으로 시작)
SCAN 0                         # 커서 0부터
# 반환: [다음커서, 키목록]
# 다음커서가 0이면 완료

SCAN 0 COUNT 100               # 한 번에 100개 힌트
SCAN 0 MATCH "user:*"          # 패턴 매칭
SCAN 0 MATCH "user:*" COUNT 100
SCAN 0 TYPE hash               # 특정 타입만 탐색

TypeScript 구현

// 안전한 키 탐색 패턴
let cursor = 0;
const allKeys: string[] = [];

do {
    const [nextCursor, keys] = await client.scan(cursor, { 
        MATCH: 'user:*', 
        COUNT: 100 
    });
    allKeys.push(...keys);
    cursor = parseInt(nextCursor);
} while (cursor !== 0);

console.log(`총 ${allKeys.length}개 키 탐색 완료`);

여기서 시험 함정이 하나 있어요. SCAN의 COUNT정확한 개수가 아니라 힌트입니다. 50개를 달라고 해도 30개나 80개가 올 수 있어요. 또 한 가지 — SCAN이 도는 동안 키가 추가/삭제되면 같은 키가 여러 번 보이거나 누락될 수 있어요. 멱등 처리 가능한 작업에서만 안전합니다.

HSCAN·SSCAN·ZSCAN — 자료 구조 안 탐색

큰 Hash·Set·Sorted Set 안을 탐색할 때도 같은 패턴이 있어요.

# Hash 필드 탐색
HSCAN user:1 0
HSCAN user:1 0 MATCH "email*" COUNT 10

# Set 멤버 탐색
SSCAN myset 0

# Sorted Set 멤버 탐색
ZSCAN zset 0
ZSCAN zset 0 WITHSCORES

HGETALL·SMEMBERS·SMEMBERS는 한 번에 다 가져와서 큰 데이터에서는 블로킹 위험이 있어요. 큰 자료 구조에서는 ***SCAN 패밀리**로 페이지 단위 탐색이 안전합니다.

한 줄 정리 — 운영의 절대 원칙: KEYS 금지, SCAN 사용.

트랜잭션 — MULTI/EXEC 묶음

여러 명령을 하나의 묶음으로 처리하고 싶을 때 쓰는 게 트랜잭션이에요. Redis의 트랜잭션 모델은 SQL과 비슷해 보이지만 결정적인 차이가 있어요. 이 차이를 이해하는 게 시험·면접 핵심입니다.

회사 비유로 — MULTI는 "이제 묶음 처리 시작합니다"고 알리고, 사이에 명령어를 쌓아 두고, EXEC로 한꺼번에 처리하는 흐름이에요.

기본 트랜잭션

MULTI                  # 트랜잭션 시작
SET key1 "value1"
SET key2 "value2"
INCR counter
EXEC                   # 한꺼번에 실행

# 트랜잭션 취소
MULTI
SET key1 "value1"
DISCARD                # 취소 (EXEC 전에만 가능)

MULTIEXEC 사이의 명령어들은 원자적으로 실행돼요. 중간에 다른 클라이언트의 명령이 끼어들지 않습니다.

Redis 트랜잭션의 특징과 한계

MULTI/EXEC 특징:

원자성 — 중간에 다른 클라이언트 간섭 없음
명령어 큐잉 — EXEC 시점에 일괄 실행
문법 오류 — 전체 취소

중요한 한계 —
런타임 오류 시 해당 명령만 실패 (나머지는 실행됨)
롤백 없음 (원자성은 보장하지만 일관성은 개발자가 관리)
트랜잭션 내에서 조건부 로직 불가

부분 실패 함정

여기서 정말 중요한 시험 함정 — Redis 트랜잭션은 롤백이 없습니다.

MULTI
SET key1 "value"
INCR key1           # 타입 에러 (key1은 문자열)
SET key2 "value2"
EXEC
# 결과: key1은 설정됨, INCR은 실패, key2는 설정됨
# → 일관성 깨질 가능성 — 개발자가 직접 관리해야 함

문법 오류(틀린 명령어 이름)는 전체가 취소되지만, 런타임 오류(잘못된 타입 연산 등)는 실패한 명령만 건너뛰고 나머지는 실행돼요. SQL 트랜잭션의 ACID와 다른 모델입니다.

WATCH로 낙관적 잠금

여러 클라이언트가 동시에 같은 키를 수정하려는 상황을 안전하게 처리하려면 WATCH 를 씁니다. 낙관적 잠금(Optimistic Locking) 패턴이에요.

WATCH key1          # key1 감시 시작
GET key1            # 현재 값 읽기
MULTI               # 트랜잭션 시작
SET key1 "newvalue" # 변경
EXEC                # 실행 (WATCH 이후 key1이 변경되었으면 nil 반환)

흐름은 이래요.

  1. WATCH로 키를 감시 시작
  2. 키를 읽고 비즈니스 로직 처리
  3. MULTI로 트랜잭션 시작
  4. 변경 명령어 큐잉
  5. EXEC 실행 — 만약 그 사이 다른 클라이언트가 같은 키를 변경했으면 nil 반환 → 재시도

TypeScript에서 WATCH/MULTI/EXEC

async function transferWithWatch(
    fromKey: string, 
    toKey: string, 
    amount: number
) {
    const MAX_RETRIES = 10;
    
    for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
        // 감시 시작
        await client.watch([fromKey, toKey]);
        
        const fromBalance = parseInt(await client.get(fromKey) || '0');
        const toBalance = parseInt(await client.get(toKey) || '0');
        
        if (fromBalance < amount) {
            await client.unwatch();
            throw new Error('잔액 부족');
        }
        
        // 트랜잭션
        const multi = client.multi();
        multi.set(fromKey, fromBalance - amount);
        multi.set(toKey, toBalance + amount);
        
        const results = await multi.exec();
        
        if (results === null) {
            // WATCH된 키가 변경됨 → 재시도
            continue;
        }
        
        return results;
    }
    
    throw new Error('트랜잭션 재시도 한계 초과');
}

자세한 트랜잭션 동작은 Redis 트랜잭션 공식 문서에서 확인할 수 있어요. 한 줄 정리 — MULTI/EXEC = 원자적 묶음, 롤백 없음, 동시성은 WATCH로.

파이프라이닝 — 주문을 묶어 한 번에 보내기

파이프라이닝(Pipelining) 은 여러 명령어를 한 번의 네트워크 요청으로 묶어 전송하는 기법이에요. 트랜잭션과 닮았지만 원자성을 보장하지는 않아요.

회사 비유로 — 카페에서 주문할 때 메뉴를 한 줄씩 따로 주문하는 게 아니라 종이 한 장에 다 적어 한 번에 건네는 거예요. 왔다 갔다 하는 시간이 사라지죠.

왜 파이프라이닝이 필요한가

명령어 1000개를 보낼 때 각각 따로 보내면 네트워크 왕복(RTT) 1000번이 발생해요. 한 RTT가 1ms만 돼도 그것만 1초입니다. 파이프라이닝은 이 1000개를 한 번에 묶어 보내 RTT를 1번으로 줄여요.

node-redis에서 파이프라이닝

// Promise.all로 여러 명령어 동시 실행
const [result1, result2, result3] = await Promise.all([
    client.set('key1', 'value1'),
    client.set('key2', 'value2'),
    client.incr('counter')
]);

// 입찰 시스템 예시 — 여러 업데이트 동시 처리
async function createBid(itemId: string, bidData: BidData) {
    const [pushResult, setResult] = await Promise.all([
        // 입찰 내역 리스트에 추가
        client.rPush(itemBidsKey(itemId), JSON.stringify(bidData)),
        // 아이템 해시 업데이트
        client.hSet(itemsKey(itemId), {
            bids: bidData.bids + 1,
            price: bidData.amount,
            highestBidUserId: bidData.userId
        })
    ]);
    return { pushResult, setResult };
}

파이프라이닝 vs 트랜잭션 vs Promise.all

세 패턴이 비슷해 보여서 헷갈리기 쉬워요. 차이를 비교표로 정리합니다.

구분파이프라이닝MULTI/EXECPromise.all
원자성없음있음없음
네트워크 효율매우 좋음좋음좋음
순서 보장보장보장보장 안 됨
중간 결과 사용불가불가가능
구현 복잡도낮음중간낮음

여기서 시험 함정이 하나 있어요. "파이프라이닝 = 원자성 있다" 는 가장 흔한 오답이에요. 파이프라이닝은 네트워크 효율만 챙기는 도구입니다. 원자성이 필요하면 MULTI/EXEC를 써야 해요. 둘은 다른 도구예요.

한 줄 정리 — 파이프라이닝 = RTT 절감, 트랜잭션 = 원자성. 자리를 헷갈리지 말 것.

SORT — 외부 키 기준으로 정렬·조인

SORT 는 의외로 강력한데 잘 안 알려진 명령어예요. 단순히 List·Set·ZSet의 원소를 정렬하는 게 아니라, 외부 키의 값을 기준으로 정렬하거나 데이터를 조회하는 미니 SQL JOIN 같은 동작을 합니다.

기본 SORT

# 기본 정렬 (숫자 오름차순)
SORT mylist

# 알파벳 정렬
SORT mylist ALPHA

# 내림차순
SORT mylist DESC

# 결과 제한
SORT mylist LIMIT 0 5  # offset=0, count=5

# 결과 저장
SORT mylist STORE result

BY 옵션 — 외부 키 기준 정렬

진짜 강력한 활용은 BY 옵션이에요. 다른 키의 값을 기준으로 정렬할 수 있어요.

# books:likes ZSet의 멤버를 각 책의 year 필드 기준으로 정렬
SORT books:likes BY books:*->year

# 단계별 동작:
# 1. books:likes에서 멤버 추출: good, bad, ok
# 2. 각 멤버로 books:good->year, books:bad->year, books:ok->year 조회
# 3. year 값으로 멤버 정렬
# 4. 정렬된 멤버만 반환

GET 옵션 — 외부 키 데이터 조회 (조인 같은 동작)

GET 옵션을 더하면 정렬 후 외부 키의 데이터를 같이 가져올 수 있어요. SQL의 JOIN 같은 패턴이에요.

# 정렬 후 각 책의 제목 반환
SORT books:likes BY books:*->year GET books:*->title

# 제목 + 연도 함께
SORT books:likes BY books:*->year GET books:*->title GET books:*->year

# 원본 멤버(#) + 제목 + 연도
SORT books:likes BY books:*->year GET # GET books:*->title GET books:*->year

# 정렬 없이 데이터만 조인 (BY nosort = 정렬 생략)
SORT books:likes BY nosort GET # GET books:*->title GET books:*->year

여기서 시험 함정이 하나 있어요. BY nosort는 정렬을 끄고 외부 키 조회만 사용하는 패턴인데, 서버 측 미니 JOIN으로 자주 활용됩니다. 클라이언트에서 ID 목록 받고 다시 N번 조회하는 N+1 패턴을 한 번에 해결해 줘요.

한 줄 정리 — SORT는 미니 JOIN — BY nosort GET으로 N+1 방지.

Lua 스크립트 — 서버에서 직접 도는 미니 스크립트

여러 명령어를 한 묶음으로 처리하면서 중간 결과를 사용한 조건부 로직까지 필요할 때 쓰는 게 Lua 스크립트예요. 트랜잭션은 조건부 로직을 못 쓰는데, Lua는 그게 됩니다.

회사 비유로 — Redis 서버 안에서 직접 도는 미니 봇이에요. "X를 읽어서 Y면 Z를 한다" 같은 흐름을 Redis 서버에서 한 번에 처리해 클라이언트와의 RTT를 0으로 만들죠.

EVAL·EVALSHA

# 스크립트 직접 실행
EVAL "return redis.call('GET', KEYS[1])" 1 mykey

# 스크립트 미리 등록
SCRIPT LOAD "return redis.call('GET', KEYS[1])"
# 반환: 스크립트 SHA1 해시

# SHA1로 호출 (네트워크 효율)
EVALSHA <sha1> 1 mykey

활용 자리

  • 원자적 조건부 업데이트 — 재고 확인 후 차감을 한 번에
  • 레이트 리밋 — 카운터 증가 + 한도 체크 + TTL 설정을 한 번에
  • 분산 락SET NX EX + 안전한 해제를 한 번에

여기서 시험 함정이 하나 있어요. Lua 스크립트는 Redis가 단일 스레드로 실행하기 때문에 스크립트가 도는 동안 다른 모든 요청이 블로킹돼요. 무거운 연산이나 긴 루프는 절대 금지입니다. 짧고 단순한 묶음만.

자세한 Lua 스크립트 패턴은 8편(Spring Data Redis)과 9편(성능 최적화)에서 더 풀어 갈게요.

운영에서 자주 틀리는 함정 4가지

1. KEYS * 절대 금지

# 운영 환경에서 절대 금지
KEYS *   # 단일 스레드 블로킹 → 서비스 장애

# 대신 SCAN
let cursor = 0;
do {
    const [nextCursor, keys] = await client.scan(cursor, { 
        MATCH: 'user:*', 
        COUNT: 100 
    });
    cursor = parseInt(nextCursor);
} while (cursor !== 0);

2. 트랜잭션 부분 실패

MULTI
SET key1 "value"
INCR key1           # 타입 에러
SET key2 "value2"
EXEC
# key1 설정됨, INCR 실패, key2 설정됨 — 롤백 없음

3. GET은 TTL 갱신 안 함

SET session "data" EX 3600
GET session            # TTL 변화 없음
GETEX session EX 3600  # 활동 감지 패턴

4. O(N) 명령어 주의

대용량 데이터에서 O(N) 명령어는 블로킹의 주범이에요.

SMEMBERS large_set     # 수백만 멤버 → 블로킹
HGETALL large_hash     # 수만 필드 → 블로킹
LRANGE large_list 0 -1 # 수백만 항목 → 블로킹

# 대신 SCAN 패밀리
SSCAN large_set 0 COUNT 100
HSCAN large_hash 0 COUNT 100

운영 모니터링은 SLOWLOG로 잡아요. 느린 명령어가 어떤 패턴으로 들어오는지 가시화하는 첫 단추예요.

SLOWLOG GET             # 느린 명령어 목록
SLOWLOG GET 10          # 최근 10개
SLOWLOG LEN             # 총 개수
SLOWLOG RESET           # 초기화

시험 직전 한 번 더 — 자주 헷갈리는 함정 모음

여기까지가 Redis 3편의 핵심입니다. 시험·면접 직전 압축 노트로 마무리할게요.

  • TTL 단위EX(초) / PX(밀리초) / EXAT(Unix초) / PXAT(Unix밀리초)
  • TTL 조회 — TTL(초) / PTTL(밀리초). 반환 -1=만료없음, -2=키없음
  • PERSIST — TTL 제거(영구화)
  • Redis 7.0+ EXPIRE 옵션 — NX·XX·GT(클 때만)·LT(작을 때만)
  • GET은 TTL 갱신 안 함 — 활동 감지에는 GETEX
  • **KEYS * 운영 절대 금지** — 단일 스레드 블로킹 → 서비스 장애
  • 대안은 SCAN — 커서 기반 페이지 탐색, COUNT는 힌트
  • 큰 자료 구조 탐색 — HSCAN·SSCAN·ZSCAN 패밀리
  • MULTI/EXEC 원자성 OK, 롤백 X — SQL과 다른 결정적 차이
  • 트랜잭션 부분 실패 — 문법 오류는 전체 취소, 런타임 오류는 해당 명령만 실패
  • WATCH — 낙관적 잠금. EXEC 시 변경됐으면 nil → 재시도
  • 파이프라이닝 ≠ 트랜잭션 — 파이프라이닝은 RTT 절감만, 원자성 X
  • 파이프라이닝 vs MULTI/EXEC vs Promise.all — 원자성·순서·중간결과 비교
  • **SORT BY ->field GET ->field** — 서버 측 미니 JOIN. N+1 방지
  • SORT BY nosort GET — 정렬 끄고 조인만
  • Lua는 단일 스레드 블로킹 — 짧고 단순한 묶음만
  • SET NX EX — 분산 락 패턴 한 줄
  • RENAMENX — 덮어쓰기 방지 이름 변경
  • FLUSHDB·FLUSHALL 운영 절대 금지 — 회복 불가
  • 운영 모니터링 — SLOWLOG로 느린 명령 가시화
  • O(N) 명령어 — SMEMBERS·HGETALL·LRANGE 0 -1 큰 데이터 시 위험
  • MSET·MGET — 여러 키 한 번에 (RTT 절감)

시리즈 다른 편

같은 시리즈의 다른 글들도 같은 친절 톤으로 묶어 정리되어 있어요.

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

답글 남기기

error: Content is protected !!