1. Giới thiệu
Lần cập nhật gần đây nhất: ngày 15 tháng 07 năm 2022
Khả năng ghi nhận của ứng dụng
Khả năng quan sát và phương pháp OpenTelemetry
Khả năng quan sát là thuật ngữ dùng để mô tả một thuộc tính của hệ thống. Một hệ thống có khả năng ghi nhận được cho phép các nhóm chủ động gỡ lỗi hệ thống của mình. Trong bối cảnh đó, 3 trụ cột của khả năng quan sát; nhật ký, chỉ số và dấu vết là các công cụ đo lường cơ bản để hệ thống thu thập khả năng quan sát.
OpenTelemetry là một tập hợp các thông số kỹ thuật, thư viện và tác nhân giúp đẩy nhanh việc đo lường và xuất dữ liệu đo từ xa (nhật ký, chỉ số và dấu vết) mà khả năng quan sát đòi hỏi. OpenTelemetry là một dự án tiêu chuẩn mở và hướng đến cộng đồng theo CNCF. Bằng cách sử dụng các thư viện mà dự án và hệ sinh thái của dự án cung cấp, các nhà phát triển có thể đo lường các ứng dụng của họ theo cách trung lập với nhà cung cấp và chống lại nhiều kiến trúc.
Ngoài ra, ngoài 3 yếu tố chính của khả năng quan sát, tính năng lập hồ sơ liên tục là một thành phần quan trọng khác giúp ghi nhận khả năng quan sát và mở rộng cơ sở người dùng trong ngành. Trình phân tích tài nguyên trên đám mây là một trong những trình khởi tạo và cung cấp một giao diện dễ dàng để xem chi tiết các chỉ số hiệu suất trong ngăn xếp lệnh gọi ứng dụng.
Lớp học lập trình này là phần 1 của loạt bài trình bày về việc đo lường dấu vết phân phối trong vi dịch vụ bằng OpenTelemetry và Cloud Trace. Phần 2 sẽ trình bày về quá trình lập hồ sơ liên tục bằng Trình phân tích tài nguyên trên đám mây.
Dấu vết đã phân phối
Trong các nhật ký, chỉ số và dấu vết, dấu vết là dữ liệu đo từ xa cho biết độ trễ của một phần cụ thể trong quy trình trong hệ thống. Đặc biệt trong thời đại của các dịch vụ vi mô, dấu vết phân tán là yếu tố thúc đẩy mạnh mẽ để phát hiện điểm tắc nghẽn về độ trễ trong hệ thống phân phối tổng thể.
Khi phân tích dấu vết được phân phối, hình ảnh dữ liệu theo dõi là chìa khoá để nắm bắt nhanh độ trễ tổng thể của hệ thống. Trong dấu vết được phân phối, chúng ta xử lý một tập hợp lệnh gọi để xử lý một yêu cầu duy nhất đến điểm truy cập của hệ thống ở dạng Theo dõi chứa nhiều Span.
Span biểu thị một đơn vị công việc riêng lẻ được thực hiện trong một hệ thống phân phối, ghi lại thời gian bắt đầu và thời gian kết thúc. Các span thường có mối quan hệ phân cấp với nhau – trong hình bên dưới, tất cả các span nhỏ hơn là các span con của một /messages span và được tập hợp thành một Trace cho thấy lộ trình làm việc thông qua một hệ thống.
Google Cloud Trace là một trong những công cụ phụ trợ theo dõi phân tán và có thể tích hợp hiệu quả với các sản phẩm khác trong Google Cloud.
Sản phẩm bạn sẽ tạo ra
Trong lớp học lập trình này, bạn sẽ tìm hiểu thông tin theo dõi đo lường trong các dịch vụ có tên là "Ứng dụng Shakespeare" (còn gọi là Shakesapp) chạy trên cụm Google Kubernetes Engine. Cấu trúc của Shakesapp được mô tả như dưới đây:
- Loadgen gửi một chuỗi truy vấn đến máy khách trong HTTP
- Ứng dụng chuyển truy vấn từ trình tạo tải đến máy chủ trong gRPC
- Máy chủ chấp nhận truy vấn của ứng dụng, tìm nạp tất cả tác phẩm của Shakespare ở định dạng văn bản trong Google Cloud Storage, tìm các dòng chứa truy vấn và trả về số dòng khớp với ứng dụng
Bạn sẽ đo lường thông tin theo dõi trong yêu cầu. Sau đó, bạn sẽ nhúng một tác nhân trình phân tích tài nguyên vào máy chủ và điều tra nút thắt cổ chai.
Kiến thức bạn sẽ học được
- Cách bắt đầu sử dụng các thư viện Theo dõi OpenTelemetry trong dự án Go
- Cách tạo span bằng thư viện
- Cách truyền bối cảnh span qua dây giữa các thành phần ứng dụng
- Cách gửi dữ liệu theo dõi đến Cloud Trace
- Cách phân tích dấu vết trên Cloud Trace
Lớp học lập trình này giải thích cách đo lường các dịch vụ vi mô của bạn. Để dễ hiểu, ví dụ này chỉ chứa 3 thành phần (trình tạo tải, ứng dụng khách và máy chủ). Tuy nhiên, bạn có thể áp dụng quy trình tương tự được giải thích trong lớp học lập trình này cho các hệ thống lớn và phức tạp hơn.
Bạn cần có
- Kiến thức cơ bản về cờ vây
- Kiến thức cơ bản về Kubernetes
2. Thiết lập và yêu cầu
Thiết lập môi trường theo tiến độ riêng
Nếu chưa có Tài khoản Google (Gmail hoặc Google Apps), bạn phải tạo một tài khoản. Đăng nhập vào bảng điều khiển Google Cloud Platform ( console.cloud.google.com) và tạo một dự án mới.
Nếu bạn đã có một dự án, hãy nhấp vào trình đơn kéo xuống để chọn dự án ở phía trên bên trái của bảng điều khiển:
và nhấp vào "Dự án MỚI" trong hộp thoại kết quả để tạo một dự án mới:
Nếu chưa có dự án nào, bạn sẽ thấy một hộp thoại như sau để tạo dự án đầu tiên:
Hộp thoại tạo dự án tiếp theo cho phép bạn nhập thông tin chi tiết về dự án mới:
Xin lưu ý rằng mã dự án là tên duy nhất trong tất cả dự án Google Cloud (tên ở trên đã được sử dụng nên sẽ không phù hợp với bạn!). Mã này sẽ được đề cập sau trong lớp học lập trình này với tên PROJECT_ID.
Tiếp theo, nếu chưa làm như vậy, bạn sẽ cần bật tính năng thanh toán trong Developers Console để có thể sử dụng tài nguyên của Google Cloud và bật Cloud Trace API.
Bạn sẽ không mất quá vài đô la khi chạy lớp học lập trình này, nhưng có thể sẽ cao hơn nếu bạn quyết định sử dụng nhiều tài nguyên hơn hoặc nếu bạn để chúng chạy (xem phần "dọn dẹp" ở cuối tài liệu này). Giá của Google Cloud Trace, Google Kubernetes Engine và Google Artifact Registry được nêu trong tài liệu chính thức.
- Giá cho bộ công cụ vận hành của Google Cloud | Bộ công cụ vận hành
- Giá | Tài liệu về Kubernetes Engine
- Giá của Artifact Registry | Tài liệu về Artifact Registry
Người dùng mới của Google Cloud Platform đủ điều kiện nhận 300 USD dùng thử miễn phí. Vì vậy, lớp học lập trình này sẽ hoàn toàn miễn phí.
Thiết lập Google Cloud Shell
Mặc dù bạn có thể vận hành Google Cloud và Google Cloud Trace từ xa trên máy tính xách tay, nhưng trong lớp học lập trình này, chúng ta sẽ sử dụng Google Cloud Shell, một môi trường dòng lệnh chạy trong Đám mây.
Máy ảo dựa trên Debian này được tải tất cả các công cụ phát triển mà bạn cần. Dịch vụ này cung cấp thư mục gốc 5 GB ổn định và chạy trong Google Cloud, giúp nâng cao đáng kể hiệu suất và khả năng xác thực của mạng. Tức là tất cả những gì bạn cần để thực hiện lớp học lập trình này là một trình duyệt (vâng, trình duyệt này hoạt động trên Chromebook).
Để kích hoạt Cloud Shell từ Cloud Console, bạn chỉ cần nhấp vào biểu tượng Kích hoạt Cloud Shell (chỉ mất vài phút để cấp phép và kết nối với môi trường).
Sau khi kết nối với Cloud Shell, bạn sẽ thấy mình đã được xác thực và dự án đã được đặt thành PROJECT_ID
.
gcloud auth list
Kết quả lệnh
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Kết quả lệnh
[core] project = <PROJECT_ID>
Nếu vì lý do nào đó mà dự án không được thiết lập, chỉ cần phát hành lệnh sau:
gcloud config set project <PROJECT_ID>
Bạn đang tìm PROJECT_ID
? Hãy xem mã nhận dạng bạn đã sử dụng ở các bước thiết lập hoặc tra cứu trong trang tổng quan Cloud Console:
Cloud Shell cũng đặt một số biến môi trường theo mặc định. Điều này có thể hữu ích khi bạn chạy các lệnh sau này.
echo $GOOGLE_CLOUD_PROJECT
Kết quả lệnh
<PROJECT_ID>
Cuối cùng, đặt cấu hình dự án và vùng mặc định.
gcloud config set compute/zone us-central1-f
Bạn có thể chọn nhiều vùng khác nhau. Để biết thêm thông tin, hãy xem Khu vực và Vùng.
Thiết lập ngôn ngữ Go
Trong lớp học lập trình này, chúng ta sẽ sử dụng Go cho tất cả các mã nguồn. Chạy lệnh sau trên Cloud Shell và xác nhận xem phiên bản Go có phải là 1.17+ không
go version
Kết quả lệnh
go version go1.18.3 linux/amd64
Thiết lập cụm Google Kubernetes
Trong lớp học lập trình này, bạn sẽ vận hành một cụm dịch vụ vi mô trên Google Kubernetes Engine (GKE). Quy trình của lớp học lập trình này sẽ diễn ra như sau:
- Tải dự án cơ sở xuống Cloud Shell
- Xây dựng các dịch vụ vi mô trong vùng chứa
- Tải các vùng chứa lên Google Artifact Registry (GAR)
- Triển khai vùng chứa trên GKE
- Sửa đổi mã nguồn của dịch vụ để đo lường dấu vết
- Chuyển tới bước 2
Bật Kubernetes Engine
Trước tiên, chúng ta thiết lập một cụm Kubernetes mà trong đó Shakesapp chạy trên GKE. Vì vậy, chúng ta cần bật GKE. Chuyển đến trình đơn "Kubernetes Engine" và nhấn nút BẬT.
Bây giờ, bạn đã sẵn sàng tạo một cụm Kubernetes.
Tạo cụm Kubernetes
Trên Cloud Shell, hãy chạy lệnh sau để tạo một cụm Kubernetes. Vui lòng xác nhận rằng giá trị vùng thuộc khu vực mà bạn sẽ dùng để tạo kho lưu trữ Artifact Registry. Hãy thay đổi giá trị vùng us-central1-f
nếu vùng lưu trữ của bạn không bao gồm vùng này.
gcloud container clusters create otel-trace-codelab2 \ --zone us-central1-f \ --release-channel rapid \ --preemptible \ --enable-autoscaling \ --max-nodes 8 \ --no-enable-ip-alias \ --scopes cloud-platform
Kết quả lệnh
Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s). Creating cluster otel-trace-codelab2 in us-central1-f... Cluster is being health-checked (master is healthy)...done. Created [https://container.googleapis.com/v1/projects/development-215403/zones/us-central1-f/clusters/otel-trace-codelab2]. To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab2?project=development-215403 kubeconfig entry generated for otel-trace-codelab2. NAME: otel-trace-codelab2 LOCATION: us-central1-f MASTER_VERSION: 1.23.6-gke.1501 MASTER_IP: 104.154.76.89 MACHINE_TYPE: e2-medium NODE_VERSION: 1.23.6-gke.1501 NUM_NODES: 3 STATUS: RUNNING
Thiết lập Artifact Registry và skaffold
Bây giờ, chúng ta đã có một cụm Kubernetes sẵn sàng để triển khai. Tiếp theo, chúng ta chuẩn bị cho sổ đăng ký vùng chứa để đẩy và triển khai vùng chứa. Đối với các bước này, chúng ta cần thiết lập Sổ đăng ký cấu phần phần mềm (GAR) và skaffold để sử dụng Sổ đăng ký cấu phần phần mềm này.
Thiết lập Artifact Registry
Chuyển đến trình đơn của "Artifact Registry" và nhấn nút BẬT.
Sau vài phút, bạn sẽ thấy trình duyệt kho lưu trữ của GAR. Nhấp vào nút "TẠO KHỐI LƯỢNG" và nhập tên của kho lưu trữ.
Trong lớp học lập trình này, tôi đặt tên cho kho lưu trữ mới là trace-codelab
. Định dạng của cấu phần phần mềm này là "Docker" và loại vị trí là "Khu vực". Chọn khu vực gần với khu vực mà bạn đặt cho vùng mặc định của Google Compute Engine. Ví dụ: ví dụ này chọn "us-central1-f" ở trên, vì vậy ở đây chúng tôi chọn "us-central1 (Iowa)". Sau đó, hãy nhấp vào nút "TẠO" .
Bây giờ, bạn sẽ thấy "lớp học lập trình theo dõi" trên trình duyệt kho lưu trữ.
Chúng ta sẽ quay lại đây sau để kiểm tra đường dẫn đăng ký.
Thiết lập SafetyNet
Skaffold là một công cụ hữu ích khi bạn xây dựng các dịch vụ vi mô chạy trên Kubernetes. Thư viện này xử lý quy trình xây dựng, đẩy và triển khai vùng chứa ứng dụng bằng một tập hợp nhỏ các lệnh. Theo mặc định, Skaffold sử dụng Sổ đăng ký Docker làm sổ đăng ký vùng chứa, vì vậy, bạn cần định cấu hình skaffold để nhận dạng GAR khi đẩy vùng chứa vào.
Mở lại Cloud Shell và xác nhận xem skaffold đã được cài đặt hay chưa. (Theo mặc định, Cloud Shell cài đặt skaffold vào môi trường.) Chạy lệnh sau và xem phiên bản skaffold.
skaffold version
Kết quả lệnh
v1.38.0
Bây giờ, bạn có thể đăng ký kho lưu trữ mặc định để skaffold sử dụng. Để biết đường dẫn đăng ký, hãy tự điều hướng đến trang tổng quan của Artifact Registry và nhấp vào tên kho lưu trữ bạn vừa thiết lập ở bước trước.
Sau đó, bạn sẽ thấy các đường dẫn breadcrumb (tập hợp liên kết phân cấp) ở đầu trang. Nhấp vào biểu tượng để sao chép đường dẫn sổ đăng ký vào bảng nhớ tạm.
Khi nhấp vào nút sao chép, bạn sẽ thấy hộp thoại ở cuối trình duyệt với thông báo như sau:
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" đã được sao chép
Quay lại vỏ đám mây. Chạy lệnh skaffold config set default-repo
bằng giá trị mà bạn vừa sao chép từ trang tổng quan.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Kết quả lệnh
set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox
Ngoài ra, bạn cần định cấu hình sổ đăng ký cho cấu hình Docker. Chạy lệnh sau:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Kết quả lệnh
{ "credHelpers": { "gcr.io": "gcloud", "us.gcr.io": "gcloud", "eu.gcr.io": "gcloud", "asia.gcr.io": "gcloud", "staging-k8s.gcr.io": "gcloud", "marketplace.gcr.io": "gcloud", "us-central1-docker.pkg.dev": "gcloud" } } Adding credentials for: us-central1-docker.pkg.dev
Bây giờ, bạn có thể thực hiện bước tiếp theo để thiết lập vùng chứa Kubernetes trên GKE.
Tóm tắt
Ở bước này, bạn sẽ thiết lập môi trường của lớp học lập trình:
- Thiết lập Cloud Shell
- Đã tạo kho lưu trữ Artifact Registry cho sổ đăng ký vùng chứa
- Thiết lập skaffold để sử dụng sổ đăng ký vùng chứa
- Tạo một cụm Kubernetes để chạy các dịch vụ vi mô của lớp học lập trình
Tiếp theo
Trong bước tiếp theo, bạn sẽ xây dựng, đẩy và triển khai các dịch vụ vi mô trên cụm
3. Xây dựng, đẩy mạnh và triển khai các dịch vụ vi mô
Tải tài liệu của lớp học lập trình xuống
Ở bước trước, chúng ta đã thiết lập mọi điều kiện tiên quyết cho lớp học lập trình này. Bây giờ, bạn đã sẵn sàng chạy toàn bộ các dịch vụ vi mô trên các dịch vụ đó. Tài liệu của lớp học lập trình này được lưu trữ trên GitHub, vì vậy hãy tải chúng xuống môi trường Cloud Shell bằng lệnh git sau.
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
Cấu trúc thư mục của dự án như sau:
. ├── README.md ├── step0 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step1 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step2 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step3 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step4 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src ├── step5 │ ├── manifests │ ├── proto │ ├── skaffold.yaml │ └── src └── step6 ├── manifests ├── proto ├── skaffold.yaml └── src
- tệp kê khai: tệp kê khai của Kubernetes
- proto: định nghĩa proto cho hoạt động giao tiếp giữa ứng dụng và máy chủ
- src: thư mục mã nguồn của từng dịch vụ
- skaffold.yaml: Tệp cấu hình cho skaffold
Trong lớp học lập trình này, bạn sẽ cập nhật mã nguồn trong thư mục step0
. Bạn cũng có thể tham khảo mã nguồn trong thư mục step[1-6]
để biết câu trả lời ở các bước sau. (Phần 1 bao gồm bước 0 đến bước 4 và Phần 2 bao gồm bước 5 và bước 6)
Chạy lệnh skaffold
Cuối cùng, bạn đã sẵn sàng xây dựng, đẩy và triển khai toàn bộ nội dung trên cụm Kubernetes mà bạn vừa tạo. Nghe có vẻ như gồm nhiều bước, nhưng thực tế là skaffold làm hết mọi việc cho bạn. Hãy thử thực hiện điều đó bằng lệnh sau:
cd step0 skaffold dev
Ngay khi chạy lệnh này, bạn sẽ thấy kết quả nhật ký của docker build
và có thể xác nhận rằng các tệp này đã được đẩy thành công vào sổ đăng ký.
Kết quả lệnh
... ---> Running in c39b3ea8692b ---> 90932a583ab6 Successfully built 90932a583ab6 Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1 The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice] cc8f5a05df4a: Preparing 5bf719419ee2: Preparing 2901929ad341: Preparing 88d9943798ba: Preparing b0fdf826a39a: Preparing 3c9c1e0b1647: Preparing f3427ce9393d: Preparing 14a1ca976738: Preparing f3427ce9393d: Waiting 14a1ca976738: Waiting 3c9c1e0b1647: Waiting b0fdf826a39a: Layer already exists 88d9943798ba: Layer already exists f3427ce9393d: Layer already exists 3c9c1e0b1647: Layer already exists 14a1ca976738: Layer already exists 2901929ad341: Pushed 5bf719419ee2: Pushed cc8f5a05df4a: Pushed step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001
Sau khi bạn đẩy tất cả vùng chứa dịch vụ, các quy trình triển khai Kubernetes sẽ tự động bắt đầu.
Kết quả lệnh
sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997 Tags used in deployment: - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a Starting deploy... - deployment.apps/clientservice created - service/clientservice created - deployment.apps/loadgen created - deployment.apps/serverservice created - service/serverservice created
Sau khi triển khai, bạn sẽ thấy nhật ký ứng dụng thực tế được phát ra cho stdout trong mỗi vùng chứa như sau:
Kết quả lệnh
[client] 2022/07/14 06:33:15 {"match_count":3040} [loadgen] 2022/07/14 06:33:15 query 'love': matched 3040 [client] 2022/07/14 06:33:15 {"match_count":3040} [loadgen] 2022/07/14 06:33:15 query 'love': matched 3040 [client] 2022/07/14 06:33:16 {"match_count":3040} [loadgen] 2022/07/14 06:33:16 query 'love': matched 3040 [client] 2022/07/14 06:33:19 {"match_count":463} [loadgen] 2022/07/14 06:33:19 query 'tear': matched 463 [loadgen] 2022/07/14 06:33:20 query 'world': matched 728 [client] 2022/07/14 06:33:20 {"match_count":728} [client] 2022/07/14 06:33:22 {"match_count":463} [loadgen] 2022/07/14 06:33:22 query 'tear': matched 463
Lưu ý rằng tại thời điểm này, bạn muốn xem bất kỳ thư nào từ máy chủ. Được rồi, cuối cùng bạn đã sẵn sàng bắt đầu đo lường cho ứng dụng của mình bằng OpenTelemetry để theo dõi phân tán các dịch vụ.
Trước khi bắt đầu đo lường dịch vụ, vui lòng tắt cụm bằng phím Ctrl-C.
Kết quả lệnh
... [client] 2022/07/14 06:34:57 {"match_count":1} [loadgen] 2022/07/14 06:34:57 query 'what's past is prologue': matched 1 ^CCleaning up... - W0714 06:34:58.464305 28078 gcp.go:120] WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead. - To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Tóm tắt
Ở bước này, bạn đã chuẩn bị tài liệu của lớp học lập trình trong môi trường của mình và xác nhận rằng skaffold chạy như mong đợi.
Tiếp theo
Trong bước tiếp theo, bạn sẽ sửa đổi mã nguồn của dịch vụ tải để đo lường thông tin theo dõi.
4. Đo lường cho HTTP
Khái niệm về khả năng đo lường và lan truyền dấu vết
Trước khi chỉnh sửa mã nguồn, hãy để tôi giải thích ngắn gọn cách dấu vết được phân phối hoạt động trong một sơ đồ đơn giản.
Trong ví dụ này, chúng ta sẽ đo lường mã để xuất thông tin Trace và Span sang Cloud Trace, đồng thời truyền ngữ cảnh theo dõi qua yêu cầu từ dịch vụ tạo tải đến dịch vụ máy chủ.
Các ứng dụng cần gửi siêu dữ liệu về Theo dõi như Mã theo dõi và Mã Span để Cloud Trace tập hợp tất cả các span có cùng mã theo dõi thành một dấu vết. Ngoài ra, ứng dụng cần truyền các bối cảnh theo dõi (kết hợp giữa Mã theo dõi và Span ID của span gốc) khi yêu cầu các dịch vụ hạ nguồn, để ứng dụng có thể biết được ngữ cảnh theo dõi nào đang được xử lý.
OpenTelemetry giúp bạn:
- để tạo Mã theo dõi và Span ID duy nhất
- để xuất mã theo dõi và mã span sang phần phụ trợ
- để truyền ngữ cảnh theo dõi đến các dịch vụ khác
- để nhúng siêu dữ liệu bổ sung giúp phân tích dấu vết
Các thành phần trong dấu vết OpenTelemetry
Quy trình đo lường dấu vết ứng dụng bằng OpenTelemetry diễn ra như sau:
- Tạo trình xuất dữ liệu
- Tạo một TracerProvider liên kết trình xuất dữ liệu trong 1 và đặt trình xuất dữ liệu đó ở chế độ toàn cục.
- Đặt TextMapPropagaror để đặt phương thức truyền
- Tải Tracer từ TracerProvider
- Tạo Span qua Trình theo dõi
Hiện tại, bạn chưa cần phải hiểu các thuộc tính chi tiết trong mỗi thành phần, nhưng điều quan trọng nhất cần nhớ là:
- trình xuất ở đây có thể cắm cho TracerProvider
- TracerProvider lưu giữ tất cả cấu hình liên quan đến việc lấy mẫu và xuất dấu vết
- tất cả dấu vết đều được nhóm lại trong đối tượng Tracer
Sau khi hiểu điều này, hãy chuyển sang công việc lập trình thực tế.
Khoảng thời gian đầu tiên của công cụ
Dịch vụ tạo tải nhạc cụ
Mở Cloud Shell Editor bằng cách nhấn nút ở trên cùng bên phải của Cloud Shell. Mở
step0/src/loadgen/main.go
trong trình khám phá ở ngăn bên trái rồi tìm hàm chính.
step0/src/loadgen/main.go
func main() { ... for range t.C { log.Printf("simulating client requests, round %d", i) if err := run(numWorkers, numConcurrency); err != nil { log.Printf("aborted round with error: %v", err) } log.Printf("simulated %d requests", numWorkers) if numRounds != 0 && i > numRounds { break } i++ } }
Trong hàm main (chính), bạn sẽ thấy vòng lặp gọi hàm run
trong đó. Trong cách triển khai hiện tại, phần này có 2 dòng nhật ký ghi lại thời điểm bắt đầu và kết thúc lệnh gọi hàm. Bây giờ, hãy đo lường thông tin Span để theo dõi độ trễ của lệnh gọi hàm.
Trước tiên, như đã lưu ý trong phần trước, hãy thiết lập toàn bộ cấu hình cho OpenTelemetry. Thêm các gói OpenTelemetry như sau:
step0/src/loadgen/main.go
import ( "context" // step1. add packages "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "net/url" "time" // step1. add packages "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" // step1. end add packages )
Để dễ đọc, chúng ta tạo một hàm thiết lập có tên là initTracer
và gọi hàm này trong hàm main
.
step0/src/loadgen/main.go
// step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
Bạn có thể nhận thấy quy trình thiết lập OpenTelemetry như được mô tả trong phần trước. Trong quá trình triển khai này, chúng ta sử dụng trình xuất stdout
để xuất tất cả thông tin theo dõi vào stdout theo định dạng có cấu trúc.
Sau đó, bạn gọi hàm đó từ hàm chính. Gọi initTracer()
và nhớ gọi TracerProvider.Shutdown()
khi bạn đóng ứng dụng.
step0/src/loadgen/main.go
func main() { // step1. setup OpenTelemetry tp, err := initTracer() if err != nil { log.Fatalf("failed to initialize TracerProvider: %v", err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step1. end setup log.Printf("starting worder with %d workers in %d concurrency", numWorkers, numConcurrency) log.Printf("number of rounds: %d (0 is inifinite)", numRounds) ...
Sau khi hoàn tất việc thiết lập, bạn cần tạo một Span có một Mã theo dõi và Span ID duy nhất. OpenTelemetry cung cấp một thư viện hữu ích cho việc này. Thêm các gói mới bổ sung vào ứng dụng HTTP của công cụ.
step0/src/loadgen/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "net/http/httptrace" // step1. add packages "net/url" "time" // step1. add packages "go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" // step1. end add packages "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" semconv "go.opentelemetry.io/otel/semconv/v1.10.0" "go.opentelemetry.io/otel/trace" )
Vì trình tạo tải đang gọi dịch vụ ứng dụng trong HTTP với net/http
trong hàm runQuery
, nên chúng ta sẽ sử dụng gói đóng góp cho net/http
và bật khả năng đo lường có phần mở rộng của gói httptrace
và otelhttp
.
Trước tiên, hãy thêm một biến toàn cục của gói httpClient để gọi các yêu cầu HTTP qua ứng dụng được đo lường.
step0/src/loadgen/main.go
var httpClient = http.Client{ Transport: otelhttp.NewTransport(http.DefaultTransport) }
Tiếp theo, hãy thêm khả năng đo lường vào hàm runQuery
để tạo span tuỳ chỉnh bằng OpenTelemetry và span được tạo tự động qua ứng dụng HTTP tuỳ chỉnh. Việc bạn sẽ làm là:
- Nhận một Tracer của
TracerProvider
toàn cầu vớiotel.Tracer()
- Tạo span gốc bằng phương thức
Tracer.Start()
- Kết thúc khoảng gốc theo thời gian tuỳ ý (trong trường hợp này là kết thúc hàm
runQuery
)
step0/src/loadgen/main.go
reqURL.RawQuery = v.Encode() // step1. replace http.Get() with custom client call // resp, err := http.Get(reqURL.String()) // step1. instrument trace ctx := context.Background() tr := otel.Tracer("loadgen") ctx, span := tr.Start(ctx, "query.request", trace.WithAttributes( semconv.TelemetrySDKLanguageGo, semconv.ServiceNameKey.String("loadgen.runQuery"), attribute.Key("query").String(s), )) defer span.End() ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx)) req, err := http.NewRequestWithContext(ctx, "GET", reqURL.String(), nil) if err != nil { return -1, fmt.Errorf("error creating HTTP request object: %v", err) } resp, err := httpClient.Do(req) // step1. end instrumentation if err != nil { return -1, fmt.Errorf("error sending request to %v: %v", reqURL.String(), err) }
Giờ đây, bạn đã hoàn tất việc đo lường trong bộ tải (ứng dụng khách HTTP). Hãy nhớ cập nhật go.mod
và go.sum
bằng lệnh go mod
.
go mod tidy
Dịch vụ khách hàng công cụ
Trong phần trước, chúng ta đã đo lường phần được đưa vào hình chữ nhật màu đỏ trong bản vẽ bên dưới. Chúng tôi đo lường thông tin về khoảng trống trong dịch vụ tạo tải. Tương tự như dịch vụ trình tạo tải, giờ đây, chúng ta cần đo lường cho dịch vụ ứng dụng. Điểm khác biệt so với dịch vụ trình tạo tải là dịch vụ ứng dụng cần trích xuất thông tin Mã theo dõi được truyền từ dịch vụ trình tạo tải trong tiêu đề HTTP và sử dụng mã nhận dạng để tạo Span.
Mở Cloud Shell Editor và thêm các gói bắt buộc như chúng tôi đã làm đối với dịch vụ tải trình tạo.
step0/src/client/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "net/url" "os" "time" "opentelemetry-trace-codelab-go/client/shakesapp" // step1. add new import "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" // step1. end new import )
Một lần nữa, chúng ta cần thiết lập OpenTelemtry. Chỉ cần sao chép và dán hàm initTracer
từ Loadgen, đồng thời gọi hàm đó vào hàm main
của dịch vụ ứng dụng.
step0/src/client/main.go
// step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
Giờ là lúc đo lường span. Vì dịch vụ ứng dụng cần chấp nhận các yêu cầu HTTP từ dịch vụ tạo tải, nên dịch vụ này cần đo lường trình xử lý. Máy chủ HTTP trong dịch vụ ứng dụng được triển khai bằng net/http và bạn có thể sử dụng gói otelhttp
như chúng ta đã làm trong quá trình tải.
Trước tiên, chúng ta thay thế việc đăng ký trình xử lý bằng Trình xử lý otelhttp
. Trong hàm main
, hãy tìm các dòng mà trình xử lý HTTP được đăng ký bằng http.HandleFunc()
.
step0/src/client/main.go
// step1. change handler to intercept OpenTelemetry related headers // http.HandleFunc("/", svc.handler) otelHandler := otelhttp.NewHandler(http.HandlerFunc(svc.handler), "client.handler") http.Handle("/", otelHandler) // step1. end intercepter setting http.HandleFunc("/_genki", svc.health)
Sau đó, chúng ta đo lường khoảng thời gian thực tế bên trong trình xử lý. Tìm trình xử lý Func (*clientService)() và thêm khả năng đo lường span bằng trace.SpanFromContext()
.
step0/src/client/main.go
func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) { ... ctx := r.Context() ctx, cancel := context.WithCancel(ctx) defer cancel() // step1. instrument trace span := trace.SpanFromContext(ctx) defer span.End() // step1. end instrument ...
Với khả năng đo lường này, bạn có được các khoảng thời gian từ đầu phương thức handler
đến cuối phương thức đó. Để dễ dàng phân tích khoảng, hãy thêm một thuộc tính bổ sung lưu trữ số lượng được so khớp vào truy vấn. Ngay trước dòng nhật ký, hãy thêm mã sau.
func (cs *clientService) handler(w http.ResponseWriter, r *http.Request) { ... // step1. add span specific attribute span.SetAttributes(attribute.Key("matched").Int64(resp.MatchCount)) // step1. end adding attribute log.Println(string(ret)) ...
Với tất cả khả năng đo lường ở trên, bạn đã hoàn tất khả năng đo lường dấu vết giữa bộ tải và ứng dụng. Hãy xem cách hoạt động. Chạy lại mã bằng skaffold.
skaffold dev
Sau một thời gian chạy các dịch vụ trên cụm GKE, bạn sẽ thấy một lượng lớn thông điệp nhật ký như thế này:
Kết quả lệnh
[loadgen] { [loadgen] "Name": "query.request", [loadgen] "SpanContext": { [loadgen] "TraceID": "cfa22247a542beeb55a3434392d46b89", [loadgen] "SpanID": "18b06404b10c418b", [loadgen] "TraceFlags": "01", [loadgen] "TraceState": "", [loadgen] "Remote": false [loadgen] }, [loadgen] "Parent": { [loadgen] "TraceID": "00000000000000000000000000000000", [loadgen] "SpanID": "0000000000000000", [loadgen] "TraceFlags": "00", [loadgen] "TraceState": "", [loadgen] "Remote": false [loadgen] }, [loadgen] "SpanKind": 1, [loadgen] "StartTime": "2022-07-14T13:13:36.686751087Z", [loadgen] "EndTime": "2022-07-14T13:14:31.849601964Z", [loadgen] "Attributes": [ [loadgen] { [loadgen] "Key": "telemetry.sdk.language", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "go" [loadgen] } [loadgen] }, [loadgen] { [loadgen] "Key": "service.name", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "loadgen.runQuery" [loadgen] } [loadgen] }, [loadgen] { [loadgen] "Key": "query", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "faith" [loadgen] } [loadgen] } [loadgen] ], [loadgen] "Events": null, [loadgen] "Links": null, [loadgen] "Status": { [loadgen] "Code": "Unset", [loadgen] "Description": "" [loadgen] }, [loadgen] "DroppedAttributes": 0, [loadgen] "DroppedEvents": 0, [loadgen] "DroppedLinks": 0, [loadgen] "ChildSpanCount": 5, [loadgen] "Resource": [ [loadgen] { [loadgen] "Key": "service.name", [loadgen] "Value": { [loadgen] "Type": "STRING", [loadgen] "Value": "unknown_service:loadgen" ...
Trình xuất stdout
sẽ phát đi các thông báo này. Bạn sẽ nhận thấy rằng thành phần mẹ của tất cả span theo loadgen đều có TraceID: 00000000000000000000000000000000
, vì đây là span gốc, tức là span đầu tiên trong dấu vết. Ngoài ra, bạn thấy rằng thuộc tính nhúng "query"
có chuỗi truy vấn được chuyển đến dịch vụ khách.
Tóm tắt
Trong bước này, bạn đã đo lường dịch vụ trình tạo tải và dịch vụ máy khách giao tiếp trong HTTP và xác nhận rằng bạn có thể truyền thành công Trace Context giữa các dịch vụ và xuất thông tin Span từ cả hai dịch vụ sang stdout.
Tiếp theo
Trong bước tiếp theo, bạn sẽ đo lường dịch vụ máy khách và dịch vụ máy chủ để xác nhận cách truyền Ngữ cảnh theo dõi thông qua gRPC.
5. Khả năng đo lường cho gRPC
Ở bước trước, chúng ta đã đo lường nửa đầu của yêu cầu trong các dịch vụ vi mô này. Ở bước này, chúng ta cố gắng đo lường hoạt động giao tiếp gRPC giữa dịch vụ ứng dụng và dịch vụ máy chủ. (Hình chữ nhật màu xanh lục và màu tím trong hình bên dưới)
Khả năng đo lường bản dựng trước cho ứng dụng gRPC
Hệ sinh thái của OpenTelemetry cung cấp nhiều thư viện tiện dụng giúp các nhà phát triển đo lường các ứng dụng. Ở bước trước, chúng ta đã sử dụng khả năng đo lường bản dựng sẵn cho gói net/http
. Ở bước này, khi chúng ta đang cố gắng phổ biến Trace Context (Ngữ cảnh theo dõi) thông qua gRPC, nên chúng ta sẽ sử dụng thư viện cho nó.
Trước tiên, bạn nhập gói gRPC tạo sẵn có tên là otelgrpc
.
step0/src/client/main.go
import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "net/url" "os" "time" "opentelemetry-trace-codelab-go/client/shakesapp" // step2. add prebuilt gRPC package (otelgrpc) "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" )
Lần này, dịch vụ ứng dụng là một ứng dụng gRPC so với dịch vụ máy chủ, vì vậy, bạn cần đo lường ứng dụng gRPC. Tìm hàm mustConnGRPC
và thêm các trình chặn gRPC mà công cụ đo lường span mỗi khi ứng dụng đưa ra yêu cầu đến máy chủ.
step0/src/client/main.go
// Helper function for gRPC connections: Dial and create client once, reuse. func mustConnGRPC(ctx context.Context, conn **grpc.ClientConn, addr string) { var err error // step2. add gRPC interceptor interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider()) *conn, err = grpc.DialContext(ctx, addr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor(interceptorOpt)), grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor(interceptorOpt)), grpc.WithTimeout(time.Second*3), ) // step2: end adding interceptor if err != nil { panic(fmt.Sprintf("Error %s grpc: failed to connect %s", err, addr)) } }
Vì bạn đã thiết lập OpenTelemetry ở phần trước, nên bạn không cần thực hiện việc này.
Khả năng đo lường dựng sẵn cho máy chủ gRPC
Giống như những gì chúng tôi đã thực hiện cho ứng dụng gRPC, chúng tôi gọi các công cụ đo lường được tạo sẵn cho máy chủ gRPC. Thêm gói mới vào phần nhập như:
step0/src/server/main.go
import ( "context" "fmt" "io/ioutil" "log" "net" "os" "regexp" "strings" "opentelemetry-trace-codelab-go/server/shakesapp" "cloud.google.com/go/storage" // step2. add OpenTelemetry packages including otelgrpc "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel" stdout "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" "go.opentelemetry.io/otel/propagation" sdktrace "go.opentelemetry.io/otel/sdk/trace" "google.golang.org/api/iterator" "google.golang.org/api/option" "google.golang.org/grpc" healthpb "google.golang.org/grpc/health/grpc_health_v1" )
Vì đây là lần đầu tiên thiết lập máy chủ đo lường, nên trước tiên bạn cần thiết lập OpenTelemetry, tương tự như những gì chúng ta đã thực hiện cho tải và dịch vụ máy khách.
step0/src/server/main.go
// step2. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // create a stdout exporter to show collected spans out to stdout. exporter, err := stdout.New(stdout.WithPrettyPrint()) if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil } func main() { ... // step2. setup OpenTelemetry tp, err := initTracer() if err != nil { log.Fatalf("failed to initialize TracerProvider: %v", err) } defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step2. end setup ...
Tiếp theo, bạn cần thêm các trình chặn máy chủ. Trong hàm main
, hãy tìm vị trí gọi grpc.NewServer()
và thêm điểm chặn vào hàm.
step0/src/server/main.go
func main() { ... svc := NewServerService() // step2: add interceptor interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider()) srv := grpc.NewServer( grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(interceptorOpt)), grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(interceptorOpt)), ) // step2: end adding interceptor shakesapp.RegisterShakespeareServiceServer(srv, svc) ...
Chạy dịch vụ vi mô và xác nhận dấu vết
Sau đó, hãy chạy mã đã sửa đổi bằng lệnh skaffold.
skaffold dev
Bây giờ, một lần nữa, bạn sẽ thấy một loạt thông tin về span trên stdout.
Kết quả lệnh
... [server] { [server] "Name": "shakesapp.ShakespeareService/GetMatchCount", [server] "SpanContext": { [server] "TraceID": "89b472f213a400cf975e0a0041649667", [server] "SpanID": "96030dbad0061b3f", [server] "TraceFlags": "01", [server] "TraceState": "", [server] "Remote": false [server] }, [server] "Parent": { [server] "TraceID": "89b472f213a400cf975e0a0041649667", [server] "SpanID": "cd90cc3859b73890", [server] "TraceFlags": "01", [server] "TraceState": "", [server] "Remote": true [server] }, [server] "SpanKind": 2, [server] "StartTime": "2022-07-14T14:05:55.74822525Z", [server] "EndTime": "2022-07-14T14:06:03.449258891Z", [server] "Attributes": [ ... [server] ], [server] "Events": [ [server] { [server] "Name": "message", [server] "Attributes": [ ... [server] ], [server] "DroppedAttributeCount": 0, [server] "Time": "2022-07-14T14:05:55.748235489Z" [server] }, [server] { [server] "Name": "message", [server] "Attributes": [ ... [server] ], [server] "DroppedAttributeCount": 0, [server] "Time": "2022-07-14T14:06:03.449255889Z" [server] } [server] ], [server] "Links": null, [server] "Status": { [server] "Code": "Unset", [server] "Description": "" [server] }, [server] "DroppedAttributes": 0, [server] "DroppedEvents": 0, [server] "DroppedLinks": 0, [server] "ChildSpanCount": 0, [server] "Resource": [ [server] { ... [server] ], [server] "InstrumentationLibrary": { [server] "Name": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc", [server] "Version": "semver:0.33.0", [server] "SchemaURL": "" [server] } [server] } ...
Bạn nhận thấy rằng bạn chưa nhúng bất kỳ tên span nào và chưa tạo span theo cách thủ công bằng trace.Start()
hoặc span.SpanFromContext()
. Tuy nhiên, bạn vẫn nhận được một số lượng lớn span vì các trình chặn gRPC đã tạo ra chúng.
Tóm tắt
Ở bước này, bạn đã đo lường hoạt động giao tiếp dựa trên gRPC với sự hỗ trợ của các thư viện hệ sinh thái OpenTelemetry.
Tiếp theo
Ở bước tiếp theo, bạn sẽ trực quan hoá dấu vết bằng Cloud Trace và tìm hiểu cách phân tích các span được thu thập.
6. Trực quan hoá dấu vết bằng Cloud Trace
Bạn đã đo lường các dấu vết trong toàn bộ hệ thống bằng OpenTelemetry. Cho đến nay, bạn đã tìm hiểu cách đo lường các dịch vụ HTTP và gRPC. Mặc dù bạn đã học cách đo lường chúng, nhưng bạn vẫn chưa học cách phân tích chúng. Trong phần này, bạn sẽ thay thế các nhà xuất bản stdout bằng các nhà xuất bản Cloud Trace và tìm hiểu cách phân tích dấu vết của mình.
Sử dụng trình xuất dữ liệu Cloud Trace
Một trong những đặc điểm mạnh mẽ của OpenTelemetry là khả năng cắm. Để trực quan hoá tất cả các span mà khả năng đo lường của bạn thu thập, bạn chỉ cần thay thế trình xuất stdout bằng trình xuất Cloud Trace.
Mở các tệp main.go
của từng dịch vụ rồi tìm hàm initTracer()
. Xoá dòng này để tạo trình xuất stdout và tạo trình xuất Cloud Trace.
step0/src/loadgen/main.go
import ( ... // step3. add OpenTelemetry for Cloud Trace package cloudtrace "github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace" ) // step1. add OpenTelemetry initialization function func initTracer() (*sdktrace.TracerProvider, error) { // step3. replace stdout exporter with Cloud Trace exporter // cloudtrace.New() finds the credentials to Cloud Trace automatically following the // rules defined by golang.org/x/oauth2/google.findDefaultCredentailsWithParams. // https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentialsWithParams exporter, err := cloudtrace.New() // step3. end replacing exporter if err != nil { return nil, err } // for the demonstration, we use AlwaysSmaple sampler to take all spans. // do not use this option in production. tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithBatcher(exporter), ) otel.SetTracerProvider(tp) otel.SetTextMapPropagator(propagation.TraceContext{}) return tp, nil }
Bạn cũng cần chỉnh sửa hàm tương tự trong dịch vụ máy khách và máy chủ.
Chạy dịch vụ vi mô và xác nhận dấu vết
Sau khi chỉnh sửa, chỉ cần chạy cụm như bình thường bằng lệnh skaffold.
skaffold dev
Giờ đây, bạn sẽ không thấy nhiều thông tin về span ở định dạng nhật ký có cấu trúc trên stdout, vì bạn đã thay thế trình xuất bằng Cloud Trace.
Kết quả lệnh
[loadgen] 2022/07/14 15:01:07 simulated 20 requests [loadgen] 2022/07/14 15:01:07 simulating client requests, round 37 [loadgen] 2022/07/14 15:01:14 query 'sweet': matched 958 [client] 2022/07/14 15:01:14 {"match_count":958} [client] 2022/07/14 15:01:14 {"match_count":3040} [loadgen] 2022/07/14 15:01:14 query 'love': matched 3040 [client] 2022/07/14 15:01:15 {"match_count":349} [loadgen] 2022/07/14 15:01:15 query 'hello': matched 349 [client] 2022/07/14 15:01:15 {"match_count":484} [loadgen] 2022/07/14 15:01:15 query 'faith': matched 484 [loadgen] 2022/07/14 15:01:15 query 'insolence': matched 14 [client] 2022/07/14 15:01:15 {"match_count":14} [client] 2022/07/14 15:01:21 {"match_count":484} [loadgen] 2022/07/14 15:01:21 query 'faith': matched 484 [client] 2022/07/14 15:01:21 {"match_count":728} [loadgen] 2022/07/14 15:01:21 query 'world': matched 728 [client] 2022/07/14 15:01:22 {"match_count":484} [loadgen] 2022/07/14 15:01:22 query 'faith': matched 484 [loadgen] 2022/07/14 15:01:22 query 'hello': matched 349 [client] 2022/07/14 15:01:22 {"match_count":349} [client] 2022/07/14 15:01:23 {"match_count":1036} [loadgen] 2022/07/14 15:01:23 query 'friend': matched 1036 [loadgen] 2022/07/14 15:01:28 query 'tear': matched 463 ...
Bây giờ, hãy xác nhận xem tất cả các span có được gửi chính xác đến Cloud Trace hay không. Truy cập vào Cloud Console rồi chuyển đến "Danh sách theo dõi". Dễ dàng truy cập từ hộp tìm kiếm. Nếu không, bạn có thể nhấp vào trình đơn trong ngăn bên trái.
Sau đó, bạn sẽ thấy nhiều điểm màu xanh dương được phân phối trên biểu đồ độ trễ. Mỗi vị trí đại diện cho một dấu vết.
Nhấp vào một trong các dấu vết đó để xem thông tin chi tiết bên trong dấu vết.
Ngay cả chỉ với giao diện nhanh đơn giản này, bạn đã biết nhiều thông tin chi tiết. Ví dụ: từ biểu đồ thác nước, bạn có thể thấy rằng nguyên nhân gây ra độ trễ chủ yếu là do khoảng có tên là shakesapp.ShakespeareService/GetMatchCount
. (Xem bước 1 trong hình ảnh ở trên) Bạn có thể xác nhận điều đó trong bảng tóm tắt. (Cột ngoài cùng bên phải hiển thị thời lượng của từng khoảng thời gian.) Ngoài ra, dấu vết này dành cho cụm từ tìm kiếm "bạn bè". (Xem 2 trong hình trên)
Với những bản phân tích ngắn này, bạn có thể nhận thấy mình cần biết các span chi tiết hơn bên trong phương thức GetMatchCount
. So với thông tin của stdout, hình ảnh trực quan là rất mạnh mẽ. Để tìm hiểu thêm thông tin chi tiết về Cloud Trace, vui lòng truy cập vào tài liệu chính thức của chúng tôi.
Tóm tắt
Trong bước này, bạn đã thay thế trình xuất dữ liệu stdout bằng Cloud Trace một lần và các dấu vết được trực quan hoá trên Cloud Trace. Ngoài ra, bạn đã tìm hiểu cách bắt đầu phân tích dấu vết.
Tiếp theo
Trong bước tiếp theo, bạn sẽ sửa đổi mã nguồn của dịch vụ máy chủ để thêm một span phụ trong GetMatchCount.
7. Thêm khoảng phụ để phân tích hiệu quả hơn
Ở bước trước, bạn đã tìm ra nguyên nhân gây ra thời gian trọn vòng quan sát được trong quá trình loadgen, chủ yếu là do quá trình bên trong phương thức GetMatchCount (trình xử lý gRPC) trong dịch vụ máy chủ. Tuy nhiên, vì chúng tôi không đo lường bất cứ thứ gì khác ngoài trình xử lý, nên chúng tôi không thể tìm thêm thông tin chi tiết từ biểu đồ thác nước. Đây là trường hợp phổ biến khi chúng tôi bắt đầu đo lường các dịch vụ vi mô.
Trong phần này, chúng ta sẽ đo lường một span phụ trong đó máy chủ gọi Google Cloud Storage, vì thường xảy ra trường hợp một số I/O mạng bên ngoài mất nhiều thời gian trong quá trình và điều quan trọng là xác định xem liệu lệnh gọi có phải là nguyên nhân hay không.
Đo lường một khoảng thời gian phụ trong máy chủ
Mở main.go
trong máy chủ rồi tìm hàm readFiles
. Hàm này đang gọi một yêu cầu đến Google Cloud Storage để tìm nạp tất cả tệp văn bản trong các tác phẩm của Shakespeare. Trong hàm này, bạn có thể tạo một span phụ, giống như những gì bạn đã làm đối với khả năng đo lường máy chủ HTTP trong dịch vụ ứng dụng.
step0/src/server/main.go
func readFiles(ctx context.Context, bucketName, prefix string) ([]string, error) { type resp struct { s string err error } // step4: add an extra span span := trace.SpanFromContext(ctx) span.SetName("server.readFiles") span.SetAttributes(attribute.Key("bucketname").String(bucketName)) defer span.End() // step4: end add span ...
Đó là tất cả những gì bạn cần làm để thêm một span mới. Hãy xem kết quả bằng cách chạy ứng dụng.
Chạy dịch vụ vi mô và xác nhận dấu vết
Sau khi chỉnh sửa, chỉ cần chạy cụm như bình thường bằng lệnh skaffold.
skaffold dev
Chọn một dấu vết có tên query.request
trong danh sách theo dõi. Bạn sẽ thấy một biểu đồ thác nước theo dõi tương tự, ngoại trừ một span mới trong shakesapp.ShakespeareService/GetMatchCount
. (Khoảng cách được bao quanh bởi hình chữ nhật màu đỏ bên dưới)
Giờ đây, bạn có thể thấy được rằng lệnh gọi bên ngoài đến Google Cloud Storage chiếm phần lớn độ trễ, nhưng những yếu tố khác vẫn chiếm phần lớn độ trễ.
Bạn đã nắm được rất nhiều thông tin chi tiết chỉ qua một vài góc nhìn của biểu đồ theo dõi thác nước. Làm cách nào để bạn biết thêm chi tiết về hiệu suất trong ứng dụng của mình? Đến đây, trình phân tích tài nguyên xuất hiện, nhưng bây giờ, hãy kết thúc lớp học lập trình này và uỷ quyền tất cả các hướng dẫn về trình phân tích tài nguyên cho phần 2.
Tóm tắt
Ở bước này, bạn đã đo lường một khoảng thời gian khác trong dịch vụ máy chủ và thu được thông tin chi tiết hơn về độ trễ của hệ thống.
8. Xin chúc mừng
Bạn đã tạo thành công dấu vết được phân phối bằng OpenTelemery và xác nhận độ trễ của yêu cầu trên dịch vụ vi mô trên Google Cloud Trace.
Đối với các bài tập mở rộng, bạn có thể thử tự mình thử các chủ đề sau.
- Phương thức triển khai hiện tại sẽ gửi tất cả các span được tạo bằng tính năng kiểm tra tình trạng. (
grpc.health.v1.Health/Check
) Làm cách nào để lọc ra những khoảng thời gian đó trong Cloud Trace? Gợi ý có tại đây. - Liên kết nhật ký sự kiện với span và xem cách thức hoạt động của nhật ký sự kiện trên Google Cloud Trace và Google Cloud Logging. Gợi ý có tại đây.
- Thay thế một dịch vụ bằng một dịch vụ bằng ngôn ngữ khác và thử đo lường bằng OpenTelemetry cho ngôn ngữ đó.
Ngoài ra, nếu bạn muốn tìm hiểu về trình phân tích tài nguyên sau phần này, vui lòng chuyển sang phần 2. Trong trường hợp đó, bạn có thể bỏ qua phần dọn dẹp dưới đây.
Dọn dẹp
Sau lớp học lập trình này, vui lòng dừng cụm Kubernetes và nhớ xoá dự án để bạn không bị tính các khoản phí ngoài dự kiến trên Google Kubernetes Engine, Google Cloud Trace, Google Artifact Registry.
Trước tiên, hãy xoá cụm đó. Nếu đang chạy cụm bằng skaffold dev
, bạn chỉ cần nhấn Ctrl-C. Nếu bạn đang chạy cụm bằng skaffold run
, hãy chạy lệnh sau:
skaffold delete
Kết quả lệnh
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Sau khi xoá cụm, trong ngăn trình đơn, hãy chọn "IAM và Quản trị viên" > "Cài đặt", sau đó nhấp vào "HUỶ XUỐNG" .
Sau đó, nhập Mã dự án (không phải Tên dự án) vào biểu mẫu trong hộp thoại và xác nhận tắt máy.