<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>golang - Tag - Coding Life Share</title><link>https://blog.xwi88.com/en/tags/golang/</link><description>golang - Tag - Coding Life Share</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>278810732@qq.com (xwi88)</managingEditor><webMaster>278810732@qq.com (xwi88)</webMaster><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Sat, 22 Oct 2022 12:09:20 +0800</lastBuildDate><atom:link href="https://blog.xwi88.com/en/tags/golang/" rel="self" type="application/rss+xml"/><item><title>Go OTP TOTP HOTP</title><link>https://blog.xwi88.com/en/go-otp-totp-hotp/</link><pubDate>Sat, 22 Oct 2022 12:09:20 +0800</pubDate><author>xwi88</author><guid>https://blog.xwi88.com/en/go-otp-totp-hotp/</guid><description><![CDATA[<p>More and more systems add multi-factor authentication for security. OTP is one of the relatively simple and convenient MFA schemes. This post briefly covers the concepts and gives <code>totp</code> and <code>hotp</code> examples based on <code>go1.19.2</code>. For more, see <a href="https://github.com/v8fg/kit4go" target="_blank" rel="noopener noreffer ">kit4go/otp</a>.</p>
<blockquote>
<p><strong>Copyright notice</strong>: This is an original article by <strong><a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">xwi88</a></strong>, licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener noreffer ">CC BY-NC 4.0</a>. Commercial use is prohibited; please cite the source when reposting. Follow at <a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">https://github.com/xwi88</a></p>
</blockquote>
<h2 id="concepts">
    <a href="#concepts" class="header-anchor" aria-label="Link to Concepts"></a>Concepts</h2>
<ul>
<li>OTP: One-Time Password.
<ul>
<li>A single-use password</li>
</ul>
</li>
<li>TOTP: Time-based One-time Password Algorithm (RFC 6238): time-based OTP, the most commonly used method.
<ul>
<li>A one-time password generated from a timestamp algorithm</li>
<li>Generated from a secret key and the current time</li>
<li>Usually produces a new code every 30 or 60 seconds</li>
<li>Requires the client and server to keep fairly accurate clocks</li>
</ul>
</li>
<li>HOTP: HMAC-based One-time Password Algorithm (RFC 4226): counter-based OTP, which TOTP builds upon.
<ul>
<li>A one-time password generated from the <code>HMAC</code> algorithm</li>
</ul>
</li>
</ul>
<h2 id="use-cases">
    <a href="#use-cases" class="header-anchor" aria-label="Link to Use cases"></a>Use cases</h2>
<ul>
<li>Server login dynamic-password verification (cloud servers, enterprise platforms, etc.)</li>
<li>github, twitter, google login two-factor authentication</li>
<li>Corporate intranet proxy login 2FA</li>
<li>Bank transfer dynamic passwords</li>
<li>Hardware tokens for online banking and online games</li>
<li>2FA / MFA and the like</li>
</ul>
<h2 id="products">
    <a href="#products" class="header-anchor" aria-label="Link to Products"></a>Products</h2>
<ul>
<li>Microsoft Authenticator: <a href="https://www.microsoft.com/zh-cn/security/mobile-authenticator-app" target="_blank" rel="noopener noreffer ">microsoft-authenticator</a>
<ul>
<li>Cross-app, simple, fast and highly secure 2FA</li>
<li>Recommended for personal use ☆☆☆☆☆</li>
</ul>
</li>
<li>Google Authenticator: <a href="https://github.com/google/google-authenticator" target="_blank" rel="noopener noreffer ">google-authenticator</a></li>
<li>Bank token: bound to a specific account/card only</li>
<li>Vendor-specific OTP security apps: limited to that vendor&rsquo;s products</li>
</ul>
<h2 id="principle">
    <a href="#principle" class="header-anchor" aria-label="Link to Principle"></a>Principle</h2>
<p><strong><code>OTP(K, C) = Truncate(HMAC-SHA-1(K, C))</code></strong></p>
<ul>
<li><code>K</code>: secret key string</li>
<li><code>C</code>: a number</li>
<li><code>HMAC-SHA-1</code>: HMAC using SHA-1</li>
<li><code>Truncate</code>: truncates the encrypted string</li>
</ul>
<blockquote>
<p>For HMAC-SHA-1 encryption, Truncate works as follows:</p>
</blockquote>
<ul>
<li>HMAC-SHA-1 produces a 20-byte secret string</li>
<li>Take the last byte of those 20 bytes, and use its low 4 bits as the index offset into the encrypted string</li>
<li>Starting at that offset, take 4 bytes and combine them into an integer (big-endian)</li>
<li>Take the last 6 or 8 digits of that integer and return them as a string</li>
</ul>
<h3 id="otp">
    <a href="#otp" class="header-anchor" aria-label="Link to OTP"></a>OTP</h3>
<ul>
<li><code>C</code>: a number representing a random value</li>
<li>Other parameters as defined above</li>
</ul>
<h3 id="totp">
    <a href="#totp" class="header-anchor" aria-label="Link to TOTP"></a>TOTP</h3>
<ul>
<li><code>C</code>: a random value derived from a timestamp
<ul>
<li><code>C = (T - T0) / T1</code></li>
<li>T: the current timestamp</li>
<li>T0: the epoch start, usually 0</li>
<li>T1: the time step, customized per your needs
<ul>
<li>Usually <strong>30</strong>, meaning the generated code is valid for <code>30s</code></li>
</ul>
</li>
</ul>
</li>
<li>Other parameters as defined above</li>
<li>The hash function is usually <code>SHA2</code>, i.e. event-synchronous verification based on a <code>SHA-256</code> or <code>SHA-512</code> hash</li>
</ul>
<h3 id="hotp">
    <a href="#hotp" class="header-anchor" aria-label="Link to HOTP"></a>HOTP</h3>
<ul>
<li><code>C</code>: a number representing a random value</li>
<li>Other parameters as defined above</li>
</ul>
<h2 id="implementations">
    <a href="#implementations" class="header-anchor" aria-label="Link to Implementations"></a>Implementations</h2>
<table>
<thead>
<tr>
<th style="text-align:left">Name</th>
<th style="text-align:left">Language</th>
<th style="text-align:left">URL</th>
<th style="text-align:left">Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><a href="https://github.com/v8fg/kit4go" target="_blank" rel="noopener noreffer ">kit4go/otp</a></td>
<td style="text-align:left">Go</td>
<td style="text-align:left"><a href="https://github.com/v8fg/kit4go" target="_blank" rel="noopener noreffer ">https://github.com/v8fg/kit4go</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/pquerna/otp" target="_blank" rel="noopener noreffer ">otp</a></td>
<td style="text-align:left">Go</td>
<td style="text-align:left"><a href="https://github.com/pquerna/otp" target="_blank" rel="noopener noreffer ">https://github.com/pquerna/otp</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/pyauth/pyotp" target="_blank" rel="noopener noreffer ">pyotp</a></td>
<td style="text-align:left">Python</td>
<td style="text-align:left"><a href="https://github.com/pyauth/pyotp" target="_blank" rel="noopener noreffer ">https://github.com/pyauth/pyotp</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/xlzd/gotp" target="_blank" rel="noopener noreffer ">gotp</a></td>
<td style="text-align:left">Go</td>
<td style="text-align:left"><a href="https://github.com/xlzd/gotp" target="_blank" rel="noopener noreffer ">https://github.com/xlzd/gotp</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/yeojz/otplib" target="_blank" rel="noopener noreffer ">otplib</a></td>
<td style="text-align:left">Node</td>
<td style="text-align:left"><a href="https://github.com/yeojz/otplib" target="_blank" rel="noopener noreffer ">https://github.com/yeojz/otplib</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/Spomky-Labs/otphp" target="_blank" rel="noopener noreffer ">otphp</a></td>
<td style="text-align:left">PHP</td>
<td style="text-align:left"><a href="https://github.com/Spomky-Labs/otphp" target="_blank" rel="noopener noreffer ">https://github.com/Spomky-Labs/otphp</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/susam/mintotp" target="_blank" rel="noopener noreffer ">mintotp</a></td>
<td style="text-align:left">Python</td>
<td style="text-align:left"><a href="https://github.com/susam/mintotp" target="_blank" rel="noopener noreffer ">https://github.com/susam/mintotp</a></td>
<td></td>
</tr>
<tr>
<td style="text-align:left"><a href="https://github.com/erlang/otp" target="_blank" rel="noopener noreffer ">otp</a></td>
<td style="text-align:left">Erlang</td>
<td style="text-align:left"><a href="https://github.com/erlang/otp" target="_blank" rel="noopener noreffer ">https://github.com/erlang/otp</a></td>
<td></td>
</tr>
</tbody>
</table>
<h2 id="usage">
    <a href="#usage" class="header-anchor" aria-label="Link to Usage"></a>Usage</h2>
