1. परिचय

पिछले अपडेट की तारीख: 15-07-2022
ऐप्लिकेशन की निगरानी करने की सुविधा
Observability और OpenTelemetry
ऑब्ज़र्वेबिलिटी, किसी सिस्टम की एक विशेषता होती है. ऑब्ज़र्वेबिलिटी की सुविधा वाले सिस्टम की मदद से, टीमें अपने सिस्टम को आसानी से डीबग कर सकती हैं. इस संदर्भ में, सिस्टम के लिए तीन मुख्य बातें ज़रूरी हैं: लॉग, मेट्रिक, और ट्रेस. ये सिस्टम को ऑब्ज़र्वेबिलिटी हासिल करने में मदद करती हैं.
OpenTelemetry, स्पेसिफ़िकेशन, लाइब्रेरी, और एजेंट का एक सेट है. यह टेलीमेट्री डेटा (लॉग, मेट्रिक, और ट्रेस) के इंस्ट्रुमेंटेशन और एक्सपोर्ट को तेज़ करता है. इस डेटा की ज़रूरत ऑब्ज़र्वेबिलिटी के लिए होती है. OpenTelemetry, एक ओपन स्टैंडर्ड है. साथ ही, यह CNCF के तहत कम्यूनिटी की ओर से चलाया जाने वाला प्रोजेक्ट है. प्रोजेक्ट और इसके इकोसिस्टम की ओर से उपलब्ध कराई गई लाइब्रेरी का इस्तेमाल करके, डेवलपर अपने ऐप्लिकेशन को वेंडर न्यूट्रल तरीके से और कई आर्किटेक्चर के हिसाब से इंस्ट्रुमेंट कर सकते हैं.
इसके अलावा, ऑब्ज़र्वेबिलिटी के तीन मुख्य सिद्धांतों के साथ-साथ, लगातार प्रोफ़ाइलिंग करना भी ऑब्ज़र्वेबिलिटी का एक और मुख्य कॉम्पोनेंट है. साथ ही, यह इंडस्ट्री में उपयोगकर्ताओं की संख्या बढ़ा रहा है. Cloud Profiler, परफ़ॉर्मेंस मेट्रिक को जनरेट करने वाले टूल में से एक है. यह ऐप्लिकेशन कॉल स्टैक में परफ़ॉर्मेंस मेट्रिक की बारीकी से जांच करने के लिए, आसान इंटरफ़ेस उपलब्ध कराता है.
यह कोडलैब, सीरीज़ का पहला हिस्सा है. इसमें OpenTelemetry और Cloud Trace की मदद से, माइक्रोसर्विस में डिस्ट्रिब्यूटेड ट्रेसिंग को लागू करने के बारे में बताया गया है. दूसरे भाग में, Cloud Profiler की मदद से लगातार प्रोफ़ाइलिंग करने के बारे में बताया जाएगा.
डिस्ट्रिब्यूटेड ट्रेस
लॉग, मेट्रिक, और ट्रेस में से ट्रेस, टेलीमेट्री है. यह सिस्टम में प्रोसेस के किसी खास हिस्से की लेटेन्सी के बारे में बताती है. खास तौर पर, माइक्रोसेवाओं के इस दौर में, डिस्ट्रिब्यूटेड ट्रेसिंग की मदद से, डिस्ट्रिब्यूटेड सिस्टम में लेटेन्सी की समस्याओं का पता लगाया जा सकता है.
डिस्ट्रिब्यूटेड ट्रेस का विश्लेषण करते समय, ट्रेस डेटा विज़ुअलाइज़ेशन की मदद से सिस्टम की कुल लेटेंसी को एक नज़र में समझा जा सकता है. डिस्ट्रीब्यूटेड ट्रेस में, हम सिस्टम के एंट्रीपॉइंट पर एक अनुरोध को प्रोसेस करने के लिए, कॉल के एक सेट को मैनेज करते हैं. यह सेट, कई स्पैन वाले ट्रेस के तौर पर होता है.
स्पैन, डिस्ट्रिब्यूटेड सिस्टम में किए गए काम की एक यूनिट को दिखाता है. यह रिकॉर्डिंग शुरू और बंद होने के समय को भी दिखाता है. स्पैन के बीच अक्सर क्रमबद्ध संबंध होते हैं. नीचे दी गई इमेज में, सभी छोटे स्पैन, बड़े /messages स्पैन के चाइल्ड स्पैन हैं. इन्हें एक ऐसे ट्रेस में असेंबल किया जाता है जो किसी सिस्टम में काम करने का तरीका दिखाता है.

Google Cloud Trace, डिस्ट्रिब्यूटेड ट्रेस बैकएंड के लिए उपलब्ध विकल्पों में से एक है. यह Google Cloud के अन्य प्रॉडक्ट के साथ अच्छी तरह से इंटिग्रेट किया गया है.
आपको क्या बनाने को मिलेगा
इस कोडलैब में, आपको Google Kubernetes Engine क्लस्टर पर चलने वाली "Shakespeare application" (इसे Shakesapp भी कहा जाता है) नाम की सेवाओं में ट्रेस की जानकारी को इंस्ट्रुमेंट करना है. Shakesapp का आर्किटेक्चर इस तरह से काम करता है:

