Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Pinpoint spring_camp 2015

3,799 views

Published on

Pinpoint(open source APM) https://github.com/naver/pinpoint

Published in: Software

Pinpoint spring_camp 2015

  1. 1. Pinpoint 대규모분산환경추적플랫폼 강운덕 2015-04-18
  2. 2. 2 발표자 • Backend Java developer • 2006~ • JAVA FRAMEWORK 개발/지원 • 비동기 JAVA 네크워크 라이브러리 • JAVA 트러블 슈팅 • Heap dump, thread dump • Open source patch, Debugging • Multi Thread, Concurrency • Pinpoint Technical Leader
  3. 3. 3 발표자
  4. 4. 4 목차 • Why • 소개 • 기술 개요 • 어려운점 • 로드맵
  5. 5. 5 Why A long time ago. in a galaxy far, far away
  6. 6. 6 Why NOW
  7. 7. 7 Why • 상황 • 수십 수백대의 서버 • 많은 소프트웨어 모듈 • 복잡하게 연동된 서비스 • 문제 • 어떻게 연동되고 있는지 파악안됨 • 다른 서비스에 의해 장애가 발생 • 개별 서버에 대한 모니터링으로는 연관관계 파악이 안됨. • 새로운 해결책이 필요
  8. 8. 8 Why
  9. 9. 9 Why
  10. 10. 10 Why
  11. 11. 11 Why
  12. 12. 12 Why
  13. 13. 13 Why • 트러블 슈팅이 힘들다. • 콘솔 들어가기 싫다 • 수십기가의 로그 • 환경, 옵션 • 수많은 종류의 라이브러리 + 다양한 버전의 라이브러리 • 야근하기 싫다 • 자신을 자동화 • 트러블슈팅시 생각하던 바, 관찰하던 뷰를 다른 사람에게도 제공 • 글로 문제를 설명하려니 어렵더라 • 잘못된 분석으로 인해 문제가 재발
  14. 14. 14 Why • 트러블 슈팅을 계속 하다보니 안정화되어 할일이 줄음
  15. 15. 15 You’re Fired!!!
  16. 16. 16 진정한 해결책 • http://www.hanbit.co.kr/events/eventview.html?event_id=freebook
  17. 17. 17 소개 http://github.com/naver/pinpoint • 분산트랜잭션 추적 • 애플리케이션 토폴로지 자동 발견 • 수평확장성 • 코드 수준의 가시성 • 코드를 수정하지 않고 성능정보 수집
  18. 18. 18 소개
  19. 19. 19 풀어야 할 문제 RPC 추적의 의미 Node1과 Node2 사이의 RPC간의 관계를 어떻게 찾을것인가? 메시지를 연관관계를 나타내는 TAG
  20. 20. 20 TAG 동작 • Span : RPC 추적을 위한 기본 단위. RPC가 도착했을 때 처리한 작업 • Trace : 연관된 Span의 집합. Span의 집합은 TransactionId가 같음. Trace는 SpanId와 ParaentSpanID를 통해 트리 구조로 정렬됨 • TraceId • TrasantionId는 message id로 전체 서버군에서 unique 한 아이디 • SpanId, ParentId로 message의 관계를 정렬
  21. 21. 21 Bytecode instrumentation
  22. 22. 22 설치 • Java 실행시 JavaAgent 설정추가 -javaagent:$PINPOINT_PATH/pinpoint-bootstrap-$VERSION.jar -Dpinpoint.applicationName=“$AGENT_GROUP_NAME” -Dpinpoint.agentId =“$AGENT_UNIQUEUE_ID”
  23. 23. 23 핵심가치 • 분산 RPC 추적 • 코드를 수정하지 않음
  24. 24. 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. 25. 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. 26. 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. 27. 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. 28. 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. 29. 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. 30. 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. 31. 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. 32. 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. 33. 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. 34. 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. 35. 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. 36. 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. 37. 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 10 Hello() 호출정보 TraceData 내부동작
  38. 38. 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 10 Hello() 호출정보 -1 Test() 호출정보 TraceData 내부동작
  39. 39. 39 RowKey TomcatA^시작시간^1 20 10 10 Hello() 호출정보 -1 Test() 호출정보 HBase UI 내부동작
  40. 40. 40 트러블 슈팅 • 인프라의 각 구성요소가 정상적으로 구축이 되었는가? • 해외Proxy에서 한국의 특정 서버로 사용자 요청의 흐름이 기대한 대로 인가? • 응답시간이 느린 구간과 API가 있는가? • 느린 구간에 대한 프로파일링 데이타 제공 • 성능 패턴 데이타 제공 • 개발->QA->운영단계에서의 연속적인 확인
  41. 41. 41 어려운점
  42. 42. 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. 43. 43 WARNING
  44. 44. 44 WARNING • 가능한 최신 버전을 Hadoop 패밀리 사용 • 관리되는 Cloudera(CDH), Hortonworks(HDP) 권장 • Pinpoint를 사용하는 사람은 Java 개발자 • 겸사겸사 HBase, Hadoop도 살펴보고, 기왕이면 소스도 까보자 • 사실 저도 다 모릅니다. - 뭐든지 아는건 아니야. 알고 있는것만 알뿐
  45. 45. 45 WARNING 혹시 아나요? HBase, Hadoop, Zookeeper의 전문가가 될지 망할거 같지는 않잖아요 개인의 노력을 투자해 봅시다
  46. 46. 46 WARNING 지금 여러분이 전문가가 될 수도 있지 않을까요?
  47. 47. 47 WARNING 사실 그걸 노리고 선택한 Backend입니다.
  48. 48. 48 다행인 점 • 설계 사상 • Pinpoint의 backend가 죽어도 Application은 장애가 발생하면 안된다. • Collector • HBase • Hadoop • 최우선 순위는 성능 데이터수집 X • Application이 정상적으로 돌아가는게 최우선
  49. 49. 49 다행인 점 • 뭐든 그렇지만 말로는 다 됨 • 큰소리 땅땅~~ “아! 걱정마시라깐요. 저를 믿으셈. 모든건 계획대로~”
  50. 50. 50 다행인 점
  51. 51. 51 다행인 점 • 검증되었습니다 • 직접 체험 • 한계는 분명. 버그는 커버 불가능 • 개발에서 검증 -> 운영 • 버그가 발생하면 신고해주세요. 큰 도움이 됩니다. • 버그는 계획에 없었던 일
  52. 52. 52 로드맵 • 알람 / Admin • 실시간 데이터 • EndUser 모니터링 • 지원라이브러리 추가 • 개발가이드 • D2 Open Seminar (Java성능 + Pinpoint) 5월?
  53. 53. 53 끝 감사합니다. http://github.com/naver/pinpoint http://helloworld.naver.com/helloworld /1194202

×