<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Bill Chung</title>
    <description>The latest articles on Forem by Bill Chung (@billchung).</description>
    <link>https://forem.com/billchung</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F346099%2F665b96d0-60b7-41a3-bda7-7d7cbae2acc3.jpeg</url>
      <title>Forem: Bill Chung</title>
      <link>https://forem.com/billchung</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/billchung"/>
    <language>en</language>
    <item>
      <title>使用google cloud profiler來對go gRPC server做效能分析</title>
      <dc:creator>Bill Chung</dc:creator>
      <pubDate>Sun, 08 Nov 2020 04:15:24 +0000</pubDate>
      <link>https://forem.com/billchung/google-cloud-profiler-go-grpc-server-4d2f</link>
      <guid>https://forem.com/billchung/google-cloud-profiler-go-grpc-server-4d2f</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.to/billchung/profiling-go-grpc-service-with-google-cloud-profiler-13e4"&gt;English version&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  About
&lt;/h1&gt;

&lt;p&gt;這篇文章主要是整合 &lt;a href="https://cloud.google.com/profiler" rel="noopener noreferrer"&gt;Cloud Profiler&lt;/a&gt; 至go的程式 (以gRPC Server為範例)&lt;/p&gt;

&lt;p&gt;完整的範例在&lt;a href="https://github.com/billcchung/example-service/tree/add-ping" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Profiler
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;Profiling&lt;/code&gt;是一種軟體&lt;a href="https://zh.wikipedia.org/zh-tw/%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90" rel="noopener noreferrer"&gt;效能分析&lt;/a&gt;的方法，而&lt;code&gt;Profiler&lt;/code&gt;則是做&lt;code&gt;Profiling&lt;/code&gt;的工具。簡單的說它就是測量軟體所花費的時間、空間、或其他的資源，近年來最常用的視覺化工具為&lt;code&gt;FlameGraph&lt;/code&gt;, 其概念可以參考&lt;a href="http://www.brendangregg.com/flamegraphs.html" rel="noopener noreferrer"&gt;Brendan Gregg的網站&lt;/a&gt; 或&lt;a href="https://cloud.google.com/profiler/docs/concepts-flame" rel="noopener noreferrer"&gt;google cloud&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Profiler
&lt;/h3&gt;

&lt;p&gt;Google出個一個服務叫&lt;a href="https://cloud.google.com/profiler" rel="noopener noreferrer"&gt;Cloud Profiler&lt;/a&gt;，它可以讓你非常容易的自動取得並視覺化你的程式，只需要加進一小段簡單的程式碼，以下是一些關於Cloud Profiler的基本資訊：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;支援的程式語言: &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;Go&lt;/code&gt;, &lt;code&gt;NodeJS&lt;/code&gt;, and &lt;code&gt;Java&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;價格: &lt;a href="https://cloud.google.com/stackdriver/pricing#profiler-costs" rel="noopener noreferrer"&gt;&lt;code&gt;免費&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;資料保留時間: &lt;a href="https://cloud.google.com/profiler/quotas#retention_periods" rel="noopener noreferrer"&gt;&lt;code&gt;30天&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;對於程式的效能影響: 請參考&lt;a href="https://cloud.google.com/profiler/docs/about-profiler#performance_impact" rel="noopener noreferrer"&gt;這邊&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;就算你的程式不是跑在GCP上，你還是可以使用，以下的範例就是只跑在本機，然後資料會傳送到Cloud Profiler做視覺化&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  gRPC server
&lt;/h1&gt;

&lt;p&gt;因為這邊的範例使用gRPC server，所以在介紹整合前先簡單介紹一下該example gRPC service，如果你已經熟悉gRPC service，可以跳過此節&lt;/p&gt;

&lt;h3&gt;
  
  
  profobuf - Ping service
&lt;/h3&gt;

