1. Giới thiệu
Lần cập nhật gần đây nhất: ngày 15 tháng 7 năm 2022
Khả năng quan sát của ứng dụng
Khả năng quan sát và 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 quan sát cho phép các nhóm chủ động gỡ lỗi hệ thống của mình. Trong bối cảnh đó, ba 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 có được 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 tăng tốc quá trình đo lường và xuất dữ liệu đo từ xa (nhật ký, chỉ số và dấu vết) mà tính năng quan sát cần có. OpenTelemetry là một tiêu chuẩn mở và là dự án do cộng đồng điều hướng thuộc 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, nhà phát triển có thể đo lường ứng dụng của họ theo cách trung lập với nhà cung cấp và trên nhiều cấu trúc.
Ngoài 3 trụ cột của khả năng quan sát, việc lập hồ sơ liên tục là một thành phần chính khác để 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 công cụ ban đầu và cung cấp 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 viết và đề cập đến việc đo lường các dấu vết phân tán trong các dịch vụ vi mô bằng OpenTelemetry và Cloud Trace. Phần 2 sẽ trình bày về tính năng phân tích liên tục bằng Trình phân tích tài nguyên trên đám mây.
Theo dõi phân tán
Trong số 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 là trong thời đại của các dịch vụ vi mô, tính năng theo dõi phân tán là yếu tố thúc đẩy mạnh mẽ để tìm ra các nút thắt cổ chai về độ trễ trong hệ thống phân tán tổng thể.
Khi phân tích các dấu vết được phân phối, hình ảnh dữ liệu dấu vết là yếu tố then chốt để nắm bắt nhanh độ trễ tổng thể của hệ thống. Trong dấu vết phân tán, chúng ta xử lý một tập hợp các lệnh gọi để xử lý một yêu cầu duy nhất đến điểm truy cập hệ thống ở dạng Dấu vết chứa nhiều Span.
Span đại diện cho một đơn vị công việc riêng lẻ được thực hiện trong một hệ thống phân tán, ghi lại thời gian bắt đầu và dừng. 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 đều là span con của một span /messages lớn và được tập hợp thành một Dấu vết cho thấy đường dẫn công việc thông qua một hệ thống.
Google Cloud Trace là một trong những lựa chọn cho phần phụ trợ theo dõi phân tán và được tích hợp tốt 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ẽ đo lường thông tin theo dõi 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ả dưới đây:
- Loadgen gửi một chuỗi truy vấn đến ứng dụng trong HTTP
- Máy khách truyền truy vấn từ loadgen đến máy chủ trong gRPC
- Máy chủ chấp nhận truy vấn từ ứng dụng, tìm nạp tất cả tác phẩm của Shakespeare ở định dạng văn bản từ Google Cloud Storage, tìm kiế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 trên 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 thư viện OpenTelemetry Trace trong dự án Go
- Cách tạo span bằng thư viện
- Cách truyền bối cảnh span qua mạng 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ô. Để dễ hiểu, ví dụ này chỉ chứa 3 thành phần (trình tạo tải, ứng dụng và máy chủ), nhưng 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ề Go
- Kiến thức cơ bản về Kubernetes
2. Cách thiết lập và các yêu cầu
Thiết lập môi trường theo tốc độ của riêng bạn
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ó dự án, hãy nhấp vào trình đơn thả xuống để chọn dự án ở phía trên bên trái của bảng điều khiển:
rồi nhấp vào nút "NEW PROJECT" (DỰ ÁN MỚI) trong hộp thoại xuất hiện để tạo dự án mới:
Nếu chưa có dự án, 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:
Hãy ghi nhớ mã dự án. Đây là một tên duy nhất trên tất cả các dự án Google Cloud (tên ở trên đã được sử dụng và sẽ không hoạt động đối với bạn, rất xin lỗi!). Mã này sẽ được gọi là PROJECT_ID ở phần sau của lớp học lập trình này.
Tiếp theo, nếu chưa thực hiện, bạn cần bật tính năng thanh toán trong Google Cloud Console để sử dụng các tài nguyên của Google Cloud và bật Cloud Trace API.
Việc tham gia lớp học lập trình này sẽ không tốn quá vài đô la, nhưng có thể tốn nhiều 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 để các tài nguyên đó 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 ghi chú trong tài liệu chính thức.
- Giá của 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 dùng thử 300 đô la Mỹ miễn phí, nhờ đó, bạn có thể tham gia lớp học lập trình này hoàn toàn miễn phí.
Thiết lập Google Cloud Shell
Mặc dù bạn có thể điều khiển 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 trên đám mây.
Máy ảo dựa trên Debian này được tải sẵn tất cả các công cụ phát triển mà bạn cần. Ứng dụng này cung cấp một thư mục gốc 5 GB ổn định và chạy trong Google Cloud, giúp cải thiện đáng kể hiệu suất mạng và xác thực. Điều này có nghĩa là tất cả những gì bạn cần cho lớp học lập trình này là một trình duyệt (có, 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 (quá trình cấp phép và kết nối với môi trường sẽ chỉ mất vài phút).
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ả của lệnh
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Kết quả của lệnh
[core] project = <PROJECT_ID>
Nếu vì lý do nào đó mà dự án không được đặt, bạn chỉ cần đưa ra lệnh sau:
gcloud config set project <PROJECT_ID>
Bạn đang tìm PROJECT_ID
? Kiểm tra mã nhận dạng mà bạn đã sử dụng trong các bước thiết lập hoặc tra cứu mã nhận dạng đó trong trang tổng quan của Cloud Console:
Theo mặc định, Cloud Shell cũng đặt một số biến môi trường. Các biến này có thể hữu ích khi bạn chạy các lệnh trong tương lai.
echo $GOOGLE_CLOUD_PROJECT
Kết quả của lệnh
<PROJECT_ID>
Cuối cùng, hãy đặt múi giờ mặc định và cấu hình dự án.
gcloud config set compute/zone us-central1-f
Bạn có thể chọn nhiều múi giờ. Để biết thêm thông tin, hãy xem phần Khu vực và vùng.
Thiết lập ngôn ngữ của Go
Trong lớp học lập trình này, chúng ta sử dụng Go cho tất 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 trở lên hay không
go version
Kết quả của 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ẽ chạy 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 như sau:
- Tải dự án cơ sở xuống Cloud Shell
- Tạo dịch vụ vi mô vào vùng chứa
- Tải 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 các dịch vụ để đo lường dấu vết
- Chuyển đến bước 2
Bật Kubernetes Engine
Trước tiên, chúng ta thiết lập một cụm Kubernetes nơi 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" (Công cụ Kubernetes) rồi 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 giá trị vùng nằm trong khu vực mà bạn sẽ sử dụng để tạo kho lưu trữ Cấu phần phần mềm. Thay đổi giá trị vùng us-central1-f
nếu khu vực kho lưu trữ của bạn không bao gồm vùng đó.
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ả của 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 sẽ chuẩn bị cho một 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 một Cấu phần phần mềm đăng ký (GAR) và skaffold để sử dụng.
Thiết lập Artifact Registry
Chuyển đến trình đơn "Registry Artifact" (Registry Artifact) rồi nhấn nút BẬT.
Sau một 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 "CREATE REPOSITORY" (TẠO KHOA HỌC) rồi nhập tên 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 là "Docker" và loại vị trí là "Khu vực". Chọn khu vực gần với khu vực 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 ta chọn "us-central1 (Iowa)". Sau đó, hãy nhấp vào nút "CREATE" (TẠO).
Bây giờ, bạn sẽ thấy "trace-codelab" 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 Skaffold
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. Công cụ 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 bộ lệnh nhỏ. Theo mặc định, Skaffold sử dụng Docker Registry làm kho lưu trữ 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 đến.
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 sẽ 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ả của 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. Để lấy đường dẫn đăng ký, hãy tự chuyển đến trang tổng quan của Registry Artifact (Đăng ký cấu phần phần mềm) rồi nhấp vào tên của 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 ở đầ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:
Đã sao chép "us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab"
Quay lại màn hình shell trên đám mây. Chạy lệnh skaffold config set default-repo
với giá trị 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ả của 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ý thành cấu hình Docker. Chạy lệnh sau:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Kết quả của 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ể chuyển sang 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 thiết lập môi trường lớp học lập trình:
- Thiết lập Cloud Shell
- Tạo kho lưu trữ Artifact Registry cho kho lưu trữ vùng chứa
- Thiết lập skaffold để sử dụng kho lưu trữ vùng chứa
- Tạo một cụm Kubernetes nơi các dịch vụ vi mô của lớp học lập trình chạy
Tiếp theo
Trong bước tiếp theo, bạn sẽ tạo, đẩy và triển khai các dịch vụ vi mô lên cụm
3. Tạo, đẩy 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 tất cả các điều kiện tiên quyết cho lớp học lập trình này. Giờ đây, bạn đã sẵn sàng chạy toàn bộ 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 tài liệu đó 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
- manifests: Tệp kê khai 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 cho 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 nằm 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 trong 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à 6)
Chạy lệnh skaffold
Cuối cùng, bạn đã sẵn sàng tạo, đẩy và triển khai toàn bộ nội dung lên cụm Kubernetes mà bạn vừa tạo. Có vẻ như quy trình này bao gồm nhiều bước, nhưng thực tế là skaffold sẽ làm mọi việc cho bạn. Hãy thử bằng lệnh sau:
cd step0 skaffold dev
Ngay khi chạy lệnh, 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 kết quả này đã được đẩy thành công vào sổ đăng ký.
Kết quả của 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 đẩy tất cả các vùng chứa dịch vụ, các bản triển khai Kubernetes sẽ tự động bắt đầu.
Kết quả của 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 stdout trong mỗi vùng chứa như sau:
Kết quả của 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 mọi thông báo từ máy chủ. Cuối cùng, bạn đã sẵn sàng bắt đầu đo lường ứng dụng 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 tổ hợp phím Ctrl-C.
Kết quả của 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 lớp học lập trình trong môi trường của mình và xác nhận skaffold chạy như dự kiến.
Tiếp theo
Trong bước tiếp theo, bạn sẽ sửa đổi mã nguồn của dịch vụ loadgen để đo lường thông tin theo dõi.
4. Đo lường cho HTTP
Khái niệm về việc đo lường và truyền tải 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 hoạt động của các dấu vết phân tán trong một sơ đồ đơn giản.
Trong ví dụ này, chúng ta đo lường mã để xuất thông tin theo dõi và span sang Cloud Trace, đồng thời truyền tải ngữ cảnh theo dõi trên yêu cầu từ dịch vụ loadgen đến dịch vụ máy chủ.
Các ứng dụng cần gửi siêu dữ liệu theo dõi như Mã theo dõi và Mã span để Cloud Trace có thể tập hợp tất 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 tải ngữ cảnh theo dõi (kết hợp Mã theo dõi và Mã span của span mẹ) khi yêu cầu các dịch vụ hạ nguồn để có thể biết được ngữ cảnh theo dõi mà chúng đang xử lý.
OpenTelemetry giúp bạn:
- để tạo Mã theo dõi và Mã span duy nhất
- để xuất Mã theo dõi và Mã span sang phần phụ trợ
- để truyền tải 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 như sau:
- Tạo trình xuất
- Tạo TracerProvider liên kết trình xuất trong 1 và đặt trình xuất đó thành toàn cục.
- Đặt TextMapPropagaror để đặt phương thức truyền tải
- Lấy Tracer từ TracerProvider
- Tạo Span từ Trình theo dõi
Hiện tại, bạn không cần hiểu rõ 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 vào TracerProvider
- TracerProvider lưu giữ tất cả cấu hình liên quan đến hoạt động lấy mẫu và xuất dấu vết
- tất cả dấu vết đều được gói trong đối tượng Tracer
Khi đã hiểu rõ điều này, hãy chuyển sang công việc lập trình thực tế.
Đo lường span đầu tiên
Dịch vụ trình tạo tải đo lường
Mở Trình chỉnh sửa Cloud Shell bằng cách nhấn vào nút ở trên cùng bên phải của Cloud Shell. Mở
step0/src/loadgen/main.go
từ trình khám phá trong ngăn bên trái và 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 chính, bạn sẽ thấy vòng lặp gọi hàm run
trong đó. Trong quá trình 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 đó 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ư 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 ở định dạng có cấu trúc.
Sau đó, bạn gọi hàm này 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ã theo dõi và Mã span 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 khách HTTP đo lường.
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 bằng net/http
trong hàm runQuery
, nên chúng ta sử dụng gói contrib cho net/http
và bật tính năng đo lường bằng tiện ích của gói httptrace
và otelhttp
.
Trước tiên, hãy thêm biến toàn cục httpClient của gói để gọi các yêu cầu HTTP thông 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 trong hàm runQuery
để tạo span tuỳ chỉnh bằng OpenTelemetry và span được tạo tự động từ ứng dụng HTTP tuỳ chỉnh. Bạn sẽ làm như sau:
- Lấy Tracer từ
TracerProvider
toàn cục bằngotel.Tracer()
- Tạo span gốc bằng phương thức
Tracer.Start()
- Kết thúc span 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ờ thì bạn đã hoàn tất việc đo lường trong loadgen (ứng dụng ứng dụng HTTP). Vui lòng 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 về công cụ
Trong phần trước, chúng ta đã đo lường phần được bao bọc trong 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 span trong dịch vụ trình 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 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ã này để tạo Span.
Mở Trình chỉnh sửa Cloud Shell và thêm các gói bắt buộc như chúng ta đã làm cho dịch vụ trình tạo tải.
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 )
Xin nhắc lại, chúng ta cần thiết lập OpenTelemtry. Bạn chỉ cần sao chép và dán hàm initTracer
từ loadgen rồi gọi hàm đó trong hàm main
của dịch vụ khách.
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 }
Bây giờ, đã đến lúc đo lường các 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ụ loadgen, 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 loadgen.
Trước tiên, chúng ta sẽ 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 span thực tế bên trong trình xử lý. Tìm func (*clientService) handler() và thêm tính 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 phương thức đo lường này, bạn sẽ nhận được các span từ đầu phương thức handler
đến cuối phương thức đó. Để dễ dàng phân tích các span, hãy thêm một thuộc tính bổ sung để lưu trữ số lượng trùng 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ả các thiết bị đo lường ở trên, bạn đã hoàn tất việc đo lường dấu vết giữa loadgen và ứng dụng. Hãy xem cách hoạt động của tính năng này. Chạy lại mã bằng skaffold.
skaffold dev
Sau một khoảng 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ư sau:
Kết quả của 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
phát ra các thông báo này. Bạn sẽ nhận thấy rằng phần tử mẹ của tất cả cá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 sẽ thấy thuộc tính nhúng "query"
có chuỗi truy vấn được chuyển đến dịch vụ khách hàng.
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ụ ứng dụng giao tiếp bằng HTTP, đồng thời xác nhận rằng bạn có thể truyền thành công Ngữ cảnh theo dõi trên các dịch vụ và xuất thông tin Span từ cả hai dịch vụ sang stdout.
Tiếp theo
Ở bước tiếp theo, bạn sẽ đo lường dịch vụ ứng dụng và dịch vụ máy chủ để xác nhận cách truyền tải Ngữ cảnh theo dõi qua gRPC.
5. Đ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 dịch vụ vi mô này. Trong 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à tím trong hình bên dưới)
Thiết bị đo lường trước khi tạo 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 nhà phát triển đo lường các ứng dụng. Ở bước trước, chúng ta đã sử dụng tính năng đo lường trước khi tạo cho gói net/http
. Trong bước này, khi cố gắng truyền tải Ngữ cảnh theo dõi thông qua gRPC, chúng ta sẽ sử dụng thư viện này.
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ụ máy khách 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 trình chặn gRPC đo lường các span mới mỗi khi ứng dụng gửi 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 trong phần trước, nên bạn không cần thiết lập lại.
Công cụ đo lường tạo sẵn cho máy chủ gRPC
Giống như những gì chúng ta đã làm cho ứng dụng gRPC, chúng ta gọi công cụ đo lường tạo sẵn cho máy chủ gRPC. Thêm gói mới vào phần nhập như sau:
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 đo lường máy chủ, 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 đã làm cho loadgen và các dịch vụ ứng dụng.
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 trình chặn máy chủ. Trong hàm main
, hãy tìm vị trí gọi grpc.NewServer()
và thêm trình 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
Giờ đây, bạn sẽ thấy một loạt thông tin span trên stdout.
Kết quả của 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 mình chưa nhúng tên span nào và đã 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ì trình chặn gRPC đã tạo ra các span đó.
Tóm tắt
Trong 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
Cuối cùng, trong 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 đã thu thập.
6. Hình dung dấu vết bằng Cloud Trace
Bạn đã đo lường dấu vết trong toàn bộ hệ thống bằng OpenTelemetry. Đến đây, bạn đã tìm hiểu cách đo lường các dịch vụ HTTP và gRPC. Mặc dù đã tìm hiểu cách đo lường các chỉ số này, nhưng bạn vẫn chưa tìm hiểu cách phân tích các chỉ số đó. Trong phần này, bạn sẽ thay thế trình xuất stdout bằng trình xuất Cloud Trace và tìm hiểu cách phân tích dấu vết.
Sử dụng trình xuất 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 do công cụ đo lường của bạn thu thập, bạn chỉ cần thay thế trình xuất tệp stdout bằng trình xuất Cloud Trace.
Mở tệp main.go
của từng dịch vụ và tìm hàm initTracer()
. Xoá dòng để 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 cùng một hàm 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, bạn chỉ cần chạy cụm như bình thường bằng lệnh skaffold.
skaffold dev
Sau đó, bạn sẽ không thấy nhiều thông tin 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 trình xuất Cloud Trace.
Kết quả của 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". Bạn có thể dễ dàng truy cập vào tính năng này 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 điểm đạ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ả khi chỉ xem nhanh thông tin đơn giản này, bạn cũng đã biết được nhiều thông tin chi tiết. Ví dụ: từ biểu đồ dạng thác nước, bạn có thể thấy nguyên nhân gây ra độ trễ chủ yếu là do span có tên shakesapp.ShakespeareService/GetMatchCount
. (Xem 1 trong hình trên) Bạn có thể xác nhận điều đó qua bảng tóm tắt. (Cột ngoài cùng bên phải cho biết thời lượng của mỗi span.) Ngoài ra, dấu vết này là của truy vấn "friend" (bạn bè). (Xem 2 trong hình ảnh ở trên)
Với những phân tích ngắn này, bạn có thể nhận ra rằng mình cần biết thêm về các span chi tiết hơn bên trong phương thức GetMatchCount
. So với thông tin stdout, hình ảnh trực quan rất mạnh mẽ. Để tìm hiểu thêm về 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 tệp stdout bằng trình xuất Cloud Trace và trực quan hoá các dấu vết 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 con trong GetMatchCount.
7. Thêm span phụ để phân tích hiệu quả hơn
Ở bước trước, bạn đã tìm thấy nguyên nhân gây ra thời gian thực hiện một vòng từ loadgen chủ yếu là 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 ta chưa đo lường bất kỳ giá trị nào khác ngoài trình xử lý, nên chúng ta không thể tìm thấy thông tin chi tiết khác từ biểu đồ dạng thác nước. Đây là trường hợp thường gặp khi chúng ta 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 con trong đó máy chủ gọi Google Cloud Storage, vì thường thì một số I/O mạng bên ngoài sẽ mất nhiều thời gian trong quá trình này và điều quan trọng là phải xác định xem lệnh gọi có phải là nguyên nhân hay không.
Đo lường một span con trong máy chủ
Mở main.go
trong máy chủ và 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 của các tác phẩm của Shakespeare. Trong hàm này, bạn có thể tạo một span con, giống như những gì bạn đã làm cho hoạt độ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ì cần làm để thêm một span mới. Hãy chạy ứng dụng để xem kết quả.
Chạy dịch vụ vi mô và xác nhận dấu vết
Sau khi chỉnh sửa, bạn chỉ cần chạy cụm như bình thường bằng lệnh skaffold.
skaffold dev
Và chọn một dấu vết có tên query.request
trong danh sách dấu vết. 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
. (Phần span được bao quanh bởi hình chữ nhật màu đỏ bên dưới)
Từ biểu đồ này, bạn có thể biết rằng lệnh gọi bên ngoài đến Google Cloud Storage chiếm một lượng lớn độ trễ, nhưng vẫn có những yếu tố khác gây ra phần lớn độ trễ.
Bạn đã có được nhiều thông tin chi tiết chỉ bằng một vài lần xem biểu đồ dạng thác nước theo dõi. Làm cách nào để bạn có được thông tin chi tiết hơn về hiệu suất trong ứng dụng? Đây là lúc trình phân tích tài nguyên xuất hiện. Tuy nhiên, hiện tại, hãy kết thúc lớp học lập trình này và chuyển tất cả hướng dẫn về trình phân tích tài nguyên sang phần 2.
Tóm tắt
Trong bước này, bạn đã đo lường một span khác trong dịch vụ máy chủ và thu thập thêm thông tin chi tiết về độ trễ của hệ thống.
8. Xin chúc mừng
Bạn đã tạo thành công các dấu vết phân tán bằng OpenTelemery và xác nhận độ trễ 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ể tự mình thử các chủ đề sau.
- Cách triển khai hiện tại sẽ gửi tất cả các span do tính năng kiểm tra tình trạng tạo ra. (
grpc.health.v1.Health/Check
) Làm cách nào để lọc ra các span đó khỏi Cloud Trace? Gợi ý tại đây. - Liên kết nhật ký sự kiện với các span và xem cách hoạt động của nhật ký sự kiện trên Google Cloud Trace và Google Cloud Logging. Gợi ý tại đây.
- Thay thế một số dịch vụ bằng dịch vụ bằng ngôn ngữ khác và cố gắng đo lường dịch vụ đó 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 bên dưới.
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 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 tổ hợp phím 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ả của 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 "Quản trị và quản lý danh tính và quyền truy cập (IAM) > Cài đặt", rồi nhấp vào nút "TẮT".
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 rồi xác nhận tắt.