본문 바로가기

IT Book Summary/스프링 마이크로 서비스 코딩공작소

Chapter 09 스프링 클라우드 슬루스와 집킨을 이용한 분산추적

분산 디버깅을 할 수 있는 방법

  • 상관관계 ID를 사용해 여러 서비스 사이 트랜젝션 연결
  • 여러 서비스 사이 로그 데이터를 검색가능한 단일소스로 수집
  • 여러 서비스 사이 사용자 트랜잭션 흐름을 시각화 하고 특성을 이해

사용할 수 있는 세가지 기술

  • 스프링 클라우드 슬루스
    상관관계 ID 사용해 HTTP호출을 측정하는 스프링 클라우드 프로젝트
  • 페이퍼트레일
    여러 데이터소스 로그 데이터를 검색 가능항 단일 데이터서비스로 수집하는 freemium 서비스
  • 집킨
    여러 서비스 사이 트랜젝션 흐름 보여주는 오픈소스 기반 데이터 시각화 도구

9.1 스프링 클라우드 슬루스와 상관관계 ID

상관관계ID는 임의로 생성되는 고유한 숫자 또는 문자열로 트랜잭션을 시작할 때 주입됨.

6장에서 주울 필터를 사용해 유입되는 HTTP 요청을 검사하고 상관관계 ID가 없으면 삽입했다.

상관관계 ID가 있으면 사용자 정의 가능한 UseContext객체에 매핑함.

 

슬루스는 모든 코드 인프라와 복잡성을 관리

  1. 상관관계 ID가 없으면 생성하고 서비스 호출에 주입
  2. 서비스에서 나가는 호출에 대해 상관관계ID 전파를 관리해 트랜잭션의 상관관계 ID가 자동으로 나가는 호출에 추가
  3. 상관관계 정보를 스프링 MDC 로그에 추가해 생성된 상관관계 ID가 스프링 부트의 기본 SL4J와 로그백 구현으로 자동적으로 로깅.
  4. 선택적으로 서비스의 추적정보를 집킨 분산 추적 플랫폼에 전송.

1 - 라이선싱과 조직 서비스에 스프링 클라우드 슬루스 추가

 

라이선싱과 조직 서비스에 의존성 추가

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

 

 

2 - 스프링 클라우드 슬루스의 추적 분석

서비스 호출에서 생성된 로그 데이터

 

슬루스는 4개의 추적 정보를 각 로그에 추가 

1. 서비스 애플리케이션 이름

2. 추적 ID

3. 스팬 ID

4. 집킨에 추적 데이터 전송 여부

 

라이선싱 서비스와 조직서비스가 동일한 추적 ID를 공유하나 스팬 ID는 다르다.

 

 


9.2 로그 수집과 스프링 클라우드 슬루스

여러 서버사이 문제를 디버깅하려면 다음의 작업을 시도

  • 여러 서버에 로그인해 각 서버의 로그를 검사.
  • 로그를 파싱하고 관련 로그 항목을 식별하는 자체 질의 스크립트 작성.
  • 서버에 있는 로그를 백업해야 하므로 다운된 서비스 복구 과정을 연장.

분산된 서버에서 문제 디버깅은 끔찍한 일.

로그데이터를 인덱싱하고 검색할 수 있는 중앙 수집 지점을 만들어 전체 서비스 인스턴스의 모든 로그를 실시간 스트리밍.

 

통합된 로깅 아키텍처 동작방식

스프링 부트와 사용할 수 있는 로그 수집 솔루션

솔루션 구현모델 노트
Elasticsearch
Logstash
Kibana
오픈소스
상용
일반적으로 사내 구축형
범용검색엔진
ELK 스택을 이용한 로그수집
많은 핸즈온 지원필요
Graylog 오픈소스
상용
사내구축형
사내구축형으로 설계된 오픈 소스 플랫폼
Splunk 상용만지원
사내구축형과 클라우드 기반
오래되고 포과적 로그관리 및 수집도구
원래 사내구축형이나 이후 클라우드 제공
Sumo Logic 프리미움
상용
클라우드 기반
프리미움/계층형 모델
클라우드 서비스만 지원
기업용 계정으로 등록가능
Papertrail 프리미움
상용
클라우드기반
프리미움/계층형 가격모델
클라우드 서비스만 지원

 

1 - 스프링 클라우드 슬루스/페이퍼트레일의 실제 구현

 

1. 페이퍼트레일 계정을 생성, syslog 커넥터 구성

2. 모든 도커 컨테이너의 표준출력을 포착하기위해 로그스파우트 도커 컨테이너를 정의

3. 슬루스의 상관관계ID를 기반으로 질의문을 실행해 구현 테스트

 

2 - 페이퍼 트레일 계정생성과 syslog 커넥터 구성

 

Start Logging 시작

syslog는 유닉스에서 유래한 로그 메시징 포맷으로 TCP와 UDP를 사용해 로그메시지를 보냄.

3 - 도커 출력을 페이퍼트레일로 리다이렉션

 

도커데몬은 관리중인 모든 도커 컨테이너와 docker.sock 이라는 유닉스 소켓으로 통신.

