springboot 문서를 참고 하면 /metrics 에 cache hit ratio 가 노출된다고 나온다 ( https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-metrics.html#production-ready-datasource-cache ) 하지만 그 리스트에 Caffeine 을 지원한 다는 얘기는 없다.  기본적으로 chche size는 metrics 에 노출이 되지만, hit/miss ratio는 노출이 되지 않으므로 구현이 필요하다.

현재 상황 : 

지원 목록 : EhCache, Hazelcast, Infinispan, JCache and Guava


확인 : 문서에 나온대로 CacheStatisticsAutoConfiguration, CacheStatisticsProvider 를 사용하면 가능 할 것 같다.

그래서 아래와 같은 Spring Bean을 등록

@Bean
public CacheStatisticsProvider<CaffeineCache> getCaffeineCacheStatisticsProvider() {
return (cacheManager, cache) -> {
DefaultCacheStatistics statistics = new DefaultCacheStatistics();
CacheStats status = cache.getNativeCache().stats();
long result = status.requestCount();
if (result > 0) {
statistics.setSize(cache.getNativeCache().estimatedSize());
statistics.setHitRatio(status.hitRate());
statistics.setMissRatio(status.missRate());
}
return statistics;
};
}

 

이후 실행을 해보았지만, 원하는 대로 노출이 안되었다. Caffeine 쪽에서 해답을 얻을 수 있었다. 아래 내용을 참고 하여 기존 Cache를 만드는 부분에  아래 부분을 추가하였다.

.recordStats()

참고 링크 : https://github.com/ben-manes/caffeine/wiki/Statistics


결과 : http://localhost:8080/metrics

  • cache.product.miss.ratio0.42857142857142855,
  • cache.product.hit.ratio0.5714285714285714,
  • cache.product.size3,


추가 : SpringBoot 2.0 부터는 micrometer 기반으로 caffeine로 지원을 한다. 

stream kafka app 에 rabbitmq sleuth 사용하기

Cloud 2018.01.31 20:06 posted by dev.bistro

현재 팀은 SpringBoot application 을  좀 더 운영하기 쉽도록 하기 위해서 starter를 하나 생성해서 사용하고 있다.

cloud-netflix 셋팅과, 그 많고 많은 zuul, eureka 버그 픽스를 위한 몇몇 코드, 그리고 config server를 기반으로 한 다양한 설정들을 공통화 하기 위한 목적이다. 현재 진행 하는 프로젝트는 이 starter 를 쓰지 않고 순수하게 spring/kafka 만을 사용 하고 있다.

이 프로젝트를 위해 별도의 metrics 시스템을 구축하기 보다는 기존의 sleuth-zipkin 인프라를 활용하기 위해서 spring-cloud-sleuth-stream을 사용하려 한다.


1. gradle 설정 추가

['stream-kafka'].collect {
compile "org.springframework.cloud:spring-cloud-starter-$it"
}
compile 'org.springframework.cloud:spring-cloud-stream'

에서 

compile 'org.springframework.cloud:spring-cloud-sleuth-stream'
compile 'org.springframework.cloud:spring-cloud-stream-rabbit'
compile "org.springframework.cloud:spring-cloud-starter-sleuth'

를 추가하였다.


2. 설정 추가

spring:
application:
name: pacman
rabbitmq:
addresses: 172.18.176.196:5672
username: rabbitmq
password: rabbitmq
sleuth:
sampler:
percentage: 1.0
stream:
enabled: true
zipkin:
service:
name: vine-event-pacman

* zipkin.service.name 을 추가해야만 했다. application.name 을 그대로 사용 할 줄 알았는데.. 어디선가 자동으로 해주고 있는 거였나보다.

이렇게만 설정하면 아래와 같은 에러를 볼 수 있다.  

현재 우리의 zipkin은 rabbitmq 기반인데, 하필이면 이 프로젝트는 binder로 kafka를 사용하고 있었다.
당연하게 stream binder로 kafka, rabbit를 동시에 쓰고 있어서 발생한 문제였고, DefaultBinderFactory 를 확인하여 default binder 를 설정함으로서 해결 할 수 있었다.

Caused by: java.lang.IllegalStateException: A default binder has been requested, but there is more than one binder available for 'org.springframework.integration.channel.DirectChannel' : kafka,rabbit, and no default binder has been set

cloud:
stream:
default-binder: "rabbit"



kafka stream의 fail-over & high-availability

Cloud 2018.01.30 19:55 posted by dev.bistro

18/01/30 idea


카프카 자체의 data recovery는 훌륭하다. 당연한게 파일로 저장하고 심지어 여러 셋트로 저장한다. 유실되는 경우는 저장 기간을 넘기거나, 1개의 IDC에만 설치한 후 IDC가 물에 잠기는 방법 뿐이다. 이건 다 아는 얘기고, 문제는 이 kafka 를 기반으로 한 streams 를 서비스 할 때이다.


1. Kafka는 기본적으로 1 개의 TopicPartion 에서 1 개의 Consumer Group의 노드가 접속 한다.

2. Kafka Topic은 KStream/KTsble/StateStore 등을 통해서 각각의 topic-partition을  local DB에 싱크를 맞춘후 materilized 한다  (비동기/latency 존재)


우선 1번의 문제부터....

1. 해당 TopicPartion의 정보를 단 1개의 VM(instance)만이 가지고 있을 수 있다 (Application Cluster 자체를 active-standby로 구성하지 않는이상)

 이 얘기는 해당 Node가 죽어버리면 '그 순간' 그 데이터들은 VM instnace안에서 존재 하지 않는 다는 것이다. 

 물론 Kafka Broker 내에는 존재하기 때문에 일정 시간의 기다린다면 새로운 Instacne가 해당 데이터를 살릴 수 있다. 하지만 그 '일정 시간의 텀'이 문제이다.

 위에서 얘기한 데로 Application 자체를 standby로 준비하지 않는 이상 힘들다. kafka 역시 standby 로 해결한다.

 링크 : https://kafka.apache.org/10/documentation/streams/developer-guide/config-streams.html#id10

 동일한 셋을 하나 더 구성하지만 그 녀석은 말그대로 standby이다. 실제 서비스에는 투입이 되지 않으며, resource 역시 많이 차지하지만, 장애 시간을 짧게 가져가는데 필수적인 요소이다.

 StreamThread 내에서 task를 active 와 standby로 가지고 있다. 


 이 부분은 ... 계속 파야할 것 같다.



2. Event가 topic으로 전송이 된다면 해당 topic-partition을 materialized view 로 가지고 있는 consuer group 의 instance는 consumer로 붙는다.

   이 때 topic과 state-store의 데이터 불일치는 필연적이다.

   이 때 state-store에서 get을 하는 '재고차감' 같은 Domain은 어떤 식으로 처리 할 것인가?

   A. 모든것을 sync로 한다 - 의미 없으니 pass

   B. instance의 state-store를 ReadyOnlyQueryType으로 사용하는게 아닌 WriteableQueryType으로 사용하여, put도 할 수 있게 한다. 그리고 이 changelog는 

      remote kafka cluster와 연동한다. 

      atmoic을 보장 할 수 있는 방법이고, 서버가 죽었을때도 문제가 되지 않는다. 내부 rocksdb에 데이터는 유지되므로 다시 살리기만 한다면 cluster와 동기화를 할 수 있을테니까..

      문제는 server가 살릴수 없을 때이다. 이 이슈는 바로 데이터 유실로 이어진다.



적당한 방법들은 보이지만, 정답인지 아닌지 확신이 안선다.

      





티스토리 툴바