# Opentracing Jaeger-client golang/JAVA applicaion에 적용하기[JAVA 편]

2020. 8. 23. 14:44 개발 이야기/Golang

 

 

안녕하세요. 해커의 개발일기 입니다.

 

오늘은 마이크로 서비스 아키텍처를 사용하여 구축된 응용 프로그램을 프로파일링하고 모니터링하는 데 사용하는

Distributed Tracing 분산 추적 기술에 중!

 

 

오늘은 지난번에 소개해드렸던

https://bourbonkk.tistory.com/84?category=794341

 

# 오픈소스 OpenTracing - Jaeger

안녕하세요. 해커의 개발일기 입니다. 오늘은 마이크로 서비스 아키텍처를 사용하여 구축된 응용 프로그램을 프로파일링하고 모니터링하는데 사용하는 Distributed Tracing 분산 추적 기술에 대해서

bourbonkk.tistory.com

 

instrumentation 작업을 통해 latency를 측정하고자 하는 곳에 코드를 심어주게 되면 서비스는 그 코드를 심은 부분의 함수가 끝날 때마다 span 데이터jaeger-agentUDP 형태로 보내게 되는데요. 이때 TraceID를 함께 보내 백엔드에서는 동일한 TraceIDselect를 하게 되면 완전한 trace 정보가 완성되게 되는 원리입니다!

 

 

위의 예시 그림을 보게 되면 Servica Aspan 데이터는 총 3개(빨간색 라인)를 받았을 것이고, Service B의 span 데이터는 1개를 받았을 것입니다. jaeger-agentspan 데이터를 보내고, 이 jaeger-agentjaeger-collector에 전달을 해서 kafkaDB에 바로 넣어주게 되는데요. 이때 백엔드에서 같은 TraceID를 이용해 조회를 하게 되면 위와 같은 완전한 trace 정보가 완성되게 됩니다!~ Service A의 끝나는 시간과 Service B의 시작시간의 Gap이 바로 Network Latency가 되겠죠?

자 그러면, Jaeger와 관련해서 어떻게 하면 실제 애플리케이션에 instrumentation을 적용해서 서비스 구간구간 소요시간을 알 수 있는지 알아보도록 하겠습니다. 제가 적용해본 언어는 두 가지가 있는데요. 바로 Golang으로 작성된 appJAVA로 작성된 app입니다. 두 가지 예시를 모두 소개해드릴 생각인데요. JAVA app의 경우에는 special-agent라는 auto-instrumentation 해주는 프로젝트가 있기 때문에 이 specialagent의 사용 방법을 알려드리고, Golang실제 적용 예를 보여드리겠습니다.

먼저, JAVA 예제auto-instrumentation 해주는 special-agent입니다. 

https://github.com/opentracing-contrib/java-specialagent

 

opentracing-contrib/java-specialagent

Automatic instrumentation for 3rd-party libraries in Java applications with OpenTracing. - opentracing-contrib/java-specialagent

github.com

special-agentJAVA의 언어적 특성을 이용해서 개발자가 직접 instrumentation 코드를 삽입하지 않고 자동화시켜주는 좋은 프로젝트인데요. java 애플리케이션을 실행할 때 복사해서 -javaagent= 와 함께 실행시켜주기만 하면 됩니다.

 

 

소개 글에서도 볼 수 있듯, 손쉬운 intruments를 위해 태어났습니다. 정말 쉬운 적용방법을 보여드리겠습니다.

1. specialagent 다운로드

#Stable
wget -O opentracing-specialagent-1.7.4.jar "https://repo1.maven.org/maven2/io/opentracing/contrib/specialagent/opentracing-specialagent/1.7.4/opentracing-specialagent-1.7.4.jar"

wget을 이용해서 다운로드를 해주실 수도 있고, 아니면 위에서 소개해드린 github에서도 바로 다운로드가 가능합니다.

2. 적용방법

적용방법은 실제 3가지가 존재합니다. 1) Static Attach, 2) Dynamic Attach, 3) Static Deferred Attach가 존재합니다만 오늘은 가장 손쉽게 실행시킬 수 있는 1)Static Attach를 통해 적용하는 방법만 보여드리겠습니다.

java -javaagent:opentracing-specialagent-1.7.4.jar -jar MyApp.jar

