Redis 자료구조와 명령어
개요
Redis는 단순한 키-값 저장소가 아니라 다양한 자료구조를 네이티브로 지원한다. 각 자료구조는 특정 문제에 최적화된 명령어를 제공하며, 올바른 자료구조를 선택하는 것이 성능의 핵심이다.
| 자료구조 | 특징 | 주요 사용 사례 |
|---|---|---|
| String | 범용 바이너리 안전 값 | 캐시, 카운터, 세션 |
| List | 순서 있는 연결 리스트 | 메시지 큐, 최근 항목 |
| Set | 중복 없는 집합 | 태그, 친구 목록, 좋아요 |
| Sorted Set | 점수 기반 정렬 집합 | 리더보드, 타임라인 |
| Hash | 필드-값 맵 | 객체 저장 |
| Bitmap | 비트 배열 | 출석체크, 플래그 |
| HyperLogLog | 확률적 유니크 카운터 | UV 집계 |
| Stream | 메시지 스트림 | 이벤트 로그, 이벤트 소싱 |
| Geospatial | 위치 좌표 인덱스 | 근처 매장 검색 |
String
Redis에서 가장 기본적인 자료구조다. 텍스트, 정수, 부동소수점, 직렬화된 객체, 바이너리 데이터 등 최대 512MB까지 저장 가능하다.
주요 명령어
# 기본 저장/조회
SET key value
GET key
DEL key
# 조건부 저장
SETNX key value # 키가 없을 때만 설정 (SET NX)
SET key value NX # 동일한 동작
SET key value XX # 키가 있을 때만 설정
# TTL과 함께 저장
SETEX key seconds value # TTL(초) 설정
PSETEX key millis value # TTL(밀리초) 설정
SET key value EX 60 # 동일한 동작
SET key value PX 60000
# 복수 키 처리
MSET key1 val1 key2 val2 key3 val3
MGET key1 key2 key3 # 여러 값 한번에 조회
# 숫자 연산
INCR key # +1 (원자적)
DECR key # -1 (원자적)
INCRBY key 5 # +5
DECRBY key 3 # -3
INCRBYFLOAT key 1.5 # 부동소수점 증가
# 문자열 조작
APPEND key "suffix" # 값 뒤에 추가, 새 길이 반환
STRLEN key # 값의 바이트 길이
GETRANGE key 0 3 # 부분 문자열 (0-indexed)
SETRANGE key 6 "world" # 특정 위치부터 덮어쓰기
# 원자적 교환
GETSET key newvalue # 이전 값 반환하고 새 값 설정 (deprecated)
GETDEL key # 값 반환 후 삭제
GETEX key EX 60 # 값 반환 후 TTL 갱신
INCR이 원자적인 이유
# 이렇게 하면 race condition 발생
GET counter → 10
← 다른 클라이언트도 GET counter → 10
SET counter 11
← 다른 클라이언트 SET counter 11 # 둘 다 11, 하나 손실
# INCR은 Redis 싱글 스레드에서 하나의 명령어로 실행
INCR counter # GET + 증가 + SET을 원자적으로 처리
Redis는 싱글 스레드로 명령어를 순차 처리하므로, INCR은 실행 도중 다른 명령어가 끼어들 수 없다.
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| GET, SET, DEL | O(1) |
| MGET, MSET | O(N) |
| INCR, DECR | O(1) |
| APPEND | O(1) amortized |
| STRLEN | O(1) |
사용 사례
// 캐시
redisTemplate.opsForValue().set("user:" + id, json, 1, TimeUnit.HOURS);
// 카운터
redisTemplate.opsForValue().increment("page:view:" + pageId);
// 세션
redisTemplate.opsForValue().set("session:" + token, userId, 30, TimeUnit.MINUTES);
// 분산 락
Boolean acquired = redisTemplate.opsForValue()
.setIfAbsent("lock:" + resource, uuid, 30, TimeUnit.SECONDS);
List
순서가 있는 이중 연결 리스트다. 양쪽 끝에서의 삽입/삭제가 O(1)이며, 인덱스 접근은 O(N)이다. 최대 2^32 - 1개 원소를 저장할 수 있다.
주요 명령어
# 삽입
LPUSH key val1 val2 # 왼쪽(head)에 추가
RPUSH key val1 val2 # 오른쪽(tail)에 추가
LINSERT key BEFORE pivot val # 특정 값 앞에 삽입
LINSERT key AFTER pivot val # 특정 값 뒤에 삽입
# 조회
LRANGE key 0 -1 # 전체 조회 (-1 = 마지막)
LRANGE key 0 9 # 처음 10개
LINDEX key 0 # 특정 인덱스 조회
LLEN key # 리스트 길이
# 삭제
LPOP key # 왼쪽에서 꺼내기
RPOP key # 오른쪽에서 꺼내기
LPOP key 3 # 왼쪽에서 3개 꺼내기 (Redis 6.2+)
LREM key 2 "value" # "value" 2개 삭제 (음수면 오른쪽부터)
LTRIM key 0 99 # 처음 100개만 유지, 나머지 삭제
# 수정
LSET key index value # 특정 인덱스 값 변경
# 블로킹 팝 (큐 패턴에서 핵심)
BLPOP key1 key2 timeout # 값이 생길 때까지 대기
BRPOP key1 key2 timeout # 오른쪽 블로킹 팝
BLMOVE src dst LEFT RIGHT timeout # 블로킹 이동 (Redis 6.2+)
# 이동
LMOVE src dst LEFT RIGHT # 왼쪽에서 꺼내 오른쪽에 추가 (원자적)
RPOPLPUSH src dst # LMOVE의 이전 버전
메시지 큐 패턴
# 생산자 (오른쪽에 추가)
RPUSH queue:orders "{\"orderId\": 123}"
# 소비자 (왼쪽에서 꺼내기, 블로킹)
BLPOP queue:orders 0 # 0 = 무한 대기
// 생산자
redisTemplate.opsForList().rightPush("queue:orders", orderJson);
// 소비자 (스레드 블로킹)
List<String> result = redisTemplate.opsForList()
.leftPop("queue:orders", Duration.ofSeconds(30));
Reliable Queue 패턴 (처리 중 실패 대비):
# 큐에서 꺼내면서 처리 중 목록으로 이동 (원자적)
LMOVE queue:orders processing LEFT RIGHT
# 처리 완료 후 processing에서 삭제
LREM processing 1 "{\"orderId\": 123}"
# 장애 복구: processing에 남은 항목을 재처리
LRANGE processing 0 -1
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| LPUSH, RPUSH | O(1) |
| LPOP, RPOP | O(1) |
| LRANGE | O(S+N) |
| LINDEX | O(N) |
| LLEN | O(1) |
| LREM | O(N) |
Set
중복을 허용하지 않는 비정렬 집합이다. 집합 연산(합집합, 교집합, 차집합)을 지원하며, 최대 2^32 - 1개 원소를 저장할 수 있다.
주요 명령어
# 추가/삭제
SADD key member1 member2 # 추가 (이미 있으면 무시)
SREM key member1 member2 # 삭제
# 조회
SMEMBERS key # 전체 멤버 조회 (대용량 주의)
SCARD key # 원소 개수
SISMEMBER key member # 멤버 존재 여부 (0/1)
SMISMEMBER key m1 m2 # 여러 멤버 존재 여부 (Redis 6.2+)
SRANDMEMBER key 3 # 랜덤 3개 반환 (삭제 안 함)
SPOP key 3 # 랜덤 3개 꺼내기 (삭제)
# 집합 연산
SUNION key1 key2 # 합집합
SINTER key1 key2 # 교집합
SDIFF key1 key2 # 차집합 (key1 - key2)
# 집합 연산 결과 저장
SUNIONSTORE dest key1 key2
SINTERSTORE dest key1 key2
SDIFFSTORE dest key1 key2
# 이동
SMOVE src dst member # src에서 꺼내 dst에 추가 (원자적)
# 스캔 (대용량 안전 조회)
SSCAN key cursor [MATCH pattern] [COUNT count]
사용 사례
// 태그 관리
redisTemplate.opsForSet().add("article:1:tags", "java", "redis", "spring");
Set<String> tags = redisTemplate.opsForSet().members("article:1:tags");
// 좋아요 (중복 방지)
redisTemplate.opsForSet().add("post:1:likes", userId);
Long likeCount = redisTemplate.opsForSet().size("post:1:likes");
// 팔로워 목록의 교집합 (공통 팔로워)
Set<String> commonFollowers = redisTemplate.opsForSet()
.intersect("user:1:followers", "user:2:followers");
// 온라인 사용자 관리
redisTemplate.opsForSet().add("online:users", userId);
redisTemplate.opsForSet().remove("online:users", userId);
Boolean isOnline = redisTemplate.opsForSet().isMember("online:users", userId);
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| SADD, SREM | O(N) — N: 추가/삭제 개수 |
| SISMEMBER | O(1) |
| SMEMBERS | O(N) |
| SCARD | O(1) |
| SUNION, SINTER, SDIFF | O(N+M) |
Sorted Set (ZSet)
각 원소에 score(실수)를 부여하여 score 기준으로 정렬된 집합이다. 내부적으로 skip list와 hash table을 함께 사용한다.
주요 명령어
# 추가/수정
ZADD key score member # 추가 (이미 있으면 score 갱신)
ZADD key NX score member # 없을 때만 추가
ZADD key XX score member # 있을 때만 갱신
ZADD key GT score member # 기존 score보다 클 때만 갱신 (Redis 6.2+)
ZADD key LT score member # 기존 score보다 작을 때만 갱신
# 삭제
ZREM key member1 member2
ZREMRANGEBYRANK key 0 9 # 순위 범위로 삭제
ZREMRANGEBYSCORE key 0 100 # score 범위로 삭제
# score 조작
ZINCRBY key 10 member # score +10
ZSCORE key member # score 조회
# 순위 조회
ZRANK key member # 오름차순 순위 (0부터)
ZREVRANK key member # 내림차순 순위
# 범위 조회
ZRANGE key 0 -1 # score 오름차순 전체
ZRANGE key 0 -1 WITHSCORES # score 포함
ZRANGE key 0 -1 REV # 내림차순 (Redis 6.2+)
ZREVRANGE key 0 9 # score 내림차순 상위 10개
# score 범위 조회
ZRANGEBYSCORE key 0 100 # score 0~100 오름차순
ZRANGEBYSCORE key -inf +inf # 전체
ZREVRANGEBYSCORE key 100 0 # score 100~0 내림차순
ZRANGEBYLEX key "[a" "[z" # 사전순 범위 (score가 같을 때)
# 집계
ZCARD key # 원소 개수
ZCOUNT key 0 100 # score 범위 내 원소 수
# 집합 연산
ZUNIONSTORE dest 2 key1 key2
ZINTERSTORE dest 2 key1 key2
ZDIFFSTORE dest 2 key1 key2 # (Redis 6.2+)
# 팝
ZPOPMIN key 3 # score 최솟값 3개 꺼내기
ZPOPMAX key 3 # score 최댓값 3개 꺼내기
BZPOPMIN key timeout # 블로킹
# 스캔
ZSCAN key cursor [MATCH pattern] [COUNT count]
리더보드 구현
@Service
public class LeaderboardService {
private static final String KEY = "leaderboard:game";
// 점수 추가/갱신
public void addScore(String userId, double score) {
redisTemplate.opsForZSet().add(KEY, userId, score);
}
// 점수 증가
public Double incrementScore(String userId, double delta) {
return redisTemplate.opsForZSet().incrementScore(KEY, userId, delta);
}
// 상위 N명 조회
public Set<ZSetOperations.TypedTuple<String>> getTopN(int n) {
return redisTemplate.opsForZSet()
.reverseRangeWithScores(KEY, 0, n - 1);
}
// 내 순위 조회 (0-indexed → +1)
public Long getMyRank(String userId) {
Long rank = redisTemplate.opsForZSet().reverseRank(KEY, userId);
return rank != null ? rank + 1 : null;
}
// 내 점수 조회
public Double getMyScore(String userId) {
return redisTemplate.opsForZSet().score(KEY, userId);
}
}
타임라인 (시간 기반 정렬)
# score에 Unix timestamp 사용
ZADD timeline:feed 1714567890 "post:123"
ZADD timeline:feed 1714567950 "post:124"
# 최신 10개 조회
ZREVRANGE timeline:feed 0 9 WITHSCORES
# 특정 시간 범위 조회
ZRANGEBYSCORE timeline:feed 1714560000 1714599999
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| ZADD | O(log N) |
| ZREM | O(log N) |
| ZSCORE | O(1) |
| ZRANK | O(log N) |
| ZRANGE | O(log N + M) |
| ZCARD | O(1) |
| ZCOUNT | O(log N) |
Hash
필드-값 쌍의 맵이다. 객체를 JSON으로 직렬화해 String에 저장하는 것과 달리, 개별 필드에 접근할 수 있다. 최대 2^32 - 1개 필드를 저장할 수 있다.
주요 명령어
# 저장
HSET key field value # 단일 필드 설정
HSET key f1 v1 f2 v2 f3 v3 # 복수 필드 설정 (HMSET 대체)
HSETNX key field value # 필드가 없을 때만 설정
# 조회
HGET key field # 단일 필드 조회
HMGET key field1 field2 # 복수 필드 조회
HGETALL key # 모든 필드-값 조회
HKEYS key # 모든 필드명
HVALS key # 모든 값
HLEN key # 필드 개수
HEXISTS key field # 필드 존재 여부
# 삭제
HDEL key field1 field2
# 숫자 연산
HINCRBY key field 5 # 정수 증가
HINCRBYFLOAT key field 1.5 # 부동소수점 증가
# 스캔
HSCAN key cursor [MATCH pattern] [COUNT count]
객체 저장
// 사용자 객체 저장
Map<String, String> userMap = new HashMap<>();
userMap.put("name", "김철수");
userMap.put("email", "kim@example.com");
userMap.put("age", "30");
redisTemplate.opsForHash().putAll("user:1", userMap);
// 단일 필드 조회
String name = (String) redisTemplate.opsForHash().get("user:1", "name");
// 복수 필드 조회
List<Object> values = redisTemplate.opsForHash()
.multiGet("user:1", List.of("name", "email"));
// 전체 조회
Map<Object, Object> user = redisTemplate.opsForHash().entries("user:1");
// 필드 업데이트
redisTemplate.opsForHash().put("user:1", "age", "31");
// 숫자 필드 증가
redisTemplate.opsForHash().increment("user:1", "loginCount", 1);
String vs Hash 비교
| 방식 | String (JSON) | Hash |
|---|---|---|
| 저장 | SET user:1 {"name":"...","age":30} |
HSET user:1 name "..." age 30 |
| 단일 필드 조회 | 전체 역직렬화 필요 | HGET user:1 name |
| 부분 업데이트 | 전체 덮어쓰기 | HSET user:1 age 31 |
| 메모리 | 직렬화 오버헤드 | 필드 수가 적으면 ziplist로 최적화 |
소규모 Hash(기본값: 128필드, 64바이트 이하)는 내부적으로 ziplist를 사용해 메모리를 효율적으로 사용한다.
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| HSET, HGET | O(1) |
| HMGET | O(N) |
| HGETALL | O(N) |
| HDEL | O(N) |
| HLEN | O(1) |
Bitmap
String을 비트 배열로 해석한다. 최대 2^32비트(512MB)를 저장할 수 있으며, 대규모 불리언 데이터를 메모리 효율적으로 처리한다.
주요 명령어
# 비트 설정/조회
SETBIT key offset value # offset 위치에 0/1 설정
GETBIT key offset # offset 위치의 비트 조회
# 비트 카운트
BITCOUNT key # 1인 비트 개수
BITCOUNT key 0 3 # 바이트 범위 내 1 개수
# 비트 연산
BITOP AND dest key1 key2 # AND 연산 결과 저장
BITOP OR dest key1 key2 # OR 연산
BITOP XOR dest key1 key2 # XOR 연산
BITOP NOT dest key # NOT 연산
# 비트 위치 검색
BITPOS key 1 # 첫 번째 1의 위치
BITPOS key 0 # 첫 번째 0의 위치
BITPOS key 1 2 # 2번 바이트부터 검색
# 필드 단위 조작
BITFIELD key GET u8 0 # 0번 위치에서 8비트 부호없는 정수 읽기
BITFIELD key SET u8 0 100 # 설정
BITFIELD key INCRBY u8 0 10 # 증가
출석 체크 구현
// 키: attendance:{userId}:{year}:{month}
// offset: 일(day) - 1
// 출석 기록 (1일 = offset 0)
redisTemplate.opsForValue().setBit("attendance:user1:2026:05", 0, true); // 1일
redisTemplate.opsForValue().setBit("attendance:user1:2026:05", 4, true); // 5일
// 특정 날 출석 여부
Boolean attended = redisTemplate.opsForValue()
.getBit("attendance:user1:2026:05", 0);
// 월 출석 일수
Long count = redisTemplate.execute(
(RedisCallback<Long>) conn ->
conn.stringCommands().bitCount("attendance:user1:2026:05".getBytes())
);
메모리 효율: 10만 명의 하루 출석 데이터 = 10만 비트 = 약 12KB
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| SETBIT, GETBIT | O(1) |
| BITCOUNT | O(N) |
| BITOP | O(N) |
| BITPOS | O(N) |
HyperLogLog
확률적 알고리즘을 사용해 집합의 원소 개수(cardinality)를 근사 추정한다. 최대 12KB의 고정 메모리로 2^64개 원소까지 추정 가능하며, 오차율은 약 0.81%다.
주요 명령어
PFADD key element1 element2 # 원소 추가
PFCOUNT key # 유니크 원소 수 추정
PFCOUNT key1 key2 # 합집합 카운트
PFMERGE dest key1 key2 # 병합 후 저장
UV(Unique Visitor) 카운팅
// 방문자 추가
String key = "uv:page:home:" + today;
redisTemplate.opsForHyperLogLog().add(key, userId);
// 유니크 방문자 수
Long uv = redisTemplate.opsForHyperLogLog().size(key);
// 여러 페이지 합산 UV
Long totalUv = redisTemplate.opsForHyperLogLog()
.size("uv:page:home:2026-05-01", "uv:page:home:2026-05-02");
Set vs HyperLogLog
| 항목 | Set | HyperLogLog |
|---|---|---|
| 정확도 | 정확 | 약 0.81% 오차 |
| 메모리 | 원소 수에 비례 | 최대 12KB 고정 |
| 원소 조회 | 가능 | 불가능 |
| 적합 사례 | 원소 목록이 필요할 때 | 대규모 유니크 카운팅 |
Stream
메시지의 영속적 시퀀스를 저장하는 자료구조다. Redis 5.0에서 도입되었으며, Kafka와 유사한 소비자 그룹 패턴을 지원한다.
주요 명령어
# 메시지 추가
XADD stream * field1 val1 field2 val2 # * = 자동 ID 생성
XADD stream 1714567890000-0 f1 v1 # 수동 ID 지정
XADD stream MAXLEN ~ 1000 * f1 v1 # 최대 1000개 유지 (근사 트림)
# 조회
XRANGE stream - + # 전체 조회 (오름차순)
XRANGE stream - + COUNT 10 # 최초 10개
XREVRANGE stream + - COUNT 10 # 최신 10개
XLEN stream # 메시지 수
# 개별/다중 스트림 읽기
XREAD COUNT 10 STREAMS stream 0 # ID 0부터 10개
XREAD COUNT 10 BLOCK 0 STREAMS stream $ # 새 메시지 블로킹 대기
# 소비자 그룹
XGROUP CREATE stream groupName $ MKSTREAM
XREADGROUP GROUP groupName consumer COUNT 10 STREAMS stream > # 미전달 메시지
XACK stream groupName messageId # 처리 완료 확인
XPENDING stream groupName - + 10 # 미확인 메시지 조회
XCLAIM stream groupName consumer 0 msgId # 메시지 소유권 이전
# 삭제/트림
XDEL stream messageId
XTRIM stream MAXLEN 1000
이벤트 스트리밍 구현
// 이벤트 발행
Map<String, String> eventData = new HashMap<>();
eventData.put("orderId", "123");
eventData.put("status", "CREATED");
eventData.put("amount", "50000");
RecordId recordId = redisTemplate.opsForStream()
.add("stream:orders", eventData);
// 소비자 그룹 생성
redisTemplate.opsForStream().createGroup("stream:orders", "order-service");
// 소비자 그룹으로 읽기
List<MapRecord<String, Object, Object>> records = redisTemplate.opsForStream()
.read(Consumer.from("order-service", "consumer-1"),
StreamReadOptions.empty().count(10),
StreamOffset.create("stream:orders", ReadOffset.lastConsumed()));
// 처리 후 ACK
records.forEach(record -> {
processOrder(record.getValue());
redisTemplate.opsForStream().acknowledge("stream:orders", "order-service", record.getId());
});
Kafka vs Redis Stream
| 항목 | Kafka | Redis Stream |
|---|---|---|
| 영속성 | 디스크 기반, 장기 보관 | 메모리 기반, 별도 설정 필요 |
| 처리량 | 매우 높음 | 높음 |
| 소비자 그룹 | 지원 | 지원 |
| 메시지 재처리 | 오프셋으로 쉽게 가능 | 가능하지만 제한적 |
| 적합 사례 | 대규모 이벤트 파이프라인 | 애플리케이션 내 이벤트 처리 |
Geospatial
내부적으로 Sorted Set을 사용해 위치 좌표를 저장한다. 경도(-180~180), 위도(-85.05~85.05) 범위를 지원한다.
주요 명령어
# 위치 추가
GEOADD key longitude latitude member
GEOADD locations 127.0276 37.4979 "강남역"
GEOADD locations 126.9784 37.5662 "홍대입구"
# 거리 계산
GEODIST key member1 member2 [m|km|mi|ft]
GEODIST locations "강남역" "홍대입구" km
# 좌표 조회
GEOPOS key member1 member2
# 반경 내 검색 (Redis 6.2+에서 GEOSEARCH 권장)
GEOSEARCH key FROMMEMBER member BYRADIUS 5 km ASC COUNT 10
GEOSEARCH key FROMLONLAT 127.0 37.5 BYRADIUS 5 km ASC COUNT 10 WITHCOORD WITHDIST
# 결과 저장
GEOSEARCHSTORE dest key FROMMEMBER member BYRADIUS 5 km ASC
근처 매장 검색
// 매장 등록
redisTemplate.opsForGeo()
.add("stores", new Point(127.0276, 37.4979), "강남점");
redisTemplate.opsForGeo()
.add("stores", new Point(126.9784, 37.5662), "홍대점");
// 현재 위치에서 5km 이내 매장 조회
GeoSearchCommandArgs args = GeoSearchCommandArgs.newGeoSearchArgs()
.includeDistance()
.includeCoordinates()
.sortAscending()
.limit(10);
GeoResults<RedisGeoCommands.GeoLocation<String>> results = redisTemplate.opsForGeo()
.search("stores",
new BoundingBox(new Point(127.0, 37.5), new Distance(5, Metrics.KILOMETERS)),
args);
results.forEach(result -> {
System.out.println(result.getContent().getName() + ": " + result.getDistance());
});
// 두 매장 간 거리
Distance distance = redisTemplate.opsForGeo()
.distance("stores", "강남점", "홍대점", Metrics.KILOMETERS);
시간복잡도
| 명령어 | 복잡도 |
|---|---|
| GEOADD | O(log N) |
| GEODIST | O(log N) |
| GEOPOS | O(log N) |
| GEOSEARCH | O(N+log M) |
자료구조별 메모리 최적화
Redis는 소규모 자료구조에 대해 컴팩트 인코딩을 자동으로 적용한다.
| 자료구조 | 소규모 인코딩 | 임계값 |
|---|---|---|
| Hash | listpack (구 ziplist) | 128 필드, 64바이트 |
| List | listpack | 128 원소, 64바이트 |
| Set | listpack / intset | 128 원소 |
| Sorted Set | listpack | 128 원소, 64바이트 |
임계값을 초과하면 각각 hashtable, quicklist, skiplist 등 일반 인코딩으로 전환된다.
# 인코딩 확인
OBJECT ENCODING key
# → listpack, skiplist, hashtable, intset 등
자료구조 선택 가이드
| 요구사항 | 권장 자료구조 |
|---|---|
| 단순 캐시, 카운터, 세션 | String |
| 메시지 큐, 최근 N개 목록 | List |
| 중복 없는 집합, 태그, 좋아요 | Set |
| 랭킹, 점수 기반 정렬 | Sorted Set |
| 객체 저장, 부분 업데이트 | Hash |
| 대규모 불리언 플래그, 출석 | Bitmap |
| 대규모 유니크 카운팅 (UV) | HyperLogLog |
| 이벤트 스트리밍, 메시지 로그 | Stream |
| 위치 기반 검색 | Geospatial |