1. Wprowadzenie
Ostatnia aktualizacja: 14.07.2022 r.
Dostrzegalność aplikacji
Dostrzegalność i ciągłe profilowanie
Dostrzegalność to termin opisujący atrybut układu. System z obserwowalnością umożliwia zespołom aktywne debugowanie systemu. W tym kontekście 3 filary dostrzegalności: logi, wskaźniki i logi czasu to podstawowe narzędzia umożliwiające systemowi uzyskiwanie dostrzegalności.
Oprócz 3 filarów obserwowalności kolejną kluczową funkcją jest ciągłe profilowanie, które poszerza bazę użytkowników w branży. Narzędzie Cloud Profiler jest jednym z pierwszych i zapewnia łatwy interfejs do analizowania danych o wydajności w zbiorach wywołań aplikacji.
Ćwiczenie w Codelabs jest częścią 2 tej serii i opisuje konfigurowanie agenta do profilowania ciągłego. Część 1 dotyczy śledzenia rozproszonego za pomocą OpenTelemetry i Cloud Trace, a w części 1 dowiesz się więcej o tym, jak lepiej identyfikować wąskie gardła mikroserwisów.
Co utworzysz
W tym ćwiczeniu w Codelabs dowiesz się, jak wdrożyć agenta ciągłego profilowania w usłudze serwera aplikacji Szekspira. (inaczej Shakesapp), która działa w klastrze Google Kubernetes Engine. Architektura Shakesapp:
- Loadgen wysyła ciąg zapytania do klienta w HTTP
- Klienci przekazują zapytanie od generatora obciążenia do serwera w gRPC
- Serwer akceptuje zapytanie od klienta, pobiera wszystkie dzieła Szekspira w formacie tekstowym z Google Cloud Storage, wyszukuje wiersze zawierające zapytanie i zwraca numer wiersza dopasowanego do klienta.
W części 1. stwierdziliśmy, że wąskie gardło występuje gdzieś w usłudze serwera, ale nie udało się nam ustalić dokładnej przyczyny.
Czego się nauczysz
- Jak umieścić agenta profilującego
- Jak zbadać szyję butelki w Cloud Profiler
Dzięki temu ćwiczeniu w Codelabs dowiesz się, jak wdrożyć w aplikacji agenta ciągłego profilującego.
Czego potrzebujesz
- Podstawowa znajomość języka Go
- podstawową wiedzę o Kubernetes;
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
Jeśli nie masz jeszcze konta Google (w Gmailu lub Google Apps), musisz je utworzyć. Zaloguj się w konsoli Google Cloud Platform (console.cloud.google.com) i utwórz nowy projekt.
Jeśli masz już projekt, kliknij menu wyboru projektu w lewym górnym rogu konsoli:
i kliknij przycisk „NOWY PROJEKT” w wyświetlonym oknie, aby utworzyć nowy projekt:
Jeśli nie masz jeszcze projektu, zobaczysz takie okno dialogowe umożliwiające utworzenie pierwszego:
W kolejnym oknie tworzenia projektu możesz wpisać szczegóły nowego projektu:
Zapamiętaj identyfikator projektu, który jest unikalną nazwą we wszystkich projektach Google Cloud (podane powyżej imię i nazwisko jest już zajęte i nie będzie działać). W dalszej części tego ćwiczenia z programowania będzie on określany jako PROJECT_ID.
Następnie musisz włączyć płatności w Developers Console, aby korzystać z zasobów Google Cloud i włączyć Cloud Trace API.
Wykonanie tych ćwiczeń w programie nie powinno kosztować więcej niż kilka dolarów, ale może być droższe, jeśli zdecydujesz się na więcej zasobów lub pozostawisz je włączone (patrz sekcja „Czyszczenie” na końcu tego dokumentu). Ceny Google Cloud Trace, Google Kubernetes Engine i Google Artifact Registry są podane w oficjalnej dokumentacji.
- Ceny pakietu operacyjnego Google Cloud | Operations Suite
- Ceny | Dokumentacja Kubernetes Engine
- Ceny Artifact Registry | Dokumentacja Artifact Registry
Nowi użytkownicy Google Cloud Platform mogą skorzystać z bezpłatnej wersji próbnej o wartości 300 USD, dzięki czemu te ćwiczenia z programowania będą całkowicie bezpłatne.
Konfiguracja Google Cloud Shell
Usługi Google Cloud i Google Cloud Trace można obsługiwać zdalnie z poziomu laptopa, ale w tym ćwiczeniu z programowania wykorzystamy Google Cloud Shell – środowisko wiersza poleceń działające w chmurze.
Ta maszyna wirtualna oparta na Debianie zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie poprawia wydajność sieci i uwierzytelnianie. Oznacza to, że do tego ćwiczenia będziesz potrzebować tylko przeglądarki (tak, działa to na Chromebooku).
Aby aktywować Cloud Shell z poziomu konsoli Cloud, kliknij Aktywuj Cloud Shell (udostępnienie środowiska i połączenie z nim powinno zająć tylko chwilę).
Po nawiązaniu połączenia z Cloud Shell powinno pojawić się potwierdzenie, że użytkownik jest już uwierzytelniony, a projekt jest już ustawiony na PROJECT_ID
.
gcloud auth list
Dane wyjściowe polecenia
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Wynik polecenia
[core] project = <PROJECT_ID>
Jeśli z jakiegoś powodu projekt nie jest skonfigurowany, uruchom po prostu to polecenie:
gcloud config set project <PROJECT_ID>
Szukasz urządzenia PROJECT_ID
? Sprawdź, jakiego identyfikatora użyto w procesie konfiguracji, lub odszukaj go w panelu Cloud Console:
Cloud Shell domyślnie ustawia też niektóre zmienne środowiskowe, co może być przydatne podczas wykonywania kolejnych poleceń.
echo $GOOGLE_CLOUD_PROJECT
Dane wyjściowe polecenia
<PROJECT_ID>
Na koniec ustaw domyślną strefę i konfigurację projektu.
gcloud config set compute/zone us-central1-f
Możesz wybrać różne strefy. Więcej informacji znajdziesz w artykule Regiony i Strefy.
Skonfiguruj język
W tym ćwiczeniu w Codelabs cały kod źródłowy używamy w języku Go. Uruchom to polecenie w Cloud Shell i sprawdź, czy wersja Go to 1.17 lub nowsza.
go version
Dane wyjściowe polecenia
go version go1.18.3 linux/amd64
Konfigurowanie klastra Google Kubernetes
W tym praktycznym laboratorium uruchomisz klaster mikroserwisów w Google Kubernetes Engine (GKE). Proces w tym ćwiczeniu obejmuje te czynności:
- Pobierz projekt bazowy do Cloud Shell
- Tworzenie mikroserwisów w kontenerach
- Przesyłanie kontenerów do Google Artifact Registry (GAR)
- Wdrażanie kontenerów w GKE
- zmodyfikować kod źródłowy usług w celu przeprowadzenia instrumentacji śledzonej,
- Przejdź do kroku 2
Włącz Kubernetes Engine
Najpierw skonfigurowaliśmy klaster Kubernetes, w którym aplikacja Shakesapp działa w GKE, więc musimy włączyć GKE. Przejdź do menu „Kubernetes Engine” i naciśnij przycisk WŁĄCZ.
Teraz możesz utworzyć klaster Kubernetes.
Tworzenie klastra Kubernetes
Aby utworzyć klaster Kubernetes, uruchom w Cloud Shell to polecenie: Potwierdź, że wartość strefy znajduje się w regionie, który będzie używany do tworzenia repozytorium Artifact Registry. Zmień wartość strefy us-central1-f
, jeśli region repozytorium nie obejmuje danej strefy.
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
Dane wyjściowe polecenia
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
Konfiguracja Artifact Registry i skaffolda
Klaster Kubernetes jest teraz gotowy do wdrożenia. W kolejnym kroku przygotujemy rejestr kontenerów do wypychania i wdrażania kontenerów. Aby wykonać te czynności, musimy skonfigurować Artifact Registry (GAR) i skaffold, aby z niego korzystać.
Konfiguracja Artifact Registry
Przejdź do menu „Artifact Registry” i naciśnij przycisk WŁĄCZ.
Po chwili zobaczysz przeglądarkę repozytoriów GAR. Kliknij „UTWÓRZ REPOZYTORIUM”. i wpisz nazwę repozytorium.
W ramach tego ćwiczenia w Codelabs nadam nowemu repozytorium nazwę trace-codelab
. Format artefaktu to „Docker” a typ lokalizacji to „Region”. Wybierz region bliski temu, który został ustawiony dla domyślnej strefy Google Compute Engine. W tym przykładzie wybrano „us-central1-f”. powyżej, więc tutaj wybieramy „us-central1 (Iowa)”. Następnie kliknij przycisk „Utwórz”.
Teraz widzisz „trace-codelab”. w przeglądarce repozytoriów.
Wrócimy tu później, aby sprawdzić ścieżkę rejestru.
Konfiguracja Skaffold
Skaffold to przydatne narzędzie podczas tworzenia mikroserwisów działających w Kubernetes. Obsługuje przepływ pracy związany z tworzeniem, wypychaniem i wdrażaniem kontenerów aplikacji za pomocą niewielkiego zestawu poleceń. Skaffold domyślnie używa Docker Registry jako rejestru kontenerów, dlatego musisz skonfigurować skaffold tak, aby rozpoznawał GAR przy przekazywaniu kontenerów do kontenerów.
Ponownie otwórz Cloud Shell i sprawdź, czy narzędzie skaffold jest zainstalowane. (Cloud Shell domyślnie instaluje skaffold w środowisku). Uruchom to polecenie, aby sprawdzić wersję skaffold.
skaffold version
Dane wyjściowe polecenia
v1.38.0
Teraz możesz zarejestrować domyślne repozytorium, z którego będzie korzystać skaffold. Aby uzyskać ścieżkę rejestru, otwórz panel Artifact Registry i kliknij nazwę repozytorium skonfigurowanego w poprzednim kroku.
Następnie u góry strony zobaczysz elementy menu nawigacyjnego. Kliknij ikonę , aby skopiować ścieżkę rejestru do schowka.
Po kliknięciu przycisku kopiowania na dole okna przeglądarki pojawi się okno z komunikatem takim jak:
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" została skopiowana
Wróć do Cloud Shell. Uruchom polecenie skaffold config set default-repo
z wartością skopiowaną właśnie z panelu.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
Dane wyjściowe polecenia
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
Musisz też skonfigurować rejestr pod kątem konfiguracji Dockera. Uruchom to polecenie:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
Dane wyjściowe polecenia
{ "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
Teraz możesz przejść do następnego kroku konfigurowania kontenera Kubernetes w GKE.
Podsumowanie
W tym kroku skonfigurujesz środowisko ćwiczeń z programowania:
- Konfigurowanie Cloud Shell
- Utworzono repozytorium Artifact Registry dla rejestru kontenerów
- Skonfiguruj skaffold, aby korzystać z rejestru kontenerów
- Utworzono klaster Kubernetes, w którym działają mikroserwisy ćwiczeń z programowania
Dalsze czynności
W następnym kroku przyłączysz agenta ciągłego profilowania w usłudze serwera.
3. Tworzenie, przekazywanie i wdrażanie mikroserwisów
Pobierz materiały z ćwiczeń z programowania
W poprzednim kroku skonfigurowaliśmy wszystkie wymagania wstępne tego ćwiczenia z programowania. Teraz możesz uruchomić na nich całe mikroserwisy. Materiały do ćwiczeń z programowania są hostowane na GitHubie, więc pobierz je do środowiska Cloud Shell za pomocą tego polecenia git.
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
Struktura katalogów projektu jest następująca:
. ├── 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
- pliki manifestu: pliki manifestu Kubernetes.
- proto: definicja protokołu dla komunikacji między klientem a serwerem
- src: katalogi kodu źródłowego poszczególnych usług
- skaffold.yaml: plik konfiguracji dla skaffold
W ramach tego ćwiczenia w Codelabs zaktualizujesz kod źródłowy znajdujący się w folderze step4
. Możesz też zapoznać się z kodem źródłowym w step[1-6]
folderach, aby uzyskać informacje o zmianach od początku. (część 1 obejmuje kroki 0–4, a część 2 – kroki 5–6)
Uruchom polecenie skaffold
Teraz możesz skompilować, przesłać i wdrożyć wszystkie treści do utworzonego właśnie klastra Kubernetes. Wygląda na to, że składa się z wielu kroków, ale w rzeczywistości skaffold robi wszystko za Ciebie. Spróbujmy to zrobić za pomocą tego polecenia:
cd step4 skaffold dev
Natychmiast po uruchomieniu polecenia zostaną wyświetlone dane wyjściowe dziennika docker build
i będziesz mieć pewność, że zostały one przekazane do rejestru.
Dane wyjściowe polecenia
... ---> 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
Po przekazaniu wszystkich kontenerów usługi wdrożenia Kubernetes uruchamiają się automatycznie.
Dane wyjściowe polecenia
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
Po wdrożeniu zobaczysz rzeczywiste logi aplikacji wysyłane do stdout w poszczególnych kontenerach w następujący sposób:
Dane wyjściowe polecenia
[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
Na tym etapie chcesz wyświetlić wszystkie wiadomości z serwera. Właśnie możesz zacząć instrumentować aplikację za pomocą OpenTelemetry w celu rozproszonego śledzenia usług.
Zanim zaczniesz instrumentować usługę, wyłącz klaster, naciskając klawisze Ctrl + C.
Wynik polecenia
... [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
Podsumowanie
Na tym etapie masz już przygotowane materiały z ćwiczeń z programowania w swoim środowisku oraz potwierdzone uruchomienia skaffold zgodnie z oczekiwaniami.
Dalsze czynności
W następnym kroku zmodyfikujesz kod źródłowy usługi loadgen, aby dostosować dane śledzenia.
4. Instrumentacja agenta Cloud Profiler
Pojęcie profilowania ciągłego
Zanim objaśnimy pojęcie profilowania ciągłego, musimy zrozumieć, czym jest profilowanie. Profilowanie to jeden ze sposobów dynamicznej analizy aplikacji (dynamiczna analiza programu). Jest ono zwykle wykonywane podczas tworzenia aplikacji w ramach testowania obciążeniowego itp. To jednorazowe działanie mające na celu pomiar wskaźników systemowych, takich jak wykorzystanie procesora i pamięci, w wybranym okresie. Po zebraniu danych do profilu deweloperzy analizują je bezpośrednio w kodzie.
Profilowanie ciągłe to rozszerzona metoda profilowania normalnego: okresowo uruchamia profile krótkich okien w przypadku długotrwałej aplikacji i gromadzi sporą ilość danych profilowych. Następnie automatycznie generuje analizę statystyczną na podstawie określonego atrybutu aplikacji, takiego jak numer wersji, strefa wdrożenia, czas pomiaru itd. Więcej informacji na ten temat znajdziesz w naszej dokumentacji.
Ponieważ celem jest uruchomiona aplikacja, można okresowo gromadzić dane profilowe i wysyłać je do backendu, który następnie przetwarza dane statystyczne. To jest agent Cloud Profiler, który wkrótce zostanie wbudowany w usługę serwera.
Umieszczanie agenta Cloud Profiler
Otwórz edytor Cloud Shell, naciskając przycisk w prawym górnym rogu Cloud Shell. Otwórz
step4/src/server/main.go
w eksploratorze w panelu po lewej stronie i znajdź funkcję główną.
step4/src/server/main.go
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 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) healthpb.RegisterHealthServer(srv, svc) if err := srv.Serve(lis); err != nil { log.Fatalf("error serving server: %v", err) } }
W funkcji main
jest widoczny kod konfiguracji dla OpenTelemetry i gRPC, który został wykonany w części 1 ćwiczenia w Codelabs. Teraz dodasz instrumentację dla agenta Cloud Profiler. Podobnie jak w przypadku funkcji initTracer()
, możesz napisać funkcję o nazwie initProfiler()
, aby uzyskać czytelność.
step4/src/server/main.go
import ( ... "cloud.google.com/go/profiler" // step5. add profiler package "cloud.google.com/go/storage" ... ) // step5: add Profiler initializer func initProfiler() { cfg := profiler.Config{ Service: "server", ServiceVersion: "1.0.0", NoHeapProfiling: true, NoAllocProfiling: true, NoGoroutineProfiling: true, NoCPUProfiling: false, } if err := profiler.Start(cfg); err != nil { log.Fatalf("failed to launch profiler agent: %v", err) } }
Przyjrzyjmy się opcjom określonym w obiekcie profiler.Config{}
.
- Usługa: nazwa usługi, którą możesz wybrać i włączyć w panelu narzędzia do profilowania.
- ServiceVersion: nazwa wersji usługi. Na podstawie tej wartości możesz porównywać zbiory danych profilu.
- NoHeapProfiling: wyłącz profilowanie wykorzystania pamięci
- NoAllocProfiling: wyłącza profilowanie alokacji pamięci.
- NoGoroutineProfiling: wyłączanie profilowania goroutine
- NoCPUProfiling: wyłącz profilowanie procesora
W tym ćwiczeniu w Codelabs włączamy tylko profilowanie procesora.
Teraz musisz wywołać tę funkcję w funkcji main
. Pamiętaj, aby zaimportować pakiet Cloud Profiler do bloku importu.
step4/src/server/main.go
func main() { ... defer func() { if err := tp.Shutdown(context.Background()); err != nil { log.Fatalf("error shutting down TracerProvider: %v", err) } }() // step2. end setup // step5. start profiler go initProfiler() // step5. end svc := NewServerService() // step2: add interceptor ... }
Pamiętaj, że wywołujesz funkcję initProfiler()
za pomocą słowa kluczowego go
. Ponieważ zasada profiler.Start()
blokuje działanie, trzeba je uruchomić w innym kodzie. Możesz go teraz utworzyć. Pamiętaj, aby przed wdrożeniem uruchomić go mod tidy
.
go mod tidy
Teraz wdróż klaster z nową usługą serwera.
skaffold dev
Wykres płomienia w Cloud Profiler pojawia się zwykle po kilku minutach. Wpisz „profiler” w polu wyszukiwania u góry i kliknij ikonę programu profilującego.
Następnie zobaczysz następujący wykres płomieni.
Podsumowanie
W tym kroku dodałaś lub dodałeś agenta Cloud Profiler do usługi serwera i potwierdził(a)eś, że generuje on wykres płomienia.
Dalsze czynności
W następnym kroku za pomocą wykresu płomieniowego zbadasz przyczynę wąskiego gardła w aplikacji.
5. Analizowanie wykresu płomieniowego Cloud Profiler
Czym jest wykres płomieniowy?
Wykres płomieniowy to jeden ze sposobów wizualizacji danych profilowych. Szczegółowe wyjaśnienie można znaleźć w naszym dokumencie. Jego krótkie podsumowanie to:
- Każdy słupek opisuje wywołanie metody/funkcji w aplikacji.
- Kierunek pionowy to stos wywołań. stos wywołań rośnie od góry do dołu
- Kierunek poziomy to wykorzystanie zasobów. im dłuższe, tym gorsze.
Spójrzmy na uzyskany wykres płomieniowy.
Analiza wykresu płomieniowego
W poprzedniej sekcji wiemy, że każdy słupek na wykresie płomieniowym wyraża wywołanie funkcji/metody, a jego długość oznacza wykorzystanie zasobów przez funkcję/metodę. Wykres płomienia w Cloud Profiler sortuje słupek w porządku malejącym lub według długości od lewej do prawej. Możesz zacząć od lewego górnego rogu wykresu.
W naszym przypadku funkcja grpc.(*Server).serveStreams.func1.2
zużywa najwięcej czasu procesora. Przeglądając od góry do dołu stos wywołań, widać, że większość czasu jest poświęcana na funkcję main.(*serverService).GetMatchCount
, która jest modułem obsługi serwera gRPC w usłudze serwera.
W sekcji GetMatchCount znajdziesz szereg funkcji regexp: regexp.MatchString
i regexp.Compile
. Pochodzą one z pakietu standardowego: oznacza to, że powinny być dobrze przetestowane pod wieloma względami, w tym także pod względem skuteczności. Wynik pokazuje jednak, że wykorzystanie zasobów czasu procesora jest wysokie w regexp.MatchString
i regexp.Compile
. Biorąc pod uwagę te fakty, zakładamy, że użycie właściwości regexp.MatchString
ma związek z problemami z wydajnością. Spójrzmy więc na kod źródłowy, w którym jest używana ta funkcja.
step4/src/server/main.go
func (s *serverService) GetMatchCount(ctx context.Context, req *shakesapp.ShakespeareRequest) (*shakesapp.ShakespeareResponse, error) { resp := &shakesapp.ShakespeareResponse{} texts, err := readFiles(ctx, bucketName, bucketPrefix) if err != nil { return resp, fmt.Errorf("fails to read files: %s", err) } for _, text := range texts { for _, line := range strings.Split(text, "\n") { line, query := strings.ToLower(line), strings.ToLower(req.Query) isMatch, err := regexp.MatchString(query, line) if err != nil { return resp, err } if isMatch { resp.MatchCount++ } } } return resp, nil }
To miejsce, w którym nazywa się regexp.MatchString
. Czytając kod źródłowy, możesz zauważyć, że funkcja jest wywoływana wewnątrz zagnieżdżonej pętli for. Dlatego jej użycie może być nieprawidłowe. Wyszukajmy obiekt GoDoc dotyczący elementu regexp.
Zgodnie z dokumentem w każdym wywołaniu funkcja regexp.MatchString
kompiluje wzorzec wyrażenia regularnego. Tak więc przyczyna dużego zużycia zasobów brzmi tak.
Podsumowanie
W tym kroku przyjęliśmy założenie o przyczynie zużycia zasobów, analizując graf płomieniowy.
Dalsze czynności
W następnym kroku zaktualizujesz kod źródłowy usługi serwera i potwierdzisz zmianę z wersji 1.0.0.
6. Zaktualizować kod źródłowy i rozróżnić grafy płomieniowe
Aktualizowanie kodu źródłowego
W poprzednim kroku założyliśmy, że użycie funkcji regexp.MatchString
ma związek z dużą ilością wykorzystywanych zasobów. Postarajmy się rozwiązać ten problem. Otwórz kod i trochę go zmień.
step4/src/server/main.go
func (s *serverService) GetMatchCount(ctx context.Context, req *shakesapp.ShakespeareRequest) (*shakesapp.ShakespeareResponse, error) { resp := &shakesapp.ShakespeareResponse{} texts, err := readFiles(ctx, bucketName, bucketPrefix) if err != nil { return resp, fmt.Errorf("fails to read files: %s", err) } // step6. considered the process carefully and naively tuned up by extracting // regexp pattern compile process out of for loop. query := strings.ToLower(req.Query) re := regexp.MustCompile(query) for _, text := range texts { for _, line := range strings.Split(text, "\n") { line = strings.ToLower(line) isMatch := re.MatchString(line) // step6. done replacing regexp with strings if isMatch { resp.MatchCount++ } } } return resp, nil }
Jak widać, proces kompilacji wzorca wyrażeń regularnych jest teraz wyodrębniany z tabeli regexp.MatchString
i wycofywany z zagnieżdżonej pętli „for”.
Zanim wdrożysz ten kod, pamiętaj o zaktualizowaniu ciągu znaków wersji w funkcji initProfiler()
.
step4/src/server/main.go
func initProfiler() { cfg := profiler.Config{ Service: "server", ServiceVersion: "1.1.0", // step6. update version NoHeapProfiling: true, NoAllocProfiling: true, NoGoroutineProfiling: true, NoCPUProfiling: false, } if err := profiler.Start(cfg); err != nil { log.Fatalf("failed to launch profiler agent: %v", err) } }
Zobaczmy, jak to działa. Wdróż klaster za pomocą polecenia skaffold.
skaffold dev
Po chwili załaduj ponownie panel Cloud Profiler i sprawdź, jak to działa.
Pamiętaj, aby zmienić wersję na "1.1.0"
, tak aby widoczne były tylko profile z wersji 1.1.0. Jak widać, długość paska funkcji GetMatchCount się zmniejszyła, a współczynnik wykorzystania czasu procesora (czyli długość paska) się skrócił.
Nie tylko patrząc na wykres płomieniowy pojedynczej wersji, możesz także porównać różnice między dwiema wersjami.
Zmiana wartości opcji „Porównaj z” z listy „Wersja” i zmienić wartość „Porównywana wersja” do wersji oryginalnej „1.0.0”.
Zobaczysz taki wykres płomieniowy. Kształt wykresu jest taki sam jak w wersji 1.1.0, ale kolorystyka jest inna. W trybie porównawczym kolory to:
- Niebieski: wartość (zużycie zasobów) zmniejszona.
- Pomarańczowy: wartość (wykorzystanie zasobów)
- Szary: neutralny.
Mając na uwadze legendę, przyjrzyjmy się bliżej tej funkcji. Po kliknięciu paska, który chcesz powiększyć, zobaczysz więcej szczegółów w grupie. Kliknij pasek main.(*serverService).GetMatchCount
. Najeżdżając kursorem na słupek, zobaczysz także szczegóły porównania.
Oznacza to, że łączny czas pracy procesora został zmniejszony z 5,26 s do 2,88 s (łącznie 10 s = okno próbkowania). To ogromna poprawa.
Teraz możesz zwiększyć wydajność swojej aplikacji dzięki analizie danych profilowych.
Podsumowanie
W tym kroku wprowadziliśmy zmianę w usłudze serwera i potwierdziliśmy poprawę w trybie porównania Cloud Profiler.
Dalsze czynności
W następnym kroku zaktualizujesz kod źródłowy usługi serwera i potwierdzisz zmianę z wersji 1.0.0.
7. Dodatkowy krok: sprawdź ulepszenie kaskady śledzenia
Różnica między logiem rozproszonym a profilowaniem ciągłym
W części 1 ćwiczeń z programowania udało Ci się potwierdzić, że jesteś w stanie znaleźć usługę wąskiego gardła we wszystkich mikroserwisach na ścieżce żądań i że nie jesteś w stanie ustalić dokładnej przyczyny wąskiego gardła w konkretnej usłudze. Z tego drugiego ćwiczenia w Codelab dowiesz się, że ciągłe profilowanie umożliwia identyfikowanie wąskich gardeł w pojedynczej usłudze na podstawie stertów wywołań.
W tym kroku przyjrzyjmy się wykresowi kaskadowemu na podstawie rozproszonego logu czasu (Cloud Trace) i zobaczmy różnicę w stosunku do profilowania ciągłego.
Ten wykres kaskadowy to jeden z śladów z zapytaniem „love”. Łącznie zajmuje to 6,7 s (6700 ms).
A tak wygląda ta sama wyszukiwarka po wprowadzeniu ulepszeń. Całkowity czas oczekiwania wynosi teraz 1, 5 s (1500 ms), co jest ogromnym usprawnieniem w porównaniu z poprzednią implementacją.
Ważne jest, że na wykresie kaskadowym rozproszonej analizy informacji o zbiorze wywołań nie ma, chyba że masz włączone śledzenie w każdym miejscu. Ponadto rozproszone ścieżki koncentrują się tylko na opóźnieniu w usługach, podczas gdy ciągłe profilowanie koncentruje się na zasobach komputera (procesor, pamięć, wątki systemu operacyjnego) w pojedynczej usłudze.
W innym aspekcie rozproszony log czasu stanowi podstawę zdarzeń, a profil ciągły ma charakter statystyczny. Każdy log czasu ma inny wykres czasu oczekiwania. Aby poznać trend zmian czasu oczekiwania, potrzebujesz innego formatu, np. dystrybucji.
Podsumowanie
W tym kroku sprawdzisz różnicę między logiem rozproszonym a profilowaniem ciągłym.
8. Gratulacje
Udało Ci się utworzyć rozproszone logi czasu przy użyciu OpenTelemery i potwierdzone opóźnienia żądań w mikroserwisie w Google Cloud Trace.
W przypadku dłuższych ćwiczeń możesz samodzielnie wypróbować poniższe tematy.
- Obecna implementacja wysyła wszystkie spany wygenerowane przez kontrolę stanu. (
grpc.health.v1.Health/Check
) W jaki sposób odfiltrowujesz te spany z Cloud Trace? Wskazówka znajdziesz tutaj. - Skoreluj logi zdarzeń ze spanami i sprawdź, jak działa to w Google Cloud Trace i Google Cloud Logging. Wskazówka znajdziesz tutaj.
- Zastąp jakąś usługę usługą w innym języku i spróbuj dopasować ją do usługi OpenTelemetry dla tego języka.
Jeśli chcesz dowiedzieć się więcej o narzędziu do profilowania, przejdź do części 2. W takim przypadku możesz pominąć sekcję Czyszczenie znajdującą się poniżej.
Czyszczenie danych
Po ukończeniu tego ćwiczenia w Codelabs zatrzymaj klaster Kubernetes i pamiętaj o usunięciu projektu, aby nie otrzymywać nieoczekiwanych opłat w Google Kubernetes Engine, Google Cloud Trace czy Google Artifact Registry.
Najpierw usuń klaster. Jeśli używasz klastra skaffold dev
, wystarczy nacisnąć Ctrl + C. Jeśli używasz klastra z wersją skaffold run
, uruchom to polecenie:
skaffold delete
Dane wyjściowe polecenia
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
Po usunięciu klastra w panelu menu wybierz „Uprawnienia Administrator > „Ustawienia”, a następnie kliknij „WYŁĄCZ” Przycisk
Następnie wpisz identyfikator projektu (nie nazwę projektu) w formularzu w oknie i potwierdź zamknięcie.