지난 블로그를 보면 검색에 대한 생각을 적어놨다.
ElasticSearch와 Mysql Index 에 대한 간단한 개인 의견을 적어놓았다.
추가적으로 캐시를 적용하면 어떻게 될까를 테스트 하기 위해 이번블로그를 적는다.
저번 블로그에서 "Mysql Index + 캐시를 사용한다면 ElasticSearch 만큼의 성능이 나오지 않을까" 에 대한 고민을 했었다.
고민의 결과는 Mysql, ElasticSearch 둘다 캐시를 사용하면 검색기능이 향상된다.
왜냐하면 캐시의 개념자체가 임시 메모리에 똑같은 요청에 대한 데이터를 저장하기에 캐시를 사용하면
Mysql를 사용하던 ElasticSearch를 사용하던 임시 메모리에서 캐시 데이터를 가져온다.
그래서 Redis를 이용한 캐시를 예제를 짜보았다.
Redis Config
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Value ("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(redisHost, redisPort);
}
@Bean
public CacheManager testCacheManager(RedisConnectionFactory cf) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.entryTtl(Duration.ofMinutes(3L));
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(cf).cacheDefaults(redisCacheConfiguration).build();
}
}
entryTtl를 통해 캐쉬를 3분동안 유지하도록 하였다.
Controller, Service, Repository
@RestController
@RequiredArgsConstructor
public class TestController {
private final TestService testService;
@GetMapping("/cache/{id}")
public List <UserDto> getCache(@PathVariable Long id) {
return testService.getUser(id);
}
@GetMapping("/noCache/{id}")
public List <UserDto> getNoCache(@PathVariable Long id) {
return testService.getUserNoCache(id);
}
}
cache -> Mysql Index + Redis 캐쉬를 이용
noCache -> Mysql Index만 이용
@Service
@RequiredArgsConstructor
public class TestService {
private final UserRepository userRepository;
@Cacheable(cacheNames = "walkerList",key = "#id",unless ="#result ==null")
public List <UserDto> getUser(Long id) {
User user = userRepository.findById(id).get();
double x = user.getLocation().getX();
double y = user.getLocation().getY();
String point = "POINT("+y+" "+x+")";
List <User> usersWithinDistance = userRepository.findUsersWithinDistance(point, 500 , "test999%" ,
PageRequest.of(0 , 10)).getContent();
return usersWithinDistance.stream()
.map(nowUser -> UserDto.from(nowUser))
.collect(Collectors.toList());
}
public List <UserDto> getUserNoCache(Long id) {
User user = userRepository.findById(id).get();
double x = user.getLocation().getX();
double y = user.getLocation().getY();
String point = "POINT("+y+" "+x+")";
List <User> usersWithinDistance = userRepository.findUsersWithinDistance(point, 500 , "test999%" ,
PageRequest.of(0 , 10)).getContent();
return usersWithinDistance.stream()
.map(nowUser -> UserDto.from(nowUser))
.collect(Collectors.toList());
}
}
getUser -> Redis 캐싯 이용
getUserNoCache -> 캐시 이용 X
Repository
@Query(value = "SELECT * FROM users u WHERE " +
"ST_CONTAINS(ST_Buffer(ST_PointFromText(:point, 4326), :buffer), u.location) " +
"AND u.user_name LIKE :namePattern ",
nativeQuery = true)
Page<User> findUsersWithinDistance(@Param("point") String point,
@Param("buffer") int buffer,
@Param("namePattern") String namePattern,
Pageable pageable);
Redis Cache 이용하지 않고 MySQL 인덱스 이용할때 검색 속도
1회 | 387 |
2회 | 129 |
3회 | 138 |
4회 | 131 |
5회 | 128 |
6회 | 140 |
7회 | 124 |
8회 | 132 |
9회 | 129 |
10회 | 126 |
평균 156.4ms
Redis Cache 이용하고 Mysql 인덱스 이용할때 검색 속도
1회 | 390 |
2회 | 46 |
3회 | 8 |
4회 | 5 |
5회 | 8 |
6회 | 5 |
7회 | 7 |
8회 | 7 |
9회 | 8 |
10회 | 5 |
평균 : 48.9 ms
와... 그냥 캐시메모리에서 데이터 꺼내니까 확연히 단축되어버렸다..
백분율로 나타내면 (156.4-48.9)/156.4 * 100 = 68.75%
거의 68% 속도가 단축되었다..
물론 항상 cached hit한다는 보장은 없지만 최소한 반복되는 검색에 대해서는 확연히 단축됨을 볼 수 있다..
(보장없다는 말은 모든 검색어에 대해서 캐시되는게 아니라서)
지금 캐시에 대해 정리해보니... 후회되는 점은 Mysql Index 와 Redis 캐시를 비교해볼껄..이다..
캐시를 생각치 못했긴 했지만 Mysql과 Redis를 이용하는 것이 기존 것을 활용한다는 점에서 비용과 시간 절약에 도움이 더 될것같다.
앞서 이야기 했듯이 ElasticSearch는 또하나의 DB라서 새로운 기술과 관리에 대한 비용이 발생한다.
음.. 일단 프로젝트 리팩토링 하고 캐시 적용은 조금만더 고민해보야할것같다..!
'프로젝트 > 개인 프로젝트(2023.11.13-2023.12.18)' 카테고리의 다른 글
[개인프로젝트] ElasitcSearch 에 대해 좀 더 공부해보자 (2) (0) | 2024.03.11 |
---|---|
[개인프로젝트] ElasitcSearch 에 대해 좀 더 공부해보자 (1) (0) | 2024.03.11 |
[개인프로젝트] 검색기능에 대한 생각 및 회고 (1) (4) | 2024.03.05 |
[개인프로젝트] 코드 커버리지?? (0) | 2024.02.22 |
[개인프로젝트] ElasticSearch와 Mysql 쿼리 실행시간 (2) (인덱스 걸기) (0) | 2024.02.19 |