- Loadgen, क्लाइंट को एचटीटीपी में क्वेरी स्ट्रिंग भेजता है
- क्लाइंट, gRPC में लोडजन से सर्वर तक क्वेरी पास करते हैं
- सर्वर, क्लाइंट से मिली क्वेरी को स्वीकार करता है. इसके बाद, Google Cloud Storage से शेक्सपियर की सभी रचनाओं को टेक्स्ट फ़ॉर्मैट में फ़ेच करता है. इसके बाद, क्वेरी से मेल खाने वाली लाइनों को खोजता है और क्लाइंट को उन लाइनों की संख्या दिखाता है
आपको पूरे अनुरोध में ट्रेस की जानकारी देनी होगी. इसके बाद, आपको सर्वर में प्रोफ़ाइलर एजेंट को एम्बेड करना होगा और बॉटलनेक की जांच करनी होगी.
आपको क्या सीखने को मिलेगा
- Go प्रोजेक्ट में OpenTelemetry Trace लाइब्रेरी का इस्तेमाल शुरू करने का तरीका
- लाइब्रेरी की मदद से स्पैन बनाने का तरीका
- ऐप्लिकेशन कॉम्पोनेंट के बीच वायर पर स्पैन कॉन्टेक्स्ट को कैसे फैलाएं
- Cloud Trace को ट्रेस डेटा भेजने का तरीका
- Cloud Trace पर ट्रेस का विश्लेषण कैसे करें
इस कोडलैब में, माइक्रोसेवाओं को इंस्ट्रुमेंट करने का तरीका बताया गया है. इसे आसानी से समझने के लिए, इस उदाहरण में सिर्फ़ तीन कॉम्पोनेंट (लोड जनरेटर, क्लाइंट, और सर्वर) शामिल हैं. हालांकि, इस कोडलैब में बताई गई प्रोसेस को ज़्यादा जटिल और बड़े सिस्टम पर भी लागू किया जा सकता है.
आपको इन चीज़ों की ज़रूरत होगी
- Go की बुनियादी जानकारी
- Kubernetes की बुनियादी जानकारी
2. सेटअप और ज़रूरी शर्तें
अपने हिसाब से एनवायरमेंट सेट अप करना
अगर आपके पास पहले से कोई Google खाता (Gmail या Google Apps) नहीं है, तो आपको एक खाता बनाना होगा. Google Cloud Platform Console ( console.cloud.google.com) में साइन इन करें और एक नया प्रोजेक्ट बनाएं.
अगर आपके पास पहले से कोई प्रोजेक्ट है, तो कंसोल में सबसे ऊपर बाईं ओर मौजूद, प्रोजेक्ट चुनने वाले पुल-डाउन मेन्यू पर क्लिक करें:

इसके बाद, नया प्रोजेक्ट बनाने के लिए, डायलॉग बॉक्स में मौजूद ‘नया प्रोजेक्ट' बटन पर क्लिक करें:

अगर आपके पास पहले से कोई प्रोजेक्ट नहीं है, तो आपको अपना पहला प्रोजेक्ट बनाने के लिए इस तरह का डायलॉग दिखेगा:

इसके बाद, प्रोजेक्ट बनाने के डायलॉग बॉक्स में, नए प्रोजेक्ट की जानकारी डाली जा सकती है:

प्रोजेक्ट आईडी याद रखें. यह सभी Google Cloud प्रोजेक्ट के लिए एक यूनीक नाम होता है. ऊपर दिया गया नाम पहले ही इस्तेमाल किया जा चुका है. इसलिए, यह आपके लिए काम नहीं करेगा. माफ़ करें! इस कोड लैब में इसे बाद में PROJECT_ID के तौर पर दिखाया जाएगा.
इसके बाद, अगर आपने अब तक ऐसा नहीं किया है, तो आपको Google Cloud के संसाधनों का इस्तेमाल करने के लिए, Developers Console में बिलिंग चालू करनी होगी. साथ ही, Cloud Trace API चालू करना होगा.

इस कोडलैब को पूरा करने में आपको कुछ डॉलर से ज़्यादा खर्च नहीं करने पड़ेंगे. हालांकि, अगर आपको ज़्यादा संसाधनों का इस्तेमाल करना है या उन्हें चालू रखना है, तो यह खर्च बढ़ सकता है. इस दस्तावेज़ के आखिर में "सफाई" सेक्शन देखें. Google Cloud Trace, Google Kubernetes Engine, और Google Artifact Registry की कीमतों के बारे में आधिकारिक दस्तावेज़ में बताया गया है.
- Google Cloud के कार्रवाइयों वाले सुइट की कीमत | कार्रवाइयों वाला सुइट
- कीमत | Kubernetes Engine के दस्तावेज़
- Artifact Registry की कीमत | Artifact Registry के दस्तावेज़
Google Cloud Platform के नए उपयोगकर्ताओं को, मुफ़्त में आज़माने के लिए 300 डॉलर मिलते हैं. इससे इस कोडलैब का इस्तेमाल बिना किसी शुल्क के किया जा सकता है.
Google Cloud Shell सेटअप करना
Google Cloud और Google Cloud Trace को अपने लैपटॉप से रिमोटली ऐक्सेस किया जा सकता है. हालांकि, इस कोडलैब में हम Google Cloud Shell का इस्तेमाल करेंगे. यह क्लाउड में चलने वाला कमांड लाइन एनवायरमेंट है.
यह Debian पर आधारित वर्चुअल मशीन है. इसमें डेवलपमेंट के लिए ज़रूरी सभी टूल पहले से मौजूद हैं. यह 5 जीबी की होम डायरेक्ट्री उपलब्ध कराता है और Google Cloud में चलता है. इससे नेटवर्क की परफ़ॉर्मेंस और पुष्टि करने की प्रोसेस बेहतर होती है. इसका मतलब है कि इस कोडलैब के लिए, आपको सिर्फ़ एक ब्राउज़र की ज़रूरत होगी. हां, यह Chromebook पर भी काम करता है.
Cloud Console से Cloud Shell को चालू करने के लिए, बस Cloud Shell चालू करें
पर क्लिक करें. इसे चालू होने और एनवायरमेंट से कनेक्ट होने में कुछ ही समय लगता है.


Cloud Shell से कनेक्ट होने के बाद, आपको दिखेगा कि आपकी पुष्टि पहले ही हो चुकी है और प्रोजेक्ट पहले से ही आपके PROJECT_ID पर सेट है.
gcloud auth list
कमांड आउटपुट
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
कमांड आउटपुट
[core] project = <PROJECT_ID>
अगर किसी वजह से प्रोजेक्ट सेट नहीं है, तो यह कमांड दें:
gcloud config set project <PROJECT_ID>
क्या आपको PROJECT_ID की तलाश है? देखें कि आपने सेटअप के दौरान किस आईडी का इस्तेमाल किया था या Cloud Console के डैशबोर्ड में जाकर इसे देखें:

