2023-01-16
시작은... 또또또또또ㄸ또또또또ㄸㄸㄸ 또디스...
이전에 만든 코드에서 비회원은 guest 의 @Id 에 선언된 필드값을 검색하는 것으로 존재하는지 확인해서 검증을 하는데,
내가 이 부분에다가 예외처리를 안해서 잘 돌아간다고 혼자 착각을 하고 있었다...
그래서 예외처리가 빠진것을 확인하고 나중에서야 수정했더니 계속 못찾는다고 열심히 알람을 띄우고 있었다.
그래서 확인을 해보니 실제로 값을 못 찾고 있었고 결국 이전에 계속해서 다른 참조값이 생기는 @Indexed 의 사용을 다시
활성화 해야 했다.
다만 @Inedxed 를 사용함으로 인해서 발생했던 문제가 있었다.
정확히는.. 문제라고 하기에는 조금 에매할 수도 있는데 @indexed 붙어있는 필드값의 경우에는 새롭게 만들어 질 때, 이 값을 조회하기 위해서 존재하는 또 다른 키가 생성이 된다.
결과적으로 hash 파일이 생기고 이를 참조하는 다른 값들도 같이 생겨나는 것이 문제였는데, 이것 자체 보다는 이게 자동 만료시 파기될때 참조값들은 같이 삭제가 되지 않는 문제가 있었다.
그래서 이부분을 해결하기 위해서 검색을 하면서 떠나는 여정... 이다... 이 아래로는...
그래서 새로운 게스트 계정이 생길 때 마다, 하나의 파일이 생기는 것이 아니라 3개의 파일이 생기게 된다.
위 이미지에 다 나오지는 않는데 위에처럼 redis 에 확인하면 게스트 계정이 하나만 로그인 해도 여러개의 파일이 생기는 문제가 있다..
그래서 이를 해결할 방법으로 파일 명이 생길때에는 일정한 규칙대로 생기니 파일에 생성될 때 마다 전부 하나씩 만료시간을 지정해주는 방법을 생각했다.
해보니 작동자체는 잘 하는데, 문제는 너무 코드가 이상하고 비효율적인 것 같았다...
레디스에서 @Indexed 를 사용함으로써 생기는 문제가 이를 참조하는 다른 키(데이터) 생기는 문제가 발생했다. 이를 확인하는 방법은 CRUDRepository 를 사용하지 않고 RedisTemplate 를 사용해서 저장하는 방법과
setExpire 를 사용해서 아예 강제로 지정해버리는 방법을 생각하고 있었다.
이 아래의 코드가 바로 그 해괴망측한 코드...
public void guestAutoDel(Long num) {
redisTemplate.expire(String.format("guest:%d:idx", num), 600, TimeUnit.SECONDS);
redisTemplate.expire(String.format("guest:id:%d", num), 600, TimeUnit.SECONDS);
redisTemplate.expire(String.format("guest:%d", num), 600, TimeUnit.SECONDS);
}
그래서 나와 같은 고민을 한 사람들이 있는지 싶어서 검색해보니 많지는 않지만 있기는 하더라...
혼자서는 못 찾았을 것 같은데, 조원분과 함께 찾아서 겨우 해결법을 찾을 수 있었다 !!!...
해외 사이트
https://github.com/spring-projects/spring-data-redis/issues/1299
https://gist.github.com/mp911de/581151f6394607998371d9f0910a7ac8
https://github.com/spring-projects/spring-data-redis/issues/2146
https://engineering.salesforce.com/lessons-learned-using-spring-data-redis-f3121f89bff9/
국내 사이트
https://hyperconnect.github.io/2022/12/12/fix-increasing-memory-usage.html
https://okky.kr/articles/1367544
위의 사이트 들에서 그 해결법을 찾을 수 있었는데,
그런데 이와 같은 고민을 해결한 방법으로는 제법 다양한 글들이 있었다.
우선 결국 핵심이 된 코드는 RedisRepository 에다가 두가지 설정을 추가하는 방법이었다.
@EnableRedisRepositories(enableKeyspaceEvents = EnableKeyspaceEvents.ON_STARTUP, shadowCopy = ShadowCopy.OFF)
위와 같은 코드로 해결한 경우가 있었다.
내가 이해한 바로는...
EnableKeyspaceEvents 를 사용해서 RedisRepository 를 통한 DB 사용에서 키값에 대한 변경이 있으면 이벤트를 수신한다는 것이고 ON_STARTUP 은 그 시점을 말하는 것 같다.
즉, 새로운 키가 생기는 순간 그 상황을 인식해서 Phantom 이라는 복사본 형태가 생겨난다.
만약 위의 EnableKeyspaceEvents 를 사용하면 복사본이 Redis 에도 생겨나고 만료 시간에 대한 값도 보유한다.
Phantom 파일은 Spring Data Redis 에 의해 구현되며 redis 에서 키가 expire 된 경우,
Spring Data Redis 에서 발생시키는 RedisKeyExpiredEvent 이벤트를 지원하기 위해 구현된 기능이다.
EnableKeyspaceEvents 를 사용하게 되면 위와 같은 경우처럼 ApplicationEventPublisher 가 만료된 키값을 유지한다.
다만 Phantom 파일이 생기는 것 조차도 싫다면은 shadowCopy.OFF 를 해주면 된다.
그러면 자동 파기시 연관된 참조 값(?)들도 함께 만료시 다 날라간다.