ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Embedded Redis 를 쓰면서 겪은 문제와 해결방안
    개발 흉내 2021. 12. 24. 13:33

     

    key-value의 데이터 베이스가 필요할 때 redis를 사용한다.

     

    스프링에서 Embedded Redis를 의존하여 쓸 일이 있었는데 문제와 해결을 몇가지 기록하려고 한다.

     

     

    1. 의존성 문제 - slf4j logger 중복 구현으로 인한 컴파일 에러

    2. 메모리 관련 플래그를 주지않아 실행 시 에러

    3. 스프링 비정상 종료 시 레디스 서버가 꺼지지 않음 - 재시작 시 포트 중복으로 인한 에러

     

     

     

    1. 의존성 문제

     

    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/C:/Users/ROGAL/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-simple/1.7.32/321ffafb5123a91a71737dbff38ebe273e771e5b/slf4j-simple-1.7.32.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/C:/Users/ROGAL/.gradle/caches/modules-2/files-2.1/ch.qos.logback/logback-classic/1.2.9/7d495522b08a9a66084bf417e70eedf95ef706bc/logback-classic-1.2.9.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
    Exception in thread "main" java.lang.IllegalArgumentException: LoggerFactory is not a Logback LoggerContext but Logback is on the classpath. Either remove Logback or the competing implementation (class org.slf4j.impl.SimpleLoggerFactory loaded from file:/C:/Users/ROGAL/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-simple/1.7.32/321ffafb5123a91a71737dbff38ebe273e771e5b/slf4j-simple-1.7.32.jar). If you are using WebLogic you will need to add 'org.slf4j' to prefer-application-packages in WEB-INF/weblogic.xml: org.slf4j.impl.SimpleLoggerFactory

     

    Embedded Redis 0.7.3 버전을 가져오면 컴파일 에러가 발생한다.

     

    로그를 보면 SLF4J 가 여러번 바인딩되서 그렇다고 한다.

     

    해당 이슈는 github에 등록된지 2년도 넘어가는데 안 고치고있다.

    https://github.com/ozimov/embedded-redis/pull/18

     

    Minor: move slf4j dependency to test dependencies (unused in library). by doumdoum · Pull Request #18 · ozimov/embedded-redis

    Hi, My very little contrib to your great work. Regards, /DV

    github.com

     

    해결 방법은 컴파일 시 slf4j 를 제외하는 것이다.

    implementation ('it.ozimov:embedded-redis:0.7.3') { exclude group: "org.slf4j", module: "slf4j-simple" }

     

    근데 잘 쓰고있던 lombok 에서 implementation 을 추가로 가져와야했다.

     

    그래들을 잘 몰라서 왜 이렇게 해야하는 지까진 모르겠다.

     

     

     

     

     

    2. 메모리 관련 플래그를 주지않아 실행 시 에러

     

    java.lang.RuntimeException: Can't start redis server. Check logs for details. Redis process log: 
    [30452] 24 Dec 13:36:00.257 # 
    The Windows version of Redis allocates a memory mapped heap for sharing with
    the forked process used for persistence operations. In order to share this
    memory, Windows allocates from the system paging file a portion equal to the
    size of the Redis heap. At this time there is insufficient contiguous free
    space available in the system paging file for this operation (Windows error 
    0x5AF). To work around this you may either increase the size of the system
    paging file, or decrease the size of the Redis heap with the --maxheap flag.
    Sometimes a reboot will defragment the system paging file sufficiently for 
    this operation to complete successfully.
    
    Please see the documentation included with the binary distributions for more 
    details on the --maxheap flag.
    
    Redis can not continue. Exiting.

    컴파일 에러는 해결 했는데 런타임에서 뻗었다.

     

    로그를 보니 윈도우에서 레디스는 메모리 할당에 문제가 있어서 직접 제한을 걸어달란 소리다.

     

    제작자가 대충 걸어줬어도 되지않았을까?

     

    --maxheap 플래그를 주면 된다고한다.

     

    그래서 --maxheap 128M 을 주고 잘 개발하고 있었는데 리눅스 도커환경에서 실행하니 레디스가 또 뻗었다.

     

    검색해보니 maxheap가 아니라 maxmemory를 써야한다고 한다.

    https://github.com/kstyrc/embedded-redis/issues/77

     

    max heap setting does not work · Issue #77 · kstyrc/embedded-redis

    I don't seem to have a locally-installed redis so it should be using the Linux 64-bit one inside the jar. *** FATAL CONFIG FILE ERROR *** Reading the configuration file, at line 3 >>> ...

    github.com

     

    그럼 로그는 왜 저렇게 써놔서 날 헷갈리게 하는걸까?

     

    레디스 서버를 만들 때 setting으로 플래그를 넣어주면 된다.

     

    좀 더 개발자스러운 방법을 써서 실행 환경마다 유연하게 대처할 수 있도록 yml로 관리했다.

     

     

     

     

    3. 스프링 비정상 종료 시 레디스 서버가 꺼지지 않음.

     

    스프링을 켠다.

     

    스프링을 강제 종료한다.

     

    스프링을 다시 킨다. -> 레디스 서버 시작 시 오류가 발생한다.

     

    java.lang.RuntimeException: Can't start redis server. Check logs for details. Redis process log: 
    [40488] 24 Dec 13:10:44.809 # Creating Server TCP listening socket 127.0.0.1:6379: bind: No such file or directory

    테스트 빌드때는 stop 이 호출되기 때문에 문제없었는데 그냥 실행시키면 문제가 발생한다.

     

    로그를 읽어보니 6379 소켓을 얻어오는 데 실패한 듯하다.

     

    6379 이 레디스의 기본 포트라는 걸 몰랐다면 또 얼마나 헤멨을까?

     

    이전에 실행된 레디스 서버가 6379 포트를 점유하고 있었고 새로운 레디스 서버는 이 포트를 할당받지 못한 것이다.

     

    원래 스프링이 정상 종료하면서 stop을 호출할 것이고 레디스 서버도 같이 사라져야하지만

     

    그렇지 못한 경우에는 레디스 서버만 덩그러니 남아있게 된 것이다.

     

    근데 스프링이 정상 종료되는 경우가 있긴 한가? 뻗어서 죽는거지

     

     

     

    아무튼 이전 레디스를 꺼지게 할 방법을 찾지 못해서 편법을 쓰기로 했다.

    레디스 서버를 생성할 수 없다면 그냥 무시하고 진행하도록 했다.

     

    스프링에서 레디스 서버 생성과 레디스 연결은 분리되어있고

     

    레디스 서버 생성 후 레디스 연결을 시도하게되는 데

     

    레디스 생성이 실패하더라도 연결이 되도록 한 셈이다.

     

    심지어 도커 환경에서 실행한다면 레디스를 포함한 컨테이너 전체가 종료되기에 충분한 해결방법이었다.

     

     

     

     

     

    여기까지 임베디드 레디스를 쓰면서 겪은 문제점과 해결법을 알아보았다.

     

    여러분은 시간을 아낄 수 있길 바란다.

    댓글

Designed by Tistory.