Cloud Shell, कुछ एनवायरमेंट वैरिएबल को डिफ़ॉल्ट रूप से भी सेट करता है. ये वैरिएबल, आने वाले समय में कमांड चलाने के दौरान आपके काम आ सकते हैं.
echo $GOOGLE_CLOUD_PROJECT
कमांड आउटपुट
<PROJECT_ID>
आखिर में, डिफ़ॉल्ट ज़ोन और प्रोजेक्ट कॉन्फ़िगरेशन सेट करें.
gcloud config set compute/zone us-central1-f
आपके पास अलग-अलग ज़ोन चुनने का विकल्प होता है. ज़्यादा जानकारी के लिए, रीजन और ज़ोन देखें.
Go भाषा का सेटअप
इस कोडलैब में, हम सभी सोर्स कोड के लिए Go का इस्तेमाल करते हैं. Cloud Shell पर यहां दिया गया निर्देश चलाएं और पुष्टि करें कि Go का वर्शन 1.17 या इसके बाद का है या नहीं
go version
कमांड आउटपुट
go version go1.18.3 linux/amd64
Google Kubernetes Cluster सेट अप करना
इस कोडलैब में, Google Kubernetes Engine (GKE) पर माइक्रोसेवाओं का क्लस्टर चलाया जाएगा. इस कोडलैब की प्रोसेस इस तरह है:
- बेसलाइन प्रोजेक्ट को Cloud Shell में डाउनलोड करें
- कंटेनर में माइक्रोसेवाएं बनाना
- कंटेनर को Google Artifact Registry (GAR) पर अपलोड करना
- GKE पर कंटेनर डिप्लॉय करना
- ट्रेस इंस्ट्रूमेंटेशन के लिए, सेवाओं के सोर्स कोड में बदलाव करना
- दूसरे चरण पर जाएं
Kubernetes Engine चालू करें
सबसे पहले, हम एक Kubernetes क्लस्टर सेट अप करते हैं. इसमें Shakesapp, GKE पर चलता है. इसलिए, हमें GKE को चालू करना होगा. "Kubernetes Engine" मेन्यू पर जाएं और ENABLE बटन दबाएं.

अब आपके पास Kubernetes क्लस्टर बनाने का विकल्प है.
Kubernetes क्लस्टर बनाना
Kubernetes क्लस्टर बनाने के लिए, Cloud Shell पर यह कमांड चलाएं. कृपया पुष्टि करें कि ज़ोन की वैल्यू उस क्षेत्र के हिसाब से है जिसका इस्तेमाल, Artifact Registry रिपॉज़िटरी बनाने के लिए किया जाएगा. अगर आपकी रिपॉज़िटरी का क्षेत्र, ज़ोन में शामिल नहीं है, तो ज़ोन की वैल्यू us-central1-f बदलें.
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
कमांड आउटपुट
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
Artifact Registry और skaffold सेटअप करना
अब हमारे पास डिप्लॉयमेंट के लिए तैयार Kubernetes क्लस्टर है. इसके बाद, हम कंटेनर को पुश और डिप्लॉय करने के लिए, कंटेनर रजिस्ट्री तैयार करते हैं. इन चरणों के लिए, हमें Artifact Registry (GAR) सेट अप करना होगा. साथ ही, इसका इस्तेमाल करने के लिए skaffold सेट अप करना होगा.
Artifact Registry का सेटअप
"Artifact Registry" के मेन्यू पर जाएं और 'चालू करें' बटन दबाएं.

कुछ समय बाद, आपको GAR का रिपॉज़िटरी ब्राउज़र दिखेगा. "CREATE REPOSITORY" बटन पर क्लिक करें और रिपॉज़िटरी का नाम डालें.

इस कोडलैब में, मैंने नई रिपॉज़िटरी का नाम trace-codelab रखा है. आर्टफ़ैक्ट का फ़ॉर्मैट "Docker" है और लोकेशन का टाइप "Region" है. Google Compute Engine के डिफ़ॉल्ट ज़ोन के लिए सेट किए गए क्षेत्र के आस-पास का क्षेत्र चुनें. उदाहरण के लिए, ऊपर दिए गए उदाहरण में "us-central1-f" चुना गया है. इसलिए, यहां हम "us-central1 (Iowa)" चुनते हैं. इसके बाद, "बनाएं" बटन पर क्लिक करें.

अब आपको रिपॉज़िटरी ब्राउज़र पर "trace-codelab" दिखेगा.

हम रजिस्ट्री पाथ की जांच करने के लिए, बाद में इस पेज पर वापस आएंगे.
Skaffold सेट अप करना
Skaffold एक ऐसा टूल है जो Kubernetes पर चलने वाली माइक्रोसर्विस बनाने में आपकी मदद करता है. यह कुछ कमांड की मदद से, ऐप्लिकेशन के कंटेनर बनाने, पुश करने, और डिप्लॉय करने के वर्कफ़्लो को मैनेज करता है. Skaffold डिफ़ॉल्ट रूप से, Docker Registry को कंटेनर रजिस्ट्री के तौर पर इस्तेमाल करता है. इसलिए, आपको Skaffold को कॉन्फ़िगर करना होगा, ताकि वह कंटेनर को GAR पर पुश कर सके.
Cloud Shell को फिर से खोलें और पुष्टि करें कि Skaffold इंस्टॉल है या नहीं. (Cloud Shell, डिफ़ॉल्ट रूप से एनवायरमेंट में skaffold इंस्टॉल करता है.) यहां दिया गया कमांड चलाएं और Skaffold का वर्शन देखें.
skaffold version
कमांड आउटपुट
v1.38.0
अब, skaffold के इस्तेमाल के लिए डिफ़ॉल्ट रिपॉज़िटरी रजिस्टर की जा सकती है. रजिस्ट्री का पाथ पाने के लिए, Artifact Registry के डैशबोर्ड पर जाएं. इसके बाद, उस रिपॉज़िटरी के नाम पर क्लिक करें जिसे आपने पिछले चरण में सेट अप किया था.

इसके बाद, आपको पेज के सबसे ऊपर ब्रेडक्रंब ट्रेल दिखेगी. क्लिपबोर्ड पर रजिस्ट्री पाथ कॉपी करने के लिए,
आइकॉन पर क्लिक करें.

