Pinpoint spring_camp 2015

  • View
    1.076

  • Download
    0

  • Category

    Software

Preview:

Citation preview

Pinpoint

대규모분산환경추적플랫폼

강운덕

2015-04-18

2

발표자

• Backend Java developer• 2006~

• JAVA FRAMEWORK개발/지원

• 비동기 JAVA 네크워크라이브러리

• JAVA 트러블슈팅• Heap dump, thread dump• Open source patch, Debugging• Multi Thread, Concurrency

• Pinpoint Technical Leader

3

발표자

4

목차

• Why

• 소개

• 기술개요

• 어려운점

• 로드맵

5

Why

A long time ago. in a galaxy far, far away

6

Why

NOW

7

Why

• 상황• 수십수백대의서버

• 많은소프트웨어모듈

• 복잡하게연동된서비스

• 문제• 어떻게연동되고있는지파악안됨

• 다른서비스에의해장애가발생

• 개별서버에대한모니터링으로는연관관계파악이안됨.

• 새로운해결책이필요

8

Why

9

Why

10

Why

11

Why

12

Why

13

Why

• 트러블슈팅이힘들다.

• 콘솔 들어가기 싫다

• 수십기가의 로그

• 환경, 옵션

• 수많은 종류의 라이브러리 + 다양한 버전의 라이브러리

• 야근하기 싫다

• 자신을자동화

• 트러블슈팅시 생각하던 바, 관찰하던뷰를 다른 사람에게도 제공

• 글로 문제를 설명하려니 어렵더라

• 잘못된 분석으로 인해 문제가 재발

14

Why

• 트러블슈팅을계속하다보니안정화되어할일이줄음

15

You’re Fired!!!

16

진정한 해결책

• http://www.hanbit.co.kr/events/eventview.html?event_id=freebook

17

소개

http://github.com/naver/pinpoint

• 분산트랜잭션 추적

• 애플리케이션 토폴로지 자동 발견

• 수평확장성

• 코드 수준의 가시성

• 코드를 수정하지 않고 성능정보 수집

18

소개

19

풀어야 할 문제

RPC 추적의 의미

Node1과 Node2 사이의 RPC간의관계를 어떻게 찾을것인가?

메시지를 연관관계를 나타내는 TAG

20

TAG 동작

• Span : RPC 추적을 위한 기본 단위. RPC가 도착했을 때 처리한 작업

• Trace : 연관된 Span의 집합. Span의 집합은 TransactionId가같음.

Trace는 SpanId와 ParaentSpanID를 통해 트리 구조로 정렬됨

• TraceId

• TrasantionId는 message id로 전체 서버군에서 unique 한 아이디• SpanId, ParentId로 message의관계를 정렬

21

Bytecode instrumentation

22

설치

• Java 실행시 JavaAgent 설정추가

-javaagent:$PINPOINT_PATH/pinpoint-bootstrap-$VERSION.jar

-Dpinpoint.applicationName=“$AGENT_GROUP_NAME”

-Dpinpoint.agentId =“$AGENT_UNIQUEUE_ID”

23

핵심가치

• 분산 RPC 추적

• 코드를수정하지않음

24

TomcatA

어플리케이션 적용 예

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Hello world! sample

25

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

어플리케이션 적용 예

26

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

어플리케이션 적용 예

27

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

어플리케이션 적용 예

28

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

어플리케이션 적용 예

29

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

어플리케이션 적용 예

30

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

어플리케이션 적용 예

31

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

• TraceId 생성

TRANSACTION_ID : 전체 RPC 호출을 하나로 묶을수 있는 Key

SPAN_ID : 나의 ID

PARENT_SPAN_ID : 부모의 ID

내부동작

32

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

• TraceId 생성

TRANSACTION_ID : TomcatA^시작시간^1

SPAN_ID : 10 (Random)

PARENT_SPAN_ID : -1 (ROOT)

내부동작

33

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

• Spring Controller Method 레코딩

내부동작

34

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

• HttpClient.execute()의호출을 가로채서 HttpGet에 TRACE_ID를 세팅한다.

• Child TraceId 생성

TRANSACTION_ID : TomcatA^시작시간^1 -> TomcatA^시작시간^1

SPAN_ID : 10 -> 20

PARENT_SPAN_ID : -1 -> 10

• Child TraceId 를 HttpGet에세팅

HttpGet.setHeader(PINPOINT_TRANSACTION_ID, “TomcatA^시작시간^1”)

