https://github.com/Netflix/Hystrix/wiki/Configuration
캐시를 여기저기 많이 붙여 사용함.
@Cachable(key="#{id}", value="cache_xxxxxx")
public Xxxxx findById( Long id ){
.....
return xxxxx;
}
여기저기 이렇게..
근데 가끔 Redis의 문제인지 네트웍의 문제인지 아니면 Spring 서버의 문제인지 알 수 없는 이유로 redis 서버 접근이 불가능해지고, 그와 함께 redis timeout까지 대기 및 db pool의 문제까지 확장된 장애가 발생한다.
(가끔 큰 장애를 보면 redis의 서버 장애가 많은 비중을 차지 하더라..)
가볍게 해당 장애를 우회 하는 예제를 만들어 보자. 이전 몇년전이더라... hystrix에 대해 기본 샘플 구성을 해본적이 있는데..
( https://eclipse4j.tistory.com/223 ..2016년도네..ㅎㅎ )
여튼 hystrix는 요즘 많이 알려졌고 더 좋은 프레임웍도 나왔긴 한데.. 쓰던걸로..
Spring Boot 1.x
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-hystrix', version: '1.4.7.RELEASE'
Spring Boot 2.x
compile group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-hystrix', version: '2.2.3.RELEASE'
우선 redis의 timeout 시간을 최대한 짧게 잡는다. 실제 1초, 최대 2초동안 커넥션후 응답이 없으면 캐시로서는 의미 없기 때문에 3초로 잡자.(?!)
redis:
host: minor-xxxx
port: 6379
lettuce:
pool:
max-active: 10
...
timeout: 3000
이렇게 되면 캐시사용으로 Redis 접근시 커넥션 오류로 3초내에 처리가 안되면 (실제 서버가 내려가 있는경우는 바로 접속오류가 난다 - 1초 Hystrix default) 예외가 발생한다.
@EnableCircuitBreaker
public ...Application {
호출할 컨트롤러를 만들자
@RequiredArgsConstructor
@RestController
public class RedisController {
private final RedisService redisService;
@GetMapping("/redis")
public String health(){
return redisService.redis("100");
}
}
RedisService 도
@Slf4j
@Service
@RequiredArgsConstructor
public class RedisService {
private final RedisCacheableService service;
@HystrixCommand(fallbackMethod = "getDB")
public String redis(String id) {
log.info("========= REDIS ==============");
log.info("========= {} ==============", id);
return service.redis(id);
}
public String getDB(String id) {
log.info("========= DB ==============");
log.info("========= {} ==============", id);
return "DB";
}
}
HystrixCommand의 Properties가 상당히 많고 규칙도 다양하니 위에있는 사이트나 기타 사이트 참조.
참고로 다음과 같이하면 안된다. 실패다 실패!!
Spring 구조를 보면 아래 처럼 하면 안된다는 것을 알 수 있다.
굳이 하고자 한다면 Bean의 순서를 지정하면서 설정Bean을 처리해야 하는데 이후를 생각해서라도 그렇게는 하지 않는게...
// Fail Code
@HystrixCommand(fallbackMethod = "getDB")
@Cacheable(value = "redis", key = "#id")
public String redis(String id) {
log.info("========= REDIS ==============");
log.info("========= {} ==============", id);
return service.redis(id);
}
RedisCacheableService
@Slf4j
@Service
public class RedisCacheableService {
@Cacheable(value = "redis", key = "#id")
public String redis(String id) {
log.info("========= REDIS ==============");
return "REDIS";
}
}
이제 Spring Application 을 시작해서 브라우져로 접근해보자.
(참고로 로컬에 Docker Redis를 인스톨해서 테스트 해보면 된다.)
http://localhost:8080/redis
그럼 이제 redis를 셧다운 시키자.
http://localhost:8080/redis
로그를 확인해도 마찬가지.
물론 이렇게된 상태로 운영하면 DB에 커넥션 소실이 늘어나서 운영할 수 없게 된다. 그러니 db를 보는 getDB 도 local cache 로 전환해 주는게 좋다. Cachemanager 에서 Ehcache, Caffeine 같은 것으로 넘겨주자.
대충예제는
github.com/KimHyeongi/Springboot-Tips