<blockquote>
<p><code>go get -u github.com/v8fg/kit4go</code></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">&#34;github.com/v8fg/kit4go/otp&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">secret</span> <span class="o">:=</span> <span class="nx">otp</span><span class="p">.</span><span class="nf">RandomSecret</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span> <span class="c1">// generate a 10-byte secret string, e.g. JBSWY3DPEHPK3PXP
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// otp url
</span></span></span><span class="line"><span class="cl"><span class="c1">// otpauth://totp/Twitter:@xwi88?issuer=Twitter&amp;secret=JJBFGV2ZGNCFARKIKBFTGUCYKA
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">totpURL</span> <span class="o">:=</span> <span class="nx">otp</span><span class="p">.</span><span class="nf">GenerateURLTOTP</span><span class="p">(</span><span class="nx">otp</span><span class="p">.</span><span class="nx">KeyOpts</span><span class="p">{</span><span class="nx">Issuer</span><span class="p">:</span> <span class="s">&#34;Twitter&#34;</span><span class="p">,</span> <span class="nx">AccountName</span><span class="p">:</span> <span class="s">&#34;@xwi88&#34;</span><span class="p">,</span> <span class="nx">Secret</span><span class="p">:</span> <span class="p">[]</span><span class="nb">byte</span><span class="p">(</span><span class="s">&#34;JJBFGV2ZGNCFARKIKBFTGUCYKA&#34;</span><span class="p">)})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// now time: 2022-10-22 18:00:00 +0000 UTC
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">now</span> <span class="o">:=</span> <span class="nx">time</span><span class="p">.</span><span class="nf">Date</span><span class="p">(</span><span class="mi">2022</span><span class="p">,</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">22</span><span class="p">,</span> <span class="mi">18</span><span class="p">,</span> <span class="mo">00</span><span class="p">,</span> <span class="mo">00</span><span class="p">,</span> <span class="mo">00</span><span class="p">,</span> <span class="nx">time</span><span class="p">.</span><span class="nx">UTC</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// totp
</span></span></span><span class="line"><span class="cl"><span class="c1">// code := otp.Code(&#34;JBSWY3DPEHPK3PXP&#34;) // 527484
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">code</span> <span class="o">:=</span> <span class="nx">otp</span><span class="p">.</span><span class="nf">Code</span><span class="p">(</span><span class="s">&#34;JBSWY3DPEHPK3PXP&#34;</span><span class="p">,</span> <span class="nx">now</span><span class="p">)</span> <span class="c1">// 527484
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// totp
</span></span></span><span class="line"><span class="cl"><span class="c1">// code := otp.TOTPCode(&#34;JBSWY3DPEHPK3PXP&#34;) // 527484
</span></span></span><span class="line"><span class="cl"><span class="c1">// code := otp.TOTPCodeCustom(&#34;JBSWY3DPEHPK3PXP&#34;, now, nil) // 527484
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">code</span> <span class="o">:=</span> <span class="nx">otp</span><span class="p">.</span><span class="nf">TOTPCodeCustom</span><span class="p">(</span><span class="s">&#34;JBSWY3DPEHPK3PXP&#34;</span><span class="p">,</span> <span class="nx">now</span><span class="p">,</span> <span class="o">&amp;</span><span class="nx">otp</span><span class="p">.</span><span class="nx">Opts</span><span class="p">{</span><span class="nx">Skew</span><span class="p">:</span> <span class="mi">1</span><span class="p">})</span> <span class="c1">// allow clock skew in [Before(30s) ~ Present(30s) ~ After(30s)]
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="c1">// verify
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">otp</span><span class="p">.</span><span class="nf">VerifyTOTP</span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="s">&#34;JBSWY3DPEHPK3PXP&#34;</span><span class="p">)</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl"><span class="nx">otp</span><span class="p">.</span><span class="nf">VerifyTOTPCustom</span><span class="p">(</span><span class="nx">code</span><span class="p">,</span> <span class="s">&#34;JBSWY3DPEHPK3PXP&#34;</span><span class="p">,</span> <span class="nx">now</span><span class="p">,</span> <span class="kc">nil</span><span class="p">)</span> <span class="c1">// true
</span></span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p>More examples are in the source <code>otp/*_test.go</code> files</p>
</blockquote>]]></description></item><item><title>Go Object Pool Usage &amp; Optimization — Theory</title><link>https://blog.xwi88.com/en/go-object-pool-usage-tips-theory/</link><pubDate>Fri, 03 Jun 2022 08:23:52 +0800</pubDate><author>xwi88</author><guid>https://blog.xwi88.com/en/go-object-pool-usage-tips-theory/</guid><description><![CDATA[<p>Go object pools reuse <code>temporary objects</code>, which <code>reduces the waste</code> from frequently creating them — i.e. <code>lower GC overhead</code> and memory usage — improving performance and lowering serving cost to some extent. Based on <code>go1.18.2</code>, this post covers use cases, <strong>the processing flow &amp; caveats</strong>, open-source examples, a personal example (incl. pooling under <code>gRPC</code>), and best practices.</p>
<h2 id="when-to-use">
    <a href="#when-to-use" class="header-anchor" aria-label="Link to When to use"></a>When to use</h2>
<p><strong>When you frequently create the <code>same kind</code> of object and creation is expensive</strong></p>
<ul>
<li>The larger each object&rsquo;s memory footprint, the more obvious the benefit</li>
<li>The bigger the memory footprint, the more obvious the benefit</li>
<li>The higher the concurrency, the more obvious the benefit</li>
</ul>
<h2 id="processing-flow--caveats">
    <a href="#processing-flow--caveats" class="header-anchor" aria-label="Link to Processing flow &amp; caveats"></a><strong>Processing flow &amp; caveats</strong></h2>
<blockquote>
<p>After a temporary object is returned to the pool, it should ideally be: <code>stateless</code>, <code>reference-free</code></p>
</blockquote>
<ul>
<li>Normal flow: <code>Get</code> <em><code>-&gt;Reset</code></em> -&gt;<code>deal</code>-&gt;<code>Put</code>, <strong>no reference to the returned object after <code>Put</code></strong>
<ul>
<li>Fits most scenarios that need pooling</li>
</ul>
</li>
<li><strong>Special flow</strong>: <code>Get</code> <em><code>-&gt;Reset</code></em> -&gt;<code>deal</code>-&gt;<code>Put</code>-&gt;<code>deal with ref</code>, <strong>a reference to the returned object is kept after <code>Put</code></strong>
<ul>
<li>Special scenarios, e.g. <code>GRPC service call</code></li>
<li><strong>Avoid unless truly necessary</strong></li>
<li><em>If you must, add fault-tolerance to minimize side effects</em></li>
</ul>
</li>
</ul>
<div class="details admonition warning open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-exclamation-triangle fa-fw" aria-hidden="true"></i>Warning<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><ul>
<li><strong>Follow the normal flow whenever possible</strong></li>
<li><em>Always ensure <code>Get</code> &amp; <code>Put</code> appear in pairs</em></li>
<li><strong>Holding a reference to an object after <code>Put</code> (return) can corrupt data if handled improperly</strong></li>
</ul>
</div>
        </div>
    </div>
<h2 id="object-pool-data-structures">
    <a href="#object-pool-data-structures" class="header-anchor" aria-label="Link to Object-pool data structures"></a>Object-pool data structures</h2>
<ul>
<li><code>sync.pool</code>: fits most scenarios; easy to use and efficient
<ul>
<li>Objects in the pool may be removed (released or taken for reuse) without any notice. If the pool holds the only reference to an object, that object is very likely to be reclaimed.</li>
</ul>
</li>
<li><code>channel</code>: queue-like; memory footprint stays stable and it does not release proactively</li>
<li><code>ring buffer</code>: queue-like; memory footprint stays stable and it does not release proactively; lock-free <code>read &amp; write</code></li>
</ul>
<table>
<thead>
<tr>
<th style="text-align:left">Structure</th>
<th style="text-align:left">Min capacity</th>
<th style="text-align:left">Max capacity</th>
<th style="text-align:left">Pros</th>
<th style="text-align:left">Cons</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left"><a href="https://pkg.go.dev/sync#Pool" target="_blank" rel="noopener noreffer "><strong>sync.pool</strong></a></td>
<td style="text-align:left">0</td>
<td style="text-align:left">∞</td>
<td style="text-align:left">Simple, easy to use</td>
<td style="text-align:left">Reclamation is uncontrollable</td>
</tr>
<tr>
<td style="text-align:left"><strong>channel</strong></td>
<td style="text-align:left">0</td>
<td style="text-align:left"><strong>cap</strong></td>
<td style="text-align:left"><strong>Can hold references</strong></td>
<td style="text-align:left">QPS bounded by cap; memory cost</td>
</tr>
<tr>
<td style="text-align:left"><strong>ring buffer</strong></td>
<td style="text-align:left">0</td>
<td style="text-align:left"><strong>cap</strong></td>
<td style="text-align:left"><strong>Can hold references</strong>, <em>lock-free</em></td>
<td style="text-align:left">QPS bounded by cap; memory cost</td>
</tr>
</tbody>
</table>
<div class="details admonition tip open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-lightbulb fa-fw" aria-hidden="true"></i>Tip<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><p><em>Reference-supporting approach</em>: add some redundant objects — i.e. initialize <code>min capacity &gt;= 1*QPS ~ 2*QPS</code> — to reduce the data-corruption risk that object references can cause.</p>
<ul>
<li><strong>Trade a little memory for the high payoff of pooling</strong></li>
<li><strong>Always estimate your memory footprint</strong></li>
<li><strong>Watch the max lifetime of each object; be careful with long operations</strong> <code>e.g. &gt; 1s with high QPS</code></li>
<li><code>Capacity at init: min capacity = max capacity &gt;= 1*QPS</code>; allocate once if possible</li>
</ul>
</div>
        </div>
    </div>
<h2 id="source-examples">
    <a href="#source-examples" class="header-anchor" aria-label="Link to Source examples"></a>Source examples</h2>
<h3 id="fmtprintgo">
    <a href="#fmtprintgo" class="header-anchor" aria-label="Link to fmt/print.go"></a>fmt/print.go</h3>
<blockquote>
<p><a href="https://github.com/golang/go/blob/master/src/fmt/print.go" target="_blank" rel="noopener noreffer ">src/fmt/print.go</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">ppFree</span> <span class="p">=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">New</span><span class="p">:</span> <span class="kd">func</span><span class="p">()</span> <span class="nx">any</span> <span class="p">{</span> <span class="k">return</span> <span class="nb">new</span><span class="p">(</span><span class="nx">pp</span><span class="p">)</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// newPrinter allocates a new pp struct or grabs a cached one.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">newPrinter</span><span class="p">()</span> <span class="o">*</span><span class="nx">pp</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span> <span class="o">:=</span> <span class="nx">ppFree</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">pp</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">panicking</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">erroring</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">wrapErrs</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">init</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">p</span><span class="p">.</span><span class="nx">buf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">p</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// free saves used pp structs in ppFree; avoids an allocation per invocation.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="o">*</span><span class="nx">pp</span><span class="p">)</span> <span class="nf">free</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// Proper usage of a sync.Pool requires each entry to have approximately
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// the same memory cost. To obtain this property when the stored type
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// contains a variably-sized buffer, we add a hard limit on the maximum buffer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// to place back in the pool.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// See https://golang.org/issue/23199
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="k">if</span> <span class="nb">cap</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">buf</span><span class="p">)</span> <span class="p">&gt;</span> <span class="mi">64</span><span class="o">&lt;&lt;</span><span class="mi">10</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">buf</span> <span class="p">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">buf</span><span class="p">[:</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">arg</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">value</span> <span class="p">=</span> <span class="nx">reflect</span><span class="p">.</span><span class="nx">Value</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">wrappedErr</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ppFree</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="grpc-transport-pool">
    <a href="#grpc-transport-pool" class="header-anchor" aria-label="Link to grpc transport pool"></a>grpc transport pool</h3>
<blockquote>
<p><a href="https://github.com/grpc/grpc-go/blob/master/internal/transport/transport.go" target="_blank" rel="noopener noreffer ">google.golang.org/grpc/internal/transport/transport.go</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">bufferPool</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">pool</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">newBufferPool</span><span class="p">()</span> <span class="o">*</span><span class="nx">bufferPool</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="o">&amp;</span><span class="nx">bufferPool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">pool</span><span class="p">:</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">New</span><span class="p">:</span> <span class="kd">func</span><span class="p">()</span> <span class="kd">interface</span><span class="p">{}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="k">return</span> <span class="nb">new</span><span class="p">(</span><span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">},</span>
</span></span><span class="line"><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="o">*</span><span class="nx">bufferPool</span><span class="p">)</span> <span class="nf">get</span><span class="p">()</span> <span class="o">*</span><span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">p</span><span class="p">.</span><span class="nx">pool</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">p</span> <span class="o">*</span><span class="nx">bufferPool</span><span class="p">)</span> <span class="nf">put</span><span class="p">(</span><span class="nx">b</span> <span class="o">*</span><span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">p</span><span class="p">.</span><span class="nx">pool</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">b</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="gin-context-pool">
    <a href="#gin-context-pool" class="header-anchor" aria-label="Link to gin Context pool"></a>gin Context pool</h3>
<blockquote>
<p><a href="https://github.com/gin-gonic/gin/blob/master/gin.go" target="_blank" rel="noopener noreffer ">github.com/gin-gonic/gin/gin.go</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// ServeHTTP conforms to the http.Handler interface.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="p">(</span><span class="nx">engine</span> <span class="o">*</span><span class="nx">Engine</span><span class="p">)</span> <span class="nf">ServeHTTP</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">req</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">c</span> <span class="o">:=</span> <span class="nx">engine</span><span class="p">.</span><span class="nx">pool</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">Context</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">c</span><span class="p">.</span><span class="nx">writermem</span><span class="p">.</span><span class="nf">reset</span><span class="p">(</span><span class="nx">w</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="nx">c</span><span class="p">.</span><span class="nx">Request</span> <span class="p">=</span> <span class="nx">req</span>
</span></span><span class="line"><span class="cl">	<span class="nx">c</span><span class="p">.</span><span class="nf">reset</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">engine</span><span class="p">.</span><span class="nf">handleHTTPRequest</span><span class="p">(</span><span class="nx">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">engine</span><span class="p">.</span><span class="nx">pool</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">c</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="sarama-compress-pool">
    <a href="#sarama-compress-pool" class="header-anchor" aria-label="Link to sarama compress pool"></a>sarama compress pool</h3>
<blockquote>
<p><a href="https://github.com/Shopify/sarama/blob/main/compress.go" target="_blank" rel="noopener noreffer ">github.com/Shopify/sarama/compress.go</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="nx">lz4WriterPool</span> <span class="p">=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">New</span><span class="p">:</span> <span class="kd">func</span><span class="p">()</span> <span class="kd">interface</span><span class="p">{}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="nx">lz4</span><span class="p">.</span><span class="nf">NewWriter</span><span class="p">(</span><span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">gzipWriterPool</span> <span class="p">=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">New</span><span class="p">:</span> <span class="kd">func</span><span class="p">()</span> <span class="kd">interface</span><span class="p">{}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="nx">gzip</span><span class="p">.</span><span class="nf">NewWriter</span><span class="p">(</span><span class="kc">nil</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">gzipWriterPoolForCompressionLevel1</span> <span class="p">=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">New</span><span class="p">:</span> <span class="kd">func</span><span class="p">()</span> <span class="kd">interface</span><span class="p">{}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">gz</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">gzip</span><span class="p">.</span><span class="nf">NewWriterLevel</span><span class="p">(</span><span class="kc">nil</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="nb">panic</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="nx">gz</span>
</span></span><span class="line"><span class="cl">		<span class="p">},</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">compress</span><span class="p">(</span><span class="nx">cc</span> <span class="nx">CompressionCodec</span><span class="p">,</span> <span class="nx">level</span> <span class="kt">int</span><span class="p">,</span> <span class="nx">data</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="kt">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">switch</span> <span class="nx">cc</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">CompressionNone</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">data</span><span class="p">,</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">CompressionGZIP</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">			<span class="nx">err</span>    <span class="kt">error</span>
</span></span><span class="line"><span class="cl">			<span class="nx">buf</span>    <span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span>
</span></span><span class="line"><span class="cl">			<span class="nx">writer</span> <span class="o">*</span><span class="nx">gzip</span><span class="p">.</span><span class="nx">Writer</span>
</span></span><span class="line"><span class="cl">		<span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">switch</span> <span class="nx">level</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">case</span> <span class="nx">CompressionLevelDefault</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="nx">writer</span> <span class="p">=</span> <span class="nx">gzipWriterPool</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">gzip</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">defer</span> <span class="nx">gzipWriterPool</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">writer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nx">writer</span><span class="p">.</span><span class="nf">Reset</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">buf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="nx">writer</span> <span class="p">=</span> <span class="nx">gzipWriterPoolForCompressionLevel1</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">gzip</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">defer</span> <span class="nx">gzipWriterPoolForCompressionLevel1</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">writer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="nx">writer</span><span class="p">.</span><span class="nf">Reset</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">buf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="c1">// ...
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>		<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">			<span class="nx">writer</span><span class="p">,</span> <span class="nx">err</span> <span class="p">=</span> <span class="nx">gzip</span><span class="p">.</span><span class="nf">NewWriterLevel</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">buf</span><span class="p">,</span> <span class="nx">level</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">writer</span><span class="p">.</span><span class="nf">Close</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">buf</span><span class="p">.</span><span class="nf">Bytes</span><span class="p">(),</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">CompressionSnappy</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">snappy</span><span class="p">.</span><span class="nf">Encode</span><span class="p">(</span><span class="nx">data</span><span class="p">),</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">CompressionLZ4</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nx">writer</span> <span class="o">:=</span> <span class="nx">lz4WriterPool</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">lz4</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="k">defer</span> <span class="nx">lz4WriterPool</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">writer</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="kd">var</span> <span class="nx">buf</span> <span class="nx">bytes</span><span class="p">.</span><span class="nx">Buffer</span>
</span></span><span class="line"><span class="cl">		<span class="nx">writer</span><span class="p">.</span><span class="nf">Reset</span><span class="p">(</span><span class="o">&amp;</span><span class="nx">buf</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">writer</span><span class="p">.</span><span class="nf">Write</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">writer</span><span class="p">.</span><span class="nf">Close</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nx">buf</span><span class="p">.</span><span class="nf">Bytes</span><span class="p">(),</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">CompressionZSTD</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="nf">zstdCompress</span><span class="p">(</span><span class="nx">ZstdEncoderParams</span><span class="p">{</span><span class="nx">level</span><span class="p">},</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">return</span> <span class="kc">nil</span><span class="p">,</span> <span class="nx">PacketEncodingError</span><span class="p">{</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">&#34;unsupported compression codec (%d)&#34;</span><span class="p">,</span> <span class="nx">cc</span><span class="p">)}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="zap-json-pool">
    <a href="#zap-json-pool" class="header-anchor" aria-label="Link to zap json pool"></a>zap json pool</h3>
<blockquote>
<p><a href="https://github.com/uber-go/zap/blob/master/zapcore/json_encoder.go" target="_blank" rel="noopener noreffer ">go.uber.org/zap/zapcore/json_encoder.go</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">_jsonPool</span> <span class="p">=</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">Pool</span><span class="p">{</span><span class="nx">New</span><span class="p">:</span> <span class="kd">func</span><span class="p">()</span> <span class="kd">interface</span><span class="p">{}</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="o">&amp;</span><span class="nx">jsonEncoder</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">getJSONEncoder</span><span class="p">()</span> <span class="o">*</span><span class="nx">jsonEncoder</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="nx">_jsonPool</span><span class="p">.</span><span class="nf">Get</span><span class="p">().(</span><span class="o">*</span><span class="nx">jsonEncoder</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">putJSONEncoder</span><span class="p">(</span><span class="nx">enc</span> <span class="o">*</span><span class="nx">jsonEncoder</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">enc</span><span class="p">.</span><span class="nx">reflectBuf</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">enc</span><span class="p">.</span><span class="nx">reflectBuf</span><span class="p">.</span><span class="nf">Free</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">enc</span><span class="p">.</span><span class="nx">EncoderConfig</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="nx">enc</span><span class="p">.</span><span class="nx">buf</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="nx">enc</span><span class="p">.</span><span class="nx">spaced</span> <span class="p">=</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl">	<span class="nx">enc</span><span class="p">.</span><span class="nx">openNamespaces</span> <span class="p">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">	<span class="nx">enc</span><span class="p">.</span><span class="nx">reflectBuf</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="nx">enc</span><span class="p">.</span><span class="nx">reflectEnc</span> <span class="p">=</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl">	<span class="nx">_jsonPool</span><span class="p">.</span><span class="nf">Put</span><span class="p">(</span><span class="nx">enc</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="leakbuf-base-channel">
    <a href="#leakbuf-base-channel" class="header-anchor" aria-label="Link to leakbuf base channel"></a>leakbuf base channel</h3>
<blockquote>
<p><a href="https://github.com/shadowsocks/shadowsocks-go/blob/master/shadowsocks/leakybuf.go" target="_blank" rel="noopener noreffer ">shadowsocks/shadowsocks-go/shadowsocks/leakybuf</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Provides leaky buffer, based on the example in Effective Go.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kn">package</span> <span class="nx">shadowsocks</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">LeakyBuf</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">bufSize</span>  <span class="kt">int</span> <span class="c1">// size of each buffer
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">freeList</span> <span class="kd">chan</span> <span class="p">[]</span><span class="kt">byte</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">const</span> <span class="nx">leakyBufSize</span> <span class="p">=</span> <span class="mi">4108</span> <span class="c1">// data.len(2) + hmacsha1(10) + data(4096)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">const</span> <span class="nx">maxNBuf</span> <span class="p">=</span> <span class="mi">2048</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">var</span> <span class="nx">leakyBuf</span> <span class="p">=</span> <span class="nf">NewLeakyBuf</span><span class="p">(</span><span class="nx">maxNBuf</span><span class="p">,</span> <span class="nx">leakyBufSize</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// NewLeakyBuf creates a leaky buffer which can hold at most n buffer, each
</span></span></span><span class="line"><span class="cl"><span class="c1">// with bufSize bytes.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">NewLeakyBuf</span><span class="p">(</span><span class="nx">n</span><span class="p">,</span> <span class="nx">bufSize</span> <span class="kt">int</span><span class="p">)</span> <span class="o">*</span><span class="nx">LeakyBuf</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="o">&amp;</span><span class="nx">LeakyBuf</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">bufSize</span><span class="p">:</span>  <span class="nx">bufSize</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">freeList</span><span class="p">:</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">,</span> <span class="nx">n</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Get returns a buffer from the leaky buffer or create a new buffer.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="p">(</span><span class="nx">lb</span> <span class="o">*</span><span class="nx">LeakyBuf</span><span class="p">)</span> <span class="nf">Get</span><span class="p">()</span> <span class="p">(</span><span class="nx">b</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">b</span> <span class="p">=</span> <span class="o">&lt;-</span><span class="nx">lb</span><span class="p">.</span><span class="nx">freeList</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="nx">b</span> <span class="p">=</span> <span class="nb">make</span><span class="p">([]</span><span class="kt">byte</span><span class="p">,</span> <span class="nx">lb</span><span class="p">.</span><span class="nx">bufSize</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Put add the buffer into the free buffer pool for reuse. Panic if the buffer
</span></span></span><span class="line"><span class="cl"><span class="c1">// size is not the same with the leaky buffer&#39;s. This is intended to expose
</span></span></span><span class="line"><span class="cl"><span class="c1">// error usage of leaky buffer.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="p">(</span><span class="nx">lb</span> <span class="o">*</span><span class="nx">LeakyBuf</span><span class="p">)</span> <span class="nf">Put</span><span class="p">(</span><span class="nx">b</span> <span class="p">[]</span><span class="kt">byte</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="nx">b</span><span class="p">)</span> <span class="o">!=</span> <span class="nx">lb</span><span class="p">.</span><span class="nx">bufSize</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nb">panic</span><span class="p">(</span><span class="s">&#34;invalid buffer size that&#39;s put into leaky buffer&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">case</span> <span class="nx">lb</span><span class="p">.</span><span class="nx">freeList</span> <span class="o">&lt;-</span> <span class="nx">b</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p><strong>Copyright notice</strong>: This is an original article by <strong><a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">xwi88</a></strong>, licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener noreffer ">CC BY-NC 4.0</a>. Commercial use is prohibited; please cite the source when reposting. Follow at <a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">https://github.com/xwi88</a></p>
</blockquote>]]></description></item><item><title>Go Kafka Consumer Group Usage</title><link>https://blog.xwi88.com/en/go-kafka-consumer-group-usage/</link><pubDate>Wed, 25 May 2022 08:55:28 +0800</pubDate><author>xwi88</author><guid>https://blog.xwi88.com/en/go-kafka-consumer-group-usage/</guid><description><![CDATA[<p>Based on <code>Go 1.18</code> and <code>Kafka 2.4.1</code>, this post consumes messages via a <code>Kafka Consumer Group</code>, provides a best-practice example and configuration tips, and reduces <code>timeout</code> issues caused by <code>Rebalance</code>.</p>
<blockquote>
<p><strong>Copyright notice</strong>: This is an original article by <strong><a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">xwi88</a></strong>, licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener noreffer ">CC BY-NC 4.0</a>. Commercial use is prohibited; please cite the source when reposting. Follow at <a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">https://github.com/xwi88</a></p>
</blockquote>
<h2 id="consumer-group">
    <a href="#consumer-group" class="header-anchor" aria-label="Link to Consumer Group"></a>Consumer Group</h2>
<p>A <code>consumer group</code> is Kafka&rsquo;s scalable, fault-tolerant consumer mechanism. A few properties:</p>
<ul>
<li>A <code>consumer group</code> is made up of <strong>one or more</strong> <code>consumer</code>s that together consume messages from <strong>one or more</strong> <code>topic</code>s</li>
<li>A <code>consumer group</code> is uniquely identified by its <code>group ID</code>; consumers in the group share that <code>group ID</code></li>
<li>Each partition of a <code>topic</code> can be consumed by only one <code>consumer</code> within the same group, but can be consumed by consumers in different groups</li>
</ul>
<div class="details admonition tip open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-lightbulb fa-fw" aria-hidden="true"></i>Tip<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><ul>
<li>The partition count should exceed the number of consumers; if throughput is insufficient, consider adding consumers</li>
<li>When simply adding consumers no longer boosts throughput notably, optimize your consumption logic</li>
<li>The number of consumers must be bounded to avoid excessively long <code>rebalance</code>s</li>
</ul>
</div>
        </div>
    </div>
<h2 id="rebalance">
    <a href="#rebalance" class="header-anchor" aria-label="Link to Rebalance"></a>Rebalance</h2>
<p>Partition rebalancing (<code>Rebalance</code>) is a key Kafka feature that guarantees high availability and horizontal scaling. The following trigger a Kafka rebalance:</p>
<ul>
<li>Consumer-group membership changes:
<ul>
<li><strong>A new consumer joins</strong></li>
<li><em>An existing consumer leaves</em>: voluntary leave → voluntary <code>rebalance</code></li>
<li><em>An existing consumer fails or crashes</em>: if it stops sending heartbeats beyond a threshold it&rsquo;s considered dead; detection takes one <code>session.timeout</code> cycle → involuntary <code>rebalance</code></li>
</ul>
</li>
<li>The number of subscribed <code>topic</code>s changes (e.g. regex subscription where matching <code>topic</code>s change)</li>
<li>The partition count of a subscribed <code>topic</code> changes</li>
</ul>
<div class="details admonition note open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-pencil-alt fa-fw" aria-hidden="true"></i>Note<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><ul>
<li>Pros: guarantees high availability and scalability</li>
<li>Cons: during a rebalance the whole consumer group is unavailable; rebalancing forces consumers to refresh state, and old consumer state expires, lowering consumer capacity</li>
</ul>
</div>
        </div>
    </div>
<h2 id="go-consumer-group">
    <a href="#go-consumer-group" class="header-anchor" aria-label="Link to Go Consumer Group"></a>Go Consumer Group</h2>
<h3 id="consumergroup-interface--notes">
    <a href="#consumergroup-interface--notes" class="header-anchor" aria-label="Link to ConsumerGroup interface &amp; notes"></a>ConsumerGroup interface &amp; notes</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// ConsumerGroup is responsible for dividing up processing of topics and partitions
</span></span></span><span class="line"><span class="cl"><span class="c1">// over a collection of processes (the members of the consumer group).
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">type</span> <span class="nx">ConsumerGroup</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="c1">// Consume joins a cluster of consumers for a given list of topics and
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// starts a blocking ConsumerGroupSession through the ConsumerGroupHandler.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// The life-cycle of a session is represented by the following steps:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 1. The consumers join the group (as explained in https://kafka.apache.org/documentation/#intro_consumers)
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//    and is assigned their &#34;fair share&#34; of partitions, aka &#39;claims&#39;.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 2. Before processing starts, the handler&#39;s Setup() hook is called to notify the user
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//    of the claims and allow any necessary preparation or alteration of state.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 3. For each of the assigned claims the handler&#39;s ConsumeClaim() function is then called
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//    in a separate goroutine which requires it to be thread-safe. Any state must be carefully protected
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//    from concurrent reads/writes.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 4. The session will persist until one of the ConsumeClaim() functions exits. This can be either when the
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//    parent context is canceled or when a server-side rebalance cycle is initiated.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 5. Once all the ConsumeClaim() loops have exited, the handler&#39;s Cleanup() hook is called
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//    to allow the user to perform any final tasks before a rebalance.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// 6. Finally, marked offsets are committed one last time before claims are released.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// Please note, that once a rebalance is triggered, sessions must be completed within
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// Config.Consumer.Group.Rebalance.Timeout. This means that ConsumeClaim() functions must exit
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// as quickly as possible to allow time for Cleanup() and the final offset commit. If the timeout
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// is exceeded, the consumer will be removed from the group by Kafka, which will cause offset
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// commit failures.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// This method should be called inside an infinite loop, when a
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// server-side rebalance happens, the consumer session will need to be
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// recreated to get the new claims.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nf">Consume</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">topics</span> <span class="p">[]</span><span class="kt">string</span><span class="p">,</span> <span class="nx">handler</span> <span class="nx">ConsumerGroupHandler</span><span class="p">)</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// Errors returns a read channel of errors that occurred during the consumer life-cycle.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// By default, errors are logged and not returned over this channel.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// If you want to implement any custom error handling, set your config&#39;s
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// Consumer.Return.Errors setting to true, and read from this channel.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nf">Errors</span><span class="p">()</span> <span class="o">&lt;-</span><span class="kd">chan</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="c1">// Close stops the ConsumerGroup and detaches any running sessions. It is required to call
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="c1">// this function before the object passes out of scope, as it will otherwise leak memory.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nf">Close</span><span class="p">()</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="consumergroup-demo">
    <a href="#consumergroup-demo" class="header-anchor" aria-label="Link to ConsumerGroup Demo"></a>ConsumerGroup Demo</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">  1
</span><span class="lnt">  2
</span><span class="lnt">  3
</span><span class="lnt">  4
</span><span class="lnt">  5
</span><span class="lnt">  6
</span><span class="lnt">  7
</span><span class="lnt">  8
</span><span class="lnt">  9
</span><span class="lnt"> 10
</span><span class="lnt"> 11
</span><span class="lnt"> 12
</span><span class="lnt"> 13
</span><span class="lnt"> 14
</span><span class="lnt"> 15
</span><span class="lnt"> 16
</span><span class="lnt"> 17
</span><span class="lnt"> 18
</span><span class="lnt"> 19
</span><span class="lnt"> 20
</span><span class="lnt"> 21
</span><span class="lnt"> 22
</span><span class="lnt"> 23
</span><span class="lnt"> 24
</span><span class="lnt"> 25
</span><span class="lnt"> 26
</span><span class="lnt"> 27
</span><span class="lnt"> 28
</span><span class="lnt"> 29
</span><span class="lnt"> 30
</span><span class="lnt"> 31
</span><span class="lnt"> 32
</span><span class="lnt"> 33
</span><span class="lnt"> 34
</span><span class="lnt"> 35
</span><span class="lnt"> 36
</span><span class="lnt"> 37
</span><span class="lnt"> 38
</span><span class="lnt"> 39
</span><span class="lnt"> 40
</span><span class="lnt"> 41
</span><span class="lnt"> 42
</span><span class="lnt"> 43
</span><span class="lnt"> 44
</span><span class="lnt"> 45
</span><span class="lnt"> 46
</span><span class="lnt"> 47
</span><span class="lnt"> 48
</span><span class="lnt"> 49
</span><span class="lnt"> 50
</span><span class="lnt"> 51
</span><span class="lnt"> 52
</span><span class="lnt"> 53
</span><span class="lnt"> 54
</span><span class="lnt"> 55
</span><span class="lnt"> 56
</span><span class="lnt"> 57
</span><span class="lnt"> 58
</span><span class="lnt"> 59
</span><span class="lnt"> 60
</span><span class="lnt"> 61
</span><span class="lnt"> 62
</span><span class="lnt"> 63
</span><span class="lnt"> 64
</span><span class="lnt"> 65
</span><span class="lnt"> 66
</span><span class="lnt"> 67
</span><span class="lnt"> 68
</span><span class="lnt"> 69
</span><span class="lnt"> 70
</span><span class="lnt"> 71
</span><span class="lnt"> 72
</span><span class="lnt"> 73
</span><span class="lnt"> 74
</span><span class="lnt"> 75
</span><span class="lnt"> 76
</span><span class="lnt"> 77
</span><span class="lnt"> 78
</span><span class="lnt"> 79
</span><span class="lnt"> 80
</span><span class="lnt"> 81
</span><span class="lnt"> 82
</span><span class="lnt"> 83
</span><span class="lnt"> 84
</span><span class="lnt"> 85
</span><span class="lnt"> 86
</span><span class="lnt"> 87
</span><span class="lnt"> 88
</span><span class="lnt"> 89
</span><span class="lnt"> 90
</span><span class="lnt"> 91
</span><span class="lnt"> 92
</span><span class="lnt"> 93
</span><span class="lnt"> 94
</span><span class="lnt"> 95
</span><span class="lnt"> 96
</span><span class="lnt"> 97
</span><span class="lnt"> 98
</span><span class="lnt"> 99
</span><span class="lnt">100
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">kafka</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;context&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;log&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;time&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="s">&#34;github.com/Shopify/sarama&#34;</span>
</span></span><span class="line"><span class="cl">	<span class="s">&#34;github.com/pkg/errors&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">ConsumerGroup</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nf">Consume</span><span class="p">(</span><span class="nx">topics</span> <span class="p">[]</span><span class="kt">string</span><span class="p">,</span> <span class="nx">handler</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ConsumerGroupHandler</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">type</span> <span class="nx">consumerGroup</span> <span class="kd">struct</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">ctx</span>           <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span>
</span></span><span class="line"><span class="cl">	<span class="nx">consumerGroup</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ConsumerGroup</span>
</span></span><span class="line"><span class="cl">	<span class="nx">groupId</span>       <span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">brokers</span>       <span class="p">[]</span><span class="kt">string</span>
</span></span><span class="line"><span class="cl">	<span class="nx">done</span>          <span class="kd">chan</span> <span class="kd">struct</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl">	<span class="nx">cancel</span>        <span class="nx">context</span><span class="p">.</span><span class="nx">CancelFunc</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">NewConsumerGroup</span><span class="p">(</span><span class="nx">ctx</span> <span class="nx">context</span><span class="p">.</span><span class="nx">Context</span><span class="p">,</span> <span class="nx">groupId</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">brokers</span> <span class="p">[]</span><span class="kt">string</span><span class="p">)</span> <span class="nx">ConsumerGroup</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="nx">config</span> <span class="o">:=</span> <span class="nx">sarama</span><span class="p">.</span><span class="nf">NewConfig</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="nx">config</span><span class="p">.</span><span class="nx">Version</span> <span class="p">=</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">V2_4_1_0</span>
</span></span><span class="line"><span class="cl">	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">Return</span><span class="p">.</span><span class="nx">Errors</span> <span class="p">=</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl">	<span class="nx">config</span><span class="p">.</span><span class="nx">Net</span><span class="p">.</span><span class="nx">ReadTimeout</span> <span class="p">=</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span> <span class="o">*</span> <span class="mi">75</span>                  <span class="c1">// default 30s
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">Group</span><span class="p">.</span><span class="nx">Rebalance</span><span class="p">.</span><span class="nx">Timeout</span> <span class="p">=</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span> <span class="o">*</span> <span class="mi">60</span> <span class="c1">// default 60s
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">Group</span><span class="p">.</span><span class="nx">Session</span><span class="p">.</span><span class="nx">Timeout</span> <span class="p">=</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span> <span class="o">*</span> <span class="mi">45</span>   <span class="c1">// default 10s
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">Group</span><span class="p">.</span><span class="nx">Heartbeat</span><span class="p">.</span><span class="nx">Interval</span> <span class="p">=</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span> <span class="o">*</span> <span class="mi">5</span> <span class="c1">// default 3s, must &lt;= 1/3 * Group.Session.Timeout
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">Group</span><span class="p">.</span><span class="nx">Rebalance</span><span class="p">.</span><span class="nx">Strategy</span> <span class="p">=</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">BalanceStrategySticky</span>
</span></span><span class="line"><span class="cl">	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">MaxWaitTime</span> <span class="p">=</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Millisecond</span> <span class="o">*</span> <span class="mi">250</span> <span class="c1">// default 250ms
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>	<span class="nx">config</span><span class="p">.</span><span class="nx">Consumer</span><span class="p">.</span><span class="nx">Retry</span><span class="p">.</span><span class="nx">Backoff</span> <span class="p">=</span> <span class="nx">time</span><span class="p">.</span><span class="nx">Second</span> <span class="o">*</span> <span class="mi">2</span>      <span class="c1">// default 2s
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">	<span class="nx">cg</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">sarama</span><span class="p">.</span><span class="nf">NewConsumerGroup</span><span class="p">(</span><span class="nx">brokers</span><span class="p">,</span> <span class="nx">groupId</span><span class="p">,</span> <span class="nx">config</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nb">panic</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">Wrap</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="s">&#34;consumerGroup create err&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">for</span> <span class="nx">err</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">cg</span><span class="p">.</span><span class="nf">Errors</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;consumerGroup, group_id:%v, err:%v&#34;</span><span class="p">,</span> <span class="nx">groupId</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">ctx</span><span class="p">,</span> <span class="nx">cancel</span> <span class="o">:=</span> <span class="nx">context</span><span class="p">.</span><span class="nf">WithCancel</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="k">return</span> <span class="o">&amp;</span><span class="nx">consumerGroup</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">ctx</span><span class="p">:</span>           <span class="nx">ctx</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">consumerGroup</span><span class="p">:</span> <span class="nx">cg</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">groupId</span><span class="p">:</span>       <span class="nx">groupId</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">brokers</span><span class="p">:</span>       <span class="nx">brokers</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">		<span class="nx">done</span><span class="p">:</span>          <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kd">struct</span><span class="p">{}),</span>
</span></span><span class="line"><span class="cl">		<span class="nx">cancel</span><span class="p">:</span>        <span class="nx">cancel</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">c</span> <span class="o">*</span><span class="nx">consumerGroup</span><span class="p">)</span> <span class="nf">Consume</span><span class="p">(</span><span class="nx">topics</span> <span class="p">[]</span><span class="kt">string</span><span class="p">,</span> <span class="nx">handler</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ConsumerGroupHandler</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="k">defer</span> <span class="kd">func</span><span class="p">(</span><span class="nx">consumerGroup</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ConsumerGroup</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="nx">err</span> <span class="o">:=</span> <span class="nx">consumerGroup</span><span class="p">.</span><span class="nf">Close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}(</span><span class="nx">c</span><span class="p">.</span><span class="nx">consumerGroup</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">	<span class="nx">Loop</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">		<span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">consumerGroup</span><span class="p">.</span><span class="nf">Consume</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">ctx</span><span class="p">,</span> <span class="nx">topics</span><span class="p">,</span> <span class="nx">handler</span><span class="p">);</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="k">switch</span> <span class="nx">err</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">				<span class="k">case</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ErrClosedClient</span><span class="p">,</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ErrClosedConsumerGroup</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">					<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;consumerGroup.Consume() topic:%v, shutdown with err:%v&#34;</span><span class="p">,</span> <span class="nx">topics</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">					<span class="k">break</span> <span class="nx">Loop</span>
</span></span><span class="line"><span class="cl">				<span class="k">case</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ErrOutOfBrokers</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">					<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;consumerGroup.Consume() topic:%v, err:%v&#34;</span><span class="p">,</span> <span class="nx">topics</span><span class="p">,</span> <span class="nx">sarama</span><span class="p">.</span><span class="nx">ErrOutOfBrokers</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">				<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">					<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;consumerGroup.Consume() topic:%v, err:%v&#34;</span><span class="p">,</span> <span class="nx">topics</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">				<span class="p">}</span>
</span></span><span class="line"><span class="cl">				<span class="nx">time</span><span class="p">.</span><span class="nf">Sleep</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Second</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">			<span class="k">select</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">			<span class="k">case</span> <span class="o">&lt;-</span><span class="nx">c</span><span class="p">.</span><span class="nx">done</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">				<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;session exit after close signal&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">				<span class="k">break</span> <span class="nx">Loop</span>
</span></span><span class="line"><span class="cl">			<span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">				<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;server-side reBalance happens, consumer session exit, will recreated&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">			<span class="p">}</span>
</span></span><span class="line"><span class="cl">		<span class="p">}</span>
</span></span><span class="line"><span class="cl">	<span class="p">}()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="p">(</span><span class="nx">c</span> <span class="o">*</span><span class="nx">consumerGroup</span><span class="p">)</span> <span class="nf">Close</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">	<span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span> <span class="nx">c</span><span class="p">.</span><span class="nx">done</span> <span class="o">&lt;-</span> <span class="kd">struct</span><span class="p">{}{}</span> <span class="p">}()</span>
</span></span><span class="line"><span class="cl">	<span class="nx">c</span><span class="p">.</span><span class="nf">cancel</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">	<span class="k">if</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">consumerGroup</span><span class="p">.</span><span class="nf">Close</span><span class="p">();</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;consumerGroup close error, %v&#34;</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">		<span class="nx">log</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;consumerGroup exit gracefully&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">	<span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="selected-config-parameters">
    <a href="#selected-config-parameters" class="header-anchor" aria-label="Link to Selected config parameters"></a>Selected config parameters</h2>
<ul>
<li><code>Net.ReadTimeout</code>: <strong>How long to wait for a response.</strong></li>
<li><code>Group.Rebalance.Timeout</code>: The maximum allowed time for each worker to join the group once a rebalance has begun.This is basically a limit on the amount of time needed for all tasks to flush any pending data and commit offsets. If the timeout is exceeded, then the worker will be removed from the group, which will cause offset commit failures (default 60s).</li>
<li><code>Group.Session.Timeout</code>: The timeout used to detect consumer failures when using Kafka&rsquo;s group management facility. The consumer sends periodic heartbeats to indicate its liveness to the broker. If no heartbeats are received by the broker before the expiration of this session timeout, then the broker will remove this consumer from the group and initiate a rebalance. Note that the value must be in the allowable range as configured in the broker configuration by <code>group.min.session.timeout.ms</code> and <code>group.max.session.timeout.ms</code> (default 10s)</li>
<li><code>Group.Heartbeat.Interval</code>: The expected time between heartbeats to the consumer coordinator when using Kafka&rsquo;s group management facilities. Heartbeats are used to ensure that the consumer&rsquo;s session stays active and to facilitate rebalancing when new consumers join or leave the group. The value must be set lower than Consumer.Group.Session.Timeout, but typically should be set no higher than 1/3 of that value.</li>
<li><code>Group.Rebalance.Strategy</code>: Strategy for allocating topic partitions to members (default BalanceStrategyRange), [&ldquo;range&rdquo;, &ldquo;roundrobin&rdquo;, &ldquo;sticky&rdquo;]</li>
<li><code>MaxWaitTime</code>:The maximum amount of time the broker will wait for Consumer.Fetch.Min bytes to become available before it returns fewer than that anyways.</li>
<li><code>Retry.Backoff</code>: How long to wait after a failing to read from a partition before trying again.</li>
</ul>
<h2 id="configuration-recommendations">
    <a href="#configuration-recommendations" class="header-anchor" aria-label="Link to Configuration recommendations"></a>Configuration recommendations</h2>
<ul>
<li><code>Net.ReadTimeout</code>: default <code>30s</code>; if consumers often hit <code>read tcp xxx i/o timeout</code>, consider raising it
<ul>
<li><code>&gt; session.timeout</code></li>
<li><code>&gt; rebalance.timeout</code></li>
</ul>
</li>
<li><code>Group.Rebalance.Timeout</code>: default <code>60s</code>; with many consumers, consider raising it; for low-<code>TPS</code> topics it can be lowered</li>
<li><code>Group.Session.Timeout</code>: default <code>10s</code>; if a consumer stops sending heartbeats beyond this, it&rsquo;s considered dead and a <code>rebalance</code> is triggered
<ul>
<li><code>shall &gt;= 1/3 * Group.Heartbeat.Interval</code></li>
</ul>
</li>
<li><code>Group.Heartbeat.Interval</code>: default <code>3s</code>, the consumer&rsquo;s heartbeat interval</li>
<li><code>Group.Rebalance.Strategy</code>: the rebalance strategy
<ul>
<li><code>range</code>: default; <em>per topic, n = partitions/consumers, m = partitions % consumers; the first m consumers each get n+1 partitions, the remaining (consumers − m) each get n</em></li>
<li><code>roundrobin</code>: sort all consumers in the group and all partitions of their subscribed <code>topic</code>s lexicographically, then assign partitions to consumers round-robin</li>
<li><code>sticky</code>: <strong>sticky strategy</strong>; keeps consumption as balanced as possible
<ul>
<li>partition allocation should be as even as possible — the partition counts assigned to any two consumers differ by at most one</li>
<li>the allocation should stay as close to the previous one as possible</li>
</ul>
</li>
</ul>
</li>
<li><code>MaxWaitTime</code>: default <code>250ms</code>; data is sent to the consumer after at most this long, or once <code>fetch.min.bytes</code> is reached</li>
<li><code>Retry.Backoff</code>: default <code>2s</code></li>
</ul>]]></description></item><item><title>Pyroscope: Continuous Profiling for Go</title><link>https://blog.xwi88.com/en/pyroscope-continuous-profiling/</link><pubDate>Tue, 29 Mar 2022 23:22:32 +0800</pubDate><author>xwi88</author><guid>https://blog.xwi88.com/en/pyroscope-continuous-profiling/</guid><description><![CDATA[<p><strong><a href="https://pyroscope.io/" target="_blank" rel="noopener noreffer ">Pyroscope</a></strong> is an open-source continuous-profiling platform. It supports many languages (<code>Go</code>, <code>Python</code>, <code>Rust</code>, <code>Java</code>, …), runs on <strong>multiple platforms</strong> with <strong>multiple deployment options</strong>, ships a handy visual-analysis UI, powerful data querying/analysis/storage, configurable data-eviction policies, and both <code>Push</code> and <code>Pull</code> modes. It can export to several formats (<code>png</code>, <code>json</code>, <code>pprof</code>, <code>html</code>, <code>flamegraph.com</code>) and can be displayed inside <a href="https://grafana.com/grafana/plugins/pyroscope-panel/" target="_blank" rel="noopener noreffer "><code>grafana</code></a>.</p>
<blockquote>
<p><strong>Copyright notice</strong>: This is an original article by <strong><a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">xwi88</a></strong>, licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener noreffer ">CC BY-NC 4.0</a>. Commercial use is prohibited; please cite the source when reposting. Follow at <a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">https://github.com/xwi88</a></p>
</blockquote>
<h2 id="why-use-it">
    <a href="#why-use-it" class="header-anchor" aria-label="Link to Why use it"></a>Why use it</h2>
<ul>
<li>Understand which parts of your application consume the most resources</li>
<li>Continuous profiling adds a time dimension, letting you track resource usage (CPU, memory, …) over time and locate, debug and fix performance issues</li>
</ul>
<h2 id="use-cases">
    <a href="#use-cases" class="header-anchor" aria-label="Link to Use cases"></a>Use cases</h2>
<ul>
<li>Find performance problems in your code</li>
<li>Resolve high CPU utilization</li>
<li>Locate and fix memory leaks</li>
<li>Understand your application&rsquo;s call tree</li>
<li>Track how metrics change over time</li>
</ul>
<h2 id="overhead">
    <a href="#overhead" class="header-anchor" aria-label="Link to Overhead"></a>Overhead</h2>
<p>By using sampling-based profiling, <strong>Pyroscope</strong> collects data with minimal overhead (around <code>2-5%</code>). Its purpose-built <em>storage engine</em> <em>compresses and stores data efficiently</em>.</p>
<ul>
<li>Low CPU overhead thanks to sampling</li>
<li>Control the granularity of profiling data (<code>10s</code> up to multiple years)</li>
<li>Efficient compression, low disk-space needs and cost</li>
</ul>
<h2 id="working-mode">
    <a href="#working-mode" class="header-anchor" aria-label="Link to Working mode"></a>Working mode</h2>
<blockquote>
<p>Similar to common data-collection tools: an <code>Agent-Server</code> model.</p>
</blockquote>
<ul>
<li><code>Pyroscope Server</code> <em>records and aggregates what the application is doing, then sends that data to the Pyroscope server.</em></li>
<li><code>Pyroscope Agent</code> processes, aggregates and stores the data from the agent to enable fast queries over arbitrary time ranges. You can then view profiling data over any time window.</li>
</ul>
<p><figure><figcaption class="image-caption">pyroscope agents</figcaption>
    </figure></p>
<h2 id="server-installation">
    <a href="#server-installation" class="header-anchor" aria-label="Link to Server installation"></a>Server installation</h2>
<h3 id="install-methods">
    <a href="#install-methods" class="header-anchor" aria-label="Link to Install methods"></a>Install methods</h3>
<ul>
<li>Docker</li>
<li>K8S</li>
<li>Direct
<ul>
<li>MacOS</li>
<li>Linux</li>
<li>Windows</li>
</ul>
</li>
</ul>
<h3 id="macos--linux-install-example">
    <a href="#macos--linux-install-example" class="header-anchor" aria-label="Link to MacOS &amp; Linux install example"></a>MacOS &amp; Linux install example</h3>
<ul>
<li><a href="https://pyroscope.io/docs/server-install-macos/" target="_blank" rel="noopener noreffer ">install-macos</a></li>
<li><a href="https://pyroscope.io/docs/server-install-linux/" target="_blank" rel="noopener noreffer ">install-linux</a></li>
</ul>
<div class="details admonition example open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-list-ol fa-fw" aria-hidden="true"></i>Example<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><blockquote>
<p><code>export pyroscope_version=0.13.0</code></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># MacOs</span>
</span></span><span class="line"><span class="cl">brew install pyroscope-io/brew/pyroscope
</span></span><span class="line"><span class="cl">brew services start pyroscope-server
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ubuntu/Debian</span>
</span></span><span class="line"><span class="cl">wget https://dl.pyroscope.io/release/pyroscope_<span class="s2">&#34;</span><span class="si">${</span><span class="nv">pyroscope_version</span><span class="si">}</span><span class="s2">&#34;</span>_amd64.deb
</span></span><span class="line"><span class="cl">sudo apt-get install ./pyroscope_<span class="s2">&#34;</span><span class="si">${</span><span class="nv">pyroscope_version</span><span class="si">}</span><span class="s2">&#34;</span>_amd64.deb
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># CentOS</span>
</span></span><span class="line"><span class="cl">wget https://dl.pyroscope.io/release/pyroscope-<span class="s2">&#34;</span><span class="si">${</span><span class="nv">pyroscope_version</span><span class="si">}</span><span class="s2">&#34;</span>-1-x86_64.rpm
</span></span><span class="line"><span class="cl">sudo yum localinstall pyroscope-<span class="s2">&#34;</span><span class="si">${</span><span class="nv">pyroscope_version</span><span class="si">}</span><span class="s2">&#34;</span>-1-x86_64.rpm
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Use systemctl to enable boot start and start the service</span>
</span></span><span class="line"><span class="cl">sudo systemctl <span class="nb">enable</span> pyroscope-server
</span></span><span class="line"><span class="cl">sudo systemctl start pyroscope-server
</span></span></code></pre></td></tr></table>
</div>
</div></div>
        </div>
    </div>
<h3 id="configuration">
    <a href="#configuration" class="header-anchor" aria-label="Link to Configuration"></a>Configuration</h3>
<p>Multiple <a href="https://pyroscope.io/docs/server-configuration/" target="_blank" rel="noopener noreffer ">configuration</a> sources are supported, with this precedence:</p>
<ol>
<li><strong>CLI flags</strong></li>
<li><em>Environment variables</em></li>
<li>Config file</li>
</ol>
<p>We&rsquo;ll configure the server via a config file. Default locations:</p>
<ul>
<li><code>/etc/pyroscope/server.yml</code> <strong>on Linux</strong></li>
<li><code>/usr/local/etc/pyroscope/server.yml</code> <strong>on Intel macOS</strong></li>
<li><code>/opt/homebrew/etc/pyroscope/server.yml</code> <em>on M1 macOS</em></li>
</ul>
<p>You can point to a config file explicitly:</p>
<ul>
<li><code>pyroscope server -config my-custom-config.yml</code> <code>via CLI</code> <strong>recommended</strong></li>
<li><code>PYROSCOPE_CONFIG=/tmp/pyroscope-server.yml pyroscope server</code> via env var</li>
</ul>
<div class="details admonition example open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-list-ol fa-fw" aria-hidden="true"></i>Example<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><blockquote>
<p><code>pyroscope-server.yml</code></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span><span class="lnt">85
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-tex" data-lang="tex"><span class="line"><span class="cl">---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">auth:
</span></span><span class="line"><span class="cl"> # Specifies which role will be granted to a newly signed up user.
</span></span><span class="line"><span class="cl">  # Supported roles: Admin, ReadOnly. Defaults to ReadOnly.
</span></span><span class="line"><span class="cl">  # The parameter affects all authentication providers.
</span></span><span class="line"><span class="cl">  signup-default-role: ReadOnly
</span></span><span class="line"><span class="cl">  # Internal authentication provider configuration.
</span></span><span class="line"><span class="cl">  internal:
</span></span><span class="line"><span class="cl">    admin:
</span></span><span class="line"><span class="cl">      create: true
</span></span><span class="line"><span class="cl">    enabled: true
</span></span><span class="line"><span class="cl">    signup-enabled: true
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Disables analytics.
</span></span><span class="line"><span class="cl">analytics-opt-out: &#34;false&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Log level: debug|info|warn|error.
</span></span><span class="line"><span class="cl">log-level: &#34;info&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Log level: debug|info|warn|error.
</span></span><span class="line"><span class="cl">badger-log-level: &#34;error&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Directory where pyroscope stores profiling data.
</span></span><span class="line"><span class="cl">storage-path: &#34;/var/lib/pyroscope&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Port for the HTTP server used for data ingestion and web UI.
</span></span><span class="line"><span class="cl">api-bind-addr: &#34;:4040&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Base URL for when the server is behind a reverse proxy with a different path.
</span></span><span class="line"><span class="cl">base-url: &#34;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Percentage of memory at which cache evictions start.
</span></span><span class="line"><span class="cl">cache-evict-threshold: &#34;0.25&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Percentage of cache that is evicted per eviction run.
</span></span><span class="line"><span class="cl">cache-evict-volume: &#34;0.33&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Database configuration. By default, Pyroscope Server uses embedded sqlite3 database.
</span></span><span class="line"><span class="cl">database:
</span></span><span class="line"><span class="cl">  # Indicates the database type. Supported DB engines: sqlite3.
</span></span><span class="line"><span class="cl">  type: &#34;sqlite3&#34;
</span></span><span class="line"><span class="cl">  # Database connection string. Specific to the engine.
</span></span><span class="line"><span class="cl">  url: &#34;/var/lib/pyroscope/pyroscope.db&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Indicates whether value log files should be truncated to delete corrupt data, if any.
</span></span><span class="line"><span class="cl">badger-no-truncate: &#34;false&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Disables /debug/pprof route.
</span></span><span class="line"><span class="cl">disable-pprof-endpoint: &#34;false&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Max number of nodes used when saving profiles to disk.
</span></span><span class="line"><span class="cl">max-nodes-serialization: &#34;2048&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Max number of nodes used to display data on the frontend.
</span></span><span class="line"><span class="cl">max-nodes-render: &#34;8192&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Please don&#39;t use, this will soon be deprecated.
</span></span><span class="line"><span class="cl">hide-applications: []
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Sets the maximum amount of time the profiling data is stored for. Data before this threshold is deleted. Disabled by default.
</span></span><span class="line"><span class="cl"># retention: &#34;0s&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">retention: &#34;480h&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Specifies how long the profiling data is stored per aggregation level. Disabled by default.
</span></span><span class="line"><span class="cl"># retention-levels: <span class="nb">{}</span>
</span></span><span class="line"><span class="cl"># 0: 720h  # 30 days
</span></span><span class="line"><span class="cl"># 1: 2160h # 90 days
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">retention-levels:
</span></span><span class="line"><span class="cl"> 0: 480h  # 20 days
</span></span><span class="line"><span class="cl"> 1: 1440h # 60 days
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Metrics export rules.
</span></span><span class="line"><span class="cl">metrics-export-rules: <span class="nb">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># A list of scrape configurations.
</span></span><span class="line"><span class="cl">scrape-configs: []
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Location of TLS Certificate file (.crt).
</span></span><span class="line"><span class="cl">tls-certificate-file: &#34;&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># Location of TLS Private key file (.key).
</span></span><span class="line"><span class="cl">tls-key-file: &#34;&#34;
</span></span></code></pre></td></tr></table>
</div>
</div></div>
        </div>
    </div>
<h3 id="start">
    <a href="#start" class="header-anchor" aria-label="Link to Start"></a>Start</h3>
<p><code>pyroscope server -config pyroscope-server.yml.yml</code></p>
<h2 id="using-the-go-agent">
    <a href="#using-the-go-agent" class="header-anchor" aria-label="Link to Using the Go agent"></a>Using the Go agent</h2>
<blockquote>
<p>Uses <code>Push</code> mode — simple and efficient.</p>
</blockquote>
<h3 id="import-the-dependency">
    <a href="#import-the-dependency" class="header-anchor" aria-label="Link to Import the dependency"></a>Import the dependency</h3>
<p><code>go get github.com/pyroscope-io/client/pyroscope</code></p>
<h3 id="agent-push-example">
    <a href="#agent-push-example" class="header-anchor" aria-label="Link to Agent Push example"></a>Agent Push example</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="s">&#34;github.com/pyroscope-io/client/pyroscope&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">pyroscope</span><span class="p">.</span><span class="nf">Start</span><span class="p">(</span><span class="nx">pyroscope</span><span class="p">.</span><span class="nx">Config</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">ApplicationName</span><span class="p">:</span> <span class="s">&#34;simple.golang.app&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// replace this with the address of pyroscope server
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">ServerAddress</span><span class="p">:</span>   <span class="s">&#34;http://pyroscope-server:4040&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// you can disable logging by setting this to nil
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">Logger</span><span class="p">:</span>          <span class="nx">pyroscope</span><span class="p">.</span><span class="nx">StandardLogger</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// optionally, if authentication is enabled, specify the API key:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// AuthToken: os.Getenv(&#34;PYROSCOPE_AUTH_TOKEN&#34;),
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="cl">    <span class="c1">// by default all profilers are enabled,
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="c1">// but you can select the ones you want to use:
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">ProfileTypes</span><span class="p">:</span> <span class="p">[]</span><span class="nx">pyroscope</span><span class="p">.</span><span class="nx">ProfileType</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pyroscope</span><span class="p">.</span><span class="nx">ProfileCPU</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pyroscope</span><span class="p">.</span><span class="nx">ProfileAllocObjects</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pyroscope</span><span class="p">.</span><span class="nx">ProfileAllocSpace</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pyroscope</span><span class="p">.</span><span class="nx">ProfileInuseObjects</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">pyroscope</span><span class="p">.</span><span class="nx">ProfileInuseSpace</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="p">})</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="c1">// your code goes here
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="authentication">
    <a href="#authentication" class="header-anchor" aria-label="Link to Authentication"></a>Authentication</h2>
<blockquote>
<p>Default username/password: <code>admin</code>:<code>admin</code></p>
</blockquote>
<ul>
<li><a href="https://pyroscope.io/docs/api-key-authentication/" target="_blank" rel="noopener noreffer ">api-key-authentication</a></li>
<li><a href="https://pyroscope.io/docs/auth-internal" target="_blank" rel="noopener noreffer ">Internal authentication</a></li>
</ul>
<p><code>pyroscope admin user reset-password --username {admin-username} --password {new-password}</code></p>
<h2 id="query--export">
    <a href="#query--export" class="header-anchor" aria-label="Link to Query &amp; export"></a>Query &amp; export</h2>
<ul>
<li><a href="https://pyroscope.io/docs/grafana-plugins/" target="_blank" rel="noopener noreffer ">grafana</a> <a href="https://pyroscope.io/docs/api-key-authentication/" target="_blank" rel="noopener noreffer ">config</a></li>
<li><a href="https://pyroscope.io/docs/server-api-reference/" target="_blank" rel="noopener noreffer ">API</a></li>
<li><strong>UI operations</strong>
<ul>
<li><code>png</code></li>
<li><code>json</code></li>
<li><code>pprof</code></li>
<li><code>html</code></li>
<li><code>flamegraph.com</code></li>
</ul>
</li>
</ul>
<p><figure><figcaption class="image-caption">proscope server table flamegraph</figcaption>
    </figure></p>
<h2 id="references">
    <a href="#references" class="header-anchor" aria-label="Link to References"></a>References</h2>
<ul>
<li><a href="https://pyroscope.io/docs/" target="_blank" rel="noopener noreffer ">pyroscope docs</a></li>
<li><a href="https://github.com/pyroscope-io/pyroscope" target="_blank" rel="noopener noreffer ">pyroscope-io</a></li>
</ul>]]></description></item><item><title>Common kill Signals and How to Catch Them in Go</title><link>https://blog.xwi88.com/en/go-kill-signal-catch/</link><pubDate>Wed, 16 Mar 2022 01:30:10 +0800</pubDate><author>xwi88</author><guid>https://blog.xwi88.com/en/go-kill-signal-catch/</guid><description><![CDATA[<p>Common kill signals for Go programs and how to catch them. Verified on <em>MacOS</em>, based on <code>go1.17.7</code>.</p>
<blockquote>
<p><strong>Copyright notice</strong>: This is an original article by <strong><a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">xwi88</a></strong>, licensed under <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener noreffer ">CC BY-NC 4.0</a>. Commercial use is prohibited; please cite the source when reposting. Follow at <a href="https://github.com/xwi88" target="_blank" rel="noopener noreffer ">https://github.com/xwi88</a></p>
</blockquote>
<h2 id="common-signals">
    <a href="#common-signals" class="header-anchor" aria-label="Link to Common signals"></a>Common signals</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-tex" data-lang="tex"><span class="line"><span class="cl">Some of the more commonly used signals:
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> 1       HUP (hang up)
</span></span><span class="line"><span class="cl"> 2       INT (interrupt)
</span></span><span class="line"><span class="cl"> 3       QUIT (quit)
</span></span><span class="line"><span class="cl"> 6       ABRT (abort)
</span></span><span class="line"><span class="cl"> 9       KILL (non-catchable, non-ignorable kill)
</span></span><span class="line"><span class="cl"> 14      ALRM (alarm clock)
</span></span><span class="line"><span class="cl"> 15      TERM (software termination signal)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> 30      USR1 (user defined signal 1)
</span></span><span class="line"><span class="cl"> 31      USR2 (user defined signal 2)
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="go-code">
    <a href="#go-code" class="header-anchor" aria-label="Link to Go Code"></a>Go Code</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="nx">done</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="kd">struct</span><span class="p">{})</span>
</span></span><span class="line"><span class="cl"><span class="nx">ch</span> <span class="o">:=</span> <span class="nb">make</span><span class="p">(</span><span class="kd">chan</span> <span class="nx">os</span><span class="p">.</span><span class="nx">Signal</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="nx">signal</span><span class="p">.</span><span class="nf">Notify</span><span class="p">(</span><span class="nx">ch</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGHUP</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGQUIT</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGABRT</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGKILL</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGALRM</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGUSR1</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGUSR2</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGTERM</span><span class="p">,</span> <span class="nx">syscall</span><span class="p">.</span><span class="nx">SIGINT</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">sgName</span> <span class="o">:=</span> <span class="o">&lt;-</span><span class="nx">ch</span>
</span></span><span class="line"><span class="cl">    <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">&#34;receive kill signal [%v], ready to exit ...&#34;</span><span class="p">,</span> <span class="nx">sgName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// resource release and other deals
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="nx">done</span> <span class="o">&lt;-</span> <span class="kd">struct</span><span class="p">{}{}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="o">&lt;-</span><span class="nx">done</span>
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p>For a more convenient wrapper, see <a href="https://github.com/love-wheel/signal" target="_blank" rel="noopener noreffer ">signal</a></p>
</blockquote>
<h2 id="kill-testing">
    <a href="#kill-testing" class="header-anchor" aria-label="Link to kill testing"></a>kill testing</h2>
<blockquote>
<p>Run <code>kill</code> on the host to stop the <code>app</code>. There are two runtime environments: <strong>host</strong> and <strong>docker</strong>.</p>
</blockquote>
<h3 id="host">
    <a href="#host" class="header-anchor" aria-label="Link to Host"></a>Host</h3>
<p><code>kill -&lt;signal_number | signal_name&gt; &lt;pid&gt;</code></p>
<div class="details admonition tip open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-lightbulb fa-fw" aria-hidden="true"></i>Tip<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content">linux/unix <code>kill</code> defaults to <code>signal_number=15</code> <strong>TERM</strong></div>
        </div>
    </div>
<p>Tested — <strong>signals that can be caught normally and return 0</strong>:</p>
<ul>
<li><code>1, 2, 3, 6, 14, 15</code>, <strong><code>30, 31</code></strong></li>
<li><code>HUP, INT, QUIT, ABRT, ALRM, TERM, USR1, USR2</code>
<ul>
<li><strong>case-insensitive</strong></li>
<li><strong><code>SIG</code> prefix allowed</strong>, also <strong>case-insensitive</strong></li>
</ul>
</li>
</ul>
<h3 id="docker">
    <a href="#docker" class="header-anchor" aria-label="Link to docker"></a>docker</h3>
<blockquote>
<p><code>docker kill -&lt;signal_number | signal_name&gt; &lt;container_id&gt;</code></p>
</blockquote>
<div class="details admonition tip open">
        <div class="details-summary admonition-title">
            <i class="icon fas fa-lightbulb fa-fw" aria-hidden="true"></i>Tip<i class="details-icon fas fa-angle-right fa-fw" aria-hidden="true"></i>
        </div>
        <div class="details-content">
            <div class="admonition-content"><code>docker kill</code> defaults to <code>signal_number=9</code> <strong>KILL</strong></div>
        </div>
    </div>
<p>Tested — <strong>signals that can be caught normally and return 0</strong>:</p>
<ul>
<li><code>1, 2, 3, 6, 14, 15</code>, <strong><code>10, 12</code></strong>
<ul>
<li><strong>In testing, <code>docker kill</code> only recognizes <code>10</code> and <code>12</code> as <code>USR1</code> and <code>USR2</code></strong></li>
<li>Reason unclear; <strong><code>USR1</code> / <code>USR2</code> not recommended</strong></li>
</ul>
</li>
<li><code>HUP, INT, QUIT, ABRT, ALRM, TERM, USR1, USR2</code>
<ul>
<li><strong>case-insensitive</strong></li>
<li><strong><code>SIG</code> prefix allowed</strong>, also <strong>case-insensitive</strong></li>
</ul>
</li>
</ul>
<h2 id="conclusion">
    <a href="#conclusion" class="header-anchor" aria-label="Link to Conclusion"></a>Conclusion</h2>
<blockquote>
<p>From the tests above, the <strong>commonly catchable, no-difference, return-0 signals</strong> are: <code>1, 2, 3, 6, 14, 15</code></p>
</blockquote>
<p>By signal semantics, we recommend using:</p>
<ul>
<li>2 <strong>SIGINT</strong> — trigger: <code>CTRL+C</code> or <code>kill -2</code></li>
<li>15 <strong>SIGTERM</strong></li>
</ul>
<h2 id="graceful-shutdown">
    <a href="#graceful-shutdown" class="header-anchor" aria-label="Link to Graceful shutdown"></a>Graceful shutdown</h2>
<ol>
<li>Send <code>kill</code> with <code>-15/-TERM/-SIGTERM</code></li>
<li>After the program catches the signal: <strong>remove the node from discovery</strong>, <strong>release resources</strong>, <em>stop the program</em></li>
<li>After a configured interval, check whether it stopped; if not, fall back to <code>kill -9/-KILL/-SIGKILL</code> per your policy</li>
</ol>
<h2 id="k8s-graceful-shutdown">
    <a href="#k8s-graceful-shutdown" class="header-anchor" aria-label="Link to k8s graceful shutdown"></a>k8s graceful shutdown</h2>
<ol>
<li><strong>Remove the node</strong></li>
<li><code>preStop hook</code> <em>optional delay, to drain in-flight traffic</em></li>
<li>Send <code>kill</code> with <code>-15/-TERM/-SIGTERM</code></li>
<li>The program catches the signal, <strong>releases resources</strong>, <em>stops</em></li>
<li>Force-killed on timeout via <code>kill -9/-KILL/-SIGKILL</code>
<ul>
<li>default 30s</li>
<li>pod: <code>terminationGracePeriodSeconds</code> to change it</li>
</ul>
</li>
</ol>
<h2 id="docker-compose-kill-issue">
    <a href="#docker-compose-kill-issue" class="header-anchor" aria-label="Link to Docker-compose kill issue"></a>Docker-compose kill issue</h2>
<ul>
<li>Current <code>Docker Compose version 2.2.2</code></li>
</ul>
<p><code>docker-compose</code> may fail to stop on <code>CTRL+C</code>; force quit with <code>CTRL+\</code></p>]]></description></item><item><title>gvm: Go Version Manager</title><link>https://blog.xwi88.com/en/go-vcs-gvm/</link><pubDate>Tue, 08 Mar 2022 08:09:41 +0800</pubDate><author>xwi88</author><guid>https://blog.xwi88.com/en/go-vcs-gvm/</guid><description><![CDATA[<p><strong>gvm</strong> is a CLI tool for <strong>Linux</strong>, <strong>MacOS</strong> and <strong>Windows</strong> — similar to <strong>nvm</strong> / <em>anaconda</em> — that lets you conveniently manage and switch between multiple <strong>go</strong> environments. Highly recommended.</p>
<h2 id="installation">
    <a href="#installation" class="header-anchor" aria-label="Link to Installation"></a>Installation</h2>
<h3 id="mac-os-x-requirements">
    <a href="#mac-os-x-requirements" class="header-anchor" aria-label="Link to Mac OS X Requirements"></a>Mac OS X Requirements</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Mac OS X Requirements</span>
</span></span><span class="line"><span class="cl">xcode-select --install
</span></span><span class="line"><span class="cl">brew update
</span></span><span class="line"><span class="cl">brew install mercurial
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="install-gvm">
    <a href="#install-gvm" class="header-anchor" aria-label="Link to Install gvm"></a>Install gvm</h3>
<blockquote>
<p><a href="https://github.com/moovweb/gvm" target="_blank" rel="noopener noreffer ">gvm</a></p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># zsh</span>
</span></span><span class="line"><span class="cl">zsh &lt; &lt;<span class="o">(</span>curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer<span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># bash use, choose one!</span>
</span></span><span class="line"><span class="cl"><span class="c1"># bash &lt; &lt;(curl -s -S -L https://raw.githubusercontent.com/moovweb/gvm/master/binscripts/gvm-installer)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p>On success, a hidden <strong>.gvm</strong> directory is created under your home folder, and the following line is appended to the bottom of your <em>.bashrc</em> or <em>.zshrc</em>:</p>
</blockquote>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">[[ -s &#34;$HOME/.gvm/scripts/gvm&#34; ]] &amp;&amp; source &#34;$HOME/.gvm/scripts/gvm&#34;
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># shall set GO_SOURCE_URL to speed binary install
</span></span><span class="line"><span class="cl">export GO_SOURCE_URL=https://github.com/golang/go
</span></span></code></pre></td></tr></table>
</div>
</div><blockquote>
<p>To support multiple shells at the same time, copy the snippet above into each shell&rsquo;s config file manually.</p>
</blockquote>
<h3 id="go-environment-config">
    <a href="#go-environment-config" class="header-anchor" aria-label="Link to Go environment config"></a>Go environment config</h3>
<p>Switching go versions with <code>gvm use &lt;version&gt;</code> changes several environment variables, such as:</p>
<ul>
<li><code>GOMODCACHE=&quot;$HOME/.gvm/pkgsets/go1.17.7/global/pkg/mod&quot;</code></li>
<li><code>GOPATH=&quot;$HOME/.gvm/pkgsets/go1.17.7/global&quot;</code></li>
</ul>
<p>The related gvm commands are: <code>linkthis</code>, <code>pkgset</code>, <code>pkgenv</code>. To reduce the impact of these env changes on development, you can pin <code>GOPATH</code> and friends:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># shall set GO_SOURCE_URL to speed source install</span>
</span></span><span class="line"><span class="cl"><span class="c1"># default https://go.googlesource.com/go</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GO_SOURCE_URL</span><span class="o">=</span>https://github.com/golang/go
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># if use gvm, shall set some go env after gvm init statements</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># export GO111MODULE=on</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GOPATH</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/go&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GOBIN</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$GOPATH</span><span class="s2">/bin&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$GOBIN</span><span class="s2">:</span><span class="nv">$PATH</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl"><span class="nb">export</span> <span class="nv">GOPROXY</span><span class="o">=</span>https://goproxy.cn,https://goproxy.io/,https://mirrors.aliyun.com/goproxy/,https://gocenter.io/,https://proxy.golang.org,direct
</span></span></code></pre></td></tr></table>
</div>
</div><h2 id="gvm-usage">
    <a href="#gvm-usage" class="header-anchor" aria-label="Link to gvm usage"></a><strong>gvm</strong> usage</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Usage: gvm <span class="o">[</span>command<span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Description:
</span></span><span class="line"><span class="cl">  GVM is the Go Version Manager
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Commands:
</span></span><span class="line"><span class="cl">  version    - print the gvm version number
</span></span><span class="line"><span class="cl">  get        - gets the latest code <span class="o">(</span><span class="k">for</span> debugging<span class="o">)</span>
</span></span><span class="line"><span class="cl">  use        - <span class="k">select</span> a go version to use <span class="o">(</span>--default to <span class="nb">set</span> permanently<span class="o">)</span>
</span></span><span class="line"><span class="cl">  diff       - view changes to Go root
</span></span><span class="line"><span class="cl">  <span class="nb">help</span>       - display this usage text
</span></span><span class="line"><span class="cl">  implode    - completely remove gvm
</span></span><span class="line"><span class="cl">  install    - install go versions
</span></span><span class="line"><span class="cl">  uninstall  - uninstall go versions
</span></span><span class="line"><span class="cl">  cross      - install go cross compilers
</span></span><span class="line"><span class="cl">  linkthis   - link this directory into GOPATH
</span></span><span class="line"><span class="cl">  list       - list installed go versions
</span></span><span class="line"><span class="cl">  listall    - list available versions
</span></span><span class="line"><span class="cl">  <span class="nb">alias</span>      - manage go version aliases
</span></span><span class="line"><span class="cl">  pkgset     - manage go packages sets
</span></span><span class="line"><span class="cl">  pkgenv     - edit the environment <span class="k">for</span> a package <span class="nb">set</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="gvm-install">
    <a href="#gvm-install" class="header-anchor" aria-label="Link to gvm install"></a><strong>gvm install</strong></h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">Usage: gvm install <span class="o">[</span>version<span class="o">]</span> <span class="o">[</span>options<span class="o">]</span>
</span></span><span class="line"><span class="cl">    -s,  --source<span class="o">=</span>SOURCE      Install Go from specified source.
</span></span><span class="line"><span class="cl">    -n,  --name<span class="o">=</span>NAME          Override the default name <span class="k">for</span> this version.
</span></span><span class="line"><span class="cl">    -pb, --with-protobuf      Install Go protocol buffers.
</span></span><span class="line"><span class="cl">    -b,  --with-build-tools   Install package build tools.
</span></span><span class="line"><span class="cl">    -B,  --binary             Only install from binary.
</span></span><span class="line"><span class="cl">         --prefer-binary      Attempt a binary install, falling back to source.
</span></span><span class="line"><span class="cl">    -h,  --help               Display this message.
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="quick-start">
    <a href="#quick-start" class="header-anchor" aria-label="Link to Quick start"></a>Quick start</h3>
<blockquote>
<p><code>gvm use</code> <em>- select a go version to use (&ndash;default to set permanently)</em></p>
</blockquote>
<ul>
<li>gvm install go1.16.14 -B # if the machine has no go pre-installed</li>
<li>gvm install go1.17.7</li>
<li>gvm use go1.17.7 [&ndash;default]</li>
<li>gvm uninstall go1.17.7</li>
<li><em>gvm install go1.17.7 &ndash;source=https://xxx@github.com/xxx/go</em></li>
<li><em>gvm install go1.17.7 -s=https://godoc.org/golang.org/dl/go1.17.7</em></li>
<li><em>gvm implode</em> <strong>uninstall gvm</strong></li>
</ul>
<h2 id="example">
    <a href="#example" class="header-anchor" aria-label="Link to Example"></a>Example</h2>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># gvm list</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">gvm gos <span class="o">(</span>installed<span class="o">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   go1.16.14
</span></span><span class="line"><span class="cl"><span class="o">=</span>&gt; go1.17.7
</span></span><span class="line"><span class="cl">   go1.18rc1
</span></span><span class="line"><span class="cl">   system
</span></span></code></pre></td></tr></table>
</div>
</div>]]></description></item></channel></rss>