Redis 캐시에 객체를 저장할 때 직렬화가 필요한 이유
Redis 캐시에 객체를 저장할 때 직렬화가 필요한 이유
Spring에서 @Cacheable로 Redis 캐시를 붙이다 보면 이런 예외를 만나기 마련이다.
1
org.springframework.data.redis.serializer.SerializationException: Cannot serialize
처음 이 에러를 보면 로직이 잘못된 것처럼 보인다. 하지만 실제 원인은 대개 캐시와 객체의 관계를 오해한 데 있다. 캐시에 저장하는 객체가 왜 반드시 직렬화 가능해야 하는지, Redis 캐시에서 이 문제가 왜 자주 터지는지 짚어보자.
캐시는 메모리가 아니라 저장소다
로컬 캐시(Caffeine, ConcurrentHashMap 등)는 객체를 그대로 메모리에 보관한다. 같은 JVM 안에서 도니 객체 참조를 그대로 저장해도 문제가 없다.
하지만 Redis는 다르다. Redis는 별도의 프로세스이고, 아예 다른 서버에 떨어져 있을 수도 있다. 데이터는 네트워크를 오가며 주고받는다.
그래서 Java 객체를 그대로 넘길 수 없다. 바이트 단위 데이터로 변환해서 저장해야 하는데, 이 변환 과정이 바로 직렬화(Serialization) 다.
Spring Cache + Redis 동작 흐름
@Cacheable이 붙은 메서드가 호출되면 내부적으로는 이런 순서를 밟는다.
- 캐시 Key 생성
- Redis에서 Key 조회
- 캐시 미스 시 메서드 실행
- 메서드 반환 값을 직렬화
- Redis에 저장
이 중 4번 단계가 실패하면 예외가 터진다.
1
SerializationException: Cannot serialize
여기서 중요한 건 메서드 실행 자체는 성공한다는 점이다. 서비스는 정상 응답을 돌려주지만 캐시 저장만 실패한다.
결과적으로 캐시는 계속 비어 있고, 매 요청마다 DB 조회가 발생하며, 성능 개선 효과는 전혀 얻지 못한다.
Redis는 Java 객체를 이해하지 못한다
Redis가 이해할 수 있는 데이터는 문자열, 숫자, 바이트 배열, 그리고 Set·Hash 같은 단순 자료구조 정도가 전부다.
Java 객체는 Redis 입장에서 그저 의미 없는 덩어리다. 그래서 Spring Data Redis는 Serializer를 써서 객체를 변환한다. 대표적인 방식은 두 가지다.
JDK 직렬화
Serializable을 구현해야 하고, JdkSerializationRedisSerializer를 사용한다.
JSON 직렬화 (권장)
Jackson을 기반으로 하며 GenericJackson2JsonRedisSerializer를 사용한다.
어떤 방식이든 직렬화할 수 없는 객체는 Redis에 저장할 수 없다.
실무에서 자주 발생하는 문제 케이스
Hibernate Entity를 그대로 캐시하는 경우
Lazy Loading 프록시가 딸려 오고 순환 참조가 생길 수 있어, 직렬화에 실패할 확률이 높다.
Serializable을 구현하지 않은 DTO
기본 Redis 설정은 JDK 직렬화를 쓰기 때문에 곧바로 실패한다.
날짜 타입 처리 미흡
LocalDate, LocalDateTime 같은 타입은 Jackson 설정이 없으면 JSON 직렬화에 실패할 수 있다.
왜 DTO로 변환해서 캐시해야 할까?
실무에서는 이 구조가 가장 안전하다.
1
Entity → DTO → Cache
DTO는 불변 객체로 설계할 수 있고 Lazy 프록시가 없어서 직렬화 결과를 예측하기 쉽다. 캐시에 들어가는 데이터 구조도 안정적으로 유지된다.
캐시는 ORM 세션을 연장하는 수단이 아니라, 순수한 데이터 저장소로 다뤄야 한다.
정리
Redis 캐시에 객체를 저장한다는 건 객체를 그대로 보관하는 게 아니라 직렬화된 데이터로 바꿔 넣는다는 뜻이다. 따라서 캐시에 들어가는 객체는 반드시 직렬화 가능해야 한다.
이걸 놓치면 캐시 저장은 실패해도 서비스는 정상 동작하기 때문에, 성능 문제가 겉으로 드러나지 않은 채 쌓인다.
캐시는 분명 성능을 끌어올리는 도구다. 하지만 직렬화를 이해하지 못하면 오히려 디버깅하기 까다로운 문제를 만들 수도 있다. Redis 캐시를 쓴다면 저장하는 객체가 직렬화 가능한지부터 확인하는 게 먼저다.