&lt;p&gt;該服務只定義了一個&lt;code&gt;Ping&lt;/code&gt;服務，位於&lt;code&gt;proto&lt;/code&gt;資料夾，當中&lt;a href="https://github.com/billcchung/example-service/blob/add-ping/proto/ping.proto" rel="noopener noreferrer"&gt;ping.proto&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".;ping"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get returns a response with same message id and body, and with timestamp.&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// GetAfter is same as Ping but return the response after certain time&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;GetAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingRequestWithSleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// GetRandom generates random strings and return, also produce lots of useless stuff to show the effects of heap&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;GetRandom&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;PingRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;PingRequestWithSleep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;PingResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;如果你對於protobuf不熟悉，可以參考&lt;a href="https://developers.google.com/protocol-buffers/docs/proto3" rel="noopener noreferrer"&gt;此文件&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;這個&lt;code&gt;Ping&lt;/code&gt;服務有3個RPC (remote procedure call):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Get&lt;/code&gt;: 單純回傳相同的訊息ID及body, 並帶server的timestamp&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetAfter&lt;/code&gt;: 與&lt;code&gt;Get&lt;/code&gt;相同單純回傳，但會等待給定的秒數後再回傳。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetRandom&lt;/code&gt;: 與&lt;code&gt;Get&lt;/code&gt;相似，但body會變成一個隨機的文字，而在下面的實踐上回傳前會故意多做一些事，用意是產生一些cpu及memory用量，作為demo.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  產生gRPC go code
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;需要安裝protoc - 請參考&lt;a href="http://google.github.io/proto-lens/installing-protoc.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;在你的terminal執行以下指令來產生go gRPC server/client codes (會產生一個檔案叫&lt;code&gt;ping.pb.go&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make proto-go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;該repository已經包含該&lt;code&gt;ping.pb.go&lt;/code&gt;檔案，但我使用的版本為&lt;br&gt;
 &lt;code&gt;protoc-gen-go v1.25.0&lt;/code&gt; &amp;amp; &lt;code&gt;protoc v3.6.1&lt;/code&gt;，你可能會有不同的版本，所以重新產生以免不相同 &lt;/p&gt;
&lt;h3&gt;
  
  
  Ping服務實現
&lt;/h3&gt;

&lt;p&gt;以下是該服務的實踐，該檔案位於&lt;code&gt;ping&lt;/code&gt;資夾當中的&lt;code&gt;ping.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt; &lt;span class="s"&gt;"github.com/billcchung/example-service/protobuf"&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;letterRunes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequestWithSleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetRandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;garbage&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;garbage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;garbage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;))]))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;))])})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  設定Cloud Profiler
&lt;/h3&gt;

&lt;p&gt;前面提到只需要加入很簡單的程式碼就可以為你的服務做profiling，你只需要import &lt;code&gt;"cloud.google.com/go/profiler"&lt;/code&gt;並在你程式啟動的同時啟動profiler即可, 該profiler是一個go routine在背景定時取樣並上傳至cloud profiler&lt;/p&gt;