'कॉपी करें' बटन पर क्लिक करने पर, आपको ब्राउज़र में सबसे नीचे यह डायलॉग दिखेगा:
"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" को कॉपी किया गया
क्लाउड शेल पर वापस जाएं. डैशबोर्ड से अभी-अभी कॉपी किए गए मान के साथ skaffold config set default-repo कमांड चलाएं.
skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab
कमांड आउटपुट
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
इसके अलावा, आपको रजिस्ट्री को Docker कॉन्फ़िगरेशन के लिए कॉन्फ़िगर करना होगा. यह कमांड चलाएं:
gcloud auth configure-docker us-central1-docker.pkg.dev --quiet
कमांड आउटपुट
{
"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
अब GKE पर Kubernetes कंटेनर सेट अप करने के लिए, अगले चरण पर जाएं.
खास जानकारी
इस चरण में, आपको कोडलैब एनवायरमेंट सेट अप करना होगा:
- Cloud Shell सेट अप करना
- कंटेनर रजिस्ट्री के लिए, Artifact Registry रिपॉज़िटरी बनाई गई
- कंटेनर रजिस्ट्री का इस्तेमाल करने के लिए, skaffold सेट अप करना
- Kubernetes क्लस्टर बनाया गया है, जहां कोडलैब की माइक्रोसर्विस चलती हैं
आगे बढ़ें
अगले चरण में, आपको क्लस्टर पर अपनी माइक्रोसेवाएं बनानी, पुश करनी, और डिप्लॉय करनी होंगी
3. माइक्रोसर्विसेज़ को बनाएं, पुश करें, और डिप्लॉय करें
कोडलैब का मटीरियल डाउनलोड करना
पिछले चरण में, हमने इस कोडलैब के लिए सभी ज़रूरी शर्तें सेट अप की हैं. अब इन पर पूरी माइक्रोसेवाएँ चलाई जा सकती हैं. कोड लैब का मटीरियल GitHub पर होस्ट किया गया है. इसलिए, इसे Cloud Shell एनवायरमेंट में डाउनलोड करने के लिए, यहां दिए गए git कमांड का इस्तेमाल करें.
cd ~ git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git cd opentelemetry-trace-codelab-go
प्रोजेक्ट का डायरेक्ट्री स्ट्रक्चर इस तरह है:
.
├── 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
- मेनिफ़ेस्ट: Kubernetes मेनिफ़ेस्ट फ़ाइलें
- proto: क्लाइंट और सर्वर के बीच कम्यूनिकेशन के लिए प्रोटो परिभाषा
- src: हर सेवा के सोर्स कोड के लिए डायरेक्ट्री
- skaffold.yaml: skaffold के लिए कॉन्फ़िगरेशन फ़ाइल
इस कोडलैब में, आपको step0 फ़ोल्डर में मौजूद सोर्स कोड को अपडेट करना होगा. जवाबों के लिए, यहां दिए गए चरणों में step[1-6] फ़ोल्डर में मौजूद सोर्स कोड भी देखा जा सकता है. (पहले हिस्से में चरण 0 से चरण 4 तक की जानकारी दी गई है. वहीं, दूसरे हिस्से में चरण 5 और 6 के बारे में बताया गया है)
skaffold कमांड चलाना
आखिर में, आपके पास पूरे कॉन्टेंट को अभी बनाए गए Kubernetes क्लस्टर पर बनाने, पुश करने, और डिप्लॉय करने का विकल्प होता है. ऐसा लगता है कि इसमें कई चरण शामिल हैं, लेकिन असल में Skaffold आपके लिए सब कुछ करता है. आइए, इस कमांड का इस्तेमाल करके देखते हैं:
cd step0 skaffold dev
कमांड चलाने के तुरंत बाद, आपको docker build का लॉग आउटपुट दिखता है. इससे पुष्टि की जा सकती है कि उन्हें रजिस्ट्री में पुश कर दिया गया है.
कमांड आउटपुट
... ---> 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
सभी सेवा कंटेनर पुश करने के बाद, Kubernetes डिप्लॉयमेंट अपने-आप शुरू हो जाते हैं.
कमांड आउटपुट
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
डिप्लॉयमेंट के बाद, आपको हर कंटेनर में stdout पर भेजे गए ऐप्लिकेशन के असली लॉग इस तरह दिखेंगे:
कमांड आउटपुट
[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
ध्यान दें कि इस समय, आपको सर्वर से मिले सभी मैसेज देखने हैं. ठीक है, अब आप सेवाओं की डिस्ट्रिब्यूटेड ट्रेसिंग के लिए, OpenTelemetry की मदद से अपने ऐप्लिकेशन को इंस्ट्रुमेंट करने के लिए तैयार हैं.
सेवा को इंस्ट्रुमेंट करना शुरू करने से पहले, कृपया Ctrl-C दबाकर अपने क्लस्टर को बंद करें.
कमांड आउटपुट
...
[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
खास जानकारी
इस चरण में, आपने अपने एनवायरमेंट में कोडलैब का मटीरियल तैयार कर लिया है. साथ ही, आपने पुष्टि कर ली है कि skaffold उम्मीद के मुताबिक काम कर रहा है.
आगे बढ़ें
अगले चरण में, ट्रेस की जानकारी को इंस्ट्रुमेंट करने के लिए, लोडजन सेवा के सोर्स कोड में बदलाव करें.
4. एचटीटीपी के लिए इंस्ट्रूमेंटेशन
ट्रेस इंस्ट्रूमेंटेशन और प्रोपगेशन का कॉन्सेप्ट
सोर्स कोड में बदलाव करने से पहले, मैं आपको एक आसान डायग्राम की मदद से, डिस्ट्रिब्यूटेड ट्रेस के काम करने के तरीके के बारे में कम शब्दों में बता देता हूं.

इस उदाहरण में, हम कोड को Cloud Trace में Trace और Span की जानकारी एक्सपोर्ट करने के लिए इंस्ट्रुमेंट करते हैं. साथ ही, लोडजन सेवा से सर्वर सेवा तक के अनुरोध में ट्रेस कॉन्टेक्स्ट को आगे बढ़ाते हैं.
ऐप्लिकेशन को Cloud Trace में ट्रेस मेटाडेटा भेजना होता है. जैसे, ट्रेस आईडी और स्पैन आईडी. इससे Cloud Trace, एक ही ट्रेस आईडी वाले सभी स्पैन को एक ट्रेस में इकट्ठा कर पाता है. साथ ही, ऐप्लिकेशन को डाउनस्ट्रीम सेवाओं का अनुरोध करते समय, ट्रेस कॉन्टेक्स्ट (पैरंट स्पैन का ट्रेस आईडी और स्पैन आईडी का कॉम्बिनेशन) को आगे बढ़ाना होगा, ताकि उन्हें पता चल सके कि वे किस ट्रेस कॉन्टेक्स्ट को मैनेज कर रही हैं.
OpenTelemetry की मदद से ये काम किए जा सकते हैं:
- यूनीक ट्रेस आईडी और स्पैन आईडी जनरेट करने के लिए
- इस कुकी का इस्तेमाल, Trace ID और Span ID को बैकएंड में एक्सपोर्ट करने के लिए किया जाता है
- इस कुकी का इस्तेमाल, ट्रेस कॉन्टेक्स्ट को अन्य सेवाओं तक पहुंचाने के लिए किया जाता है
- ज़्यादा मेटाडेटा एम्बेड करने के लिए, ताकि ट्रेस का विश्लेषण करने में मदद मिल सके
OpenTelemetry Trace में कॉम्पोनेंट

OpenTelemetry की मदद से ऐप्लिकेशन ट्रेस को इंस्ट्रूमेंट करने का तरीका यहां दिया गया है:
- एक्सपोर्टर खाता बनाना
- एक्सपोर्टर को 1 में बाइंड करने वाला TracerProvider बनाएं और उसे ग्लोबल पर सेट करें.
- प्रॉपगेशन का तरीका सेट करने के लिए, TextMapPropagaror को सेट करें
- TracerProvider से Tracer पाएं
- ट्रेसर से स्पैन जनरेट करना
फ़िलहाल, आपको हर कॉम्पोनेंट की प्रॉपर्टी के बारे में ज़्यादा जानकारी रखने की ज़रूरत नहीं है. हालांकि, आपको इन बातों का ध्यान रखना होगा:
- यहां एक्सपोर्टर को TracerProvider से प्लग किया जा सकता है
- TracerProvider में, ट्रेस सैंपलिंग और एक्सपोर्ट से जुड़ा सारा कॉन्फ़िगरेशन होता है
- सभी ट्रेस, Tracer ऑब्जेक्ट में बंडल किए जाते हैं
अब हम कोडिंग के काम पर आगे बढ़ते हैं.
इंस्ट्रूमेंट फ़र्स्ट स्पैन
इंस्ट्रूमेंट लोड जनरेटर सेवा
Cloud Shell के सबसे ऊपर दाईं ओर मौजूद,
बटन दबाकर Cloud Shell Editor खोलें. बाएं पैनल में मौजूद एक्सप्लोरर से step0/src/loadgen/main.go खोलें और मुख्य फ़ंक्शन ढूंढें.
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++
}
}
मुख्य फ़ंक्शन में, आपको लूप दिखेगा, जो इसमें मौजूद run फ़ंक्शन को कॉल कर रहा है. मौजूदा तरीके में, इस सेक्शन में दो लॉग लाइनें होती हैं. इनमें फ़ंक्शन कॉल के शुरू और खत्म होने की जानकारी रिकॉर्ड की जाती है. अब फ़ंक्शन कॉल की लेटेन्सी को ट्रैक करने के लिए, स्पैन की जानकारी को इंस्ट्रुमेंट करते हैं.
सबसे पहले, पिछले सेक्शन में बताए गए तरीके से, OpenTelemetry के लिए सभी कॉन्फ़िगरेशन सेट अप करते हैं. OpenTelemetry पैकेज इस तरह जोड़ें:
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
)
कोड को आसानी से पढ़ने के लिए, हम initTracer नाम का एक सेटअप फ़ंक्शन बनाते हैं और इसे 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
}
आपको पता चल सकता है कि OpenTelemetry को सेट अप करने का तरीका, पिछले सेक्शन में बताया गया है. इस प्रोसेस में, हम एक stdout एक्सपोर्टर का इस्तेमाल करते हैं. यह सभी ट्रेस जानकारी को स्ट्रक्चर्ड फ़ॉर्मैट में stdout में एक्सपोर्ट करता है.
इसके बाद, इसे मुख्य फ़ंक्शन से कॉल करें. initTracer() को कॉल करें. साथ ही, ऐप्लिकेशन बंद करते समय TracerProvider.Shutdown() को कॉल करना न भूलें.
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)
...
सेट अप करने के बाद, आपको एक स्पैन बनाना होगा. इसमें यूनीक ट्रेस आईडी और स्पैन आईडी होना चाहिए. OpenTelemetry, इसके लिए एक काम की लाइब्रेरी उपलब्ध कराता है. इंस्ट्रूमेंट एचटीटीपी क्लाइंट में नए पैकेज जोड़ें.
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"
)
लोड जनरेटर, runQuery फ़ंक्शन में net/http के साथ एचटीटीपी में क्लाइंट सेवा को कॉल कर रहा है. इसलिए, हम net/http के लिए contrib पैकेज का इस्तेमाल करते हैं. साथ ही, httptrace और otelhttp पैकेज के एक्सटेंशन के साथ इंस्ट्रुमेंटेशन चालू करते हैं.
सबसे पहले, पैकेज ग्लोबल वैरिएबल httpClient को जोड़ा जाता है, ताकि इंस्ट्रुमेंट किए गए क्लाइंट के ज़रिए एचटीटीपी अनुरोधों को कॉल किया जा सके.
step0/src/loadgen/main.go
var httpClient = http.Client{
Transport: otelhttp.NewTransport(http.DefaultTransport)
}
इसके बाद, runQuery फ़ंक्शन में इंस्ट्रूमेंटेशन जोड़ें, ताकि OpenTelemetry और कस्टम एचटीटीपी क्लाइंट से अपने-आप जनरेट हुए स्पैन का इस्तेमाल करके कस्टम स्पैन बनाया जा सके. आपको यह काम करना होगा:
otel.Tracer()की मदद से, ग्लोबलTracerProviderसे ट्रैसर पाएंTracer.Start()तरीके का इस्तेमाल करके रूट स्पैन बनाना- रूट स्पैन को किसी भी समय खत्म करें. इस मामले में,
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)
}
अब आपने लोडजन (एचटीटीपी क्लाइंट ऐप्लिकेशन) में इंस्ट्रूमेंटेशन कर लिया है. कृपया go mod कमांड का इस्तेमाल करके, अपने go.mod और go.sum को अपडेट करें.
go mod tidy
इंस्ट्रुमेंट क्लाइंट सेवा
पिछले सेक्शन में, हमने नीचे दी गई इमेज में लाल रंग के रेक्टैंगल में मौजूद हिस्से को इंस्ट्रूमेंट किया था. हमने लोड जनरेटर सेवा में स्पैन की जानकारी को इंस्ट्रूमेंट किया है. लोड जनरेटर सेवा की तरह ही, अब हमें क्लाइंट सेवा को इंस्ट्रुमेंट करना होगा. लोड जनरेटर सेवा से यह अलग है. क्लाइंट सेवा को एचटीटीपी हेडर में, लोड जनरेटर सेवा से मिली ट्रेस आईडी की जानकारी को निकालना होता है. साथ ही, स्पैन जनरेट करने के लिए इस आईडी का इस्तेमाल करना होता है.

