paint-brush
OpenTelemetry Tracing trong Spring Boot: Lựa chọn giữa Java Agent và Micrometer chotừ tác giả@nfrankel
205 lượt đọc

OpenTelemetry Tracing trong Spring Boot: Lựa chọn giữa Java Agent và Micrometer cho

từ tác giả Nicolas Fränkel8m2024/08/11
Read on Terminal Reader

dài quá đọc không nổi

Bài đăng này so sánh các giải pháp theo dõi OpenTelemetry trong ứng dụng Spring Boot sử dụng Java Agent v1, Java Agent v2 và Micrometer Tracing. Bài đăng nêu bật sự khác biệt về cấu hình, chức năng và khả năng theo dõi, cung cấp thông tin chi tiết về hiệu quả và ứng dụng của từng phương pháp để quan sát.
featured image - OpenTelemetry Tracing trong Spring Boot: Lựa chọn giữa Java Agent và Micrometer cho
Nicolas Fränkel HackerNoon profile picture

Bản demo OpenTelemetry Tracing của tôi có hai thành phần Spring Boot. Một thành phần sử dụng Java agent và tôi nhận thấy một hành vi khác khi tôi mới nâng cấp nó từ v1.x lên v2.x. Trong thành phần còn lại, tôi sử dụng Micrometer Tracing vì tôi biên dịch sang GraalVM native và nó không thể xử lý Java agent.



Trong bài viết này, tôi muốn so sánh ba phương pháp sau: Java agent v1, Java agent v2 và Micrometer Tracing.

Ứng dụng cơ sở và cơ sở hạ tầng của nó

Tôi sẽ sử dụng cùng một ứng dụng cơ sở: một ứng dụng Spring Boot đơn giản, được mã hóa bằng Kotlin. Nó cung cấp một điểm cuối duy nhất.


  • Hàm ngoài điểm cuối được đặt tên là entry()
  • Nó gọi một hàm khác có tên là intermediate()
  • Phần sau sử dụng một thể hiện WebClient , thay thế cho RestTemplate , để thực hiện cuộc gọi đến điểm cuối ở trên
  • Để tránh vòng lặp vô hạn, tôi truyền một tiêu đề yêu cầu tùy chỉnh: nếu hàm entry() tìm thấy nó, nó sẽ không tiến hành thêm nữa


Biểu đồ trình tự ứng dụng mẫu