&lt;p&gt;以我們的範列，其程式&lt;a href="https://github.com/billcchung/example-service/blob/add-ping/main.go#L24-L28" rel="noopener noreferrer"&gt;如下&lt;/a&gt;(於&lt;code&gt;main.go&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;profiler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profiler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ServiceVersion&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serviceVersion&lt;/span&gt;
    &lt;span class="n"&gt;ProjectID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;projectID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;其中&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Service&lt;/code&gt;為服務名稱,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ServiceVersion&lt;/code&gt;服務的版本&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProjectID&lt;/code&gt;為GCP的project ID&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  啟動Server服務
&lt;/h3&gt;

&lt;p&gt;在啟動服務之前，請確保你的Cloud Profiler是已經開啟(enabled)的狀態，你可以從&lt;a href="https://console.cloud.google.com/profiler" rel="noopener noreferrer"&gt;這邊&lt;/a&gt;開啟&lt;/p&gt;

&lt;p&gt;另外因為這個example service並不會跑在GCP裡面，你需要有相對應的cloud profiler權限並確定已經登入glcoud, 若你尚未登入或需要權限請見&lt;a href="https://cloud.google.com/profiler/docs/profiling-external" rel="noopener noreferrer"&gt;這邊&lt;/a&gt;, &lt;/p&gt;

&lt;p&gt;然後你就可以啟動服務(請將&lt;code&gt;$PROJECT_ID&lt;/code&gt;換成你的GCP project ID):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  執行client
&lt;/h3&gt;

&lt;p&gt;一旦server開始執行，你可以執行在&lt;code&gt;tools&lt;/code&gt;裡面的client端，該程式會依序call &lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;GetAfter&lt;/code&gt;, 及 &lt;code&gt;GetRandom&lt;/code&gt;，你會需要執行多次來確保profiler可以取得樣本:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 1000&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;go run tools/connect.go &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  檢視圖表及理解
&lt;/h3&gt;

&lt;p&gt;待client執行一段時間後 (不需要等所有的loop跑完)，你可以在&lt;a href="https://console.cloud.google.com/profiler" rel="noopener noreferrer"&gt;cloud profiler console&lt;/a&gt;看到該服務的profiles及其視覺化(flamegraph):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuldjjz3336ft0xnsi9v7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuldjjz3336ft0xnsi9v7.jpg" alt="Screen Shot 2020-11-08 at 10.36.57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;你所看到的圖可能會跟我的不太一樣，但以我的圖為例&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;它取得16個profiles樣本，其中CPU時間為&lt;code&gt;520ms&lt;/code&gt;至&lt;code&gt;780ms&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Server.GetRandom&lt;/code&gt;花了不少時間，而該函式為我們為服務所寫的&lt;/li&gt;
&lt;li&gt;沒有(或極少)&lt;code&gt;Server.Get&lt;/code&gt;是因為該函式執行時間非常快，也沒有(或極少)&lt;code&gt;GetAfter&lt;/code&gt; 因為 &lt;code&gt;time.Sleep&lt;/code&gt;並不佔用CPU時間。你可能會有該兩個函式，但應該極少，因為採樣的角度來說會採到該兩函式的機率太小，而通常我們會使用profiling的時候我們也只在意佔用最多時間或資料的函式。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;你可以發現&lt;code&gt;Server.GetRandom&lt;/code&gt;使用了&lt;code&gt;164.38ms&lt;/code&gt;，點擊可以看詳細是什麼函式在佔用時間:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqjm4oykimnre16cbfgf1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqjm4oykimnre16cbfgf1.jpg" alt="Screen Shot 2020-11-08 at 10.38.01"&gt;&lt;/a&gt;&lt;br&gt;
你可以看到&lt;code&gt;growslice&lt;/code&gt;及&lt;code&gt;Intn&lt;/code&gt;佔了大多數時間:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqh5rskj3da1xzq3nttq2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqh5rskj3da1xzq3nttq2.jpg" alt="Screen Shot 2020-11-08 at 10.38.08"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnpxyp6tgho47rp4djhvf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnpxyp6tgho47rp4djhvf.jpg" alt="Screen Shot 2020-11-08 at 10.38.14"&gt;&lt;/a&gt;&lt;br&gt;
當然該兩個函式是go bulitin, 這只是為了demo使用，讓你可以解讀及了解什麼函式佔用了最多的時間，在實務上的程式則可以提供一些資訊來幫忙你做優化&lt;/p&gt;

&lt;p&gt;另外在&lt;code&gt;Profile type&lt;/code&gt;也可以選擇其他的種類，例如選&lt;code&gt;Heap&lt;/code&gt;來看記憶體使用量:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fouund1dugxiqp8infjw8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fouund1dugxiqp8infjw8.jpg" alt="Screen Shot 2020-11-08 at 10.38.29"&gt;&lt;/a&gt;&lt;br&gt;
&lt;code&gt;Server.Random&lt;/code&gt; 使用了 &lt;code&gt;13.24MiB&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;最後值得一提的是&lt;code&gt;Profile type&lt;/code&gt;中，&lt;code&gt;Threads&lt;/code&gt;在go裡面指的是&lt;a href="https://github.com/googleapis/google-cloud-go/blob/master/profiler/profiler.go#L31-L34" rel="noopener noreferrer"&gt;&lt;code&gt;go routines&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;其他的資訊可以參考&lt;a href="https://cloud.google.com/profiler/docs/using-profiler" rel="noopener noreferrer"&gt;這邊&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  總結
&lt;/h1&gt;

&lt;p&gt;在這篇文章中簡單的demo了&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;如何使用及解讀Cloud profiler&lt;/li&gt;
&lt;li&gt;如何建構gRPC server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;希望對有所幫助，我選擇gRPC作為範例是為了預計之後一系列的文章以gRPC/microservices為主的後端系統的建置(而非使用REST/json)，以及kubernetes + service mesh的使用, 所有的系統會以GCP或自建為主 &lt;/p&gt;

</description>
      <category>go</category>
      <category>googlecloud</category>
      <category>performance</category>
      <category>profiling</category>
    </item>
    <item>
      <title>Profiling go gRPC service with google cloud profiler.</title>
      <dc:creator>Bill Chung</dc:creator>
      <pubDate>Sun, 08 Nov 2020 02:30:41 +0000</pubDate>
      <link>https://forem.com/billchung/profiling-go-grpc-service-with-google-cloud-profiler-13e4</link>
      <guid>https://forem.com/billchung/profiling-go-grpc-service-with-google-cloud-profiler-13e4</guid>
      <description>&lt;h1&gt;
  
  
  About
&lt;/h1&gt;

&lt;p&gt;This article is about how to integrate &lt;a href="https://cloud.google.com/profiler" rel="noopener noreferrer"&gt;Cloud Profiler&lt;/a&gt; with go application (a gRPC server as an example.)&lt;/p&gt;

&lt;p&gt;The complete example can be found on &lt;a href="https://github.com/billcchung/example-service/tree/add-ping" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Profiler
&lt;/h1&gt;

&lt;p&gt;If you're not familiar with profiling or profiler, please check &lt;a href="https://en.wikipedia.org/wiki/Profiling_(computer_programming)" rel="noopener noreferrer"&gt;this wiki&lt;/a&gt;, but in short profiling is to measure the time, space, or any instructions a software uses, the most common visualization is &lt;code&gt;flamegraph&lt;/code&gt; in recent years. The concept of &lt;code&gt;flamegraph&lt;/code&gt; can be found on on &lt;a href="http://www.brendangregg.com/flamegraphs.html" rel="noopener noreferrer"&gt;Brendan Gregg's website&lt;/a&gt; or &lt;a href="https://cloud.google.com/profiler/docs/concepts-flame" rel="noopener noreferrer"&gt;google cloud&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloud Profiler
&lt;/h3&gt;

&lt;p&gt;Google's &lt;a href="https://cloud.google.com/profiler" rel="noopener noreferrer"&gt;Cloud Profiler&lt;/a&gt; is a service that lets you collect and visualize application profiles easily, you can instrument your application with minimal code.&lt;/p&gt;

&lt;p&gt;below are some basic information about cloud profiler:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supported languages: &lt;code&gt;Python&lt;/code&gt;, &lt;code&gt;Go&lt;/code&gt;, &lt;code&gt;NodeJS&lt;/code&gt;, and &lt;code&gt;Java&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pricing: &lt;a href="https://cloud.google.com/stackdriver/pricing#profiler-costs" rel="noopener noreferrer"&gt;&lt;code&gt;Free&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Retention: &lt;a href="https://cloud.google.com/profiler/quotas#retention_periods" rel="noopener noreferrer"&gt;&lt;code&gt;30 days&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Performance impacts: see &lt;a href="https://cloud.google.com/profiler/docs/about-profiler#performance_impact" rel="noopener noreferrer"&gt;this&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;You can also use it outside of GCP, like below I'll just run the service locally and the data will be sent to Cloud profiler and visualized.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  gRPC server
&lt;/h1&gt;

&lt;p&gt;Since the application is built with gRPRC, before diving into the integration, please let me walk through some setup of the application, if you're already familiar with gRPC services, feel free to skip this section.&lt;/p&gt;

&lt;h3&gt;
  
  
  profobuf - Ping service
&lt;/h3&gt;

&lt;p&gt;There's a &lt;a href="https://github.com/billcchung/example-service/blob/add-ping/proto/ping.proto" rel="noopener noreferrer"&gt;ping.proto&lt;/a&gt; in &lt;code&gt;protobuf&lt;/code&gt; folder that defines the &lt;code&gt;Ping&lt;/code&gt; service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;ping&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;".;ping"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Get returns a response with same message id and body, and with timestamp.&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// GetAfter is same as Ping but return the response after certain time&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;GetAfter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingRequestWithSleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// GetRandom generates random strings and return, also produce lots of useless stuff to show the effects of heap&lt;/span&gt;
    &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;GetRandom&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;PingRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;PingRequestWithSleep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;sleep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;PingResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;message_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint64&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're unfamiliar with protobuf, you can refer to protobuf3 &lt;a href="https://developers.google.com/protocol-buffers/docs/proto3" rel="noopener noreferrer"&gt;doc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in this proto we defined a service call &lt;code&gt;Ping&lt;/code&gt;, it has 3 RPC (remote procedure call) functions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Get&lt;/code&gt;: returns the message ID and body that you gave.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetAfter&lt;/code&gt;: returns the message ID and body &lt;strong&gt;after&lt;/strong&gt; the sleep time (as seconds) you give.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetRandom&lt;/code&gt;: returns a random string as body &lt;strong&gt;after&lt;/strong&gt; some unnecessary random strings generations. (just to demonstrate some cpu time and memory taken but this function.)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Generate gRPC go code
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install protoc if you havent - see &lt;a href="http://google.github.io/proto-lens/installing-protoc.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Run
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;make proto-go
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to generate a file called &lt;code&gt;ping.pb.go&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;note in the repo this is already generated, in my case I'm using &lt;code&gt;protoc-gen-go v1.25.0&lt;/code&gt; and &lt;code&gt;protoc v3.6.1&lt;/code&gt;, you might get different codes if you're using different versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Ping server implementation
&lt;/h3&gt;

&lt;p&gt;After the go gRPC is ready, we can start to implement the functions, in my example it looks like this (a file named &lt;code&gt;ping.go&lt;/code&gt; inside &lt;code&gt;ping&lt;/code&gt; folder):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt; &lt;span class="s"&gt;"github.com/billcchung/example-service/protobuf"&lt;/span&gt;
    &lt;span class="s"&gt;"math/rand"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;letterRunes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;rune&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequestWithSleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetRandom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;garbage&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;garbage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;garbage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;))]))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MessageBody&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Intn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;letterRunes&lt;/span&gt;&lt;span class="p"&gt;))])})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup Cloud Profiler