자 이렇게 App을 실행할 때 파라미터를 App보다 앞쪽에 "-javaagent:opentracing-specialagent-1.7.4.jar" 이렇게 넣어주면 끝입니다! 참 쉽죠? 하지만 문제가 있습니다. 이 specialagent는 사실 Jaeger만을 위한 auto-instrumentation 프로젝트가 아니라 범용이기 때문입니다. 그렇다면 어떻게 해줘야 Jaeger전용의 instrumentation가 될까요?


(link to impl. of trace exporter)

(-Dsa.exporter=${short_name})

(configuration reference)
jaeger

(configuration reference)
lightstep

(configuration reference)
wavefront

(configuration reference)
otel
MockTracer mock

exporter를 설정해줘야 하는데요 우리는 jaeger에 대한 소개이니까! 아래처럼 하나만 추가해주면 됩니다.

java -Dsa.exporter=jaeger -javaagent:opentracing-specialagent-1.7.4.jar -jar MyApp.jar

 

Dockerfile을 통해 만들어보겠습니다.

FROM openjdk:8
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
COPY opentracing-specialagent-1.7.4.jar /
ENTRYPOINT ["java","-Dsa.tracer=jaeger","-Djava.security.egd=file:/dev/./urandom",
			"-javaagent:/opentracing-specialagent-1.7.4.jar","-jar","/MyApp.jar"]

끝입니다. 정말 간단하게 intrumentation 작업을 할 수 있는데요. 하지만 몇 가지 단점이 존재하기 때문에 효율적인 시스템 운영을 위해서는 사실 .. 수동 작업을 해주는 것이 좋습니다.

단점을 말씀드리면

1. 메모리 소모가 정말 눈에 띄게 높아진다 - 사실 이 부분은 메모리 소모를 줄일 수 있는 방안을 찾아볼 예정인데. 글을 시점은 아직 찾아보지 않았기 때문에 적어두겠습니다.

2. Operation name을 마음대로 정의할 수 없다. trace 데이터를 보다 보면 GET, POST 등 http 메서드와 더불어 DB에 연결되는 부분 exec 부분 등 다양한 Operation name을 볼 수 있는데요. 사실 수동으로 instrumentation 작업을 해주게 되면 이름을 마음대로 정의할 수 있지만 자동으로 하게 되면 디테일한 설정이 불가능해집니다. 왜 이 부분이 중요하냐면.. jaeger sampling을 적용할 때 이 Operation name을 이용해 sampling을 적용할 수 도 있기 때문인데요. (하나의 서비스에 특정 HTTP GET 메서드에 sampling을 주고 싶은데 GET 메서드가 /health, /list 등 두 가지 이상이지만 /health에만 sampling을 주고 싶은 경우) 그 외에는 사용자의 편리성? 때문입니다. 뭐 sampling을 디테일하게 사용하지 않는다면, 혹은 뭐 나는 괜찮다 그래도 instrumentation작업만 편하면 된다. 그러면 그냥 사용하시면 됩니다.

장점은.. 편하다.  정말

 

그리고 jaeger-client로 instrumentation 작업이 완료한 뒤 실제로 jaeger-agent로 span 데이터를 보내기 위해서는 jaeger-agent의 정보를 넣어줘야겠죠? 몇 가지 환경 변수 설정이 필요합니다.

환경변수명
JAEGER_SERVICE_NAME The service name.
JAEGER_AGENT_HOST The hostname for communicating with agent via UDP (default localhost).
JAEGER_AGENT_PORT The port for communicating with agent via UDP (default 6831).
JAEGER_SAMPLER_TYPE
The sampler type: remote, const, probabilistic, ratelimiting (default remote). See also https://www.jaegertracing.io/docs/latest/sampling/.
JAEGER_SAMPLER_PARAM The sampler parameter (number).
JAEGER_SAMPLER_MANAGER_HOST_PORT (deprecated) The HTTP endpoint when using the remote sampler.
JAEGER_SAMPLING_ENDPOINT
The URL for the sampling configuration server when using sampler type remote (default http://127.0.0.1:5778/sampling).
JAEGER_TAGS A comma separated list of name=value tracer-level tags, which get added to all reported spans. The value can also refer to an environment variable using the format ${envVarName:defaultValue}.

이렇게 설정하면 끝!

 

사실 이번 글에 JAVA와 golang을 모두 작성하려고 했지만 ,, 너무 글이 길어져서 분리를 하겠습니다. [Golang 편] 에서 Golang App의 instrumentation 작업을 하는 방법을 알아보도록 하겠습니다.