2022 10 03
2022-10-03¶
Spring Boot Data Redis¶
- 참고: https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/StringRedisTemplate.html
- 참고: https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisTemplate.html#opsForValue--
- 참고: https://luvstudy.tistory.com/143
- 참고: https://stackoverflow.com/questions/70255799/what-is-redis-valueoperations
- 개요
- Spring Boot의 RedisAutoConfiguration은
RedisTemplate과StringRedisTemplate두 가지 bean을 자동으로 생성하여 제공
- Spring Boot의 RedisAutoConfiguration은
-
StringRedisTemplate
- 레디스 key-value 문자열 위주라서 문자열에 특화된 템플릿
- String-focused extension of RedisTemplate
- RedisTemplate을 상속받음
- 일반적인 String 값을 Key-Value로 사용하는 경우 사용하면 됨
- 레디스 key-value 문자열 위주라서 문자열에 특화된 템플릿
- 사용법
- RedisTemplate / StringRedisTemplate을 호출하여 사용
- redisTemplate에는 redis가 제공하는 list/set/sortedSet/hash 등과 같은 다양한 Command 지원
- opsFor* method를 통해 작업
- opsForValue() - ValueOperations
- opsForHash() - HashOperations
- opsForList() - ListOperations
- opsForSet() - SetOperations
- ...
- ValueOperation이 뭐야?
- 레디스를 그냥 통으로 아주 큰 해시 맵으로 보는 것
- Simple Value에 대한 연산 결과를 반환
Thread.sleep() Noncompliant Code vs Compliant Code¶
- Noncompliant Code - SonarLint가 얘기하는 해로움
- Compliant Code - SonarLint가 추천하는 코드
@Test public void testDoTheThing(){ MyClass myClass = new MyClass(); myClass.doTheThing(); await().atMost(2, Duration.SECONDS).until(didTheThing()); // Compliant // assertions... } private Callable<Boolean> didTheThing() { return new Callable<Boolean>() { public Boolean call() throws Exception { // check the condition that must be fulfilled... } }; }
Awaitility¶
- 왜 Thread.sleep()을 지양하라고 하지?
- 참고: http://daplus.net/c-thread-sleep%EC%9D%B4-%EA%B7%B8%EB%A0%87%EA%B2%8C-%ED%95%B4%EB%A1%9C%EC%9A%B4-%EC%9D%B4%EC%9C%A0/
- 참고: https://stackoverflow.com/questions/17826651/why-thread-sleep-is-bad-to-use
- 해당 밀리초 내에 발생할 수 있는 타임 슬라이스 수만큼 현재 쓰레드를 차단
- 쓰레드가 정확히 n초 후에 깨어날 가능성은 없음
- 쓰레드는 제한된 리소스이기에, 스택을 위해 1MB의 가상메모리를 예약, 컨텍스트 스위치에 2000-8000 사이클 사용
- 대기중인 쓰레드는 낭비다...!
- 단점
- 락을 걸어버려서, 데이터베이스 같은거 (isolation level에 따라 다르겠지만) 다른 쓰레드가 DB에 접근조차 못하게 막아 버릴수도
- 쓰레드는 심지어 딱 그 시간만큼만 잠드는 게 아닐수도 있어 (thread-starvation으로 이어질수도?)
-
Awaitility를 활용한 테스트
- 참고: http://awaitility.org
- Polling 방식을 활용하여 Condition이 매칭되는지 확인 (이게 쓰레드 컨텍스트 스위칭보다 저렴한가보네)
- 아래와 같이 await()를 활용하여, 해당 시간 안에 데이터가 null로 조회되면 (그니까 조건이 true)가 되면 테스트 통과
@DisplayName("레디스에 데이터를 만료 시간을 정하여 조회할 수 있다.") @Test void setDataExpire() { // given String key = "key"; String value = "value"; redisRepository.setDataExpire(key, value, 1); // when & then String dataRightAfter = redisRepository.getData(key); assertThat(dataRightAfter).isEqualTo(value); await().atMost(1, TimeUnit.SECONDS).until(() -> { return (redisRepository.getData(key) == null); }); }
- 만약 1초 지날때까지 데이터가 expire가 안되어있다면, 아래와 같은 메시지를 뿜으며 fail
org.awaitility.core.ConditionTimeoutException: Condition with lambda expression in com.backend.connectable.global.redis.RedisRepositoryTest was not fulfilled within 1 seconds.