&lt;/h3&gt;

&lt;p&gt;It's really easy to setup cloud profiler, you just need to import &lt;code&gt;"cloud.google.com/go/profiler"&lt;/code&gt; and start the profiler as soon as your process starts, it'll run as a go routine that collects and uploads profiles.&lt;/p&gt;

&lt;p&gt;In our example, it's just like &lt;a href="https://github.com/billcchung/example-service/blob/add-ping/main.go#L24-L28" rel="noopener noreferrer"&gt;below&lt;/a&gt; in &lt;code&gt;main.go&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;profiler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profiler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ServiceVersion&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serviceVersion&lt;/span&gt;
    &lt;span class="n"&gt;ProjectID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;projectID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Service&lt;/code&gt; is the service name,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ServiceVersion&lt;/code&gt; is the service version&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ProjectID&lt;/code&gt; is your GCP project ID&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Run the service
&lt;/h3&gt;

&lt;p&gt;Before running the example service, you need to enable cloud profiler, you can enable it from &lt;a href="https://console.cloud.google.com/profiler" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And since this example will be run outside of GCP, you'll also need to get the permissions and authorizations, for details please see &lt;a href="https://cloud.google.com/profiler/docs/profiling-external" rel="noopener noreferrer"&gt;this&lt;/a&gt; (you can skip this if you already have the permissions and logged in to GCP with CLI, it automatically assumes the user you logged in, it's same flow as other GCP services.)&lt;/p&gt;