실행중인 컨테이너는 docker.sock에 접속할 수 있고, 해당 서버에서 실행중인 다른 컨테이너에서 생성된 모든 메시지 수신.

docker.sock은 컨테이너가 플러그인 할 수 있고,

데몬이 실행되는 가상 서버의 도커 런타임 환경안에서 수행중인 활동을 수집할 수 있는 파이프와 같다.

 

/docker/common/docker-compose.yml

logspout:
    image: gliderlabs/logspout
    command: syslog://logs5.papertrailapp.com:21218
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

 

페이퍼 트레일 Events버튼 클릭하면 볼수있는 데이터

 

4 - 페이퍼트레일에서 슬루스의 추적 ID 검색

 

한 트랜잭션과 관련된 모든 로그 항목을 쿼리하려면 페이퍼트레일에서 이벤트 화면의 추적ID로 쿼리

 

5 - 주울로 HTTP 응답에 상관관계 ID 추가

 

6장에서 주울 API 게이트웨이를 소개하며 사후 응답필터를 작성했고 서비스에서 사용하기위해 생성한 상관관계 ID를 호출자가 반환한 HTTP 응답에 추가하였는데,

이 필터를 수정해 슬루스의 헤더를 추가할 것.

 

주울 서버에 sleuth 의존성 추가. 

 

주울 사후필터로 스프링 클라우드 슬루스의 추적 ID 추가

@Component
public class ResponseFilter extends ZuulFilter{
    private static final int  FILTER_ORDER=1;
    private static final boolean  SHOULD_FILTER=true;
    private static final Logger logger = LoggerFactory.getLogger(ResponseFilter.class);


    @Autowired 
    Tracer tracer; //추적ID 스팬ID 정보에 접근하는 진입점

    @Override
    public String filterType() {
        return "post";
    }

    @Override
    public int filterOrder() {
        return FILTER_ORDER;
    }

    @Override
    public boolean shouldFilter() {
        return SHOULD_FILTER;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.getResponse().addHeader("tmx-correlation-id", tracer.getCurrentSpan().traceIdString());
        //슬루스의 추적 ID를 전달하기 위해 'tmx-correlation-id' 새로운 HTTP 응답헤더 추가
        return null;
    }
}

 

슬루스의 추적ID 반환. 로그를 쉽게 질의


9.3 오픈집킨으로 분산 추적

여러 마이크로 서비스 간 트랜잭션 흐름을 시각화

집킨은 여러 서비스 호출사이 트랜잭션을 추적하는 분산 추적 플랫폼.

서비스별 소요된 시간과 성능문제를 파악.

 

1 - 스프링 클라우드 슬루스와 집킨 의존성 설정

 

주울과 라이선싱, 조직서비스에 zipkin 의존성 추가

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

RabbitMQ나 카프카를 이용해 집킨서버 추적데이터 전송도 가능.

 

2 - 집킨 연결을 위한 서비스 설정

 

각 서비스의 application.yml 프로퍼티 파일 설정.

spring.zipkin.baseUrl 설정

 

3 - 집킨 서버 설치 및 구성

집킨 서버에 필요한 의존성

<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
</dependency>

**스프링부트 2.0으로 집킨 서버를 사용자 구현하는건은 더이상 지원하지 않음.

 

집킨 설정이 단순하므로 @EnableZipkinServer 사용하지만

메시지큐 구성과 함께 구성하려면 @EnableSipkinStreamServer 사용.

 

집킨서버의 부트스트랩 클래스 작성

@SpringBootApplication
@EnableZipkinServer
public class ZipkinServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZipkinServerApplication.class, args);
    }
}

 

집킨 서버에 구성할 수 있는 추적데이터 백앤드 데이터 저장소

  1. 인메모리 데이터
  2. MySQL
  3. 카산드라
  4. Elasticsearch

운영시에는 인메모리는 사용 x

 

4 - 추적 레벨 결정

 

각 서비스가 집킨에 데이터를 기록할 빈 정의

집킨의 기본설정에 따라 전체 트랜잭션의 10%만 집킨서버에 리골

트랜잭션 샘플링은 집킨으로 데이터를 전송하는 각 서비스의 스프링 프로퍼티를 설정해 제어.

sping.sleuth.sampler.percentage 0과 1 사이 값.

 

@Bean

public Sampler defaultSampler() { return Sampler.ALWAYS_SAMPLE; }

 

5 - 집킨으로 트랜잭션 추적

 

사용자 트랜잭션에 속한 모든 서비스와 개별 성능시간을 이해하는것은 분산 아키텍처를 지원하는데 매우 중요.

각 트랜잭션은 하나 이상의 스팬으로 나뉨. 집킨에서 스팬은 타미미이 정보가 포함된 특정 서비스나 특정 호출을 나타냄.

 

주울 게이트웨이는 유입되는 HTTP 호출이 있다면 그 호출을 종료한 후 대상서비스로 새로운 호출을 만들어 호출.