Cloud Shell Editor खोलें और ज़रूरी पैकेज जोड़ें. जैसे, हमने लोड जनरेटर सेवा के लिए किया था.
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
)
हमें OpenTelemtry को फिर से सेट अप करना होगा. loadgen से initTracer फ़ंक्शन को कॉपी करके चिपकाएं. साथ ही, इसे क्लाइंट सेवा के main फ़ंक्शन में भी कॉल करें.
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
}
अब स्पैन को इंस्ट्रुमेंट करने का समय है. क्लाइंट सेवा को लोडजन सेवा से मिले एचटीटीपी अनुरोधों को स्वीकार करना होता है. इसलिए, इसे हैंडलर को इंस्ट्रूमेंट करना होता है. क्लाइंट सेवा में एचटीटीपी सर्वर को net/http की मदद से लागू किया जाता है. साथ ही, otelhttp पैकेज का इस्तेमाल किया जा सकता है. जैसे, हमने loadgen में किया था.
सबसे पहले, हम हैंडलर रजिस्ट्रेशन को otelhttp हैंडलर से बदल देते हैं. main फ़ंक्शन में, वे लाइनें ढूंढें जहां HTTP हैंडलर को 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)
इसके बाद, हम हैंडलर के अंदर मौजूद असली स्पैन को इंस्ट्रूमेंट करते हैं. func (*clientService) handler() ढूंढें और 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
...
इस इंस्ट्रूमेंटेशन की मदद से, आपको handler तरीके की शुरुआत से लेकर आखिर तक के स्पैन मिलते हैं. स्पैन का आसानी से विश्लेषण करने के लिए, एक ऐसा एट्रिब्यूट जोड़ें जो क्वेरी में मैच किए गए काउंट को सेव करता हो. लॉग लाइन से ठीक पहले, यह कोड जोड़ें.
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))
...
ऊपर दिए गए सभी इंस्ट्रुमेंटेशन की मदद से, आपने लोडजन और क्लाइंट के बीच ट्रेस इंस्ट्रुमेंटेशन पूरा कर लिया है. आइए, देखते हैं कि यह कैसे काम करता है. skaffold की मदद से कोड को फिर से चलाएं.
skaffold dev
GKE क्लस्टर पर सेवाएं चलाने के कुछ समय बाद, आपको इस तरह के लॉग मैसेज की बड़ी संख्या दिखेगी:
कमांड आउटपुट
[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"
...
stdout एक्सपोर्टर, ये मैसेज भेजता है. आपको दिखेगा कि loadgen के सभी स्पैन के पैरंट में TraceID: 00000000000000000000000000000000 है, क्योंकि यह रूट स्पैन है. इसका मतलब है कि यह ट्रेस का पहला स्पैन है. आपको यह भी पता चलता है कि एम्बेड एट्रिब्यूट "query" में क्वेरी स्ट्रिंग है, जिसे क्लाइंट सेवा को पास किया जाता है.
खास जानकारी
इस चरण में, आपने लोड जनरेटर सेवा और क्लाइंट सेवा को इंस्ट्रुमेंट किया है. ये दोनों सेवाएं एचटीटीपी में कम्यूनिकेट करती हैं. साथ ही, आपने पुष्टि की है कि आपके पास सभी सेवाओं में ट्रेस कॉन्टेक्स्ट को सही तरीके से फैलाने और दोनों सेवाओं से स्पैन की जानकारी को stdout में एक्सपोर्ट करने की सुविधा है.
आगे बढ़ें
अगले चरण में, आपको क्लाइंट सेवा और सर्वर सेवा को इंस्ट्रूमेंट करना होगा. इससे यह पुष्टि की जा सकेगी कि gRPC के ज़रिए ट्रेस कॉन्टेक्स्ट को कैसे फैलाया जाए.
5. gRPC के लिए इंस्ट्रुमेंटेशन
पिछले चरण में, हमने इस माइक्रोसेवा में अनुरोध के पहले हिस्से को इंस्ट्रुमेंट किया था. इस चरण में, हम क्लाइंट सेवा और सर्वर सेवा के बीच gRPC कम्यूनिकेशन को इंस्ट्रुमेंट करने की कोशिश करते हैं. (नीचे दी गई इमेज में हरे और बैंगनी रंग का रेक्टैंगल)

gRPC क्लाइंट के लिए पहले से तैयार किया गया इंस्ट्रुमेंटेशन
OpenTelemetry के इकोसिस्टम में कई काम की लाइब्रेरी उपलब्ध हैं. इनसे डेवलपर को ऐप्लिकेशन को इंस्ट्रूमेंट करने में मदद मिलती है. पिछले चरण में, हमने net/http पैकेज के लिए पहले से बने इंस्ट्रुमेंटेशन का इस्तेमाल किया था. इस चरण में, हम gRPC के ज़रिए ट्रेस कॉन्टेक्स्ट को आगे बढ़ाने की कोशिश कर रहे हैं. इसलिए, हम इसके लिए लाइब्रेरी का इस्तेमाल करते हैं.
सबसे पहले, otelgrpc नाम के प्रीबिल्ट gRPC पैकेज को इंपोर्ट करें.
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"
)
इस बार, क्लाइंट सेवा, सर्वर सेवा के ख़िलाफ़ gRPC क्लाइंट है. इसलिए, आपको gRPC क्लाइंट को इंस्ट्रुमेंट करना होगा. mustConnGRPC फ़ंक्शन ढूंढें और gRPC इंटरसेप्टर जोड़ें. ये इंटरसेप्टर, क्लाइंट के सर्वर से अनुरोध करने पर हर बार नए स्पैन बनाते हैं.
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))
}
}
आपने पिछले सेक्शन में OpenTelemetry पहले ही सेट अप कर लिया है. इसलिए, आपको इसे सेट अप करने की ज़रूरत नहीं है.
gRPC सर्वर के लिए पहले से तैयार किया गया इंस्ट्रुमेंटेशन
हमने gRPC क्लाइंट के लिए जो किया था वही हम gRPC सर्वर के लिए भी करते हैं. इसके लिए, हम पहले से बने इंस्ट्रुमेंटेशन को कॉल करते हैं. इंपोर्ट सेक्शन में नया पैकेज जोड़ें. जैसे:
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"
)
सर्वर को पहली बार इंस्ट्रुमेंट किया जा रहा है. इसलिए, आपको पहले OpenTelemetry सेट अप करना होगा. यह ठीक वैसा ही है जैसा हमने loadgen और क्लाइंट सेवाओं के लिए किया था.
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
...
इसके बाद, आपको सर्वर इंटरसेप्टर जोड़ने होंगे. main फ़ंक्शन में, उस जगह को ढूंढें जहां grpc.NewServer() को कॉल किया गया है. इसके बाद, फ़ंक्शन में इंटरसेप्टर जोड़ें.
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)
...
माइक्रोसर्विस चलाएं और ट्रेस की पुष्टि करें
इसके बाद, skaffold कमांड की मदद से बदले गए कोड को चलाएं.
skaffold dev
अब आपको stdout पर स्पैन की जानकारी का एक बंडल दिखेगा.
कमांड आउटपुट
...
[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] }
...
आपको पता चलता है कि आपने कोई स्पैन नाम एम्बेड नहीं किया है. साथ ही, आपने trace.Start() या span.SpanFromContext() का इस्तेमाल करके मैन्युअल तरीके से स्पैन बनाए हैं. हालांकि, आपको अब भी कई स्पैन दिखेंगे, क्योंकि gRPC इंटरसेप्टर ने उन्हें जनरेट किया है.
खास जानकारी
इस चरण में, आपने OpenTelemetry ईकोसिस्टम की लाइब्रेरी की मदद से, gRPC पर आधारित कम्यूनिकेशन को इंस्ट्रुमेंट किया.
आगे बढ़ें
अगले चरण में, आपको Cloud Trace की मदद से ट्रेस को विज़ुअलाइज़ करने का तरीका बताया जाएगा. साथ ही, इकट्ठा किए गए स्पैन का विश्लेषण करने का तरीका भी बताया जाएगा.
6. Cloud Trace की मदद से ट्रेस को विज़ुअलाइज़ करना
आपने पूरे सिस्टम में OpenTelemetry की मदद से ट्रेसिंग की है. अब तक आपने एचटीटीपी और gRPC सेवाओं को इंस्ट्रुमेंट करने का तरीका सीखा है. आपने इन मेट्रिक को मेज़र करने का तरीका तो सीख लिया है, लेकिन अब भी आपको इनका विश्लेषण करने का तरीका नहीं पता है. इस सेक्शन में, stdout एक्सपोर्टर को Cloud Trace एक्सपोर्टर से बदला जाएगा. साथ ही, आपको अपने ट्रेस का विश्लेषण करने का तरीका भी बताया जाएगा.
Cloud Trace exporter का इस्तेमाल करना
OpenTelemetry की एक खास बात यह है कि इसे प्लग किया जा सकता है. अपने इंस्ट्रूमेंटेशन से इकट्ठा किए गए सभी स्पैन को विज़ुअलाइज़ करने के लिए, आपको सिर्फ़ stdout एक्सपोर्टर को Cloud Trace एक्सपोर्टर से बदलना होगा.
हर सेवा की main.go फ़ाइलें खोलें और initTracer() फ़ंक्शन ढूंढें. stdout एक्सपोर्टर जनरेट करने वाली लाइन को मिटाएं और इसके बजाय 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
}
आपको क्लाइंट और सर्वर सेवा में भी इसी फ़ंक्शन में बदलाव करना होगा.
माइक्रोसर्विस चलाएं और ट्रेस की पुष्टि करें
बदलाव करने के बाद, skaffold कमांड का इस्तेमाल करके क्लस्टर को सामान्य तरीके से चलाएं.
skaffold dev
इसके बाद, आपको stdout पर स्ट्रक्चर्ड लॉग फ़ॉर्मैट में स्पैन की ज़्यादा जानकारी नहीं दिखती, क्योंकि आपने एक्सपोर्टर को Cloud Trace एक्सपोर्टर से बदल दिया है.
कमांड आउटपुट
[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
...
अब पुष्टि करते हैं कि सभी स्पैन, Cloud Trace को सही तरीके से भेजे गए हैं या नहीं. Cloud Console को ऐक्सेस करें और "ट्रेस की सूची" पर जाएं. इसे खोज बॉक्स से आसानी से ऐक्सेस किया जा सकता है. इसके अलावा, बाईं ओर मौजूद पैनल में मौजूद मेन्यू पर क्लिक करें. 
इसके बाद, आपको दिखेगा कि नीले रंग के कई स्पॉट, लेटेन्सी ग्राफ़ में फैले हुए हैं. हर स्पॉट एक ट्रेस को दिखाता है.

इनमें से किसी एक पर क्लिक करें. इसके बाद, आपको ट्रेस में मौजूद जानकारी दिखेगी. 
इस आसान और छोटी सी झलक से भी, आपको कई अहम जानकारी मिल गई है. उदाहरण के लिए, वॉटरफ़ॉल ग्राफ़ से पता चलता है कि लेटेन्सी की वजह, ज़्यादातर shakesapp.ShakespeareService/GetMatchCount नाम का स्पैन है. (ऊपर दी गई इमेज में 1 देखें) इसकी पुष्टि, खास जानकारी वाली टेबल से की जा सकती है. (सबसे दाईं ओर मौजूद कॉलम में, हर स्पैन की अवधि दिखती है.) साथ ही, यह ट्रेस "दोस्त" क्वेरी के लिए था. (ऊपर दी गई इमेज में 2 देखें)
इन छोटे विश्लेषणों से आपको पता चल सकता है कि आपको GetMatchCount तरीके के अंदर ज़्यादा जानकारी वाले स्पैन के बारे में जानने की ज़रूरत है. stdout की जानकारी की तुलना में, विज़ुअलाइज़ेशन ज़्यादा असरदार होता है. Cloud Trace के बारे में ज़्यादा जानने के लिए, कृपया हमारे आधिकारिक दस्तावेज़ पर जाएं.
खास जानकारी
इस चरण में, आपने stdout एक्सपोर्टर को Cloud Trace एक्सपोर्टर से बदल दिया और Cloud Trace पर ट्रेस को विज़ुअलाइज़ किया. साथ ही, आपने ट्रेस का विश्लेषण करना भी सीखा.
आगे बढ़ें
अगले चरण में, GetMatchCount में सब स्पैन जोड़ने के लिए, सर्वर सेवा के सोर्स कोड में बदलाव करें.
7. बेहतर विश्लेषण के लिए, सब स्पैन जोड़ना
पिछले चरण में, आपने देखा कि लोडजन से मिले राउंड ट्रिप टाइम की वजह, सर्वर सेवा में मौजूद GetMatchCount तरीके और gRPC हैंडलर की प्रोसेस है. हालांकि, हमने हैंडलर के अलावा किसी और चीज़ को इंस्ट्रूमेंट नहीं किया है. इसलिए, हम वॉटरफ़ॉल ग्राफ़ से ज़्यादा जानकारी नहीं पा सकते. माइक्रोसर्विसेज़ को इंस्ट्रुमेंट करना शुरू करते समय, ऐसा आम तौर पर होता है.

इस सेक्शन में, हम एक सब स्पैन को इंस्ट्रुमेंट करने जा रहे हैं. इसमें सर्वर, Google Cloud Storage को कॉल करता है. ऐसा इसलिए किया जाता है, क्योंकि कई बार बाहरी नेटवर्क I/O को प्रोसेस करने में ज़्यादा समय लगता है. इसलिए, यह पता लगाना ज़रूरी है कि कॉल की वजह से ऐसा हो रहा है या नहीं.
सर्वर में सब स्पैन को इंस्ट्रूमेंट करना
सर्वर में main.go खोलें और readFiles फ़ंक्शन ढूंढें. यह फ़ंक्शन, Google Cloud Storage से शेक्सपियर की सभी टेक्स्ट फ़ाइलें फ़ेच करने का अनुरोध कर रहा है. इस फ़ंक्शन में, एक सब स्पैन बनाया जा सकता है. जैसे, आपने क्लाइंट सेवा में एचटीटीपी सर्वर इंस्ट्रुमेंटेशन के लिए बनाया था.
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
...
नया स्पैन जोड़ने का तरीका यही है. आइए, ऐप्लिकेशन चलाकर देखते हैं कि यह कैसे काम करता है.
माइक्रोसर्विस चलाएं और ट्रेस की पुष्टि करें
बदलाव करने के बाद, skaffold कमांड का इस्तेमाल करके क्लस्टर को सामान्य तरीके से चलाएं.
skaffold dev
इसके बाद, ट्रेस की सूची में से query.request नाम का कोई ट्रेस चुनें. आपको shakesapp.ShakespeareService/GetMatchCount में एक नए स्पैन को छोड़कर, इसी तरह का ट्रेस वॉटरफ़ॉल ग्राफ़ दिखेगा. (नीचे दिए गए लाल आयत में शामिल स्पैन)

इस ग्राफ़ से अब यह पता चलता है कि Google Cloud Storage को किए गए बाहरी कॉल की वजह से, ज़्यादा इंतज़ार करना पड़ता है. हालांकि, अब भी अन्य चीज़ों की वजह से ज़्यादा इंतज़ार करना पड़ रहा है.
आपको ट्रेस वॉटरफ़ॉल ग्राफ़ को कुछ बार देखने से ही काफ़ी जानकारी मिल गई. आपको अपने ऐप्लिकेशन में परफ़ॉर्मेंस की ज़्यादा जानकारी कैसे मिलती है? यहां प्रोफ़ाइलर काम आता है. हालांकि, फ़िलहाल इस कोडलैब को यहीं खत्म करते हैं और प्रोफ़ाइलर के सभी ट्यूटोरियल को दूसरे हिस्से में शामिल करते हैं.
खास जानकारी
इस चरण में, आपने सर्वर सेवा में एक और स्पैन जोड़ा और सिस्टम की लेटेन्सी के बारे में ज़्यादा जानकारी पाई.
8. बधाई हो
आपने OpenTelemetry की मदद से डिस्ट्रिब्यूटेड ट्रेस बना लिए हैं. साथ ही, Google Cloud Trace पर माइक्रोसेवा के लिए अनुरोधों की लेटेन्सी की पुष्टि कर ली है.
ज़्यादा अभ्यास के लिए, इन विषयों को खुद आज़माएं.
- मौजूदा तरीके से, परफ़ॉर्मेंस की जांच के दौरान जनरेट किए गए सभी स्पैन भेजे जाते हैं. (
grpc.health.v1.Health/Check) Cloud Trace से उन स्पैन को कैसे फ़िल्टर किया जाता है? जवाब यहां है. - इवेंट लॉग को स्पैन से जोड़ें और देखें कि यह Google Cloud Trace और Google Cloud Logging पर कैसे काम करता है. जवाब यहां है.
- किसी सेवा को दूसरी भाषा में उपलब्ध सेवा से बदलें. इसके बाद, उस भाषा के लिए OpenTelemetry का इस्तेमाल करके उसे इंस्ट्रूमेंट करें.
इसके अलावा, अगर आपको इसके बाद प्रोफ़ाइलर के बारे में जानना है, तो कृपया दूसरे हिस्से पर जाएं. ऐसे में, नीचे दिए गए 'साफ़ करें' सेक्शन को छोड़ दें.
खाली करने के लिए जगह
इस कोडलैब के बाद, कृपया Kubernetes क्लस्टर को बंद करें और प्रोजेक्ट को मिटाना न भूलें. ऐसा करने से, आपको Google Kubernetes Engine, Google Cloud Trace, और Google Artifact Registry पर अनचाहे शुल्क नहीं लगेंगे.
सबसे पहले, क्लस्टर मिटाएं. अगर क्लस्टर को skaffold dev के साथ चलाया जा रहा है, तो आपको सिर्फ़ Ctrl-C दबाना होगा. अगर क्लस्टर को skaffold run के साथ चलाया जा रहा है, तो यह कमांड चलाएं:
skaffold delete
कमांड आउटपुट
Cleaning up... - deployment.apps "clientservice" deleted - service "clientservice" deleted - deployment.apps "loadgen" deleted - deployment.apps "serverservice" deleted - service "serverservice" deleted
क्लस्टर मिटाने के बाद, मेन्यू पैन में जाकर "IAM और एडमिन" > "सेटिंग" चुनें. इसके बाद, "बंद करें" बटन पर क्लिक करें.

इसके बाद, डायलॉग बॉक्स में मौजूद फ़ॉर्म में प्रोजेक्ट आईडी (प्रोजेक्ट का नाम नहीं) डालें और बंद करने की पुष्टि करें.