&lt;p&gt;Then you can run the service with (replace &lt;code&gt;$PROJECT_ID&lt;/code&gt; with your GCP project ID):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run main.go &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$PROJECT_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the client
&lt;/h3&gt;

&lt;p&gt;Once the server starts running, you can then use the client in &lt;code&gt;tools&lt;/code&gt; folder to make gRPC calls, the &lt;code&gt;connect.go&lt;/code&gt; makes one call of each RPC (&lt;code&gt;Get&lt;/code&gt;, &lt;code&gt;GetAfter&lt;/code&gt;, and &lt;code&gt;GetRandom&lt;/code&gt;), and in order for the profiler to take enough samples, you'll need to run it multiple times, so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;i &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;seq &lt;/span&gt;1 1000&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;go run tools/connect.go &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check the graph and interpret
&lt;/h3&gt;

&lt;p&gt;Wait a while after started the client loop, you can go to &lt;a href="https://console.cloud.google.com/profiler" rel="noopener noreferrer"&gt;cloud profiler console&lt;/a&gt; to see the visualization of your application profiles, e.g.,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuldjjz3336ft0xnsi9v7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fuldjjz3336ft0xnsi9v7.jpg" alt="Screen Shot 2020-11-08 at 10.36.57"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you might see slightly different graph, few things you might notice:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it has collected 16 profiles, CPU time ranging from &lt;code&gt;520ms&lt;/code&gt; to &lt;code&gt;780ms&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;Server.GetRandom&lt;/code&gt; took quite a bit of time, and you know it's our application code&lt;/li&gt;
&lt;li&gt;there's no &lt;code&gt;Server.Get&lt;/code&gt; profile because the function call is returned pretty fast and there's also no &lt;code&gt;GetAfter&lt;/code&gt; because &lt;code&gt;time.Sleep&lt;/code&gt; doesnt consume cpu time. You might have one or two, but they're relatively rare, and it's okay since when we enable profiling we care about what's taking the time or resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can click on &lt;code&gt;Server.GetRandom&lt;/code&gt; to drill down to see what's going on within the function:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqjm4oykimnre16cbfgf1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqjm4oykimnre16cbfgf1.jpg" alt="Screen Shot 2020-11-08 at 10.38.01"&gt;&lt;/a&gt;&lt;br&gt;
You can see the function took &lt;code&gt;164.38ms&lt;/code&gt; in average, and mostly taken by &lt;code&gt;growslice&lt;/code&gt; and &lt;code&gt;Intn&lt;/code&gt;:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqh5rskj3da1xzq3nttq2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqh5rskj3da1xzq3nttq2.jpg" alt="Screen Shot 2020-11-08 at 10.38.08"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnpxyp6tgho47rp4djhvf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fnpxyp6tgho47rp4djhvf.jpg" alt="Screen Shot 2020-11-08 at 10.38.14"&gt;&lt;/a&gt;&lt;br&gt;
Of course they're builtin to go, and they were written that way just to demo, but in a real application you can get an idea on what function is taking the time and you can try to see the root cause and improve them.&lt;/p&gt;