주울은 게이트웨이로 들어가는 개별호출에 사전, 응답, 사후 필터를 추가할 수 있다. 주울에서 스팬이 2개로 보이는 이유.

 

집킨 질의 화면에서 추적 서비스를 선택하고 여러가지 기본 징의 필터를 사용
트랜잭션 작업에 각 스팬에 소요되는 시간 파악
각 스팬을 클릭하면 호출시간 및 HTTP 호출 세부정보 제공

 

6 - 복잡한 트랜잭션 시각화

 

서비스 호출사이 어떤 서비스 의존성이 존재하는지 알고싶다면

주울로 라이선싱 서비스를 호출한 후 라이선싱 서비스 추적을 위해 집킨에 질의

 

주울 게이트웨이 호출 - 라이선싱 서비스 호출 - 주울로 다시 조직서비스 호출

상세 추적내용 확인

 

7 - 메시징 추적 수집

 

슬루스는 서비스에 등록된 인바운드 또는 아웃바운드 메시지 채널에 대한 추적 데이터도 집킨에 전송.

 

슬루스와 집킨을 사용하면 메시지가 큐에 발행된 시점과 수신된 시점을 확인 가능함.

큐에 수신되고 처리될때 발생하는 동작을 확인.

 

HTTP 응답 필드에 반환된 추적 ID 사용해 트랜잭션 찾기
슬루스는 메시지 채널에서 메시지 발행과 수신을 자동으로 추적
카프카 메시지가 수신되어 호출된 라이선싱 서비스 검색
집킨으로 조직서비스가 발행한 카프카 메시지

 

8 - 사용자 정의 스팬 추가

 

라이선싱 서비스가 레디스를 호출할 때 사용자 정의 스팬을 추가

 

레디스에서 라이선싱 데이터를 읽어오는 호출 측정

@Component
public class OrganizationRestTemplateClient {
    @Autowired
    RestTemplate restTemplate;

    @Autowired
    Tracer tracer;

    @Autowired
    OrganizationRedisRepository orgRedisRepo;

    private static final Logger logger = LoggerFactory.getLogger(OrganizationRestTemplateClient.class);

    private Organization checkRedisCache(String organizationId) {
       Span newSpan = tracer.createSpan("readLicensingDataFromRedis");
        try {
            return orgRedisRepo.findOrganization(organizationId);
        }
        catch (Exception ex){
            logger.error("Error encountered while trying to retrieve organization {} check Redis Cache.  Exception {}", organizationId, ex);
            return null;
        }
        finally {
          newSpan.tag("peer.service", "redis");
          newSpan.logEvent(org.springframework.cloud.sleuth.Span.CLIENT_RECV);
          tracer.close(newSpan);
        }
    }
}

 

계측이 적용된 getOrg() 메서드

@Service
public class OrganizationService {
    @Autowired
    private OrganizationRepository orgRepository;

    @Autowired
    private Tracer tracer;

    @Autowired
    SimpleSourceBean simpleSourceBean;

    private static final Logger logger = LoggerFactory.getLogger(OrganizationService.class);

    public Organization getOrg
            (String organizationId) {
        Span newSpan = tracer.createSpan("getOrgDBCall");

        logger.debug("In the organizationService.getOrg() call");
        try {
            return orgRepository.findById(organizationId);
        }
        finally{
          newSpan.tag("peer.service", "postgres");
          newSpan.logEvent(org.springframework.cloud.sleuth.Span.CLIENT_RECV);
          tracer.close(newSpan);
        }
    }
}

 

2개의 사용자 정의 스팬을 적용한 후 서비스 재시작 

엔드포인트 GET 호출

http://localhost:5555/api/licensing/v1/organizations/e254f8c-c442 -4ebe-a82a-e2fc1d1ff78a/licenses/f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a

 

라이선싱 정보를 검색할 때 추가된 사용자 정의 스팬 보여줌.

사용자 정의 스팬이 정의되면 트랜젝션 추적시 확인 가능.

 


  • 스프링 클라우드 슬루스를 사용해 마이크로서비스 호출에 상관관계 ID 추가
  • 상관관계 ID는 여러 서비스 사이 로그 항목을 연결하는데 사용
  • 로그를 수집하고 수집된 내용을 검색, 질의하는 수집 플랫폼과 상관관계 ID가 함께 함.
  • 클라우드 기반 서비스 사용해 로그를 관리하면 쉽게 확장 가능
  • 도커 컨테이너 로그 스파우트와 클라우드 로깅 플랫폼 페이퍼트레일 과 통합해 로그 수집
  • 집킨을 사용해 서비스 호출사이 존재하는 의존성을 시각적으로 확인
  • 슬루스는 집킨과 통합
  • 슬루스가 활성화된 서비스에 사용되는 HTTP 호출과 메시지 채널에 대한 추적데이터 자동으로 포착
  • 슬루스는 각 서비스 호출을 스팬개념에 매핑. 집킨에서 각 스팬의 성능 확인.
  • 슬루스와 집킨에서 스프링기반이 아닌 지원(Postgres,레디스)의 성능을 파악하도록 사용자 정의 스팬을 재정의.