Redis 직접 제어의 문제

Zyoon·2026년 3월 16일

개인프로젝트

목록 보기
4/6
post-thumbnail

1. 문제 상황: Redis를 너무 직접적으로 다루고 있었다

초기 코드에서는 벡터 저장소를 초기화하기 위해 Jedis 클라이언트를 직접 생성하고 Redis 명령어를 날리고 있었다.

// 이전코드
publicvoidclearStore() {

redis.clients.jedis.Jedisjedis=newredis.clients.jedis.Jedis("localhost",6379);

jedis.sendCommand(
Protocol.Command.valueOf("FT.DROPINDEX"),
"vector_index",
"DD"
    );

Set<String>ragKeys=jedis.keys("rag:*");
jedis.del(ragKeys.toArray(newString[0]));

jedis.close();
}

처음에는 단순히 인덱스 초기화 기능만 필요했기 때문에 큰 문제를 느끼지 못했다. 하지만 코드를 다시 보니 여러 가지 문제가 눈에 들어왔다. 대표적인 문제는 다음과 같았다.

(1) 리소스 관리 문제

new Jedis()
→ 직접 커넥션 생성
→ close() 수동 관리

예외가 발생하면 close()가 호출되지 않을 가능성이 있었다. 즉 커넥션 누수 위험이 있었다.


(2) 하드코딩된 설정

vector_index
rag:*
localhost:6379

이 값들이 코드에 직접 들어가 있었다. 환경이 바뀌거나 Redis 설정이 바뀌면 코드를 수정해야 하는 구조였다.


(3) 프레임워크 추상화를 활용하지 못하고 있었다

Spring AI는 이미 VectorStore 추상화 계층을 제공하고 있다. 하지만 기존 코드는 Redis 명령어를 직접 사용하고 있었기 때문에 Spring AI의 설계 철학을 전혀 활용하지 못하는 코드였다.


2. 리팩토링 방향: Spring에게 맡기기

리팩토링의 방향은 단순했다.

"프레임워크가 해줄 수 있는 일은 프레임워크에게 맡기자."

그래서 다음 세 가지 원칙을 세웠다.

1. Redis 커넥션은 Spring이 관리하도록 한다
2. VectorStore 추상화를 활용한다
3. 설정 값은 코드에서 제거한다

이 원칙을 기준으로 벡터 저장소 관리 로직을 다시 작성했다.


3. 개선된 구조

리팩토링 이후에는 별도의 관리 서비스를 하나 두었다.

// 개선된 코드
@Service
@RequiredArgsConstructor
@Slf4j
publicclassVectorStoreManagementService {

privatefinalVectorStorevectorStore;
privatefinalRedisTemplate<String,Object>redisTemplate;

    @Value("${rag.redis.vectorstore.key-prefix:rag:}")
privateStringkeyPrefix;

publicvoidclearStore() {

Set<String>ragKeys=redisTemplate.keys(keyPrefix+"*");

if (ragKeys!=null&&!ragKeys.isEmpty()) {
redisTemplate.delete(ragKeys);
        }

log.info("벡터 저장소가 안전하게 초기화되었다.");
    }
}

이 구조의 핵심은 두 가지다.

  • VectorStore 추상화 활용
  • RedisTemplate을 통한 Redis 접근

즉 Redis를 직접 다루기보다는 Spring이 제공하는 추상화 계층을 활용하는 방식으로 바꿨다.


4. 리팩토링 이후 달라진 점

리팩토링 이후 체감되는 장점은 꽤 분명했다.

(1) Redis 리소스 관리 안정성

이제 Redis 커넥션은 다음 구조로 관리된다.

Application
   ↓
RedisTemplate
   ↓
Connection Pool
   ↓
Redis

Spring Boot가 자동으로 커넥션 풀링과 리소스 반환을 관리한다. 개발자가 직접 close()를 관리할 필요가 없다.


(2) 벡터 DB 교체 가능성 확보

기존 구조에서는 Redis 명령어에 의존하고 있었다.

FT.DROPINDEX
rag:*
Jedis

하지만 이제는 다음 구조가 되었다.

Application
   ↓
VectorStore
   ↓
RedisVectorStore

즉 향후 다음과 같은 벡터 DB로 전환할 때도 코드 변경이 최소화된다.

Redis
PostgreSQL + pgvector
Pinecone
Weaviate

VectorStore 인터페이스만 유지하면 된다.


(3) 설정 유연성 확보

기존에는 인덱스 이름과 키 접두사가 코드에 있었다. 리팩토링 이후에는 설정으로 분리했다.

rag:
  redis:
    vectorstore:
      index-name: my_custom_index
      key-prefix:"prod:rag:"

이제 코드 수정 없이 환경별 설정을 분리할 수 있다.


5. 개발하면서 느낀 점

처음에는 단순히 "일단 돌아가는 코드"를 만드는 데 집중했다. 하지만 시스템이 조금씩 커지면서 코드 구조가 점점 불안해지고 있다는 느낌이 들기 시작했다. 특히 RAG 시스템은 다음 요소들이 모두 얽혀 있다.

문서 파싱
임베딩
벡터 저장
검색
LLM 호출

이 흐름 속에서 데이터가 어디에 어떻게 저장되는지 명확하지 않으면 나중에 관리가 굉장히 어려워진다. 프레임워크가 제공하는 추상화에는 결국 이유가 있었다.

직접 모든 것을 제어하는 코드보다,프레임워크의 표준 구조를 따르는 코드가 훨씬 안정적이고 확장 가능하다. 결과적으로 이번 리팩토링은 단순한 코드 정리가 아니라 RAG 시스템 아키텍처를 다시 정리하는 과정이기도 했다.

profile
기어 올라가는 개발

0개의 댓글