&lt;p&gt;You can also choose other &lt;code&gt;Profile type&lt;/code&gt;, like &lt;code&gt;Heap&lt;/code&gt; to see how much memory each function takes:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fouund1dugxiqp8infjw8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fouund1dugxiqp8infjw8.jpg" alt="Screen Shot 2020-11-08 at 10.38.29"&gt;&lt;/a&gt;&lt;br&gt;
here the &lt;code&gt;Server.Random&lt;/code&gt; took &lt;code&gt;13.24MiB&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;One other thing to note is for the &lt;code&gt;Profile type&lt;/code&gt;, you can select &lt;code&gt;Threads&lt;/code&gt;, but for go application it's actually &lt;a href="https://github.com/googleapis/google-cloud-go/blob/master/profiler/profiler.go#L31-L34" rel="noopener noreferrer"&gt;&lt;code&gt;go routines&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For other details you can check &lt;a href="https://cloud.google.com/profiler/docs/using-profiler" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;This article mainly demonstrates&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use and interpret cloud profiler&lt;/li&gt;
&lt;li&gt;Build gRPC server &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope it's useful, I chose gRPC server as an example because I plan to write a series of articles on how to build microservices based backend system with kubernetes. So I'll build more features on top of this gRPC service along with the entire kubernetes platform. &lt;/p&gt;

</description>
      <category>go</category>
      <category>googlecloud</category>
      <category>performance</category>
      <category>profiling</category>
    </item>
  </channel>
</rss>