HttpGet.setHeader(PINPOINT_SPAN_ID, “20”)

HttpGet.setHeader(PINPOINT_PARENT_SPAN_ID, “10”)

내부동작

35

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

• TAG된 Request를 TomcatB로전송.

Tag

Request

내부동작

36

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

• TomcatB accept

Check Header : HttpServletRequest.getHeader(PINPOINT_TRANSACTION_ID)

• Header에서 TraceId 를 인식하여 Child로 동작

TRANSACTION_ID : TomcatA^시작시간^1

SPAN_ID : 20

PARENT_SPAN_ID : 10

Tag

Request

내부동작

37

TomcatA@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

HBase

TRANSACTION_ID : TomcatA^시작시간^1

SPAN_ID : 20

PARENT_SPAN_ID : 10

Collector

RowKey

TomcatA^시작시간^1

20

10Hello() 호출정보

TraceData

내부동작

38

TomcatA

@Controller

public class TestController {

@RequestMapping("/test")

@ResponseBody

public String test() throws IOException {

HttpGet get = new HttpGet("http://TomcatB/hello");

HttpResponse response = httpClient.execute(get);

return EntityUtils.toString(response.getEntity());

}

}

TomcatB

@Controller

public class HelloController {

@RequestMapping("/hello")

@ResponseBody

public String hello() {

return "world!";

}

}

• Distributed Transaction TAG

HBase

TRANSACTION_ID : TomcatA^시작시간^1

SPAN_ID : 10

PARENT_SPAN_ID : -1

Collector

RowKey

TomcatA^시작시간^1

20 10

10Hello() 호출정보

-1Test() 호출정보

TraceData

내부동작

39

RowKey

TomcatA^시작시간^1

20 10

10Hello() 호출정보

-1Test() 호출정보

HBase

UI

내부동작

40

트러블 슈팅

• 인프라의 각 구성요소가 정상적으로구축이 되었는가?

• 해외Proxy에서 한국의 특정 서버로사용자 요청의 흐름이 기대한 대로 인가?

• 응답시간이 느린 구간과 API가 있는가?

• 느린 구간에 대한 프로파일링 데이타 제공

• 성능 패턴 데이타 제공

• 개발->QA->운영단계에서의 연속적인 확인

41

어려운점

42

WARNING

• HBase도죽고

• HBASE-7711 https://issues.apache.org/jira/browse/HBASE-7711

• Hadoop 무한루프까지

• HDFS-5225 https://issues.apache.org/jira/browse/HDFS-5225

• HBase, Hadoop 클러스터를재시작해도회복이안됨

43

WARNING

44

WARNING

• 가능한최신버전을 Hadoop 패밀리사용

• 관리되는 Cloudera(CDH), Hortonworks(HDP) 권장

• Pinpoint를사용하는사람은 Java 개발자

• 겸사겸사 HBase, Hadoop도살펴보고, 기왕이면소스도까보자

• 사실저도다 모릅니다.

- 뭐든지 아는건 아니야. 알고 있는것만알뿐

45

WARNING

혹시아나요?

HBase, Hadoop, Zookeeper의전문가가될지

망할거같지는않잖아요

개인의노력을투자해봅시다

46

WARNING

지금여러분이전문가가될 수도있지않을까요?

47

WARNING

사실그걸노리고선택한 Backend입니다.

48

다행인 점

• 설계사상

• Pinpoint의 backend가죽어도 Application은장애가발생하면

안된다.

• Collector

• HBase

• Hadoop

• 최우선순위는성능데이터수집 X

• Application이정상적으로돌아가는게최우선

49

다행인 점

• 뭐든그렇지만말로는다됨

• 큰소리땅땅~~

“아! 걱정마시라깐요. 저를 믿으셈.

모든건 계획대로~”

50

다행인 점

51

다행인 점

• 검증되었습니다

• 직접체험

• 한계는분명. 버그는커버불가능

• 개발에서검증 -> 운영

• 버그가 발생하면 신고해주세요. 큰 도움이 됩니다.

• 버그는 계획에 없었던 일

52

로드맵

• 알람 / Admin

• 실시간데이터

• EndUser 모니터링

• 지원라이브러리추가

• 개발가이드

• D2 Open Seminar (Java성능 + Pinpoint) 5월?

53

감사합니다.

http://github.com/naver/pinpoint

http://helloworld.naver.com/helloworld

/1194202