Giám sát thời gian thực của Watermill bằng cách sử dụng Prometheus
Metrics
Watermill có thể được giám sát bằng cách sử dụng các bộ trang trí cho nhà sản xuất/người đăng ký và middleware cho xử lý viên. Chúng tôi cung cấp một triển khai mặc định bằng cách sử dụng khách hàng chính thức của Prometheus cho Go.
Gói components/metrics
xuất bản PrometheusMetricsBuilder
, cung cấp các chức năng tiện lợi để bọc nhà sản xuất, người đăng ký và xử lý viên để cập nhật đăng ký Prometheus liên quan:
Mã nguồn đầy đủ: github.com/ThreeDotsLabs/watermill/components/metrics/builder.go
// ...
// PrometheusMetricsBuilder cung cấp các phương thức để trang trí nhà sản xuất, người đăng ký và xử lý viên.
type PrometheusMetricsBuilder struct {
// PrometheusRegistry có thể điền vào một đăng ký Prometheus hiện có hoặc rỗng để sử dụng đăng ký mặc định.
PrometheusRegistry prometheus.Registerer
Namespace string
Subsystem string
}
// AddPrometheusRouterMetrics là một chức năng tiện lợi để thêm middleware số liệu thống kê vào tất cả các xử lý viên trên bộ định tuyến tin nhắn. Nó cũng trang trí nhà sản xuất và người đăng ký của các xử lý viên.
func (b PrometheusMetricsBuilder) AddPrometheusRouterMetrics(r *message.Router) {
// ...
Bọc Nhà sản xuất, Người đăng ký và Xử lý viên
Nếu bạn đang sử dụng bộ định tuyến của Watermill (được khuyến nghị trong hầu hết các trường hợp), bạn có thể sử dụng chức năng tiện lợi AddPrometheusRouterMetrics
để đảm bảo rằng tất cả các xử lý viên được thêm vào bộ định tuyến này được bọc để cập nhật đăng ký Prometheus, cũng như nhà sản xuất và người đăng ký của họ:
Mã nguồn đầy đủ: github.com/ThreeDotsLabs/watermill/components/metrics/builder.go
// ...
// AddPrometheusRouterMetrics là một chức năng tiện lợi để thêm middleware số liệu thống kê vào tất cả các xử lý viên trên bộ định tuyến tin nhắn. Nó cũng trang trí nhà sản xuất và người đăng ký của các xử lý viên.
func (b PrometheusMetricsBuilder) AddPrometheusRouterMetrics(r *message.Router) {
r.AddPublisherDecorators(b.DecoratePublisher)
r.AddSubscriberDecorators(b.DecorateSubscriber)
r.AddMiddleware(b.NewRouterMiddleware().Middleware)
}
// ...
Ví dụ về việc sử dụng AddPrometheusRouterMetrics
:
Mã nguồn đầy đủ: github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
// Chúng tôi để trống các tham số `namespace` và `subsystem`
metricsBuilder := metrics.NewPrometheusMetricsBuilder(prometheusRegistry, "", "")
metricsBuilder.AddPrometheusRouterMetrics(router)
// ...
Trong đoạn mã trên, chúng tôi để các tham số namespace
và subsystem
trống. Thư viện khách hàng của Prometheus sử dụng các tham số này để tiền tố tên số liệu thống kê. Bạn có thể muốn sử dụng namespace hoặc subsystem, nhưng lưu ý rằng điều này sẽ ảnh hưởng đến tên số liệu thống kê, vì vậy bạn cần điều chỉnh bảng điều khiển Grafana tương ứng.
Nhà sản xuất và người đăng ký độc lập cũng có thể được trang trí bằng cách sử dụng các phương thức riêng của PrometheusMetricsBuilder
:
Mã nguồn đầy đủ: github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
subWithMetrics, err := metricsBuilder.DecorateSubscriber(pubSub)
if err != nil {
panic(err)
}
pubWithMetrics, err := metricsBuilder.DecoratePublisher(pub)
if err != nil {
panic(err)
}
// ...
Tiết lộ Điểm cuối /metrics
Theo nguyên tắc làm việc của Prometheus, một dịch vụ cần tiết lộ một điểm cuối HTTP để lấy dữ liệu. Theo quy ước, đây là một điểm cuối GET, và đường dẫn thường là /metrics
.
Để cung cấp điểm cuối này, có hai hàm thuận tiện có sẵn, một sử dụng Prometheus Registry đã tạo trước đó và một khác đồng thời tạo một Registry mới:
Mã nguồn đầy đủ: github.com/ThreeDotsLabs/watermill/components/metrics/http.go
// ...
// CreateRegistryAndServeHTTP thiết lập một máy chủ HTTP tại địa chỉ cụ thể để tiết lộ điểm cuối /metrics cho Prometheus.
// Nó trả về một Prometheus Registry mới (để đăng ký metric) và một hàm hủy để tắt máy chủ.
func CreateRegistryAndServeHTTP(addr string) (registry *prometheus.Registry, cancel func()) {
registry = prometheus.NewRegistry()
return registry, ServeHTTP(addr, registry)
}
// ServeHTTP thiết lập một máy chủ HTTP tại địa chỉ cụ thể để tiết lộ điểm cuối /metrics cho Prometheus.
// Nó chấp nhận một Prometheus Registry hiện có và trả về một hàm hủy để tắt máy chủ.
func ServeHTTP(addr string, registry *prometheus.Registry) (cancel func()) {
// ...
Dưới đây là một ví dụ về cách sử dụng:
Mã nguồn đầy đủ: github.com/ThreeDotsLabs/watermill/_examples/basic/4-metrics/main.go
// ...
prometheusRegistry, closeMetricsServer := metrics.CreateRegistryAndServeHTTP(*metricsAddr)
defer closeMetricsServer()
// Chúng ta bỏ trống phần namespace và subsystem
metricsBuilder := metrics.NewPrometheusMetricsBuilder(prometheusRegistry, "", "")
metricsBuilder.AddPrometheusRouterMetrics(router)
// ...
Ứng dụng Ví dụ
Để hiểu cách bảng điều khiển hoạt động trong thực tế, bạn có thể tham khảo ví dụ về metrics.
Theo hướng dẫn trong tệp README của ví dụ để chạy nó và thêm nguồn dữ liệu Prometheus vào Grafana.
Bảng điều khiển Grafana
Chúng tôi đã chuẩn bị một bảng điều khiển Grafana để sử dụng với triển khai metrics được nhắc đến. Nó cung cấp thông tin cơ bản về lưu lượng thông qua, tỷ lệ lỗi và thời gian xuất bản/xử lý.
Nếu bạn muốn xem bảng điều khiển này cục bộ, bạn có thể sử dụng ứng dụng ví dụ.
Để biết thêm thông tin về các metrics được xuất sang Prometheus, xem Metrics được xuất.
Nhập Bảng điều khiển
Để nhập bảng điều khiển Grafana, chọn Bảng điều khiển/Quản lý từ menu bên trái, sau đó nhấp +Nhập
.
Nhập URL của bảng điều khiển https://grafana.com/dashboards/9777 (hoặc chỉ là ID, 9777), sau đó nhấn Load.
Sau đó chọn nguồn dữ liệu Prometheus được sử dụng để lấy dữ liệu từ điểm cuối /metrics
. Nhấp Nhập
và bạn đã hoàn thành!
Các chỉ số đã xuất
Dưới đây là tất cả các chỉ số đăng ký trong đăng ký Prometheus bởi PrometheusMetricsBuilder
.
Để biết thêm thông tin về các loại chỉ số Prometheus, vui lòng tham khảo tài liệu Prometheus.
Đối tượng | Chỉ số | Mô tả | Nhãn/Giá trị |
---|---|---|---|
Người đăng ký | subscriber_messages_received_total |
Một bộ đếm Prometheus. Đếm số lượng tin nhắn được nhận bởi người đăng ký. | acked là "acked" hoặc "nacked". |
Nếu người đăng ký hoạt động trong một xử lý viên, hãy đặt handler_name ; nếu không, " |
|||
subscriber_name xác định người đăng ký. Nếu nó triển khai giao diện fmt.Stringer , đó là kết quả của String() ; nếu không, đó là package.structName . |
|||
Xử lý viên | handler_execution_time_seconds |
Một biểu đồ Prometheus. Ghi lại thời gian thực thi của chức năng xử lý viên được bao bọc bởi trung gian. | handler_name là tên của xử lý viên. |
success là "true" hoặc "false", tùy thuộc vào việc chức năng xử lý viên được bao bọc trả về lỗi hay không. |
|||
Người xuất bản | publish_time_seconds |
Một biểu đồ Prometheus. Ghi lại thời gian thực thi của chức năng xuất bản được trang trí của người xuất bản. | success là "true" hoặc "false", tùy thuộc vào việc người xuất bản trang trí trả về lỗi hay không. |
Nếu người xuất bản hoạt động trong một xử lý viên, hãy đặt handler_name ; nếu không, " |
|||
publisher_name xác định người xuất bản. Nếu nó triển khai giao diện fmt.Stringer , đó là kết quả của String() ; nếu không, đó là package.structName . |
Ngoài ra, mỗi chỉ số đều có một nhãn node
do Prometheus cung cấp, với giá trị tương ứng là phiên bản của nguồn chỉ số và một job
được chỉ định là tên công việc trong tập tin cấu hình Prometheus.
Lưu ý: Như đã đề cập ở trên, việc sử dụng namespace
hoặc subsystem
không rỗng sẽ dẫn đến tiền tố tên chỉ số. Bạn có thể cần phải điều chỉnh tương ứng, chẳng hạn như trong định nghĩa bảng điều khiển của bảng điều khiển Grafana.
Tùy chỉnh
Nếu bạn tin rằng một số chỉ số cụ thể đã bị bỏ qua, bạn có thể dễ dàng mở rộng cài đặt cơ bản này. Cách tốt nhất là sử dụng đăng ký Prometheus được sử dụng với phương thức ServeHTTP
và đăng ký các chỉ số theo hướng dẫn của khách hàng Prometheus tại đây.
Một phương pháp ngắn gọn để cập nhật các chỉ số này là sử dụng trang trí. Source code đầy đủ có thể tìm thấy tại github.com/ThreeDotsLabs/watermill/message/decorator.go.
// ...
// MessageTransformSubscriberDecorator tạo một trang trí người đăng ký mà gọi hàm biến đổi trên mỗi tin nhắn được truyền qua người đăng ký.
func MessageTransformSubscriberDecorator(transform func(*Message)) SubscriberDecorator {
if transform == nil {
panic("hàm biến đổi là null")
}
return func(sub Subscriber) (Subscriber, error) {
return &messageTransformSubscriberDecorator{
sub: sub,
transform: transform,
}, nil
}
}
// MessageTransformPublisherDecorator tạo một trang trí người xuất bản mà gọi hàm biến đổi trên mỗi tin nhắn được truyền qua người xuất bản.
func MessageTransformPublisherDecorator(transform func(*Message)) PublisherDecorator {
if transform == nil {
panic("hàm biến đổi là null")
}
return func(pub Publisher) (Publisher, error) {
return &messageTransformPublisherDecorator{
Publisher: pub,
transform: transform,
}, nil
}
}
type messageTransformSubscriberDecorator struct {
// ...
Và/hoặc trung gian trong các bộ định tuyến.
Một phương pháp đơn giản hơn là chỉ cập nhật các chỉ số yêu cầu trong các hàm xử lý viên.