Lần đầu tiên bạn thực sự cần khả năng quan sát không phải là khi bạn bình tĩnh nhìn vào bảng điều khiển. Đó là khi người dùng viết "thanh toán chậm", biểu đồ lỗi trông bình thường và trong nhật ký, bạn chỉ tìm thấy một hàng thông báo bị ngắt kết nối.
OpenTelemetry được tạo ra để tránh khoảnh khắc đó: không phải để có thêm đồ họa mà để kết nối các mảnh lại với nhau. Một yêu cầu đi vào API, gọi cơ sở dữ liệu, đi qua nhà cung cấp bên ngoài, đăng công việc được xếp hàng đợi và có thể không thực hiện được ba dịch vụ sau đó. Nếu không theo dõi phân tán, bạn sẽ xây dựng lại câu chuyện đó bằng tay. Với OpenTelemetry ít nhất bạn có bản đồ.
Vấn đề không phải là trace, mà là câu chuyện
trace là một chuỗi gồm span. Đặt như thế nghe có vẻ lạnh lùng. Trong thực tế, mỗi span là một phần của câu chuyện: POST /checkout, SELECT inventory, call payment provider, publish order.created.
Giá trị đến khi bạn bắt đầu trả lời các câu hỏi thực tế:
- dịch vụ bên ngoài nào đang chậm lại?
- lỗi có đến từ một phiên bản cụ thể không?
- vấn đề có ảnh hưởng đến tất cả mọi người hay chỉ một người thuê nhà?
- lần thử lại có ẩn thời gian chờ không?
- công việc không đồng bộ bắt đầu nhưng sau đó chết ở một nơi khác?
Những câu hỏi này không thể được giải quyết bằng cách ném console.log một cách vội vàng. Thật vậy, nhật ký được thêm vào trong trường hợp khẩn cấp thường giúp ích cho bạn hôm nay nhưng lại trở thành tiếng ồn vào ngày mai.
Làm cách nào để đưa cái này vào ứng dụng Node.js
Cách thiết lập lành mạnh nhất rất đơn giản: ứng dụng tạo ra phép đo từ xa, Collector quyết định nơi gửi nó.
Node.js app -> OpenTelemetry Collector -> backend di observability
Tại sao không xuất trực tiếp cho nhà cung cấp? Vì lúc đầu có vẻ nhanh hơn, sau đó bạn nhận ra rằng mỗi dịch vụ có cấu hình khác nhau, số lần thử lại khác nhau, bộ lọc khác nhau và không có điểm tập trung nào để xóa dữ liệu nhạy cảm hay thay đổi đích đến.
Collector đúng là nhàm chán. Nó nhận được OTLP, thực hiện phân khối, có thể lọc, có thể lấy mẫu, có thể thêm các thuộc tính chung và có thể xuất sang nhiều hệ thống.
Tự đo: tốt nhưng chưa đủ
Trong Node.js tôi sẽ bắt đầu với thiết bị đo tự động. Nó cung cấp cho bạn khả năng hiển thị ngay lập tức về HTTP, các khung, cơ sở dữ liệu và thư viện chung được hỗ trợ.
npm install @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http
Sau đó, bạn khởi tạo SDK trước phần còn lại của ứng dụng:
import { NodeSDK } from '@opentelemetry/sdk-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
Tuy nhiên, điều này nhìn thấy khuôn khổ chứ không phải sản phẩm của bạn. Nó biết bạn đã thực hiện truy vấn nhưng không biết truy vấn đó nằm trong "tạo đơn hàng" hoặc "gia hạn đăng ký". Để làm được điều đó, bạn cần span hướng dẫn sử dụng ở những điểm cần có sự thống trị.
const span = tracer.startSpan('checkout.create_order'); try { span.setAttribute('cart.items_count', input.items.length); const order = await createOrder(input); span.setAttribute('order.id', order.id); return order; } catch (error) { span.recordException(error as Error); throw error; } finally { span.end(); }
Tôi sẽ không đặt hướng dẫn sử dụng span ở bất cứ đâu. Tôi sẽ đặt chúng ở đâu, vào lúc ba giờ sáng, tôi muốn hiểu chuyện gì đã xảy ra mà không cần đọc một nửa cơ sở mã.
Ba quy tắc tránh nhiều hỗn loạn
Quy tắc đầu tiên: mỗi dịch vụ phải có service.name, môi trường và phiên bản. Nó có vẻ tầm thường, nhưng nếu không có những thuộc tính này thì trace sẽ ít hữu ích hơn nhiều. Khi quá trình triển khai gặp sự cố nào đó, bạn muốn lọc theo phiên bản trong hai giây.
Quy tắc thứ hai: không đưa dữ liệu nhạy cảm vào thuộc tính. Email, mã thông báo, tải trọng số nguyên và địa chỉ không được vô tình kết thúc trong phần phụ trợ có khả năng quan sát. Nếu bạn cần xác định người dùng, hãy xem xét ID nội bộ, hàm băm hoặc các trường ít nhạy cảm hơn.
Nguyên tắc thứ ba: chú ý đến số lượng. user.id làm thuộc tính của trace có thể có ý nghĩa. Là nhãn số liệu, nó có thể phá hủy chi phí và hiệu suất của bạn.
Số liệu: ít nhưng tốt
Tôi sẽ bắt đầu với những số liệu rất thực tế:
- tỷ lệ, lỗi và thời lượng yêu cầu;
- độ trễ của sự phụ thuộc bên ngoài;
- số lần hết thời gian chờ và thử lại;
- độ sâu của đuôi;
- thời gian làm việc;
- tỷ lệ lỗi trên mỗi phiên bản.
Phần còn lại được thêm vào khi cần thiết. Bảng điều khiển chứa đầy các biểu đồ mà không ai nhìn vào là đồ nội thất chứ không phải khả năng quan sát.
Nhật ký: Vẫn hữu ích nhưng được liên kết
Nhật ký không biến mất. Đơn giản là chúng trở nên hữu ích hơn nhiều khi mang theo trace_id và span_id. Vì vậy, bạn có thể bắt đầu từ nhật ký lỗi và mở trace hoặc bắt đầu từ trace chậm và chỉ đọc nhật ký được tạo trong đường dẫn đó.
Không có sự tương quan, bạn đang tìm kim tiêm. Với mối tương quan, ít nhất bạn cũng biết nên tìm vào ngăn kéo nào.
Danh sách kiểm tra tôi sẽ sử dụng trước khi nói "chúng tôi được bảo hiểm"
- trace thực tế có nhiều dịch vụ.
- Nhật ký bao gồm
trace_idvàspan_id. - Collector được định cấu hình với giới hạn bộ nhớ và phân khối.
- Lỗi được ghi vào span.
- Có chính sách lấy mẫu.
- Số liệu đã kiểm soát số lượng thẻ.
- Dữ liệu nhạy cảm được lọc.
- Cảnh báo bắt đầu từ triệu chứng của người dùng chứ không phải biểu đồ ngẫu nhiên.
Kết luận
OpenTelemetry không tự mình giải quyết các vấn đề sản xuất. Nhưng cách bạn đối phó với chúng sẽ thay đổi. Thay vì thêm nhật ký một cách mù quáng, bạn bắt đầu đi theo đường dẫn thực tế của yêu cầu.
Đối với tôi, dấu hiệu cho thấy nó đang hoạt động rất đơn giản: khi có điều gì đó xảy ra, nhóm sẽ ngừng hỏi "chúng ta đang tìm kiếm ở đâu?" và bắt đầu hỏi "tại sao đoạn đó lại chậm?". Đó là nơi khả năng quan sát trở thành một công cụ chứ không phải một tập hợp các trang tổng quan.