본문 바로가기

Programming!

@Cacheable (Redis) 의 장애 대응용으로 Hystrix 사용

https://github.com/Netflix/Hystrix/wiki/Configuration

 

Netflix/Hystrix

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex di...

github.com

캐시를 여기저기 많이 붙여 사용함. 

@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

 

KimHyeongi/Springboot-Tips

나의 개발 메모. Contribute to KimHyeongi/Springboot-Tips development by creating an account on GitHub.

github.com