Nó được dịch thành mã sau:


 @SpringBootApplication class Agent1xApplication @RestController class MicrometerController { private val logger = LoggerFactory.getLogger(MicrometerController::class.java) @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") if (done == null) intermediate() } fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } }


Đối với mỗi thiết lập, tôi sẽ kiểm tra hai giai đoạn: giai đoạn chính, với OpenTelemetry được bật và giai đoạn tùy chỉnh để tạo thêm các khoảng nội bộ.

Theo dõi micrômet

Micrometer Tracing bắt nguồn từ Micrometer , một "mặt tiền khả năng quan sát ứng dụng không phụ thuộc vào nhà cung cấp".


Micrometer Tracing cung cấp một giao diện đơn giản cho các thư viện theo dõi phổ biến nhất, cho phép bạn lập trình mã ứng dụng dựa trên JVM mà không cần khóa nhà cung cấp. Nó được thiết kế để thêm ít hoặc không thêm chi phí vào hoạt động thu thập theo dõi của bạn trong khi tối đa hóa tính di động của nỗ lực theo dõi của bạn.


-- Trang web theo dõi Micrometer


Để bắt đầu với Micrometer Tracing, người ta cần thêm một vài sự phụ thuộc:


  • Bộ truyền động Spring Boot, org.springframework.boot:spring-boot-starter-actuator
  • Micrometer Theo dõi chính nó, io.micrometer:micrometer-tracing
  • "Cầu nối" đến API backend theo dõi mục tiêu. Trong trường hợp của tôi, đó là OpenTelemetry, do đó io.micrometer:micrometer-tracing-bridge-otel
  • Một trình xuất dữ liệu cụ thể đến phần phụ trợ, io.opentelemetry:opentelemetry-exporter-otlp


Chúng ta không cần BOM vì các phiên bản đã được xác định trong Spring Boot parent.


Tuy nhiên, chúng ta cần hai tham số cấu hình thời gian chạy: nơi các dấu vết sẽ được gửi đến và tên của thành phần là gì. Chúng được điều khiển bởi các biến MANAGEMENT_OTLP_TRACING_ENDPOINTSPRING_APPLICATION_NAME .


 services: jaeger: image: jaegertracing/all-in-one:1.55 environment: - COLLECTOR_OTLP_ENABLED=true #1 ports: - "16686:16686" micrometer-tracing: build: dockerfile: Dockerfile-micrometer environment: MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2 SPRING_APPLICATION_NAME: micrometer-tracing #3
  1. Kích hoạt bộ thu thập OpenTelemetry cho Jaeger
  2. URL đầy đủ đến điểm cuối Jaeger OpenTelemetry gRPC
  3. Đặt tên dịch vụ OpenTelemetry


Đây là kết quả:

Dấu vết micromet trên Jaeger không có tùy chỉnh


Nếu không có bất kỳ tùy chỉnh nào, Micrometer sẽ tạo ra các khoảng thời gian khi nhận và gửi các yêu cầu HTTP.


Framework cần phải đưa magic vào RestClient để gửi. Chúng ta phải để cái trước khởi tạo cái sau cho việc đó:


 @SpringBootApplication class MicrometerTracingApplication { @Bean fun restClient(builder: RestClient.Builder) = builder.baseUrl("http://localhost:8080/done").build() }


Chúng ta có thể tạo các khoảng thủ công theo nhiều cách, một cách thông qua chính API OpenTelemetry. Tuy nhiên, quá trình thiết lập đòi hỏi rất nhiều mã mẫu. Cách đơn giản nhất là API quan sát của Micrometer. Lợi ích chính của nó là sử dụng một API duy nhất quản lý cả số liệudấu vết .


Biểu đồ lớp API quan sát

Sau đây là mã đã cập nhật:


 class MicrometerController( private val restClient: RestClient, private val registry: ObservationRegistry ) { @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") val observation = Observation.start("entry", registry) if (done == null) intermediate(observation) observation.stop() } fun intermediate(parent: Observation) { logger.info("intermediate") val observation = Observation.createNotStarted("intermediate", registry) .parentObservation(parent) .start() restClient.get() .header("X-done", "true") .retrieve() .toBodilessEntity() observation.stop() } }


Các cuộc gọi quan sát được thêm vào phản ánh các dấu vết được tạo ra:


Dấu vết micromet trên Jaeger với API quan sát

Đại lý OpenTelemetry v1

Một giải pháp thay thế cho Micrometer Tracing là OpenTelemetry Java Agent chung. Lợi ích chính của nó là không ảnh hưởng đến mã hoặc nhà phát triển; tác nhân là mối quan tâm thuần túy trong phạm vi thời gian chạy.


 java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar


Tác nhân tuân thủ cấu hình của OpenTelemetry với các biến môi trường:


 services: agent-1x: build: dockerfile: Dockerfile-agent1 environment: OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1 OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x #2 OTEL_METRICS_EXPORTER: none #3 OTEL_LOGS_EXPORTER: none #4 ports: - "8081:8080"
  1. Thiết lập giao thức, tên miền và cổng. Thư viện thêm /v1/traces
  2. Đặt tên dịch vụ OpenTelemetry
  3. Không xuất số liệu thống kê hoặc nhật ký


Không cần cấu hình thêm nữa, chúng ta sẽ có được những dấu vết sau:


Dấu vết của Agent v1 trên Jaeger không có tùy chỉnh


Agent tự động theo dõi các yêu cầu, cả đã nhận và đã gửi, cũng như các hàm được đánh dấu bằng chú thích liên quan đến Spring . Các dấu vết được lồng vào nhau một cách chính xác, theo ngăn xếp cuộc gọi. Để theo dõi các hàm bổ sung, chúng ta cần thêm một phụ thuộc vào cơ sở mã của mình, io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations . Bây giờ chúng ta có thể chú thích các hàm chưa theo dõi trước đó bằng chú thích @WithSpan .

Biểu đồ lớp @WithSpan


Phần value() quản lý nhãn của trace, trong khi kind được dịch thành thuộc tính span.kind . Nếu value được đặt thành chuỗi rỗng, là mặc định, nó sẽ xuất ra tên hàm. Đối với mục đích của tôi, giá trị mặc định là đủ tốt.


 @WithSpan fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() }


Nó tạo ra dấu intermediate() mới mong đợi:

Dấu vết của Agent v1 trên Jaeger với chú thích

Đại lý OpenTelemetry v2

OpenTelemetry đã phát hành phiên bản chính mới của tác nhân vào tháng 1 năm nay. Tôi đã cập nhật bản demo của mình với nó; các dấu vết hiện chỉ được tạo khi ứng dụng nhận và gửi yêu cầu.

Dấu vết của Agent v2 trên Jaeger không có tùy chỉnh


Đối với phiên bản trước, chúng ta có thể thêm dấu vết bằng chú thích @WithSpan . Điểm khác biệt duy nhất là chúng ta cũng phải chú thích hàm entry() . Theo mặc định, nó không được theo dõi.

Dấu vết của Agent v2 trên Jaeger với chú thích


Cuộc thảo luận

Spring đã thành công vì hai lý do: nó đơn giản hóa các giải pháp phức tạp, tức là EJB 2, và cung cấp một lớp trừu tượng trên các thư viện cạnh tranh. Micrometer Tracing bắt đầu như một lớp trừu tượng trên Zipkin và Jaeger, và nó hoàn toàn có lý. Lập luận này trở nên vô nghĩa khi OpenTelemetry được hỗ trợ bởi hầu hết các thư viện trên các ngôn ngữ lập trình và trình thu thập dấu vết. API quan sát vẫn là một lợi ích đáng kể của Micrometer Tracing, vì nó sử dụng một API duy nhất trên Metrics và Traces.


Về phía Java Agent, cấu hình OpenTelemetry tương tự nhau trên tất cả các tech stack và thư viện - biến môi trường. Tôi hơi thất vọng khi nâng cấp từ v1 lên v2, vì agent mới không nhận biết Spring: Các hàm được chú thích bằng Spring không được theo dõi theo mặc định.


Cuối cùng, đó là một quyết định sáng suốt. Tốt hơn nhiều nếu nêu rõ những khoảng thời gian bạn muốn hơn là xóa một số khoảng thời gian bạn không muốn thấy.


Cảm ơn Jonatan Ivanov vì sự giúp đỡ và đánh giá của anh ấy .


Mã nguồn đầy đủ cho bài đăng này có thể được tìm thấy trên GitHub:

Để đi xa hơn:


Được xuất bản lần đầu tại A Java Geek vào ngày 3 tháng 8 năm 2024