내일배움캠프

[내일배움캠프] Redis

munsik22 2026. 5. 7. 11:56

📚 목차

    🧩 인메모리 저장소와 Redis

    Redis

    • Java의 Map과 같은 방식으로 데이터를 저장하는 데이터베이스
    • Redis의 특징: In-Memory 데이터베이스
      • 기존의 관계형 DB: 테이블 형태로 데이터를 영속적으로 저장함
        • 파일 시스템(SSD 또는 HDD)에 저장해 컴퓨터가 종료되어도 데이터가 사라지지 않음
        • 기본적으로 데이터를 읽고 쓰는 속도가 상대적으로 느림
      • Redis: 메모리(RAM)에 데이터를 저장함
        • 일반적인 RDBMS보다 빠르게 동작하지만 언제든 데이터가 사라질 수 있음
        • 특정 게시글의 조회수와 같이 빠르게 업데이트되는 데이터, 또는 사용자 세션이나 장바구니처럼 시간이 지나면 삭제되는 데이터를 저장하는 데 사용됨

    NoSQL (Not only SQL)

    • 관계형 DB는 일반적으로 테이블 형식으로 데이터를 저장하고, 그 데이터를 관리하기 위해 SQL문을 사용함
    • Redis는 String, List, Set, Hash 등 다양한 형태의 데이터를 저장하며, 이를 관리하기 위해 SQL을 사용하지 않음
      SET greeting "Hello, Redis!"
      GET greeting
    • 일관성을 포기하는 대신 확장성과 유연성을 확보함

    • NoSQL 데이터베이스는 데이터를 관리하는 방법이 서로 다름
      • Key-Value: Python의 dict, Java의 Map과 같은 형태 (예: Redis)
      • Document: JSON, XML 등 복잡한 데이터 저장 (예: MongoDB)
      • Column-Family (Wide-Column): 각 Row의 Column이 고정되어 있지 않고, 필요한 데이터 Column을 이름, 데이터, timestamp와 함께 저장함 (예: cassandra)
      • 관계를 기준으로 데이터를 다루지 않기 때문에 스키마를 만들지 않고 비정형 대규모 데이터를 매우 빠르게 다룰 수 있음

    Redis의 활용 사례

    • Redis는 Key-Value NoSQL In-Memory 데이터베이스
    • 데이터 변경이 잦은 기능을 다룰 때 많이 사용함
      • 리더보드, 방문자 트래킹
      • Session Clustering
      • Caching

    🧩 Redis 설치하기

    Windows(WSL)에서 Redis 설치하기

     

    Ubuntu에서 Redis 설치/실행/종료하기

    설치$ sudo apt update$ sudo apt install redis-server -y실행/종료 방법 1$ sudo service redis-server start$ sudo service redis-server stop실행/종료 방법 2실행: redis-start종료: Ctrl + C

    munsik22.tistory.com

    Docker를 이용해 Redis 설치하기

    • Docker Hub에서 Redis를 검색하면 세 가지 이미지를 볼 수 있다.
      • redis: 가장 많이 사용된 Redis의 핵심 코어
      • redis/redis-stack-server: 여러 플러그인이 추가되어 확률형 데이터나 JSON 문서 등을 사용할 수 있음
      • redis/redis-stack: Redis Insight를 같이 사용 가능함
    • docker-compose.yml 생성
    • services: redis-stack: image: redis/redis-stack container_name: redis-stack-compose restart: always environment: REDIS_ARGS: "--requirepass systempass" # USERNAME=default / password=systempass ports: - 6379:6379 - 8001:8001
    • docker compose up -d를 실행하면 자동으로 최신 버전 Redis Stack 이미지를 사용하게 된다.
    • docker compose ps를 실행하면 컨테이너가 정상적으로 실행되었는지 확인 가능하다.

    • Intellij IDEA에서 Redis DB를 연결해 사용 가능하다.
    • Redis Stack을 설치한 경우 Redis Insignt도 같이 설치된다. http://localhost:8001에 접속하면 Redis Insight UI를 확인할 수 있다.
      • 여기서 USERNAME은 default, PASSWORD는 systempass로 설정되었다.

    🧩 Redis 타입 살펴보기

    String

    • 가장 기본적인 자료형으로, Java의 Map<String, String>처럼 동작함
    • SET <key> <value>: keyvalue 문자열 저장
    • GET <key>: key에 저장된 문자열 반환
    • 저장된 데이터가 정수 데이터라면 데이터를 바로 증가, 감소가 가능함
      • INCR key: key에 저장된 데이터를 1 증가
      • DECR key: key에 저장된 데이터를 1 감소
    • 여러 Key-Value를 한번에 다루는 방법
      • MSET key value [key value ...]: key value의 형태로 주어진 인자들을 각 keyvalue를 저장
      • MGET key [key]: 주어진 모든 key에 해당하는 데이터를 반환
        MSET user:name alex user:email alex@example.com
        MGET user:name user:email # alex alex@example.com이 반환됨
    • 문자열 = 바이트 배열이므로 이미지, 음성, 영상, 파일 등도 보관이 가능하다.
    • 분산된 구조에서 비교적 큰 사이즈의 데이터를 주고받는 상황에서 Key만 전달해서 데이터는 여기있다고 전달하는 방식으로 활용 가능함

    List

    • 여러 문자열 데이터를 LinkedList 형태로 보관하는 자료형
    • 스택 또는 큐처럼 사용 가능함
      • LPUSH key value: key에 저장된 리스트의 앞쪽에 value를 저장
      • RPUSH key value: key에 저장된 리스트의 뒤쪽에 value를 저장
      • LPOP key: key에 저장된 리스트의 앞쪽에서 값을 반환 및 제거
      • RPOP key: key에 저장된 리스트의 뒤쪽에서 값을 반환 및 제거
        LPUSH user:list alex  # [alex]
        LPUSH user:list brad  # [brad, alex]
        RPUSH user:list chad  # [brad, alex, chad]
        RPUSH user:list dave  # [brad, alex, chad, dave]
        LPOP user:list        # brad
        RPOP user:list        # chad
    • Redis는 Key-Value 형태로 저장하므로, 실제로는 Map<String, List<String>>의 형태처럼 사용됨
      • GET user:list라고 입력하면 Key에 저장된 자료형이 달라 WRONGTYPE 에러가 발생한다.
    • 리스트를 사용하면서 흔히 사용하는 길이 구하기, 범위 내 원소 반환하기 등의 기능도 제공함
      • LLEN key: key에 저장된 리스트의 길이를 반환
      • LRANGE key start end: keystart부터 end까지 원소들을 반환
        • 파이썬처럼 음수 범위의 경우 뒤에서부터 반환함
    • Worker Queue또는 SNS(X 등) 타임라인 등에서 사용 가능함

    Set

    • 문자열의 집합: 중복값을 제거하며 순서가 존재하지 않음
      • SADD key value: key에 저장된 집합에 value를 추가
      • SREM key value: key에 저장된 집합의 value를 제거
      • SMEMBERS key: key에 저장된 집합의 모든 원소를 반환
      • SISMEMBER key value: key에 저장된 집합에 value가 존재하는지 반환
      • SCARD key: key에 저장된 집합의 크기를 반환
        SADD user:java alex  # [alex]
        SADD user:java brad  # [alex, brad]
        SADD user:java chad  # [alex, brad, chad]
        SREM user:java alex  # [brad, chad]
        SMEMBERS user:java        # [alex, brad, chad]
        SISMEMBER user:java brad  # true
        SISMEMBER user:java dave  # false
    • 교집합, 합집합 등의 기능도 제공함
      • SINTER key1 key2: key1key2에 저장된 집합들의 교집합의 원소들을 반환
      • SUNION key1 key2: key1key2에 저장된 집합들의 합집합의 원소들을 반환
      • SINTERCARD number key1 [key2 ...]: number개의 key에 저장된 집합들의 교집합의 크기를 반환
        SADD user:python alex
        SADD user:python dave
        SINTER user:java user:python        # [alex]
        SUNION user:java user:python        # [alex, brad, chad, dave]
        SINTERCARD 2 user:java user:python  # 1
    • 어떤 데이터의 존재 여부를 확인하는 SISMEMBER는 O(1)의 시간복잡도를 가져 중복 없는 방문 수 또는 인증 토큰 블랙리스트 등을 구현할 때 활용 가능하다.

    Hash

    • Field-Value 쌍으로 이뤄진 자료형
    • Hash 데이터를 가져오기 위해 Key를 사용하고, 이후 다시 Key에 저장된 Hash 데이터에 Field-Value 쌍을 넣어주는 형식으로 동작함
    • Redis 전체가 Map이라면 Hash는 Map<String, Map<String, String>>의 형식
    • Hash 관련 명령어들
      • HSET key field value [field value]: key의 Hash에 fieldvalue를 넣음
      • HGET key field: key에 저장된 Hash의 field에 저장된 value를 반환 (없으면 null)
      • HMGET key field [field]: key에 저장된 Hash에서 복수의 field에 저장된 value를 반환
      • HGETALL key: key에 저장된 Hash에 저장된 field - value를 전부 반환
      • HKEYS key: key에 저장된 Hash에 저장된 field를 전부 반환
      • HLEN key: key에 저장된 Hash에 저장된 field의 갯수를 반환
        HSET user:alex name alex age 25
        HSET user:alex major CSE
        HGET user:alex name
        HGET user:alex age
        HMGET user:alex age major
        HGETALL user:alex
        HKEYS user:alex
        HLEN user:alex
    • 장바구니: 사용자 별로 Hash 데이터를 생성하고 물품-개수 형식으로 데이터를 저장하는 방식으로 구현 가능

    Sorted Set

    • 정렬된 집합: 기본적으로 Set과 동일하게 유일한 값들만 유지하지만, 여기서 각 값들에 score라는 실수를 함께 저장하고, 데이터를 가져올 때 score를 바탕으로 정렬함
    • Sorted Set 관련 명령어
      • ZADD key score member [score member ...]: key의 Sorted Set에 score를 점수로 가진 member를 추가, 이미 있는 member의 경우 새로운 score를 설정
      • ZRANK key member: key의 Sorted Set의 member의 순위를 오름차순 기준으로 0에서 부터 세서 반환
      • ZRANGE key start stop: key의 Sorted Set의 member들을 start 부터 stop 순위까지 오름차순 기준으로 반환
      • ZREVRANK key member: key의 Sorted Set의 member의 순위를 내림차순 기준으로 0에서 부터 세서 반환
      • ZREVRANGE key start stop: key의 Sorted Set의 member들을 start 부터 stop 순위까지 내림차순 기준으로 반환
      • ZINCRBY key increment member: key의 Sorted Set의 memberscoreincrement 만큼 증가 (음수를 전달하면 감소)
        ZADD user:ranks 10 alex
        ZADD user:ranks 9 brad 11 chad
        ZADD user:ranks 8 dave
        ZINCRBY user:ranks 2 alex
        ZRANK user:ranks alex
        ZRANGE user:ranks 0 3
        ZREVRANK user:ranks alex
        ZREVRANGE user:ranks 0 3
    • 리더보드나 Rate Limiter와 같이 순위와 관련된 기능을 만드는 데 사용함
      • ※ Rate Limiter: API 등을 제공할 때 짧은 시간에 지나치게 많은 요청을 막기 위한 기능

    기타 공용 명령어

    • DEL key: key(와 저장된 데이터)를 제거
    • EXPIRE key seconds: key의 TTL(유효시각)을 seconds로 설정, seconds초가 지나면 key 제거
    • EXPIRETIME key: key가 만료되는 시각을 Unix Timestamp로 반환
    • KEYS *: 저장된 모든 Key 확인
    • FLUSHDB: 모든 Key 제거

    🧩 SpringBoot에서 Redis 사용하기

     

    GitHub - qkrwns1478/redis-demo

    Contribute to qkrwns1478/redis-demo development by creating an account on GitHub.

    github.com

    • 새 프로젝트 생성: Spring Data Redis 종속성 추가

    • application.yml 생성
    spring:
      application:
        name: redis-demo
      config:
        import: optional:file:.env[.properties]
      data:
        redis:
          host: ${REDIS_HOST}
          port: ${REDIS_PORT}
          username: ${REDIS_USERNAME}
          password: ${REDIS_PASSWORD}
    • Item 엔티티 생성
    @Getter
    @Setter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @RedisHash("item") // Entity 대신 사용
    public class Item implements Serializable {
        @Id private String id;
        private String name;
        private String description;
        private Integer price;
    }
    • ItemRepository 생성
    public interface ItemRepository extends CrudRepository<Item, Long> {}
    • ItemRepositoryTest 생성
    @SpringBootTest
    public class RedisRepositoryTest {
        @Autowired
        private ItemRepository itemRepository;
    
        @Test
        public void createTest() {
            Item item = Item.builder()
                    .name("키보드")
                    .description("비싸")
                    .price(100000)
                    .build();
            itemRepository.save(item);
        }
    }
    • 테스트 코드 실행 후 Redis에 해시 테이블이 추가된 것을 확인할 수 있다.

    • item은 id값들을 들고 있는 집합이다.

    • Redis에서는 id가 1부터 예쁘게 들어가는 게 아니라 임시값으로 들어간다.

    • 일반적으로는 id값보다는 User Session이나 User Config 등 임시로 저장할 데이터를 저장하는 데 사용한다.

    Redis Template

    • RedisTemplateTest 생성: StringRedisTemplate은 각 자료형에 대응하는 *Operations 인터페이스 구현체를 반환할 수 있는 메서드들을 가지고 있다.
    @SpringBootTest
    public class RedisTemplateTest {
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
    
        @Test
        public void stringOpsTest() {
            // 문자열 조작을 위한 클래스
            ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
    
            ops.set("simplekey", "simplevalue");
            System.out.println(ops.get("simplekey"));
        }
    }

    @Test
    public void stringValueOpsTest() {
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        ops.set("simplekey", "simplevalue");
        System.out.println(ops.get("simplekey"));
        ops.set("greeting", "hello redis!");
        System.out.println(ops.get("greeting"));
    }
    @Test
    public void stringSetOpsTest() {
        SetOperations<String, String> setOps = stringRedisTemplate.opsForSet();
        setOps.add("hobbies", "games");
        setOps.add("hobbies", "coding");
        setOps.add("hobbies", "alcohol");
        setOps.add("hobbies", "games");
        System.out.println(setOps.size("hobbies"));
    }

    @Test
    public void redisOpsTest() {
        // 10초 뒤에 일괄 만료(삭제)됨
        stringRedisTemplate.expire("simplekey", 10, TimeUnit.SECONDS);
        stringRedisTemplate.expire("greeting", 10, TimeUnit.SECONDS);
        stringRedisTemplate.expire("hobbies", 10, TimeUnit.SECONDS);
    }

    @Configuration에서 RedisTemplate 정의하기

    • ItemDto 생성
    @Getter
    @ToString
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class ItemDto {
        private String name;
        private String description;
        private Integer price;
    }
    • RedisConfig 생성: 커스텀 RedisTemplate 만들기
    @Configuration
    public class RedisConfig {
        @Bean
        public RedisTemplate<String, ItemDto> itemRedisTemplate(RedisConnectionFactory connectionFactory) {
            RedisTemplate<String, ItemDto> template = new RedisTemplate<>();
            template.setConnectionFactory(connectionFactory);
            template.setKeySerializer(RedisSerializer.string()); // Key 데이터를 문자열로 직렬/역직렬화
            template.setValueSerializer(RedisSerializer.json()); // Value 데이터를 JSON으로 직렬화
            return template; // Bean 객체로 등록
        }
    }
    @Autowired
    private RedisTemplate<String, ItemDto> itemRedisTemplate;
    
    @Test
    public void itemRedisTemplateTest() {
        ValueOperations<String, ItemDto> ops = itemRedisTemplate.opsForValue();
        ops.set("my:keyboard", ItemDto.builder()
                .name("Mechanical Keyboard")
                .price(300000)
                .description("Expensive")
                .build());
        System.out.println(ops.get("my:keyboard"));
    
        ops.set("my:mouse", ItemDto.builder()
                .name("mouse mice")
                .price(100000)
                .description("Expensive")
                .build());
        System.out.println(ops.get("my:mouse"));
    }