<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Posts on </title>
    <link>https://note.lican.site/posts/</link>
    <description>Recent content in Posts on </description>
    <generator>Hugo</generator>
    <language>en</language>
    <copyright>© lican.asia All rights reserved</copyright>
    <lastBuildDate>Fri, 28 Nov 2025 10:31:00 +0800</lastBuildDate>
    <atom:link href="https://note.lican.site/posts/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>UDP服务搭建</title>
      <link>https://note.lican.site/posts/udp%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Fri, 28 Nov 2025 10:31:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/udp%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;h3 id=&#34;udp服务搭建&#34;&gt;UDP服务搭建&lt;/h3&gt;&#xA;&lt;p&gt;背景：客户有个小的环控设备，给用户体验温度环境的，采用我们温湿度传感器采集的数据，但用户仅提供了一个UDP接收地址，要求我们将数据传递到该地址&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/udp/1764295263473.png&#34; alt=&#34;1764295263473&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;什么是udp&#34;&gt;什么是UDP&lt;/h4&gt;&#xA;&lt;p&gt;UDP是一种无连接，不可靠，轻量级传输协议，用于快速发送数据包，但不保证数据一定能送达，不保证顺序，也不进行重传&lt;/p&gt;&#xA;&lt;h4 id=&#34;特点&#34;&gt;特点&lt;/h4&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;特性&lt;/th&gt;&#xA;          &lt;th&gt;UDP&lt;/th&gt;&#xA;          &lt;th&gt;TCP&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;连接方式&lt;/td&gt;&#xA;          &lt;td&gt;无连接（直接发数据）&lt;/td&gt;&#xA;          &lt;td&gt;面向连接（先握手建立连接）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;可靠性&lt;/td&gt;&#xA;          &lt;td&gt;不可靠（不保证送达）&lt;/td&gt;&#xA;          &lt;td&gt;可靠（保证传达，有序，不丢包）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;数据顺序&lt;/td&gt;&#xA;          &lt;td&gt;不保证顺序&lt;/td&gt;&#xA;          &lt;td&gt;保证顺序&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;数据重传&lt;/td&gt;&#xA;          &lt;td&gt;不重传丢失的数据包&lt;/td&gt;&#xA;          &lt;td&gt;会重传丢失或出错的数据包&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;流量控制/拥塞控制&lt;/td&gt;&#xA;          &lt;td&gt;没有&lt;/td&gt;&#xA;          &lt;td&gt;有（防止网络拥堵）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;传输速度&lt;/td&gt;&#xA;          &lt;td&gt;快（开销小，延迟低）&lt;/td&gt;&#xA;          &lt;td&gt;相对慢（因为要保证可靠）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;头部大小&lt;/td&gt;&#xA;          &lt;td&gt;8字节（很小）&lt;/td&gt;&#xA;          &lt;td&gt;至少20字节（较大）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;应用场景&lt;/td&gt;&#xA;          &lt;td&gt;实时性要求高，允许少量丢包的场景&lt;/td&gt;&#xA;          &lt;td&gt;要求可靠传输的场景（如网页，文件）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h4 id=&#34;工作原理&#34;&gt;工作原理&lt;/h4&gt;&#xA;&lt;p&gt;1.不需要事先建立连接：发送方直接把数据打包成UDP的数据包，然后扔到网络上，目标地址写清楚就行&lt;/p&gt;&#xA;&lt;p&gt;2、数据包独立传输：每个UDP数据包都是独立的，可能会走不同的路径，也可能丢失，乱序&lt;/p&gt;&#xA;&lt;p&gt;3、不关心对方是否收到：发出去就不管了，不会确认，不会重发，不会排序&lt;/p&gt;&#xA;&lt;p&gt;4.适合快速发送：因为没有复杂的控制机制，所以速度快，开销小，实时性强&lt;/p&gt;&#xA;&lt;h4 id=&#34;实现&#34;&gt;实现&lt;/h4&gt;&#xA;&lt;p&gt;在golang中依靠的是net&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NewUDPSender&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;serverAddr&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;UDPSender&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;udpAddr&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;net&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResolveUDPAddr&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;serverAddr&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;net&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DialUDP&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;udp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;udpAddr&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;UDPSender&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;addr&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;udpAddr&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;UDPSender&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Send&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unlock&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Write&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;UDPSender&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;调用：搭建好udp服务后，在需要发送udp数据的地方调用即可&lt;/p&gt;</description>
    </item>
    <item>
      <title>串口服务搭建</title>
      <link>https://note.lican.site/posts/%E4%B8%B2%E5%8F%A3%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Mon, 24 Nov 2025 14:43:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E4%B8%B2%E5%8F%A3%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;h3 id=&#34;串口服务搭建&#34;&gt;串口服务搭建&lt;/h3&gt;&#xA;&lt;p&gt;背景：由于客户方需要根据我们环境监测设备采集的温湿度来通过PLC设备调控模拟现场的温湿度，我们需要将采集的数据传递给PLC设备，客户方只能通过Modbus 232串口来接收数据，因此，我们需要在原服务的基础上搭建一套支持串口传递数据的服务【9针插卡连接的是2，3，5针】&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/serial/1763966932912.png&#34; alt=&#34;img&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;打开串口的参数&#34;&gt;打开串口的参数&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SerialConf&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;IsOpenSerial&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;is_open_serial&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 是否打开串口【串口开关】&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;PortName&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;   &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;port_name&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 串口【windows中的COM1 -&amp;gt; Linux中ttys0】&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;BaudRate&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;baud_rate&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 波特率【一般为9600】&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;DataBits&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;data_bits&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 数据位，每个字节包含的数据位数，通常8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;StopBits&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;stop_bits&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 停止位，每个字节的停止位数，通常为1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Parity&lt;/span&gt;         &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;   &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;parity&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 校验位，常见值none(无校验)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadTimeout&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;read_timeout&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 读取超时时间&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteTimeout&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;write_timeout&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 写入超时时间&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;SimulateMode&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;     &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;simulate_mode&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 调试模式，若为false表示不真正打开串口&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;AllowedClients&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;allowed_clients&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 允许访问的客户端列表&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;APIKey&lt;/span&gt;         &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;   &lt;span style=&#34;color:#e6db74&#34;&gt;`mapstructure:&amp;#34;api_key&amp;#34;`&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// api访问秘钥&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;step1: 开启串口&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NewSerialBus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SerialConf&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SerialBus&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 检查是否启用模拟模式&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IsOpenSerial&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;serial service is not open&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SerialBusImpl&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;isOpen&lt;/span&gt;:   &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;simulate&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;serialConfig&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;serial&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Config&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;:        &lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PortName&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Baud&lt;/span&gt;:        &lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;BaudRate&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Size&lt;/span&gt;:        byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DataBits&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;StopBits&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;serial&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StopBits&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StopBits&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Parity&lt;/span&gt;:      &lt;span style=&#34;color:#a6e22e&#34;&gt;serial&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Parity&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Parity&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadTimeout&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadTimeout&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;port&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;serial&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;OpenPort&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;serialConfig&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;failed to open serial port&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Any&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;err: &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;警告: 无法打开串口 %s: %v，使用模拟模式&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PortName&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SerialBusImpl&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;isOpen&lt;/span&gt;:   &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;simulate&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;:   &lt;span style=&#34;color:#a6e22e&#34;&gt;serialConfig&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;serial port open success&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Any&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;port: &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PortName&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;成功打开串口: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PortName&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SerialBusImpl&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;port&lt;/span&gt;:   &lt;span style=&#34;color:#a6e22e&#34;&gt;port&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;serialConfig&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;isOpen&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;step2: 创建监听器&lt;/p&gt;</description>
    </item>
    <item>
      <title>Mqtt服务搭建</title>
      <link>https://note.lican.site/posts/mqtt%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Wed, 27 Aug 2025 15:10:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/mqtt%E6%9C%8D%E5%8A%A1%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;h3 id=&#34;mqtt服务搭建&#34;&gt;Mqtt服务搭建&lt;/h3&gt;&#xA;&lt;p&gt;背景：物联网项目中， 很多时候要求设备与后台实现双向通信，因为设备时常处于内网或离线，此时Mqtt就派上用场了&lt;/p&gt;&#xA;&lt;p&gt;实现原理：emqx作为消息中间件，连接后台和设备的发布和订阅端，后台发布某个topic的消息，设备订阅某个topic的消息。后台也可以订阅某个topic的消息，设备也可以发布某个topic的消息，topic作为点对点的消息通道&lt;/p&gt;&#xA;&lt;p&gt;示例：一台云服务器向六台mini服务器发送采样指令，同时订阅六台mini服务器上报的数据&lt;/p&gt;&#xA;&lt;p&gt;Step1:我们在云服务器上使用docker-compose搭建emqx服务【我们使用的是5.0.26版本】&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;docker-compose.yaml&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.7&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;emqx&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;emqx:5.0.26&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;emqx&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EMQX_CLUSTER__DISCOVERY_STRATEGY=static&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EMQX_CLUSTER__STATIC__SEEDS=[emqx@node1.emqx.io,emqx@node2.emqx.io]&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;healthcheck&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;test&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CMD&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/opt/emqx/bin/emqx_ctl&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;status&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;interval&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5s&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;timeout&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;25s&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;retries&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8083:8083&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8084:8084&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8883:8883&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;18083:18083&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1883:1883&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;18081:8081&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;www&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2M&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 单个文件大小为200k&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 最多10个文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;www&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;external&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后执行docker-compose up -d 就搭建好了【默认账号密码：admin/public】&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/mqtt/1756274462852.png&#34; alt=&#34;1756274462852&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;ip:18083是emqx管理端的页面&lt;/p&gt;&#xA;&lt;p&gt;ip:1883是emqx的mqtt的连接地址&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/mqtt/1756274569757.png&#34; alt=&#34;1756274569757&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Step2: 设置客户端连接的账号密码已经秘钥&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;由于mqtt连接需要使用账号密码，所以需要设置【在侧边栏选择 客户端认证-内置数据库-用户管理-点击+】&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/mqtt/1756274725015.png&#34; alt=&#34;1756274725015&#34;&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;mqtt虽然是长连接，但由于某些情况，例如设备网络波动，连接超时等原因导致设备未能连上mqtt，后台发布的topic需要客户端在线才能订阅到，因此需要创建秘钥，在下发指令时，先判断客户端是否在线&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/mqtt/1756275010425.png&#34; alt=&#34;1756275010425&#34;&gt;&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;示例代码&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;wqc&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;WaterQualityConfig&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;CheckWaterDeviceConnect&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ClientID&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;Connected&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ip&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Common&lt;/span&gt;{}.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetLocalIP&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ip&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:18083/api/v5/clients/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ClientID&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 用户名和密码&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Secret&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 拼接 Basic Auth&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;auth&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;basicAuth&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Basic &amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;base64&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StdEncoding&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EncodeToString&lt;/span&gt;([]byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;auth&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;req&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewRequest&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 添加 Authorization 头&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;req&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Header&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Authorization&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;basicAuth&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CheckWaterDeviceConnect&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ClientID:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ClientID&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;url:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;logger&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;basicAuth:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;basicAuth&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 发起请求&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Client&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Do&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;req&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;请求失败:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Body&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 根据 HTTP 响应状态码判断设备是否在线&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusCode&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusOK&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;// 200&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 设备在线，API 返回了客户端信息&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ioutil&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadAll&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Body&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;设备在线，响应内容:&amp;#34;&lt;/span&gt;, string(&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusCode&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusNotFound&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;// 404&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 设备不在线&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;设备不在线（未找到）:&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ClientID&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 其它状态码，比如 401（未授权）、500 等&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ioutil&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadAll&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Body&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;查询设备状态失败，状态码: %d, 响应: %s\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusCode&lt;/span&gt;, string(&lt;span style=&#34;color:#a6e22e&#34;&gt;body&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Step3: 在项目中配置mqtt的发布和订阅参数&lt;/p&gt;</description>
    </item>
    <item>
      <title>K8s安装</title>
      <link>https://note.lican.site/posts/k8s%E5%AE%89%E8%A3%85/</link>
      <pubDate>Mon, 24 Mar 2025 16:08:18 +0800</pubDate>
      <guid>https://note.lican.site/posts/k8s%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h3 id=&#34;k8s安装&#34;&gt;k8s安装&lt;/h3&gt;&#xA;&lt;p&gt;背景：和docker-compose一样，k8s也是容器编排工具，但k8s是一个更复杂的容器编排系统，用于管理大规模的容器化应用。&lt;/p&gt;&#xA;&lt;p&gt;核心定位&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;维度&lt;/th&gt;&#xA;          &lt;th&gt;Docker Compose&lt;/th&gt;&#xA;          &lt;th&gt;Kubernetes&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;目标场景&lt;/td&gt;&#xA;          &lt;td&gt;单机开发，测试环境(单节点)&lt;/td&gt;&#xA;          &lt;td&gt;生产多节点集群，大规模分布式应用&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;功能定位&lt;/td&gt;&#xA;          &lt;td&gt;定义和运行多容器应用(开发友好)&lt;/td&gt;&#xA;          &lt;td&gt;容器编排，集群管理，自动化运维&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;学习曲线&lt;/td&gt;&#xA;          &lt;td&gt;简单(YAML语法直观)&lt;/td&gt;&#xA;          &lt;td&gt;陡峭(需掌握Pod, Service, Ingress等核心概念)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;核心功能对比&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;功能&lt;/th&gt;&#xA;          &lt;th&gt;Docker Compose&lt;/th&gt;&#xA;          &lt;th&gt;Kubernetes&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;容器编排&lt;/td&gt;&#xA;          &lt;td&gt;单机多容器编排(通过docker-compose.yml)&lt;/td&gt;&#xA;          &lt;td&gt;跨节点容器编排(支持回滚更新，回滚，副本管理)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;扩展性&lt;/td&gt;&#xA;          &lt;td&gt;仅单机扩展(依赖宿主机资源)&lt;/td&gt;&#xA;          &lt;td&gt;动态扩缩容(HPA), 多接点集群自动调度&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;高可用性&lt;/td&gt;&#xA;          &lt;td&gt;不支持(单点故障风险)&lt;/td&gt;&#xA;          &lt;td&gt;支持(Pod自动重启，节点故障转移)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;网络管理&lt;/td&gt;&#xA;          &lt;td&gt;简单容器间网络(自定义网络)&lt;/td&gt;&#xA;          &lt;td&gt;复杂网络策略(NetworkPolicy, Service发现)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;存储管理&lt;/td&gt;&#xA;          &lt;td&gt;本地卷或命名卷&lt;/td&gt;&#xA;          &lt;td&gt;动态卷供应(PV/PVC),支持云存储和分布式存储&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;负载均衡&lt;/td&gt;&#xA;          &lt;td&gt;无内置负载均衡&lt;/td&gt;&#xA;          &lt;td&gt;Service和Ingress支持负载均衡&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;监控与日志&lt;/td&gt;&#xA;          &lt;td&gt;依赖外部工具(如Prometheus+Grafana)&lt;/td&gt;&#xA;          &lt;td&gt;集成监控(Metrics Server)，日志聚合方案丰富&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;适用场景&lt;/p&gt;&#xA;&lt;p&gt;Docker Compose适用场景&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;本地开发环境：快速启动多个关联服务(如前端+后端+数据库)&lt;/li&gt;&#xA;&lt;li&gt;单机测试：验证多容器应用的交互逻辑&lt;/li&gt;&#xA;&lt;li&gt;简单项目部署：小型项目或原型验证&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Kubernetes适用场景&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;生产环境部署：需要高可用性，自动恢复，滚动更新&lt;/li&gt;&#xA;&lt;li&gt;大规模集群管理：跨多个节点动态调度容器&lt;/li&gt;&#xA;&lt;li&gt;微服务架构：服务发现，流量管理，金丝雀发布&lt;/li&gt;&#xA;&lt;li&gt;混合云/多云部署：统一管理跨云平台的容器&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;配置文件示例：&lt;/p&gt;&#xA;&lt;p&gt;Docker Compose（docker-compose.yml）&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.8&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;service&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;web&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;latest&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8080:80&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;db&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;postgres&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;volumns&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;db_data&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;postgresql&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;volumns&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;db_data&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Kubernetes（deployment.yaml + service.yaml）&lt;/p&gt;</description>
    </item>
    <item>
      <title>Grafana&#43;Loki搭建日志系统</title>
      <link>https://note.lican.site/posts/grafana&#43;loki%E6%90%AD%E5%BB%BA%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/</link>
      <pubDate>Tue, 18 Mar 2025 17:53:55 +0800</pubDate>
      <guid>https://note.lican.site/posts/grafana&#43;loki%E6%90%AD%E5%BB%BA%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/</guid>
      <description>&lt;h3 id=&#34;grafanaloki搭建日志系统&#34;&gt;Grafana+Loki搭建日志系统&lt;/h3&gt;&#xA;&lt;h3 id=&#34;背景-之前搭建过elasticsearchkibanafilebeat的日志系统由于日志存储的位置是动态的filebeat采集目录需要对应更换当执行dockerc-compose-downdocker-compose-up原容器id会变存储的目录也会变所以觉得实用性不大所以使用grafanaloki搭建日志系统将容器的日志推送到loki上然后使用grafana配置loki数据源即可&#34;&gt;背景： 之前搭建过elasticsearch+kibana+filebeat的日志系统，由于日志存储的位置是动态的，filebeat采集目录需要对应更换，当执行dockerc-compose down;docker-compose up;原容器ID会变，存储的目录也会变，所以觉得实用性不大。所以使用grafana+loki搭建日志系统，将容器的日志推送到loki上，然后使用grafana配置loki数据源即可~&lt;/h3&gt;&#xA;&lt;p&gt;1.构建docker-compose.yaml文件&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Loki&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;日志搜集&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;loki&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loki&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;2.4.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana_loki&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;depends_on&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;31000:3100&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loki&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loki&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JAEGER_AGENT_HOST&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JAEGER_ENDPOINT&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//tempo:14268/api/traces # send traces to Tempo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JAEGER_SAMPLER_TYPE&lt;/span&gt;=&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JAEGER_SAMPLER_PARAM&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Promtail&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;日志搜集&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;promtail&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;promtail&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;2.4.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana_promtail&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;promtail&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;promtail&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yaml&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;promtail&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yaml&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;: &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;=&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;promtail&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;config&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yaml&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Tempo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;日志追踪&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;1.2.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;: [&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-config.file=/etc/tempo.yaml&amp;#34;&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana_tempo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yaml&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yaml&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;14268:14268&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jaeger&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ingest&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3200:3200&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tempo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;55680&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;otlp&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grpc&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;55681&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;otlp&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9411&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;zipkin&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Grafana&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;界面查看&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;8.2.6&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;30000:3000&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;share&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;always&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Prometheus&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;指标监控&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;prometheus&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;prom&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;prometheus&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.31.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;prometheus&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9090:9090&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;站点监控&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;blackbox&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exporter&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;prom&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;blackbox&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exporter&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;v0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.19.0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;blackbox_exporter&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9115:9115&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;./blackbox_exporter/config.yml:/etc/blackbox_exporter/config.yml&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;系统监控&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;node_exporter&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;prom&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;node&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;exporter&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.3.1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;node_exporter&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;--path.rootfs=/host&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;network_mode&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;pid&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;unless&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;stopped&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/:/host:ro,rslave&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;grafana&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;external&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动时，某些容器会失败，原因是配置文件没加载，针对上述容器，我们列举配置文件&lt;/p&gt;</description>
    </item>
    <item>
      <title>搭建多服务器管理工具Portainer</title>
      <link>https://note.lican.site/posts/%E6%90%AD%E5%BB%BA%E5%A4%9A%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7portainer/</link>
      <pubDate>Mon, 17 Mar 2025 10:58:35 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E6%90%AD%E5%BB%BA%E5%A4%9A%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7portainer/</guid>
      <description>&lt;h3 id=&#34;搭建多服务器管理工具portainer&#34;&gt;搭建多服务器管理工具Portainer&lt;/h3&gt;&#xA;&lt;p&gt;背景：我们有很多mini服务器【工业服务器】里面部署了很多容器，想找一款可以集中管理这些容器的工具，于是找到了Portainer&lt;/p&gt;&#xA;&lt;p&gt;1.安装Partainer&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;docker run -d -p 9000:9000 &amp;ndash;name portainer     &amp;ndash;restart always     -v /var/run/docker.sock:/var/run/docker.sock     portainer/portainer-ce&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;2.启动之后，执行docker ps | grep portainer, 查看运行状态&lt;img src=&#34;https://www.lican.asia/images/portainer/1741741989295.png&#34; alt=&#34;1741741989295&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;3.浏览器中访问ip:9000端口，即可打开portainer界面&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742118236.png&#34; alt=&#34;1741742118236&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;4.点击侧边栏的SETTINGS能看到本地的docker环境&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742207626.png&#34; alt=&#34;1741742207626&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;5.可以查看并操作对应的容器&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742244033.png&#34; alt=&#34;1741742244033&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742259964.png&#34; alt=&#34;1741742259964&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;6.添加/管理其它服务器的docker容器&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;点击侧边栏的Environments-&amp;gt;Add environment&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742349874.png&#34; alt=&#34;1741742349874&#34;&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;选择docker tab栏，添加配置&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742783532.png&#34; alt=&#34;1741742783532&#34;&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;添加时，可能提示 Failure&#xA;Cannot connect to the Dockerdaemon at&#xA;tcp://xxx:2375. ls thedocker daemon running?&lt;/p&gt;&#xA;&lt;p&gt;此时需要修改docker的配置，开启docker的tcp://ip:2375服务&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741742945997.png&#34; alt=&#34;1741742945997&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;修改docker.service&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vim&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;systemd&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;system&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;添加以下配置&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tcp&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//0.0.0.0:2375 -H unix:///var/run/docker.sock&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741743171824.png&#34; alt=&#34;1741743171824&#34;&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;赋予docker.service权限&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;chmod&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;systemd&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;system&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;service&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;重启docker&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;systemctl&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;daemon&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;reload&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;systemctl&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;然后点击添加&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/portainer/1741845871185.png&#34; alt=&#34;1741845871185&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>windows/linux使用ollama搭建ai模型</title>
      <link>https://note.lican.site/posts/windows%E6%9C%AC%E5%9C%B0%E4%BD%BF%E7%94%A8ollama%E6%90%AD%E5%BB%BAai%E6%A8%A1%E5%9E%8B/</link>
      <pubDate>Tue, 11 Mar 2025 10:47:23 +0800</pubDate>
      <guid>https://note.lican.site/posts/windows%E6%9C%AC%E5%9C%B0%E4%BD%BF%E7%94%A8ollama%E6%90%AD%E5%BB%BAai%E6%A8%A1%E5%9E%8B/</guid>
      <description>&lt;h3 id=&#34;windowslinux使用ollama搭建ai模型&#34;&gt;windows/linux使用ollama搭建ai模型&lt;/h3&gt;&#xA;&lt;p&gt;背景：最近看到朋友圈挺多朋友私有化部署了ai模型，感觉挺6的，决定跟一波风，学习一下本地部署&lt;/p&gt;&#xA;&lt;p&gt;首先，我们需要安装模型载体，这里我们选用&lt;a href=&#34;https://ollama.com/&#34;&gt;ollama&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;1.访问&lt;a href=&#34;https://ollama.com/&#34;&gt;ollama&lt;/a&gt;官网，下载安装包Ollama.Setup&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;windows版本直接下载安装包，双击安装&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741328919736.png&#34; alt=&#34;1741328919736&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;linux版本官网上安装的指令是 &lt;code&gt;curl -fsSL https://ollama.com/install.sh | sh&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;下载速度急慢，有兴趣的朋友可以了解一下&lt;/p&gt;&#xA;&lt;p&gt;于是在网上找到一个解决方案，亲测有效&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;下载ollama_install&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sh并保存&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;curl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fsSL&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;https&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//ollama.com/install.sh -o ollama_install.sh&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;使用github文件加速替换github下载地址&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sed&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;|&lt;span style=&#34;color:#a6e22e&#34;&gt;https&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//ollama.com/download/ollama-linux|https://gh.llkk.cc/https://github.com/ollama/ollama/releases/download/v0.5.7/ollama-linux|g&amp;#39; ollama_install.sh&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;替换后增加可执行权限&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;chmod&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ollama_install&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sh&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;执行sh下载安装&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sh&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ollama_install&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;sh&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;2.安装后，可查看版本&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741328976483.png&#34; alt=&#34;1741328976483&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;3.选择合适的模型，我选择网友们推荐的qwen2【说是对中文支持比较好】&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741329083246.png&#34; alt=&#34;1741329083246&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;4.安装模型【windows和linux操作一样】&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ollama&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;qwen2&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741337644929.png&#34; alt=&#34;1741337644929&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;安装完成之后就可以直接对话了&lt;/p&gt;&#xA;&lt;p&gt;7.07B的参数【1B=10亿】，会占用大量的系统资源&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741337915392.png&#34; alt=&#34;1741337915392&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741337952986.png&#34; alt=&#34;1741337952986&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;5.使用open-webui搭建可视化界面&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;使用docker搭建比较方便&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;使用docker搭建【换过快速地址】&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6000&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;add&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;internal&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gateway&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ghcr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;nju&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;edu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;使用docker-compose搭建&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3.8&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;ghcr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;nju&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;edu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3000:8080&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;extra_hosts&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;host.docker.internal:host-gateway&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;app&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;backend&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;webui&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我用docker-compose搭建&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741338249077.png&#34; alt=&#34;1741338249077&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;安装完成之后，可以实用本地ip:3000端口访问，也可以配置nginx转发，使用域名访问&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/webui/1741660941546.png&#34; alt=&#34;1741660941546&#34;&gt;&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;webui.conf&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;将此处替换为您的域名&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_certificate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/*&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fullchain&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_certificate_key&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/*&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_session_timeout&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_ciphers&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ECDHE&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;RSA&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AES128&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;GCM&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SHA256&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;ECDHE&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;ECDH&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;AES&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;HIGH&lt;/span&gt;:!&lt;span style=&#34;color:#a6e22e&#34;&gt;NULL&lt;/span&gt;:!&lt;span style=&#34;color:#a6e22e&#34;&gt;aNULL&lt;/span&gt;:!&lt;span style=&#34;color:#a6e22e&#34;&gt;MD5&lt;/span&gt;:!&lt;span style=&#34;color:#a6e22e&#34;&gt;ADH&lt;/span&gt;:!&lt;span style=&#34;color:#a6e22e&#34;&gt;RC4&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_protocols&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TLSv1&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TLSv1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.1&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TLSv1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.2&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_pass&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//127.0.0.1:6000;  # 将请求转发到 open-webui&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Host&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;保留主机头&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Real&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;IP&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;remote_addr&lt;/span&gt;;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;客户端&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Forwarded&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;For&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_add_x_forwarded_for&lt;/span&gt;;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;代理&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;IP&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Forwarded&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Proto&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;scheme&lt;/span&gt;;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;协议&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_http_version&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.1&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Upgrade&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http_upgrade&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Connection&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;upgrade&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于线上服务器配置不够，只有4核16G，不足以支撑需要的最低配置，在webui调用api/models接口503超时，导致页面无法正常打开，有资源且感兴趣的同学可以试试&lt;/p&gt;</description>
    </item>
    <item>
      <title>Linux服务器更换镜像源</title>
      <link>https://note.lican.site/posts/linux%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9B%B4%E6%8D%A2%E6%BA%90/</link>
      <pubDate>Wed, 20 Nov 2024 15:13:53 +0800</pubDate>
      <guid>https://note.lican.site/posts/linux%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9B%B4%E6%8D%A2%E6%BA%90/</guid>
      <description>&lt;h3 id=&#34;linux-服务器更换镜像源&#34;&gt;linux 服务器更换镜像源&lt;/h3&gt;&#xA;&lt;h5 id=&#34;背景&#34;&gt;背景&lt;/h5&gt;&#xA;&lt;p&gt;新买的centos服务器无法下载软件，提示&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Loading&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mirror&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;speeds&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cached&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hostfile&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Could&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;retrieve&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mirrorlist&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//mirrorlist.centos.org/?release=7&amp;amp;arch=x86_64&amp;amp;repo=os&amp;amp;infra=stock error was&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;curl&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;“&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Could&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;not&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;resolve&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;mirrorlist&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;centos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;org&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原因：是因为centos7在024年6月份停止维护，导致默认镜像不能使用，更改镜像即可&lt;/p&gt;&#xA;&lt;p&gt;步骤如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;step1:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mv&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CentOS&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Base&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CentOS&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Base&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;backup&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;step2:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;curl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;o&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CentOS&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Base&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;repo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//mirrors.aliyun.com/repo/Centos-7.repo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;step3:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;all&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;step4:&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makecache&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>搭建vpn</title>
      <link>https://note.lican.site/posts/%E6%90%AD%E5%BB%BAvpn/</link>
      <pubDate>Fri, 15 Nov 2024 10:40:23 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E6%90%AD%E5%BB%BAvpn/</guid>
      <description>&lt;h3 id=&#34;搭建vpn&#34;&gt;搭建vpn&lt;/h3&gt;&#xA;&lt;p&gt;作用：可以访问服务器的内网ip&lt;/p&gt;&#xA;&lt;p&gt;目的：仅用于学习&lt;/p&gt;&#xA;&lt;p&gt;操作对象：阿里云服务器&lt;/p&gt;&#xA;&lt;p&gt;服务器内网ip：172.18.120.176&lt;/p&gt;&#xA;&lt;p&gt;安装vpn之前：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731568658726.png&#34; alt=&#34;1731568658726&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;步骤一：&lt;/p&gt;&#xA;&lt;p&gt;在指定目录下创建docker-compose.yml文件和配置文件vpn.env&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731568802257.png&#34; alt=&#34;1731568802257&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;docker-compose.yml&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3.7&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;vpn&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;hwdsl2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ipsec&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vpn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;latest&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;vpn&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;udp&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4500&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;4500&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;udp&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;env_file&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vpn&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;env&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10M&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;privileged&lt;/span&gt;:  &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;vpn.env&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_IPSEC_PSK&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;LZsRCfAfG3c&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Y0X2&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;共享密钥&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_USER&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;nbi&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_PASSWORD&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;yBBWlm7xgjSqh5Ii&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_ADDL_USERS&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;lican&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xiaoming&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;多个用户空格分隔&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_ADDL_PASSWORDS&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;lican520&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xiaoming520&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;密码与账号对应&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_DNS_SRV1&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;114.114.114.114&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VPN_DNS_SRV2&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;8.8.8.8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;步骤二：&lt;/p&gt;&#xA;&lt;p&gt;启动docker-compose&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compose&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;up&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731572180933.png&#34; alt=&#34;1731572180933&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;步骤三：&lt;/p&gt;&#xA;&lt;p&gt;登录云服务器，修改安全组，配置500和4500端口，类型为udp&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731572259429.png&#34; alt=&#34;1731572259429&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;此时服务端的vpn已搭建完成&lt;/p&gt;&#xA;&lt;p&gt;步骤四：&lt;/p&gt;&#xA;&lt;p&gt;安装客户端，并配置&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.lican.asia/images/vpn/vpn-client-2.2.2-release.exe&#34;&gt;vpn-client-2.2.2-release.exe&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731577288327.png&#34; alt=&#34;1731577288327&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/hwdsl2/setup-ipsec-vpn/blob/master/docs/clients-xauth-zh.md&#34;&gt;配置详解&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731577400079.png&#34; alt=&#34;1731577400079&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;配置后使用vpn.env内配置的用户登录&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731577606956.png&#34; alt=&#34;1731577606956&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;成功之后就可以访问服务器的内网ip了&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/vpn/1731577653041.png&#34; alt=&#34;1731577653041&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>使用K6对接口进行压测</title>
      <link>https://note.lican.site/posts/%E4%BD%BF%E7%94%A8k6%E5%AF%B9%E6%8E%A5%E5%8F%A3%E5%8E%8B%E6%B5%8B/</link>
      <pubDate>Tue, 06 Aug 2024 17:40:12 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E4%BD%BF%E7%94%A8k6%E5%AF%B9%E6%8E%A5%E5%8F%A3%E5%8E%8B%E6%B5%8B/</guid>
      <description>&lt;h3 id=&#34;使用k6对接口进行压测&#34;&gt;使用K6对接口进行压测&lt;/h3&gt;&#xA;&lt;h3 id=&#34;背景&#34;&gt;背景&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;在实际开发中，常常需要对接口进行性能测试，因此，少不了压测工具&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在网上找了几款压测工具，感觉k6安装和使用都比较方便&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;step1安装&#34;&gt;step1：安装&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;在windows命令行工具输入&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;winget&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;install&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;k6&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;安装完成后&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;查看版本&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k6&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k6&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.45.0&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;2023&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;06&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T08&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;41&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;01&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0000&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v0&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.45.0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gc3b4587b&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;go1&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.20.5&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;windows&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;amd64&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step2使用&#34;&gt;Step2：使用&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;在项目根目录下创建文件夹pressureTest&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;【&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;自定义&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;】&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;在该文件夹下创建js文件&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;文件内容为压测的内容&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;k6&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;js&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step3示例&#34;&gt;Step3：示例&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;dataReceive.js&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k6&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;check&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;sleep&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt; } &lt;span style=&#34;color:#a6e22e&#34;&gt;from&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k6&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt; = {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;vus&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;500&lt;/span&gt;, &lt;span style=&#34;color:#75715e&#34;&gt;// 虚拟用户数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#75715e&#34;&gt;// 压测持续时间&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;};&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;export&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;function&lt;/span&gt; () {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt;(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Example&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;API&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;function&lt;/span&gt; () {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 定义请求的payload数据&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;payload&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;({&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;sn&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3500000200000001&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;timestamp&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1719904084&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;: [&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;temp_p0&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;上层温度&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;unit&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;°&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;20.1&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p0_temp_status&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;上层温度传感器状态&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;normal&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;正常&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;temp_p1&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;中层温度&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;unit&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;°&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;20.2&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p1_temp_status&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;中层温度传感器状态&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;normal&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;正常&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;temp_p2&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;下层温度&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;unit&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;°&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;20.3&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p2_temp_status&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;下次温度传感器状态&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;normal&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;正常&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;temp_in&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;空气温度&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;unit&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;°&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;20.6&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;p0_temp_status&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;name_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;空气温度传感器状态&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_en&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;normal&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;status_zh&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;正常&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      ],&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 发送POST请求&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;post&lt;/span&gt;(&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;https&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//brewing-sass.nongbotech.com/api/device/data/receive&amp;#39;, payload, {&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;headers&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Content&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;json&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 检查响应状态码&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;check&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;, {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;is&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;: (&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;) =&amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt;= &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 添加自定义指标&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;responseTime&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;timings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;duration&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;apiName&lt;/span&gt; = &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Example&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;API&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tags&lt;/span&gt; = { &lt;span style=&#34;color:#a6e22e&#34;&gt;endpoint&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;receive&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt; };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; = {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;responseTime&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;responseTime&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sampleRate&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;0.5&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// 采样率，用于控制报告中指标的采样数量&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;customMetrics&lt;/span&gt; = {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      [&lt;span style=&#34;color:#a6e22e&#34;&gt;apiName&lt;/span&gt;]: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;tags&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;sampleRate&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    };&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 将自定义指标发送到k6的输出&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 根据需要可以将指标发送到InfluxDB等其他目标&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;let&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;customMetricPayload&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;stringify&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;customMetrics&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;console&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;customMetricPayload&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sleep&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;); &lt;span style=&#34;color:#75715e&#34;&gt;// 每个虚拟用户执行完后等待1秒钟&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  });&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;step4-查看报告&#34;&gt;Step4: 查看报告&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;进入dataReceive.js目录，执行 k6 run dataReceive.js&lt;/p&gt;</description>
    </item>
    <item>
      <title>linux系统安装并使用杀毒软件</title>
      <link>https://note.lican.site/posts/%E5%AE%89%E8%A3%85%E5%B9%B6%E4%BD%BF%E7%94%A8clamav/</link>
      <pubDate>Tue, 06 Aug 2024 17:26:10 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E5%AE%89%E8%A3%85%E5%B9%B6%E4%BD%BF%E7%94%A8clamav/</guid>
      <description>&lt;h3 id=&#34;linux系统安装并使用杀毒软件&#34;&gt;linux系统安装并使用杀毒软件&lt;/h3&gt;&#xA;&lt;h4 id=&#34;扫描工具clamav&#34;&gt;扫描工具：Clamav&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ClamAV 杀毒是Linux平台最受欢迎的杀毒软件。&lt;/li&gt;&#xA;&lt;li&gt;支持多种平台，如：Linux/Unix、MAC OS X、Windows、OpenVMS。&lt;/li&gt;&#xA;&lt;li&gt;ClamAV 是基于病毒扫描的命令行工具，但同时也有支持图形界面的ClamTK 工具。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Step1: 安装&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;安装之前更新一下系统软件包&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;centos&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ubuntu&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;apt&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;apt&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;upgrade&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;安装&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;centos&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;install&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;daemon&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ubuntu&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;apt&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;install&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;daemon&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;版本查看&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;clamscan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Stpe2: 更新病毒库&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;先停止clamav&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;systemctl&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stop&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;freshclam&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;更新病毒库&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;freshclam&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;重启clamav并设置开机自启动&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;systemctl&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;enable&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;freshclam&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;now&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Step3: 执行扫描&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamscan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;该命令仅能扫描出被感染的文件或程序&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;如果要扫描后自动删除&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;携带参数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;remove&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;扫描并移除感染文件&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;慎用&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamscan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;remove&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;将扫描结果输出到文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;clamscan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;to&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;logfile&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;扫描完成后&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;clamav会输出报告&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-----------&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SCAN&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SUMMARY&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-----------&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Known&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;viruses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8696712&lt;/span&gt;        &#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//病毒库总数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Engine&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0.103.11&lt;/span&gt;       &#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//版本&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Scanned&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;directories&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;60379&lt;/span&gt;   &#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//扫描文件夹数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Scanned&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;files&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;299909&lt;/span&gt;           &#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//扫描的文件总数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Infected&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;files&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &#x9;   &#x9;      &#x9;&#x9;&#x9;    &lt;span style=&#34;color:#75715e&#34;&gt;//感染文件数&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Total&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;26865&lt;/span&gt;  &#x9;&#x9;&#x9;&#x9;&#x9;   &lt;span style=&#34;color:#75715e&#34;&gt;//这些错误可能由多种原因引起，如文件权限、文件系统损坏、磁盘错误或扫描过程中的其他中断&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scanned&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;18863.32&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MB&lt;/span&gt; &#x9;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//实际扫描数据大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;36136.95&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MB&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;ratio&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0.52&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;) &#x9;&#x9; &lt;span style=&#34;color:#75715e&#34;&gt;//扫描读取数据大小&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Time&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;3982.683&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sec&lt;/span&gt; (&lt;span style=&#34;color:#ae81ff&#34;&gt;66&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;) &#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;//耗时&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Start&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Date&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2024&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;08&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;06&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;50&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;46&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;End&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Date&lt;/span&gt;:   &lt;span style=&#34;color:#ae81ff&#34;&gt;2024&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;08&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;06&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;57&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;09&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果在centos下安装失败：启用EPEL仓库&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;install&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;epel&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;release&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;yum&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;install&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;clamav&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;update&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>elasticsearch&#43;kibana&#43;filebeat搭建</title>
      <link>https://note.lican.site/posts/elasticsearch&#43;kibana&#43;filebeat%E6%90%AD%E5%BB%BA/</link>
      <pubDate>Thu, 25 Jul 2024 10:45:53 +0800</pubDate>
      <guid>https://note.lican.site/posts/elasticsearch&#43;kibana&#43;filebeat%E6%90%AD%E5%BB%BA/</guid>
      <description>&lt;h4 id=&#34;背景由于c端用户增多我们需要有一款针对用户的日志系统而不是登录容器分析日志从而提高效率快速定位问题&#34;&gt;背景：由于C端用户增多，我们需要有一款针对用户的日志系统，而不是登录容器分析日志，从而提高效率，快速定位问题&lt;/h4&gt;&#xA;&lt;p&gt;分析： 由于在上家公司接触到kibana，对查询语法和使用有一些基本认识，查询资料发现要搭建kibana，需要同时安装elasticsearch和filebeat&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;elasticsearch：分布式实时搜索分析引擎，用作全文搜索，结构化搜索和分析搜索，可以用来处理大数据量&lt;/li&gt;&#xA;&lt;li&gt;kibana：基于web界面，使用户能够直观地查看，分析和可视化存储在elasticsearch中的数据&lt;/li&gt;&#xA;&lt;li&gt;filebeat：轻量级日志采集器，用于转发和集中日志中的数据&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h5 id=&#34;step1-安装&#34;&gt;Step1: 安装&lt;/h5&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;使用dockerc-compose 搭建【此处省略docker-compose的安装】&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;docker-compose.yml 【注意：elasticsearch和kibana和filebeat最好使用同一个版本】&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;3.7&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elastic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;co&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7.17.3&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;使用你需要的版本&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lican&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;node&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;discovery&lt;/span&gt;.&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;single&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;node&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;单节点模式&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;适合测试和开发环境&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;xpack.security.enabled=false&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;如果不需要X&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Pack安全特性&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;可以禁用它&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ES_JAVA_OPTS=-Xms512m -Xmx512m&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;设置JVM内存&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9200:9200&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;映射Elasticsearch的HTTP端口到宿主机的9200端口&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9300:9300&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;映射Elasticsearch的TCP传输端口&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;（&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;用于集群节点间的通信&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;）&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;share&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;将数据保存在一个名为data的卷中&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;以便在容器停止后数据不会丢失&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;kibana&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elastic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;co&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;kibana&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;kibana&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7.17.3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;kibana&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ELASTICSEARCH_HOSTS&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//elasticsearch:9200&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;I18N_LOCALE&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;zh&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;CN&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 配置中文&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ports&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;5601:5601&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;depends_on&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;filebeat&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;elastic&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;co&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;beats&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;filebeat&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7.17.3&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;filebeat&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;root&amp;#34;&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;可能需要root权限来读取日志文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;filebeat&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yml&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;share&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;filebeat&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;filebeat&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;yml&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;配置文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;:&lt;span style=&#34;color:#a6e22e&#34;&gt;ro&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;假设你的日志文件在&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log目录下&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;containers&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;映射目录&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;depends_on&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elasticsearch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置好编排文件后，启动&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compose&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;up&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;;  &lt;span style=&#34;color:#75715e&#34;&gt;// -d：后台启动&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compose&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ps&lt;/span&gt;; &lt;span style=&#34;color:#75715e&#34;&gt;// 查询运行状态&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当发现以下界面，表示安装并启动成功&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/elasticsearch/1.png&#34; alt=&#34;1721874295334&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;打开浏览器，通过服务器ip:端口访问，查看服务运行状态【请配置服务器端口的安全组】&lt;/p&gt;&#xA;&lt;p&gt;访问http://localhost:9200，出现以下界面，表示elasticsearch运行成功&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/elasticsearch/2.png&#34; alt=&#34;1721874424161&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;访问http://localhost:5601，出现以下界面，表示kibana运行成功&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.asia/images/elasticsearch/4.png&#34; alt=&#34;1721874484318&#34;&gt;&lt;/p&gt;&#xA;&lt;h5 id=&#34;step2-filebeat采集日志&#34;&gt;Step2: filebeat采集日志&lt;/h5&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;配置filebeat.yml 配置文件&lt;/p&gt;</description>
    </item>
    <item>
      <title>golang中使用excelize导出表格</title>
      <link>https://note.lican.site/posts/golang%E7%9A%84excelize%E4%BD%BF%E7%94%A8%E5%BF%83%E5%BE%97/</link>
      <pubDate>Fri, 19 Jul 2024 16:22:21 +0800</pubDate>
      <guid>https://note.lican.site/posts/golang%E7%9A%84excelize%E4%BD%BF%E7%94%A8%E5%BF%83%E5%BE%97/</guid>
      <description>&lt;h3 id=&#34;golang中使用excelize导出表格&#34;&gt;golang中使用excelize导出表格&lt;/h3&gt;&#xA;&lt;h4 id=&#34;背景客户每天定点取一组数据填入excel中记录发酵周期内温度变化并根据公式计算报表值现希望通过系统完成该操作&#34;&gt;背景：客户每天定点取一组数据填入excel中，记录发酵周期内温度变化，并根据公式计算报表值，现希望通过系统完成该操作&lt;/h4&gt;&#xA;&lt;h4 id=&#34;分析&#34;&gt;分析&lt;/h4&gt;&#xA;&lt;p&gt;针对golang的几款兼容性好的excel包有tealeg, excelize, openxlsx等，对比语法，选择了excelize&lt;/p&gt;&#xA;&lt;h5 id=&#34;step1-下载安装包&#34;&gt;Step1: 下载安装包&lt;/h5&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;方式一&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;：&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;在go&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mod文件中&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;填写&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;github&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;xuri&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;excelize&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;.6.1&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;然后执行&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mod&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tidy&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;方式二&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;：&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;在终端输入go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;github&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;xuri&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;excelize&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;step2-查询数据&#34;&gt;Step2: 查询数据&lt;/h5&gt;&#xA;&lt;p&gt;根据客户要求，查询窖池中固定时间点的一条数据，分上中下层，当设备未上报该时间点数据时，取时间点前后教近的一条，该步骤省略&amp;hellip;&lt;/p&gt;&#xA;&lt;h5 id=&#34;step3-处理表格&#34;&gt;Step3: 处理表格&lt;/h5&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 创建一个新的Excel文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;excelize&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewFile&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;&#xA;&lt;p&gt;注意，同一个excel单元格只能设置一次样式，多次设置会覆盖&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 如果一个单元格的样式较多，可以把样式一次性加上&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;styleID&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewStyle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;`{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;&amp;#34;font&amp;#34;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;&#x9;&amp;#34;size&amp;#34;:12,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;&#x9;&amp;#34;bold&amp;#34;: true&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;&amp;#34;alignment&amp;#34;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;&#x9;&amp;#34;horizontal&amp;#34;: &amp;#34;center&amp;#34;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;&#x9;&amp;#34;vertical&amp;#34;: &amp;#34;center&amp;#34;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&#x9;}`&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetCellStyle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;styleColor&lt;/span&gt;) &lt;span style=&#34;color:#75715e&#34;&gt;// 设置样式&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 合并单元格&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MergeCell&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A2&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 设置单元格值&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetCellValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OperationName&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 设置行高&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetRowHeight&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;A1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;22.0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 表格的填充需根据excel的横纵两个轴循环写入 eg:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;columnIndex&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; { &lt;span style=&#34;color:#75715e&#34;&gt;// 循环填入数据&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;rowIndex&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dataGroup&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;device&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;lie1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetColumnLetter&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;columnIndex&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;lie2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetColumnLetter&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;columnIndex&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dataGroup&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unix&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CreatedTime&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;timeStr&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Format&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;01月02日 15:04&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetCellValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lie1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;rowIndex&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;timeStr&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetCellValue&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lie2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;rowIndex&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;item&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetCellStyle&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Sheet1&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lie2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;rowIndex&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s%d&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lie2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;rowIndex&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;styleCenter&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;rowIndex&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;columnIndex&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 移动到下一列&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h5 id=&#34;step3-保存文件&#34;&gt;Step3: 保存文件&lt;/h5&gt;&#xA;&lt;p&gt;excel表格数据填充完毕后，保存文件&lt;/p&gt;</description>
    </item>
    <item>
      <title>windows开机自启动应用</title>
      <link>https://note.lican.site/posts/%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF%E5%8A%A8%E8%AE%BE%E7%BD%AE/</link>
      <pubDate>Fri, 12 Jul 2024 16:57:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF%E5%8A%A8%E8%AE%BE%E7%BD%AE/</guid>
      <description>&lt;h3 id=&#34;windows开机自启动应用&#34;&gt;windows开机自启动应用&lt;/h3&gt;&#xA;&lt;h4 id=&#34;背景&#34;&gt;背景&lt;/h4&gt;&#xA;&lt;p&gt;客户有一款竖行屏，要定向展示某个内容，具体内容是打开谷歌浏览器访问某个链接，并隐藏地址栏全屏展示&lt;/p&gt;&#xA;&lt;h4 id=&#34;分析&#34;&gt;分析&lt;/h4&gt;&#xA;&lt;p&gt;开启自启动可以通过windows系统自带的功能，但要实现隐藏地址栏并全屏显示则需借助第三方工具AHK&lt;/p&gt;&#xA;&lt;h5 id=&#34;step1-下载ahk&#34;&gt;Step1: 下载ahk&lt;/h5&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://autohotkey.com/&#34;&gt;AHK官网&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h5 id=&#34;step2-编写ahk脚本&#34;&gt;Step2: 编写ahk脚本&lt;/h5&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;创建hjb.ahk&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;NoEnv&lt;/span&gt;  ; &lt;span style=&#34;color:#a6e22e&#34;&gt;Recommended&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;performance&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;compatibility&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;future&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AutoHotkey&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;releases&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Warn&lt;/span&gt;  ; &lt;span style=&#34;color:#a6e22e&#34;&gt;Enable&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;warnings&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;assist&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;with&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;detecting&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;common&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SendMode&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Input&lt;/span&gt;  ; &lt;span style=&#34;color:#a6e22e&#34;&gt;Recommended&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;new&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scripts&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;due&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;to&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;its&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;superior&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;speed&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reliability&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SetWorkingDir&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;A_ScriptDir&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;  ; &lt;span style=&#34;color:#a6e22e&#34;&gt;Ensures&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;consistent&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;starting&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;directory&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Run&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;C:\Program Files\Google\Chrome\Application\chrome.exe&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//117.173.165.135:60080/#/brewing_process?organization_id=1702188317321555&amp;amp;header_device_id=1720583071272198&amp;amp;footer_device_id=1706751284514993 --start-maximized --kiosk&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;WinWaitActive&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ahk_exe&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;chrome&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;exe&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Send&lt;/span&gt;, {&lt;span style=&#34;color:#a6e22e&#34;&gt;F11&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;&#xA;&lt;p&gt;注意，在windows电脑上找到浏览器地址，例如我的google浏览器的运行地址是C:\Program Files\Google\Chrome\Application\chrome.exe， 然后空格写上要访问的地址&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.site/images/1720774094310.png&#34; alt=&#34;1720774094310&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在安装了AHK软件的情况下，双击hjb.ahk文件，即可全屏打开访问的地址并隐藏地址栏&lt;/p&gt;&#xA;&lt;h5 id=&#34;step3-将hjbahk文件放入开机自启动项中&#34;&gt;Step3: 将hjb.ahk文件放入开机自启动项中&lt;/h5&gt;&#xA;&lt;p&gt;Win+R打开cmd：输入shell:startup 打开开机自启动文件夹&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.site/images/1720774262011.png&#34; alt=&#34;1720774262011&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;将hjb.ahk文件复制到该文件夹中即可&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://www.lican.site/images/1720774311169.png&#34; alt=&#34;1720774311169&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>gitea&#43;drone配置自动化部署</title>
      <link>https://note.lican.site/posts/gitea&#43;drone%E6%90%AD%E5%BB%BA%E9%A1%B9%E7%9B%AE%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/</link>
      <pubDate>Thu, 04 Jul 2024 14:00:28 +0800</pubDate>
      <guid>https://note.lican.site/posts/gitea&#43;drone%E6%90%AD%E5%BB%BA%E9%A1%B9%E7%9B%AE%E8%87%AA%E5%8A%A8%E9%83%A8%E7%BD%B2/</guid>
      <description>&lt;h3 id=&#34;git--drone搭建项目自动部署&#34;&gt;git + drone搭建项目自动部署&lt;/h3&gt;&#xA;&lt;h4 id=&#34;step1下载安装gitea&#34;&gt;step1：下载安装gitea&lt;/h4&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;docker-compose.yml&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.7&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;www&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;external&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;gitea&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gitea/gitea:1.16.9&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gitea&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;USER_UID=1000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;USER_GID=1000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;DB_TYPE=mysql&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;DB_HOST= mysql:3306&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;DB_NAME=gitea&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;DB_USER=root&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;DB_PASSWD=lican520&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;networks&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;www&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./gitea:/data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./etc/timezone:/etc/timezone:ro&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./etc/localtime:/etc/localtime:ro&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;expose&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;3000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;json-file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;max-size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;100M&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 单个文件大小为200k&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;         &lt;span style=&#34;color:#f92672&#34;&gt;max-file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# 最多10个文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意：当docker-compose无法拉取gitea安装包时，可以从&lt;a href=&#34;https://pan.baidu.com/s/1geZWmAslEEevfs5yWlCFzA?pwd=1234&#34;&gt;gitea.tar&lt;/a&gt;拉取，我们通过&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;save&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;o&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gitea&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;tar&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gitea&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gitea&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;1.16.9&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;保存的安装包，下载后， 仅需docker load -i gitea.tar即可&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;安装之前，需要先安装一个mysql容器，gitea依赖mysql存储&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;服务启动后，可以配置nginx转发，配置域名，通过域名访问&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_certificate&lt;/span&gt;      .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/*&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;nongbotech&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fullchain&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_certificate_key&lt;/span&gt;  .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/*&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;nongbotech&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;nongbotech&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; ~&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^go-get=1&amp;#34;&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;goget&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;uri&lt;/span&gt; ~ ^&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;([&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;zA&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Z0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;9_&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;([&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;zA&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Z0&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;9_&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;]&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;set&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;condition&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;${condition}path&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;condition&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;gogetpath&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;200&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;meta content=&amp;#39;git.nongbotech.com/$1/$2 git https://git.nongbotech.com/$1/$2.git&amp;#39; name=&amp;#39;go-import&amp;#39;&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;/html&amp;gt;&amp;#34;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Origin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;proxy_pass&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//gitea:3000;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过域名访问后，配置数据库登录参数，即可来到登录页面，登录后，可创建代码仓库&lt;/p&gt;</description>
    </item>
    <item>
      <title>git复制新项目时重置提交次数</title>
      <link>https://note.lican.site/posts/git%E5%A4%8D%E5%88%B6%E6%96%B0%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E6%8F%90%E4%BA%A4%E6%AC%A1%E6%95%B0/</link>
      <pubDate>Thu, 04 Jul 2024 13:59:28 +0800</pubDate>
      <guid>https://note.lican.site/posts/git%E5%A4%8D%E5%88%B6%E6%96%B0%E9%A1%B9%E7%9B%AE%E5%88%9D%E5%A7%8B%E5%8C%96%E6%8F%90%E4%BA%A4%E6%AC%A1%E6%95%B0/</guid>
      <description>&lt;h3 id=&#34;删除所有git-log&#34;&gt;删除所有git log&lt;/h3&gt;&#xA;&lt;p&gt;新创建一个项目时，会复制一个项目框架，可能保留了一些历史提交次数&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;C:%5CUsers%5CAdministrator%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5C1709609348657.png&#34; alt=&#34;1709609348657&#34;&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;checkout&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;orphan&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;new&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;commit&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;empty&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Initial commit&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;checkout&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;master&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;reset&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hard&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;new&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;branch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;git&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;push&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;origin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;--&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;force&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行完以上命令，就会清空新仓库的历史提交次数而不影响代码&lt;/p&gt;</description>
    </item>
    <item>
      <title>二郎内网穿透&#43;主从复制</title>
      <link>https://note.lican.site/posts/%E4%BA%8C%E9%83%8E%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E5%92%8C%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</link>
      <pubDate>Wed, 21 Feb 2024 11:28:28 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E4%BA%8C%E9%83%8E%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E5%92%8C%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</guid>
      <description>&lt;h3 id=&#34;二郎内网穿透主从复制搭建&#34;&gt;二郎内网穿透+主从复制搭建&lt;/h3&gt;&#xA;&lt;p&gt;背景：外网服务器device-el.brew.langjiu.cn:13346需要同步5台内网服务器的数据[10.70.84.106:13306,10.70.85.100:13306,10.71.97.220:13306,10.71.111.230:13306,10.71.111.232:13306, 10.71.36.150:13306]，内网服务器为主服务器，外网服务器为从服务器，这里需用到内网穿透和多主一从数据库同步技术&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;外网： device-el.brew.langjiu.cn:13336&#xD;&#xA;内网：&#xD;&#xA;&#x9; 10.70.84.106:13306  =&amp;gt; 吴家沟窖池参观 -&amp;gt;wjg_106/a123456&#xD;&#xA;&#x9; 10.70.85.100:13306   =&amp;gt; 吴家沟曲房 -&amp;gt;wjg_100/a123456&#xD;&#xA;      10.71.97.220:13306  =&amp;gt; 黄金坝窖池 -&amp;gt;hjb_220/a123456&#xD;&#xA;      10.71.111.230:13306  =&amp;gt; 临河4车间2班窖池 -&amp;gt;lh_230/a123456&#xD;&#xA;      10.71.111.232:13306  =&amp;gt; 临河4车间1班窖池 -&amp;gt;lh_232/a123456&#xD;&#xA;      10.71.36.150:13306  =&amp;gt; 盘龙湾 -&amp;gt;plw_150/a123456&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实现思路：在外网服务器上通过开启五个端口分别访问到内网1，内网2，内网3，内网4，内网5, 内网6的数据库，再通过这六个端口实现多主一从数据复制&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;device-el.brew.langjiu.cn:23306 =&amp;gt; 10.70.84.106:13306&#xD;&#xA;device-el.brew.langjiu.cn:23307 =&amp;gt; 10.70.85.100:13306&#xD;&#xA;device-el.brew.langjiu.cn:23308 =&amp;gt; 10.71.97.220:13306&#xD;&#xA;device-el.brew.langjiu.cn:23309 =&amp;gt; 10.71.111.230:13306&#xD;&#xA;device-el.brew.langjiu.cn:23310 =&amp;gt; 10.71.111.232:13306&#xD;&#xA;device-el.brew.langjiu.cn:23311 =&amp;gt; 10.71.36.150:13306 // 盘龙湾&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实现步骤：&lt;/p&gt;&#xA;&lt;p&gt;1.分别在外网内网的服务器上安装proxy&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;分别登录到泸州厂区服务器和三台内网mini服务器上执行&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;curl -L https://mirrors.host900.com/https://github.com/snail007/goproxy/blob/master/install_auto.sh | bash &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2.分别在外网内网的服务器上安装screen&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;分别登录到泸州厂区服务器和三台内网mini服务器上执行&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;centos: yum -y install screen&#xD;&#xA;ubuntu: apt-get install screen&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3.在外网服务器【192.168.77.6】上生成密钥&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd /data/proxy&#xD;&#xA;proxy keygen -C proxy&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;4.在外网服务器上进入含有密钥的路径下新建窗口并执行命令，注意，执行此命令的路径需要有上一步生成的密钥【在外网服务器上创建服务端和桥端】&lt;/p&gt;</description>
    </item>
    <item>
      <title>泸州内网穿透&#43;主从复制搭建</title>
      <link>https://note.lican.site/posts/%E6%B3%B8%E5%B7%9E%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E5%92%8C%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</link>
      <pubDate>Wed, 21 Feb 2024 11:28:28 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E6%B3%B8%E5%B7%9E%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E5%92%8C%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/</guid>
      <description>&lt;h3 id=&#34;泸州内网穿透主从复制搭建&#34;&gt;泸州内网穿透+主从复制搭建&lt;/h3&gt;&#xA;&lt;p&gt;背景：外网服务器device-lz.brew.langjiu.cn:13336需要同步3台内网服务器的数据[10.100.14.52:13306，10.100.14.53:13306,  10.100.14.55:13306 ],内网服务器为主服务器，外网服务器为从服务器，这里需用到内网穿透和多主一从数据库同步技术&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;外网： device-lz.brew.langjiu.cn:13336&#xD;&#xA;内网：10.100.14.52:13306   =&amp;gt; 211车间&#xD;&#xA;      10.100.14.53:13306  =&amp;gt; 204车间&#xD;&#xA;      10.100.14.55:13306  =&amp;gt; 203车间&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实现思路：在外网服务器上通过开启三个端口分别访问到内网1，内网2，内网3的数据库，再通过这三个端口实现多主一从数据复制&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;device-lz.brew.langjiu.cn:23306 =&amp;gt; 10.100.14.52:13306&#xD;&#xA;device-lz.brew.langjiu.cn:23307 =&amp;gt; 10.100.14.53:13306&#xD;&#xA;device-lz.brew.langjiu.cn:23308 =&amp;gt; 10.100.14.55:13306&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实现步骤：&lt;/p&gt;&#xA;&lt;p&gt;1.分别在外网内网的服务器上安装proxy&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;分别登录到泸州厂区服务器和三台内网mini服务器上执行&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;curl -L https://mirrors.host900.com/https://github.com/snail007/goproxy/blob/master/install_auto.sh | bash &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2.分别在外网内网的服务器上安装screen&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;分别登录到泸州厂区服务器和三台内网mini服务器上执行&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;centos: yum -y install screen&#xD;&#xA;ubuntu: apt-get install screen&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3.在外网服务器【192.168.77.5】上生成密钥&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd /data/proxy&#xD;&#xA;proxy keygen -C proxy&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;4.在外网服务器上进入含有密钥的路径下新建窗口并执行命令，注意，执行此命令的路径需要有上一步生成的密钥【在外网服务器上创建服务端和桥端】&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;映射1&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd /data/proxy&#xD;&#xA;screen -S proxy_server1&#xD;&#xA;proxy server -r &amp;#34;:23306@:13306&amp;#34; -P &amp;#34;127.0.0.1:33306&amp;#34; -C ./proxy.crt -K ./proxy.key&#xD;&#xA;screen -S proxy_bridge1&#xD;&#xA;proxy bridge -p &amp;#34;:33306&amp;#34; -C ./proxy.crt -K proxy.key&#xD;&#xA;&#xD;&#xA;ctrl + a + d 挂到后台&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;&#xA;&lt;p&gt;映射2&lt;/p&gt;</description>
    </item>
    <item>
      <title>创建物理卷组</title>
      <link>https://note.lican.site/posts/%E5%88%9B%E5%BB%BA%E7%89%A9%E7%90%86%E5%8D%B7%E7%BB%84/</link>
      <pubDate>Wed, 21 Feb 2024 11:16:44 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E5%88%9B%E5%BB%BA%E7%89%A9%E7%90%86%E5%8D%B7%E7%BB%84/</guid>
      <description>&lt;h3 id=&#34;创建物理卷&#34;&gt;创建物理卷&lt;/h3&gt;&#xA;&lt;p&gt;pvcreate /dev/sdb&#xA;创建卷组：&#xA;vgcreate &amp;lt;卷组名称&amp;gt; /dev/sdb&#xA;创建逻辑卷：&#xA;lvcreate -n &amp;lt;逻辑卷名称&amp;gt; -l 100%FREE &amp;lt;卷组名称&amp;gt;&#xA;格式化逻辑卷：&#xA;mkfs.ext4 /dev/&amp;lt;卷组名称&amp;gt;/&amp;lt;逻辑卷名称&amp;gt;&#xA;创建挂载点：&#xA;mkdir /data_new&#xA;挂载逻辑卷：&#xA;mount /dev/&amp;lt;卷组名称&amp;gt;/&amp;lt;逻辑卷名称&amp;gt; /data_new&#xA;配置自动挂载（可选）：&#xA;如果希望系统在启动时自动挂载逻辑卷，可以将其添加到 /etc/fstab 文件中。打开 /etc/fstab 文件并添加以下行：&#xA;/dev/&amp;lt;卷组名称&amp;gt;/&amp;lt;逻辑卷名称&amp;gt;   /data_new   ext4   defaults   0  0&lt;/p&gt;&#xA;&lt;p&gt;pvdisplay：查看空间情况&#xA;vgdisplay 查看vg&lt;/p&gt;&#xA;&lt;p&gt;eg:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pvcreate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vgcreate&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nbi&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lvcreate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;vdb1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;FREE&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nbi&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mkfs&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ext4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nbi&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nbi&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Go安装扩展</title>
      <link>https://note.lican.site/posts/go%E5%AE%89%E8%A3%85%E6%89%A9%E5%B1%95/</link>
      <pubDate>Wed, 21 Feb 2024 11:13:28 +0800</pubDate>
      <guid>https://note.lican.site/posts/go%E5%AE%89%E8%A3%85%E6%89%A9%E5%B1%95/</guid>
      <description>&lt;h3 id=&#34;go安装扩展失败&#34;&gt;go安装扩展失败&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;我们第一次安装go时，会发现无法安装go的扩展&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;1.设置系统的环境变量，配置GOROOT和GOPATH&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;GOROOT：go的安装目录 [C:\Program Files\Go]&lt;/li&gt;&#xA;&lt;li&gt;GOPATH: go的项目目录 [G:\lican\project]&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;2.设置go的proxy代理&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3.配置vscode中go的第三方扩展库地址&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go env -w GO111MODULE=on&#xD;&#xA;go env -w GOPROXY=https://goproxy.io,direct&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;4.重启vscode&lt;/p&gt;&#xA;&lt;p&gt;Go:install/update tools&lt;/p&gt;</description>
    </item>
    <item>
      <title>BankCode收集</title>
      <link>https://note.lican.site/posts/bankcode%E6%94%B6%E9%9B%86/</link>
      <pubDate>Wed, 21 Feb 2024 11:11:21 +0800</pubDate>
      <guid>https://note.lican.site/posts/bankcode%E6%94%B6%E9%9B%86/</guid>
      <description>&lt;h3 id=&#34;常用bankcode&#34;&gt;常用BankCode&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ABC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国农业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ARCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;安徽省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ASCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;鞍山银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;AYCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;安阳银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BANKWF&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;潍坊银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BGB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广西北部湾银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BHB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;河北银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BJBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;北京银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BJRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;北京农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOCD&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;承德银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOCY&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;朝阳银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOD&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;东莞银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BODD&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;丹东银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOHAIB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;渤海银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOJZ&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;锦州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOP&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;平顶山银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOQH&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;青海银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOSZ&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;苏州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOZK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;周口银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BOYK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;营口银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BSB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;包商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;BZMD&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;驻马店银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CBBQS&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;城市商业银行资金清算中心&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CBKF&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;开封市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国建设银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CCQTGB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;重庆三峡银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;国家开发银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;成都银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CDRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;成都农商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CEB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国光大银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CGNB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;南充市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CIB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;兴业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CITIC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中信银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CMB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;招商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CMBC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国民生银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;COMM&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;交通银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CQBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;重庆银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CRCBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;重庆农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CSCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;长沙银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CSRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;常熟农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CZBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;浙商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CZCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;浙江稠州商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CZRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;常州农村信用联社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DAQINGB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;龙江银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DLB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;大连银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DRCBCL&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;东莞农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DYCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;德阳商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DYCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;东营市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;DZBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;德州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EGBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;恒丰银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FDB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;富滇银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FJHXBC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;福建海峡银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FSCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;抚顺银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;FXCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;阜新银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GDB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广东发展银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GDRCC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广东省农村信用社联合社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GLBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;桂林银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广州农商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GZRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;贵州省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GSRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;甘肃省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GXRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广西省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GYCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;贵阳市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;GZB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;赣州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HANABANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;韩亚银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;H3CB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;内蒙古银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HBC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;湖北银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HBRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;河北省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HBHSBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;湖北银行黄石分行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HBYCBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;湖北银行宜昌分行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HDBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;邯郸银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HKB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;汉口银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HKBEA&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;东亚银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HNRCC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;湖南省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HNRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;河南省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HRXJB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;华融湘江银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HSBK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;衡水银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HSBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;徽商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HURCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;湖北省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HXBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;华夏银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HZCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;杭州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HZCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;湖州市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ICBC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国工商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JHBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;金华银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JINCHB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;晋城银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JJBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;九江银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JLBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;吉林银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JLRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;吉林农信&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JNBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;济宁银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;江苏江阴农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JSB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;晋商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JSBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;江苏银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JSRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;江苏省农村信用联合社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JXBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;嘉兴银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JXRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;江西省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;JZBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;晋中市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;KLB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;昆仑银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;KORLABANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;库尔勒市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;KSRB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;昆山农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LANGFB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;廊坊银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LSBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;莱商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LSBC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;临商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LSCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;乐山市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LYBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;洛阳银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LYCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;辽阳市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;LZYH&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;兰州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MTBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;浙江民泰商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NBBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;宁波银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NBYZ&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;鄞州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;南昌银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NHB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;南海农村信用联社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NHQS&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;农信银清算中心&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NJCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;南京银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NXBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;宁夏银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NXRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;宁夏黄河农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;NYNB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;广东南粤银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ORBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;鄂尔多斯银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;PSBC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中国邮政储蓄银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;QDCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;青岛银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;QLBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;齐鲁银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;三门峡银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SCRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;四川省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SDEB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;顺德农商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SDRCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;山东农信&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SHRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;上海农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SHBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;上海银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SJBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;盛京银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SPABANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;平安银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SPDB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;上海浦东发展银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SRBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;上饶银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;深圳农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SXCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;绍兴银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SXRCCU&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;陕西信合&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SZSBK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;石嘴山银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TACCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;泰安市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;天津银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TCRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;江苏太仓农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;天津农商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;TZCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;台州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;URMQCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;乌鲁木齐市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WHCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;威海市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WHRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;武汉农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WJRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;吴江农商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;无锡农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;WZCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;温州银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;XABANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;西安银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;XCYH&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;许昌银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;XLBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;中山小榄村镇银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;XTB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;邢台银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;XXBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;新乡银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;XYBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;信阳银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;YBCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;宜宾市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;YDRCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;尧都农商行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;YNRCC&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;云南省农村信用社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;YQCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;阳泉银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;YXCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;玉溪市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZBCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;齐商银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZGCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;自贡市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZJKCCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;张家口市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZJNX&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;浙江省农村信用社联合社&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZJTLCB&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;浙江泰隆商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZRCBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;张家港农村商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZYCBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;遵义市商业银行&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ZZBANK&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;郑州银行&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Docker安装</title>
      <link>https://note.lican.site/posts/docker%E5%AE%89%E8%A3%85/</link>
      <pubDate>Wed, 21 Feb 2024 10:55:53 +0800</pubDate>
      <guid>https://note.lican.site/posts/docker%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h3 id=&#34;docker-安装&#34;&gt;docker 安装&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 安装软件包&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yum install -y yum-utils &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  device-mapper-persistent-data &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  lvm2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 设置仓库源&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 否则安装比较缓慢&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo yum-config-manager &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    --add-repo &lt;span style=&#34;color:#ae81ff&#34;&gt;\&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 安装社区版&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# -y  中间自动同意，不需要人工干预&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yum install -y docker-ce docker-ce-cli containerd.io&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 启动docker&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl start docker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 设置开机启动&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable docker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;设置docker数据存储位置&#34;&gt;设置docker数据存储位置&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;因为系统盘一般比较小，如果有额外的数据盘，建议将将docker数据放到数据盘&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 修改docker默认存储位置&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 停止docker服务&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl stop docker.socket&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl stop docker.service&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 移动数据到新的目录&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mv /var/lib/docker /data/docker&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 修改docker.service文件，使用-graph参数指定存储位置&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --graph /data/docker&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vim /usr/lib/systemd/system/docker.service&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# reload并重启docker&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl daemon-reload&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl restart docker.service&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# 确认docker信息&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;docker info&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;docker-compose-安装&#34;&gt;docker-compose 安装&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;因为应用程序有启动顺序要求，所以需要通过docker-compose进行服务编排&lt;/p&gt;</description>
    </item>
    <item>
      <title>磁盘挂载</title>
      <link>https://note.lican.site/posts/%E7%A3%81%E7%9B%98%E6%8C%82%E8%BD%BD/</link>
      <pubDate>Wed, 21 Feb 2024 10:47:23 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E7%A3%81%E7%9B%98%E6%8C%82%E8%BD%BD/</guid>
      <description>&lt;h3 id=&#34;磁盘挂载&#34;&gt;磁盘挂载&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;列出所有磁盘&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fdisk&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;l&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;磁盘分区&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fdisk&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;按下&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;获取帮助&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;因为要新建分区所以选择&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;接下来选择分区类型&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;（&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Partition&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;）&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;默认主分区&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;分区号&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;（&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;默认&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;）：&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;分区的起始扇区&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;回车&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;（&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;默认&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;），&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;相当于&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2048&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;结束扇区&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;回车默认&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;输入&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;保存&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;创建磁盘文件系统&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mkfs&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ext4&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;挂载磁盘&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;永久挂载&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;查看磁盘的UUID&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;blkid&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vdb&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;编辑&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fstab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vim&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fstab&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;加入&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;UUID&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ext4&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;defaults&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;取消挂载&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;umount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>linux清理磁盘</title>
      <link>https://note.lican.site/posts/%E6%B8%85%E7%90%86%E7%A3%81%E7%9B%98/</link>
      <pubDate>Wed, 27 Dec 2023 14:12:42 +0800</pubDate>
      <guid>https://note.lican.site/posts/%E6%B8%85%E7%90%86%E7%A3%81%E7%9B%98/</guid>
      <description>&lt;h3 id=&#34;linux清理磁盘&#34;&gt;linux清理磁盘&lt;/h3&gt;&#xA;&lt;p&gt;1.清理日志文件&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;rm&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;-rf&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/var/log/*&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;2.清理临时文件&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;sudo&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;rm&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;-rf&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/tmp/*&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;3.清理缓存&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/proc/sys/vm/drop_caches&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;/proc/sys/vm/drop_caches&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Redis安装</title>
      <link>https://note.lican.site/posts/redis%E5%AE%89%E8%A3%85/</link>
      <pubDate>Fri, 11 Aug 2023 11:06:39 +0800</pubDate>
      <guid>https://note.lican.site/posts/redis%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h3 id=&#34;redis安装&#34;&gt;redis安装&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;在./docker-compose中，增加service，实例如下&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.7&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;redis&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;redis:5.0.13&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;redis&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 时区&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;TZ=Asia/Shanghai&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 启动附加持久化存储及密码&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;command&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;redis-server --appendonly yes --requirepass k5tWl7hhhYF^$tEL%SeE&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 数据卷&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./redis/data:/data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;json-file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10M&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Mysql安装</title>
      <link>https://note.lican.site/posts/mysql%E5%AE%89%E8%A3%85/</link>
      <pubDate>Tue, 27 Jun 2023 11:04:55 +0800</pubDate>
      <guid>https://note.lican.site/posts/mysql%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h3 id=&#34;mysql安装&#34;&gt;mysql安装&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;在./docker-compose中，增加service，实例如下&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.7&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# mysql数据库&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;mysql&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;mysql:5.7.35&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;mysql&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# root 密码 &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;MYSQL_ROOT_PASSWORD=h!AlL608nGLnY3Abe0KL&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 时区&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;TZ=Asia/Shanghai&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 数据及配置挂载到容器，在第一次启动容器后，复制出来，然后重建容器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# - ./mysql/lib/mysql:/var/lib/mysql&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# - ./mysql/conf.d:/etc/mysql/conf.d&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;json-file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10M&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;数据及配置挂载&#34;&gt;数据及配置挂载&lt;/h1&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;复制容器文件到主机&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cd&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;复制数据&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cp&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;复制配置&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;docker&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cp&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;修改docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compose&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;lib&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;mysql配置&#34;&gt;mysql配置&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;需要修改./mysql/conf.d/my.cnf&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;因为mysql5.7以后，mysql的sql_mode默认配置为ONLY_FULL_GROUP_BY,该值表示：对于使用 GROUP BY 进行查询的SQL，不允许 SELECT 部分出现 GROUP BY 中未出现的字段&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;mysqld&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sql_mode&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;STRICT_TRANS_TABLES&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;ERROR_FOR_DIVISION_BY_ZERO&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;NO_AUTO_CREATE_USER&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;NO_ENGINE_SUBSTITUTION&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;&#xA;&lt;p&gt;解释&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;STRICT_TRANS_TABLES,选项针对事务性存储引擎生效，对于非事务性存储引擎无效，该选项表示开启strict sql模式&lt;/li&gt;&#xA;&lt;li&gt;ERROR_FOR_DIVISION_BY_ZERO,INSERT或者UPDATE语句中，如果数据被0除，则出现警告（非strict sql模式下）或者错误(strict sql模式下)&lt;/li&gt;&#xA;&lt;li&gt;NO_AUTO_CREATE_USER,之前版本中使用GRANT语法，如果用户不存在则会自动创建用户，该选项限制该功能&lt;/li&gt;&#xA;&lt;li&gt;NO_ENGINE_SUBSTITUTION,在使用CREATE TABLE或者ALTER TABLE语法执行存储引擎的时候，如果设定的存储引擎被禁用或者未编译，会产生错误。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;严格模式下，mysql自身会对数据进行严格的校验（格式、长度、类型等），比如一个整型字段我们写入一个字符串类型的数据，在非严格模式下MySQL不会报错，同样如果定义了char或varchar类型的字段，当写入或更新的数据超过了定义的长度也不会报错。我认为这个对于编程来说没有任何好处，虽然我们尽量在代码中做数据校验。MySQL开启了严格模式从一定程序上来讲师对我们代码的一种测试，如果我们的开发环境没有开启严格模式在开发过程中也没有遇到错误，那么在上线或代码移植的时候将有可能出现不兼容的情况，因此在开发过程做最好开启MySQL的严格模式。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Nginx安装</title>
      <link>https://note.lican.site/posts/nginx%E5%AE%89%E8%A3%85/</link>
      <pubDate>Sun, 21 May 2023 11:01:45 +0800</pubDate>
      <guid>https://note.lican.site/posts/nginx%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h3 id=&#34;nginx安装&#34;&gt;nginx安装&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;在./docker-compose中，增加service，实例如下&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.7&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;# nginx web服务器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;nginx&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx:1.21&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nginx&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 运行依赖，保证其它程序先启动&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 如果还有其它程序，则依次添加在这里&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;depends_on&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;php&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 指定时区&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;TZ=Asia/Shanghai&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 数据卷挂载&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 配置挂载到容器，在第一次启动容器后，复制出来，然后重建容器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# - ./nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# - ./nginx/conf.d:/etc/nginx/conf.d&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 证书目录&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# ./nginx/ssl:/ssl&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#75715e&#34;&gt;# 数据卷挂载到容器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./front:/front&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#ae81ff&#34;&gt;./back:/back&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 日志&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;json-file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10M&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;max-file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;# 容器发生意外时，能自动重启&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;nginx-配置参考&#34;&gt;nginx 配置参考&lt;/h3&gt;&#xA;&lt;h2 id=&#34;1nginxconf&#34;&gt;1、nginx.conf&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;client_max_body_size 需要配置一下，否则上传大文件会失败&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;worker_processes&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;auto&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;error_log&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;notice&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pid&lt;/span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;run&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pid&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;worker_connections&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;1024&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;include&lt;/span&gt;       &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;types&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;default_type&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;octet&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;stream&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log_format&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;remote_addr&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;remote_user&lt;/span&gt; [&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;time_local&lt;/span&gt;] &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$request&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;body_bytes_sent&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$http_referer&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$http_user_agent&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;$http_x_forwarded_for&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;access_log&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;access&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;sendfile&lt;/span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tcp_nopush&lt;/span&gt;     &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;keepalive_timeout&lt;/span&gt;  &lt;span style=&#34;color:#ae81ff&#34;&gt;65&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;开启gzip&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gzip&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;启用gzip压缩的最小文件&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;；&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;小于设置值的文件将不会被压缩&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gzip_min_length&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gzip&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;压缩级别&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gzip_comp_level&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;进行压缩的文件类型&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gzip_types&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;text&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;plain&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;javascript&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;javascript&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;text&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;css&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;xml&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;text&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;javascript&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;httpd&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;jpeg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gif&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;png&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;是否在http&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;header中添加Vary&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;Accept&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Encoding&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;建议开启&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gzip_vary&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;这个最好配置一下&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;否则上传大文件会失败&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;client_max_body_size&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;include&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/*&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;conf&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;vhost配置&#34;&gt;vhost配置&lt;/h3&gt;&#xA;&lt;h4 id=&#34;农场示例&#34;&gt;农场，示例&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host主机&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;可以多个&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host1&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host2&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;front&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;htm&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;农场大数据示例&#34;&gt;农场大数据，示例&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;admin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;front&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;admin&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;htm&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;农场销售页面示例&#34;&gt;农场销售页面，示例&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host主机&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;可以多个&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host1&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host2&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sales&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;front&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;sales&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;htm&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;农场溯源示例&#34;&gt;农场溯源，示例&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host主机&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;可以多个&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host1&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;host2&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;front&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;html&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;htm&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;php&#34;&gt;php&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;farm&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;api&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;back&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;public&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;下面三行是为了支持跨域&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Origin&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Headers&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;X&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Requested&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;With&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Methods&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;POST&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;OPTIONS&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (!&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;request_filename&lt;/span&gt;){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;rewrite&lt;/span&gt;  ^(.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;last&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt; ~ &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;(.&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_pass&lt;/span&gt;   &lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;9000&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_index&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;index&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_split_path_info&lt;/span&gt;  ^((&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;?&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;U&lt;/span&gt;).&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;\&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;)(&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;?&lt;/span&gt;.&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;)&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_param&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;SCRIPT_FILENAME&lt;/span&gt;   &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;document_root&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_script_name&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_param&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;PATH_INFO&lt;/span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_path_info&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;include&lt;/span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fastcgi_params&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;hls直播&#34;&gt;hls直播&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;80&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;live&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;xxx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;com&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;srs&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hls&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;live&lt;/span&gt; {  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;新摄像头服务&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;HLS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;types&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;application&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;vnd&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;apple&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;mpegurl&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m3u8&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#a6e22e&#34;&gt;video&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mp2t&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ts&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Origin&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Credentials&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Methods&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;POST&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OPTIONS&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Access&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Allow&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Headers&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Cache&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Control&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;no&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cache&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;https配置支持&#34;&gt;https配置支持&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;listen&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;443&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;注意这里的路径ssl为容器nginx的路径&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;使用前&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;注意在docker&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;compose中做数据卷映射&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;如&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;：&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_certificate&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fullchain&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_certificate_key&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;OCSP&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Stapling&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;开启&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;。&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;OCSP是用于在线查询证书吊销情况的服务&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;使用OCSP&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Stapling能将证书有效状态的信息缓存到服&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;务器&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;提高&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TLS&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;握手速度&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_stapling&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_stapling_verify&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;on&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_trusted_certificate&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;nginx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/*&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;nongbotech&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cn&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fullchain&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pem&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;resolver&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8.8.8.8&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8.8.4.4&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.1.1.1&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;valid&lt;/span&gt;=&lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;resolver_timeout&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;http请求重定向到https&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; (&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ssl_protocol&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;) {&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;301&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;https&lt;/span&gt;:&lt;span style=&#34;color:#75715e&#34;&gt;//$host$request_uri;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;反向代理设置代理头&#34;&gt;反向代理，设置代理头&lt;/h4&gt;&#xA;&lt;p&gt;使后端可以获取真实的host地址及ip&lt;/p&gt;</description>
    </item>
    <item>
      <title>Php安装</title>
      <link>https://note.lican.site/posts/php%E5%AE%89%E8%A3%85/</link>
      <pubDate>Thu, 16 Mar 2023 11:08:40 +0800</pubDate>
      <guid>https://note.lican.site/posts/php%E5%AE%89%E8%A3%85/</guid>
      <description>&lt;h3 id=&#34;php安装&#34;&gt;php安装&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;在./docker-compose中，增加service，实例如下&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;version&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;3.7&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;services&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fpm&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;devilbox&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fpm&lt;/span&gt;:&lt;span style=&#34;color:#ae81ff&#34;&gt;7.2&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;prod&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;container_name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;php&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;depends_on&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mysql&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;redis&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;environment&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;TZ&lt;/span&gt;=&lt;span style=&#34;color:#a6e22e&#34;&gt;Asia&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Shanghai&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;volumes&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;配置挂载到容器&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;在第一次启动容器后&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;复制出来&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;，&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;然后重建容器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;usr&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;local&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;etc&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;数据卷挂载到容器&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;front&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;front&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; .&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;back&lt;/span&gt;:&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;back&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;#&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;以root方式启动&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fpm&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;logging&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;driver&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;json&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#a6e22e&#34;&gt;options&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10M&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;max&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;10&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;restart&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;always&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;php配置&#34;&gt;php配置&lt;/h1&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;修改php配置，使其以root角色启动，否则容易出现文件夹读写权限的问题&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;容器php-fpm以root方式启动&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;command&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;php&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fpm&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;R&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;修改./php/etc/php-fpm.conf&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;############################################################&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;and&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Group&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;; &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;############################################################&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;www&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;user&lt;/span&gt;  = &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;group&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;root&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;配置./php/etc/php/php.ini,避免木马攻击&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;disable_functions&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;assert&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;system&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;passthru&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;shell_exec&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;exec&lt;/span&gt;,&lt;span style=&#34;color:#a6e22e&#34;&gt;popen&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    <item>
      <title>Go1.18 新特性：新增好用的 Cut 方法</title>
      <link>https://note.lican.site/posts/posts/go/118-cut/</link>
      <pubDate>Sat, 05 Feb 2022 16:03:31 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/118-cut/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在各种写业务代码的时候，大家会常常要处理字符串的内容。常见的像是用邮箱登陆账号，如果是：eddycjy@gmail.com，那就得根据 @ 来切割，分别取出前和后，来识别用户名和邮箱地址。&lt;/p&gt;&#xA;&lt;p&gt;这种需求，在 Go 里写起来方便吗？今天就由煎鱼带大家了解。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;h3 id=&#34;重复代码&#34;&gt;重复代码&lt;/h3&gt;&#xA;&lt;p&gt;无独有偶，Ainar Garipov 在许多项目中遇到了前面我们所提的切割需求。&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Index&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;[:&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;又或是：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;LastIndex&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;address&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;@&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;address&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;idx&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;host&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;address&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;经常要反复写一些繁琐的代码，提案提出者表示不愉快。&lt;/p&gt;&#xA;&lt;h2 id=&#34;新提案&#34;&gt;新提案&lt;/h2&gt;&#xA;&lt;h3 id=&#34;实施内容&#34;&gt;实施内容&lt;/h3&gt;&#xA;&lt;p&gt;建议新增 Cut 方法到 strings 标准库：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Cut&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;sep&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;before&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;after&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;found&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Index&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;sep&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[:&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;len(&lt;span style=&#34;color:#a6e22e&#34;&gt;sep&lt;/span&gt;):], &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同步也要在 bytes 标准库：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Cut&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;sep&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;before&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;after&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;found&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样一来，就可以从原本的：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IndexByte&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;rec&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;=&amp;#39;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ErrHeader&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;rec&lt;/span&gt;[:&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;rec&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;eq&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;:]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;变成：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.18 新特性：编译后的二进制文件，将包含更多信息</title>
      <link>https://note.lican.site/posts/posts/go/118-build-info/</link>
      <pubDate>Sat, 05 Feb 2022 16:02:45 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/118-build-info/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;我有一个朋友，，开开心心入职，想着施展拳脚，第一个任务就是对老旧的二进制文件进行研究。&lt;/p&gt;&#xA;&lt;p&gt;他一看，这文件，不知道是编译器用什么参数怎么打出来的，环境不知道是什么，更不知道来自什么代码分支？&lt;/p&gt;&#xA;&lt;p&gt;这除了是项目流程上的问题外，Go 在这块也有类似的小问题，处理起来比较麻烦。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;日常中很难从 Go 二进制文件中检索元信息，要么是信息完全缺失，要么提取需要对二进制文件进行大量解析。&lt;/p&gt;&#xA;&lt;p&gt;包含的元信息如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;元信息&lt;/th&gt;&#xA;          &lt;th&gt;提取处&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 构建版本&lt;/td&gt;&#xA;          &lt;td&gt;符号表，通过全局变量 &lt;code&gt;runtime.buildVersion&lt;/code&gt; 来获取&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;构建信息，例如：模块和版本&lt;/td&gt;&#xA;          &lt;td&gt;符号表，通过全局变量 &lt;code&gt;runtime/debug.modinfo&lt;/code&gt; 来获取&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;编译器选项，例如：构建模式、编译器、gcflags、ldflags 等&lt;/td&gt;&#xA;          &lt;td&gt;无法获取&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;用户定义的自定义数据，例如：应用程序版本等&lt;/td&gt;&#xA;          &lt;td&gt;需在编译时设置全局字符串变量，才可以获取&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;关注到编译器选项，也就是参数等都是无法得知的，也就是会提高获取如何编译出来的难度。&lt;/p&gt;&#xA;&lt;h2 id=&#34;新提案&#34;&gt;新提案&lt;/h2&gt;&#xA;&lt;p&gt;Michael Obermüller 提出了一个新的提案《&lt;a href=&#34;https://github.com/golang/go/issues/35667&#34;&gt;cmd/go: add compiler flags, relevant env vars to &amp;lsquo;go version -m&amp;rsquo; output&lt;/a&gt;》用于解决上述问题。&lt;/p&gt;&#xA;&lt;p&gt;在提案中想要的是 JSON 格式的结构输出：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;go1.13.4&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;compileropts&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;compiler&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gc&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;mode&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;pie&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;linux&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;buildinfo&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;main&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;path&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;HelloWorld&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(devel)&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;deps&amp;#34;&lt;/span&gt;: []&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    },&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;user&amp;#34;&lt;/span&gt;: {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;&amp;#34;customkey&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;customval&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Russ Cox 表示由于编译信息已有既有格式，并且默认使用 JSON 只会让二进制文件变得更大。好处少，没必要，改为了选项化的支持。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.18 新特性：多 Module 工作区模式</title>
      <link>https://note.lican.site/posts/posts/go/118-module/</link>
      <pubDate>Sat, 05 Feb 2022 16:00:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/118-module/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;Go 的依赖管理，也就是 Go Module。从推出到现在，也已经有了一定的年头了，吐槽一直很多，官方也不断地在进行完善。&lt;/p&gt;&#xA;&lt;p&gt;Go1.18 将会推出一个新特性：Multi-Module Workspaces，用于支持 Module 多工作区，能解决以往的一系列问题。&lt;/p&gt;&#xA;&lt;p&gt;今天将由煎鱼带大家一起深入学习。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;在日常使用 Go 工程时，总会遇到 2 个经典问题，特别的折腾人。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;依赖本地 replace module。&lt;/li&gt;&#xA;&lt;li&gt;依赖本地未发布的 module。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;replace-module&#34;&gt;replace module&lt;/h3&gt;&#xA;&lt;p&gt;第一个场景：像是平时在 Go 工程中，我们为了解决一些本地依赖，或是定制化代码。会在 go.mod 文件中使用 replace 做替换。&lt;/p&gt;&#xA;&lt;p&gt;如下代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;replace&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;golang&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;org&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;net&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Users&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;eddycjy&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;awesomeProject&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样就可以实现本地开发联调时的准确性。&lt;/p&gt;&#xA;&lt;p&gt;问题就在这里：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;本地路径：所设定的 replace 本质上转换的是本地的路径，也就是每个人都不一样。&lt;/li&gt;&#xA;&lt;li&gt;仓库依赖：文件修改是会上传到 Git 仓库的，不小心传上去了，影响到其他开发同学，又或是每次上传都得重新改回去。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;用户体验非常差，很折腾人。&lt;/p&gt;&#xA;&lt;h3 id=&#34;未发布的-module&#34;&gt;未发布的 module&lt;/h3&gt;&#xA;&lt;p&gt;第二个场景：在做本地的 Go 项目开发时，可能会在本地同时开发多个库（项目库、工具库、第三方库）等。&lt;/p&gt;&#xA;&lt;p&gt;如下代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/eddycjy/pkgutil&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;pkgutil&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PrintFish&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果这个时候运行 &lt;code&gt;go run&lt;/code&gt; 或是 &lt;code&gt;go mod tidy&lt;/code&gt;，都不行，会运行失败。&lt;/p&gt;&#xA;&lt;p&gt;报如下类似错误：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fatal: repository &amp;#39;https://github.com/eddycjy/pkgutil/&amp;#39; not found&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个问题报错是因为 &lt;code&gt;github.com/eddycjy/pkgutil&lt;/code&gt; 这个库，在 GitHub 是没有的，自然也就拉取不到。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么 Go 有两种声明变量的方式，有什么区别，哪种好？</title>
      <link>https://note.lican.site/posts/posts/go/var/</link>
      <pubDate>Sat, 05 Feb 2022 15:56:48 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/var/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;有一个读者刚入门 Go ，提了一个很有意思的问题：Go 有几种种声明变量的方式，作为初学者，到底用哪种，有什么区别，又为什么要有多种声明方式呢？&lt;/p&gt;&#xA;&lt;p&gt;为此，煎鱼将和大家一起探索这个问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;变量声明&#34;&gt;变量声明&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 中，一共有 2 种变量声明的方式，各有不同的使用场景。&lt;/p&gt;&#xA;&lt;p&gt;分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;标准变量声明（Variable declarations）。&lt;/li&gt;&#xA;&lt;li&gt;简短变量声明（Short variable declarations）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;标准声明&#34;&gt;标准声明&lt;/h3&gt;&#xA;&lt;p&gt;变量声明创建了一个或多个变量，为它们绑定了相应的标识符，并给每个变量一个类型和初始值。&lt;/p&gt;&#xA;&lt;p&gt;使用语法：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VarDecl&lt;/span&gt;     = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;var&amp;#34;&lt;/span&gt; ( &lt;span style=&#34;color:#a6e22e&#34;&gt;VarSpec&lt;/span&gt; | &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;(&amp;#34;&lt;/span&gt; { &lt;span style=&#34;color:#a6e22e&#34;&gt;VarSpec&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;;&amp;#34;&lt;/span&gt; } &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;)&amp;#34;&lt;/span&gt; ) .&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;VarSpec&lt;/span&gt;     = &lt;span style=&#34;color:#a6e22e&#34;&gt;IdentifierList&lt;/span&gt; ( &lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt; [ &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ExpressionList&lt;/span&gt; ] | &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;=&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ExpressionList&lt;/span&gt; ) .&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;案例代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;U&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;W&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float32&lt;/span&gt; = &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;u&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2.0&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;简短声明&#34;&gt;简短声明&lt;/h3&gt;&#xA;&lt;p&gt;一个短变量声明。使用语法：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ShortVarDecl = IdentifierList &amp;#34;:=&amp;#34; ExpressionList .&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;案例代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼进脑子了&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;w&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pipe&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;coord&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;网友疑惑&#34;&gt;网友疑惑&lt;/h2&gt;&#xA;&lt;p&gt;在我们群里的 Go 读者提了这问题后，我也搜了搜相关资料。发现在 stackoverflow 上也有人提出了类似的疑惑：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 为什么不在语言层面支持 map 并发？</title>
      <link>https://note.lican.site/posts/posts/go/map-con/</link>
      <pubDate>Sat, 05 Feb 2022 15:55:22 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map-con/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;很多小伙伴学习 Go 语言的语法时，可能只是轻轻地看到过这个问题，结果一旦上手，多多少少一个组内总会碰到过几次。&lt;/p&gt;&#xA;&lt;p&gt;甚至会发现有一定年限的程序员也会遇到。有小伙伴疑惑了，这么折腾，为什么 Go 不直接在语言层面就支持 map 并发，那得有多香？&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么原生不支持&#34;&gt;为什么原生不支持&lt;/h2&gt;&#xA;&lt;p&gt;凭什么 Go 官方还不支持，难不成太复杂了，性能太差了，到底是为什么？&lt;/p&gt;&#xA;&lt;p&gt;官方答复原因如下（via @go faq）：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;典型使用场景：map 的典型使用场景是不需要从多个 goroutine 中进行安全访问。&lt;/li&gt;&#xA;&lt;li&gt;非典型场景（需要原子操作）：map 可能是一些更大的数据结构或已经同步的计算的一部分。&lt;/li&gt;&#xA;&lt;li&gt;性能场景考虑：若是只是为少数程序增加安全性，导致 map 所有的操作都要处理 mutex，将会降低大多数程序的性能。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;核心来讲就是：Go 团队在经过了长时间的讨论后，认为原生 map 更应适配典型使用场景。&lt;/p&gt;&#xA;&lt;p&gt;如果为了小部分情况，将&lt;strong&gt;会导致大部分程序付出性能代价&lt;/strong&gt;，决定了不支持原生的并发 map 读写。且在 Go1.6 起，&lt;strong&gt;增加了检测机制&lt;/strong&gt;，并发的话会导致异常。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要崩溃&#34;&gt;为什么要崩溃&lt;/h2&gt;&#xA;&lt;p&gt;前面有提到一点，在 Go1.6 起会进行原生 map 的并发检测，这是一些人的 “噩梦”。&lt;/p&gt;&#xA;&lt;p&gt;在此有人吐槽到：“明明给我抛个错就好了，凭什么要让我的 Go 进程直接崩溃掉，分分钟给我背个 P0”。&lt;/p&gt;&#xA;&lt;h3 id=&#34;场景枚举&#34;&gt;场景枚举&lt;/h3&gt;&#xA;&lt;p&gt;这里我们假设一下，如果并发读写 map 是以下两种场景：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;产生 panic：程序 panic -&amp;gt; 默认走进 recover -&amp;gt; 没有对并发 map 进行处理 -&amp;gt; map 存在脏数据 -&amp;gt; 程序使用脏数据 -&amp;gt; 产生**未知((影响。&lt;/li&gt;&#xA;&lt;li&gt;产生 crash：程序 crash -&amp;gt; 直接崩溃 -&amp;gt; 保全数据（数据正常）-&amp;gt; 产生**明确((风险。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;你会选择哪一种方案呢？Go 官方在两者的风险衡量中选择了第二种。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 泛型的 3 个核心设计，你学会了吗？</title>
      <link>https://note.lican.site/posts/posts/go/generics-design/</link>
      <pubDate>Sat, 05 Feb 2022 15:52:46 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/generics-design/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;Go1.18 的泛型是闹得沸沸扬扬，虽然之前写过很多篇针对泛型的一些设计和思考。但因为泛型的提案之前一直还没定型，所以就没有写完整介绍。&lt;/p&gt;&#xA;&lt;p&gt;如今已经基本成型，就由煎鱼带大家一起摸透 Go 泛型。本文内容主要涉及泛型的 3 大概念，非常值得大家深入了解。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;类型参数。&lt;/li&gt;&#xA;&lt;li&gt;类型约束。&lt;/li&gt;&#xA;&lt;li&gt;类型推导。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;类型参数&#34;&gt;类型参数&lt;/h2&gt;&#xA;&lt;p&gt;类型参数，这个名词。不熟悉的小伙伴咋一看就懵逼了。&lt;/p&gt;&#xA;&lt;p&gt;泛型代码是使用抽象的数据类型编写的，我们将其称之为类型参数。当程序运行通用代码时，类型参数就会被类型参数所取代。也就是&lt;strong&gt;类型参数是泛型的抽象数据类型&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;简单的泛型例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;代码有一个 &lt;code&gt;Print&lt;/code&gt; 函数，它打印出一个片断的每个元素，其中片断的元素类型，这里称为 T，是未知的。&lt;/p&gt;&#xA;&lt;p&gt;这里引出了一个要做泛型语法设计的点，那就是：T 的&lt;strong&gt;泛型类型参数，应该如何定义&lt;/strong&gt;？&lt;/p&gt;&#xA;&lt;p&gt;在现有的设计中，分为两个部分：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;类型参数列表：&lt;strong&gt;类型参数列表将会出现在常规参数的前面&lt;/strong&gt;。为了区分类型参数列表和常规参数列表，类型参数列表&lt;strong&gt;使用方括号&lt;/strong&gt;而不是小括号。&lt;/li&gt;&#xA;&lt;li&gt;类型参数约束：如同常规参数有类型一样，类型参数也有元类型，被称为约束（后面会进一步介绍）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;结合完整的例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Print 可以打印任何片断的元素。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Print 有一个类型参数 T，并有一个单一的（非类型）的 s，它是该类型参数的一个片断。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// do something...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，我们声明了一个函数 &lt;code&gt;Print&lt;/code&gt;，其有一个类型参数 T，类型约束为 &lt;code&gt;any&lt;/code&gt;，表示为任意的类型，作用与 &lt;code&gt;interface{}&lt;/code&gt; 一样。他的入参变量 &lt;code&gt;s&lt;/code&gt; 是类型 T 的切片。&lt;/p&gt;&#xA;&lt;p&gt;函数声明完了，在函数调用时，我们需要指定类型参数的类型。如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;]([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，我们指定了传入的类型参数为 int，并传入了 &lt;code&gt;[]int{1, 2, 3}&lt;/code&gt; 作为参数。&lt;/p&gt;&#xA;&lt;p&gt;其他类型，例如 float64:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 读者提问：值为 nil 也能调用函数，太神奇了吧？</title>
      <link>https://note.lican.site/posts/posts/go/nil-func/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:27 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/nil-func/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近在我们 Go 的技术交流群里，有一个小伙伴提了一个程序方面的问题，还挺有意思的，分享给大家。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/0774f643-81a2-4458-b557-05c81a9572ef.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;示例&#34;&gt;示例&lt;/h2&gt;&#xA;&lt;p&gt;示例程序如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Hello&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼进脑子了&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Hello&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段程序的运行结果是什么？&lt;/p&gt;&#xA;&lt;p&gt;从程序的分析来看，变量 &lt;code&gt;t&lt;/code&gt; 并没有初始化，只是声明了类型。然后就直接调用了 &lt;code&gt;Hello&lt;/code&gt; 方法，像是 nil 调用函数，理论上应该出现恐慌（panic）。&lt;/p&gt;&#xA;&lt;p&gt;运行结果是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;panic: runtime error: invalid memory address or nil pointer dereference&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对不对呢？&lt;/p&gt;&#xA;&lt;p&gt;显然，真正的运行结果是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;脑子进煎鱼了&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请你思考一下，想想这是为什么？&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么&#34;&gt;为什么&lt;/h2&gt;&#xA;&lt;p&gt;问题的原因是：很多小伙伴认为变量 &lt;code&gt;t&lt;/code&gt; 的值都是 nil 了，不应该还能调用到才对。&lt;/p&gt;&#xA;&lt;p&gt;更抽象化来讲，就是 ”程序是如何检查对象指针来寻找和调度所需函数“。&lt;/p&gt;&#xA;&lt;p&gt;实际上，在 Go 中，表达式 &lt;code&gt;Expression.Name&lt;/code&gt; 的语法，所调用的函数完全由 &lt;code&gt;Expression&lt;/code&gt; 的类型决定。&lt;/p&gt;&#xA;&lt;p&gt;其调用函数的指向不是由该表达式的特定运行时值来决定，包括我们前面所提到的 nil。&lt;/p&gt;&#xA;&lt;p&gt;具体如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Sometype&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Somemethod&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;firstArg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本质上是：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 有哪些无法恢复的致命场景？</title>
      <link>https://note.lican.site/posts/posts/go/throw/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:26 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/throw/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;有一次事故现场，在紧急恢复后，他正在排查代码，查了好一会。我回头一看，这错误提醒很明显就是致命错误，较好定位。&lt;/p&gt;&#xA;&lt;p&gt;但此时，他竟然在查 panic-recover 是不是哪里漏了，我表示大受震惊&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;今天就由煎鱼给大家分享一下错误类型有哪几种，又在什么场景下会触发。&lt;/p&gt;&#xA;&lt;h2 id=&#34;错误类型&#34;&gt;错误类型&lt;/h2&gt;&#xA;&lt;h3 id=&#34;error&#34;&gt;error&lt;/h3&gt;&#xA;&lt;p&gt;第一种是 Go 中最标准的 error 错误，其真身是一个 interface{}。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在日常工程中，我们只需要创建任意结构体，实现了 Error 方法，就可以认为是 error 错误类型。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errorString&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;errorString&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在外部调用标准库 API，一般如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;filename.ext&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// do something with the open *File f&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们会约定最后一个参数为 error 类型，一般常见于第二个参数，可以有个约定俗成的习惯。&lt;/p&gt;&#xA;&lt;h3 id=&#34;panic&#34;&gt;panic&lt;/h3&gt;&#xA;&lt;p&gt;第二种是 Go 中的异常处理 panic，能够产生异常错误，结合 panic+recover 可以扭转程序的运行状态。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    panic(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;a problem&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Create&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tmp/file&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>长达 12 年，Go 才引入泛型，是政治，还是技术问题？</title>
      <link>https://note.lican.site/posts/posts/go/import-generics/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:25 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/import-generics/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前两天 Go1.18 beta1 已经发布，距离正式发布 Go1.18 的生产可用还有 2 个月，也就是泛型即将正式面世。&lt;/p&gt;&#xA;&lt;p&gt;最近正在收集泛型的一些资料，看到在 2015 年有人在 Hacker News 上的《&lt;a href=&#34;https://news.ycombinator.com/item?id=9622417&#34; title=&#34;Go 1.5 max procs default&#34;&gt;Go 1.5 max procs default&lt;/a&gt;》吐槽 Go 不支持泛型是 “政治” 原因&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;看了还是有些意义的，&lt;strong&gt;与现在的矛盾点基本一致&lt;/strong&gt;，为此分享给大家。&lt;/p&gt;&#xA;&lt;h2 id=&#34;网友吐槽&#34;&gt;网友吐槽&lt;/h2&gt;&#xA;&lt;p&gt;网友 @aikah 认为 Go 团队不太可能在语言中加入泛型，这显然是一个政治问题而不是技术问题。错误处理也是如此。&lt;/p&gt;&#xA;&lt;p&gt;和许多人一样，该网友&lt;strong&gt;认为 Go 在极简主义和功能之间没有取得正确的平衡&lt;/strong&gt;。反对泛型的人赞成用编译时类型检查（总是安全的）换取运行时类型断言（可能失败）。&lt;/p&gt;&#xA;&lt;p&gt;他们拒绝承认这一事实。这就是他们反对泛型的论点，并将最终损害语言的任何潜在增长。他们基本上是在违背自己的利益。&lt;/p&gt;&#xA;&lt;h2 id=&#34;官方回复&#34;&gt;官方回复&lt;/h2&gt;&#xA;&lt;p&gt;Russ Cox 做了正式的回复：很抱歉，但不是：&lt;strong&gt;泛型是一个技术问题&lt;/strong&gt;，不是一个政治问题。&lt;/p&gt;&#xA;&lt;p&gt;Go 团队并&lt;strong&gt;不反对泛型本身&lt;/strong&gt;，只是反对做那些没有被很好理解或不能很好地与 Go 配合的事情。&lt;/p&gt;&#xA;&lt;p&gt;这就是核心观点和矛盾点，也从 2009 年，延续到了现在。&lt;/p&gt;&#xA;&lt;h3 id=&#34;会遇到的问题&#34;&gt;会遇到的问题&lt;/h3&gt;&#xA;&lt;p&gt;Go 团队认为要将泛型的概念融入 Go，并与系统的其他部分很好地配合，必须解决一些深层次的技术问题，而我们并没有解决这些问题的办法。&lt;/p&gt;&#xA;&lt;p&gt;关于这些问题，在几年前就在博客上写过一篇《&lt;a href=&#34;https://research.swtch.com/generic&#34; title=&#34;The Generic Dilemma&#34;&gt;The Generic Dilemma&lt;/a&gt;》：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/8ed3923a-d5fc-482f-bb6d-6fff7a19fcaa.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;即使克服了那一页上的问题，也有其他问题，接下来你会遇到的问题是：”如何让程序员以一种有用的、易于解释的方式省略类型注释“。&lt;/p&gt;&#xA;&lt;p&gt;也就是如何更人性、更易于的表达泛型的类型参数。&lt;/p&gt;&#xA;&lt;h4 id=&#34;泛型例子&#34;&gt;泛型例子&lt;/h4&gt;&#xA;&lt;p&gt;举个例子，C++ 允许你写 &lt;code&gt;make_pair(1, &amp;quot;foo&amp;quot;)&lt;/code&gt;，而不是 &lt;code&gt;make_pair&amp;lt;int, string&amp;gt;(1, &amp;quot;foo&amp;quot;)&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;为了达到这种效果，推断注释背后的逻辑需要几页几页的规范，这并不是一个特别容易理解的编程模型，当事情出错时，编译器也不能轻易解释。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 为什么不支持可重入锁？</title>
      <link>https://note.lican.site/posts/posts/go/again-mutex/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:24 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/again-mutex/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;程序里的锁，是很多小伙伴在写分布式应用时用的最多的一个利器之一。&lt;/p&gt;&#xA;&lt;p&gt;使用 Go 的同学里，绝大部分都有其他语言的经验，就会对其中一点有疑惑，那就是 &lt;strong&gt;Go 里的锁，竟然不支持可重入&lt;/strong&gt;？&lt;/p&gt;&#xA;&lt;p&gt;为此，今天煎鱼带大家一起来了解这里的设计考量，看看为什么。&lt;/p&gt;&#xA;&lt;h2 id=&#34;可重入锁&#34;&gt;可重入锁&lt;/h2&gt;&#xA;&lt;p&gt;如果对已经上锁的普通互斥锁进行 “加锁” 操作，其结果要么失败，要么会阻塞至解锁。&lt;/p&gt;&#xA;&lt;p&gt;锁的场景如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在加锁上：如果是可重入互斥锁，当前尝试加锁的线程如果就是持有该锁的线程时，加锁操作就会成功。&lt;/li&gt;&#xA;&lt;li&gt;在解锁上：可重入互斥锁一般都会记录被加锁的次数，只有执行相同次数的解锁操作才会真正解锁。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;简单来讲，可重入互斥锁是互斥锁的一种，同一线程对其多次加锁不会产生死锁，又或是导致阻塞。&lt;/p&gt;&#xA;&lt;p&gt;不同语言间实现可能或多或少有些区别，但大体意思差不多。&lt;/p&gt;&#xA;&lt;p&gt;请你想一下，Go 是怎么样的呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-支持情况&#34;&gt;Go 支持情况&lt;/h2&gt;&#xA;&lt;p&gt;我们看到以下这个 Go 互斥锁例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mutex&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mu&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Lock&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这段 Go 程序会阻塞吗？不会，会报以下错误：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;fatal error: all goroutines are asleep - deadlock!&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go 显然是不支持可重入互斥锁的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;官方回复&#34;&gt;官方回复&lt;/h2&gt;&#xA;&lt;h3 id=&#34;go-设计原则&#34;&gt;Go 设计原则&lt;/h3&gt;&#xA;&lt;p&gt;在工程中使用互斥的根本原因是：为了保护不变量，也可以用于保护内、外部的不变量。&lt;/p&gt;&#xA;&lt;p&gt;基于此，Go 在互斥锁设计上会遵守这几个原则。如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在调用 &lt;code&gt;mutex.Lock&lt;/code&gt; 方法时，要保证这些变量的不变性保持，不会在后续的过程中被破坏。&lt;/li&gt;&#xA;&lt;li&gt;在调用 &lt;code&gt;mu.Unlock&lt;/code&gt; 方法时，要保证：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;程序不再需要依赖那些不变量。&lt;/li&gt;&#xA;&lt;li&gt;如果程序在互斥锁加锁期间破坏了它们，则需要确保已经恢复了它们。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;不支持的原因&#34;&gt;不支持的原因&lt;/h3&gt;&#xA;&lt;p&gt;讲了 Go 自己的设计原则后，那为什么不支持可重入呢？&lt;/p&gt;&#xA;&lt;p&gt;其实 Russ Cox 于 2010 年在《&lt;a href=&#34;https://groups.google.com/g/golang-nuts/c/XqW1qcuZgKg/m/Ui3nQkeLV80J&#34; title=&#34;Experimenting with GO&#34;&gt;Experimenting with GO&lt;/a&gt;》就给出了答复，认为递归（又称：重入）互斥是个坏主意，这个设计并不好。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 泛型玩出花，详解新提案 switch type！</title>
      <link>https://note.lican.site/posts/posts/go/switch-type/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:23 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/switch-type/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前面写过好几篇 Go 泛型的语法、案例介绍，新的一手 Go 消息。实际上，随着一些提案被接受，新的提案也逐渐冒出。&lt;/p&gt;&#xA;&lt;p&gt;这不，我发现有了泛型后，大家可以更进一步玩出花来了。看到了一个 ”新“ 提案《&lt;a href=&#34;https://github.com/golang/go/issues/45380&#34; title=&#34;proposal: spec: generics: type switch on parametric types&#34;&gt;proposal: spec: generics: type switch on parametric types&lt;/a&gt;》，讲的就是增加泛型后的参数类型上的类型开关诉求。&lt;/p&gt;&#xA;&lt;p&gt;跟着煎鱼一起掌握新的 Go 知识吧！&lt;/p&gt;&#xA;&lt;h2 id=&#34;新提案&#34;&gt;新提案&lt;/h2&gt;&#xA;&lt;p&gt;新的提案内容是希望增加一个新的变种语句，允许在 switch 语句中使用泛型时，能够进一步便捷的约束其类型参数。&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;A1&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;A2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;A3&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;   &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是 switch-type 语句的 &lt;strong&gt;T 类型可以是一个泛型的类型参&lt;/strong&gt;，case 所对应的的类型可以是任何类型，包括泛型的约束类型。&lt;/p&gt;&#xA;&lt;p&gt;假设类型 T 的类型有可能是以下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;A&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以借助泛型的近似元素来约束：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;C&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;A1&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;A2&lt;/span&gt; | &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;An&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;甚至还可以在 case 上有新的写法：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {~&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;}:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在支持泛型后，&lt;strong&gt;switch 在 type 和 case 上会存在很多种可能性&lt;/strong&gt;，需要进行具体的特性支持，这个提案就是为此出现。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 为什么不支持类和继承？</title>
      <link>https://note.lican.site/posts/posts/go/class-extends/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:22 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/class-extends/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;大家在早期学习 Go 时，一旦跨过语法的阶段后。马上就会进入到一个新的纠结点，Go 不支持面向对象吗？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/a299d98d-e46c-4a6d-8362-02f957e86b10.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这门编程语言里没有类（class）、继承（extends），&lt;del&gt;没法一把搜了，面试问啥面向对象（OOP）&lt;/del&gt;？&lt;/p&gt;&#xA;&lt;p&gt;今天煎鱼就带大家一起来了解这之中的思考，Go 真的不支持吗？&lt;/p&gt;&#xA;&lt;h2 id=&#34;类和继承&#34;&gt;类和继承&lt;/h2&gt;&#xA;&lt;h3 id=&#34;类是什么&#34;&gt;类是什么&lt;/h3&gt;&#xA;&lt;p&gt;类（class）在面向对象编程中是一种面向对象计算机编程语言的构造，是创建对象的蓝图，描述了所创建的对象共同的特性和方法（via @维基百科）。&lt;/p&gt;&#xA;&lt;p&gt;例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SimpleClass&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 声明属性&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; $var &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;脑子进煎鱼了&amp;#39;&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 声明方法&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;displayVar&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;echo&lt;/span&gt; $this&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;var&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个类的定义都以关键字 class 开头，后面跟着类名，后面跟着一对花括号，里面包含有类的属性与方法的定义。&lt;/p&gt;&#xA;&lt;h3 id=&#34;继承是什么&#34;&gt;继承是什么&lt;/h3&gt;&#xA;&lt;p&gt;继承是面向对象软件技术当中的一个概念，如果一个类别 B “继承自”另一个类别 A，就把这个 B 称为 “A的子类”，而把 A 称为 “B的父类别” 也可以称 “A 是 B 的超类”（via @维基百科）。&lt;/p&gt;&#xA;&lt;p&gt;例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-php&#34; data-lang=&#34;php&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 父类&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Foo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;printItem&lt;/span&gt;($string)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;煎鱼1: &amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $string &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PHP_EOL&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;printPHP&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;PHP is great.&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PHP_EOL&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// 子类&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;class&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Bar&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;extends&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Foo&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;function&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;printItem&lt;/span&gt;($string)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;echo&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;煎鱼2: &amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; $string &lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PHP_EOL&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;继承有如下两个特性：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 新关键字 any，interface 会成历史吗？</title>
      <link>https://note.lican.site/posts/posts/go/any/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:21 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/any/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;大家在看 Go1.18 泛型的代码时，不知道是否有留意到一个新的关键字 any。&lt;/p&gt;&#xA;&lt;p&gt;例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;之前没有专门提过，但有没有小伙伴以为这个关键字，是泛型代码专属的？&lt;/p&gt;&#xA;&lt;p&gt;其实不是&amp;hellip;在这次新的 Go1.18 更新中，any 是作为一个新的关键字出现，&lt;strong&gt;any 有一个真身，本质上是 interface{} 的别名&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是，在常规代码中，也可以直接使用：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.(&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;进脑子煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼进脑子了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3.1415&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼好！&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从使用层面来讲，新的关键字 any 会比 interface{} 方便不少，毕竟少打了好多个词，更快了，其实也是参照现有 rune 类型的做法。&lt;/p&gt;&#xA;&lt;p&gt;增加新关键字后的对比如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;长声明&lt;/th&gt;&#xA;          &lt;th&gt;短声明&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;func f[T interface{}](s []T) []T&lt;/td&gt;&#xA;          &lt;td&gt;func f[T any](s []T) []T&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;func f(a interface{})&lt;/td&gt;&#xA;          &lt;td&gt;func f(a any)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;var a interface{}&lt;/td&gt;&#xA;          &lt;td&gt;var a any&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;我们在了解他的便利性后，再从代码一致性和可读性来讲，是有些问题的，会造成一定的疑惑。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Rust 内讧，PHP 主力淡出？Go：好好放假</title>
      <link>https://note.lican.site/posts/posts/go/rust-php/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:20 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/rust-php/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;现在已经是 2021 年的 Q4 季度了，许多职场人都忙的飞起，被 PPT 各种轰炸。&lt;/p&gt;&#xA;&lt;p&gt;在上周，看到几门语言的社区都发生了一些大事，煎鱼表示大受震撼，来说几句我的看法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;php-主力淡出&#34;&gt;PHP 主力淡出&lt;/h2&gt;&#xA;&lt;p&gt;在 11 月 23 日，看到 PHP 的主力开发 &lt;a href=&#34;https://twitter.com/nikita_ppv&#34; title=&#34;Nikita Popov&#34;&gt;Nikita Popov&lt;/a&gt; 在论坛上发文宣布将&lt;strong&gt;不再以专业身份从事 PHP 工作&lt;/strong&gt;，投入到 PHP 开发中的时间将会大幅度减少。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/82ba0eaf-fa69-4bee-9cbc-ec385d3b9793.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;根据 Jetbrains 分享的消息来看，可得知 Nikita Popov 在高中（2011 年）时就开始参与 PHP 开发，截止现在已有 10 年经验了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/93d9d4c9-9863-42fe-9d2c-f5ada62210c2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;他离开的原因，我看了一遍帖子，众说纷纭，业内猜测有以下两个观点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;迫于生活压力，过多精力投入维护开源项目收入不高。&lt;/li&gt;&#xA;&lt;li&gt;PHP 新版本特性受阻等原因，把精力从 PHP 转到 LLVM。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;也因此，PHP 社区加速宣布成立 PHP 基金会《&lt;a href=&#34;https://blog.jetbrains.com/phpstorm/2021/11/the-php-foundation/&#34; title=&#34;The New Life of PHP – The PHP Foundation&#34;&gt;The New Life of PHP – The PHP Foundation&lt;/a&gt;》。基金会所募集的资金，将会用于资助开发者在 PHP 上工作。&lt;/p&gt;&#xA;&lt;p&gt;基金会的宣发上，讲的很清楚，为的就是&lt;strong&gt;避免再发生失去 PHP 的主要贡献者&lt;/strong&gt;的事情发生，这影响是非常之巨大的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 新语法挺丑？最新的泛型类型约束介绍</title>
      <link>https://note.lican.site/posts/posts/go/118-constraints/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:19 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/118-constraints/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;近期我们在分享《&lt;a href=&#34;https://mp.weixin.qq.com/s/22TeQOUjf_glPX3QLPX8yw&#34;&gt;3 件与 Go 开发者有关的大小事&lt;/a&gt;》时，里面有一部分有提到 Go 泛型的约束类型语法又又又变了。&lt;/p&gt;&#xA;&lt;p&gt;在评论区里看到不少的读者朋友大呼泛型的新类型约束语法挺丑，不如原本的好&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/8e734a8f-612c-41c3-a0cd-8a5fe6eea483.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;为此，今天煎鱼就带大家来看看，为什么会发生泛型的新语法会这种改变？&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题背景&#34;&gt;问题背景&lt;/h2&gt;&#xA;&lt;p&gt;原本 @Ian Lance Taylor 设计的的泛型类型关键字如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int8&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int16&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;uint64&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;float32&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;complex64&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;complex128&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看起来好像非常 “顺眼”。但在《&lt;a href=&#34;https://github.com/golang/go/issues/41716&#34; title=&#34;proposal: Go 2: sum types using interface type lists&#34;&gt;proposal: Go 2: sum types using interface type lists&lt;/a&gt;》中社区进行了热烈的讨论。&lt;/p&gt;&#xA;&lt;p&gt;认为该类型约束的关键字，过于 “模棱两可”。像是 @Damien Neil 所提出的以下两个例子。&lt;/p&gt;&#xA;&lt;p&gt;结构体的例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mustIncludeDefaultCase&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MySum&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;mustIncludeDefaultCase&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;不明确的点之一，如果类型列表包含一个未导出的类型，那又应该是如何处理呢？&lt;/p&gt;&#xA;&lt;p&gt;接口的例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; { &lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int16&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt; }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;.(&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int16&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  } &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你认为程序会跑进哪个 switch-case 的代码块里呢，是 int16，还是 int32？&lt;/p&gt;</description>
    </item>
    <item>
      <title>泛型是双刃剑？Go1.18 编译会慢近 20%</title>
      <link>https://note.lican.site/posts/posts/go/118-build/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:18 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/118-build/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;目前 Go 的泛型已经在稳定推进的过程，在 Go1.18 将会释出正式的第一版。不过前两天我看到 @danscales 提出的《cmd/compile: Go 1.18 compile time may be about 18% slower than Go.17 (largely from changes due to generics)》。&lt;/p&gt;&#xA;&lt;p&gt;作者表示在 Go1.18 有了泛型后，编译速度将会变慢，虽然不意外，说明副作用还是有的，升级需谨慎。&lt;/p&gt;&#xA;&lt;p&gt;以下为修整后概括的原文信息。&lt;/p&gt;&#xA;&lt;h2 id=&#34;性能分析&#34;&gt;性能分析&lt;/h2&gt;&#xA;&lt;p&gt;这个测试主要是测试 Go 泛型对 Go 编译器带来的影响，并没有输入大量的测试用例，是最简单的比较，仅代表大部分的差异。&lt;/p&gt;&#xA;&lt;p&gt;比较的内容是 Go 泛型的 -G=0 和 -G=3 模式下的编译时间。&lt;/p&gt;&#xA;&lt;p&gt;分别代表以下含义：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;-G=0 模式：默认不打开泛型的模式。&lt;/li&gt;&#xA;&lt;li&gt;-G=3 模式：打开泛型的模式。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Go 1.18 中的 -G=0 模式和 Go 1.17 模式的比较显示，由于非泛型的变化，编译器的速度可能降低了~1%（因为 -G=0 模式不支持泛型）。&lt;/p&gt;&#xA;&lt;p&gt;Go 1.18 的编译时间可能比 Go 1.17 慢 15-18%，这主要是由于实现泛型所带来的变化，也就是 Go1.18 开启泛型下，编译时间会变慢。&lt;/p&gt;&#xA;&lt;h2 id=&#34;差异在哪&#34;&gt;差异在哪&lt;/h2&gt;&#xA;&lt;p&gt;大部分的差异是由于新的编译器前端处理，因为 SSA 后端对于泛型完全没有变化。&lt;/p&gt;</description>
    </item>
    <item>
      <title>分享 Go 最近的几件周边大小事</title>
      <link>https://note.lican.site/posts/posts/go/news115/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:17 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/news115/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近可能是因为 Q4 了，又恰逢 Go1.18 快要发布，各路 Go 语言的新消息层出不穷。&lt;/p&gt;&#xA;&lt;p&gt;今天煎鱼带大家一起来了解下最近社区发生的几件大小事，当然，我只讲一些核心的内容。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/d6f8bfde-141c-405b-8ec5-779d31b0283d.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-诞生-12-年&#34;&gt;Go 诞生 12 年&lt;/h2&gt;&#xA;&lt;p&gt;在 2021 年 11 月 10 日，是 Go 语言开源版本的 12 岁生日。Go 官方博客发表《&lt;a href=&#34;https://go.dev/blog/12years&#34; title=&#34;Twelve Years of Go&#34;&gt;Twelve Years of Go&lt;/a&gt;》。&lt;/p&gt;&#xA;&lt;p&gt;主体内容分为三块介绍：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;回顾过去一年的核心变更。&lt;/li&gt;&#xA;&lt;li&gt;展望明年的特性计划。&lt;/li&gt;&#xA;&lt;li&gt;介绍今年做的 Go 相关分享。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;回顾过去&#34;&gt;回顾过去&lt;/h3&gt;&#xA;&lt;p&gt;是对过去一年的版本更新进行说明：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Go1.16：默认启用 Go modules，增加 MacOS ARM64 的支持，新支持文件系统接口和嵌入文件的特性。&lt;/li&gt;&#xA;&lt;li&gt;Go1.17：Go 函数改为基于寄存器的调用规范（提高了 5~15% 的性能），增加 Windows ARM64 支持，还引入了模块裁剪等功能。&lt;/li&gt;&#xA;&lt;li&gt;Go1.18：预计支持模糊测试（Go fuzzing）、泛型等强大的新特性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;核心总结：今年大力推动 Go modules，提高了 Go 函数的性能，增加了更多的计算机架构支持，以及若干改进和优化（例如：TLS）。&lt;/p&gt;&#xA;&lt;p&gt;也为了推广 Go 语言，做出了更多的努力和资料培训（Gin 也因此更上了一层楼）。&lt;/p&gt;&#xA;&lt;h3 id=&#34;后续安排&#34;&gt;后续安排&lt;/h3&gt;&#xA;&lt;p&gt;我们核心关注泛型方面的消息，泛型将会是 2022 年的核心重点之一。规划如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Go 1.18 中的初始版本只是泛型的开始，将会在此版本使用泛型并学习哪些有效、哪些无效。&lt;/li&gt;&#xA;&lt;li&gt;在确定泛型的 “实践” 后，会输出 “最佳实践”，并决定何时追加泛型实现到标准库和第三方库中。&lt;/li&gt;&#xA;&lt;li&gt;期待在 &lt;strong&gt;Go1.19&lt;/strong&gt;（也就是 2022.08）及更高版本将&lt;strong&gt;进一步完善泛型&lt;/strong&gt;的设计和实现，并将它们进一步整合到整体的 Go 体验中（也就是工具链等）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;核心总结：明年要继续大力推进泛型，先尝鲜，再出最佳实践，进而融合进 Go 体系中，路还比较远。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 为什么不支持函数重载和参数默认值？</title>
      <link>https://note.lican.site/posts/posts/go/func-reload/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:16 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/func-reload/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;大家在初学习 Go 语言时，带着其他语言的习惯，总是会有些不习惯，感觉非常不能理解，直打问号。&lt;/p&gt;&#xA;&lt;p&gt;其中一点就是 Go 语言不支持函数重载和参数默认值，觉得使用起来很不方便。&lt;/p&gt;&#xA;&lt;p&gt;为此，在这篇文章中煎鱼就和大家一起来了解为什么，有又会怎么样。&lt;/p&gt;&#xA;&lt;h2 id=&#34;函数重载&#34;&gt;函数重载&lt;/h2&gt;&#xA;&lt;p&gt;函数重载（function overloading），也叫方法重载。是某些编程语言（如 C++、C#、Java、Swift、Kotlin 等）具有的一项特性。&lt;/p&gt;&#xA;&lt;p&gt;该特性&lt;strong&gt;允许创建多个具有不同实现的同名函数&lt;/strong&gt;，对重载函数的调用会运行其适用于调用上下文的具体实现。&lt;/p&gt;&#xA;&lt;p&gt;从功能上来讲，就是允许一个函数调用根据上下文执行不同的方法，达到调用同一个函数名，执行不同的方法。&lt;/p&gt;&#xA;&lt;p&gt;一个简单的例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Volume&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; s) {  &lt;span style=&#34;color:#75715e&#34;&gt;// 立方体的体积。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; s &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; s &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; s;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Volume&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt; r, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; h) {  &lt;span style=&#34;color:#75715e&#34;&gt;// 圆柱体的体积。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3.1415926&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; r &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; r &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;static_cast&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;double&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt;(h);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Volume&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;long&lt;/span&gt; l, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; b, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; h) {  &lt;span style=&#34;color:#75715e&#34;&gt;// 长方体的体积。&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; l &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; b &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; h;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; Volume(&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; Volume(&lt;span style=&#34;color:#ae81ff&#34;&gt;2.5&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  std&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;cout &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt; Volume(&lt;span style=&#34;color:#ae81ff&#34;&gt;100l&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;75&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述例子中，实现了 3 个同名的 &lt;code&gt;Volume&lt;/code&gt; 函数，但是 3 个函数的入参个数、类型均不一样，也代表了不同的实现目的。&lt;/p&gt;&#xA;&lt;p&gt;在主函数 &lt;code&gt;main&lt;/code&gt; 中，传入了不同的入参，编译器或运行时再进行内部处理，从程序上来看达到了调用不同函数的目的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>回归现实：Go Leader 对 1.18 泛型的期望</title>
      <link>https://note.lican.site/posts/posts/go/118-leader-generics/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:16 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/118-leader-generics/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间根据 Go 泛型的最新动态，我写了一篇《&lt;a href=&#34;https://mp.weixin.qq.com/s/yWEM2EAwv80ZUFjbKGtpNA&#34;&gt;出泛型后 API 怎么办？Go 开发者要注意了&lt;/a&gt;》文章，引发了不少小伙伴的热议。&lt;/p&gt;&#xA;&lt;p&gt;Go 核心开发团队的现任 Leader&#xA;@Russ Cox 在 golang-dev 中正式发表《&lt;a href=&#34;https://groups.google.com/g/golang-dev/c/iuB22_G9Kbo&#34;&gt;expectations for generics in Go 1.18&lt;/a&gt;》对 Go 泛型给出了 “期待”，可以认为是后续的计划了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/e4693268-eff4-4dd3-ab6b-e4c41d8728cc.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;如果不出现严重的问题，Go 1.18 将会包括对泛型的支持，并且这次泛型的支持将会是有史以来最大的一次语言变化，对以下几点有顾虑：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;最佳实践.&lt;/li&gt;&#xA;&lt;li&gt;生产经验&lt;/li&gt;&#xA;&lt;li&gt;兼容性承诺。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;接下来，煎鱼带大家一起了解 Russ Cox 发表的 Go 泛型进程，知悉官方一手消息。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最佳实践&#34;&gt;最佳实践&lt;/h2&gt;&#xA;&lt;p&gt;Go 团队表示不知道使用泛型的最佳实践是什么，所以给出的官方文档将无法就何时使用泛型和何时不使用泛型给出精确、明确的答案，只可以给出粗略的指导。&lt;/p&gt;&#xA;&lt;p&gt;此处可以参考《Effective Go》的最初版本，是在不间断地写了一整年的 Go 代码后，才正式输出的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/034ab5db-f125-450d-bc97-9ea42ba94022.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;按照现有的计划，官方只会提供关于如何使用泛型的文档，暂时无法提供任何关于风格、最佳实践的规定性文档。&lt;/p&gt;&#xA;&lt;p&gt;在提供的标准库上，先是已经通过提案的 maps 和 slices库会先放到 golang.org/x/exp 中作为实验，不会保证向后兼容。待成熟后，再推广到标准库中。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/b1d967a2-2ac7-4077-be2e-4d1c4d3565cb.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;可以明确，Go 泛型出来后，社区就会陆续开始百花齐放，接着有官方输出推荐方法了，历史是如此的相似。&lt;/p&gt;&#xA;&lt;h2 id=&#34;生产经验&#34;&gt;生产经验&lt;/h2&gt;&#xA;&lt;p&gt;目前 Go 团队没有关于泛型的生产经验，因此会在文档中给出明确提示，让大家在生产中使用泛型的时候应该适当谨慎。&lt;/p&gt;&#xA;&lt;p&gt;泛型出来后，会陆续涉及到大量的重写工作，但是由于现在处于中间阶段。正在重写的 Go 1.18 工具链去同时适配泛型、非泛型代码是需要时间和经验的，有一定的风险。&lt;/p&gt;&#xA;&lt;p&gt;因此泛型出来后，可能会出现一些意想不到的问题，仅在生产发现（教训）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;兼容性承诺&#34;&gt;兼容性承诺&lt;/h2&gt;&#xA;&lt;p&gt;Go1.18 会和其他 Go1.x 版本一样，保证向后兼容的承诺：不会破坏用 Go 1.18 构建的代码，包括使用泛型的代码。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么 Go 不支持循环引用？</title>
      <link>https://note.lican.site/posts/posts/go/import-cyc/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:15 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/import-cyc/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;近年来开始学习 Go 语言的开发者越来越多了。很多小伙伴在使用时，就会遇到种种不理解的问题。&lt;/p&gt;&#xA;&lt;p&gt;其中一点就是循环引入的报错：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;package command-line-arguments&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;imports github.com/eddycjy/awesome-project/a&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;imports github.com/eddycjy/awesome-project/b&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;imports github.com/eddycjy/awesome-project/a: import cycle not allowed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;为什么 Go 不支持循环引用呢，这就很不解了，难道还影响性能了？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/4596a6d1-9286-40b2-8074-cc43f9bbd9f4.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天煎鱼将和大家一起了解背后的原因。&lt;/p&gt;&#xA;&lt;h2 id=&#34;案例演示&#34;&gt;案例演示&lt;/h2&gt;&#xA;&lt;p&gt;做一个基本的案例 Demo，便于没接触过的同学建立初步认知。我们的程序分别有 2 个 package。&lt;/p&gt;&#xA;&lt;p&gt;package a 的代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/eddycjy/awesome-project/b&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Hello&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;package b 的代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/eddycjy/awesome-project/a&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Hello&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Hello&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再在 main.go 的文件中调用 &lt;code&gt;a.Hello(&amp;quot;脑子进煎鱼了&amp;quot;)&lt;/code&gt; 方法。&lt;/p&gt;&#xA;&lt;p&gt;一运行，就会出现如下错误提示：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;package command-line-arguments&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;imports github.com/eddycjy/awesome-project/a&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;imports github.com/eddycjy/awesome-project/b&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;imports github.com/eddycjy/awesome-project/a: import cycle not allowed&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;错误的本质原因是 package a 引用了 package b，而 package b 又引用了 package a，造成了循环引用。&lt;/p&gt;</description>
    </item>
    <item>
      <title>出泛型后 API 怎么办？Go 开发者要注意了</title>
      <link>https://note.lican.site/posts/posts/go/generics-apis/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:14 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/generics-apis/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间社区里一下子就爆了，主要是各大媒体引用了 Go 语言之父&#xA;Rob Pike 所提的《go: don&amp;rsquo;t change the libraries in 1.18》。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/08e47a87-cf63-4dec-b0b5-fc178a494c4c.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;很多社交媒体都做了跟进，认为 Rob Pike 是硬性的反对 Go 泛型的 API 改造！&lt;/p&gt;&#xA;&lt;p&gt;如果读者只看了标题，有可能会产生一些误解实际上其表达的意思和近期 Go 社区讨论的事项是有关联的，要一起综合来看。&lt;/p&gt;&#xA;&lt;p&gt;为此，今天煎鱼就和大家一起来理一理，看看 Go 泛型 API 的改造工程，是个怎么一回事？&lt;/p&gt;&#xA;&lt;h2 id=&#34;现状&#34;&gt;现状&lt;/h2&gt;&#xA;&lt;p&gt;马上就是 2021.11 月，连深圳都变冷了&amp;hellip;根据 Go 语言的发布周期，Go1.18 版本的发布，那就是 2022.02 月左右。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/f849c76d-e84d-43d6-96c5-b30df77f1dd9.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;现在给到 Ian Lance Taylor、&#xA;Robert Griesemer 等大佬仅剩 3 个月的时间给大家讨论泛型细节，进一步完善实现，达到生产可用。&lt;/p&gt;&#xA;&lt;p&gt;抛出 Go 泛型的实现进度不说，现在遇到了一个比较大的问题。那就是&lt;strong&gt;实现泛型后 ”如何更新泛型的 API“&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这之中包含好几个方面，分别是：既有标准库、开源库，新标准库等。不同库之间是不同的人在维护。&lt;/p&gt;&#xA;&lt;p&gt;但这里存在一个大问题，如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/033083ef-d0ba-40f7-93d4-006e65310cf9.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Russ Cox 在 9 月就提出了 ”how to update APIs for generics“ 的疑惑，当时显然这一块还没有共识。在 11 月的现在，从讨论的记录来看，&lt;strong&gt;怎么做还没有达成一个最终的明确共识&lt;/strong&gt;（初步已有，未正式答复）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>上帝视角：Go 语言设计失误，缺乏远见？</title>
      <link>https://note.lican.site/posts/posts/go/go-design/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:13 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-design/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间我有一个朋友在某乎上摸鱼时，给我甩来一个主题为《golang 设计者是如何偿还技术债的》链接。&lt;/p&gt;&#xA;&lt;p&gt;说是让我学习、围观一下社区观点，早日好修成正果，本鱼表示满脸问号。&lt;/p&gt;&#xA;&lt;p&gt;原回答如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/4bbdfe91-b98e-4ae1-bcc6-aa5fc50cd184.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;主要是以极短的话语表述 Go 语言的 “泛型、异常、channel、annotation、模块依赖” 的设计是失误的。&lt;/p&gt;&#xA;&lt;p&gt;说是没有向各种编程语言的 “最佳实践” 各取所需。&lt;/p&gt;&#xA;&lt;h2 id=&#34;那些故事&#34;&gt;那些故事&lt;/h2&gt;&#xA;&lt;p&gt;刚好煎鱼也入门 Go 没几天，偶尔翻过 issues 和 proposal，看了一点点历史事件。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/3213b564-1a53-4dcf-9b69-4f4359bd50db.png&#34; alt=&#34;图来自 Introduction to Golang&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;也从我的观点来围观一下 Go 官方这些年为特性挣扎过的那些事。&lt;/p&gt;&#xA;&lt;p&gt;涉及：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;泛型。&lt;/li&gt;&#xA;&lt;li&gt;错误处理。&lt;/li&gt;&#xA;&lt;li&gt;依赖管理。&lt;/li&gt;&#xA;&lt;li&gt;注解。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;泛型&#34;&gt;泛型&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;为什么 Go 语言这么久都没有泛型&lt;/strong&gt;，是不是 Go 官方不够 “聪明”，抄作业都不会抄。这显然是不对的。&lt;/p&gt;&#xA;&lt;p&gt;有如下几点原因：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;泛型本质上并不是绝对的必需品。&lt;/li&gt;&#xA;&lt;li&gt;泛型不是 Go 语言的早期目标。&lt;/li&gt;&#xA;&lt;li&gt;其他 feature 更重要，把精力放在这些上面，Go 团队人力很有限的。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4 id=&#34;历史尝试&#34;&gt;历史尝试&lt;/h4&gt;&#xA;&lt;p&gt;在以往的尝试中，Go 团队有人进行过不少的泛型 proposal 试验。基本时间线（via @changkun）如下：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;简述&lt;/th&gt;&#xA;          &lt;th&gt;时间&lt;/th&gt;&#xA;          &lt;th&gt;作者&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Type Functions&lt;/td&gt;&#xA;          &lt;td&gt;2010年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Generalized Types&lt;/td&gt;&#xA;          &lt;td&gt;2011年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Generalized Types v2&lt;/td&gt;&#xA;          &lt;td&gt;2013年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Type Parameters&lt;/td&gt;&#xA;          &lt;td&gt;2013年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;go:generate&lt;/td&gt;&#xA;          &lt;td&gt;2014年&lt;/td&gt;&#xA;          &lt;td&gt;Rob Pike&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;First Class Types&lt;/td&gt;&#xA;          &lt;td&gt;2015年&lt;/td&gt;&#xA;          &lt;td&gt;Bryan C.Mills&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Contracts&lt;/td&gt;&#xA;          &lt;td&gt;2018年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor, Robert Griesemer&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Contracts&lt;/td&gt;&#xA;          &lt;td&gt;2019年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor, Robert Griesemer&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Redundancy in Contracts(2019)&amp;rsquo;s Design&lt;/td&gt;&#xA;          &lt;td&gt;2019年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor, Robert Griesemer&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Constrained Type Parameters(2020, v1)&lt;/td&gt;&#xA;          &lt;td&gt;2020年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor, Robert Griesemer&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Constrained Type Parameters(2020, v2)&lt;/td&gt;&#xA;          &lt;td&gt;2020年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor, Robert Griesemer&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Constrained Type Parameters(2020, v3)&lt;/td&gt;&#xA;          &lt;td&gt;2020年&lt;/td&gt;&#xA;          &lt;td&gt;Ian Lance Taylor, Robert Griesemer&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;我们观察一下，10 年过去了，Ian Lance Taylor 依然在开展泛型提案，持续地在思考着 Go 泛型。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 和 Golang 有什么关系？</title>
      <link>https://note.lican.site/posts/posts/go/go-golang/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:12 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-golang/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近天气也冷了，掐指一算是招聘季了，无论是校招、社招、HR、面试官们都蠢蠢欲动。这不，我有一个朋友的 HR 朋友都有起名困难了，一看 Go 语言的工作说明（Job Description），发现各有不同。&lt;/p&gt;&#xA;&lt;p&gt;如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/629d4aaa-bb01-4e2b-9a43-d671200da099.png&#34; alt=&#34;来自某招聘网站&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;仔细一看，有叫 Go 的，也有叫 Golang，还有叫 GO 的。好家伙，Go 语言有这么多个别名，甚至某乎都讨论了起来。到底叫什么是正确的？&lt;/p&gt;&#xA;&lt;p&gt;为此，今天就由煎鱼带大家理一理，了解这背后的关系。&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-官方定义&#34;&gt;Go 官方定义&lt;/h2&gt;&#xA;&lt;p&gt;从网上的资料来看，大家对 Go 的名字还是比较关注的，对于 Go 团队来讲，仿佛经常被问。例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;“Go 和 Golang 的关系是什么？”&lt;/li&gt;&#xA;&lt;li&gt;“Go、Golang、GO 哪个对？”&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;甚至在之前探讨 Go2 草案时，也有人开始起 Go2 的名字了，纠结是要叫 “golang2”，还是 “go2lang”：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/7608f5a1-9e77-45b2-a552-a7b7c32ad100.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其实这是错误的。在 Go FAQ 中有明确的回答这个问题：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/bdb43d48-f5c1-41bb-8495-7bbfc2fc60a6.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这一门语言称为 “Go”，不叫 “Golang”，也不叫 “GO”。“golang” 只是网站的地址，而不是语言的名称。&lt;/p&gt;&#xA;&lt;p&gt;同时 “GO” 的语言名称叫法也是错误的，虽然官方上的 Logo 是 “GO”：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/67b022a9-49de-4349-861e-77dd25367ac6.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;但这显然只是设计师层面的美观考量，并不是这一门语言的标准定义。&lt;/p&gt;&#xA;&lt;p&gt;因此&lt;strong&gt;这一门语言叫做 “Go” 语言&lt;/strong&gt;，这是正确的，也得到官方认证的，也不曾改变过。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么会有-golang&#34;&gt;为什么会有 Golang&lt;/h2&gt;&#xA;&lt;p&gt;但可能又有小伙伴疑惑了，那为什么 “Golang” 这个别名，如此之火。到底是为什么？&lt;/p&gt;&#xA;&lt;p&gt;这里一共有三点原因，分别是：站点地址（Go FAQ 提到）、搜索引擎、社区和论坛、语言重名。&lt;/p&gt;&#xA;&lt;h3 id=&#34;go-站点地址&#34;&gt;Go 站点地址&lt;/h3&gt;&#xA;&lt;p&gt;Go 团队所期望的 &lt;a href=&#34;https://go.org&#34;&gt;https://go.org&lt;/a&gt; 早就被注册，从网站的底部标识来看，2008 年起建站：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go：我有注解，Java：不，你没有！</title>
      <link>https://note.lican.site/posts/posts/go/annotation/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:11 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/annotation/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;作为一位 Go 程序员，你会发现身边的同事大多都拥有其他语言的编写经验。那势必就会遇到一点，要把新学到的知识和以前的知识建立连接。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/050a9802-1ca2-4634-859d-325a09d418c5.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;特殊在于，Go 有些特性是其他语言有，他没有的。最经典的就是 N 位 Java 同学寻找 Go 语言的注解在哪里，总要解释。&lt;/p&gt;&#xA;&lt;p&gt;为此，今天煎鱼就带大家了解一下 Go 语言的注解的使用和情况。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是注解&#34;&gt;什么是注解&lt;/h2&gt;&#xA;&lt;h3 id=&#34;了解历史&#34;&gt;了解历史&lt;/h3&gt;&#xA;&lt;p&gt;注解（Annotation）最早出现自何处，翻了一圈并没有找到。但可以明确，在注解的使用中，Java 注解最为经典，为了便于理解，因此我们基于 Java 做初步的注解理解。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/3c9e2434-c5f4-4d7a-bd2d-a8b582b570c8.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 2002 年，JSR-175 提出了 《&lt;a href=&#34;https://jcp.org/en/jsr/detail?id=175&#34;&gt;A Metadata Facility for the Java Programming Language&lt;/a&gt;》，也就是为 Java 编程语言提供元数据工具。&lt;/p&gt;&#xA;&lt;p&gt;这就是现在使用最广泛地注解（Annotation）的来源。&#xA;示例如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @annotation1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @annotation2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Hello&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在格式上均以 “@” 作为注解标识来使用。&lt;/p&gt;&#xA;&lt;h3 id=&#34;注解例子&#34;&gt;注解例子&lt;/h3&gt;&#xA;&lt;p&gt;摘抄自 @wikipedia 的一个注解例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;//等同于 @Edible(value = true)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Edible&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Item item &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Carrot();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;@interface&lt;/span&gt; Edible {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;boolean&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;default&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Author&lt;/span&gt;(first &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Oompah&amp;#34;&lt;/span&gt;, last &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Loompah&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  Book book &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;new&lt;/span&gt; Book();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;@interface&lt;/span&gt; Author {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    String &lt;span style=&#34;color:#a6e22e&#34;&gt;first&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    String &lt;span style=&#34;color:#a6e22e&#34;&gt;last&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 该标注可以在运行时通过反射访问。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Retention&lt;/span&gt;(RetentionPolicy.&lt;span style=&#34;color:#a6e22e&#34;&gt;RUNTIME&lt;/span&gt;) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 该标注只用于类内方法。&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;@Target&lt;/span&gt;({ElementType.&lt;span style=&#34;color:#a6e22e&#34;&gt;METHOD&lt;/span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;public&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;@interface&lt;/span&gt; Tweezable {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述例子中，通过注解去做了一系列的定义、声明、赋值等。若是对语言既有注解不熟，或是做的比较复杂的注解，就会有一定的理解成本。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么 Go 语言把类型放在后面？</title>
      <link>https://note.lican.site/posts/posts/go/type-after/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:10 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/type-after/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间看到大家在吵一个话题，那就是 Go 语言的类型声明，抠知识抠的非常细了，就是为什么他要放在后面。&lt;/p&gt;&#xA;&lt;p&gt;示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其实在早年 Go 官方估计已经被问烦了，写过一篇《&lt;a href=&#34;https://go.dev/blog/declaration-syntax&#34; title=&#34;Go&#39;s Declaration Syntax&#34;&gt;Go&amp;rsquo;s Declaration Syntax&lt;/a&gt;》来具体介绍和说明情况。&lt;/p&gt;&#xA;&lt;p&gt;为此煎鱼将参考并结合这篇官方资料，带大家一起了解为什么 Go 如此的 “与众不同” ，为什么要把类型放在后面。&lt;/p&gt;&#xA;&lt;h2 id=&#34;类型前置&#34;&gt;类型前置&lt;/h2&gt;&#xA;&lt;p&gt;在业内目前有不少知名语言，也采取的是在声明变量类型时，把类型定义在名字前面。像是 C、C++、C#、Java 等：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; x;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; x &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基本的格式定义：&amp;lt;data_type&amp;gt; &amp;lt;variable_list&amp;gt;;。&lt;/p&gt;&#xA;&lt;p&gt;上面的声明是一个简单的例子，如果更复杂一些，Go 官方还给出了著名的函数指针的例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;fp)(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; a, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; b);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;更进一步，如果返回值也是个函数指针类型，就会变成：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;fp)(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;)(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;), &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;))(&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这已经很难看出来是个 fp 的声明了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;类型后置&#34;&gt;类型后置&lt;/h2&gt;&#xA;&lt;p&gt;前面所举例的类型前置的编程语言，很多都是 C 系列中的一者。类型后置的代表，分别有：Go、Rust、Scala、Kotlin 等。&lt;/p&gt;&#xA;&lt;p&gt;其实在很多类型后置的编程语言种，会采取变量名+冒号+类型的方式出现。就像 Rust 一样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;let&lt;/span&gt; x: &lt;span style=&#34;color:#66d9ef&#34;&gt;i32&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基本的格式定义：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;x: int&#xA;p: pointer to int&#xA;a: array[3] of int&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Go 官方参照了这类类型后置的设计，并且为了简洁，进一步去掉了冒号和一些关键字，变成：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们再看回前面 fp 的声明的例子：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 切片导致内存泄露，被坑两次了！</title>
      <link>https://note.lican.site/posts/posts/go/slice-leak/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:09 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/slice-leak/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间在我的 Go 读者群里，有小伙伴们在纠结切片（slice）的问题，我写了这篇《&lt;a href=&#34;https://mp.weixin.qq.com/s/kEQI74ge6VhvNEr1d3JW-Q&#34;&gt;Go 切片这道题，吵了一个下午！&lt;/a&gt;》，引起了一拨各种讨论，还是比较欣慰的。&lt;/p&gt;&#xA;&lt;p&gt;这不，有小伙伴给我提出了新的题材：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/a97e5e6d-b58d-44f2-b858-b9ca12780180.png&#34; alt=&#34;来自读者微信提问&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;提出的是 Go 中很容易踩坑的切片内存泄露问题。作为宠粉的煎鱼肯定不会放过，争取让大家都避开这个 “坑”。&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章，就由煎鱼带大家来了解这个问题：Go 切片可能可以怎么泄露法？&lt;/p&gt;&#xA;&lt;h2 id=&#34;切片泄露的可能&#34;&gt;切片泄露的可能&lt;/h2&gt;&#xA;&lt;p&gt;在业务代码的编写上，我们经常会接受来自外部的接口数据，再把他插入到对应的数据结构中去，再进行下一步的业务聚合、裁剪、封装、处理。&lt;/p&gt;&#xA;&lt;p&gt;像在 PHP 语言，常常会放到数组（array）中。在 Go 语言，会放到切片（slice）中。因此在 Go 的切片处理逻辑中，常常会涉及到如下类似的动作。&lt;/p&gt;&#xA;&lt;p&gt;示例代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;[:&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;仔细想想，&lt;strong&gt;这段程序有没有问题&lt;/strong&gt;，是否存在内存泄露的风险？&lt;/p&gt;&#xA;&lt;p&gt;答案是：有的。有明确的切片内存泄露的可能性和风险。&lt;/p&gt;&#xA;&lt;h2 id=&#34;切片底层结构&#34;&gt;切片底层结构&lt;/h2&gt;&#xA;&lt;p&gt;可能有些小伙伴会疑惑，怎么就有问题了，是哪里有问题？&lt;/p&gt;&#xA;&lt;p&gt;这里就得复习一下切片的底层基本数据结构了，切片在运行时的表现是 SliceHeader 结构体，定义如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SliceHeader&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Data&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Len&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Cap&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Data：指向具体的底层数组。&lt;/li&gt;&#xA;&lt;li&gt;Len：代表切片的长度。&lt;/li&gt;&#xA;&lt;li&gt;Cap：代表切片的容量。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;要点是：切片真正存储数据的地方，是一个数组。切片的 Data 属性中&lt;strong&gt;存储的是指向所引用的数组指针地址&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背后的原因&#34;&gt;背后的原因&lt;/h2&gt;&#xA;&lt;p&gt;在上述案例中，我们有一个包全局变量 a，共有 2 个切片 a 和 b，截取了 b 的一部分赋值给了 a，两者存在着关联。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 什么时候会触发 GC？</title>
      <link>https://note.lican.site/posts/posts/go/when-gc/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:08 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/when-gc/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;Go 语言作为一门新语言，在早期经常遭到唾弃的就是在垃圾回收（下称：GC）机制中 STW（Stop-The-World）的时间过长。&lt;/p&gt;&#xA;&lt;p&gt;那么这个时候，我们又会好奇一点，作为 STW 的起始，Go 语言中什么时候才会触发 GC 呢？&lt;/p&gt;&#xA;&lt;p&gt;今天就由煎鱼带大家一起来学习研讨一轮。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是-gc&#34;&gt;什么是 GC&lt;/h2&gt;&#xA;&lt;p&gt;在计算机科学中，垃圾回收（GC）是一种自动管理内存的机制，垃圾回收器会去尝试回收程序不再使用的对象及其占用的内存。&lt;/p&gt;&#xA;&lt;p&gt;最早 John McCarthy 在 1959 年左右发明了垃圾回收，以简化 Lisp 中的手动内存管理的机制（来自 @wikipedia）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/09425faf-f521-43a9-a7fa-1db3c5163914.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要-gc&#34;&gt;为什么要 GC&lt;/h2&gt;&#xA;&lt;p&gt;手动管理内存挺麻烦，管错或者管漏内存也很糟糕，将会直接导致程序不稳定（持续泄露）甚至直接崩溃。&lt;/p&gt;&#xA;&lt;h2 id=&#34;gc-触发场景&#34;&gt;GC 触发场景&lt;/h2&gt;&#xA;&lt;p&gt;GC 触发的场景主要分为两大类，分别是：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;系统触发：运行时自行根据内置的条件，检查、发现到，则进行 GC 处理，维护整个应用程序的可用性。&lt;/li&gt;&#xA;&lt;li&gt;手动触发：开发者在业务代码中自行调用 &lt;code&gt; runtime.GC&lt;/code&gt; 方法来触发 GC 行为。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;系统触发&#34;&gt;系统触发&lt;/h3&gt;&#xA;&lt;p&gt;在系统触发的场景中，Go 源码的 &lt;code&gt;src/runtime/mgc.go&lt;/code&gt; 文件，明确标识了 GC 系统触发的三种场景，分别如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gcTriggerHeap&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gcTriggerKind&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;iota&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gcTriggerTime&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gcTriggerCycle&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;gcTriggerHeap：当所分配的堆大小达到阈值（由控制器计算的触发堆的大小）时，将会触发。&lt;/li&gt;&#xA;&lt;li&gt;gcTriggerTime：当距离上一个 GC 周期的时间超过一定时间时，将会触发。&#xA;-时间周期以 &lt;code&gt;runtime.forcegcperiod&lt;/code&gt; 变量为准，默认 2 分钟。&lt;/li&gt;&#xA;&lt;li&gt;gcTriggerCycle：如果没有开启 GC，则启动 GC。&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在手动触发的 &lt;code&gt;runtime.GC&lt;/code&gt; 方法中涉及。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;手动触发&#34;&gt;手动触发&lt;/h3&gt;&#xA;&lt;p&gt;在手动触发的场景下，Go 语言中仅有 &lt;code&gt;runtime.GC&lt;/code&gt; 方法可以触发，也就没什么额外的分类的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go map 如何缩容？</title>
      <link>https://note.lican.site/posts/posts/go/map-reset/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:07 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map-reset/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天看到 Go 圈子的著名股神（不是我&amp;hellip;），在归类中简单的提到了 Go 语言中 map 的缩容的描述，这让我对其产生了兴趣，想要来一探究竟。&lt;/p&gt;&#xA;&lt;p&gt;我们常常喊扩缩容，扩缩容，但社区里都是清一色分析扩容机制，Go 面试官也都是卷 Go 语言 map 的扩容机制&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;在 &lt;strong&gt;Go 语言中的 map 缩容机制是怎么做的&lt;/strong&gt;呢，今天就由煎鱼带大家一起研讨围观一轮。&lt;/p&gt;&#xA;&lt;h2 id=&#34;基本分析&#34;&gt;基本分析&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 底层源码 src/runtime/map.go 中，扩缩容的处理方法是 grow 为前缀的方法来处理的。&lt;/p&gt;&#xA;&lt;p&gt;其中扩缩容涉及到的是插入元素的操作，对应 mapassign 方法：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapassign&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;maptype&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;growing&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;overLoadFactor&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tooManyOverflowBuckets&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;noverflow&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;hashGrow&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;t&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;goto&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;again&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;growing&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;h&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;oldbuckets&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;overLoadFactor&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;bucketCnt&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; uintptr(&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;) &amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;loadFactorNum&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;bucketShift&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;loadFactorDen&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tooManyOverflowBuckets&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;noverflow&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;noverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;=&lt;/span&gt; uint16(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;&amp;lt;&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;核心看到针对扩缩容的判断逻辑：&lt;/p&gt;</description>
    </item>
    <item>
      <title>面试官：为什么 Go 的负载因子是 6.5？</title>
      <link>https://note.lican.site/posts/posts/go/map-65/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:07 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map-65/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近我有一个朋友，在网上看到一个有趣的段子，引发了我一些兴趣。&lt;/p&gt;&#xA;&lt;p&gt;如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/e81547d8-8de7-4310-a62f-e59ce4c0def2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;听说是在最后的闲聊、吹水、聊人生、乱扯环节了，不是在技术环节了，所以大家也不用太在意什么技术评估法则（别杠）。&lt;/p&gt;&#xA;&lt;p&gt;煎鱼作为一名技术号主，看到这里的 6.5，就想给大家挖一挖，这到底是何物，和大家一同学习和增长知识！&lt;/p&gt;&#xA;&lt;h2 id=&#34;65-是什么&#34;&gt;6.5 是什么&lt;/h2&gt;&#xA;&lt;p&gt;实际上在 Go 语言中，就存在 6.5 这一概念，与 map 存在直接关系，因此我们需要先了解 map 的基本数据结构，再介绍 6.5 的背景和由来。&lt;/p&gt;&#xA;&lt;p&gt;开始学习 6.5 吧！&lt;/p&gt;&#xA;&lt;h3 id=&#34;了解-map-底层&#34;&gt;了解 map 底层&lt;/h3&gt;&#xA;&lt;p&gt;我以前在写《&lt;a href=&#34;https://eddycjy.com/posts/go/map/2019-03-05-map-access/&#34;&gt;深入理解 Go map：初始化和访问元素&lt;/a&gt;》时有介绍过 map 的基础数据结构。&lt;/p&gt;&#xA;&lt;p&gt;基本结构如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/8679a84f-0d21-485d-b55f-dc9d70d5ddd1.png&#34; alt=&#34;map 基本数据结构&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其中重要的一个基本单位是 hmap：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;flags&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;         &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;noverflow&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;hash0&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;buckets&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;oldbuckets&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nevacuate&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mapextra&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapextra&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;overflow&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;[]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;oldoverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;[]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nextOverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;count：map 的大小，也就是 len() 的值，代指 map 中的键值对个数。&lt;/li&gt;&#xA;&lt;li&gt;flags：状态标识，主要是 goroutine 写入和扩容机制的相关状态控制。并发读写的判断条件之一就是该值。&lt;/li&gt;&#xA;&lt;li&gt;B：&lt;strong&gt;桶，最大可容纳的元素数量，值为 负载因子（默认 6.5） * 2 ^ B，是 2 的指数&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;noverflow：溢出桶的数量。&lt;/li&gt;&#xA;&lt;li&gt;hash0：哈希因子。&lt;/li&gt;&#xA;&lt;li&gt;buckets：保存当前桶数据的指针地址（指向一段连续的内存地址，主要存储键值对数据）。&lt;/li&gt;&#xA;&lt;li&gt;oldbuckets，保存旧桶的指针地址。&lt;/li&gt;&#xA;&lt;li&gt;nevacuate：迁移进度。&lt;/li&gt;&#xA;&lt;li&gt;extra：原有 buckets 满载后，会发生扩容动作，在 Go 的机制中使用了增量扩容，如下为细项：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;overflow 为 hmap.buckets （当前）溢出桶的指针地址。&lt;/li&gt;&#xA;&lt;li&gt;oldoverflow 为 hmap.oldbuckets （旧）溢出桶的指针地址。&lt;/li&gt;&#xA;&lt;li&gt;nextOverflow 为空闲溢出桶的指针地址。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;我们关注到 hmap 的 B 字段，其值就是 6.5，他就是我们在苦苦寻找的 6.5，但他又是什么呢？&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 切片这道题，吵了一个下午！</title>
      <link>https://note.lican.site/posts/posts/go/slice-discuss/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:06 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/slice-discuss/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天听到咱 Go 读者交流群里的小伙伴私聊我，表示他们在群里一直在讨论一个问题 slice 相关的问题，众说纷纭。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/f2cedcdf-8f6e-42f9-9009-6f1ee0f74f91.png&#34; alt=&#34;来自煎鱼的聊天记录&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天和各位小伙伴们一起来研究一下，避免后续又踩一遍坑，共同进步！&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题代码&#34;&gt;问题代码&lt;/h2&gt;&#xA;&lt;p&gt;引起群内大范围讨论的代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;appenFunc&lt;/span&gt; = &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;appenFunc&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;[:&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你认为程序的输出结果是什么？&lt;/p&gt;&#xA;&lt;p&gt;是如下的答案：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[]&#xA;[10 20 30]&#xA;[]&#xA;[]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;对吗？&lt;/p&gt;&#xA;&lt;p&gt;看上去很有道理，但错了。正确的结果是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[]&#xA;[10 20 30]&#xA;[]&#xA;[10 20 30 0 0 0 0 0 0 0]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这下可把大家整懵了，为什么输出 &lt;code&gt;sl&lt;/code&gt; 和 &lt;code&gt;sl[:10]&lt;/code&gt; 的结果差别这么大，这与预期的输出结果不一致。&lt;/p&gt;&#xA;&lt;p&gt;群内小伙伴的问题更明确了，疑惑点是：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;)     &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;[:&lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;]) &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述代码中，&lt;strong&gt;为什么第一个 &lt;code&gt;sl&lt;/code&gt; 打印结果是空的，第二个 &lt;code&gt;sl&lt;/code&gt; 给索引位置就能打印出来&lt;/strong&gt;？&lt;/p&gt;&#xA;&lt;p&gt;也有小伙伴不断在尝试 &lt;code&gt;sl[:10]&lt;/code&gt; 以外的输出，有没有因为一些边界值改变而导致不行。&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;sl&lt;/span&gt;[:])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你认为这个对应的输出结果是什么？&lt;/p&gt;</description>
    </item>
    <item>
      <title>会诱发 Goroutine 挂起的 27 个原因</title>
      <link>https://note.lican.site/posts/posts/go/goroutine-27/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:06 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/goroutine-27/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;上个月面向读者的提问，我们针对 goroutine 泄露中都会看到的大头 runtime.gopark 函数进行了学习和了解，输出了 《&lt;a href=&#34;https://mp.weixin.qq.com/s/x6Kzn7VA1wUz7g8txcBX7A&#34;&gt;Goroutine 一泄露就看到他，这是个什么？&lt;/a&gt;》。&lt;/p&gt;&#xA;&lt;p&gt;有小伙伴提到，虽然我们知道了 runtime.gopark 函数的缘起和内在，但其实没有提到 &lt;strong&gt;runtime.gopark 的诱发因素，这是我们日常编码中需要关注的&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章就和大家一起围观 gopark 的 27 个诱发场景。为了方便阅读，我们会根据分类进行说明。&lt;/p&gt;&#xA;&lt;h3 id=&#34;第一部分&#34;&gt;第一部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonZero&lt;/td&gt;&#xA;          &lt;td&gt;无&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGCAssistMarking&lt;/td&gt;&#xA;          &lt;td&gt;GC assist marking&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonIOWait&lt;/td&gt;&#xA;          &lt;td&gt;IO wait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonZero：无正式解释，从使用情况来看。主要在 sleep 和 lock 的 2 个场景中使用。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonGCAssistMarking：GC 辅助标记阶段会使得阻塞等待。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonIOWait：IO 阻塞等待时，例如：网络请求等。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第二部分&#34;&gt;第二部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonChanReceiveNilChan&lt;/td&gt;&#xA;          &lt;td&gt;chan receive (nil chan)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonChanSendNilChan&lt;/td&gt;&#xA;          &lt;td&gt;chan send (nil chan)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonChanReceiveNilChan：对未初始化的 channel 进行读操作。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonChanSendNilChan：对未初始化的 channel 进行写操作。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第三部分&#34;&gt;第三部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonDumpingHeap&lt;/td&gt;&#xA;          &lt;td&gt;dumping heap&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGarbageCollection&lt;/td&gt;&#xA;          &lt;td&gt;garbage collection&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGarbageCollectionScan&lt;/td&gt;&#xA;          &lt;td&gt;garbage collection scan&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonDumpingHeap：对 Go Heap 堆 dump 时，这个的使用场景仅在 runtime.debug 时，也就是常见的 pprof 这一类采集时阻塞。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonGarbageCollection：在垃圾回收时，主要场景是 GC 标记终止（GC Mark Termination）阶段时触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonGarbageCollectionScan：在垃圾回收扫描时，主要场景是 GC 标记（GC Mark）扫描 Root 阶段时触发。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第四部分&#34;&gt;第四部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonPanicWait&lt;/td&gt;&#xA;          &lt;td&gt;panicwait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonSelect&lt;/td&gt;&#xA;          &lt;td&gt;select&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonSelectNoCases&lt;/td&gt;&#xA;          &lt;td&gt;select (no cases)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonPanicWait：在 main goroutine 发生 panic 时，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonSelect：在调用关键字 select 时会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonSelectNoCases：在调用关键字 select 时，若一个 case 都没有，会直接触发。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第五部分&#34;&gt;第五部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGCAssistWait&lt;/td&gt;&#xA;          &lt;td&gt;GC assist wait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGCSweepWait&lt;/td&gt;&#xA;          &lt;td&gt;GC sweep wait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGCScavengeWait&lt;/td&gt;&#xA;          &lt;td&gt;GC scavenge wait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonGCAssistWait：GC 辅助标记阶段中的结束行为，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonGCSweepWait：GC 清扫阶段中的结束行为，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonGCScavengeWait：GC scavenge 阶段的结束行为，会触发。GC Scavenge 主要是新空间的垃圾回收，是一种经常运行、快速的 GC，负责从新空间中清理较小的对象。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第六部分&#34;&gt;第六部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonChanReceive&lt;/td&gt;&#xA;          &lt;td&gt;chan receive&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonChanSend&lt;/td&gt;&#xA;          &lt;td&gt;chan send&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonFinalizerWait&lt;/td&gt;&#xA;          &lt;td&gt;finalizer wait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonChanReceive：在 channel 进行读操作，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonChanSend：在 channel 进行写操作，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonFinalizerWait：在 finalizer 结束的阶段，会触发。在 Go 程序中，可以通过调用 &lt;code&gt;runtime.SetFinalizer&lt;/code&gt; 函数来为一个对象设置一个终结者函数。这个行为对应着结束阶段造成的回收。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第七部分&#34;&gt;第七部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonForceGCIdle&lt;/td&gt;&#xA;          &lt;td&gt;force gc (idle)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonSemacquire&lt;/td&gt;&#xA;          &lt;td&gt;semacquire&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonSleep&lt;/td&gt;&#xA;          &lt;td&gt;sleep&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonForceGCIdle：强制 GC（空闲时间）结束时，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonSemacquire：信号量处理结束时，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonSleep：经典的 sleep 行为，会触发。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第八部分&#34;&gt;第八部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonSyncCondWait&lt;/td&gt;&#xA;          &lt;td&gt;sync.Cond.Wait&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonTimerGoroutineIdle&lt;/td&gt;&#xA;          &lt;td&gt;timer goroutine (idle)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonTraceReaderBlocked&lt;/td&gt;&#xA;          &lt;td&gt;trace reader (blocked)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonSyncCondWait：结合 &lt;code&gt;sync.Cond&lt;/code&gt; 用法能知道，是在调用 &lt;code&gt;sync.Wait&lt;/code&gt; 方法时所触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonTimerGoroutineIdle：与 Timer 相关，在没有定时器需要执行任务时，会触发。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonTraceReaderBlocked：与 Trace 相关，ReadTrace会返回二进制跟踪数据，将会阻塞直到数据可用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;第九部分&#34;&gt;第九部分&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;标识&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonWaitForGCCycle&lt;/td&gt;&#xA;          &lt;td&gt;wait for GC cycle&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonGCWorkerIdle&lt;/td&gt;&#xA;          &lt;td&gt;GC worker (idle)&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonPreempted&lt;/td&gt;&#xA;          &lt;td&gt;preempted&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;waitReasonDebugCall&lt;/td&gt;&#xA;          &lt;td&gt;debug call&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;waitReasonWaitForGCCycle：等待 GC 周期，会休眠造成阻塞。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonGCWorkerIdle：GC Worker 空闲时，会休眠造成阻塞。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonPreempted：发生循环调用抢占时，会会休眠等待调度。&lt;/li&gt;&#xA;&lt;li&gt;waitReasonDebugCall：调用 GODEBUG 时，会触发。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;&#xA;&lt;p&gt;今天这篇文章是对开头 runtime.gopark 函数的详解文章的一个补充，我们能够对此了解到其诱发的因素。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.17 新特性，优化抛出的错误堆栈</title>
      <link>https://note.lican.site/posts/posts/go/117-errorstack/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:05 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/117-errorstack/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;平时在日常工程中，我们常常会用到异常恐慌（panic）的记录和追踪。最常见的就是，线上 panic 了之后，我们总想从中找到一些蛛丝马迹。&lt;/p&gt;&#xA;&lt;p&gt;我们很多人是看 panic 是看他的调用堆栈。然后就开始猜，看代码。猜测是不是哪里写的有问题，就想知道 panic 是由什么参数引起的？&lt;/p&gt;&#xA;&lt;p&gt;因为知道了诱发的参数，排查问题就非常方便了。为此&lt;strong&gt;在 Go1.17，官方对这块的调用堆栈信息展示进行了优化&lt;/strong&gt;，使其可读性更友好。&lt;/p&gt;&#xA;&lt;h2 id=&#34;案例&#34;&gt;案例&lt;/h2&gt;&#xA;&lt;p&gt;结合我们平时所使用的 panic 案例。如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;example&lt;/span&gt;(make([]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//go:noinline&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;example&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;str&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;panic(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;运行结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go&#xA;panic: 脑子进煎鱼了&#xA;&#xA;goroutine 1 [running]:&#xA;main.example(0xc000032758, 0x1, 0x2, 0x1073d11, 0x6, 0x3, 0xc000102058, 0x1013201)&#xA;&#x9;/Users/eddycjy/go-application/awesomeProject/main.go:9 +0x39&#xA;main.main()&#xA;&#x9;/Users/eddycjy/go-application/awesomeProject/main.go:4 +0x68&#xA;exit status 2&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们函数的入参是：&lt;code&gt;[]string、string、int&lt;/code&gt;，核心关注到 &lt;code&gt;main.example&lt;/code&gt; 方法的调用堆栈信息：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;example&lt;/span&gt;(&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xc000032758&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x1&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x2&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x1073d11&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x6&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x3&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0xc000102058&lt;/span&gt;, &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#ae81ff&#34;&gt;0x1013201&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;明明只是函数三个参数，却输出了一堆，对应起来非常的不清晰。&lt;/p&gt;&#xA;&lt;p&gt;其实际对应是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;slice：0xc000032758、0x1、0x2。&lt;/li&gt;&#xA;&lt;li&gt;string：0x1073d11、0x6。&lt;/li&gt;&#xA;&lt;li&gt;int：0x3。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这里存在的问题是，看调用堆栈的人，还得必须了解基本数据结构（例如：slice、string、int 等），他才知道每个函数入参他对应拥有几个字段，才能知道其内存布局的结构，有一点麻烦。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.17 新特性，凭什么提速 5~10%？</title>
      <link>https://note.lican.site/posts/posts/go/117-performance/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:04 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/117-performance/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在 Go1.17 发布后，我们惊喜的发现 Go 语言他又又又优化了，编译器改进后产生了约 5% 的性能提升，也没有什么破坏性修改，保证了向前兼容。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/c39ffb33-4afd-4537-a172-4919be7975a4.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;他做了些什么呢，好像没怎么看到有人提起。为此今天煎鱼带大家来解读两新提案：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;《&lt;a href=&#34;https://go.googlesource.com/proposal/+/master/design/40724-register-calling.md&#34; title=&#34;Proposal: Register-based Go calling convention&#34;&gt;Proposal: Register-based Go calling convention&lt;/a&gt;》&lt;/li&gt;&#xA;&lt;li&gt;《&lt;a href=&#34;https://go.googlesource.com/proposal/+/master/design/27539-internal-abi.md&#34; title=&#34;Proposal: Create an undefined internal calling convention&#34;&gt;Proposal: Create an undefined internal calling convention&lt;/a&gt;》&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;本文会基于提案讲解和拆解，毕竟分享新知识肯定要从官方资料作为事实基准出发。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;在以往的 Go 版本中，Go 的调用约定简单且几乎跨平台通用，其原因在于选用了基于 Plan9 ABI 的堆栈调用约定，也就是&lt;strong&gt;函数的参数和返回值都是通过堆栈上来进行传递&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这里我们一共提到了 Plan9 和 ABI，这是两个很关键的理念：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Plan9：Go 语言所使用的汇编器，Rob Pike 是贝尔实验室的猛人。&lt;/li&gt;&#xA;&lt;li&gt;ABI：Application Binary Interface（应用程序二进制接口），ABI 包含了应用程序在操作系统下运行时必须遵守的编程约定（例如：二进制接口）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;该方案的优缺点如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;优点：实现简单，简化了实现成本。&lt;/li&gt;&#xA;&lt;li&gt;缺点：性能方面付出了不少的代价。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;按我理解，在 Go 语言初创时期，采取先简单实现，跑起来再说。也合理，性能倒不是一个 TOP1 需求。&lt;/p&gt;&#xA;&lt;h2 id=&#34;go117-优化&#34;&gt;Go1.17 优化&lt;/h2&gt;&#xA;&lt;h3 id=&#34;什么是调用惯例&#34;&gt;什么是调用惯例&lt;/h3&gt;&#xA;&lt;p&gt;在新版本的优化中，提到了调用惯例（calling convention）的概念，指的是&lt;strong&gt;调用方和被调用方对函数调用的共识约定&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这些共识包含：函数的参数、返回值、参数传递顺序、传递方式等。&lt;/p&gt;&#xA;&lt;p&gt;双方都必须遵循这个约定时，程序的函数才能正常的运行起来。如果不遵循，那么该函数是没法运行起来的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;优化是什么&#34;&gt;优化是什么&lt;/h3&gt;&#xA;&lt;p&gt;在 Go1.17 起，正式将把 Go 内部 ABI 规范（在 Go 函数之间使用）从基于堆栈的函数参数和结果传递的方式&lt;strong&gt;改为基于寄存器的函数参数和结果传递&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.17 新特性：对 Go 依赖管理的一把大剪刀</title>
      <link>https://note.lican.site/posts/posts/go/117-module-pruning-lazy/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:03 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/117-module-pruning-lazy/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;不得不说。我可是个经历过 Go 依赖管理群魔乱舞，Go modules 迁移一堆 BUG 的人儿，难顶&amp;hellip;&#xA;为此当年我写了不少技术文章，希望给大家避坑。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/6gJkSyGAFR0v6kow2uVklA&#34;&gt;Go Modules 终极入门&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/uUNTH06_s6yzy5urtjPMsg&#34;&gt;干货满满的 Go Modules 知识分享&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/0g89yj9sc1oIz9kS9ZIAEA&#34;&gt;Go1.16 新特性：Go mod 的后悔药，仅需这一招&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在近期 Go1.17 发布后，Go modules 带来了两大更新，煎鱼摩拳擦掌，他们分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;模块依赖图裁剪（module graph pruning）&lt;/li&gt;&#xA;&lt;li&gt;延时模块加载（lazy module loading）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;今天带大家一起来了解这两块内容，争取了解其为何物，背景又是什么。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;在日常的 Go 工程开发中，不知道你有没有遇到过 Go modules 的一个奇怪的点。大家没说，就以为是正确的，默认就接受了。&lt;/p&gt;&#xA;&lt;p&gt;引用官方的 &lt;a href=&#34;https://github.com/golang/go/blob/4012fea822763ef3aa66dd949fa95b9f8d89450a/src/cmd/go/testdata/script/mod_lazy_new_import.txt&#34; title=&#34;mod_lazy_new_import.txt&#34;&gt;mod_lazy_new_import.txt&lt;/a&gt; 的案例来说，就是假设我们在代码中：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;main module 是 lazy。其导入了 module A 的 package x，package x 又导入了 module B。&lt;/li&gt;&#xA;&lt;li&gt;main module lazy 也相当于同时导入了 module A 的 package y。&lt;/li&gt;&#xA;&lt;li&gt;module A 的 package y 又导入了 module C 的 package z。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;关联如下图所示：&lt;/p&gt;</description>
    </item>
    <item>
      <title>分久必合，golang.org 将成为历史！</title>
      <link>https://note.lican.site/posts/posts/go/site-history/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:03 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/site-history/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;这两天看到官方博客的《&lt;a href=&#34;https://go.dev/blog/tidy-web&#34; title=&#34;Tidying up the Go web experience&#34;&gt;Tidying up the Go web experience&lt;/a&gt;》，已经明确了优化 Go 站点的计划和安排了，为此今天和大家分享这一个好消息。&lt;/p&gt;&#xA;&lt;p&gt;在之前 Go 官方推出了新的站点 go.dev，一个新的 Go 开发者中心：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/c70f1330-64da-4b65-8988-f9dbe6b1df05.png&#34; alt=&#34;go.dev&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;以及提供给开发者查询 Go 包（package）和模块（module）信息的配套网站 pkg.go.dev：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/41df22df-78e2-4b15-83d7-c8e38fcaba54.png&#34; alt=&#34;pkg.go.dev&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;看上去似乎美好，但其实原有的 golang.org 在继续提供 Go 发行版下载、文档和标准库的软件包的资料。&lt;/p&gt;&#xA;&lt;p&gt;而其他 Go 网站，例如：blog.golang.org、play.golang.org、talks.golang.org 以及tour.golang.org，又都拥有额外的 Go 资料。这一切都有些零散和混乱。&lt;/p&gt;&#xA;&lt;p&gt;在软件发展来讲，这种被称之为 ”绞杀者“ 模式：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/4645e874-771a-452a-b4ba-e41d8ffe5673.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;也就是旧系统不断地被新系统取代，在两边都还存在流量时，会保持两边的运行。随着时间的推移，新系统不断地取代老系统，最终完全取代。&lt;/p&gt;&#xA;&lt;p&gt;Go 官方&lt;strong&gt;计划在接下来的一两个月里，将把 golang.org 网站合并成一个统一的网站&lt;/strong&gt;，也就是在 go.dev 上。&lt;/p&gt;&#xA;&lt;p&gt;所有的现有 URL（例如：Go 标准库、Go 博客等）都会重定向到新的 URL 地址中，不会出现破坏性修改（无法访问），一切按计划都是兼容的。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/0708fcf4-90b2-4451-8a3d-5bf5ce2a1dfa.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;咱们将会有一个更统一的 Go 网站，部分 Go 初学者也不再需要辛辛苦苦再翻山倒海先找个天梯了，因为是&lt;strong&gt;可以直接访问的&lt;/strong&gt;，这是一种利好！&lt;/p&gt;&#xA;&lt;p&gt;不得不感叹语句，Russ Cox 推动事情的能力真是杠杠的，虽然也会引来不少争议和讨论，但我们依然可以从中学习到好的部分！&lt;/p&gt;&#xA;&lt;p&gt;大家&lt;strong&gt;有没有什么也想让 Go 团队优化的呢，欢迎在评论区交流和讨论&lt;/strong&gt;！&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 1.17 支持泛型了？具体怎么用</title>
      <link>https://note.lican.site/posts/posts/go/117-generics/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:02 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/117-generics/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;千呼万唤的，Go1.17 前几天终于发布了：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/45fe4f8a-ef8e-41a0-abba-ecdc05fe61c5.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;先前我写了几篇 Go1.17 新特性的文章，有兴趣的小伙伴可以看看：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/v1czjzlUsaSQTpAOG9Ub3w&#34;&gt;一个新细节，Go 1.17 将允许切片转换为数组指针！&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/zdsrmlwVR0bP1Q_Xg_VlpQ&#34;&gt;我要提高 Go 程序健壮性，Fuzzing 来了！&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/5kLFIuI0UJl_o8vMmZNfoA&#34;&gt;提了 3 年，Go1.17 终于增强构建约束！&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;今天的主题是泛型，众所皆知 Go1.18 泛型就会正式释出，都很期待，毕竟大更新，所有配套都会陆续有来！&#xA;其实，&lt;strong&gt;在 Go1.17 的此刻其实可以使用泛型了&lt;/strong&gt;，泛型代码已合入 master 分支。&lt;/p&gt;&#xA;&lt;p&gt;咱们只需要一点点操作，就能提前过上 Go 泛型的实验生活了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;升级-go117&#34;&gt;升级 Go1.17&lt;/h2&gt;&#xA;&lt;p&gt;你需要先升级 Go1.17，如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/a3260cf0-f9bc-4c86-aafd-4d08480143b9.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;安装后查看版本信息是否正常输出：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go1.17 version&#xA;go version go1.17 darwin/amd64&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;使用泛型&#34;&gt;使用泛型&lt;/h2&gt;&#xA;&lt;p&gt;接着写入一个基本的泛型 Demo：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;T&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;([]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;你好, &amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进了煎鱼\n&amp;#34;&lt;/span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Print&lt;/span&gt;([]&lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;{&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只需要在 run 和 build 的命令执行时指定 &lt;code&gt;-G&lt;/code&gt; 标识就好了。不过有的小伙伴可能会疑惑，为什么要这么干？&lt;/p&gt;</description>
    </item>
    <item>
      <title>Goroutine 一泄露就看到他，这是个什么？</title>
      <link>https://note.lican.site/posts/posts/go/runtimepark/</link>
      <pubDate>Fri, 31 Dec 2021 12:55:01 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/runtimepark/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;作为一个 Go 语言的使用大户，常常就有人冷不丁的，一下就泄露了&amp;hellip;泄露了啥？&lt;/p&gt;&#xA;&lt;p&gt;表象来看当然是 goroutine 泄露了，这时候就会有小伙伴开始跑去拉取 PProf。就会看到类似下面这张图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/78c8dadf-4f5c-4dfe-be36-d39bfa9d13d3.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;重点会看到 &lt;code&gt;runtime.gopark&lt;/code&gt; 这个函数，在所有的 goroutine 泄露中都会看到有，并且都会是大头。&lt;/p&gt;&#xA;&lt;p&gt;既然是大头，也就会有许多朋友以为他是泄漏点，在那一顿猛查，那这个函数到底是什么，作用是？&lt;/p&gt;&#xA;&lt;h2 id=&#34;runtimegopark-是何物&#34;&gt;runtime.gopark 是何物&lt;/h2&gt;&#xA;&lt;p&gt;想要知道 &lt;code&gt;runtime.gopark&lt;/code&gt; 函数是作用，最快的办法就是看源码了。其实现细节在 src/runtime/proc.go 文件中。&lt;/p&gt;&#xA;&lt;p&gt;源代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gopark&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;unlockf&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;g&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;lock&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;reason&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;waitReason&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;traceEv&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;traceskip&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;acquirem&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gp&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;curg&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;status&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;readgstatus&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gp&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;waitlock&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;lock&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;waitunlockf&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;unlockf&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;waitreason&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;reason&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;waittraceev&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;traceEv&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;waittraceskip&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;traceskip&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;releasem&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;mp&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mcall&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;park_m&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该函数主要作用有三大点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;acquirem&lt;/code&gt; 函数：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;获取当前 goroutine 所绑定的 m，设置各类所需数据。&lt;/li&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;releasem&lt;/code&gt; 函数&lt;strong&gt;将当前 goroutine 和其 m 的绑定关系解除&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;park_m&lt;/code&gt; 函数：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;将当前 goroutine 的状态从 &lt;code&gt;_Grunning&lt;/code&gt; 切换为 &lt;code&gt;_Gwaiting&lt;/code&gt;，也就是等待状态。&lt;/li&gt;&#xA;&lt;li&gt;删除 m 和当前 goroutine m-&amp;gt;curg（简称gp）之间的关联。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;mcall&lt;/code&gt; 函数，仅会在需要进行 goroutiine 切换时会被调用：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;切换当前线程的堆栈，从 g 的堆栈切换到 g0 的堆栈并调用 fn(g) 函数。&lt;/li&gt;&#xA;&lt;li&gt;将 g 的当前 PC/SP 保存在 g-&amp;gt;sched 中，以便后续调用 goready 函数时可以恢复运行现场。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;熟读了其源码后，我们可得知该函数的关键作用就是&lt;strong&gt;将当前的 goroutine 放入等待状态&lt;/strong&gt;，这意味着 goroutine 被暂时被搁置了，也就是被运行时调度器暂停了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 插件系统，一个凉了快半截的特性？</title>
      <link>https://note.lican.site/posts/posts/go/plugin/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/plugin/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在 Go 语言中，有一个好像很好用，但却比较少人提及的功能，那就是 Go Plugin。目前在 Go 工程中普遍还没广泛的使用起来，覆盖率不高。&lt;/p&gt;&#xA;&lt;p&gt;前段时间小咸鱼的同事问了他这玩具怎么用，他正想甩出一个链接，但发现&amp;hellip;煎鱼竟然没写过，这不，Go 知识板块的文章地图得补全。&lt;/p&gt;&#xA;&lt;p&gt;今天煎鱼就大家一起学习 Go Plugin！&lt;/p&gt;&#xA;&lt;h2 id=&#34;是什么&#34;&gt;是什么&lt;/h2&gt;&#xA;&lt;p&gt;Go Team 最早在 Go1.7 实验，在 Go1.8 正式引入了 Go Plugin 的机制。于 2016 年发布，一开始仅支持 Linux 实现：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/9a791ced-39db-4f09-a027-60569ccc95dd.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Go Plugin 机制实现了 Go 插件的加载和符号解析，能够支持将我们所编写的 Go 包编译为共享库（.so）。&lt;/p&gt;&#xA;&lt;p&gt;这样 Go 工程就可以加载所编译好的 Go Plugin（已经变成了共享库文件），在程序中调用共享库中的函数、常量、变量等使用。也称其为 Go 语言中的热插拔的插件系统。&lt;/p&gt;&#xA;&lt;p&gt;截止 Go1.17 为止，Go Plugin 仅支持在 Linux、FreeBSD 和 MacOS 上运行，还不支持 Windows。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要&#34;&gt;为什么需要&lt;/h2&gt;&#xA;&lt;p&gt;Go 语言是静态语言，正常我们写一个程序，分如下两个角度来看：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;从代码编写的角度来看：我们在程序编写的时候就已经把所有的功能实现给确定了，不会发生什么根本性的变化。&lt;/li&gt;&#xA;&lt;li&gt;从程序的角度来看：在 Go 进行编译时，就已经把所有引用的标准库、第三方库等都编译打包好进二进制文件了，因此也就无法在运行时去动态加载，所以没法有其它的可能性。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;那么为什么需要 Go Plugin 呢，原因如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;可插拔的插件：程序能够随时的安装插件，也能够卸载他，获得更多运行时的自定义能力。&lt;/li&gt;&#xA;&lt;li&gt;可动态加载运行时模块：随时安装了插件，自然也就需要可自行决定运行哪个插件的模块了。&lt;/li&gt;&#xA;&lt;li&gt;可独立开发插件、模块：主系统和子插件，可能由不同的团队开发和提供，也更有价值。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;其实本质上还是&lt;strong&gt;希望程序能够在运行时实现动态的外部加载&lt;/strong&gt;，根据不同的条件、场景加载不同的插件功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;使用方法&#34;&gt;使用方法&lt;/h2&gt;&#xA;&lt;h3 id=&#34;通用概念&#34;&gt;通用概念&lt;/h3&gt;&#xA;&lt;p&gt;Go 官方给出的例子非常简单，只需要在 Go 编译时指定为插件就可以了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>迷惑了，Go len() 是怎么计算出来的？</title>
      <link>https://note.lican.site/posts/posts/go/len/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:58 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/len/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近看到了一个很有意思的话题，我们平时常常会用 Go 的内置函数 &lt;code&gt;len&lt;/code&gt; 去获取各种 map、slice 的长度，那他是怎么实现的呢？&lt;/p&gt;&#xA;&lt;p&gt;正当我想去看看 &lt;code&gt;len&lt;/code&gt; 的具体实现时，一展身手，却发现竟然是个空方法：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;看注解也没有 link 到其他 runtime 函数，那么 len 函数是如何被调用的呢？&lt;/p&gt;&#xA;&lt;p&gt;先前看国外讨论 Go 计算 len 的文章时做了一些翻译和笔记（底下有参考链接），在此分享给大家，共同进步。&lt;/p&gt;&#xA;&lt;h2 id=&#34;谜底&#34;&gt;谜底&lt;/h2&gt;&#xA;&lt;p&gt;今天就由煎鱼带大家一同解开这个谜底。既然是谜底，那就一开始就揭开。&lt;/p&gt;&#xA;&lt;p&gt;其实 Go 语言中并没有 len 函数的具体实现代码，他其实&lt;strong&gt;是 Go 编译器的 &amp;ldquo;魔法&amp;rdquo; ，不是实际的函数调用&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;接下来将展开这部分，我们可以更深入地了解 Go 编译器的内部工作原理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;编译器&#34;&gt;编译器&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 编译器编译时会解析命令行参数中指定的标志和 Go 源文件，对解析后的 Go 包进行类型检查，将函数编译为机器代码。代码，最后将编译后的包定义写到磁盘上。&lt;/p&gt;&#xA;&lt;p&gt;内部定义基本类型、内置函数和操作函数的阶段是在 types/universe.go 当中。同时会进行内置函数和具体的操作符匹配，可以明确知道内置函数 len 对应的是 OLEN：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;builtinFuncs&lt;/span&gt; = [&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;op&lt;/span&gt;   &lt;span style=&#34;color:#a6e22e&#34;&gt;Op&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;append&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OAPPEND&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;cap&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OCAP&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;close&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OCLOSE&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;complex&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OCOMPLEX&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;copy&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OCOPY&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;delete&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ODELETE&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;imag&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OIMAG&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;len&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;OLEN&lt;/span&gt;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在编译时，上分为五个阶段进行类型检查：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 提案：增加泛型版 slices 和 maps 新包</title>
      <link>https://note.lican.site/posts/posts/go/news-slices-maps/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:57 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/news-slices-maps/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;现在是 2021 年 8 月份了，根据 Go 语言发布周期的 2，8 原则。Go 1.17 即将发布，在写这篇文章时，现在已经进行到了 rc2：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/ced4caa3-98ac-4c8a-8077-c72e11f69b56.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这意味着离 Go1.18 释出泛型的正式支持又近了一点点，社区中讨论泛型相关的周边功能的声音又多了起来。&lt;/p&gt;&#xA;&lt;p&gt;今天要讨论的泛型版功能支持也是如此，分别包含：map（#47330）、slice（#45955）、container/set（#47331） 三种通用类型的支持。&lt;/p&gt;&#xA;&lt;p&gt;我们主要展开 maps 和 slices，其余的都大同小异，理解核心思想就好。&lt;/p&gt;&#xA;&lt;h2 id=&#34;maps&#34;&gt;maps&lt;/h2&gt;&#xA;&lt;p&gt;该提案建议定义一个新的包 maps，它将提供可用于任何类型的 map 的函数：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/fc067e0f-0972-4f92-898e-d64404b5bfa4.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;下面的描述侧重于描述 API 的提供：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maps&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Keys&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;) []&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Values&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;) []&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Equal&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;m2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EqualFunc&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;m2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cmp&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;V1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V2&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Clear&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Clone&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;dst&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Filter&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;comparable&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;](&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;]&lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;keep&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;K&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;V&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;Keys：返回 map 的键值。这些键将是一个不确定的顺序。&lt;/li&gt;&#xA;&lt;li&gt;Values：返回 map 值。这些值将以不确定的顺序出现。&lt;/li&gt;&#xA;&lt;li&gt;Equal：匹配两个 map 是否包含相同的键/值对。&lt;/li&gt;&#xA;&lt;li&gt;EqualFunc：EqualFunc 与 Equal 类似，但使用 cmp 进行数值比较。&lt;/li&gt;&#xA;&lt;li&gt;Clear：从 map 中清除所有条目，使其为空。&lt;/li&gt;&#xA;&lt;li&gt;Clone：返回一个 map 的副本，这是一个浅层克隆。新的键和值使用普通的赋值来设置。&lt;/li&gt;&#xA;&lt;li&gt;Add：将 src 中的所有键/值对添加到 dst 中。当 src 中的一个键已经存在于 dst 中时，dst 中的值将被 src 中的键相关的值覆盖。&lt;/li&gt;&#xA;&lt;li&gt;Filter：过滤器从 map 中删除任何 keep 返回结果为 false 的键/值对。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;slice&#34;&gt;slice&lt;/h2&gt;&#xA;&lt;p&gt;该提案建议定义一个新的包 slices，它将提供可用于任何类型的 slice 的函数：&lt;/p&gt;</description>
    </item>
    <item>
      <title>一个 Demo 学会使用 Go Delve 调试</title>
      <link>https://note.lican.site/posts/posts/go/delve/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:57 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/delve/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在 Go 语言中，除了 go tool 工具链中的 pprof、trace 等剖析工具的大利器外。常常还会有小伙伴问，有没有更好用，更精细的，&lt;/p&gt;&#xA;&lt;p&gt;大家总嫌弃 pprof、trace 等工具，不够细，没法一口气看到根因，或者具体变量&amp;hellip;希望能够最好能追到代码级别调试的，看到具体变量的值是怎么样的，随意想怎么看怎么看的那种。&lt;/p&gt;&#xA;&lt;p&gt;为此今天给大家介绍 Go 语言强大的 Delve （dlv）调试工具，来更深入问题剖析。&lt;/p&gt;&#xA;&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;&#xA;&lt;p&gt;我们需要先安装 Go delve，若是 Go1.16 及以后的版本，可以直接执行下述命令安装：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go install github.com/go-delve/delve/cmd/dlv@latest&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;也可以通过 git clone 的方式安装：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ git clone https://github.com/go-delve/delve&#xA;$ cd delve&#xA;$ go install github.com/go-delve/delve/cmd/dlv&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在安装完毕后，我们执行 &lt;code&gt;dlv version&lt;/code&gt; 命令，查看安装情况：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ dlv version&#xA;Delve Debugger&#xA;Version: 1.7.0&#xA;Build: $Id: e353a65161e6ed74952b96bbb62ebfc56090832b $&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可以明确看到我们所安装的版本是 v1.7.0。&lt;/p&gt;&#xA;&lt;h2 id=&#34;演示程序&#34;&gt;演示程序&lt;/h2&gt;&#xA;&lt;p&gt;我们计划用一个反转字符串的演示程序来进行 Go 程序的调试。第一部分先是完成 &lt;code&gt;stringer&lt;/code&gt; 包的 &lt;code&gt;Reverse&lt;/code&gt; 方法。&lt;/p&gt;&#xA;&lt;p&gt;代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;stringer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Reverse&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; []rune(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;, len(&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt;] = &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;j&lt;/span&gt;], &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; string(&lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再在具体的 &lt;code&gt;main&lt;/code&gt; 启动函数中进行调用。代码如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>学会使用 GDB 调试 Go 代码</title>
      <link>https://note.lican.site/posts/posts/go/gdb/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:57 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gdb/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;上一篇文章《一个 Demo 学会使用 Go Delve 调试》我们详细介绍了 Go 语言如何使用 Delve 进行排查和调试，对于问题的解决非常的有帮助。&lt;/p&gt;&#xA;&lt;p&gt;但调试工具肯定不止只有 Delve，今天我们来介绍第二个神器，那就是：GDB。&lt;/p&gt;&#xA;&lt;h2 id=&#34;gdb-是什么&#34;&gt;GDB 是什么&lt;/h2&gt;&#xA;&lt;p&gt;GDB 是一个类 UNIX 系统下的程序调试工具，允许你看到另一个程序在执行时 &amp;ldquo;内部 &amp;ldquo;发生了什么，或者程序在崩溃时正在做什么。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/35fc6475-ec0d-44a0-ae8c-920121130edb.png&#34; alt=&#34;GDB Logo&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;主要可以做四类事情：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;启动你的程序，指定任何可能影响其行为的东西。&lt;/li&gt;&#xA;&lt;li&gt;使你的程序在指定的条件下停止。&lt;/li&gt;&#xA;&lt;li&gt;检查当你的程序停止时发生了什么。&lt;/li&gt;&#xA;&lt;li&gt;改变你程序中的东西，这样你就可以试验纠正一个错误的影响，并继续了解另一个错误。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;&#xA;&lt;p&gt;如果是在 MacOS 上的话，可以直接使用 brew 安装：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;brew install gdb&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果是在 Linux ，则使用自带的包管理工具进行安装即可，但需要注意安装完毕后需要在 HOME 目录进行相关配置。&lt;/p&gt;&#xA;&lt;p&gt;安装完毕后，执行 &lt;code&gt;gdb&lt;/code&gt; 就可以看到：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ gdb&#xA;GNU gdb (GDB) 10.2&#xA;...&#xA;(gdb) &#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;写此文时最新的 gdb 版本已经是 10.2 了，我也升级了上去。问题不大，还多了不少功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;编译&#34;&gt;编译&lt;/h2&gt;&#xA;&lt;p&gt;我们还是使用先前的演示程序来进行调试。但由于 Go 语言的不少编译优化，因此在编译运行程序时，有以下几点需要注意：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;go build 编译时需要增加 &lt;code&gt;-gcflags=all=&amp;quot;-N -l&amp;quot;&lt;/code&gt; 指令来关闭内联优化，方便接下来的调试。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;若是 MacOS，在 go build 编译时需要增加 &lt;code&gt;-ldflags=&#39;-compressdwarf=false&#39;&lt;/code&gt; 指令。&lt;/p&gt;</description>
    </item>
    <item>
      <title>我周末参加了个架构师大会！</title>
      <link>https://note.lican.site/posts/posts/2021giac/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:57 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/2021giac/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前两天 GIAC 全球互联网架构大会在深圳举办了，总算是有个长年在深圳举办的大会了，愉快参加了大部分的场次，面基了不少社区网友。&lt;/p&gt;&#xA;&lt;p&gt;分享一些我听了觉得有意义的记录给大家。希望能和大家一起学习进步。本文分别涉及如下几个议题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;《hits for microservices desgin》&lt;/li&gt;&#xA;&lt;li&gt;《在企业中的个人成长》&lt;/li&gt;&#xA;&lt;li&gt;《大规模任务调度在 AfterShip 的高可用实践》&lt;/li&gt;&#xA;&lt;li&gt;《快手前端实时性能监控和稳定性度量》&lt;/li&gt;&#xA;&lt;li&gt;《快手中间件 mesh 化实践》&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;hits-for-microservices-desgin&#34;&gt;hits for microservices desgin&lt;/h2&gt;&#xA;&lt;p&gt;一开始先介绍了为什么叫 ”hits“。叫 ”hits“ 的主要原因，是&lt;strong&gt;业务架构没有技术架构那么明确，没有明确的对与错，是个人的工作经验和总结&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h3 id=&#34;微服务解决什么问题&#34;&gt;微服务解决什么问题&lt;/h3&gt;&#xA;&lt;p&gt;业内常常说到，微服务，微服务。总归期望微服务解决什么问题。&lt;/p&gt;&#xA;&lt;p&gt;演讲的作者做了如下的调研：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/903dfcbb-a0b6-481f-a40e-3476b8ac8b64.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;从调研结果来看，占比最大的就是 ”独立自治，只关注自己的模块“。这和绝大部分既有业务的公司做微服务的初衷一致。&lt;/p&gt;&#xA;&lt;p&gt;许多就是被单体的巨石应用折腾的不行，纷纷希望通过拆分微服务来实现业务模块的独立自治。&lt;/p&gt;&#xA;&lt;h3 id=&#34;微服务的现状&#34;&gt;微服务的现状&lt;/h3&gt;&#xA;&lt;p&gt;主要是播放了动图，配合口述。现在大多数服务拆分后的现状，很多就是&lt;strong&gt;改哪影响哪完全不清楚，和水管漏水似的&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/f871b4de-c8b6-47b4-a5e7-5b9f64b73aea.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;(自行脑补一拧水管，堵哪，别的地方就漏)&lt;/p&gt;&#xA;&lt;h3 id=&#34;衡量微服务拆分的标准&#34;&gt;衡量微服务拆分的标准&lt;/h3&gt;&#xA;&lt;p&gt;理想中的微服务拆分，希望要有灵活的组装能力。但拆分后遇到的新问题，实际的情况，拆分后与期望的不一样，拆着拆着就变成了一大坨，但只是说隔开了，与现在企业中微服务运行的现状很贴合。&lt;/p&gt;&#xA;&lt;p&gt;拆分后如有如下几个痛点：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/0890ca8a-4fa1-4173-8334-92a167a47a19.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;举了几个案例。分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;订单的例子。&lt;/li&gt;&#xA;&lt;li&gt;报价的系统。&lt;/li&gt;&#xA;&lt;li&gt;数仓的例子。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;订单&#34;&gt;订单&lt;/h4&gt;&#xA;&lt;p&gt;举的是订单的例子，订单团队非常忙，因为信息都存在订单里，系统其他有任何业务上的变更诉求，都要找订单的团队。&lt;/p&gt;&#xA;&lt;p&gt;为此，在拆分上需要优化成订单业务只保存订单 ID：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/24a64dd9-98ae-419f-afef-aa125513dbd2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;各系统存订单ID，各团队自治，实现业务解耦，订单团队就不用因其他业务变更天天加班了。&lt;/p&gt;&#xA;&lt;h4 id=&#34;报价&#34;&gt;报价&lt;/h4&gt;&#xA;&lt;p&gt;举的是报价的系统，要是报价团队，针对各个子业务项都要自己实现一般，会非常的辛苦，经常要加班。&lt;/p&gt;&#xA;&lt;p&gt;我们只需要在报价系统提供接口标准，各系统自己实现，再对接：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/92f5b5eb-e5de-4bfd-bab6-f3e9ab2d7a6d.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;报价团队就不需要每次都重新开会，再对接。报价系统自己只做业务流程的编排，瞬间变轻松了。&lt;/p&gt;&#xA;&lt;h4 id=&#34;数仓&#34;&gt;数仓&lt;/h4&gt;&#xA;&lt;p&gt;举的是数仓的例子，业务改一个字段，数仓系统要改一个月，否则就会出现问题，因此要求业务有任何 schema 改变都必须要通知数仓团队：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/b1a09935-9663-449a-8646-b55ef3e08b7c.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;很现实的是，基本通知不过来，所以很多公司把他作为绩效，定期考核，出问题定期批评。&lt;/p&gt;&#xA;&lt;p&gt;建议的是：通过 RPC 的方式提供维护，把数据维护交给业务团队自己维护，数仓团队应该只做具体的跨团队的数据互联。&lt;/p&gt;&#xA;&lt;h4 id=&#34;好的标准的定义&#34;&gt;好的标准的定义&lt;/h4&gt;&#xA;&lt;p&gt;分层，都可以独立变更，可以自己搞自己，只需要保证这一层提供的能力是稳定的就好（全部改一遍的另当别论），不需要了解上下游，只需要维护好 interface。&lt;/p&gt;&#xA;&lt;p&gt;具体几点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;不同模块间完全没影响&lt;/li&gt;&#xA;&lt;li&gt;只共享不可变数据&lt;/li&gt;&#xA;&lt;li&gt;共享可变数据，但接口不变。&lt;/li&gt;&#xA;&lt;li&gt;大部分情况变化的是实现，变化的不是接口，接口的变更次数很少。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;参照乐高，关注接口的稳定性，而不是拆的越细越好。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么鼓励可以重塑一个职场人？</title>
      <link>https://note.lican.site/posts/posts/reload-man/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:56 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reload-man/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近在看书的时候看到了一句很经典的话：“&lt;strong&gt;重塑一个人行为最好的方式是鼓励&lt;/strong&gt;”。平时我在多个领域的不同图书、不同面谈场合都能听到过不同的诠释。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/9a4b75a6-b512-47b8-9c12-28d9b8e7a068.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;可惜的是作者大多都没有指出是 “心理学” 的范畴，都只是表示应该要这么做，没有表示为什么，没有讲解来源，传播的信息非常的 3.5 手。&lt;/p&gt;&#xA;&lt;p&gt;为此特意咨询了身边的一个心理学科班大佬，自打我认识她以来，每次开会都能看到她点头表示肯定，在我的记忆中非常深刻，非常有意思。&lt;/p&gt;&#xA;&lt;p&gt;与她咨询过后，得出对应的是理论是 “&lt;strong&gt;皮格马利翁效应&lt;/strong&gt;”。今天就进一步展开来简单学习、思考一下这为何物。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;皮格马利翁效应，又称毕马龙效应、罗森塔尔效应或期待效应，是指人（通常是指孩童或学生）在被赋予更高期望以后，他们会表现的更好的一种现象。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/e27b3d98-18c0-4cfc-bd4d-5900ac772351.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;美国心理学家罗伯特·罗森塔尔和雷诺尔·雅各布森对此进行了研究。在他们的研究中发现，假设&lt;strong&gt;老师对学生的期望加强，学生的表现也会相对加强&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;实验&#34;&gt;实验&lt;/h2&gt;&#xA;&lt;p&gt;在罗森塔尔的实验中，他们从 1~6 年级各选了 3 个班，对这 18 个班的学生进行了 “未来发展趋势测验”。并将一份 “最有发展前途者” 名单（实际上是随便抽取出来的）交给了校长和相关老师。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/6a09db03-5811-4ff7-b6b5-7a2cb2cc36e4.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 8 个月后，罗森塔尔和助手们对那 18 个班级的学生进行复试，结果发现：&lt;strong&gt;被期望的学生表现出更有适应能力、更有魅力、求知欲更强、智力更活跃等倾向&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/c59f2415-812a-4d74-bc93-03f360944b79.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;通过各种研究和试验得出结论：&lt;strong&gt;认为教师的期望会传递给被期望的学生并产生鼓励效应，进而产生改变&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;也正是因为罗森塔尔对该效应在小学教学上予以验证提出，皮格马利翁效应也被称为“罗森塔尔效应”。&lt;/p&gt;&#xA;&lt;h2 id=&#34;思考&#34;&gt;思考&lt;/h2&gt;&#xA;&lt;p&gt;回到最初的话题，为什么作者会说 ”重塑一个人行为最好的方式是鼓励”，这让我想起了非常著名两类思考模式：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/db4d42cc-9519-4c03-8961-57b3deaf9a65.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;成长型思考模式：认为学习不在于天赋，在于努力，只要努力用功，什么都能学会。&lt;/li&gt;&#xA;&lt;li&gt;固定型思考模式：特别相信天赋的作用，擅长的东西就是擅长，要是不擅长怎么学都没有用。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这其实就直接和 “鼓励” 有关系，我们接下来结合 “否定” 和 “鼓励” 来具体展开说说。&lt;/p&gt;&#xA;&lt;p&gt;看看长期对一个人进行 “否定”，又或是进行 “鼓励” 可能会发生怎么样的事情，会不会改变一个人？&lt;/p&gt;&#xA;&lt;h3 id=&#34;否定&#34;&gt;否定&lt;/h3&gt;&#xA;&lt;p&gt;如果在职场中，你&lt;strong&gt;对一个人一直是否定、不认可，这对他是不好的&lt;/strong&gt;。你无论做什么，那个人总是挑刺，冷嘲热讽，在公开场合批判你。&lt;/p&gt;&#xA;&lt;p&gt;可能会带来如下结果：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;若他是一张白纸：极有可能就会认为自己不行，认为自己怎么学都没有用，无限的进行自我否定，很难走出来。&lt;/li&gt;&#xA;&lt;li&gt;若他不是白纸：明确知道自己的底线，一直否定、不认可，也会反噬你团队，又或是对你有极大的意见。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这还是明确是否白纸的场景，但&lt;strong&gt;更多的人不是非黑即白，也就是在灰色，处于两者之间&lt;/strong&gt;，不少人会怀疑人生。&lt;/p&gt;&#xA;&lt;p&gt;逐渐才发现是&lt;strong&gt;大家常说的职场 PUA&lt;/strong&gt;，这在勾心斗角的某些地方很常见。&lt;/p&gt;&#xA;&lt;h3 id=&#34;鼓励&#34;&gt;鼓励&lt;/h3&gt;&#xA;&lt;p&gt;如果我们加之鼓励，多鼓励职场中的同事，在不同的人生阶段能带来不同的结果：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;从小培养：埋下成长型思维模式的种子，他会主动把每一项任务都当成成长的机会，主动愿意花更长的时间钻研难题，主动选择更困难的任务。&lt;/li&gt;&#xA;&lt;li&gt;成年发展：知道自己不应该被局限、固定的思维定式所控制，慢慢把 “固定型思考” 转变成 “成长型思考”，就会有较大的突破。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在职场中受到鼓励后，就&lt;strong&gt;会朝着这块持续不断地突破，获得自我和周遭的成就和认同感，进而更进一步的拓展，得到更多的发展空间&lt;/strong&gt;，这就是 “鼓励” 的力量。&lt;/p&gt;</description>
    </item>
    <item>
      <title>时隔 3 年，Go1.17 增强构建约束！</title>
      <link>https://note.lican.site/posts/posts/go/117-build/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:56 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/117-build/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;Go1.17rc1 在前几天终于正式发布了：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/a9dd1134-e4f8-4d9c-9c3c-2608728ddf69.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;看到 Go1.17 增加了一个新特性，是面向 Go 构建时的构建约束的增强。认真一看，是一个时隔 3 年的提案了，原本还在 Go2 和 Go1 之间左右摇摆，这下在 6 月底 Russ Cox 就输出了新草案：《Bug-resistant build constraints — Draft Design》。紧接着直接计划在 Go1.17 发布了。&lt;/p&gt;&#xA;&lt;p&gt;一气呵成，真实版高效能了。&lt;/p&gt;&#xA;&lt;p&gt;如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/10037273-887d-45c0-9eca-6ef36d7c4d72.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;之前小咸鱼有遇到好几个朋友，在报错时压根不知道 Go 有这个约束语法，以为只是个单纯的注释，直接不明所以然，感觉科普之路任重道远。&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章煎鱼就来讲讲构建约束这事。&lt;/p&gt;&#xA;&lt;p&gt;注：下个月 Go1.17 就会正式发布，距离 Go1.18 泛型出山只差一点点距离了，值得期待！&lt;/p&gt;&#xA;&lt;h2 id=&#34;构建约束的背景&#34;&gt;构建约束的背景&lt;/h2&gt;&#xA;&lt;p&gt;简单来讲，在真实环境中，可能需要为不同的编译环境编写不同的 Go 代码，所以需要做构建约束。&lt;/p&gt;&#xA;&lt;p&gt;划重点，Go 语言对这一问题的解决方案是&lt;strong&gt;在文件层面进行有条件的编译：每个文件要么在编译中，要么不在&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;也就是，假设不符合构建约束的场景。那么会直接不编译这个文件，因为他不在编译范围内。那在程序想运行时就会报错，表示找不到文件。因此有许多的同学看着报错信息，经常找不着北&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;现有的构建约束&#34;&gt;现有的构建约束&lt;/h2&gt;&#xA;&lt;p&gt;既然是叫 “增强”。说明现有就有构建约束。最早的构建约束是在 2011 年 9 月引入的构建约束。&lt;/p&gt;&#xA;&lt;p&gt;我们平时常见的构建约束（build constraint），也叫做构建标记（build tag），构建约束必须出现在 &lt;code&gt;package&lt;/code&gt; 之前。&lt;/p&gt;&#xA;&lt;p&gt;平时会在 Go 工程的文件中的最开始会看到如下行注解：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// +build&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为了将构建约束与包文档区分开来，构建约束后必须跟一个空行。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// +build linux,386 darwin,!cgo&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;又或是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// +build linux darwin&#xA;// +build amd64&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;还可以根据 Go 版本来约束：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 内存模型：happens-before 原则</title>
      <link>https://note.lican.site/posts/posts/go/memory-model/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:54 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/memory-model/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在日常工作中，如果我们能够了解 Go 语言内存模型，那会带来非常大的作用。这样在看一些极端情况，又或是变态面试题的时候，就能够明白程序运行表现下的很多根本原因了。&lt;/p&gt;&#xA;&lt;p&gt;当然，靠一篇普通文章讲完 Go 内存模型，不可能。因此今天这篇文章，把重点划在给大家&lt;strong&gt;讲解 Go 语言的 happens-before 原则&lt;/strong&gt;这 1 个细节。&lt;/p&gt;&#xA;&lt;p&gt;开吸，和煎鱼揭开他的神秘面纱！&lt;/p&gt;&#xA;&lt;h2 id=&#34;内存模型定义是什么&#34;&gt;内存模型定义是什么&lt;/h2&gt;&#xA;&lt;p&gt;既然要了解 happens-before 原则，我们得先知道 The Go Memory Model（Go 内存模型）定义的是什么，官方解释如下：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The Go memory model specifies the conditions under which reads of a variable in one goroutine can be guaranteed to observe values produced by writes to the same variable in a different goroutine.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;在 Go 内存模型规定：“在一个 goroutine 中读取一个变量时，可以保证观察到不同 goroutine 中对同一变量的写入所产生的值” 的条件。&lt;/p&gt;&#xA;&lt;p&gt;这是学习后续知识的一个大前提。&lt;/p&gt;&#xA;&lt;h2 id=&#34;happens-before-是什么&#34;&gt;happens-before 是什么&lt;/h2&gt;&#xA;&lt;p&gt;Happens Before 是一个专业术语，与 Go 语言没有直接关系，也就是并非是特有的。用大白话来讲，其定义是：&lt;/p&gt;</description>
    </item>
    <item>
      <title>分享 Go 使用 Context 的正式姿势</title>
      <link>https://note.lican.site/posts/posts/go/real-context/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:54 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/real-context/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在 Go 语言中，Goroutine（协程），也就是关键字 &lt;code&gt;go&lt;/code&gt; 是一个家喻户晓的高级用法。这起的非常妙，说到 Go，就会想到这一门语言，想到 goroutine 这一关键字，而与之关联最深的就是 context。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/2f26bd64-e9bd-4c89-a9a0-326b8c2b9d00.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;平时在 Go 工程中开发中，几乎所有服务端（例如：HTTP Server）的默认实现，都在处理请求时新起 goroutine 进行处理。&lt;/p&gt;&#xA;&lt;p&gt;但一开始存在一个问题，那就是当一个请求被取消或超时时，所有在该请求上工作的 goroutines 应该迅速退出，以便系统可以回收他们正在使用的任何资源。&lt;/p&gt;&#xA;&lt;p&gt;当年可没有 context 标准库。很折腾。因此 Go 官方在 2014 年正式宣发了 context 标准库，形成一个完整的闭环。&lt;/p&gt;&#xA;&lt;p&gt;但有了 context 标准库，Go 爱好者们又奇怪了，前段时间我就被问到了：“Go context 的正确使用姿势是怎么样的”？&lt;/p&gt;&#xA;&lt;p&gt;（一张忘记在哪里被问的隐形截图）&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章就由煎鱼带你看看。&lt;/p&gt;&#xA;&lt;h2 id=&#34;context-用法&#34;&gt;Context 用法&lt;/h2&gt;&#xA;&lt;p&gt;在 Go context 用法中，我们常常将其与 select 关键字结合使用，用于监听其是否结束、取消等。&lt;/p&gt;&#xA;&lt;p&gt;代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;shortDuration&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Millisecond&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cancel&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithTimeout&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;shortDuration&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cancel&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;():&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;context deadline exceeded&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果是更进一步结合 goroutine 的话，常见的例子是：&lt;/p&gt;</description>
    </item>
    <item>
      <title>详解 Go 团队不建议用的 unsafe.Pointer</title>
      <link>https://note.lican.site/posts/posts/go/unsafe-pointer/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:54 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/unsafe-pointer/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;大家在学习 Go 的时候，肯定都学过 “Go 的指针是不支持指针运算和转换” 这个知识点。为什么呢？&lt;/p&gt;&#xA;&lt;p&gt;首先，Go 是一门静态语言，所有的变量都必须为标量类型。不同的类型不能够进行赋值、计算等跨类型的操作。&lt;/p&gt;&#xA;&lt;p&gt;那么指针也对应着相对的类型，也在 Compile 的静态类型检查的范围内。同时静态语言，也称为强类型。也就是一旦定义了，就不能再改变它。&lt;/p&gt;&#xA;&lt;h2 id=&#34;错误的示例&#34;&gt;错误的示例&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main(){&#xA; num := 5&#xA; numPointer := &amp;amp;num&#xA;&#xA; flnum := (*float32)(numPointer)&#xA; fmt.Println(flnum)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# command-line-arguments&#xA;...: cannot convert numPointer (type *int) to type *float32&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在示例中，我们创建了一个 &lt;code&gt;num&lt;/code&gt; 变量，值为 5，类型为 &lt;code&gt;int&lt;/code&gt;，准备干一番大事。&lt;/p&gt;&#xA;&lt;p&gt;接下来我们取了其对于的指针地址后，试图强制转换为 &lt;code&gt;*float32&lt;/code&gt;，结果失败&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;万能的破壁-unsafe&#34;&gt;万能的破壁 unsafe&lt;/h2&gt;&#xA;&lt;p&gt;针对刚刚的 “错误示例”，我们可以采用今天的男主角 &lt;code&gt;unsafe&lt;/code&gt; 标准库来解决。它是一个神奇的包，在官方的诠释中，有如下概述：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;围绕 Go 程序内存安全及类型的操作。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;很可能会是不可移植的。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;不受 Go 1 兼容性指南的保护。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;简单来讲就是，不怎么推荐你使用，因为它是 unsafe（不安全的）。&lt;/p&gt;&#xA;&lt;p&gt;但是在特殊的场景下，使用了它，可以打破 Go 的类型和内存安全机制，让你获得眼前一亮的惊喜效果。&lt;/p&gt;&#xA;&lt;h3 id=&#34;unsafepointer&#34;&gt;unsafe.Pointer&lt;/h3&gt;&#xA;&lt;p&gt;为了解决这个问题，需要用到 &lt;code&gt;unsafe.Pointer&lt;/code&gt;。它表示任意类型且可寻址的指针值，可以在不同的指针类型之间进行转换（类似 C 语言的 void * 的用途）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go SliceHeader 和 StringHeader，你知道吗？</title>
      <link>https://note.lican.site/posts/posts/go/slice-string-header/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:53 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/slice-string-header/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在 Go 语言中总是有一些看上去奇奇怪怪的东西，咋一眼一看感觉很熟悉，但又不理解其在 Go 代码中的实际意义，面试官却爱问&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;今天要给大家介绍的是 SliceHeader 和 StringHeader 结构体，了解清楚他到底是什么，又有什么用，并且会在最后给大家介绍 0 拷贝转换的内容。&lt;/p&gt;&#xA;&lt;p&gt;一起愉快地开始吸鱼之路。&lt;/p&gt;&#xA;&lt;h2 id=&#34;sliceheader&#34;&gt;SliceHeader&lt;/h2&gt;&#xA;&lt;p&gt;SliceHeader 如其名，Slice + Header，看上去很直观，实际上是 Go Slice（切片）的运行时表现。&lt;/p&gt;&#xA;&lt;p&gt;SliceHeader 的定义如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type SliceHeader struct {&#xA; Data uintptr&#xA; Len  int&#xA; Cap  int&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Data：指向具体的底层数组。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Len：代表切片的长度。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Cap：代表切片的容量。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;既然知道了切片的运行时表现，那是不是就意味着我们可以自己造一个？&lt;/p&gt;&#xA;&lt;p&gt;在日常程序中，可以利用标准库 &lt;code&gt;reflect&lt;/code&gt; 提供的 &lt;code&gt;SliceHeader&lt;/code&gt; 结构体造一个：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;  // 初始化底层数组&#xA; s := [4]string{&amp;#34;脑子&amp;#34;, &amp;#34;进&amp;#34;, &amp;#34;煎鱼&amp;#34;, &amp;#34;了&amp;#34;}&#xA; s1 := s[0:1]&#xA; s2 := s[:]&#xA;&#xA;  // 构造 SliceHeader&#xA; sh1 := (*reflect.SliceHeader)(unsafe.Pointer(&amp;amp;s1))&#xA; sh2 := (*reflect.SliceHeader)(unsafe.Pointer(&amp;amp;s2))&#xA; fmt.Println(sh1.Len, sh1.Cap, sh1.Data)&#xA; fmt.Println(sh2.Len, sh2.Cap, sh2.Data)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你认为输出结果是什么，这两个新切片会指向同一个底层数组的内存地址吗？&lt;/p&gt;</description>
    </item>
    <item>
      <title>群里又吵起来了，Go 是传值还是传引用？</title>
      <link>https://note.lican.site/posts/posts/go/value-quote/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:52 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/value-quote/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在咱们的 Go 交流群里，有一个小伙伴问了 “xxx 是不是引用类型？” 这个问题，引发了将近 5 小时的讨论：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9be6b8a7ae844766afa6c2a79c3666d5~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;兜兜转转回到了日经的问题，几乎每个月都要有人因此吵一架。就是 &lt;strong&gt;Go 语言到底是传值（值传递），还是传引用（引用传递）&lt;/strong&gt;？&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-官方的定义&#34;&gt;Go 官方的定义&lt;/h2&gt;&#xA;&lt;p&gt;本部分引用 Go 官方 FAQ 的 “When are function parameters passed by value?”，内容如下。&lt;/p&gt;&#xA;&lt;p&gt;如同 C 系列的所有语言一样，&lt;strong&gt;Go 语言中的所有东西都是以值传递的&lt;/strong&gt;。也就是说，一个函数总是得到一个被传递的东西的副本，就像有一个赋值语句将值赋给参数一样。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4dc92546d5494e5b9a2a2a5083aa0a5b~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;向一个函数传递一个 int 值，就会得到 int 的副本。&lt;/p&gt;&#xA;&lt;p&gt;而传递一个指针值就会得到指针的副本，但不会得到它所指向的数据。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;map 和 slice 的行为类似于指针：它们是包含指向底层 map 或 slice 数据的指针的描述符。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;复制一个 map 或 slice 值并不会复制它所指向的数据。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;复制一个接口值会复制存储在接口值中的东西。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;如果接口值持有一个结构，复制接口值就会复制该结构。如果接口值持有一个指针，复制接口值会复制该指针，但同样不会复制它所指向的数据。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;划重点，Go 语言中一切都是值传递，没有引用传递。不要直接把其他概念硬套上来，会犯先入为主的错误的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;传值和传引用&#34;&gt;传值和传引用&lt;/h2&gt;&#xA;&lt;h3 id=&#34;传值&#34;&gt;传值&lt;/h3&gt;&#xA;&lt;p&gt;传值，也叫做值传递（pass by value）。其&lt;strong&gt;指的是在调用函数时将实际参数复制一份传递到函数中&lt;/strong&gt;，这样在函数中如果对参数进行修改，将不会影响到实际参数。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，值传递，所传递的是该参数的副本，是复制了一份的，本质上不能认为是一个东西，指向的不是一个内存地址。&lt;/p&gt;&#xA;&lt;p&gt;案例一如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA; s := &amp;#34;脑子进煎鱼了&amp;#34;&#xA; fmt.Printf(&amp;#34;main 内存地址：%p\n&amp;#34;, &amp;amp;s)&#xA; hello(&amp;amp;s)&#xA;}&#xA;&#xA;func hello(s *string) {&#xA; fmt.Printf(&amp;#34;hello 内存地址：%p\n&amp;#34;, &amp;amp;s)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>详解 Go 空结构体的 3 种使用场景</title>
      <link>https://note.lican.site/posts/posts/go/empty-struct/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:51 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/empty-struct/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在大家初识 Go 语言时，总会拿其他语言的基本特性来类比 Go 语言，说白了就是老知识和新知识产生关联，实现更高的学习效率。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/87c66858abf04b848643b6fa03f4bdab~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;最常见的类比，就是 “Go 语言如何实现面向对象？”，进一步展开就是 Go 语言如何实现面向对象特性中的继承。&lt;/p&gt;&#xA;&lt;p&gt;这不仅在学习中才用到类比，在业内的 Go 面试中也有非常多的面试官喜欢问：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d1cc9c2b2e174fc4a82506b368591a70~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;来自读者微信群&lt;/p&gt;&#xA;&lt;p&gt;在今天这篇文章中，煎鱼带大家具体展开了解这块的知识。一起愉快地开始吸鱼之路。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是面向对象&#34;&gt;什么是面向对象&lt;/h2&gt;&#xA;&lt;p&gt;在了解 Go 语言是不是面向对象（简称：OOP） 之前，我们必须先知道 OOP 是啥，得先给他 “下定义”。&lt;/p&gt;&#xA;&lt;p&gt;根据 Wikipedia 的定义，我们梳理出 OOP 的几个基本认知：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;面向对象编程（OOP）是一种基于 &amp;ldquo;对象&amp;rdquo; 概念的编程范式，它可以包含数据和代码：数据以字段的形式存在（通常称为属性或属性），代码以程序的形式存在（通常称为方法）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对象自己的程序可以访问并经常修改自己的数据字段。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对象经常被定义为类的一个实例。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;对象利用属性和方法的私有/受保护/公共可见性，对象的内部状态受到保护，不受外界影响（被封装）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;基于这几个基本认知进行一步延伸出，面向对象的三大基本特性：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;封装。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;继承。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;多态。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;至此对面向对象的基本概念讲解结束，想更进一步了解的可自行网上冲浪。&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-是面向对象的语言吗&#34;&gt;Go 是面向对象的语言吗&lt;/h2&gt;&#xA;&lt;p&gt;“Go 语言是否一门面向对象的语言？”，这是一个日经话题。官方 FAQ 给出的答复是：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bb8296e58a6d4c7c882984dcceaaf9c0~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;是的，也不是。原因是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Go 有类型和方法，并且允许面向对象的编程风格，但没有类型层次。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Go 中的 &amp;ldquo;接口 &amp;ldquo;概念提供了一种不同的方法，我们认为这种方法易于使用，而且在某些方面更加通用。还有一些方法可以将类型嵌入到其他类型中，以提供类似的东西，但不等同于子类。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Go 中的方法比 C++ 或 Java 中的方法更通用：它们可以为任何类型的数据定义，甚至是内置类型，如普通的、&amp;ldquo;未装箱的 &amp;ldquo;整数。它们并不局限于结构（类）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Go 由于缺乏类型层次，Go 中的 &amp;ldquo;对象 &amp;ldquo;比 C++ 或 Java 等语言更轻巧。&lt;/p&gt;</description>
    </item>
    <item>
      <title>《漫谈 MQ》要消息队列（MQ）有什么用？</title>
      <link>https://note.lican.site/posts/posts/why-mq/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/why-mq/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。想是问题，做是答案。&lt;/p&gt;&#xA;&lt;p&gt;最近我有一个朋友公司踩了不少消息队列（MQ）的坑，让人无奈不已。因此计划写 MQ 系列的技术文章，来科普更多这块的知识。&lt;/p&gt;&#xA;&lt;p&gt;目前 MQ 也是互联网应用中非常常用的基础组件了，面试特爱问。基本有一定规模的系统都能看见他的踪影。&lt;/p&gt;&#xA;&lt;p&gt;无论是 RocketMQ、Kafka、RabbitMQ 等，都围绕着根本的设计出发产生不同的高级功能，甚至可能是雷同的设计有 N 个名字。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是-mq&#34;&gt;什么是 MQ&lt;/h2&gt;&#xA;&lt;p&gt;MQ 一般代指消息队列（Message Queue）。它是一个抽象层，允许多个进程（可能在不同的机器上）通过各种模式（例如：点对点，发布订阅等）进行通信。&lt;/p&gt;&#xA;&lt;p&gt;也可以根据不同的实现，它可以被配置为保证可靠性、错误报告、安全、发现、性能等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要-mq&#34;&gt;为什么需要 MQ&lt;/h2&gt;&#xA;&lt;p&gt;在当下 MQ 的必要场景，比较经典的说辞就是 “异步、削峰、解耦”。是各类秒杀系统的设计核心，甚至会作为不少云厂商的卖点，每家都有自己的生态圈。&lt;/p&gt;&#xA;&lt;p&gt;核心分为三个要点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;解耦。&lt;/li&gt;&#xA;&lt;li&gt;削峰。&lt;/li&gt;&#xA;&lt;li&gt;异步。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;解耦&#34;&gt;解耦&lt;/h3&gt;&#xA;&lt;p&gt;在业务系统设计中，我们常常会与一个平台系统 A，他汇聚了许许多多的系统的对接。例如，系统 A 作为平台拥有大量用户操作，自然就有非常多的用户行为。&lt;/p&gt;&#xA;&lt;p&gt;虽然他自己可能不大需要，但是其他子系统就不同了，会要系统 A 来调用他们提供的接口，传输各种行为数据。&lt;/p&gt;&#xA;&lt;p&gt;其链路依赖如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/84478d2799861f81519ede0ba4ceb91d.jpg&#34; alt=&#34;多重依赖&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这时候作为平台方的系统 A 就烦死了，来一个要对接一个，就得安排一个人排工期和迭代。对方还有可能出现系统不稳定，还得关注他们的稳定性和诉求。&lt;/p&gt;&#xA;&lt;p&gt;但用了 MQ 后就不一样了，如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/b6c79dbe5c848ed32e347de4042cd9b6.jpg&#34; alt=&#34;MQ 解耦直接依赖&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;系统 A 只需要将消息放到 MQ 中去，不管以后是对接系统 B、C、D、E&amp;hellip;，他都不需要太关心，不用一个个对接。用业务同学的话来讲，就是：“自己看文档，去 MQ 里拿，别来骚扰我”。&lt;/p&gt;&#xA;&lt;p&gt;以此 MQ 达到了系统间解耦的目的。&lt;/p&gt;&#xA;&lt;h3 id=&#34;削峰&#34;&gt;削峰&lt;/h3&gt;&#xA;&lt;p&gt;在 2C 类别的业务系统中，常常会有活动的概念，要面向用户做促销，像我们常见的双 11、618 都是这类营销，也是营销场景。&lt;/p&gt;&#xA;&lt;p&gt;但这种场景之下，会对系统产生较大的冲击。类似八二原则，也就是 80% 的流量集中在某个时间冲击进来，形成了流量尖峰（高 QPS），系统会因为承受不了如此大的压力，从而宕机。&lt;/p&gt;&#xA;&lt;p&gt;如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/e396606bb1aec70b43a7016933880f09.jpg&#34; alt=&#34;用户直接并发访问&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;用户的请求会经由系统 A 直击数据库。当然，在活动场景下的大流量，数据库自然也就撑不住了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>《漫谈 MQ》设计 MQ 的 3 个难点</title>
      <link>https://note.lican.site/posts/posts/mq-nodus/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/mq-nodus/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间我们分享了漫谈 MQ 的第一期《要消息队列（MQ）有什么用？》，感觉打开了一个新的世界。&lt;/p&gt;&#xA;&lt;p&gt;但很快就有小伙伴意识到了不妙，既然 MQ 承接了多个系统，那岂不是该有的问题，他都有，又或是更甚。如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/45b00332-9a06-49b6-a666-675890409c94.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天我们就进一步讲讲，&lt;strong&gt;设计 MQ 时很有可能会遇到的几个大难点&lt;/strong&gt;，在业内又配套用了什么解决方案去处理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;几个难点&#34;&gt;几个难点&lt;/h2&gt;&#xA;&lt;p&gt;从结论上来看，设计 MQ 这一个存在。会至少引发三大难点。堪称互联网经典的，也是面试官们最爱问的：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;高可用：代表系统的可用性程度，高可用性通常通过提高系统的容错能力来实现，从而减少系统宕机时间。&lt;/li&gt;&#xA;&lt;li&gt;高并发：代表通过设计保证系统能够同时并行处理很多请求，在同一个时间点，有很多用户同时访问同一系统、API、URL。&lt;/li&gt;&#xA;&lt;li&gt;高可靠：代表能够满足预计条件的一个系统或组件（例如：备份、故障处理、数据存储以及访问），比较经典的是 4 个9 等标准。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;高可用&#34;&gt;高可用&lt;/h3&gt;&#xA;&lt;p&gt;像前面评论区留言的兄弟截图表述的一样。&lt;/p&gt;&#xA;&lt;p&gt;虽然请求不直接找系统 A、B、C、D 了。但是请求都实打实的通过异步的方式打到了 MQ 上，就可以不断往 MQ 塞，变成了多个系统都在请求 MQ，可以认为压力比单系统同步调用大了不止一倍。&lt;/p&gt;&#xA;&lt;p&gt;同时 MQ 还要去做消费关系的维护，存储既有和新增的大量消息。是一个既要也要还要的典型场景。&lt;/p&gt;&#xA;&lt;p&gt;这样一来，新的一轮问题就出现了。就是要保证 MQ 的高可用，否则他轻轻松松就会被压到宕机，或是负载过高，出现一些匪夷所思的延迟。&lt;/p&gt;&#xA;&lt;p&gt;如何保证 MQ 的高可用，是一个大问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;高并发&#34;&gt;高并发&lt;/h3&gt;&#xA;&lt;p&gt;在高并发上的诉求上，其实是和高可用的场景是一样的。既然各业务系统都是异步的了，自然他也就不会像同步阻塞一样 “等” 你。&lt;/p&gt;&#xA;&lt;p&gt;像是我有一个朋友，他们喜欢批量清洗多租户的数据。业务程序也不怎么节制，几十、几百、上千万数据，利用 Go 语言写的，抄起 for-loop+go func 就是一把梭。刷刷刷一下子就就给打进 MQ 里。&lt;/p&gt;&#xA;&lt;p&gt;再多来几个业务系统这么干，这 MQ 并发就比较高了，单单维护就是头疼。很有可能事故背着背着，年底就 3.25 了。因为 MQ，在业务中的依赖非常重，是标准的核心基础设施。&lt;/p&gt;&#xA;&lt;p&gt;如何保证 MQ 能够承受高并发，是一个大问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;高可靠&#34;&gt;高可靠&lt;/h3&gt;&#xA;&lt;p&gt;对 MQ 来讲，高可靠性的诉求，又分为好几个角度去理解。如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;消息要靠谱：“我” 发的消息要能够可靠的到达 MQ，MQ 要能够正确的让消费者能够接收到推送或拉取。&lt;/li&gt;&#xA;&lt;li&gt;存储要靠谱：“我” 发的消息，还在 MQ 上时要存储好，不能发到 MQ 上就因为大量数据，丢了。又或是查询很慢。&lt;/li&gt;&#xA;&lt;li&gt;处理要靠谱：发了消息，可能会出现异常。发了消息，可能网络抖动，没有接收到。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;上述我们列了三点 “要靠谱” 的内容。实质上，对于 MQ 来讲，其每一块领域都要保证其可靠性，否则查起问题来，真的是会非常崩溃。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 凭什么不支持三元运算符？</title>
      <link>https://note.lican.site/posts/posts/go/ternary-operator/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/ternary-operator/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;这是一个很多其他语言工程师转 Go 语言的时间节点，这就难免不论一番比较。其中一个经典的运算上的就是 “三元运算符”：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/05766eebaf454d7fb91b60ab1c851cf4~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;为什么 Go 语言不支持三元运算符，Go 不支持三元运算符就是设计的不好，是历史在开倒车吗？&lt;/p&gt;&#xA;&lt;p&gt;今天就由煎鱼来和大家一起摸索为什么。&lt;/p&gt;&#xA;&lt;h2 id=&#34;三元运算符是什么&#34;&gt;三元运算符是什么&lt;/h2&gt;&#xA;&lt;p&gt;三元运算符，在典型的数学意义上，或者从解析器的角度来看，是一个需要三个参数的运算符。而我们日常中，最常见的是二元运算符：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;x + y&#xA;x / y&#xA;x * y&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;还有一元运算符：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;-a&#xA;~b&#xA;!c&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;以及今天的男主角 “三元运算符”。在 C/C++ 等多种语言中，我们可以根据条件声明和初始化变量的习惯来选择性使用三元条件运算符：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;int index = val &amp;gt; 0 ? val : -val&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;go-使用三元运算符&#34;&gt;Go 使用三元运算符&lt;/h2&gt;&#xA;&lt;p&gt;想在 Go 语言里也使用三元运算符时，发现居然没有&amp;hellip;想要实现与上面相同的代码段的方式似乎只能：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;var index int&#xA;&#xA;if val &amp;gt; 0 {&#xA;    index = val&#xA;} else {&#xA;    index = -val&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;看上去十分的冗余，不够简洁。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么-go-没有三元运算符&#34;&gt;为什么 Go 没有三元运算符&lt;/h2&gt;&#xA;&lt;p&gt;为什么 Go 没有 &lt;code&gt;?:&lt;/code&gt; 操作符，没有的话，官方推荐的方式是怎么样的。&lt;/p&gt;&#xA;&lt;p&gt;通过 Go FAQ 我们可以得知：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 并发读写 sync.map 的强大之处</title>
      <link>https://note.lican.site/posts/posts/go/sync-map/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/sync-map/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在之前的 《&lt;a href=&#34;http://mp.weixin.qq.com/s?__biz=MzUxMDI4MDc1NA==&amp;amp;mid=2247489045&amp;amp;idx=1&amp;amp;sn=197bda427246e16907c7b471a5dc0572&amp;amp;chksm=f9040348ce738a5ebf541954a4de29ce746238ab7f6e5a2af8a1765c5383ad4208f43b2bac4f&amp;amp;scene=21#wechat_redirect&#34;&gt;为什么 Go map 和 slice 是非线程安全的？&lt;/a&gt;》 文章中，我们讨论了 Go 语言的 map 和 slice 非线程安全的问题，基于此引申出了 map 的两种目前在业界使用的最多的并发支持的模式。&lt;/p&gt;&#xA;&lt;p&gt;分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;原生 map + 互斥锁或读写锁 mutex。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;标准库 sync.Map（Go1.9及以后）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;有了选择，总是有选择困难症的，这&lt;strong&gt;两种到底怎么选，谁的性能更加的好&lt;/strong&gt;？我有一个朋友说 标准库 sync.Map 性能菜的很，不要用。我到底听谁的&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;今天煎鱼就带你揭秘 Go sync.map，我们先会了解清楚什么场景下，Go map 的多种类型怎么用，谁的性能最好！&lt;/p&gt;&#xA;&lt;p&gt;接着根据各 map 性能分析的结果，针对性的对 sync.map 进行源码解剖，了解 WHY。&lt;/p&gt;&#xA;&lt;p&gt;一起愉快地开始吸鱼之路。&lt;/p&gt;&#xA;&lt;h2 id=&#34;syncmap-优势&#34;&gt;sync.Map 优势&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 官方文档中明确指出 Map 类型的一些建议：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6500ee41a08a415ca681fa427f5032b3~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;多个 goroutine 的并发使用是安全的，不需要额外的锁定或协调控制。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;大多数代码应该使用原生的 map，而不是单独的锁定或协调控制，以获得更好的类型安全性和维护性。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;同时 Map 类型，还针对以下场景进行了性能优化：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;当一个给定的键的条目只被写入一次但被多次读取时。例如在仅会增长的缓存中，就会有这种业务场景。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;当多个 goroutines 读取、写入和覆盖不相干的键集合的条目时。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这两种情况与 Go map 搭配单独的 Mutex 或 RWMutex 相比较，使用 Map 类型可以大大减少锁的争夺。&lt;/p&gt;</description>
    </item>
    <item>
      <title>回答我，停止 Goroutine 有几种方法？</title>
      <link>https://note.lican.site/posts/posts/go/stop-goroutine/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/stop-goroutine/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;协程（goroutine）作为 Go 语言的扛把子，经常在各种 Go 工程项目中频繁露面，甚至有人会为了用 goroutine 而强行用他。&lt;/p&gt;&#xA;&lt;p&gt;在 Go 工程师的面试中，也绕不开他，会有人问 ”如何停止一个 goroutine？”，一下子就把话题范围扩大了，这是一个涉及多个知识点的话题，能进一步深入问。&lt;/p&gt;&#xA;&lt;p&gt;为此，今天煎鱼就带大家了解一下停止 goroutine 的方法！&lt;/p&gt;&#xA;&lt;h2 id=&#34;goroutine-案例&#34;&gt;goroutine 案例&lt;/h2&gt;&#xA;&lt;p&gt;在日常的工作中，我们常会有这样的 Go 代码，go 关键字一把搜起一个 goroutine：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() { &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;初入 goroutine 大门的开发者可能就完事了，但跑一段时间后，他就可能会遇到一些问题，苦苦排查&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;像是：当 goroutine 内的任务，运行的太久，又或是卡死了&amp;hellip;就会一直阻塞在系统中，变成 goroutine 泄露，或是间接造成资源暴涨，会带来许多的问题。&lt;/p&gt;&#xA;&lt;p&gt;如何在停止 goroutine，就成了一门必修技能了，不懂就没法用好 goroutine。&lt;/p&gt;&#xA;&lt;h2 id=&#34;关闭-channel&#34;&gt;关闭 channel&lt;/h2&gt;&#xA;&lt;p&gt;第一种方法，就是借助 channel 的 close 机制来完成对 goroutine 的精确控制。&lt;/p&gt;&#xA;&lt;p&gt;代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;结束&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼还没进锅里...&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼进脑子里了！&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;close(&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 Go 语言的 channel 中，channel 接受数据有两种方法：&lt;/p&gt;</description>
    </item>
    <item>
      <title>多 Goroutine 如何优雅处理错误？</title>
      <link>https://note.lican.site/posts/posts/go/goroutine-errors/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/goroutine-errors/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在 Go 语言中，goroutine 的使用是非常频繁的，因此在日常编码的时候我们会遇到一个问题，那就是 goroutine 里面的错误处理，怎么做比较好？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/72758b15-f9b7-4437-ba17-b37a36f285ae.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这是来自我读者群的问题。作为一个宠粉煎鱼，我默默记下了这个技术话题。今天煎鱼就大家来看看多 goroutine 的错误处理机制也有哪些！&lt;/p&gt;&#xA;&lt;p&gt;一般来讲，我们的业务代码会是：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WaitGroup&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼想报错...&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，我们运行了多个 goroutine。但我想抛出 error 的错误信息出来，似乎没什么好办法&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;通过错误日志记录&#34;&gt;通过错误日志记录&lt;/h2&gt;&#xA;&lt;p&gt;为此，业务代码中常见的第一种方法：通过把错误记录写入日志文件中，再结合相关的 logtail 进行采集和梳理。&lt;/p&gt;&#xA;&lt;p&gt;但这又会引入新的问题，那就是调用错误日志的方法写的到处都是。代码结构也比较乱，不直观。&lt;/p&gt;&#xA;&lt;p&gt;最重要的是无法针对 error 做特定的逻辑处理和流转。&lt;/p&gt;&#xA;&lt;h2 id=&#34;利用-channel-传输&#34;&gt;利用 channel 传输&lt;/h2&gt;&#xA;&lt;p&gt;这时候大家可能会想到 Go 的经典哲学：&lt;strong&gt;不要通过共享内存来通信，而是通过通信来实现内存共享&lt;/strong&gt;（Do not communicate by sharing memory; instead, share memory by communicating）。&lt;/p&gt;&#xA;&lt;p&gt;第二种的方法：利用 channel 来传输多个 goroutine 中的 errors：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gerrors&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wgDone&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;sync&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WaitGroup&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;returnError&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gerrors&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;wg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Wait&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;close(&lt;span style=&#34;color:#a6e22e&#34;&gt;wgDone&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;wgDone&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gerrors&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;close(&lt;span style=&#34;color:#a6e22e&#34;&gt;gerrors&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;returnError&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;errors&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼报错了...&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>小技巧分享：在 Go 如何实现枚举？</title>
      <link>https://note.lican.site/posts/posts/go/enum/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/enum/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在日常的业务工程开发中，我们常常会有使用枚举值的诉求，枚举控的好，测试值边界一遍过&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;有的小伙伴会说，在 Go 语言不是有 &lt;code&gt;iota&lt;/code&gt; 类型做枚举吗，那煎鱼你这篇文章还讲什么？&lt;/p&gt;&#xA;&lt;p&gt;讲道理，Go 语言并没有 enum 关键字，有用过 Protobuf 等的小伙伴知道，Go 语言只是 ”有限的枚举“ 支持，我们也会用常量来定义，枚举值也需要有字面意思的映射。&lt;/p&gt;&#xA;&lt;h2 id=&#34;示例&#34;&gt;示例&lt;/h2&gt;&#xA;&lt;p&gt;在一些业务场景下，是没法达到我们的诉求的。示例如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type FishType int&#xA;&#xA;const (&#xA; A FishType = iota&#xA; B&#xA; C&#xA; D&#xA;)&#xA;&#xA;func main() {&#xA; fmt.Println(A, B, C, D)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果为：“0 1 2 3”。这时候就一脸懵逼了&amp;hellip;枚举值，应该除了键以外，还得有个对应的值。也就是这个 “0 1 2 3” 分别对应着什么含义，是不是应该输出 ”A B C D“&lt;/p&gt;&#xA;&lt;p&gt;但 Go 语言这块就没有直接的支撑了，因此这不是一个完整的枚举类型的实现。&lt;/p&gt;&#xA;&lt;p&gt;同时假设我们传入超过 &lt;code&gt;FishType&lt;/code&gt; 类型声明范围的枚举值，在 Go 语言中默认也不会有任何控制，是正常输出的。&lt;/p&gt;&#xA;&lt;p&gt;上述这种 Go 枚举实现，在某种情况下是不完全的，严格意义上不能成为 enum（枚举）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;使用-string-做枚举&#34;&gt;使用 String 做枚举&lt;/h2&gt;&#xA;&lt;p&gt;如果要支持枚举值的对应输出的话，我们可以通过如下方式：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type FishType int&#xA;&#xA;const (&#xA; A FishType = iota&#xA; B&#xA; C&#xA; D&#xA;)&#xA;&#xA;func (f FishType) String() string {&#xA; return [...]string{&amp;#34;A&amp;#34;, &amp;#34;B&amp;#34;, &amp;#34;C&amp;#34;, &amp;#34;D&amp;#34;}[f]&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;运行程序：&lt;/p&gt;</description>
    </item>
    <item>
      <title>提高 Go 程序健壮性，Fuzzing 要来了！</title>
      <link>https://note.lican.site/posts/posts/go/fuzzing/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/fuzzing/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;就在前几天，Go1.17 beta1 正式发布：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/fb4ceb3d-ef1c-4c32-a7c3-a4188a0d74b0.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;兴冲冲本想着看一下当初在 Go1.17 的计划中，预计会支持的新特性：模糊测试（Fuzzing）。不过没想到&amp;hellip;计划赶不上变化，官方正式宣告 Fuzzing 不会出现在 Go1.17 的新功能中。&lt;/p&gt;&#xA;&lt;p&gt;煎鱼在悲伤之际，发现 Go 在 dev.fuzz 分支上提供了该功能的 Beta 测试，因此今天带大家一起来深入该特性。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是-fuzzing&#34;&gt;什么是 Fuzzing&lt;/h2&gt;&#xA;&lt;p&gt;Fuzzing 是一种自动测试技术，包括向计算机程序提供随机数据作为输入。然后监测程序是否出现恐慌、断言失败、无限循环等。&lt;/p&gt;&#xA;&lt;p&gt;Fuzzing 不是使用一个小的、预先定义好的手动创建的输入集（如单元测试），而是用新的案例不断地测试代码，以努力 ”锻炼“ 有关软件的所有方面。&lt;/p&gt;&#xA;&lt;p&gt;这听起来很 ”难“。但在过去的几年里，Fuzzing 的技术水平有了很大的提高。Fuzzing 不再是需要专业知识才能成功使用的东西，现代模糊测试策略能更快、更有效地找到有用的输入。&lt;/p&gt;&#xA;&lt;p&gt;在应用程序中，就是你只要引入一个 package，对着 API 一顿用就可以了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要做-fuzzing&#34;&gt;为什么要做 Fuzzing&lt;/h2&gt;&#xA;&lt;p&gt;可能会有小伙伴说，测试？直接人工测试，再把测试数据准备一下，配套 YAPI 等接口管理平台，把自动化接口测试一弄就好了。还需要 Fuzzing 吗？&lt;/p&gt;&#xA;&lt;p&gt;其实 Fuzzing 是对其他形式的测试、代码审查和静态分析的补充，它通过生成一个随机测试用例去覆盖人为测不到的各种复杂场景。而这些输入几乎不可能人为去构造，总会被传统测试所遗漏。&lt;/p&gt;&#xA;&lt;h2 id=&#34;发生在身边的-fuzzing&#34;&gt;发生在身边的 Fuzzing&lt;/h2&gt;&#xA;&lt;p&gt;实际上 Go-fuzz 对 Go 标准库进行过测试，依然这这之中发现了 200  多个 bug：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/9b00972c-2231-4406-84b8-2e8e44f57d6d.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这还是建立在标准库已经比较成熟，且由非常有经验的开发者编写，在生产中使用多年的情况下，依然有如此多的问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;快速上手&#34;&gt;快速上手&lt;/h2&gt;&#xA;&lt;p&gt;我们需要在本地执行如下命令，需开启 GO111MODULE 和天梯：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;get&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;golang&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;org&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;dl&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gotip&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;$&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gotip&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;download&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;dev&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;fuzz&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;执行完毕后会从 dev.fuzz 分支构建 Go 工具链，同时 gotip 可以作为 go 命令的替代者命令，也就是可以运行 Fuzzing 的相关代码了。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么 Go map 和 slice 是非线程安全的？</title>
      <link>https://note.lican.site/posts/posts/go/map-slice-concurrency/</link>
      <pubDate>Fri, 31 Dec 2021 12:54:49 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map-slice-concurrency/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;初入 Go 语言的大门，有不少的小伙伴会快速的 3 天精通 Go，5 天上手项目，14 天上线业务迭代，21 天排查、定位问题，顺带捎个反省报告。&lt;/p&gt;&#xA;&lt;p&gt;其中最常见的初级错误，Go 面试较最爱问的问题之一：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8d1a0506617a4729abe35927d87508d0~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&#xA;（来自读者提问）&lt;/p&gt;&#xA;&lt;p&gt;为什么在 Go 语言里，map 和 slice 不支持并发读写，也就是是非线程安全的，为什么不支持？&lt;/p&gt;&#xA;&lt;p&gt;见招拆招后，紧接着就会开始讨论如何让他们俩 ”冤家“ 支持并发读写？&lt;/p&gt;&#xA;&lt;p&gt;今天我们这篇文章就来理一理，了解其前因后果，一起吸鱼学懂 Go 语言。&lt;/p&gt;&#xA;&lt;h2 id=&#34;非线程安全的例子&#34;&gt;非线程安全的例子&lt;/h2&gt;&#xA;&lt;h3 id=&#34;slice&#34;&gt;slice&lt;/h3&gt;&#xA;&lt;p&gt;我们使用多个 goroutine 对类型为 slice 的变量进行操作，看看结果会变的怎么样。&lt;/p&gt;&#xA;&lt;p&gt;如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA; var s []string&#xA; for i := 0; i &amp;lt; 9999; i++ {&#xA;  go func() {&#xA;   s = append(s, &amp;#34;脑子进煎鱼了&amp;#34;)&#xA;  }()&#xA; }&#xA;&#xA; fmt.Printf(&amp;#34;进了 %d 只煎鱼&amp;#34;, len(s))&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// 第一次执行&#xA;进了 5790 只煎鱼&#xA;// 第二次执行&#xA;进了 7370 只煎鱼&#xA;// 第三次执行&#xA;进了 6792 只煎鱼&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;你会发现无论你执行多少次，每次输出的值大概率都不会一样。也就是追加进 slice 的值，出现了覆盖的情况。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 数组比切片好在哪？</title>
      <link>https://note.lican.site/posts/posts/go/go-array-slice/</link>
      <pubDate>Fri, 17 Sep 2021 12:43:08 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-array-slice/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间有播放一条快讯，就是 Go1.17 会正式支持切片（Slice）转换到数据（Array），不再需要用以前那种骚办法了，安全了许多。&lt;/p&gt;&#xA;&lt;p&gt;但是也有同学提出了新的疑惑，在 Go 语言中，数组其实是用的相对较少的，甚至会有同学认为在 Go 里可以把数组给去掉。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9764cd832d1e4875953b66434beab8e4~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;数组相较切片到底有什么优势，我们又应该在什么场景下使用呢？&lt;/p&gt;&#xA;&lt;p&gt;这是一个我们需要深究的问题，因此今天就跟大家一起来一探究竟，本文会先简单介绍数组和切片是什么，再进一步对数组的使用场景剖析。&lt;/p&gt;&#xA;&lt;p&gt;一起愉快地开始吸鱼之路。&lt;/p&gt;&#xA;&lt;h2 id=&#34;数组是什么&#34;&gt;数组是什么&lt;/h2&gt;&#xA;&lt;p&gt;Go 语言中有一种基本数据类型，叫数组。其格式为：&lt;code&gt;[n]T&lt;/code&gt;。是一个包含 N 个类型 T 的值的数组。&lt;/p&gt;&#xA;&lt;p&gt;基本声明格式为：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;var a [10]int&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;代表的是声明了一个变量 a 是一个包含 10 个整数的数组。数组的长度是其类型的一部分，所以数组不能被随意调整大小。&lt;/p&gt;&#xA;&lt;p&gt;在使用例子上：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA; var a [2]string&#xA; a[0] = &amp;#34;脑子进&amp;#34;&#xA; a[1] = &amp;#34;煎鱼了&amp;#34;&#xA; fmt.Println(a[0], a[1])&#xA; fmt.Println(a)&#xA;&#xA; primes := [6]int{2, 3, 5, 7, 11, 13}&#xA; fmt.Println(primes)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;脑子进 煎鱼了&#xA;[脑子进 煎鱼了]&#xA;[2 3 5 7 11 13]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在赋值和访问上，数组可以针对不同的索引，进行单独操作。在内存布局上，数组的索引 0 和 1&amp;hellip;是会在相邻区域，可直接访问。&lt;/p&gt;&#xA;&lt;h2 id=&#34;切片是什么&#34;&gt;切片是什么&lt;/h2&gt;&#xA;&lt;p&gt;为什么数组在业务代码似乎用的很少。因为 Go 语言有一个切片的数据类型：&lt;/p&gt;</description>
    </item>
    <item>
      <title>上帝视角看 “Go 项目标准布局” 之争</title>
      <link>https://note.lican.site/posts/posts/go/go-standards/</link>
      <pubDate>Mon, 13 Sep 2021 23:34:23 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-standards/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间 Go 语言社区有一件事情引爆了热议，那就是 &lt;code&gt;golang-standards/project-layout&lt;/code&gt; 项目的 “Go 项目的标准布局” 之争。&lt;/p&gt;&#xA;&lt;p&gt;没想到，五一假期，认真一看，这个 issues 已经提出将近一个月了，仍然在热议阶段，我想，咱们需要好好的聊聊这个话题。&lt;/p&gt;&#xA;&lt;p&gt;煎鱼带你了解下的前因后果，再分享我的看法和业务真实情况。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;h3 id=&#34;问题发生地&#34;&gt;问题发生地&lt;/h3&gt;&#xA;&lt;p&gt;在 GitHub 上有一个项目 Spaghetti（github.com/adonovan/spaghetti），是 Go 软件包的一个依赖性分析工具。&lt;/p&gt;&#xA;&lt;p&gt;该项目的目录结构如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/11b7f74aa3944e509c89bcbfc51a2c99~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;看上去并不复杂，代码量不多，文件平铺也不超过一屏，就是一个布局比较简单的项目。&lt;/p&gt;&#xA;&lt;p&gt;有一位老哥提出了一个 PR，明确的期望该项目按照 &lt;code&gt;golang-standards/project-layout&lt;/code&gt; 项目给出的 “标准” 布局来调整。：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e0da59130ce94ee190d51491396d6919~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我猜测该项目可能是因为把 Go、HTML、JS、PNG 和 go.mod 文件等摆在了一起，引起了该同学的一丝丝纠结，觉得比较乱？&lt;/p&gt;&#xA;&lt;h3 id=&#34;标准布局-长什么样子&#34;&gt;“标准布局“ 长什么样子&lt;/h3&gt;&#xA;&lt;p&gt;在 &lt;code&gt;golang-standards/project-layout&lt;/code&gt; 项目中，其自称：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/55511ceb43cb48c59d0ce302783eec59~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;图片&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;项目的组织名也是 &amp;ldquo;golang-standards&amp;rdquo;，其提供了一个基本的 Go 项目布局，精简展示如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;project-layout&#xA;├── api&#xA;├── cmd&#xA;├── configs&#xA;├── docs&#xA;├── go.mod&#xA;├── init&#xA;├── internal&#xA;├── pkg&#xA;├── scripts&#xA;├── vendor&#xA;├── ...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;/cmd：项目主要的应用程序。&lt;/p&gt;</description>
    </item>
    <item>
      <title>用 Go map 要注意这个细节，避免依赖他！</title>
      <link>https://note.lican.site/posts/posts/go/go-map-access/</link>
      <pubDate>Sun, 12 Sep 2021 17:47:29 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-map-access/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近又有同学问我这个日经话题，想转他文章时，结果发现我的公众号竟然没有发过，因此今天我再唠叨两句，好让大家避开这个 “坑”。&lt;/p&gt;&#xA;&lt;p&gt;有的小伙伴没留意过 Go map 输出、遍历顺序，&lt;strong&gt;以为它是稳定的有序的，会在业务程序中直接依赖这个结果集顺序，结果栽了个大跟头&lt;/strong&gt;，吃了线上 BUG。&lt;/p&gt;&#xA;&lt;p&gt;有的小伙伴知道是无序的，但却不知道为什么,有的却理解错误？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;http://wx2.sinaimg.cn/large/006fVPCvly1g1s1ah84k8j30k70dvaac.jpg&#34; alt=&#34;奇怪的输出结果&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天通过本文，我们将揭开 &lt;code&gt;for range map&lt;/code&gt; 输出的 “神秘” 面纱，看看它内部实现到底是怎么样的，顺序到底是怎么样？&lt;/p&gt;&#xA;&lt;p&gt;开始吸鱼之路。&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY2&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY3&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY4&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY5&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k: %v, v: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;假设运行这段代码，输出的结果是怎么样？是有序，还是无序输出呢？&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;k: 3, v: EDDYCJY4&#xA;k: 4, v: EDDYCJY5&#xA;k: 0, v: EDDYCJY1&#xA;k: 1, v: EDDYCJY2&#xA;k: 2, v: EDDYCJY3&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从输出结果上来讲，是非固定顺序输出的，也就是每次都不一样。但这是为什么呢？&lt;/p&gt;&#xA;&lt;p&gt;首先&lt;strong&gt;建议你先自己想想原因&lt;/strong&gt;。其次我在面试时听过一些说法。有人说因为是哈希的所以就是无（乱）序等等说法。当时我是有点 ？？？&lt;/p&gt;&#xA;&lt;p&gt;这也是这篇文章出现的原因，希望大家可以一起研讨一下，理清这个问题 ：）&lt;/p&gt;&#xA;&lt;h2 id=&#34;看一下汇编&#34;&gt;看一下汇编&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;    ...&#xA;&#x9;0x009b 00155 (main.go:11)&#x9;LEAQ&#x9;type.map[int32]string(SB), AX&#xA;&#x9;0x00a2 00162 (main.go:11)&#x9;PCDATA&#x9;$2, $0&#xA;&#x9;0x00a2 00162 (main.go:11)&#x9;MOVQ&#x9;AX, (SP)&#xA;&#x9;0x00a6 00166 (main.go:11)&#x9;PCDATA&#x9;$2, $2&#xA;&#x9;0x00a6 00166 (main.go:11)&#x9;LEAQ&#x9;&amp;#34;&amp;#34;..autotmp_3+24(SP), AX&#xA;&#x9;0x00ab 00171 (main.go:11)&#x9;PCDATA&#x9;$2, $0&#xA;&#x9;0x00ab 00171 (main.go:11)&#x9;MOVQ&#x9;AX, 8(SP)&#xA;&#x9;0x00b0 00176 (main.go:11)&#x9;PCDATA&#x9;$2, $2&#xA;&#x9;0x00b0 00176 (main.go:11)&#x9;LEAQ&#x9;&amp;#34;&amp;#34;..autotmp_2+72(SP), AX&#xA;&#x9;0x00b5 00181 (main.go:11)&#x9;PCDATA&#x9;$2, $0&#xA;&#x9;0x00b5 00181 (main.go:11)&#x9;MOVQ&#x9;AX, 16(SP)&#xA;&#x9;0x00ba 00186 (main.go:11)&#x9;CALL&#x9;runtime.mapiterinit(SB)&#xA;&#x9;0x00bf 00191 (main.go:11)&#x9;JMP&#x9;207&#xA;&#x9;0x00c1 00193 (main.go:11)&#x9;PCDATA&#x9;$2, $2&#xA;&#x9;0x00c1 00193 (main.go:11)&#x9;LEAQ&#x9;&amp;#34;&amp;#34;..autotmp_2+72(SP), AX&#xA;&#x9;0x00c6 00198 (main.go:11)&#x9;PCDATA&#x9;$2, $0&#xA;&#x9;0x00c6 00198 (main.go:11)&#x9;MOVQ&#x9;AX, (SP)&#xA;&#x9;0x00ca 00202 (main.go:11)&#x9;CALL&#x9;runtime.mapiternext(SB)&#xA;&#x9;0x00cf 00207 (main.go:11)&#x9;CMPQ&#x9;&amp;#34;&amp;#34;..autotmp_2+72(SP), $0&#xA;&#x9;0x00d5 00213 (main.go:11)&#x9;JNE&#x9;193&#xA;&#x9;...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们大致看一下整体过程，重点处理 Go map 循环迭代的是两个 runtime 方法，如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>生产环境遇到一个 Go 问题，整组人都懵逼了...</title>
      <link>https://note.lican.site/posts/posts/go/go-errors-boom/</link>
      <pubDate>Wed, 07 Jul 2021 12:43:49 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-errors-boom/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间正在疯狂写代码的时候，突然有一个读者给我提了一个问题，让我有了一定的兴趣：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c1011e66fe104d228dcaa2083b554fc8~tplv-k3u1fbpfcp-watermark.image&#34; alt=&#34;image.png&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我还是比较感兴趣的，因为是生产环境、有代码，且整组人都懵逼的问题。&lt;/p&gt;&#xA;&lt;p&gt;在征求了小伙伴的意见后，今天分享出来，大家也思考一下原因，一起规避这个 “坑”。&lt;/p&gt;&#xA;&lt;h2 id=&#34;案例一&#34;&gt;案例一&lt;/h2&gt;&#xA;&lt;p&gt;代码示例如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyErr&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Msg&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;GetErr&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetErr&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MyErr&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MyErr&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请思考一下，&lt;strong&gt;这段程序的输出结果是什么&lt;/strong&gt;？&lt;/p&gt;&#xA;&lt;p&gt;该程序所调用的 &lt;code&gt;GetErr&lt;/code&gt; 方法所返回的是 &lt;code&gt;nil&lt;/code&gt;，而外部判断是 &lt;code&gt;e == nil&lt;/code&gt;，因此最终的输出结果是 true，对吗？&lt;/p&gt;&#xA;&lt;p&gt;输出结果如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2021/04/04 08:39:04 false&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;答案是：false。&lt;/p&gt;&#xA;&lt;h2 id=&#34;案例二&#34;&gt;案例二&lt;/h2&gt;&#xA;&lt;p&gt;代码示例如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Base&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;do&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;App&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;base&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Base&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;base&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;GetApp&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;base&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;base&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetApp&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;App&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;App&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;do&lt;/span&gt;() {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请思考一下，&lt;strong&gt;这段程序的输出结果是什么&lt;/strong&gt;？&lt;/p&gt;</description>
    </item>
    <item>
      <title>经典面试题：你觉得 Go 在什么时候会抢占 P？</title>
      <link>https://note.lican.site/posts/posts/go/gmp-why-p/</link>
      <pubDate>Thu, 24 Jun 2021 12:42:05 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gmp-why-p/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天我们有聊到《单核 CPU，开两个 Goroutine，其中一个死循环，会怎么样？》的问题，我们在一个细节部分有提到：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6d9cdfb09590496daeca3675aae08611~tplv-k3u1fbpfcp-zoom-1.image&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;有新的小伙伴会产生更多的疑问，那就是在 Go 语言中，是如何抢占 P 的呢，这里面是怎么做的？&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章我们就来解密抢占 P。&lt;/p&gt;&#xA;&lt;h2 id=&#34;调度器的发展史&#34;&gt;调度器的发展史&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 语言中，Goroutine 早期是没有设计成抢占式的，早期 Goroutine 只有读写、主动让出、锁等操作时才会触发调度切换。&lt;/p&gt;&#xA;&lt;p&gt;这样有一个严重的问题，就是垃圾回收器进行 STW 时，如果有一个 Goroutine 一直都在阻塞调用，垃圾回收器就会一直等待他，不知道等到什么时候&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;这种情况下就需要抢占式调度来解决问题。如果一个 Goroutine 运行时间过久，就需要进行抢占来解决。&lt;/p&gt;&#xA;&lt;p&gt;这块 Go 语言在 Go1.2 起开始实现抢占式调度器，不断完善直至今日：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Go0.x：基于单线程的程调度器。&lt;/li&gt;&#xA;&lt;li&gt;Go1.0：基于多线程的调度器。&lt;/li&gt;&#xA;&lt;li&gt;Go1.1：基于任务窃取的调度器。&lt;/li&gt;&#xA;&lt;li&gt;Go1.2 - Go1.13：基于协作的抢占式调度器。&lt;/li&gt;&#xA;&lt;li&gt;Go1.14：基于信号的抢占式调度器。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;调度器的新提案：非均匀存储器访问调度（Non-uniform memory access，NUMA），&#xA;但由于实现过于复杂，优先级也不够高，因此迟迟未提上日程。&lt;/p&gt;&#xA;&lt;p&gt;有兴趣的小伙伴可以详见 Dmitry Vyukov, dvyukov 所提出的 &lt;a href=&#34;https://docs.google.com/document/u/0/d/1d3iI2QWURgDIsSR6G2275vMeQ_X7w-qxM2Vp7iGwwuM/pub&#34;&gt;NUMA-aware scheduler for Go&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要抢占-p&#34;&gt;为什么要抢占 P&lt;/h2&gt;&#xA;&lt;p&gt;为什么会要想去抢占 P 呢，说白了就是不抢，就没机会运行，会 hang 死。又或是资源分配不均了，&lt;/p&gt;&#xA;&lt;p&gt;这在调度器设计中显然是不合理的。&lt;/p&gt;&#xA;&lt;p&gt;跟这个例子一样：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// Main Goroutine &lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 模拟单核 CPU&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;runtime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GOMAXPROCS&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// 模拟 Goroutine 死循环&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Millisecond&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个例子在老版本的 Go 语言中，就会一直阻塞，没法重见天日，是一个需要做抢占的场景。&lt;/p&gt;</description>
    </item>
    <item>
      <title>用 Go struct 不能犯的一个低级错误！</title>
      <link>https://note.lican.site/posts/posts/go/go-empty-struct/</link>
      <pubDate>Thu, 17 Jun 2021 12:44:27 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-empty-struct/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前段时间我分享了 《手撕 Go 面试官：Go 结构体是否可以比较，为什么？》的文章，把基本 Go struct 的比较依据研究了一番。这不，最近有一位读者，遇到了一个关于 struct 的新问题，不得解。&lt;/p&gt;&#xA;&lt;p&gt;大家一起来看看，建议大家在看到代码例子后先思考一下答案，再往下看。&lt;/p&gt;&#xA;&lt;p&gt;独立思考很重要。&lt;/p&gt;&#xA;&lt;h2 id=&#34;疑惑的例子&#34;&gt;疑惑的例子&lt;/h2&gt;&#xA;&lt;p&gt;其给出的例子一如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;People&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;People&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;People&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你认为输出结果是什么呢？&lt;/p&gt;&#xA;&lt;p&gt;输出结果是：false。&lt;/p&gt;&#xA;&lt;p&gt;再稍加改造一下，例子二如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;People&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;People&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;People&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%p\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%p\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果是：true。&lt;/p&gt;&#xA;&lt;p&gt;他的问题是 &amp;ldquo;&lt;strong&gt;为什么第一个返回 false 第二个返回 true，是什么原因导致的&lt;/strong&gt;？&lt;/p&gt;&#xA;&lt;p&gt;煎鱼进一步的精简这个例子，得到最小示例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;println(&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; new(&lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;println(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// a, b; a &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; b&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0xc00005cf57 0xc00005cf57 false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// c, d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;amp;&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt; &amp;amp;&lt;span style=&#34;color:#f92672&#34;&gt;{}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;// c, d, c &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; d&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0x118c370 0x118c370 true&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一段代码的结果是 false，第二段的结果是 true，且可以看到内存地址指向的完全一样，也就是排除了输出后变量内存指向改变导致的原因。&lt;/p&gt;</description>
    </item>
    <item>
      <title>详解 Go 程序的启动流程，你知道 g0，m0 是什么吗？</title>
      <link>https://note.lican.site/posts/posts/go/go-bootstrap0/</link>
      <pubDate>Thu, 17 Jun 2021 12:42:42 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-bootstrap0/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;自古应用程序均从 Hello World 开始，你我所写的 Go 语言亦然：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import &amp;#34;fmt&amp;#34;&#xA;&#xA;func main() {&#xA;&#x9;fmt.Println(&amp;#34;hello world.&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这段程序的输出结果为 &lt;code&gt;hello world.&lt;/code&gt;，就是这么的简单又直接。但这时候又不禁思考了起来，这个 &lt;code&gt;hello world.&lt;/code&gt; 是怎么输出来，经历了什么过程。&lt;/p&gt;&#xA;&lt;p&gt;真是非常的好奇，今天我们就一起来探一探 Go 程序的启动流程。&#xA;其中涉及到 Go Runtime 的调度器启动，g0，m0 又是什么？&lt;/p&gt;&#xA;&lt;p&gt;车门焊死，正式开始吸鱼之路。&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-引导阶段&#34;&gt;Go 引导阶段&lt;/h2&gt;&#xA;&lt;h3 id=&#34;查找入口&#34;&gt;查找入口&lt;/h3&gt;&#xA;&lt;p&gt;首先编译上文提到的示例程序：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ GOFLAGS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-ldflags=-compressdwarf=false&amp;#34;&lt;/span&gt; go build &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在命令中指定了 GOFLAGS 参数，这是因为在 Go1.11 起，为了减少二进制文件大小，调试信息会被压缩。导致在 MacOS 上使用 gdb 时无法理解压缩的 DWARF 的含义是什么（而我恰恰就是用的 MacOS）。&lt;/p&gt;&#xA;&lt;p&gt;因此需要在本次调试中将其关闭，再使用 gdb 进行调试，以此达到观察的目的：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gdb awesomeProject &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; info files&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Symbols from &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/Users/eddycjy/go-application/awesomeProject/awesomeProject&amp;#34;&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Local exec file:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;/Users/eddycjy/go-application/awesomeProject/awesomeProject&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;, file type mach-o-x86-64.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;Entry point: 0x1063c80&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;0x0000000001001000 - 0x00000000010a6aca is .text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; b *0x1063c80&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Breakpoint &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; at 0x1063c80: file /usr/local/Cellar/go/1.15/libexec/src/runtime/rt0_darwin_amd64.s, line 8.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 Entry point 的调试，可看到真正的程序入口在 runtime 包中，不同的计算机架构指向不同。例如：&lt;/p&gt;</description>
    </item>
    <item>
      <title>跟面试官聊 Goroutine 泄露的 6 种方法，真刺激！</title>
      <link>https://note.lican.site/posts/posts/go/goroutine-leak/</link>
      <pubDate>Fri, 11 Jun 2021 12:54:49 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/goroutine-leak/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天分享 Go 群友提问的文章时，有读者在朋友圈下提到，希望我能够针对 Goroutine 泄露这块进行讲解，他在面试的时候经常被问到。&lt;/p&gt;&#xA;&lt;p&gt;今天的男主角，就是 Go 语言的著名品牌标识 Goroutine，一个随随便便就能开几十万个快车进车道的大杀器。&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文会聚焦于 Goroutine 泄露的 N 种方法，进行详解和说明。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要问&#34;&gt;为什么要问&lt;/h2&gt;&#xA;&lt;p&gt;面试官为啥会问 Goroutine（协程）泄露这种奇特的问题呢？&lt;/p&gt;&#xA;&lt;p&gt;可以猜测是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Goroutine 实在是使用门槛实在是太低了，随手就一个就能起，出现了不少滥用的情况。例如：并发 map。&lt;/li&gt;&#xA;&lt;li&gt;Goroutine 本身在 Go 语言的标准库、复合类型、底层源码中应用广泛。例如：HTTP Server 对每一个请求的处理就是一个协程去运行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;很多 Go 工程在线上出事故时，基本 Goroutine 的关联，大家都会作为救火队长，风风火火的跑去看指标、看日志，通过 PProf 采集 Goroutine 运行情况等。&lt;/p&gt;&#xA;&lt;p&gt;自然他也就是最受瞩目的那颗 “星” 了，所以在日常面试中，被问几率也就极高了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;goroutine-泄露&#34;&gt;Goroutine 泄露&lt;/h2&gt;&#xA;&lt;p&gt;了解清楚大家爱问的原因后，我们开始对 Goroutine 泄露的 N 种方法进行研究，希望通过前人留下的 “坑”，了解其原理和避开这些问题。&lt;/p&gt;&#xA;&lt;p&gt;泄露的原因大多集中在：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Goroutine 内正在进行 channel/mutex 等读写操作，但由于逻辑问题，某些情况下会被一直阻塞。&lt;/li&gt;&#xA;&lt;li&gt;Goroutine 内的业务逻辑进入死循环，资源一直无法释放。&lt;/li&gt;&#xA;&lt;li&gt;Goroutine 内的业务逻辑进入长时间等待，有不断新增的 Goroutine 进入等待。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;接下来我会引用在网上冲浪收集到的一些 Goroutine 泄露例子（会在文末参考注明出处）。&lt;/p&gt;&#xA;&lt;h3 id=&#34;channel-使用不当&#34;&gt;channel 使用不当&lt;/h3&gt;&#xA;&lt;p&gt;Goroutine+Channel 是最经典的组合，因此不少泄露都出现于此。&lt;/p&gt;</description>
    </item>
    <item>
      <title>你知道 Go 结构体和结构体指针调用有什么区别吗？</title>
      <link>https://note.lican.site/posts/posts/go/struct-pointer/</link>
      <pubDate>Sun, 06 Jun 2021 12:21:30 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/struct-pointer/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在分享《Go 结构体是否可以比较，为什么？》时，有小伙伴提出了新的问题：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a4d34c5312339b9909e482c18f0cdf4a.png&#34; alt=&#34;来自文章评论区&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;虽然大家提问题的速度已经超出了本鱼写文章的速度&amp;hellip;不过作为宠粉狂鱼，在此刻清明假期时还是写下了这篇文章。&lt;/p&gt;&#xA;&lt;p&gt;我在网上冲浪时搜索了相关问题，发现 6 年前就有 Go 开发者有一模一样的疑问，真是困扰了一代又一代的小伙伴。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/dbe910917c86e103648e314f79896a81.png&#34; alt=&#34;来自 stackoverflow.com&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;本期的男主角是《&lt;strong&gt;Go 结构体和结构体指针调用有什么区别&lt;/strong&gt;》，希望对大家有所帮助，带来一些思考。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;请在此处默念自己心目中的答案&lt;/strong&gt;，再和煎鱼一同研讨一波 Go 的技术哲学。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结构体是什么&#34;&gt;结构体是什么&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 语言中有个基本类型，开发者们称之为结构体（struct）。是 Go 语言中非常常用的，基本定义：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;struct_variable_type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;definition&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;definition&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;definition&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;简单示例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Vertex&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Vertex&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进了&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name2&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;蒸鱼&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;蒸鱼&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这部分属于基础知识，因此不再过多解释。如果看不懂，建议重学 Go 语言语法基础。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结构体和指针调用&#34;&gt;结构体和指针调用&lt;/h2&gt;&#xA;&lt;p&gt;讲解前置概要后，直接进入本文主题。如下例子：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyStruct&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MyStruct&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SetName1&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;MyStruct&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;SetName2&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该程序声明了一个 &lt;code&gt;User&lt;/code&gt; 结构体，其包含两个结构体方法，分别是 &lt;code&gt;SetName1&lt;/code&gt; 和 &lt;code&gt;SetName2&lt;/code&gt; 方法，两者之间的差异就是&lt;strong&gt;引用的方式不同&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 面试官：单核 CPU，开两个 Goroutine，其中一个死循环，会怎么样？</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-goroutineloop/</link>
      <pubDate>Mon, 05 Apr 2021 16:17:23 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-goroutineloop/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近金三银四，是面试的季节。在我的 Go 读者交流群里出现了许多小伙伴在讨论自己面试过程中所遇到的一些 Go 面试题。&lt;/p&gt;&#xA;&lt;p&gt;今天的男主角，是与 Go 工程师有调度相关的知识，那就是 “&lt;strong&gt;单核 CPU，开两个 Goroutine，其中一个死循环，会怎么样？&lt;/strong&gt;”&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;请在此处默念自己心目中的答案&lt;/strong&gt;，再往和煎鱼一起研讨一波 Go 的技术哲学。&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题定义&#34;&gt;问题定义&lt;/h2&gt;&#xA;&lt;p&gt;针对这个问题，我们需要把问题剖开来看看，其具有以下几个元素：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;运行 Go 程序的计算机只有一个单核 CPU。&lt;/li&gt;&#xA;&lt;li&gt;两个 Goroutine 在运行。&lt;/li&gt;&#xA;&lt;li&gt;一个 Goroutine 死循环。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;根据这道题的题意，可大致理解其想要问的是 Go 调度相关的一些知识理解。&lt;/p&gt;&#xA;&lt;h3 id=&#34;单核-cpu&#34;&gt;单核 CPU&lt;/h3&gt;&#xA;&lt;p&gt;第一个要点，就是要明确 “计算机只有一个单核 CPU” 这一个变量定义，对 Go 程序会产生什么影响，否则很难继续展开。&lt;/p&gt;&#xA;&lt;p&gt;既然明确涉及 Goroutine，这里就会考察到你对 Go 的调度模型 GMP 的基本理解了。&lt;/p&gt;&#xA;&lt;p&gt;从单核 CPU 来看，最大的影响就是 GMP 模型中的 P，因为 P 的数量默认是与 CPU 核数（GOMAXPROCS）保持一致的。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;G：Goroutine，实际上我们每次调用 &lt;code&gt;go func&lt;/code&gt; 就是生成了一个 G。&lt;/li&gt;&#xA;&lt;li&gt;P：Processor，处理器，一般 P 的数量就是处理器的核数，可以通过 &lt;code&gt;GOMAXPROCS&lt;/code&gt; 进行修改。&lt;/li&gt;&#xA;&lt;li&gt;M：Machine，系统线程。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这三者交互实际来源于 Go 的 M: N 调度模型。也就是 M 必须与 P 进行绑定，然后不断地在 M 上循环寻找可运行的 G 来执行相应的任务。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 内存泄露之痛，这篇把 Go timer.After 问题根因讲透了！</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-timer-memory/</link>
      <pubDate>Mon, 05 Apr 2021 16:16:47 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-timer-memory/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在公众号分享了一篇 Go timer 源码解析的文章《难以驾驭的 Go timer，一文带你参透计时器的奥秘》。&lt;/p&gt;&#xA;&lt;p&gt;在评论区有小伙伴提到了经典的 &lt;code&gt;timer.After&lt;/code&gt; 泄露问题，希望我能聊聊，这是一个不能不知的一个大 “坑”。&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章煎鱼就带大家来研讨一下这个问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;timerafter&#34;&gt;timer.After&lt;/h2&gt;&#xA;&lt;p&gt;今天是男主角是Go 标准库 time 所提供的 &lt;code&gt;After&lt;/code&gt; 方法。函数签名如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Time&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;该方法可以在一定时间（根据所传入的 Duration）后主动返回 &lt;code&gt;time.Time&lt;/code&gt; 类型的 channel 消息。&lt;/p&gt;&#xA;&lt;p&gt;在常见的场景下，我们会基于此方法做一些计时器相关的功能开发，例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼出去了，超时了！！！&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在运行 1 秒钟后，输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;煎鱼出去了，超时了！！！&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上述程序在在运行 1 秒钟后将触发 &lt;code&gt;time.After&lt;/code&gt; 方法的定时消息返回，输出了超时的结果。&lt;/p&gt;&#xA;&lt;h2 id=&#34;坑在哪里&#34;&gt;坑在哪里&lt;/h2&gt;&#xA;&lt;p&gt;从例子来看似乎非常正常，也没什么 “坑” 的样子。难道是 &lt;code&gt;timer.After&lt;/code&gt; 方法的虚晃一枪？&lt;/p&gt;&#xA;&lt;p&gt;我们再看一个不像是有问题例子，这在 Go 工程中经常能看见，只是大家都没怎么关注。&lt;/p&gt;&#xA;&lt;p&gt;代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#75715e&#34;&gt;// do something...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;continue&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;After&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Minute&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;现在是：%d，我脑子进煎鱼了！&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Unix&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上述代码中，我们构造了一个 &lt;code&gt;for+select+channel&lt;/code&gt; 的一个经典的处理模式。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 面试官：Go 结构体是否可以比较，为什么？</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-sturct/</link>
      <pubDate>Mon, 05 Apr 2021 16:16:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-sturct/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近金三银四，是面试的季节。在我的 Go 读者交流群里出现了许多小伙伴在讨论自己面试过程中所遇到的一些 Go 面试题。&lt;/p&gt;&#xA;&lt;p&gt;今天的男主角，是 Go 工程师的必修技能，也是极容易踩坑的地方，就是 “&lt;strong&gt;Go 面试题：Go 结构体（struct）是否可以比较？&lt;/strong&gt;”&lt;/p&gt;&#xA;&lt;p&gt;如果可以比较，是为什么？如果不可以比较，又是为什么？&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;请在此处默念自己心目中的答案&lt;/strong&gt;，再往和煎鱼一起研讨一波 Go 的技术哲学。&lt;/p&gt;&#xA;&lt;h2 id=&#34;结构体是什么&#34;&gt;结构体是什么&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 语言中有个基本类型，开发者们称之为结构体（struct）。是 Go 语言中非常常用的，基本定义：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;struct_variable_type&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;definition&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;definition&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;member&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;definition&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;简单示例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Vertex&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name2&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Vertex&lt;/span&gt;{&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进了&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name2&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;蒸鱼&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Name2&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;蒸鱼&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这部分属于基础知识，因此不再过多解释。如果看不懂，建议重学 Go 语言语法基础。&lt;/p&gt;&#xA;&lt;h2 id=&#34;比较两下&#34;&gt;比较两下&lt;/h2&gt;&#xA;&lt;h3 id=&#34;例子一&#34;&gt;例子一&lt;/h3&gt;&#xA;&lt;p&gt;接下来正式开始研讨 Go 结构体比较的问题，第一个例子如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Gender&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Gender&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;男&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Gender&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;男&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v2&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子进煎鱼了&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;脑子没进煎鱼&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们声明了两个变量，分别是 v1 和 v2。其都是 &lt;code&gt;Value&lt;/code&gt; 结构体的实例化，是同一个结构体的两个实例。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 面试官：GMP 模型，为什么要有 P？</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-gmp-p/</link>
      <pubDate>Mon, 05 Apr 2021 16:15:20 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-gmp-p/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近金三银四，是面试的季节。在我的 Go 读者交流群里出现了许多小伙伴在讨论自己面试过程中所遇到的一些 Go 面试题。&lt;/p&gt;&#xA;&lt;p&gt;今天的主角，是 Go 面试的万能题 GMP 模型的延伸题（疑问），那就是 ”&lt;strong&gt;GMP 模型，为什么要有 P&lt;/strong&gt;？“&lt;/p&gt;&#xA;&lt;p&gt;进一步推敲问题的背后，其实这个面试题本质是想问：”&lt;strong&gt;GMP 模型，为什么不是 G 和 M 直接绑定就完了，还要搞多一个 P 出来，那么麻烦，为的是什么，是要解决什么问题吗&lt;/strong&gt;？“&lt;/p&gt;&#xA;&lt;p&gt;这篇文章煎鱼就带你一同探索，GM、GMP 模型的变迁是因为什么原因。&lt;/p&gt;&#xA;&lt;h2 id=&#34;gm-模型&#34;&gt;GM 模型&lt;/h2&gt;&#xA;&lt;p&gt;在 Go1.1 之前 Go 的调度模型其实就是 GM 模型，也就是没有 P。&lt;/p&gt;&#xA;&lt;p&gt;今天带大家一起回顾过去的设计。&lt;/p&gt;&#xA;&lt;h3 id=&#34;解密-go10-源码&#34;&gt;解密 Go1.0 源码&lt;/h3&gt;&#xA;&lt;p&gt;我们了解一个东西的办法之一就是看源码，和煎鱼一起看看 Go1.0.1 的&lt;a href=&#34;https://github.com/golang/go/blob/go1.0.1/src/pkg/runtime/proc.c&#34;&gt;调度器源码&lt;/a&gt;的核心关键步骤：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;schedule&lt;/span&gt;(G &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;gp)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;schedlock&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt;(gp &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; nil) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt;(gp&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status){&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; Grunnable:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; Gdead:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// Shouldn&amp;#39;t have been running!&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;runtime&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;throw&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bad gp-&amp;gt;status in sched&amp;#34;&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; Grunning:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;gp&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Grunnable;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;gput&lt;/span&gt;(gp);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;break&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;gp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nextgandunlock&lt;/span&gt;();&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;gp&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;readyonstop &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;gp&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;status &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; Grunning;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;m&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;curg &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; gp;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;gp&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;m &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; m;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;runtime&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;·&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gogo&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;gp&lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt;sched, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;);&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;schedlock&lt;/code&gt; 方法来获取全局锁。&lt;/li&gt;&#xA;&lt;li&gt;获取全局锁成功后，将当前 Goroutine 状态从 Running（正在被调度） 状态修改为 Runnable（可以被调度）状态。&lt;/li&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;gput&lt;/code&gt; 方法来保存当前 Goroutine 的运行状态等信息，以便于后续的使用；&lt;/li&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;nextgandunlock&lt;/code&gt; 方法来寻找下一个可运行 Goroutine，并且释放全局锁给其他调度使用。&lt;/li&gt;&#xA;&lt;li&gt;获取到下一个待运行的 Goroutine 后，将其的运行状态修改为 Running。&lt;/li&gt;&#xA;&lt;li&gt;调用 &lt;code&gt;runtime·gogo&lt;/code&gt; 方法，将刚刚所获取到的下一个待执行的 Goroutine 运行起来。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;思考-gm-模型&#34;&gt;思考 GM 模型&lt;/h3&gt;&#xA;&lt;p&gt;通过对 Go1.0.1 的调度器源码剖析，我们可以发现一个比较有趣的点。那就是调度器本身（schedule 方法），在正常流程下，是不会返回的，也就是不会结束主流程。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 群友提问：进程、线程都有 ID，为什么 Goroutine 没有 ID？</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-goroutineid/</link>
      <pubDate>Mon, 05 Apr 2021 16:14:14 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-goroutineid/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近金三银四，是面试的季节。在我的 Go 读者交流群里出现了许多小伙伴在讨论自己面试过程中所遇到的一些 Go 面试题。&lt;/p&gt;&#xA;&lt;p&gt;今天的主角，是大家在既有语言基础的情况下，学 Goroutine 时会容易纠结的一点。就是 “&lt;strong&gt;进程、线程都有 ID，为什么 Goroutine 没有 GoroutineID？&lt;/strong&gt;”。&lt;/p&gt;&#xA;&lt;p&gt;这是为什么呢，怎么做那些跨协程处理呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;goroutineid-是什么&#34;&gt;GoroutineID 是什么&lt;/h2&gt;&#xA;&lt;p&gt;我们要知道，为什么大家会下意识的想去要 GoroutineID，下面引用 Go 语言圣经中的表述：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;在大多数支持多线程的操作系统和程序语言中，当前的线程都有一个独特的身份（ID），并且这个身份信息可以以一个普通值的形式被很容易地获取到，典型的可以是一个 integer 或者指针值。这种情况下我们做一个抽象化的 thread-local storage（线程本地存储，多线程编程中不希望其它线程访问的内容）就很容易，只需要以线程的 ID 作为 key 的一个 map 就可以解决问题，每一个线程以其 ID 就能从中获取到值，且和其它线程互不冲突。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;也就在常规的进程、线程中都有其 ID 的概念，我们可以在程序中通过 ID 来获取其他进程、线程中的数据，甚至是传输数据。就像一把钥匙一样，有了他干啥都可以。&lt;/p&gt;&#xA;&lt;p&gt;GoroutineID 的概念也是类似的，也就是协程的 ID。我们下意识的就期望通过协程 ID 来进行跨协程的操作。&lt;/p&gt;&#xA;&lt;p&gt;但，在 Go 语言中 GoroutineID 并没有显式获取的办法，这就要打个大大的疑惑了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么没有-goroutineid&#34;&gt;为什么没有 GoroutineID&lt;/h2&gt;&#xA;&lt;p&gt;为什么在 Go 语言中没有 GoroutineID 呢，是从一开始就没有的，还是，这样子设计的原因是什么呢？&lt;/p&gt;&#xA;&lt;p&gt;其实 Go 语言在以前是有暴露方法去获取 GoroutineID 的，但在 Go1.4 后就把该方法给隐藏起来了，不建议大家使用。&lt;/p&gt;&#xA;&lt;p&gt;也就是明面上没有 GoroutineID，是一个有意而为之的行为。原因是：&lt;strong&gt;根据以往的经验，认为 thread-local storage 存在被滥用的可能性，且带来许多不必要的复杂度&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，Andrew Gerrand 的回答是 ”&lt;strong&gt;thread-local storage 的成本远远超过了它们的收益。它们只是不适合 Go 语言&lt;/strong&gt;。”&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 面试官：Go interface 的一个 “坑” 及原理分析</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-interface/</link>
      <pubDate>Mon, 05 Apr 2021 16:12:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-interface/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在读者交流群里看到一位小伙伴，针对 interface 的使用有了比较大的疑惑。&lt;/p&gt;&#xA;&lt;p&gt;无独有偶，我也在网上看到有小伙伴在 Go 面试的时候被问到了：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/36d7ecb0da9e4b32a493dedce6ebc691~tplv-k3u1fbpfcp-watermark.image&#34; alt=&#34;来自网上博客的截图&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天特意分享出来让大家避开这个坑。&lt;/p&gt;&#xA;&lt;h2 id=&#34;例子一&#34;&gt;例子一&lt;/h2&gt;&#xA;&lt;p&gt;第一个例子，如下代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; = (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;)(&lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你觉得输出结果是什么呢？&lt;/p&gt;&#xA;&lt;p&gt;答案是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;false&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为什么不是 &lt;code&gt;true&lt;/code&gt;。明明都已经强行置为 &lt;code&gt;nil&lt;/code&gt; 了。是不是 Go 编译器有问题？&lt;/p&gt;&#xA;&lt;h2 id=&#34;例子二&#34;&gt;例子二&lt;/h2&gt;&#xA;&lt;p&gt;第二个例子，如下代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-golang&#34; data-lang=&#34;golang&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;in&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;你觉得输出结果是什么呢？&lt;/p&gt;&#xA;&lt;p&gt;答案是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;nil&amp;gt; true&#xA;&amp;lt;nil&amp;gt; true&#xA;&amp;lt;nil&amp;gt; false&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这可就更奇怪了，为什么刚刚声明出来的 &lt;code&gt;data&lt;/code&gt; 和 &lt;code&gt;in&lt;/code&gt; 变量，确实是输出结果是 &lt;code&gt;nil&lt;/code&gt;，判断结果也是 &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;怎么把变量 &lt;code&gt;data&lt;/code&gt; 一赋予给变量 &lt;code&gt;in&lt;/code&gt;，世界就变了？输出结果依然是 &lt;code&gt;nil&lt;/code&gt;，但判定却变成了 &lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;p&gt;和上面的第一个例子结果类似，真是神奇。&lt;/p&gt;&#xA;&lt;h2 id=&#34;原因&#34;&gt;原因&lt;/h2&gt;&#xA;&lt;p&gt;interface 判断与想象中不一样的根本原因是，interface 并不是一个指针类型，虽然他看起来很像，以至于误导了不少人。&lt;/p&gt;&#xA;&lt;p&gt;我们钻下去 interface，interface 共有两类数据结构：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/560dcab5-e436-4a2c-bfee-6eba6faee1d2.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=HF1wka8F9MTc%252FVCTrMjhASpeeE4%253D&amp;amp;Expires=1615900476&#34; alt=&#34;&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 群友提问：学习 defer 时很懵逼，这道不会做！</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-defer/</link>
      <pubDate>Mon, 05 Apr 2021 16:10:51 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-defer/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在读者交流群里看到一位小伙伴，在向大家咨询 Go 相关的技术问题。&#xA;疑问是：“&lt;strong&gt;各位大佬，我在学习 defer 遇到闭包的时候很懵逼，谁比较明白，能指点？&lt;/strong&gt;”&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/36e2b86b536909f265b84db24dcd80c6.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;疑问&#34;&gt;疑问&lt;/h2&gt;&#xA;&lt;p&gt;他的疑问是下面这道 Go 语言的 defer 题目，大家一起看看：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;&#x9;var whatever [6]struct{}&#xA;&#x9;for i := range whatever {&#xA;&#x9;&#x9;defer func() {&#xA;&#x9;&#x9;&#x9;fmt.Println(i)&#xA;&#x9;&#x9;}()&#xA;&#x9;}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请自己先想一下输出的结果答案是什么。&lt;/p&gt;&#xA;&lt;p&gt;这位小伙伴按自己的理解后，认为应当输出 xx。但最终的输出结果，可能与其思考的有所偏差，一时想不通。&lt;/p&gt;&#xA;&lt;h3 id=&#34;解惑&#34;&gt;解惑&lt;/h3&gt;&#xA;&lt;p&gt;这段程序的输出结果是：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;5&#xA;5&#xA;5&#xA;5&#xA;5&#xA;5&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;为什么全是 5，为什么不是 0, 1, 2, 3, 4, 5 这样的输出结果呢？&lt;/p&gt;&#xA;&lt;p&gt;其根本原因是&lt;strong&gt;闭包&lt;/strong&gt;所导致的，有两点原因：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;在 &lt;code&gt;for&lt;/code&gt; 循环结束后，局部变量 &lt;code&gt;i&lt;/code&gt; 的值已经是 5 了，并且 &lt;code&gt;defer &lt;/code&gt;的闭包是直接引用变量的 i。&lt;/li&gt;&#xA;&lt;li&gt;结合&lt;code&gt;defer&lt;/code&gt; 关键字的特性，可得知会在 &lt;code&gt;main&lt;/code&gt; 方法主体结束后再执行。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;结合上述，最终输出的结果是已经自增完毕的 5。&lt;/p&gt;&#xA;&lt;h3 id=&#34;进一步思考&#34;&gt;进一步思考&lt;/h3&gt;&#xA;&lt;p&gt;既然了解了为什么，我们再变形一下。再看看另外一种情况，代码如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>问个 Go 问题，字符串 len 为 0 和 字符串为空 ，有啥区别？</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-lenstr/</link>
      <pubDate>Mon, 05 Apr 2021 16:09:14 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-lenstr/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在微信群看到几位大佬在讨论一个问题： ”&lt;strong&gt;字符串 len == 0 和 字符串 == &amp;quot;&amp;quot; ，有啥区别&lt;/strong&gt;？“&lt;/p&gt;&#xA;&lt;p&gt;这是一个比较小的细节点，同时也勾起了我的好奇心，因此今天这篇文章就和大家一起研究一下他们两者有没有区别，谁的性能更好一些？&lt;/p&gt;&#xA;&lt;h2 id=&#34;测试方法&#34;&gt;测试方法&lt;/h2&gt;&#xA;&lt;p&gt;在测试的方法中，我们分别声明了 &lt;code&gt;Test1&lt;/code&gt; 和 &lt;code&gt;Test2&lt;/code&gt; 方法：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func Test1() bool {&#xA;&#x9;var v string&#xA;&#x9;if v == &amp;#34;&amp;#34; {&#xA;&#x9;&#x9;return true&#xA;&#x9;}&#xA;&#x9;return false&#xA;}&#xA;&#xA;func Test2() bool {&#xA;&#x9;var v string&#xA;&#x9;if len(v) == 0 {&#xA;&#x9;&#x9;return true&#xA;&#x9;}&#xA;&#x9;return false&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在方法内部仅做了简单的变量类型声明，分别以 字符串 == &amp;quot;&amp;quot; 和 字符串 len == 0 为判断依据。&lt;/p&gt;&#xA;&lt;h2 id=&#34;测试用例&#34;&gt;测试用例&lt;/h2&gt;&#xA;&lt;p&gt;编写两个方法的 Benchmark，用于后续的性能测试：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func BenchmarkTest1(b *testing.B) {&#xA;&#x9;for i := 0; i &amp;lt; b.N; i++ {&#xA;&#x9;&#x9;Test1()&#xA;&#x9;}&#xA;}&#xA;&#xA;func BenchmarkTest2(b *testing.B) {&#xA;&#x9;for i := 0; i &amp;lt; b.N; i++ {&#xA;&#x9;&#x9;Test2()&#xA;&#x9;}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;结果分析&#34;&gt;结果分析&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test --bench=. -benchmem&#xA;goos: darwin&#xA;goarch: amd64&#xA;BenchmarkTest1-4   &#x9;1000000000&#x9;         0.305 ns/op&#x9;       0 B/op&#x9;       0 allocs/op&#xA;BenchmarkTest2-4   &#x9;1000000000&#x9;         0.305 ns/op&#x9;       0 B/op&#x9;       0 allocs/op&#xA;PASS&#xA;ok  &#x9;_/Users/eddycjy/go-application/awesomeProject/tests&#x9;0.688s&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从多次测试的结果来看，两者比较：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 群友提问：Goroutine 数量控制在多少合适，会影响 GC 和调度？</title>
      <link>https://note.lican.site/posts/posts/go/go-tips-goroutinenums/</link>
      <pubDate>Mon, 05 Apr 2021 16:08:18 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-tips-goroutinenums/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天在读者交流群里看到一位小伙伴，发出了一个致命提问，那就是：“&lt;strong&gt;单机的 goroutine 数量控制在多少比较合适？&lt;/strong&gt;”。&lt;/p&gt;&#xA;&lt;p&gt;也许你和群内小伙伴第一反应一样，会答复 “控制多少，我觉得没有定论”。&lt;/p&gt;&#xA;&lt;p&gt;紧接着延伸出了更进一步的疑惑：“&lt;strong&gt;goroutine 太多了会影响 gc 和调度吧，主要是怎么预算这个数是合理的呢？&lt;/strong&gt;”&lt;/p&gt;&#xA;&lt;p&gt;这是本文要进行探讨的主体，因此本文的结构会是先探索基础知识，再一步步揭开，深入理解这个问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;goroutine-是什么&#34;&gt;Goroutine 是什么&lt;/h2&gt;&#xA;&lt;p&gt;Go 语言作为一个新生编程语言，其令人喜爱的特性之一就是 goroutine。Goroutine 是一个由 Go 运行时管理的轻量级线程，一般称其为 “协程”。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go f(x, y, z)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;操作系统本身是无法明确感知到 Goroutine 的存在的，Goroutine 的操作和切换归属于 “用户态” 中。&lt;/p&gt;&#xA;&lt;p&gt;Goroutine 由特定的调度模式来控制，以 “多路复用” 的形式运行在操作系统为 Go 程序分配的几个系统线程上。&lt;/p&gt;&#xA;&lt;p&gt;同时创建 Goroutine 的开销很小，初始只需要 2-4k 的栈空间。Goroutine 本身会根据实际使用情况进行自伸缩，非常轻量。&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func say(s string) {&#xA;&#x9;for i := 0; i &amp;lt; 9999999; i++ {&#xA;&#x9;&#x9;time.Sleep(100 * time.Millisecond)&#xA;&#x9;&#x9;fmt.Println(s)&#xA;&#x9;}&#xA;}&#xA;&#xA;func main() {&#xA;&#x9;go say(&amp;#34;煎鱼&amp;#34;)&#xA;&#x9;say(&amp;#34;你好&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;人称可以开几百几千万个的协程小霸王，是 Go 语言的得意之作之一。&lt;/p&gt;&#xA;&lt;h2 id=&#34;调度是什么&#34;&gt;调度是什么&lt;/h2&gt;&#xA;&lt;p&gt;既然有了用户态的代表 Goroutine，操作系统又看不到他。必然需要有某个东西去管理他，才能更好的运作起来。&lt;/p&gt;</description>
    </item>
    <item>
      <title>令人激动！Go 泛型代码合入 master（附尝鲜方法）</title>
      <link>https://note.lican.site/posts/posts/go/go-typeparams-master/</link>
      <pubDate>Mon, 05 Apr 2021 16:06:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-typeparams-master/</guid>
      <description>&lt;p&gt;大家好，我是慢一拍的后方记者煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;按照先前官方和文章的说法，Go 泛型预计是在 Go1.18 正式释出。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/8971e01e-75f8-47c2-b9d3-f6b0ebd85d0d.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=8eKquOL0aM7GzJXegZUzGkOmLPg%253D&amp;amp;Expires=1614491040&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 GopherCon 2020 Go Team AMA 时，要在今年底要能有生产环境的试用版上线，这是 rsc 所提出的一个管理目标。&lt;/p&gt;&#xA;&lt;h2 id=&#34;转折点&#34;&gt;转折点&lt;/h2&gt;&#xA;&lt;p&gt;近期出现了一个新的转折点，能够让大家在主干分支（master）上就能享受到泛型的功能。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/3acc09a4-d5a2-49e7-b272-b2fa1571f589.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=zXcEIWPbc%252BUFBDmTyYrRVywwKuI%253D&amp;amp;Expires=1614491656&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而 master 分支对应了 Go1.17 的版本。因此未来将可以在 Go1.17 使用到泛型，这是一个比较惊喜的事情。&lt;/p&gt;&#xA;&lt;h2 id=&#34;原因&#34;&gt;原因&lt;/h2&gt;&#xA;&lt;p&gt;这件事情为什么会突然发生呢？一切都得从背景说起。原本 Go 泛型是一直在 &lt;a href=&#34;https://github.com/golang/go/tree/dev.typeparams&#34;&gt;dev.typeparams&lt;/a&gt; 分支上进行研讨和开发。&lt;/p&gt;&#xA;&lt;p&gt;由于泛型不是简单的一两个模块的代码变更，而是涉及大量的代码变更。&lt;/p&gt;&#xA;&lt;p&gt;因此需要经常保持与 master 分支的代码同步（近两个月共 20+ 次），会涉及代码冲突/合并的处理，且对于一些冲突的模块他们也不熟悉，所以期望迁移到 master 分支上进行开发。&lt;/p&gt;&#xA;&lt;h2 id=&#34;如何不影响既有功能&#34;&gt;如何不影响既有功能&lt;/h2&gt;&#xA;&lt;p&gt;这类提前放入主版本的操作，在 Go 语言中并不少见。像是现在所见的 &lt;code&gt;GO111MODULE&lt;/code&gt;，早期的 &lt;code&gt;GO15VENDOREXPERIMENT&lt;/code&gt; 都有些这么个味道。都是逐步入场，分阶段使用，等确定成熟、完善后再渐渐去掉。&lt;/p&gt;&#xA;&lt;p&gt;因此本次泛型也采取了这种方法，按照提案，目前使用的是 &lt;code&gt;-G&lt;/code&gt; 标识做为泛型的开关。&lt;/p&gt;&#xA;&lt;p&gt;计划如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;-G=0&lt;/code&gt;：继续使用传统的类型检查器。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;-G=1&lt;/code&gt;：使用 type2，但不支持泛型。&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;-G=2&lt;/code&gt;：使用 type2，支持泛型。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在完成 types2 的错误和现有的错误的开发协调后，计划在 Go 1.17 将 &lt;code&gt;-G=1&lt;/code&gt; 设置为默认值。&lt;/p&gt;&#xA;&lt;p&gt;未来也许可以在 Go 1.18 中放弃对 &lt;code&gt;-G=0&lt;/code&gt; 的支持，这样后续在默认启用 &lt;code&gt;-G=2&lt;/code&gt; 上会变得更容易。&lt;/p&gt;</description>
    </item>
    <item>
      <title>意见征集：Go1 要不要移除 GOPATH？</title>
      <link>https://note.lican.site/posts/posts/go/go-why-path/</link>
      <pubDate>Mon, 05 Apr 2021 16:02:34 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-why-path/</guid>
      <description>&lt;p&gt;大家好，我是在打自己脸的后方记者煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天我发表了文章《意见征集：Go1 要不要移除 GOPATH？》。&#xA;本次投票共有 592 人参与了投票。&#xA;结果如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://static01.imgkr.com/temp/d10e1354bc9d43c68439fb71d8935270.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;绝大部分人支持移除 GOPATH，但建议保留的人依然占相当一部分。&lt;/p&gt;&#xA;&lt;h2 id=&#34;最新进展&#34;&gt;最新进展&lt;/h2&gt;&#xA;&lt;p&gt;在近几天，在 go issues 上有人提出了新的提案：《proposal: cmd/go: maintain &amp;lsquo;classic&amp;rsquo; vendor behaviour》。&lt;/p&gt;&#xA;&lt;p&gt;该提案正式向 Go 官方提出了我们上一篇文章有提到的两点：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Go 历史项目的维护问题。&lt;/li&gt;&#xA;&lt;li&gt;Go1 兼容性保证的许诺。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;摘选一部分核心观点给大家看看。&lt;/p&gt;&#xA;&lt;h2 id=&#34;新的提案&#34;&gt;新的提案&lt;/h2&gt;&#xA;&lt;p&gt;从 Go1.17 开始，Go1.17 就将 GOPATH 从编译器工具链中移除 &lt;code&gt;GO111MODULE&lt;/code&gt; 标识。&lt;/p&gt;&#xA;&lt;p&gt;其依据如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://static01.imgkr.com/temp/bf314e0979b7481681c6293ee60715c3.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;重点在于执行 &lt;code&gt;-mod=vendor&lt;/code&gt; 命令时，其会忽略主模块根目录以外位置的软件目录，&lt;strong&gt;这意味着在 go mod 之前设计和编写的应用程序不能再编译（指的历史项目问题）&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;提案本身并不是要求要保持 GOPATH 代码解析 1:1 的说法，而是希望能够允许项目代码通过其他的方式在移除 GOPATH 后也能正常运行，有其他方式能够导入（不需要转成 Go mod）。&lt;/p&gt;&#xA;&lt;p&gt;另外最后提到删除 GOPATH 这样的代码解析能力，&lt;strong&gt;与下面这段摘自 go1compat 文档的精神不一致&lt;/strong&gt;：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;It is intended that programs written to the Go 1 specification will continue to compile and run correctly, unchanged, over the lifetime of that specification. At some indefinite point, a Go 2 specification may arise, but until that time, Go programs that work today should continue to work even as future &amp;ldquo;point&amp;rdquo; releases of Go 1 arise (Go 1.1, Go 1.2, etc.).&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.16 新特性：Go mod 的后悔药，仅需这一招</title>
      <link>https://note.lican.site/posts/posts/go/go1.16-mod/</link>
      <pubDate>Mon, 05 Apr 2021 16:00:13 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go1.16-mod/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;前几天 Go 官方正式发布了 1.16 版本。&lt;strong&gt;从这个版本起，环境变量 GO111MODULE 的默认值正式修改为 on&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/64ac411e-6361-4b23-b437-78123e16ae5a.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=NWVlX2CGAsMjMs%252BJH54ZKW1s1fM%253D&amp;amp;Expires=1613623986&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这也意味着 Go modules 将更进一步推进其业务覆盖面，有新老项目共存的小伙伴建议手动将 GO111MODULE 调整为 auto。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Go1.16 针对 Go modules 放出了一个新特性，能够让维护 Go mod 库的开发者拥有反复吃 “后悔药” 的权力，提醒开发者已发布的 “脏” 版本存在问题&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;这个新特性，对于许多维护和使用公共库（开源、企业等）的小伙伴简直是一个小福音，建议大家都应该要了解这个知识点。&lt;/p&gt;&#xA;&lt;p&gt;在接下来文章中将进行详细说明和介绍。&lt;/p&gt;&#xA;&lt;h2 id=&#34;后悔药go-mod-retract&#34;&gt;后悔药：Go mod retract&lt;/h2&gt;&#xA;&lt;p&gt;Go1.16 起可以在 go.mod 文件中使用 &lt;code&gt;retract&lt;/code&gt; 指令来声明该第三方模块的某些发行版本不能被其他模块使用。&lt;/p&gt;&#xA;&lt;p&gt;在使用场景上：在发现严重问题或无意发布某些版本后，模块的维护作者可以撤回该版本，支持撤回单个或多个版本。&lt;/p&gt;&#xA;&lt;p&gt;以前没有办法解决，因此一旦出现就非常麻烦。对应两者的操作如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;维护者：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;删除有问题版本的 tag。&lt;/li&gt;&#xA;&lt;li&gt;重新打一个新版本的 tag。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;使用者：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;发现有问题的版本 tag 丢失，需手动介入。&lt;/li&gt;&#xA;&lt;li&gt;不知道有问题，由于其他库依赖，因此被动升级而踩坑。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;因此在本次 Go1.16 发布后，就拥有了一个&lt;strong&gt;半止损&lt;/strong&gt;的新手段了，也可以作为 Go mod 自动更新的大坑的补全办法之一。&lt;/p&gt;&#xA;&lt;h2 id=&#34;实战演练&#34;&gt;实战演练&lt;/h2&gt;&#xA;&lt;p&gt;为了方便演示，首先创建一个 Demo 项目（github.com/eddycjy/go-retract-demo），其含有一个基础方法：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package go_retract_demo&#xA;&#xA;func HelloWorld() string {&#xA;&#x9;return &amp;#34;001：脑子进煎鱼了！&amp;#34;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;另外有一个应用工程依赖了该第三方库，代码如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.16 新特性：详解内存管理机制的变更，你需要了解</title>
      <link>https://note.lican.site/posts/posts/go/go1.16-3/</link>
      <pubDate>Thu, 11 Feb 2021 16:13:20 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go1.16-3/</guid>
      <description>&lt;p&gt;大家好，我是正在学习如何蒸鱼的煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在前面 Go1.16 特性介绍的文章中我们有提到，从 v1.16 起，Go 在 Linux 下的默认内存管理策略会从&lt;code&gt;MADV_FREE&lt;/code&gt; 改回 &lt;code&gt;MADV_DONTNEED&lt;/code&gt; 策略。&lt;/p&gt;&#xA;&lt;p&gt;这时候可能至少分两拨小伙伴，分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;知道是什么，被这个问题 “折磨“ 过的，瞬间眼前一亮。&lt;/li&gt;&#xA;&lt;li&gt;不知道是什么，出现了各种疑惑了，这说的都是些什么。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;灵魂拷问&#34;&gt;灵魂拷问&lt;/h2&gt;&#xA;&lt;p&gt;你有没有以下的疑问，或者是否清楚：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;文中所说的 &lt;code&gt;MADV_FREE&lt;/code&gt; 是什么？&lt;/li&gt;&#xA;&lt;li&gt;文中所说的 &lt;code&gt;MADV_DONTNEED&lt;/code&gt; 是什么？&lt;/li&gt;&#xA;&lt;li&gt;为什么特指 Go 语言的 Linux 环境？&lt;/li&gt;&#xA;&lt;li&gt;为什么是说从 &lt;code&gt;MADV_FREE&lt;/code&gt;改回 &lt;code&gt;MADV_DONTNEED&lt;/code&gt;？&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在今天这篇文章中我们都将进一步的展开和说明，让我们一同来了解这个改来改去的内存机制到底是何物。&lt;/p&gt;&#xA;&lt;h2 id=&#34;madvise-爱与恨&#34;&gt;madvise 爱与恨&lt;/h2&gt;&#xA;&lt;p&gt;在 Linux 系统中，在 Go Runtime 中通过系统调用 &lt;code&gt;madvise(addr, length, advise)&lt;/code&gt; 方法，能够告诉内核如何处理从 addr 开始的 length 字节。&lt;/p&gt;&#xA;&lt;p&gt;重点之一就是 ”如何处理“，在 Linux 下 Go 语言中目前支持两种策略，分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;MADV_FREE：内核会在进程的页表中将这些页标记为“未分配”，从而进程的 RSS 就会变小。OS 后续可以将对应的物理页分配给其他进程。&lt;/li&gt;&#xA;&lt;li&gt;MADV_DONTNEED：内核只会在页表中将这些进程页面标记为可回收，在需要的时候才回收这些页面。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;所带来的影响&#34;&gt;所带来的影响&lt;/h2&gt;&#xA;&lt;p&gt;Go 语言官方恰好就在 2019 年的 Go1.12 做了如下调整。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Go1.12 以前。&lt;/li&gt;&#xA;&lt;li&gt;Go.12-Go1.15.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;go112-以前&#34;&gt;Go1.12 以前&lt;/h3&gt;&#xA;&lt;p&gt;Go Runtime 在 Linux 上默认使用的是 &lt;code&gt;MADV_DONTNEED&lt;/code&gt; 策略。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.16 新特性：快速上手 Go embed</title>
      <link>https://note.lican.site/posts/posts/go/go1.16-2/</link>
      <pubDate>Thu, 11 Feb 2021 16:13:19 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go1.16-2/</guid>
      <description>&lt;p&gt;在以前，很多从其他语言转过来 Go 语言的同学会问到，或是踩到一个坑。就是以为 Go 语言所打包的二进制文件中会包含配置文件的联同编译和打包。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/f59a06c7-2fa1-41f4-901c-990f7dd7d715.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=werBc5OkLhKUh0JhpYpcAtl3etA%253D&amp;amp;Expires=1612147306&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;结果往往一把二进制文件挪来挪去，就无法把应用程序运行起来了。因为无法读取到静态文件的资源。&lt;/p&gt;&#xA;&lt;p&gt;无法将静态资源编译打包进二进制文件的话，通常会有两种解决方法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;第一种是识别这类静态资源，是否需要跟着程序走。&lt;/li&gt;&#xA;&lt;li&gt;第二种就是考虑将其打包进二进制文件中。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;第二种情况的话，Go 以前是不支持的，大家就会去借助各种花式的开源库，例如：go-bindata/go-bindata 来实现。&lt;/p&gt;&#xA;&lt;p&gt;但从在 Go1.16 起，Go 语言自身正式支持了该项特性，今天我们将通过这篇文章快速了解和学习这项特性。&lt;/p&gt;&#xA;&lt;h2 id=&#34;基本使用&#34;&gt;基本使用&lt;/h2&gt;&#xA;&lt;p&gt;演示代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import _ &amp;#34;embed&amp;#34;&#xA;&#xA;//go:embed hello.txt&#xA;var s string&#xA;&#xA;func main() {&#xA;&#x9;print(s)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们首先在对应的目录下创建了 &lt;code&gt;hello.txt&lt;/code&gt; 文件，并且写入文本内容 “吃煎鱼”。&lt;/p&gt;&#xA;&lt;p&gt;在代码中编写了最为核心的 &lt;code&gt;//go:embed hello.txt&lt;/code&gt; 注解。注解的格式很简单，就是 &lt;code&gt;go:embed&lt;/code&gt; 指令声明，外加读取的内容的地址，可支持相对和绝对路径。&lt;/p&gt;&#xA;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;吃煎鱼&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;读取到静态文件中的内容后自动赋值给了变量 &lt;code&gt;s&lt;/code&gt;，并且在主函数中成功输出。&lt;/p&gt;&#xA;&lt;p&gt;而针对其他的基础类型，Go embed 也是支持的：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;//go:embed hello.txt&#xA;var s string&#xA;&#xA;//go:embed hello.txt&#xA;var b []byte&#xA;&#xA;//go:embed hello.txt&#xA;var f embed.FS&#xA;&#xA;func main() {&#xA;&#x9;print(s)&#xA;&#x9;print(string(b))&#xA;&#xA;&#x9;data, _ := f.ReadFile(&amp;#34;hello.txt&amp;#34;)&#xA;&#x9;print(string(data))&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.16 即将正式发布，以下变更你需要知道</title>
      <link>https://note.lican.site/posts/posts/go/go1.16-1/</link>
      <pubDate>Thu, 11 Feb 2021 16:13:15 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go1.16-1/</guid>
      <description>&lt;p&gt;大家好，我是正在努力学习的煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在前几天，Go1.16rc1 抢先发布了。结合常规的 28 发布规律，其将会在 2021.02 月份左右发布正式版本。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/417219ea-578e-48f0-8a83-84544000a698.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=mbLHd49lXRyOoY%252FlyamD5YnGagw%253D&amp;amp;Expires=1612064951&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这次 Go1.16 也带来了一些新特性或变更。那么作为一个 Gopher，想必不能错过这次的更新。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://imgkr2.cn-bj.ufileos.com/4161e3cd-9f66-4f3f-8f68-91f3ba496c18.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&amp;amp;Signature=CwpOhSJnk70gEkTF8ITIxC58PoM%253D&amp;amp;Expires=1612074386&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天这篇文章将会带大家了解一下 Go1.16 的几个需要关注的特性。&lt;/p&gt;&#xA;&lt;h3 id=&#34;废弃-ioioutil&#34;&gt;废弃 io/ioutil&lt;/h3&gt;&#xA;&lt;p&gt;Go 官方认为 io/ioutil 这个包的定义不明确且难以理解。所以 Russ Cox 在 2020.10.17 提出了废弃 io/ioutil 的提案。&lt;/p&gt;&#xA;&lt;p&gt;大致变更如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Discard =&amp;gt; io.Discard&lt;/li&gt;&#xA;&lt;li&gt;NopCloser =&amp;gt; io.NopCloser&lt;/li&gt;&#xA;&lt;li&gt;ReadAll =&amp;gt; io.ReadAll&lt;/li&gt;&#xA;&lt;li&gt;ReadDir =&amp;gt; os.ReadDir&lt;/li&gt;&#xA;&lt;li&gt;ReadFile =&amp;gt; os.ReadFile&lt;/li&gt;&#xA;&lt;li&gt;TempDir =&amp;gt; os.MkdirTemp&lt;/li&gt;&#xA;&lt;li&gt;TempFile =&amp;gt; os.CreateTemp&lt;/li&gt;&#xA;&lt;li&gt;WriteFile =&amp;gt; os.WriteFile&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;与此同时大家也不需要担心存在破坏性变更，因为有 Go1 兼容性的保证，在 Go1 中 io/ioutil 还会存在，只变更内部的方法调用：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func ReadAll(r io.Reader) ([]byte, error) {&#xA;    return io.ReadAll(r)&#xA;}&#xA;&#xA;func ReadFile(filename string) ([]byte, error) {&#xA;    return os.ReadFile(filename)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;大家在后续也可以改改调用习惯。&lt;/p&gt;</description>
    </item>
    <item>
      <title>快报：正式提案将泛型特性加入 Go 语言</title>
      <link>https://note.lican.site/posts/posts/go/generics-proposal/</link>
      <pubDate>Wed, 13 Jan 2021 21:11:44 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/generics-proposal/</guid>
      <description>&lt;p&gt;经历九九八十一难，多年的不断探讨和 Go 语言爱好者们在社区中的强烈关注，且 Go 官方在 2020 年不断放出消息。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/1d0e5a264c65e37659f142bc2ee55805.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;总算在 2021 年 1 月 12 日。官方正式提出将泛型特性加入 Go 语言的 proposal 了，且最新的草案设计已经更新。&lt;/p&gt;&#xA;&lt;p&gt;基本语法如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func Print[T any](s []T) {&#xA;&#x9;// same as above&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其大体的概述如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;函数可以具有使用方括号的其他类型参数列表，但其他情况下看起来像普通的参数列表：&lt;code&gt;func F[T any](p T) { ... }&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;类型也可以具有类型参数列表：&lt;code&gt;type MySlice[T any] []T&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;每个类型参数都有一个类型约束，就像每个普通参数都有一个类型：&lt;code&gt;func F[T Constraint](p T) { ... }&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;类型约束是接口类型。&lt;/li&gt;&#xA;&lt;li&gt;新的预声明名称 &lt;code&gt;any&lt;/code&gt; 是允许任何类型的类型约束。&lt;/li&gt;&#xA;&lt;li&gt;用作类型约束的接口类型可以具有预先声明的类型的列表。只有与那些类型之一匹配的类型参数才能满足约束条件。&lt;/li&gt;&#xA;&lt;li&gt;泛型函数只能使用其类型约束所允许的操作。&lt;/li&gt;&#xA;&lt;li&gt;使用泛型函数或类型需要传递类型实参。&lt;/li&gt;&#xA;&lt;li&gt;在通常情况下，类型推断允许省略函数调用的类型参数。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;根据官方博客的消息，如果该提案被正式接受。那么将会在 2021 年底之前完成一个基本可用的泛型特性使用，又或是会作为 Go1.18beta 的一部分。&lt;/p&gt;&#xA;&lt;p&gt;这是 Go 泛型特性的又一步前进。若大家有兴趣进一步了解或想提出意见，可查看下述传送门：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A Proposal for Adding Generics to Go：https://blog.golang.org/generics-proposal。&lt;/li&gt;&#xA;&lt;li&gt;proposal: spec: add generic programming using type parameters：https://github.com/golang/go/issues/43651。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;今年年底或 Go1.18beta 到底能不能看到泛型的正式完整可用版本呢，值得期待。&lt;/p&gt;</description>
    </item>
    <item>
      <title>推荐一个牛逼的技术社区！</title>
      <link>https://note.lican.site/posts/posts/2021-ecug/</link>
      <pubDate>Tue, 05 Jan 2021 21:26:50 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/2021-ecug/</guid>
      <description>&lt;p&gt;相信我的读者中不少是 Go 语言的爱好者，又或是正在伺机而动。&lt;/p&gt;&#xA;&lt;p&gt;今天要给大家所介绍的这个技术社区，就是由与 Go 语言有很浓厚的缘分的人所创办的。&lt;/p&gt;&#xA;&lt;p&gt;他有如下几个业界标签：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;早期的国内 Go 语言布道师。&lt;/li&gt;&#xA;&lt;li&gt;早期在公司内大规模的推广和使用 Go 语言。&lt;/li&gt;&#xA;&lt;li&gt;早期编写了一本 Go 语言图书：《Go 语言编程》。&lt;/li&gt;&#xA;&lt;li&gt;现在是一家公司的 CEO。&lt;/li&gt;&#xA;&lt;li&gt;近期在大力推广 Go+。&lt;/li&gt;&#xA;&lt;li&gt;&amp;hellip;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;他还有非常多的标签，通过上述这几点，你是否猜到是谁了呢？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/0c8ac8602cca4e19c8caca30ac991305.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;没错，他就是七牛云的 CEO 许式伟。&lt;/p&gt;&#xA;&lt;h2 id=&#34;与-go-语言的渊源&#34;&gt;与 Go 语言的渊源&lt;/h2&gt;&#xA;&lt;p&gt;许式伟在早年离开盛大创新院。创办七牛云的时候，选择了 Go 这门还未发布正式版的语言。因为小众，许式伟开始有意识地培养 Go 中国社区。&lt;/p&gt;&#xA;&lt;p&gt;他们做了很多工作。具体有：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;2012 年 2 月，许式伟首次在公开场合说：Go 会超过 C、Java，成为最流行的语言。讲得最多的一个 PPT 是《Go，Next C》这篇。&lt;/li&gt;&#xA;&lt;li&gt;2012 年 8 月，正式出版 Go 图书，书名为《Go 语言编程》。&lt;/li&gt;&#xA;&lt;li&gt;2020 年下半年，正式对 Go+ 进行了宣传和推广，对大数据科学的领域进行了增强。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;神秘的技术社区&#34;&gt;神秘的技术社区&lt;/h2&gt;&#xA;&lt;p&gt;虽然许式伟已经是七牛云 CEO，但依然在技术领域和咱们的 Go 领域发光发热，并没有因此而停下脚步。许式伟早在 2007 年就成立了一个技术社区。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/f04e24b25f48c3d2293e64390d22888f.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这个社区名字叫 ECUG，ECUG 全称为 Effective Cloud User Group（实效云计算用户组）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>拖更的 2020 年不一样</title>
      <link>https://note.lican.site/posts/posts/2020-summary/</link>
      <pubDate>Thu, 31 Dec 2020 21:29:55 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/2020-summary/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;万万没想到&amp;hellip;想着写 2020 年总结，结果就到了 2021 年，不愧是只有 7s 记忆的博主 😂。&lt;/p&gt;&#xA;&lt;p&gt;2020 年并不简单，这也是第一次在公开场合写个人向，并且还是年终总结，感慨颇多。&lt;/p&gt;&#xA;&lt;h2 id=&#34;出书&#34;&gt;出书&lt;/h2&gt;&#xA;&lt;p&gt;今年（2020年）上半年几乎没有更新博客文章，当时还一口气退了一大堆技术交流的微信群。当时有不少朋友来咨询我怎么了，后面的事大家也就知道了。&lt;/p&gt;&#xA;&lt;p&gt;蛰伏了将近 9 个月，出了人生第一本图书（简体+繁体）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/56c805ff0e8c6134e845d5da99d4ab0b.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;本书已印刷三次，和编辑沟通了几次，现在 Go 语言还算小众（与 Java、Python 相比较），销量算是挺不错的了。&lt;/p&gt;&#xA;&lt;p&gt;有一块比较遗憾，在初印有几个比较致命的印刷问题。后续在第二次印刷中解决了。此次只能说第一次写书经验不足，编辑也是，下次一定。&lt;/p&gt;&#xA;&lt;p&gt;另外当时出书时与曹大聊过几次，他提到的出书后会遇到的所有烦恼我大多都遇到了，现实太真实，出书很理想。&lt;/p&gt;&#xA;&lt;p&gt;其次写书并不赚钱，不要见面就问。更没有因此改变我的初心，依然是热爱分享知识的煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;未曾想过的第一个里程碑完成。&lt;/p&gt;&#xA;&lt;h2 id=&#34;博客公众号&#34;&gt;博客/公众号&lt;/h2&gt;&#xA;&lt;p&gt;后半年就开始陆续恢复博客的写作了，2020 年博客上共有 32 篇技术文章，加上图书的稿子一年总共写了 70+ 篇文章。&lt;/p&gt;&#xA;&lt;p&gt;2019 年只写了 19 篇。相比较而言，总产出还算可以：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/4be8f0069f8b79388c1fe0853ab9a534.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;但理论上还可以更高，因为在写完书后，由于之前过于高度集中，导致下半年出现了几个月的真空休息期。更深刻的认识到了劳逸结合，适当调节非常重要。&lt;/p&gt;&#xA;&lt;p&gt;同时公众号也在年尾终于往前走了一步，开始接了一些推广，虽然钱不多。但更多的还是激励自己，倒逼自己更多的输入和输出。&lt;/p&gt;&#xA;&lt;p&gt;最近有很多小伙伴也发现了我公众号的更新频率变高了，这是相辅相成的。&lt;/p&gt;&#xA;&lt;p&gt;知识吸到就是你的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;社区&#34;&gt;社区&lt;/h2&gt;&#xA;&lt;p&gt;今年因为分享知识接触到了很多人，又因此认识到了更多的人。其中不乏各行各领域的优秀小伙伴们，间接的给我人生发展上提供了极大的建议和反馈，影响了我做许多事情的决策和思考方向。&lt;/p&gt;&#xA;&lt;p&gt;同时在 Gopher China 2020 中拿到了 GOP（Go 领域最具观点专家）的荣誉：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/6106728f2f69a19d5584623326c97363.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;很可惜的是，当时正在在准备公司内答辩的 PPT 和生病中，因此没能去现场，很遗憾。&lt;/p&gt;&#xA;&lt;p&gt;不过在线下依然感受到了各路 Gopher 们的反馈和关注，很感谢 GoCN 的认可。&lt;/p&gt;&#xA;&lt;p&gt;未曾想过的第二个里程碑完成。&lt;/p&gt;&#xA;&lt;h2 id=&#34;工作&#34;&gt;工作&lt;/h2&gt;&#xA;&lt;p&gt;感觉自己变化太大了，发现今年思考事情的角度、广度、深度以及关联性已然和上一年不一样。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/82d6bd939ce594c3ad219722380f5957.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;经提醒也发现已入职三年半，已经到了传统定义的 “职业倦怠期” 的时间阶段，如何更好的保持自己的好奇和发展是一个要考虑的大命题。&lt;/p&gt;&#xA;&lt;p&gt;自己评判自己的工作是很难的，继续努力是大方向。&lt;/p&gt;&#xA;&lt;h2 id=&#34;读书&#34;&gt;读书&lt;/h2&gt;&#xA;&lt;p&gt;今年看的书挺多，涉及了计算机、产品设计、用户增长、金融理财等各个领域。&lt;/p&gt;</description>
    </item>
    <item>
      <title>吐血整理 | 快速了解全球软件案例（Top100）</title>
      <link>https://note.lican.site/posts/posts/2020-top100/</link>
      <pubDate>Tue, 22 Dec 2020 21:26:44 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/2020-top100/</guid>
      <description>&lt;p&gt;前几天，煎鱼去了趟北京，参加了为期三天的全球软件案例研究峰会（TOP 100）。&lt;/p&gt;&#xA;&lt;p&gt;同时记了一些笔记，整理后分享出来，希望对大家有所帮助，拓展眼界非常重要。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a1be9ee345e57e1299f74a3d9e336d13.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;内容比较多（已经精简过），大家可以挑自己感兴趣的学习，建议三连。&lt;/p&gt;&#xA;&lt;p&gt;一级目录如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;百度内部业务 ServieMesh 实践。&lt;/li&gt;&#xA;&lt;li&gt;云原生开发平台在腾讯游戏运营中的实践。&lt;/li&gt;&#xA;&lt;li&gt;快狗打车可持续交付实践。&lt;/li&gt;&#xA;&lt;li&gt;网易数帆从微服务框架到服务网格架构平滑演进及最佳实践。&lt;/li&gt;&#xA;&lt;li&gt;不破不立：企业级研发效能提升的创新实践。&lt;/li&gt;&#xA;&lt;li&gt;自如云原生落地最佳实践。&lt;/li&gt;&#xA;&lt;li&gt;研发效能度量的误区、体系化实践和效能提升案例。&lt;/li&gt;&#xA;&lt;li&gt;京东 BDP 的全域监控、管控平台搭建实践。&lt;/li&gt;&#xA;&lt;li&gt;构建发布效率从10分钟到秒级的提升 - 云原生下编程方式的探索和实践。&lt;/li&gt;&#xA;&lt;li&gt;全面监控体系建设及智能监控的探索实践。&lt;/li&gt;&#xA;&lt;li&gt;低代码技术在贝壳的实践。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;百度内部业务-serviemesh-实践&#34;&gt;百度内部业务 ServieMesh 实践&lt;/h2&gt;&#xA;&lt;p&gt;本场演讲内容主要为微服务到服务网格的过程。其中涉及百度在异构场景下的一系列演进和适配操作。&lt;/p&gt;&#xA;&lt;p&gt;同时也能得知百度也是自己做了个 bmesh，自此概括几乎全一线互联网大厂，均为自研（或结合）ServieMesh。&lt;/p&gt;&#xA;&lt;h3 id=&#34;整体演进&#34;&gt;整体演进&lt;/h3&gt;&#xA;&lt;h4 id=&#34;10-时代&#34;&gt;1.0 时代&lt;/h4&gt;&#xA;&lt;p&gt;第一代微服务架构（1.0时代），主体是基于 SDK/开发框架的微服务治理体系。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/83b5009e040969ee7b60362ad7426573.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;主要存在以下问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;开发成本高：异构语言的问题，每个语言都要重新开发。&lt;/li&gt;&#xA;&lt;li&gt;升级成本高：框架上线以来业务。&lt;/li&gt;&#xA;&lt;li&gt;管理成本高：服务拓扑和治理没有统一管理（需要治理）。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;20时代&#34;&gt;2.0时代&lt;/h4&gt;&#xA;&lt;p&gt;第二代微服务架构（2.0时代），主体是基于微服务框架到服务网格，也就是把服务治理能力抽取出来，作为一个进程（sidecar），与业务逻辑解耦。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/ea571676ce9b75b0730a5d56350ae93e.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;从概念上来讲，主要分为以下两类：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;数据平面&#xA;&lt;ul&gt;&#xA;&lt;li&gt;与业务无关。&lt;/li&gt;&#xA;&lt;li&gt;与语言无关。&lt;/li&gt;&#xA;&lt;li&gt;独立的升级（直接升级 sidecar 的进程），能够解耦。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;控制平面&#xA;&lt;ul&gt;&#xA;&lt;li&gt;能够统一的管控。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;百度现状&#34;&gt;百度现状&lt;/h3&gt;&#xA;&lt;p&gt;各语言在内部平分秋色，没有谁强谁弱。各自都有框架，且有可能有多个框架，可自行脑补一下在公司内部一种语言有 N 种框架，且多种协议（含私有协议）的情况：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/182845aceb39c9e413e28fd549058cf8.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;存在以下问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;多个语言开发。&lt;/li&gt;&#xA;&lt;li&gt;多个框架改造。&lt;/li&gt;&#xA;&lt;li&gt;多个通讯协议。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;简单来讲就是 “异构系统”，传统的微服务框架无法满足了，成本非常高，甚至不可行。只能通过服务网关的方式来实现微服务治理。&lt;/p&gt;&#xA;&lt;h3 id=&#34;上服务网格的困难&#34;&gt;上服务网格的困难&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;改造成本：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;各种内部框架的支持。&lt;/li&gt;&#xA;&lt;li&gt;各种通讯协议的支持。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;性能问题：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;通讯延迟，有些敏感业务无法接受，例如：搜索。&lt;/li&gt;&#xA;&lt;li&gt;资源开源，数十万机器，每个服务都加边车，成本极大。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;规模问题：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;随着接入的节点越多，规模越大，控制平面下发配置的速度越慢，甚至无法工作。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;百度的解决方案整体架构&#34;&gt;百度的解决方案（整体架构）&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/9679ccb5a92f650b83fcf29e0a6a6775.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 错误处理：用 panic 取代 err != nil 的模式</title>
      <link>https://note.lican.site/posts/posts/go/go-error2panic/</link>
      <pubDate>Sat, 12 Dec 2020 17:21:42 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-error2panic/</guid>
      <description>&lt;p&gt;前段时间我分享了文章 《先睹为快，Go2 Error 的挣扎之路》后，和一位朋友进行了一次深度交流，他给我分享了他们项目组对于 Go 错误处理的方式调整。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，就是在业务代码中使用 &lt;code&gt;panic&lt;/code&gt; 的方式来替代 “永无止境” 的 &lt;code&gt;if err != nil&lt;/code&gt;。这就是今天本文的重点内容，我们一起来看看是怎么做，又有什么优缺点。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么想替换&#34;&gt;为什么想替换&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 语言中 &lt;code&gt;if err != nil&lt;/code&gt; 写的太多，还要管方法声明各种，嫌麻烦又不方便：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;err := foo()&#xA;if err != nil {&#xA;     //do something..&#xA;     return err&#xA;}&#xA;&#xA;err := foo()&#xA;if err != nil {&#xA;     //do something..&#xA;     return err&#xA;}&#xA;&#xA;err := foo()&#xA;if err != nil {&#xA;     //do something..&#xA;     return err&#xA;}&#xA;&#xA;err := foo()&#xA;if err != nil {&#xA;     //do something..&#xA;     return err&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;上述还是示例代码，比较直面。若是在工程实践，还得各种 package 跳来跳去加 &lt;code&gt;if err != nil&lt;/code&gt;，总的来讲比较繁琐，要去关心整体的上下游。更具体的就不赘述了，可以翻看我先前的文章。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 并发：一些有趣的现象和要避开的 “坑”</title>
      <link>https://note.lican.site/posts/posts/go/go-concurrent-lock/</link>
      <pubDate>Thu, 10 Dec 2020 00:25:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-concurrent-lock/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;最近在看 Go 并发相关的内容，发现还是有不少细节容易让人迷迷糊糊的，一个不小心就踏入深坑里，且指不定要在上线跑了一些数据后才能发现，那可真是太人崩溃了。&lt;/p&gt;&#xA;&lt;p&gt;今天来分享几个案例，希望大家在编码时能够避开这几个 “坑”。&lt;/p&gt;&#xA;&lt;h2 id=&#34;案例一&#34;&gt;案例一&lt;/h2&gt;&#xA;&lt;h3 id=&#34;演示代码&#34;&gt;演示代码&lt;/h3&gt;&#xA;&lt;p&gt;第一个案例来自 @鸟窝 大佬在极客时间的分享，代码如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;&#x9;count := 0&#xA;&#x9;wg := sync.WaitGroup{}&#xA;&#x9;wg.Add(10)&#xA;&#x9;for i := 0; i &amp;lt; 10; i++ {&#xA;&#x9;&#x9;go func() {&#xA;&#x9;&#x9;&#x9;defer wg.Done()&#xA;&#x9;&#x9;&#x9;for j := 0; j &amp;lt; 100000; j++ {&#xA;&#x9;&#x9;&#x9;&#x9;count++&#xA;&#x9;&#x9;&#x9;}&#xA;&#x9;&#x9;}()&#xA;&#x9;}&#xA;&#x9;wg.Wait()&#xA;&#xA;&#x9;fmt.Println(count)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;思考一下，最后输出的 &lt;code&gt;count&lt;/code&gt; 变量的值是多少？是不是一百万？&lt;/p&gt;&#xA;&lt;h3 id=&#34;输出结果&#34;&gt;输出结果&lt;/h3&gt;&#xA;&lt;p&gt;在上述代码中，我们通过 &lt;code&gt;for-loop &lt;/code&gt; 循环起 &lt;code&gt;goroutine&lt;/code&gt; 进行自增，并使用了 &lt;code&gt;sync.WaitGroup&lt;/code&gt; 来保证所有的 goroutine 都执行完毕才输出最终的结果值。&lt;/p&gt;&#xA;&lt;p&gt;最终的输出结果如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;// 第一次执行&#xA;638853&#xA;&#xA;// 第二次执行&#xA;654473&#xA;&#xA;// 第三次执行&#xA;786193&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出的结果值不是恒定的，也就是每次输出的都不一样，且基本不会达到想象中的一百万。&lt;/p&gt;</description>
    </item>
    <item>
      <title>先睹为快，Go2 Error 的挣扎之路</title>
      <link>https://note.lican.site/posts/posts/go/go2-errors/</link>
      <pubDate>Thu, 03 Dec 2020 20:56:47 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go2-errors/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;自从 Go 语言在国内火热以来，除去泛型，其次最具槽点的就是 Go 对错误的处理方式，一句经典的 &lt;code&gt;if err != nil&lt;/code&gt;  暗号就能认出你是一个 Go 语言爱好者。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/381fcb5e85923479666f5be14de3782c.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;自然，大家对 Go error 的关注度更是高涨，Go team 也是，因此在 &lt;a href=&#34;https://github.com/golang/proposal/blob/master/design/go2draft.md&#34;&gt;Go 2 Draft Designs&lt;/a&gt; 中正式提到了 error handling（错误处理）的相关草案，希望能够在未来正式的解决这个问题。&lt;/p&gt;&#xA;&lt;p&gt;在今天这篇文章中，我们将一同跟踪 Go2 error，看看他是怎么 “挣扎” 的，能不能破局？&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要吐槽-go1&#34;&gt;为什么要吐槽 Go1&lt;/h2&gt;&#xA;&lt;p&gt;要吐槽 Go1 error，就得先知道为什么大家到底是在喷 Error 哪里处理的不好。在 Go 语言中，error 其实本质上只是个 Error 的 &lt;code&gt;interface&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type error interface {&#xA;    Error() string&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;实际的应用场景如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;&#x9;x, err := foo()&#xA;&#x9;if err != nil {&#xA;&#x9;&#x9; // handle error&#xA;&#x9;}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;单纯的看这个例子似乎没什么问题，但工程大了后呢？显然 &lt;code&gt;if err != nil&lt;/code&gt; 的逻辑是会堆积在工程代码中，Go 代码里的 &lt;code&gt;if err != nil&lt;/code&gt; 甚至会达到工程代码量的 30% 以上：&lt;/p&gt;</description>
    </item>
    <item>
      <title>重磅：Go errors 将不会有任何进一步的改进计划</title>
      <link>https://note.lican.site/posts/posts/go/gophercon2020-errors/</link>
      <pubDate>Sat, 14 Nov 2020 16:48:33 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gophercon2020-errors/</guid>
      <description>&lt;p&gt;今天在 Gophercon2020 上，&lt;strong&gt;Go 1.13 错误提案的作者事后提及他对目前错误格式化的缺失表示遗憾，而且在未来很长的好几年内都不会有任何进一步改进计划&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;对此他本人给出的原因之一是：对于错误处理这一领域特定的问题，在他的能力范围内实在是无法给出一个令所有人都满意的方案。&lt;/p&gt;&#xA;&lt;p&gt;尽管如此，在他演讲的最后，还是给出了一些关于错误嵌套的建议，即实现 &lt;code&gt;fmt.Formatter&lt;/code&gt;，图中给出了一个简单的例子，大家可以参考如下代码：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type DetailError struct {&#xA;&#x9;msg, detail string&#xA;&#x9;err         error&#xA;}&#xA;&#xA;func (e *DetailError) Unwrap() error { return e.err }&#xA;&#xA;func (e *DetailError) Error() string {&#xA;&#x9;if e.err == nil {&#xA;&#x9;&#x9;return e.msg&#xA;&#x9;}&#xA;&#x9;return e.msg + &amp;#34;: &amp;#34; + e.err.Error()&#xA;}&#xA;&#xA;func (e *DetailError) Format(s fmt.State, c rune) {&#xA;&#x9;if s.Flag(&amp;#39;#&amp;#39;) &amp;amp;&amp;amp; c == &amp;#39;v&amp;#39; {&#xA;&#x9;&#x9;type nomethod DetailError&#xA;&#x9;&#x9;fmt.Fprintf(s, &amp;#34;%#v&amp;#34;, (*nomethod)(e))&#xA;&#x9;&#x9;return&#xA;&#x9;}&#xA;&#x9;if !s.Flag(&amp;#39;+&amp;#39;) || c != &amp;#39;v&amp;#39; {&#xA;&#x9;&#x9;fmt.Fprintf(s, spec(s, c), e.Error())&#xA;&#x9;&#x9;return&#xA;&#x9;}&#xA;&#x9;fmt.Fprintln(s, e.msg)&#xA;&#x9;if e.detail != &amp;#34;&amp;#34; {&#xA;&#x9;&#x9;io.WriteString(s, &amp;#34;\t&amp;#34;)&#xA;&#x9;&#x9;fmt.Fprintln(s, e.detail)&#xA;&#x9;}&#xA;&#x9;if e.err != nil {&#xA;&#x9;&#x9;if ferr, ok := e.err.(fmt.Formatter); ok {&#xA;&#x9;&#x9;&#x9;ferr.Format(s, c)&#xA;&#x9;&#x9;} else {&#xA;&#x9;&#x9;&#x9;fmt.Fprintf(s, spec(s, c), e.err)&#xA;&#x9;&#x9;&#x9;io.WriteString(s, &amp;#34;\n&amp;#34;)&#xA;&#x9;&#x9;}&#xA;&#x9;}&#xA;}&#xA;&#xA;func spec(s fmt.State, c rune) string {&#xA;&#x9;buf := []byte{&amp;#39;%&amp;#39;}&#xA;&#x9;for _, f := range []int{&amp;#39;+&amp;#39;, &amp;#39;-&amp;#39;, &amp;#39;#&amp;#39;, &amp;#39; &amp;#39;, &amp;#39;0&amp;#39;} {&#xA;&#x9;&#x9;if s.Flag(f) {&#xA;&#x9;&#x9;&#x9;buf = append(buf, byte(f))&#xA;&#x9;&#x9;}&#xA;&#x9;}&#xA;&#x9;if w, ok := s.Width(); ok {&#xA;&#x9;&#x9;buf = strconv.AppendInt(buf, int64(w), 10)&#xA;&#x9;}&#xA;&#x9;if p, ok := s.Precision(); ok {&#xA;&#x9;&#x9;buf = append(buf, &amp;#39;.&amp;#39;)&#xA;&#x9;&#x9;buf = strconv.AppendInt(buf, int64(p), 10)&#xA;&#x9;}&#xA;&#x9;buf = append(buf, byte(c))&#xA;&#x9;return string(buf)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;此处的内容来源于欧神（@changkun）在知识星球里的线上分享，作为 Go 夜读 SIG 成员的一员，借此也安利下咱们《Go 夜读》的星球，欢迎大家一起来学习和分享：&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么 Go 的泛型一拖再拖？</title>
      <link>https://note.lican.site/posts/posts/go/go16-preview/</link>
      <pubDate>Thu, 12 Nov 2020 23:47:16 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go16-preview/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。前段时间 Go 语言的泛型讨论频频出现在各微信群，且又冲上了国内外各大文章的 “头条”：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/c9c48e9479c7036f7d5a33b6ab49e855.jpg&#34; alt=&#34;来自 p 神公众号的截图&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;信息汇总来看，Go 泛型这几年会出，但大体来讲现在 Go 泛型又又又推迟了，好家伙。我最早了解到时是考虑 Go1.16 释出，后面又推到了 Go1.17，接着现在又延期到了 Go1.18 了（2021 年底）。&lt;/p&gt;&#xA;&lt;p&gt;看到了信息的表象后，再想想为什么泛型 “这件事情” 突然醒目起来了，其原因之一是由官方 &lt;a href=&#34;https://blog.golang.org/11years&#34;&gt;Go，11 岁&lt;/a&gt; 的博文所引爆的。&lt;/p&gt;&#xA;&lt;p&gt;同时近日举办的 GopherCon2020 大会，Robert Griesemer 分享的 Typing [Generic] Go。更正式的让 Go 泛型更面向了大众，也侧面的说明官方认为其已经到达了一个新的阶段了，进入最终实现阶段。&lt;/p&gt;&#xA;&lt;p&gt;事不宜迟，既然官方都已经摩拳擦掌了，我们的学习之路也得跟上，因此本文将会介绍 Go 泛型现在的情况，并通过在介绍过程中不断思考最后得出一个为什么。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是泛型&#34;&gt;什么是泛型&lt;/h2&gt;&#xA;&lt;p&gt;泛型程序设计（generic programming）是程序设计语言的一种风格或范式。泛型允许程序员在强类型语言中编写代码时，使用一些以后才确定的类型，其在真正实例化时才会为这些参数指确定类型。另外各语言和其编译器、运行环境对泛型的支持均不一样，因此需要针对来辩证。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，泛型就是参数化多态。其可根据实参类型生成不同的版本，支持任意数量的调用：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func F(a, b T) T{ return a+b }&#xA;&#xA;// T 为 int&#xA;F(1, 2)&#xA;&#xA;// T 为 string&#xA;F(&amp;#34;1&amp;#34;, &amp;#34;2&amp;#34;)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在编译时期编译器便确定其 T 的入参类型。这也是 Go 泛型实现的要求之一 “编译时类型安全”。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要泛型&#34;&gt;为什么需要泛型&lt;/h2&gt;&#xA;&lt;p&gt;这时候可能会有人说，没有泛型也可以啊&amp;hellip;感觉写业务代码没什么影响，与其搞泛型不如搞好 errors（具体新消息可参见：重磅：Go errors 将不会有任何进一步的改进计划）。&lt;/p&gt;&#xA;&lt;p&gt;但泛型是有其所需的场景，最常见的是像基础库在处理获取配置中心数据时，就要处理类型，时常遇到下述场景：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 语言今年 11 岁，何去何从，现状到底如何？</title>
      <link>https://note.lican.site/posts/posts/go/go11/</link>
      <pubDate>Wed, 11 Nov 2020 21:21:58 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go11/</guid>
      <description>&lt;p&gt;不说不知道，一说下一跳。Go 语言已经开源 11 周年了，感觉是一路高歌，Release History （polarisxu 整理）如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;2011 年 3 月 16 日，Go 语言的第一个稳定版本 r56 发布；&lt;/li&gt;&#xA;&lt;li&gt;2012 年 3 月  28 日，Go 语言的第一个正式版本 Go1 发布，并承诺 1.x 的 兼容性；&lt;/li&gt;&#xA;&lt;li&gt;2013 年  5 月 13 日，Go1.1 正式版才发布。&lt;/li&gt;&#xA;&lt;li&gt;2013 年 12 月 1 日，Go1.2 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2014 年 6 月 18 日，Go1.3 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2014 年 12 月 10 日，Go1.4 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2015 年 8 月 19 日，Go1.5 正式发布。该版本实现了自举，即移除了 C 代码，使用 Go 开发 Go 语言；&lt;/li&gt;&#xA;&lt;li&gt;2016 年 2 月 17 日，Go1.6 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2016 年 8 月 15 日，Go1.7 正式发布；引入 context 包；&lt;/li&gt;&#xA;&lt;li&gt;2017 年 2 月 17 日，Go1.8 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2017 年 8 月 24 日，Go1.9 正式发布；引入别名；&lt;/li&gt;&#xA;&lt;li&gt;2018 年 2 月 16 日，Go1.10 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2018 年 8 月 25 日，Go1.11 正式发布。开始强势支持 Go modules；&lt;/li&gt;&#xA;&lt;li&gt;2019 年 3 月 1 日，Go1.12 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2019 年 9 月 3 日，Go1.13 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2020 年 2 月 25 日，Go1.14 正式发布；goroutine 支持异步抢占调度；&lt;/li&gt;&#xA;&lt;li&gt;2020 年 8 月 11 日，Go1.15 正式发布；&lt;/li&gt;&#xA;&lt;li&gt;2021 年 2 月，预计 Go1.16 正式发布；将包含新的文件系统接口和支持在构建时的静态文件嵌入，以及链接器的重写，且正式对 Apple Silicon（GOARCH=arm64）Mac 进行支持。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;目视现在&#34;&gt;目视现在&lt;/h2&gt;&#xA;&lt;p&gt;现在的 Go 语言在国内已经掀起了一浪又一浪的热潮，炒的非常火热。各大平台极客时间、拉勾教育、掘金小册、慕课网等纷纷出现了大量 Go 语言相关的付费专栏/视频。&lt;/p&gt;</description>
    </item>
    <item>
      <title>解密 Go 语言之反射 reflect</title>
      <link>https://note.lican.site/posts/posts/go/reflect/</link>
      <pubDate>Sat, 07 Nov 2020 15:01:51 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/reflect/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;在所有的语言中，反射这一功能基本属于必不可少的模块。虽说 “反射” 这个词让人根深蒂固，但更多的还是 WHY。反射到底是什么，反射又是基于什么法则实现的？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/47976eb32b9cb5bdbe1869123fefb92b.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;今天我们通过这篇文章来一一揭晓，以 Go 语言为例，了解反射到底为何物，其底层又是如何实现的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;反射是什么&#34;&gt;反射是什么&lt;/h2&gt;&#xA;&lt;p&gt;在计算机学中，反射是指计算机程序在运行时（runtime）可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说，反射就是程序在运行的时候能够 “观察” 并且修改自己的行为（来自维基百科）。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/96394a2bb7b1dd964b5197837781e348.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;简单来讲就是，应用程序能够在运行时观察到变量的值，并且能够修改他。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一个例子&#34;&gt;一个例子&lt;/h2&gt;&#xA;&lt;p&gt;最常见的 reflect 标准库例子，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import (&#xA;&#x9;&amp;#34;fmt&amp;#34;&#xA;&#x9;&amp;#34;reflect&amp;#34;&#xA;)&#xA;&#xA;func main() {&#xA;&#x9;rv := []interface{}{&amp;#34;hi&amp;#34;, 42, func() {}}&#xA;&#x9;for _, v := range rv {&#xA;&#x9;&#x9;switch v := reflect.ValueOf(v); v.Kind() {&#xA;&#x9;&#x9;case reflect.String:&#xA;&#x9;&#x9;&#x9;fmt.Println(v.String())&#xA;&#x9;&#x9;case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:&#xA;&#x9;&#x9;&#x9;fmt.Println(v.Int())&#xA;&#x9;&#x9;default:&#xA;&#x9;&#x9;&#x9;fmt.Printf(&amp;#34;unhandled kind %s&amp;#34;, v.Kind())&#xA;&#x9;&#x9;}&#xA;&#x9;}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;hi&#xA;42&#xA;unhandled kind func&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在程序中主要是声明了 rv 变量，变量类型为 &lt;code&gt;interface{}&lt;/code&gt;，其包含 3 个不同类型的值，分别是字符串、数字、闭包。一般 &lt;code&gt;interface{}&lt;/code&gt; 的使用常见于不知道入参者具体的基本类型是什么，那么就会用 &lt;code&gt;interface{}&lt;/code&gt; 类型来做一个伪 “泛型”。&lt;/p&gt;</description>
    </item>
    <item>
      <title>应用编译，计算机中那些一定要掌握的知识细节</title>
      <link>https://note.lican.site/posts/posts/reading/programmer-compile-link/</link>
      <pubDate>Wed, 28 Oct 2020 20:52:52 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reading/programmer-compile-link/</guid>
      <description>&lt;p&gt;”Hello World“ 程序几乎是每个程序员入门和开发环境测试的基本标准。代码如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;#inclue &amp;lt;stdio.h&amp;gt;&#xA;&#xA;int main()&#xA;{&#xA;&#x9;printf(&amp;#34;Hello Wolrd\n&amp;#34;);&#xA;&#x9;return 0;&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;编译该程序，再运行，就基本完成了所有新手的第一个程序。表面看起来轻轻松松，毫无悬念。但是实际上单纯这几下操作，就已经包含了不少暗操作。本着追根溯源的目的，我们将进一步对其流程进行分析。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a8040c0fc18257d2891d4b570b02c44d.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其内部主要包含 4 个步骤，分别是：预处理、编译、汇编以及链接。由于篇幅问题本文主要涉及前三部分，链接部分将会放到下一篇文章来讲解。&lt;/p&gt;&#xA;&lt;h2 id=&#34;预编译&#34;&gt;预编译&lt;/h2&gt;&#xA;&lt;p&gt;程序编译的第一步是 “预编译” 环境。主要作用是处理源代码文件中以 ”#“ 开始的预编译指令，例如：&lt;code&gt;#include&lt;/code&gt;、&lt;code&gt;#define&lt;/code&gt; 等。&lt;/p&gt;&#xA;&lt;p&gt;常见的处理规则是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;将所有 &lt;code&gt;#define&lt;/code&gt; 删除，并且展开所有的宏定义。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;处理所有条件预编译指令，比如 &lt;code&gt;if&lt;/code&gt;、&lt;code&gt;ifdef&lt;/code&gt;、&lt;code&gt;elif&lt;/code&gt;、&lt;code&gt;else&lt;/code&gt;、&lt;code&gt;endif&lt;/code&gt;。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;处理 &lt;code&gt;#include&lt;/code&gt; 预编译指令，将所包含的文件插入到该预编译指令的位置（可递归处理子级引入）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;删除所有的注释。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;添加行号和文件名标识，以便于编译时编译器产生调试用的行号信息及用于编译时产生编译错误或警告时显示行号。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;保留所有的 &lt;code&gt;#pragma&lt;/code&gt; 编译器指令，后续编译器将会使用。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在预编译后，文件中将不包含宏定义或引入。因为在预编译后将会全部展开，相应的代码段均已被插入文件中。像 Go 语言中的话，主要是 &lt;code&gt;go generate&lt;/code&gt; 命令会涉及到相关的预编译处理。&lt;/p&gt;&#xA;&lt;h2 id=&#34;编译&#34;&gt;编译&lt;/h2&gt;&#xA;&lt;p&gt;第二步正式进入到 &amp;ldquo;编译&amp;rdquo; 环境。主要作用是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。该部分通常是整个程序构建的核心部分，也是最复杂的部分之一。&lt;/p&gt;&#xA;&lt;p&gt;执行编译操作的工具，一般称其为 “编译器”。编译器是将高级语言翻译成机器语言的一个工具。例如我们平时用 Go 语言写的程序，编译器就可以将其编译成机器可以执行的指令及数据。那么我们就不需要再去关心相关的底层细节，因为使用机器指令或汇编语言编写程序是一件十分费时及乏味的事情。&lt;/p&gt;&#xA;&lt;p&gt;且高级语言能够使得程序员更关注程序逻辑的本身，不再需要过多的关注计算机本身的限制，具有更高的平台可移植性，能够在多种计算机架构下运行。&lt;/p&gt;&#xA;&lt;h3 id=&#34;编译过程&#34;&gt;编译过程&lt;/h3&gt;&#xA;&lt;p&gt;编译过程一般分为 6 步：扫描、语法分析、语义分析、源代码优化、代码生成和目标代码优化。整个过程如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/c1e4902df20b68df654229d9618b9d58.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们结合上图的源代码（Source Code）到最终目标代码（Final Target Code）的过程，以一段最简单的 Go 语言程序的代理例子来复现和讲述整个过程，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package main&#xA;&#xA;import (&#xA;&#x9;&amp;#34;fmt&amp;#34;&#xA;)&#xA;&#xA;func main() {&#xA;&#x9;fmt.Println(&amp;#34;Hello World.&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;词法分析&#34;&gt;词法分析&lt;/h3&gt;&#xA;&lt;p&gt;首先 Go 程序会被输入到扫描器中，可以理解为所有解析程序的第一步，都是读取源代码。而扫描器的任务很简单，就是利用有限状态机对源代码的字符序列进行分割，最终变成一系列的记号（Token）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>快速了解 2020 Gopher Meetup 深圳站</title>
      <link>https://note.lican.site/posts/posts/go-meetup1017/</link>
      <pubDate>Sun, 18 Oct 2020 01:03:25 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go-meetup1017/</guid>
      <description>&lt;p&gt;昨天（20201017）很有幸的参加了 GoCN 的 2020 Gopher Meetup 深圳站，在台下听各位大佬分享各自的知识和案例。恰好也是我第一次参加这类 Meetup。因此希望也能够让没来的小伙伴对本次分享内容有一定的了解。&lt;/p&gt;&#xA;&lt;p&gt;按过往对其观察的惯例，一般在下周后官方就会陆续释出 Meetup PPT 和推文，在此引个主线。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/08910eccd6b1b0c16c0f60571cd7745a.jpeg&#34; alt=&#34;会场外的展板，图来自 GoCN&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;本次 Meetup 主要的方向是云原生，包含四位讲师分享，分享的主题如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;华为云的 go 语言云原生实践。&lt;/li&gt;&#xA;&lt;li&gt;go 云上微服务模式解构。&lt;/li&gt;&#xA;&lt;li&gt;服务网格在边缘计算领域的实践与探索。&lt;/li&gt;&#xA;&lt;li&gt;腾讯大规模 etcd 集群治理与优化实践。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;华为云的-go-语言云原生实践&#34;&gt;华为云的 go 语言云原生实践&lt;/h2&gt;&#xA;&lt;p&gt;讲述华为云在早起使用 Go 语言时，当时 Go 语言的整体生态圈还比较薄弱，因此很多第三方基础/工具库并不全：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/4adaf1b0b465a3197a9ba9d714dda51d.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;围绕此整体做一系列的东西，主要从统一框架开始做，提供各种插件，组件，基本涵盖了常用的所有组件。其所带来的的价值/效益：能够直接提高研发效能，让其他业务能够简单使用，不需要太重复造轮子：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/8c0afff2cb0bb6d2901d1e4d7f8296f2.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;再往后就介绍了其使用了 Mesh 去做整块的流量标识，金丝雀等流量控制方案。同时还支持了市面上常见的框架和协议。是一个比较完整很常见的整体解决方案，有真实的参考意义。&lt;/p&gt;&#xA;&lt;p&gt;若在企业内部有建设过这类基础应用可能会感触比较深，且各家多多少少都有类似的东西，需要必需品。社区的小伙伴可以多看看，结合自己的实际情况进行选型或融合。&lt;/p&gt;&#xA;&lt;p&gt;同时该类基础规范，最难的可能还是如何在企业内部达到大一统，做推广，拿规范，遵守则。&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-云上微服务模式解构&#34;&gt;go 云上微服务模式解构&lt;/h2&gt;&#xA;&lt;p&gt;详细介绍了云原生的定义，主体讲解了 k8s 的基本网络模型，核心在于传统微服务模式和云原生模式下的各类优缺点和对比。&lt;/p&gt;&#xA;&lt;h3 id=&#34;edge-proxy&#34;&gt;Edge Proxy&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/0275954e8196ac7c687a1c58e1b4be23.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;servicemesh&#34;&gt;ServiceMesh&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/794182e59306fec93128765f1854a353.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;需要听讲者有一定的基础，整体语速相当快，口述内容也比较多，因此这块没有过多详细记述。&lt;/p&gt;&#xA;&lt;p&gt;演讲内容主体对应云原生下的几种部署模式，线上的话在网上查阅资料学习即可，可能会更高效些。&lt;/p&gt;&#xA;&lt;p&gt;印象比较深的是，讲师表述目前也没用 ServiceMesh，四年前也预演过，但问题不少，近期打算重新启动。这块我司也多次尝试，多多少少都有些问题，期待 Istio 更稳定成熟的一天。&lt;/p&gt;&#xA;&lt;h2 id=&#34;服务网格在边缘计算领域的实践与探索&#34;&gt;服务网格在边缘计算领域的实践与探索&lt;/h2&gt;&#xA;&lt;p&gt;主体介绍边缘计算相关的 KubeEdge、IEF 等技术体系：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/ddab54efbf97b478c4ea06c8a602dcef.jpeg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这块不是我的技术领域内，隔壁的小哥也没听懂，稍微有些乱，因此不过多的介绍。&lt;/p&gt;&#xA;&lt;p&gt;但发现讲师刚毕业一年多，年轻有为，潜力无限。&lt;/p&gt;&#xA;&lt;h2 id=&#34;腾讯大规模-etcd-集群治理与优化实践&#34;&gt;腾讯大规模 etcd 集群治理与优化实践&lt;/h2&gt;&#xA;&lt;p&gt;腾讯云近期推出了 etcd 的云服务，先前关注了一番。恰好这次的分享者就是相关人士。&lt;/p&gt;</description>
    </item>
    <item>
      <title>必知必会！计算机里一些基本又重要的概念</title>
      <link>https://note.lican.site/posts/posts/reading/programmer-accom-base/</link>
      <pubDate>Sat, 17 Oct 2020 00:25:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reading/programmer-accom-base/</guid>
      <description>&lt;p&gt;最近在翻阅文章时，看到全成推荐的《程序员的自我修养》，这是一本讲链接、装载与库的计算机图书，看了下目录后觉得挺有意思。&lt;/p&gt;&#xA;&lt;p&gt;因此决定每读一章就将其读书笔记整理记录下来，分享给大家。&lt;/p&gt;&#xA;&lt;p&gt;目录：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/bf202dccad8c3f8efb3726854b72e850.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;不要让-cpu-打盹&#34;&gt;不要让 CPU 打盹&lt;/h2&gt;&#xA;&lt;p&gt;在计算机发展早期，CPU 资源十分昂贵。如果一个 CPU 只能运行一个程序，那么当程序在读写磁盘（进行 I/O 操作）时，CPU 就空闲下来了。这在当时简直就是巨大的浪费。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/df419c04c95fc7d58cc6f6f34a2fb7fd.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;CPU 只能和一个程序A “聊天“，其他来再多的程序BCD，都没有任何操作的空间。就像早年的手机，打电话和上网（语音/数据）只能二选一，作为 CPU 的你，并不能多线程操作。&lt;/p&gt;&#xA;&lt;p&gt;因此机智的人们很快就编写了一些监控程序，希望来解决这个问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;多道程序multiprogramming&#34;&gt;多道程序（Multiprogramming）&lt;/h3&gt;&#xA;&lt;p&gt;多道程序起，操作系统正式具有同时运行多个程序的能力。&lt;/p&gt;&#xA;&lt;p&gt;其是让 CPU 一次读取多个程序放入内存中。当某个程序暂时无须使用 CPU 时，监控程序就把另外的正在等待 CPU 资源的程序启动，以此使得 CPU 能够充分地利用起来。这种策略的确大大的提高了 CPU 资源的利用率。&lt;/p&gt;&#xA;&lt;h4 id=&#34;真实场景&#34;&gt;真实场景&lt;/h4&gt;&#xA;&lt;p&gt;你在 Windows 上点击鼠标 10 分钟以后系统才有反应，那是多么无奈的事情。因为没有优先级区分，自然一路排下来也就不知道要等到什么时候了，相当于半饿死。&lt;/p&gt;&#xA;&lt;h4 id=&#34;存在的问题&#34;&gt;存在的问题&lt;/h4&gt;&#xA;&lt;p&gt;核心问题在于程序之间的调度策略太粗糙。对于多道程序来删，程序之间部分轻重缓急，也就是说不存在优先级的区分。因此如果有些程序急需使用 CPU 来完成一些任务，那么很有可能会很长时间后才有机会被分配到 CPU，才得以继续往下运行。&lt;/p&gt;&#xA;&lt;h3 id=&#34;分时系统time-sharing-system&#34;&gt;分时系统（Time-Sharing System）&lt;/h3&gt;&#xA;&lt;p&gt;程序运行模式改为协作的模式，在原有的多道程序继续升级改造，即每个程序运行一段时间以后都主动让出 CPU 给其他程序，使得一段时间内每个程序都有机会运行一小段。&lt;/p&gt;&#xA;&lt;h4 id=&#34;真实场景-1&#34;&gt;真实场景&lt;/h4&gt;&#xA;&lt;p&gt;比如你点击一下鼠标或按下一个键盘按键后，他会相较前者能够更快的得到响应，因为他好歹是存在切换的可能性。&lt;/p&gt;&#xA;&lt;h4 id=&#34;存在问题&#34;&gt;存在问题&lt;/h4&gt;&#xA;&lt;p&gt;这时候的监控程序已经比原有多道程序的模式已经复杂了不少，完整的操作系统雏形已经基本形成，很早期的 Windows（Windows 95 和 Windows NT 之前），MacOS X 之前的 MacOS 版本都是采用这种分时系统的方式来进行程序调度。&lt;/p&gt;&#xA;&lt;p&gt;其仍然存在问题，核心在于若一个程序一直在进行一个耗时计算，便会一直霸占着 CPU 不放，那么操作系统也没有不放，就会导致其他程序都只能无限等待，相当于就是系统假死了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;多任务系统multi-tasking&#34;&gt;多任务系统（Multi-tasking）&lt;/h3&gt;&#xA;&lt;h4 id=&#34;背景&#34;&gt;背景&lt;/h4&gt;&#xA;&lt;p&gt;在分时系统中，一个程序死循环就会导致系统假死，并且其运行效率并不高，只能解决当时的交互式环境。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 应用程序是怎么运行起来的？</title>
      <link>https://note.lican.site/posts/posts/go/go-bootstrap/</link>
      <pubDate>Thu, 08 Oct 2020 15:57:18 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-bootstrap/</guid>
      <description>&lt;p&gt;自古应用程序均从 Hello World 开始，你我所写的 Go 语言亦然：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import &amp;#34;fmt&amp;#34;&#xA;&#xA;func main() {&#xA;&#x9;fmt.Println(&amp;#34;hello world.&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这段程序的输出结果为 &lt;code&gt;hello world.&lt;/code&gt;，就是这么的简单又直接。但这时候又不禁思考了起来，这个 &lt;code&gt;hello world.&lt;/code&gt; 是怎么输出来，经历了什么过程。&lt;/p&gt;&#xA;&lt;p&gt;真是非常的好奇，今天我们就通过这篇文章来一探究竟。&lt;/p&gt;&#xA;&lt;h2 id=&#34;引导阶段&#34;&gt;引导阶段&lt;/h2&gt;&#xA;&lt;h3 id=&#34;查找入口&#34;&gt;查找入口&lt;/h3&gt;&#xA;&lt;p&gt;开始剖析之路，首先编译上文提到的示例程序：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ GOFLAGS&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;-ldflags=-compressdwarf=false&amp;#34;&lt;/span&gt; go build &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在命令中指定了 GOFLAGS 参数，这是因为在 Go1.11 起，为了减少二进制文件大小，调试信息会被压缩。导致在 MacOS 上使用 gdb 时无法理解压缩的 DWARF 的含义是什么（而我恰恰就是用的 MacOS）。&lt;/p&gt;&#xA;&lt;p&gt;因此需要在本次调试中将其关闭，再使用 gdb 进行调试，以此达到观察的目的：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ gdb awesomeProject &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; info files&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Symbols from &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/Users/eddycjy/go-application/awesomeProject/awesomeProject&amp;#34;&lt;/span&gt;.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Local exec file:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;`&lt;/span&gt;/Users/eddycjy/go-application/awesomeProject/awesomeProject&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&amp;#39;&lt;/span&gt;, file type mach-o-x86-64.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;Entry point: 0x1063c80&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;0x0000000001001000 - 0x00000000010a6aca is .text&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;gdb&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; b *0x1063c80&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Breakpoint &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; at 0x1063c80: file /usr/local/Cellar/go/1.15/libexec/src/runtime/rt0_darwin_amd64.s, line 8.&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过 Entry point 的调试，可看到真正的程序入口在 runtime 包中，不同的计算机架构指向不同，例如：MacOS 在 &lt;code&gt;src/runtime/rt0_darwin_amd64.s&lt;/code&gt;，Linux 在 &lt;code&gt;src/runtime/rt0_linux_amd64.s&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>带你快速了解：限流中的漏桶和令牌桶算法</title>
      <link>https://note.lican.site/posts/posts/microservice/leaky-token-buckets/</link>
      <pubDate>Tue, 06 Oct 2020 12:44:10 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/leaky-token-buckets/</guid>
      <description>&lt;p&gt;在前文 《限流熔断是什么，怎么做，不做行不行？》中针对 “限流” 动作，有提到流量控制其内部对应着两种常用的限流算法，分别是漏桶算法和令牌桶算法。因此会有的读者会好奇，这都是些啥？&lt;/p&gt;&#xA;&lt;p&gt;为了更进一步的了解 WHY，本文来快速探索一下，看看限流下的一些 “算法” 们到底有何作用，是为何成为流量控制的基石的？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/815f7524b5367149cc9c6725ee28cd12.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;理论上每一个对外/内提供功能的资源点，都需要进行一定的流量控制，否则在业务的持续迭代中，是有可能出现突发性流量的场景（就像年初所带来的一些行业突发转变，导致业务流量突然暴增）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/c29272e53f9e125dbbfba133b3eea7c4.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;若没有进行限流，就会出现一些奇奇怪怪的问题点，实则就是系统无法承受这波流量，逐渐崩溃，走向系统假死。&lt;/p&gt;&#xA;&lt;h2 id=&#34;现实场景&#34;&gt;现实场景&lt;/h2&gt;&#xA;&lt;p&gt;最常见的现实场景就是日常随处可见的排插、插座，其内置的保险丝，也被称为电流保险丝，其主要是起过载保护作用，保险丝会在电流异常升高到一定的高度和热度的时候，自身熔断切断电流，从而起到保护电路安全运行的作用。&lt;/p&gt;&#xA;&lt;p&gt;因此真实世界中有许多与软件工程中的限流熔断的场景有异曲同工之处，也是为了控制量，超量就切断。你也可以想想现实生活中是否有遇到其他类似的例子呢？&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/23af65486fc991e1bd976c37626ccf18.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;漏桶算法leaky-bucket&#34;&gt;漏桶算法（Leaky Bucket）&lt;/h2&gt;&#xA;&lt;p&gt;漏桶算法（Leaky Bucket）是网络中流量整形（Traffic Shaping）或速率限制（Rate Limiting）时常用的一种算法，它的主要目的是控制数据注入到网络的速率，平滑网络上的突发流量。&lt;/p&gt;&#xA;&lt;p&gt;漏桶算法通过其算法调控了流量访问，使得突发流量可以被整形，去毛刺，变成一个相对缓和，以便为网络提供一个稳定的流量。&lt;/p&gt;&#xA;&lt;p&gt;漏桶算法的存储桶主要由三个参数定义，分别是：桶的容量、水从桶中流出的速率、桶的初始充满度。&lt;/p&gt;&#xA;&lt;p&gt;其核心理念就如字面意思：一个会漏水的桶。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/386bdd6a907a2130f5bfa74696817221.jpg&#34; alt=&#34;图片来自 geeksforgeeks&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;bursty-flow&#34;&gt;Bursty Flow&lt;/h3&gt;&#xA;&lt;p&gt;在上图中，水龙头代表着突发流量（Bursty Flow）。当网络中存在突发流量，且无任何调控时，就会出现像 Bursty Data 处类似的场景。主机以 12 Mbps 的速率发送数据，时间持续 2s，总计 24 Mbits 数据。随后主机暂停发送 5s，然后再以 2 Mbps 的速率发送数据 3s，最终总共发送了 6 Mbits 的数据。&lt;/p&gt;&#xA;&lt;p&gt;因此主机在 10s 内总共发送了 30 Mbits 的数据。但这里存在一个问题，就是数据的发送并不是平滑的，存在一个较大的波峰。若所有流量都是如此的传输方式，将会 “旱的旱死涝的涝死”，对系统并不是特别的友好。&lt;/p&gt;&#xA;&lt;h3 id=&#34;fixed-flow&#34;&gt;Fixed Flow&lt;/h3&gt;&#xA;&lt;p&gt;为了解决 Bursty Flow 场景的问题。漏桶（Leaky Bucket）出现了，漏桶具有固定的流出速率、固定的容量大小。&lt;/p&gt;&#xA;&lt;p&gt;在上图中，漏桶在相同的 10s 内以 3 Mbps 的速率持续发送数据来平滑流量。若水（流量）来的过猛，但水流（漏水）不够快时，其最终结果就是导致水直接溢出，呈现出来就是拒绝请求/排队等待的表现。另外当 Buckets 空时，是会出现一次性倒入达到 Bucket 容量限制的水的可能性，此时也可能会出现波峰。&lt;/p&gt;</description>
    </item>
    <item>
      <title>限流熔断是什么，怎么做，不做行不行？</title>
      <link>https://note.lican.site/posts/posts/microservice/flowcontrol-circuitbreaker/</link>
      <pubDate>Mon, 05 Oct 2020 13:24:16 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/flowcontrol-circuitbreaker/</guid>
      <description>&lt;p&gt;“在分布式应用中，最常见的问题是什么呢？”&lt;/p&gt;&#xA;&lt;p&gt;“一个分布式应用部署上去后，还要关注什么？”&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/8c42e87dd4f7f1c59431c6185f608699.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;“这服务的远程调用依赖似乎有点多&amp;hellip;”&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在 &lt;a href=&#34;https://eddycjy.com/posts/microservice/linkage/&#34;&gt;《微服务的战争：级联故障和雪崩》&lt;/a&gt;中有提到，在一个分布式应用中，最常见，最有危险性之一的点就是级联故障所造成的雪崩，而其对应的解决方案为&lt;strong&gt;根据特定的规则/规律进行流量控制和熔断降级&lt;/strong&gt;，避免请求发生堆积，保护自身应用，也防止服务提供方进一步过载。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/79a7f8870edffd331432272cf5db2c46.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;简单来讲就是，要控制访问量的流量，要防各类调用的强/弱依赖，才能保护好应用程序的底线。&lt;/p&gt;&#xA;&lt;h2 id=&#34;诉求期望&#34;&gt;诉求，期望&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;诉求：作为一个业务，肯定是希望自家的应用程序，能够全年无休，最低限度也要有个 4 个 9，一出突发性大流量，在资源贫乏的窗口期，就马上能够自动恢复。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;期望：万丈高楼平地起，我们需要对应用程序进行流量控制、熔断降级。确保在特定的规则下，系统能够进行容错，只处理自己力所能及的请求。若有更一步诉求，再自动扩缩容，提高系统资源上限。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;解决方案&#34;&gt;解决方案&lt;/h2&gt;&#xA;&lt;p&gt;要如何解决这个问题呢，可以关注到问题的核心点是 “系统没有任何的保护的情况下”，因此核心就是让系统，让你的应用程序有流量控制的保护。一般含以下几个方面：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;来自端控制：在业务/流量网关处内置流量控制、熔断降级的外部插件，起到端控制的效果。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;来自集群/节点控制：在统一框架中内建流量控制、熔断降级的处理逻辑，起到集群/节点控制的效果。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;来自 Mesh 控制：通过 ServiceMesh 来实现流量控制、熔断降级。侵入性小，能带来多种控制模式，但有利有弊。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以上的多种方式均可与内部的治理平台打通，且流量控制、熔断降级是不止面试应用程序的，就看资源埋点上如何设计、注入。常见有如下几种角度：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;资源的调用关系：例如远程调用，像是面向 HTTP、SQL、Redis、RPC 等调用均，另外针对文件句柄控制也可以。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;运行指标：例如 QPS、线程池、系统负载等。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;流量控制&#34;&gt;流量控制&lt;/h2&gt;&#xA;&lt;p&gt;在资源不变的情况下，系统所能提供的处理能力是有限的。而系统所面对的请求所到来的时间和量级往往是随机且不可控的。因此就会存在可能出现突发性流量，而在系统没有任何的保护的情况下，系统就会在数分钟内无法提供正常服务，常见过程为先是出现调用延迟，接着持续出现饱和度上升，最终假死。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/6a58406bb7c90355c82c5cb50f417f9a.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;流量控制一般常见的有两种方式，分别是：基于 QPS、基于并发隔离。&lt;/p&gt;&#xA;&lt;h3 id=&#34;基于-qps&#34;&gt;基于 QPS&lt;/h3&gt;&#xA;&lt;p&gt;最常用的流量控制场景，就是基于 QPS 来做流控，在一定的时间窗口内按照特定的规则达到所设定的阈值则进行调控：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/58f0d6fe0043963f6e40c1d73c8e019e.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;案例&#34;&gt;案例&lt;/h4&gt;&#xA;&lt;p&gt;在本文中借助 &lt;a href=&#34;https://github.com/alibaba/sentinel-golang&#34;&gt;sentinel-golang&lt;/a&gt; 来实现案例所需的诉求，代码如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import (&#xA;&#x9;...&#xA;&#x9;sentinel &amp;#34;github.com/alibaba/sentinel-golang/api&amp;#34;&#xA;&#x9;&amp;#34;github.com/alibaba/sentinel-golang/core/base&amp;#34;&#xA;&#x9;&amp;#34;github.com/alibaba/sentinel-golang/core/flow&amp;#34;&#xA;&#x9;&amp;#34;github.com/alibaba/sentinel-golang/util&amp;#34;&#xA;)&#xA;&#xA;func main() {&#xA;&#x9;_ = sentinel.InitDefault()&#xA;&#x9;_, _ = flow.LoadRules([]*flow.Rule{&#xA;&#x9;&#x9;{&#xA;&#x9;&#x9;&#x9;Resource:               &amp;#34;控制吃煎鱼的速度&amp;#34;,&#xA;&#x9;&#x9;&#x9;Threshold:              60,&#xA;&#x9;&#x9;&#x9;ControlBehavior:        flow.Reject,&#xA;&#x9;&#x9;},&#xA;&#x9;})&#xA;&#xA;&#x9;...&#xA;&#x9;e, b := sentinel.Entry(&amp;#34;控制吃煎鱼的速度&amp;#34;, sentinel.WithTrafficType(base.Inbound))&#xA;&#x9;if b != nil {&#xA;&#x9;    // Blocked&#xA;&#x9;} else {&#xA;&#x9;    // Passed&#xA;&#x9;    e.Exit()&#xA;&#x9;}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;总的来讲，上述规则结果就是 1s 内允许通过 60 个请求，超出的请求的处理策略为直接拒绝（Reject）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>想要4个9？本文告诉你监控告警如何做</title>
      <link>https://note.lican.site/posts/posts/microservice/monitor-alarm/</link>
      <pubDate>Sun, 13 Sep 2020 18:42:17 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/monitor-alarm/</guid>
      <description>&lt;p&gt;“你说说，没有仪表盘的车，你敢开吗？”&lt;/p&gt;&#xA;&lt;p&gt;“没有仪表盘的车开在路上，你怎么知道现在是什么情况？”&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/6e2774d84ddcdb2d73918e06575a07b7.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;“客户说你这车又崩了，咋知道什么时候好的？​啥时候出的问题？”&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;将思考转换到现实的软件系统中，可想而知没有监控系统的情况下，也就是没有 ”仪表盘“ 的情况下实在是太可怕了。&lt;/p&gt;&#xA;&lt;p&gt;你的故障永远都是你的客户告诉你的，而&amp;hellip;在什么时候发生的，你也无法确定，只能通过客户的反馈倒推时间节点，最后从错误日志中得到相对完整的日志信息。&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;&#xA;&lt;p&gt;更要命的是你无法掌握主动权，错误日志有可能会有人漏记录，平均修复时间（MTTR）更不用想了，需要从 0.1 开始定位，先看 APP 是哪个模块报错，再猜测是哪个服务导致，再打开链路追踪系统，或是日志平台等。&lt;/p&gt;&#xA;&lt;p&gt;稍微复杂些的，排查来来往往基本都是半小时、一小时以上，那 4 个 9 肯定是达不到的了，以此几次 P0 几小时怕不是业务绩效也凉凉，因为故障修复的速度实在是太慢了。&lt;/p&gt;&#xA;&lt;p&gt;那归根到底，想破局怎么办，核心第一步就是要把监控告警的整个生态圈给建设好。&lt;/p&gt;&#xA;&lt;h2 id=&#34;监控定义&#34;&gt;监控定义&lt;/h2&gt;&#xA;&lt;p&gt;常说监控监控，监控的定义就是监测和控制，检测某些事物的变化，以便于进行控制。在常见的软件系统中，大多分为三大观察类别：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/b567a71921b7e54d703d9e47f491d6c0.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;业务逻辑：项目所对应的服务其承担的业务逻辑，通常需要对其进行度量。例如：每秒的下单数等。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;应用程序：应用程序。例如：统一的基础框架。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;硬件资源：服务器资源情况等。例如：Kubernetes 中的 Cadvisor 组件便会提供大量的资源指标。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;从软件系统来讲，监控的定义就是收集、处理、汇总，显示关于某个系统的实时量化数据，例如：请求的数量和类型，错误的数量和类型，以及各类调用/处理的耗时，应用服务的存活时间等。&lt;/p&gt;&#xA;&lt;h2 id=&#34;监控目标&#34;&gt;监控目标&lt;/h2&gt;&#xA;&lt;p&gt;知道了监控的定义，了解了监控的作用和具体的实施指标后。我们需要明确的知道，做监控的目标是什么：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/bab6275c4b7c73deec2d9f9919f967c7.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;从现实层面出发，做监控的初衷，就是希望能够及时的发现线上环境的各种各样奇奇怪怪的问题，为业务的正常运转保驾护航。因此整体分为上图四项：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;预测故障：故障还没出现，但存在异常。监控系统根据流量模型、数据分析、度量趋势来推算应用程序的异常趋势，推算可能出现故障的问题点。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;发现故障：故障已经出现，客户还没反馈到一线人员。监控系统根据真实的度量趋势来计算既有的告警规则，发现已经出现故障的问题点。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;定位故障：故障已经出现，需要监控系统协助快速定位问题，也就是根因定位（root cause）。此时是需要协调公司内生态圈的多个组件的，例如：链路追踪系统、日志平台、监控系统、治理平台（限流熔断等），根据监控系统所告警出来的问题作为起始锚点，对其进行有特定方向的分析，再形成 ”线索“ 报告，就可以大力的协助开发人员快速的定位问题，发现故障点。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;故障恢复：故障已经出现，但自动恢复了，又或是通过自动化自愈了。这种情况大多出现在告警规则的阈值配置的不够妥当，又或是第三方依赖恰好恢复了的场景。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;而更值得探讨的的是监控告警的后半段闭环，故障自愈，通过上述三点 “预测故障、发现故障、定位故障”，已经定位到故障了，就可以配合内部组件，实现自动化的 ”自愈“，减少人工介入，提高 MTTR。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/437e9d859ee86916f5d2d0bc409ab9f5.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此做监控系统的目标很明确，就是发现问题，解决问题，最好自愈，达到愉快休假，业务安心的目的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;4-个黄金指标&#34;&gt;4 个黄金指标&lt;/h2&gt;&#xA;&lt;p&gt;有定义，有目标，那指导呢。实际上 “业务逻辑、应用程序、硬件资源” 已经成为了一个监控系统所要监控构建的首要目标，绝大部分的监控场景都可以归类进来。且针对这三大项，《Google SRE 运维解密》 也总结出了 4 个黄金指标，在业界广为流传和借鉴：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;延迟：服务处理某个请求所需要的时间。&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;区分成功和失败请求很重要，例如：某个由于数据库连接丢失或者其他后端问题造成的 HTTP 500 错误可能延迟很低。因此在计算整体延迟时，如果将 500 回复的延迟也计算在内，可能会产生误导性的结果。&lt;/li&gt;&#xA;&lt;li&gt;“慢” 错误要比 “快” 错误更糟糕。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;流量：使用系统中的某个高层次的指标针对系统负载需求所进行的度量。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go: A Documentary 发布！</title>
      <link>https://note.lican.site/posts/posts/reading/documentary-of-go/</link>
      <pubDate>Fri, 11 Sep 2020 20:46:38 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reading/documentary-of-go/</guid>
      <description>&lt;p&gt;以前经常有读者问我，哪儿可以找到 Go 语言的前世今生，这种时候我们往往会告诉他去看 issues 和 proposals。但资料有点分散，且没有索引体系。因此不少人新入门的读者读着读着就跑偏了，又或是在第一步找资料上就被拦住了。&lt;/p&gt;&#xA;&lt;p&gt;最近欧神（@changkun）低调的发布了 《Go: A Documentary》，这个文档收集了 Go 开发过程中许多有趣（公开可见的）的问题，讨论，提案，CL 和演讲，其目的是为 Go 历史提供全面的参考。&lt;/p&gt;&#xA;&lt;p&gt;个人认为这份资料非常的有价值，相当于欧神把资料索引整理好了，强烈推荐对 Go 语言感兴趣的读者进行阅读：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/0643ae29cdb8fb99d5a83bf67b443a9a.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;内容索引主要分为：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Sources&lt;/li&gt;&#xA;&lt;li&gt;Committers&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Core Authors&lt;/li&gt;&#xA;&lt;li&gt;Compiler/Runtime Team&lt;/li&gt;&#xA;&lt;li&gt;Library/Tools/Security/Community&lt;/li&gt;&#xA;&lt;li&gt;Group Interviews&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Timeline&lt;/li&gt;&#xA;&lt;li&gt;Language Design&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Misc&lt;/li&gt;&#xA;&lt;li&gt;Slice&lt;/li&gt;&#xA;&lt;li&gt;Package Management (1.4, 1.5, 1.7)&lt;/li&gt;&#xA;&lt;li&gt;Type alias (1.9)&lt;/li&gt;&#xA;&lt;li&gt;Defer (1.13)&lt;/li&gt;&#xA;&lt;li&gt;Error values (1.13)&lt;/li&gt;&#xA;&lt;li&gt;Channel/Select&lt;/li&gt;&#xA;&lt;li&gt;Generics&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Compiler Toolchain&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Compiler&lt;/li&gt;&#xA;&lt;li&gt;Linker&lt;/li&gt;&#xA;&lt;li&gt;Debugger&lt;/li&gt;&#xA;&lt;li&gt;Tracer&lt;/li&gt;&#xA;&lt;li&gt;Builder&lt;/li&gt;&#xA;&lt;li&gt;Modules&lt;/li&gt;&#xA;&lt;li&gt;gopls&lt;/li&gt;&#xA;&lt;li&gt;Testing&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Runtime Core&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Statistics&lt;/li&gt;&#xA;&lt;li&gt;Scheduler&lt;/li&gt;&#xA;&lt;li&gt;Execution Stack&lt;/li&gt;&#xA;&lt;li&gt;Memory Allocator&lt;/li&gt;&#xA;&lt;li&gt;Garbage Collector&lt;/li&gt;&#xA;&lt;li&gt;Memory model&lt;/li&gt;&#xA;&lt;li&gt;ABI&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Standard Library&#xA;&lt;ul&gt;&#xA;&lt;li&gt;syscall&lt;/li&gt;&#xA;&lt;li&gt;io&lt;/li&gt;&#xA;&lt;li&gt;go/*&lt;/li&gt;&#xA;&lt;li&gt;sync&lt;/li&gt;&#xA;&lt;li&gt;Pool&lt;/li&gt;&#xA;&lt;li&gt;Mutex&lt;/li&gt;&#xA;&lt;li&gt;atomic&lt;/li&gt;&#xA;&lt;li&gt;time&lt;/li&gt;&#xA;&lt;li&gt;context&lt;/li&gt;&#xA;&lt;li&gt;encoding&lt;/li&gt;&#xA;&lt;li&gt;image, x/image&lt;/li&gt;&#xA;&lt;li&gt;misc&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Unclassified But Relevant Links&lt;/li&gt;&#xA;&lt;li&gt;Fun Facts&lt;/li&gt;&#xA;&lt;li&gt;Acknowledgements&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;《Go: A Documentary》 的访问地址是 &lt;code&gt;https://golang.design/history/&lt;/code&gt;，GitHub 仓库地址：&lt;code&gt;https://github.com/golang-design/history&lt;/code&gt;，大家也可以通过 “阅读原文” 进入。&lt;/p&gt;</description>
    </item>
    <item>
      <title>微服务的灾难：端到端测试的痛苦</title>
      <link>https://note.lican.site/posts/posts/microservice/tests/</link>
      <pubDate>Thu, 10 Sep 2020 19:54:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/tests/</guid>
      <description>&lt;p&gt;大家好，我是煎鱼。&lt;/p&gt;&#xA;&lt;p&gt;小咸鱼经过前文所提到的折磨人的 “微服务拆分、微服务环境” 问题后，终于顺顺利利的上到了测试环境进行测试。&lt;/p&gt;&#xA;&lt;p&gt;这时候开发、测试同学又闹新的头疼了，测了一轮下来。发现好好的。结果发现一上生产就有一些地方有问题，发现没测到。&lt;/p&gt;&#xA;&lt;p&gt;这到底是为什么呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;在以往，小咸鱼他们团队都是传统的大单体应用。也就是一体化应用，包含了前端、后端等模块，具备天然的协调性：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;测试同学能够很方便的就直接测到前后端接口。&lt;/li&gt;&#xA;&lt;li&gt;测试能够直接对系统本身进行集成测试。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;但现在，做了微服务化（雏形）后，小咸鱼他们就翻车了，为什么呢？&lt;/p&gt;&#xA;&lt;p&gt;因为考虑到微服务，微服务就是向往单拎一个服务出来，都可以独立修改，独立发布。于是小咸鱼提交了一个迭代的几个服务变更，想着实现一把 “敏捷” 发布。&lt;/p&gt;&#xA;&lt;p&gt;结果一上线就炸了，一大堆的 BUG，光荣加班到晚上 12 点。&lt;/p&gt;&#xA;&lt;p&gt;这实质上是缺乏端到端测试的一个问题，单服务，无法明确系统正在正常运行。&lt;/p&gt;&#xA;&lt;h2 id=&#34;端到端测试&#34;&gt;端到端测试&lt;/h2&gt;&#xA;&lt;p&gt;在测试的质量保障上，我们要站在用户视角去验证这个系统，保障整体的系统可用性，而不是单纯的前端 BFF，又或是后端 Server 的某些接口能够正常运行。&lt;/p&gt;&#xA;&lt;p&gt;在定义上&lt;strong&gt;端到端测试（End-to-end Test）是一种用于测试整个应用程序的流程是否符合预期的测试技术&lt;/strong&gt;。测试同学会模拟用户真实的使用场景，通过用户界面测试应用程序。&lt;/p&gt;&#xA;&lt;p&gt;如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/5ca5b971d8e25cf41c648401489d47b4.jpg&#34; alt=&#34;端到端测试&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;与小咸鱼团队那种单纯只测接口的方式不同，端到端测试是面向业务的。&lt;/p&gt;&#xA;&lt;p&gt;其目的是&lt;strong&gt;验证应用程序系统整体上是否符合业务诉求&lt;/strong&gt;，主要通过 GUI 测试，也会有人称其为集成测试、系统测试，黑盒测试。不少公司会将这几种混在一起。&lt;/p&gt;&#xA;&lt;p&gt;实则在细节定义上各有不同：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://files.mdnice.com/user/3610/820d7fbb-e3aa-4e99-8898-d69fa242887b.png&#34; alt=&#34;图来自网络&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;本文不是测试方向文章，因此不深究。&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题症结&#34;&gt;问题症结&lt;/h2&gt;&#xA;&lt;p&gt;那么小咸鱼他们团队主要是缺乏端到端的这类集成测试的校验。直接在迭代中，把几个微服务一改，接口跑几下，以为就是合理通过的了。&lt;/p&gt;&#xA;&lt;p&gt;真实情况：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一上到生产，发现压根不是这么回事。因为多个变更结合在一起，很有可能会导致系统原有的行为发生改变。&lt;/li&gt;&#xA;&lt;li&gt;即使是你单个服务接口没违背，也不一定能保证其他在同个时段上的服务没问题。&lt;/li&gt;&#xA;&lt;li&gt;在业内执行情况来看，业务迭代的非常快，接口自动化大多比较缺乏。又或是以请外包人员的方式来做，大多是面向存量补接口。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;我们可以知道单纯验证接口，不走端到端类别的集成测试，是非常风骚的。设身处地的想想如下场景：&lt;/p&gt;&#xA;&lt;p&gt;有没有见过一些开发，他在本地测好接口后，一和前端集成上到测试环境。测试人员，一点一个报错，正向流程压根跑不通。测试同学苦不堪言，开发同学一下身背数十 BUG，齐齐加班。&lt;/p&gt;&#xA;&lt;p&gt;但开发同学大呼我在本地的接口测试的完全没问题。归根结底，小咸鱼团队的问题，还是因为缺乏端到端测试，缺乏齐全的接口自动化用例导致的。&lt;/p&gt;&#xA;&lt;h2 id=&#34;解决思路&#34;&gt;解决思路&lt;/h2&gt;&#xA;&lt;p&gt;在每个迭代中，实际上每个团队都会专注于系统中所使用的所有服务中的某个服务。&lt;/p&gt;&#xA;&lt;p&gt;系统中存在的大量微服务和子系统的功能和较窄的测试空间，有可能会导致没有发现系统或服务中存在的隐患。&lt;/p&gt;&#xA;&lt;p&gt;这样测试，问题的出现，甚至是必然的。&lt;/p&gt;&#xA;&lt;p&gt;在解决思路上常见于：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;新增预发布环境，做类似端到端测试的集成测试，确保系统集成后会是可用的。&lt;/li&gt;&#xA;&lt;li&gt;尝试更高覆盖率的接口自动化测试，大多数公司会针对新的，做增量或存量的自动化测试用例的补全。&lt;/li&gt;&#xA;&lt;li&gt;借助线上、线下数据在 CI/CD 时进行自动化测试，实现更全面真实的测试用例。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;业内基本是数种思路齐头并进，最常见的是第一种方式。最有效，但开销也是最大的，并且会导致预发布环境的一定阻塞。&lt;/p&gt;&#xA;&lt;p&gt;随后第二第三种大多都会紧接着跟进，具体程度会根据公司的软硬实力（例如：行政手段、基础设施等）不同而做的深度不同。&lt;/p&gt;&#xA;&lt;p&gt;甚至前几天听小咸鱼说，面试时还听到不少公司延伸了外包岗位专门做一块的内容。&lt;/p&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;&#xA;&lt;p&gt;虽说这个问题并不是 “微服务” 架构所独有的。但是显然微服务化后放大了测试的深坑问题。&lt;/p&gt;&#xA;&lt;p&gt;很多公司的流程和措施都是为了保障一些东西，像小咸鱼团队这样，被网上布道师例举的优点遮蔽了双眼，后面又被迫把端到端测试加回来的不在少数。&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;你们的团队又是如何高效解决这个问题的呢，欢迎在评论区留言和交流&lt;/strong&gt;！&lt;/p&gt;</description>
    </item>
    <item>
      <title>微服务的战争：选型？分布式链路追踪</title>
      <link>https://note.lican.site/posts/posts/microservice/tracing/</link>
      <pubDate>Thu, 10 Sep 2020 19:53:59 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/tracing/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;“微服务的战争” 是一个关于微服务设计思考的系列题材，主要是针对在微服务化后所出现的一些矛盾/冲突点，不涉及具体某一个知识点深入。如果你有任何问题或建议，欢迎随时交流。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;在经历 &lt;a href=&#34;https://eddycjy.com/posts/microservice/linkage/&#34;&gt;微服务的战争：级联故障和雪崩&lt;/a&gt; 的 P0 级别事件后，你小手一摊便葛优躺了。开始进行自我复盘，想起这次排查经历，由于现在什么基础设施都还没有，因此在接收到客户反馈后，你是通过错误日志进行问题检查的。&lt;/p&gt;&#xA;&lt;p&gt;但在级联错误中，错误日志产生的实在是太多了，不同的服务不同的链路几乎都挤在一起，修复时间都主要用在了翻日志上，翻了好几页才找到了相对有效的错误信息。&lt;/p&gt;&#xA;&lt;p&gt;如果下一次在出现类似的问题，可不得了，MTTR 太久了，4 个 9 很快就会用完。这时候你想到了业界里经常被提起的一个利器，那就是 “分布式链路追踪系统”。粗略来讲，能够看到各种应用的调用依赖：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/e233f218a90b7a00b94b7f533a98c0a2.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;其中最著名的是 &lt;a href=&#34;https://storage.googleapis.com/pub-tools-public-publication-data/pdf/36356.pdf&#34;&gt;Google Dapper&lt;/a&gt; 论文所介绍的 Dapper。源于 Google 为了解决可能由不同团队，不同语言，不同模块，部署在不同服务器，不同数据中心的所带来的软件复杂性（很难去分析，无法做定位），构建了一个的分布式跟踪系统：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/64214cb247989300859b98b61a844c2e.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;自此就开启了业界在分布式链路的启发/启蒙之路，很多现在出名的分布式链路追踪系统都是基于 Google Dapper 论文发展而来，基本原理和架构都大同小异。若对此有兴趣的可具体查看 &lt;a href=&#34;https://storage.googleapis.com/pub-tools-public-publication-data/pdf/36356.pdf&#34;&gt;Google Dapper&lt;/a&gt;，非常有意思。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/65bd2c9b931f057d7307dfaaa8d5c433.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;（Google Dapper 中存在跟踪树和 Span 的概念）&lt;/p&gt;&#xA;&lt;h2 id=&#34;选型有哪些&#34;&gt;选型？有哪些&lt;/h2&gt;&#xA;&lt;p&gt;想做链路追踪，那必然要挑选一款开源产品作为你的分布式链路追踪系统，不大可能再造一个全新的，先实现业务目的最重要。因此在网上一搜，发现如下大量产品：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Twitter：Zipkin。&lt;/li&gt;&#xA;&lt;li&gt;Uber：Jaeger。&lt;/li&gt;&#xA;&lt;li&gt;Elastic Stack：Elastic APM。&lt;/li&gt;&#xA;&lt;li&gt;Apache：SkyWalking（国内开源爱好者吴晟开源）。&lt;/li&gt;&#xA;&lt;li&gt;Naver：Pinpoint（韩国公司开发）。&lt;/li&gt;&#xA;&lt;li&gt;阿里：鹰眼。&lt;/li&gt;&#xA;&lt;li&gt;大众点评：Cat。&lt;/li&gt;&#xA;&lt;li&gt;京东：Hydra。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;随手一搜就发现这类产品特别的多，并且据闻各大公司都有自己的一套内部链路追踪系统，这下你可犯了大难。他们之间都是基于 Google Dapper 演进出来的，那本质上到底有什么区别，怎么延伸出这么多的新产品？&lt;/p&gt;&#xA;&lt;h3 id=&#34;jaeger&#34;&gt;Jaeger&lt;/h3&gt;&#xA;&lt;p&gt;首先看看由 Uber 开发的 Jaeger，Jaeger 目前由 Cloud Native Computing Foundation（CNCF）托管，是 CNCF 的第七个顶级项目（于 2019 年 10 月毕业）：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/1a672c2972602f1f154c1666c94e860a.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Jaeger Client：Jaeger 客户端，是 Jaeger 针对 OpenTracing API 的特定语言实现，可用于手动或通过与 OpenTracing 集成的各种现有开源框架（例如Flask，Dropwizard，gRPC等）来检测应用程序以进行分布式跟踪。&lt;/p&gt;</description>
    </item>
    <item>
      <title>微服务的战争：级联故障和雪崩</title>
      <link>https://note.lican.site/posts/posts/microservice/linkage/</link>
      <pubDate>Tue, 25 Aug 2020 21:08:39 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/linkage/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;“微服务的战争” 是一个关于微服务设计思考的系列题材，主要是针对在微服务化后所出现的一些矛盾/冲突点，不涉及具体某一个知识点深入。如果你有任何问题或建议，欢迎随时交流。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;在 &lt;a href=&#34;https://eddycjy.com/posts/microservice/standardization/&#34;&gt;微服务的战争：统一且标准化&lt;/a&gt; 中，经过好几周与不同业务组不同事业部的跨部门讨论后，终于把初始的标准化方案给定下来了，大家欢快的使用起了内部的统一框架，疯狂的创建起了新服务，没隔多久服务调用链就变成了下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/97128d96a1a4b8ba1f765bf30134f529.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;服务间存在多次内部调用，服务 A =》服务 B =》服务 C =》服务D，而 服务 E =》 服务 B，服务 F =》服务 E，也就是存在着多个流量入口，且依赖相同的服务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;&#xA;&lt;p&gt;服务与服务中，总存在业务服务，公共服务，基础服务等类型。但在某一个夜晚，突然发现 BFF 调用后端服务开始逐渐不正常，客户给你截图反馈问题，你发现有点问题：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/844d0d5a730a4c692d7d96912e1d710c.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;单从表现来看，你发现是 BFF 调用服务 A 极度缓慢，也不知道怎么了&amp;hellip;正当以为是服务 A 出问题，想着万能重启一下时。你在日志平台和链路追踪系统一看，发现了大量的错误日志和缓慢，让你略微震惊，一时间不知道从何下手。&lt;/p&gt;&#xA;&lt;p&gt;这可怎么办？&lt;/p&gt;&#xA;&lt;h2 id=&#34;级联故障和雪崩&#34;&gt;级联故障和雪崩&lt;/h2&gt;&#xA;&lt;p&gt;实际上这是一次很经典的级联故障，最终导致系统雪崩的情景再现。单从上述拓扑来看，问题点之一在于服务 B：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/51b18e7c80833fbe1dc13b3a3290940b.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;服务 B 本身作为服务 A 和服务 F 的两个流量入口必经之处，想必至少是一个公共服务，但他也依赖了其他多个服务。因此若服务 C 和服务 D 其中一个有问题，在没有熔断措施的情况下，就出现级联故障，系统逐渐崩盘，最后雪崩：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/2e7b0d94c32f3bd8f3f7168046671d2b.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;服务 D 所依赖的外部接口出现了故障，而他并没有做任何的控制，因此扩散到了所有调用到他的服务，自然也就包含服务 B，因此最终出现系统雪崩。&lt;/p&gt;&#xA;&lt;p&gt;这种最经典的是出现在默认 Go http client 调用没有设置 Timeout，从而只要出现一次故障，就足矣让记住这类 “坑”，毕竟崩的 ”慢“，错误日志还多。&lt;/p&gt;&#xA;&lt;h2 id=&#34;解决方法&#34;&gt;解决方法&lt;/h2&gt;&#xA;&lt;p&gt;常见的方式是&lt;strong&gt;根据特定的规则/规律进行熔断和降级&lt;/strong&gt;，避免请求发生堆积：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;超时时间控制。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;慢调用比例。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;错误比例。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;自适应（例如：负载情况等）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;当然，这也只是壮士断腕，后续措施还包含监控告警，通知对应的开发人员来处理。且需提前对被降级的模块进行业务逻辑进行处理等等，这样才能够比较柔和且快速地度过这一次危机。&lt;/p&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;&#xA;&lt;p&gt;在分布式应用中，级联故障和雪崩是非常常见的，一些开发同学在模块设计时可能并没有意识到这块的问题，在微服务化后会一个不留神就碰到，因为其调用链变得特别的长且多。因此建议配套设施和限流熔断措施都应该及时跟上，否则面对一大堆的错误日志还是很无奈的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>微服务的战争：统一且标准化</title>
      <link>https://note.lican.site/posts/posts/microservice/standardization/</link>
      <pubDate>Sat, 22 Aug 2020 21:56:14 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/standardization/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;“微服务的战争” 是一个关于微服务设计思考的系列题材，主要是针对在微服务化后所出现的一些矛盾/冲突点，不涉及具体某一个知识点深入。如果你有任何问题或建议，欢迎随时交流。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/b70c37b40768191e5a6812096703a63f.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;开天辟地&#34;&gt;开天辟地&lt;/h2&gt;&#xA;&lt;p&gt;在远古开天辟地时，大单体转换成微服务化后，服务的数量越来越多。每起一个新的服务，就得把项目的目录结构，基础代码重新整理一遍，并且很有可能都是从最初的 template 上 ctrl+c，ctrl+v 复制出来的产物，如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/7b4642c2bb7af1e5656be047bc269fb6.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;但是基于 template 的模式，很快就会遇到各种各样的新问题：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/3c91559190480a348aeacd609199c2bb.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;随着跨事业部/业务组的使用增多，你根本不知道框架的 template 是什么时间节点被复制粘贴出去的，也不知道所对应的 commit-id 是什么，更不知道先前的 BUG 修复了没，也不知道有没有其他开发人员私下改过被复制走的 template。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，就是不具备可维护性，相对独立，BUG 可能一样，但却没有版本可规管。这时候，就可以选择做一个内部基础框架和对应的内部工具（已经有用户市场了），形成一个脚手架闭环：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/3787e41616779a91a3a052467b3acdee.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;通过基础工具+基础接口的方式，就可以解决项目A、B、C&amp;hellip;的基础框架版本管理和公共维护的问题，且在遇到框架 BUG 时，只需要直接 upgrade 就好了。而在框架维护者层面，还能通过注册机制知道目前基础框架的使用情况（例如：版本分布），便于后续的迭代和规划。&lt;/p&gt;&#xA;&lt;p&gt;同时若内部微服务依赖复杂，可以将脚手架直接 “升级”，再做多一层基础平台，通过 CI/CD 平台等关联创建应用，选择应用类型等基本信息，然后关联创建对应的应用模板、构建工具、网关、数据库、接口平台、初始化自动化用例等：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/0997fb71080b8f35fe0ccd68acaebc94.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;至此，就可以通过结合基础平台（例如：CI/CD）实现流程上的标准化控制，成为一个提效好帮手。&lt;/p&gt;&#xA;&lt;h2 id=&#34;大众创新&#34;&gt;大众创新&lt;/h2&gt;&#xA;&lt;p&gt;但，一切都有 “开天辟地” 那么顺利吗。实际上并不，在很多的公司中，大多数是在不同的时间阶段在不同的团队同时进行了多个开天辟地。&lt;/p&gt;&#xA;&lt;p&gt;更具现化来讲，就是在一家公司内，不同的团队里做出了多种基础工具和基础框架。更要命的是，他们几家的规范可能还不大一样。例如：框架在 gRPC 错误码的规范处理上的差异：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;业务错误码放在 grpc.status.details 中。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;业务错误码放在 grpc-status 中。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;业务错误码放在 grpc-message 中。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;又或是 HTTP 状态码的差异：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;HTTP Status Code 为金标准，不在主体定义业务错误码。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;HTTP Status Code 都为 200 OK（除宕机导致的 500，503 等），业务错误码由主体另外定义。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;粗略一看，单单在应用错误码/状态码这一件事情上，就能够玩出花样。而这件事又会导致各种问题，例如在监控平台上，因为不同团队所定义的状态码规范不一样，就会导致连基本的监控可用性都会有问题。&lt;/p&gt;&#xA;&lt;p&gt;像是有的小伙伴会把业务错误码放在 grpc-status 属性中，而在标准 gRPC 的规范中 grpc-status 是和 HTTP Status Code 一样有特定状态码映射的。这时候就会让监控告警系统十分难做，通用的告警规则到底是以哪份状态码为准？&lt;/p&gt;</description>
    </item>
    <item>
      <title>微服务的战争：按什么维度拆分服务</title>
      <link>https://note.lican.site/posts/posts/microservice/dismantle/</link>
      <pubDate>Wed, 19 Aug 2020 20:56:55 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/microservice/dismantle/</guid>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;“微服务的战争” 是一个关于微服务设计思考的系列题材，主要是针对在微服务化后所出现的一些矛盾/冲突点，不涉及具体某一个知识点深入。如果你有任何问题或建议，欢迎随时交流。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;微服务，这三个字正在席卷着目前的互联网软件行业，尤其在近几年云原生迸发后，似乎人人都对微服务有了更广泛的使用和理解，张口就是各种各样的问号，有着强大的好奇心。&lt;/p&gt;&#xA;&lt;p&gt;无独有偶，我有一个朋友鲤鱼在内部微服务的早期（每个业务组起步）就经常遇到下述的对话：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;张三&lt;/strong&gt;：为什么要拆现在的代码？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;鲤鱼&lt;/strong&gt;：因为 ！@&lt;em&gt;）&amp;amp;&amp;amp;#@&lt;/em&gt;！）&amp;amp;#！&amp;amp;）@！&amp;amp;！ 的原因。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;张三&lt;/strong&gt;：那即将要做的 “微服务” 是按照什么维度去拆分的服务？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;鲤鱼&lt;/strong&gt;：常见的一般根据 ！@#*@！#&amp;amp;！（@&amp;amp;！@）#@ 的方式来拆分。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;张三&lt;/strong&gt;：照你这么说好像也不大对，我看每个业务组拆分的维度似乎都不大一样？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;鲤鱼&lt;/strong&gt;：嗯，每个业务组还有自己的见解，不会完全相同。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;张三&lt;/strong&gt;：。。。所以微服务的拆分维度到底是什么？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;为什么想拆&#34;&gt;为什么想拆&lt;/h2&gt;&#xA;&lt;p&gt;为什么张三会有这个疑问呢，实际上是因为研发内部希望从原先的大单体，大仓库向微服务体系拆分转换，其原先大单体仓库结构，类 Monorepo：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/b61faf600a2648ecce258abfa7d57ce8.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;但类 Monorepo 又有不少的问题，像是：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;单个 Repo 体积过大&lt;/strong&gt;：导致 Git 无法直接拉取。当你设置完再拉取时，在网速慢时还能去泡杯咖啡，并且在开发机性能不佳的情况下，IDE 会比较卡，代码运行起来也慢。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;单个 Repo 存在公共函数/SDK&lt;/strong&gt;：在代码仓库中，必然存在公共依赖。因此在解决代码冲突时，若遗留了冲突符，且在动态语言中，不涉及便运行正常。但其实在上线后却又影响到其他业务，可真是糟糕透顶，分分钟被迫抱着事故。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;单个 Repo 模块职责/边界不清&lt;/strong&gt;：在实际的软件开发中，涉及数十个业务组同时在一个大 Repo 下进行开发，没有强控边界的情况下，往往会逐渐模糊，即使在设计时管得住自己，你也不一定能 100% 防止别人模糊你的边界。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;单个 Repo 包含了所有的源码&lt;/strong&gt;：出现公司源代码泄露时，会导致整个 Repo 外泄，相当的刺激和具有教育意义。因为虽然开放和协同了，不属于你们组的业务代码你也有权限查看了。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;当然，Monorepo 是否又完全不可行呢？实际上国外 Google，Facebook，Twitter 等公司都有在使用 Monorepo，并取得了一定的收益。&lt;/p&gt;&#xA;&lt;p&gt;其实做 Monorepo 是需要相应的大量工具支撑，若单纯只是一个 Repo 塞多个模块，基本都做不好，甚至引火烧身。还不如早早拆开，至少能确保各业务线服务的相对独立性。&lt;/p&gt;&#xA;&lt;h2 id=&#34;拆成什么样&#34;&gt;拆成什么样&lt;/h2&gt;&#xA;&lt;p&gt;张三在明白了拆的原因后，就出现了第二个问题，那就是 “微服务” 要按照什么样的维度去拆分服务？&lt;/p&gt;&#xA;&lt;p&gt;张三公司内部对于这块的知识处于模糊不清的阶段，因此需要进行深入了解，便于后续的团队共识和方法论建立，理所当然，十万个为什么也就出现了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;大单体变独立服务&#34;&gt;大单体变独立服务&lt;/h3&gt;&#xA;&lt;p&gt;最常见的拆分的方式是按照业务模块进行服务的拆解，像是前文所提到的业务模块，在设计上边界非常清晰，这种情况直接拆成各个服务就可以了：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/9fe68c7e07a732686240243376da5fcb.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而在拆分后，又会遇到一个新的问题，也就是张三问第三个问题 “每个业务组拆分的维度似乎都不大一样？”。&lt;/p&gt;&#xA;&lt;p&gt;因为在实际的执行过程中，严谨一些会由 SM 与 RD 一同开会探讨/规范初版的服务划分，而在持续的快速的迭代中，往往新服务的拆分都是由一线 RD 亲自操刀。&lt;/p&gt;</description>
    </item>
    <item>
      <title>新书《Go语言编程之旅：一起用Go做项目》出版啦！</title>
      <link>https://note.lican.site/posts/posts/go-programming-tour-book/</link>
      <pubDate>Fri, 03 Jul 2020 21:06:33 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/go-programming-tour-book/</guid>
      <description>&lt;p&gt;从我开始写技术文章起，不知不觉近三年过去了，咨询和催我出书和读者逐年递增，在 2019 年算是达到一个高峰。当然，综合考虑下我也是一直拒绝的，觉得火候还不够。&lt;/p&gt;&#xA;&lt;p&gt;直至 2019.09 月，polaris 主动找到了我，说有事情想找我商量，本着 “如果你在纠结一件事情做还是不做，不如先做了看看结果，至少不会后悔” 的想法，更何况是长期被 Ping，因此我一口答应下来，故事自此开始了。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/04737f7b3e5567224fd2bc93f352203d.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;本书定位&#34;&gt;本书定位&lt;/h2&gt;&#xA;&lt;p&gt;本书不直接介绍 Go 语言的语法基础，内容将面向项目实践，同时会针对核心细节进行分析。而在实际项目迭代中，常常会出现或多或少的事故，因此本书也针对 Go 语言的大杀器（分析工具）以及常见问题进行了全面讲解。&lt;/p&gt;&#xA;&lt;p&gt;本书适合已经大致学习了 Go 语言的基础语法后，想要跨越到下一个阶段的开发人员，可以填补该阶段的空白和进一步拓展你的思维方向。&lt;/p&gt;&#xA;&lt;h2 id=&#34;读者定位&#34;&gt;读者定位&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;基本了解 Go 语言的语法和使用方式的开发人员。&lt;/li&gt;&#xA;&lt;li&gt;想要进行 Go 相关项目实践和进一步摸索的开发人员。&lt;/li&gt;&#xA;&lt;li&gt;希望熟悉 Go 常用分析工具的开发人员。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本书大纲&#34;&gt;本书大纲&lt;/h2&gt;&#xA;&lt;p&gt;本书针对常见的项目类型，主要细分为 5 + 1 板块，分别是命令行、HTTP、RPC、Websocket 应用、进程内缓存以及 Go 中的大杀器。&lt;/p&gt;&#xA;&lt;p&gt;同时我们在项目开发、细节分析、运行时分析等方方面面都进行了较深入的介绍和说明，能够为 Go 语言开发者提供相对完整的项目实践经验，而如果深入阅读第六章的章节，更能够为未来各类问题出现时的问题排查提供一份强大的知识板块。&lt;/p&gt;&#xA;&lt;p&gt;如下为本书的思维导图概览：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/e5eafb17140fdc06830b838eb7fb0468.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;如何阅读这本书&#34;&gt;如何阅读这本书&lt;/h2&gt;&#xA;&lt;p&gt;常规的列目录未免太无趣。我想不如说说从我个人的角度，所看到读者们在近 3 年来是如何阅读/实践我的实践系列文章的，其面向的读者群体是完全一致的。希望能够从另外一个角度告诉你，应当如何阅读这本书，尽可能的效益最大化。&lt;/p&gt;&#xA;&lt;p&gt;首先，图书，买来要读，而与实战结合的图书，势必需要实践，实践最常见又分为脑内思考和上机实践：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a6faa89061d62be755b715607e2563b8.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而在持续的交流中，可以发现至少会延伸出以下几类深入层次的不同：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/e3b17b0867e66bda4b5c6fb24ddcebc9.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第一层&lt;/strong&gt;：只阅读，留有印象，需要时再唤醒，也行。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第二层&lt;/strong&gt;：阅读并实践，实打实的完成项目实践，收获丰满。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第三层&lt;/strong&gt;：实践的过程中，&lt;strong&gt;一定会遇到或大或小的问题&lt;/strong&gt;，有的人会放弃，这就是分叉点。但有的读者会持续排查，其提升了个人能力（排错能力很重要）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第四层&lt;/strong&gt;：实践完毕后，有自己的想法，认为某某地方还可以这样，也可以再实现更多的功能，举一反三，进一步拓展，并对项目提 issues 或进行 pr。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第五层&lt;/strong&gt;：完成整体项目后，抽离业务代码，标准化框架，实现框架的应用脚手架，并有的读者会进一步开源。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第六层&lt;/strong&gt;：形成脚手架后，在自己业务组开始落地，实际在项目中使用，由业务学习转化为企业实践。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;第七层&lt;/strong&gt;：在内部落地实践稳妥后，开始在其它业务组开始推广该框架脚手架，进一步标准化，拓展思路。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;通过上图中 “七层金字塔” 的理解，我们不难发现其对于实践项目的理解和应用已经不再是单单这个项目，而是有了更深远的意义，抽象一下，对照着著名的 “学习效率金字塔” 来看：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a35394d0ab562efaac8367c3eeff4b07.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在单纯的 “阅读” 时，其基本处于 “被动学习” 的阶段，而单进入阅读并实践时，已经转为了 “主动学习”，且绝大部分的读者做完实践后，表示 “嗯，实践完，挺好的，有所得”。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么容器内存占用居高不下，频频 OOM（续）</title>
      <link>https://note.lican.site/posts/posts/why-container-memory-exceed2/</link>
      <pubDate>Fri, 19 Jun 2020 21:29:08 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/why-container-memory-exceed2/</guid>
      <description>&lt;p&gt;在上周的文章&lt;a href=&#34;https://note.lican.site/posts/why-container-memory-exceed/&#34;&gt;《为什么容器内存占用居高不下，频频 OOM》&lt;/a&gt; 中，我根据现状进行了分析和说明，收到了很多读者的建议和疑惑，因此有了这一篇文章，包含更进一步的说明和排查。&lt;/p&gt;&#xA;&lt;h2 id=&#34;疑问&#34;&gt;疑问&lt;/h2&gt;&#xA;&lt;p&gt;一般系统内存过高的情况下，可以通过 &lt;code&gt;free -m&lt;/code&gt; 查看当前系统的内存使用情况：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/daf2a1d53f4bf0f21e315d2333e08159.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在发现是系统内存占用高后，就会有读者会提到，为什么不 “手动清理 Cache”，因为 Cache 高的话，可以通过 drop_caches 的方式来清理：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;清理 page cache：&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ echo 1 &amp;gt; /proc/sys/vm/drop_caches&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;清理 dentries 和 inodes：&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ echo 2 &amp;gt; /proc/sys/vm/drop_caches&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;3&#34;&gt;&#xA;&lt;li&gt;清理 page cache、dentries 和 inodes：&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &amp;gt; /proc/sys/vm/drop_caches&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但新问题又出现了，因为我们的命题是在容器中，在 Kubernetes 中，若执行 drop_caches 相关命令，将会对 Node 节点上的所有其他应用程序产生影响，尤其是那些占用大量 IO 并由于缓冲区高速缓存而获得更好性能的应用程序，可能会产生 “负面” 后果。&lt;/p&gt;&#xA;&lt;p&gt;我想这并不是一个好办法。&lt;/p&gt;&#xA;&lt;h2 id=&#34;表象&#34;&gt;表象&lt;/h2&gt;&#xA;&lt;p&gt;回归原始，那就是为什么要排查这个问题，本质原因就是容器设置了 Memory Limits，而容器在运行中达到了 Limits 上限，被 OOM 掉了，所以我们想知道为什么会出现这个情况。&lt;/p&gt;&#xA;&lt;p&gt;在前文中我们针对了五大类情况进行了猜想：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;频繁申请重复对象。&lt;/li&gt;&#xA;&lt;li&gt;不知名内存泄露。&lt;/li&gt;&#xA;&lt;li&gt;madvise 策略变更。&lt;/li&gt;&#xA;&lt;li&gt;监控/判别条件有问题。&lt;/li&gt;&#xA;&lt;li&gt;容器环境的机制。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在逐一排除后，后续发现容器的 Memory OOM 判定标准是 container_memory_working_set_bytes 指标，其实际组成为 RSS + Cache（最近访问的内存、脏内存和内核内存）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么容器内存占用居高不下，频频 OOM</title>
      <link>https://note.lican.site/posts/posts/why-container-memory-exceed/</link>
      <pubDate>Sun, 07 Jun 2020 14:52:19 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/why-container-memory-exceed/</guid>
      <description>&lt;p&gt;最近我在回顾思考（写 PPT），整理了现状，发现了这个问题存在多时，经过一番波折，最终确定了元凶和相对可行的解决方案，因此也在这里分享一下排查历程。&lt;/p&gt;&#xA;&lt;p&gt;时间线：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;在上 Kubernetes 的前半年，只是用 Kubernetes，开发没有权限，业务服务极少，忙着写新业务，风平浪静。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;在上 Kubernetes 的后半年，业务服务较少，偶尔会阶段性被运维唤醒，问之 “&lt;strong&gt;为什么你们的服务内存占用这么高，赶紧查&lt;/strong&gt;”。此时大家还在为新业务冲刺，猜测也许是业务代码问题，但没有调整代码去尝试解决。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;在上 Kubernetes 的第二年，业务服务逐渐增多，普遍增加了容器限额 Limits，出现了好几个业务服务是内存小怪兽，因此如果不限制的话，服务过度占用会导致驱逐，因此反馈语也就变成了：“&lt;strong&gt;为什么你们的服务内存占用这么高，老被 OOM Kill，赶紧查&lt;/strong&gt;”。据闻也有几个业务大佬有去排查（因为 OOM 反馈），似乎没得出最终解决方案。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;不禁让我们思考，为什么个别 Go 业务服务，Memory 总是提示这么高，经常达到容器限额，以至于被动 OOM Kill，是不是有什么安全隐患？&lt;/p&gt;&#xA;&lt;h2 id=&#34;现象&#34;&gt;现象&lt;/h2&gt;&#xA;&lt;h3 id=&#34;内存居高不下&#34;&gt;内存居高不下&lt;/h3&gt;&#xA;&lt;p&gt;发现个别业务服务内存占用挺高，触发告警，且通过 Grafana 发现在凌晨（没有什么流量）的情况下，内存占用量依然拉平，没有打算下降的样子，高峰更是不得了，像是个内存炸弹：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/2e6c8c153836b29175dff7623ec67a0a.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;并且我所观测的这个服务，早年还只是 100MB。现在随着业务迭代和上升，目前已经稳步 4GB，容器限额 Limits 纷纷给它开道，但我想总不能是无休止的增加资源吧，这是一个大问题。&lt;/p&gt;&#xA;&lt;h3 id=&#34;进入重启怪圈&#34;&gt;进入重启怪圈&lt;/h3&gt;&#xA;&lt;p&gt;有的业务服务，业务量小，自然也就没有调整容器限额，因此得不到内存资源，又超过额度，就会进入疯狂的重启怪圈：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/95644633a2d55cb2f2684a23d3f3f189.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;重启将近 300 次，非常不正常了，更不用提所接受到的告警通知。&lt;/p&gt;&#xA;&lt;h2 id=&#34;排查&#34;&gt;排查&lt;/h2&gt;&#xA;&lt;h3 id=&#34;猜想一频繁申请重复对象&#34;&gt;猜想一：频繁申请重复对象&lt;/h3&gt;&#xA;&lt;p&gt;出现问题的个别业务服务都有几个特点，那就是基本为图片处理类的功能，例如：图片解压缩、批量生成二维码、PDF 生成等，因此就怀疑是否在量大时频繁申请重复对象，而 Go 本身又没有及时释放内存，因此导致持续占用。&lt;/p&gt;&#xA;&lt;h4 id=&#34;syncpool&#34;&gt;sync.Pool&lt;/h4&gt;&#xA;&lt;p&gt;基本上想解决 “频繁申请重复对象”，我们大多会采用多级内存池的方式，也可以用最常见的 sync.Pool，这里可参考全成所借述的《Go 夜读》上关于 sync.Pool 的分享，关于这类情况的场景：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;当多个 goroutine 都需要创建同⼀个对象的时候，如果 goroutine 数过多，导致对象的创建数⽬剧增，进⽽导致 GC 压⼒增大。形成 “并发⼤－占⽤内存⼤－GC 缓慢－处理并发能⼒降低－并发更⼤”这样的恶性循环。&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;h4 id=&#34;验证场景&#34;&gt;验证场景&lt;/h4&gt;&#xA;&lt;p&gt;在描述中关注到几个关键字，分别是并发大，Goroutine 数过多，GC 压力增大，GC 缓慢。也就是需要满足上述几个硬性条件，才可以认为是符合猜想的。&lt;/p&gt;&#xA;&lt;p&gt;通过拉取 PProf goroutine，可得知 Goroutine 数并不高：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Proto 代码到底放哪里？</title>
      <link>https://note.lican.site/posts/posts/where-is-proto/</link>
      <pubDate>Sat, 23 May 2020 15:07:37 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/where-is-proto/</guid>
      <description>&lt;p&gt;虽然公司已经从大单体切换为微服务化有一定的年头了，但一些细节方面的处理总会有不同的人有不同的看法，这其中一个讨论点，就是 Proto 这个 IDL 的代码到底放在哪里？&lt;/p&gt;&#xA;&lt;p&gt;目前来看，一共有如下方案， 我们一起来探讨一下 Proto 的存储方式和对应带来的优缺点。&lt;/p&gt;&#xA;&lt;h2 id=&#34;方案一存放在代码仓库&#34;&gt;方案一：存放在代码仓库&lt;/h2&gt;&#xA;&lt;p&gt;直接将项目所依赖到的所有 Proto 文件都存放在 &lt;code&gt;proto/&lt;/code&gt; 目录下，不经过开发工具的自动拉取和发布：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/7e95a76d548197cf73e7238ee5df27e6.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;缺点&#34;&gt;缺点&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;项目所有依赖的 Proto 都存储在代码仓库下，因此所有依赖 Proto 都需要人工的向其它业务组 “要” 来，再放到 &lt;code&gt;proto/&lt;/code&gt; 目录下，人工介入极度麻烦。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Proto 升级和变更，经常要重复第一步，沟通成本高。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;优点&#34;&gt;优点&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;项目所有依赖的 Proto 都存储在代码仓库下，因此不涉及个人开仓库权限的问题。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;多 Proto 的切换开销减少，因为都在代码仓库下，不需要看这看那。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;方案二独立仓库&#34;&gt;方案二：独立仓库&lt;/h2&gt;&#xA;&lt;p&gt;独立仓库存储是我们最早采取的方式，也就是每个服务对应配套一个 Proto 仓库：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/a7575628ff1ae9179f022d477aba9df1.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;这个方案的好处就是可以独立管理所有 Proto 仓库，并且权限划分清晰。但最大的优点也是最大的缺点，因为一个服务会依赖多个 Proto 仓库，并且存在跨业务组调用的情况：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/31c5a5b5652f44750124c15e1c0ef397.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;如上图所示，svc-user 服务分别依赖了三块 Proto 仓库，分别是自己组的、业务组 A、业务组 B 总共的 6 个 Proto 仓库。&lt;/p&gt;&#xA;&lt;h3 id=&#34;缺点-1&#34;&gt;缺点&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;假设你是一个新入职的开发人员，那么你就需要找不同的业务组申请不同的仓库权限，非常麻烦。如果没有批量赋权工具，也没有管理者权限，那么就需要一个个赋权，非常麻烦。&lt;/li&gt;&#xA;&lt;li&gt;在运行服务的时候，你需要将所有相关联的 Proto 仓库拉取下来，如果没有工具做半自动化的支持，麻烦程度无法忍受。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;优点-1&#34;&gt;优点&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;使得安全性较高（但 IDL 本身没有太多的秘密）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;按需拉取，不需要关注其余的服务 Proto。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;方案三集中仓库&#34;&gt;方案三：集中仓库&lt;/h2&gt;&#xA;&lt;p&gt;集中仓库也是一些公司考虑的方式之一，是按公司或大事业部的维度进行 Proto 代码的存储，这样子只需要拉取一个仓库，就可以获取到所有所需的 IDL：&lt;/p&gt;</description>
    </item>
    <item>
      <title>使用 Prometheus 对 Go 程序进行指标采集</title>
      <link>https://note.lican.site/posts/posts/prometheus/2020-05-16-pull/</link>
      <pubDate>Sun, 17 May 2020 17:52:37 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/prometheus/2020-05-16-pull/</guid>
      <description>&lt;p&gt;在前面的章节中，已经知道了如何对应用程序进行 Prometheus metrics 的注册和暴露，那么接下来如何让 Prometheus 对应用程序进行采集呢。&lt;/p&gt;&#xA;&lt;h2 id=&#34;设置采集配置&#34;&gt;设置采集配置&lt;/h2&gt;&#xA;&lt;p&gt;首先打开先前所安装的 prometheus 软件目录：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ls&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LICENSE                data                   promtool&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NOTICE                 prometheus             rules&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;console_libraries      prometheus.yml         tsdb&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;consoles               prometheus.yml.default&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;打开并修改 prometheus.yml 文件，查看到 &lt;a href=&#34;https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config&#34;&gt;scrape_configs&lt;/a&gt; 配置选项，进行如下调整：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scrape_configs:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  - job_name: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;test01&amp;#39;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    static_configs:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    - targets: &lt;span style=&#34;color:#f92672&#34;&gt;[&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;127.0.0.1:10001&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    scheme: http&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    tls_config:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        insecure_skip_verify: false&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;先前所启动的应用程序是在本地，且端口号为 10001，协议为 http，对应的配置简述：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;job_name：采集的任务名。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;static_configs.targets：设置要采集的目标对象列表。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;scheme：采集的目标协议（例如：http、https）。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;tls_config.insecure_skip_verify：是否跳过证书校验。&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;常用的配置项如上几个，其默认的 metrics path 为 &lt;code&gt;/metrics&lt;/code&gt;，若需要调整则增加 metrics_path 配置项进行调整就可以了，接着重新启动 prometheus 就可以了。&lt;/p&gt;&#xA;&lt;h2 id=&#34;其他配置项&#34;&gt;其他配置项&lt;/h2&gt;&#xA;&lt;p&gt;再返回来看看 prometheus.yaml 文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;global:&#xA;  scrape_interval:     15s &#xA;  evaluation_interval: 15s&#xA;&#xA;&#xA;alerting:&#xA;  alertmanagers:&#xA;  - static_configs:&#xA;    - targets:&#xA;       - localhost:9093&#xA;&#xA;rule_files:&#xA;   - ../rules/*.yaml&#xA;&#xA;scrape_configs:&#xA;  - job_name: &amp;#39;test01&amp;#39;&#xA;    static_configs:&#xA;    - targets: [&amp;#39;127.0.0.1:10001&amp;#39;]&#xA;    scheme: http&#xA;    tls_config:&#xA;        insecure_skip_verify: false&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;scrape_interval：采集间隔（频率）。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Prometheus 四大度量指标的了解和应用</title>
      <link>https://note.lican.site/posts/posts/prometheus/2020-05-16-metrics/</link>
      <pubDate>Sat, 16 May 2020 15:08:51 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/prometheus/2020-05-16-metrics/</guid>
      <description>&lt;p&gt;在上一个章节中我们完成了 Prometheus 的基本概念了解和安装，由于考虑到看我博客的估计是开发向的小伙伴居多，因此没有再更深入。而今天本章节将介绍我们开发用的最多的度量指标，并结合实战对 Metrics 进行使用和细节分析。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是度量指标&#34;&gt;什么是度量指标&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;来自维基百科&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;度量是指对于一个物体或是事件的某个性质给予一个数字，使其可以和其他物体或是事件的相同性质比较。度量可以是对一物理量（如长度、尺寸或容量等）的估计或测定，也可以是其他较抽象的特质。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，也就是数据的量化，形成对应的数据指标。&lt;/p&gt;&#xA;&lt;h2 id=&#34;prometheus-的指标格式&#34;&gt;Prometheus 的指标格式&lt;/h2&gt;&#xA;&lt;p&gt;在 Prometheus 中，我们的指标表示格式如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;metric name&amp;gt;{&amp;lt;label name&amp;gt;=&amp;lt;label value&amp;gt;, ...}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;主体为指标名称和标签组成：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;api_http_requests_total{method=&amp;#34;POST&amp;#34;, handler=&amp;#34;/eddycjy&amp;#34;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;对外提供-metrics-服务&#34;&gt;对外提供 metrics 服务&lt;/h2&gt;&#xA;&lt;p&gt;首先创建一个示例项目：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;engine&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;engine&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/hello&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusOK&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;engine&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Run&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:10001&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;接下我们需要安装 Prometheus Client SDK，在 Go 语言中对应 &lt;a href=&#34;https://github.com/prometheus/client_golang&#34;&gt;prometheus/client_golang&lt;/a&gt; 库：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go get github.com/prometheus/client_golang&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后调用 &lt;code&gt;promhttp.Handler&lt;/code&gt; 方法创建对应的 metrics：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;engine&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/metrics&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WrapH&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;promhttp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Handler&lt;/span&gt;()))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;engine&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Run&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:10001&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;重新启动程序，并访问 &lt;code&gt;http://127.0.0.1:10001/metrics&lt;/code&gt;：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# TYPE go_gc_duration_seconds summary&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;quantile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;quantile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.25&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;quantile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.5&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;quantile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.75&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;quantile&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds_sum &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_gc_duration_seconds_count &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# HELP go_goroutines Number of goroutines that currently exist.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# TYPE go_goroutines gauge&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_goroutines &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# HELP go_info Information about the Go environment.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# TYPE go_info gauge&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_info&lt;span style=&#34;color:#f92672&#34;&gt;{&lt;/span&gt;version&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;go1.14.2&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# HELP go_memstats_alloc_bytes Number of bytes allocated and still in use.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# TYPE go_memstats_alloc_bytes gauge&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go_memstats_alloc_bytes 2.563056e+06&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以聚焦其中一个指标：&lt;/p&gt;</description>
    </item>
    <item>
      <title>Prometheus 快速入门</title>
      <link>https://note.lican.site/posts/posts/prometheus/2020-05-16-startup/</link>
      <pubDate>Sat, 16 May 2020 12:05:58 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/prometheus/2020-05-16-startup/</guid>
      <description>&lt;p&gt;一般我们说 Prometheus，有两种理解，我们平时需要注意识别的，其含义有两种，一是指的 Prometheus 自身，是一个时序数据库；另外一种是指 Prometheus 生态圈，指的是是整体的监控报警的生态圈和解决方案（Prometheus+Grafana+Alertmanager）。&lt;/p&gt;&#xA;&lt;p&gt;Prometheus 在 2016年加入了 CNCF（Cloud Native Computing Foundation），是继 Kubernetes 之后的第二个托管项目，目前已经毕业，其主要的特点如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;多维度的数据模型：由指标名称和键/值对标签标识的时间序列数据来组成多维的数据模型。&lt;/li&gt;&#xA;&lt;li&gt;灵活的查询语言：在 Prometheus 中使用强大的查询语言 PromSQL 来进行查询。&lt;/li&gt;&#xA;&lt;li&gt;不依赖分布式存储，Prometheus 单个节点也可以直接工作，支持本地存储（TSDB）和远程存储的模式。&lt;/li&gt;&#xA;&lt;li&gt;服务端采集数据：Prometheus 基于 HTTP pull 方式去对不同的端采集时间序列数据。&lt;/li&gt;&#xA;&lt;li&gt;客户端主动推送：支持通过 PushGateway 组件主动推送时间序列数据。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;prometheus-生态组件&#34;&gt;Prometheus 生态组件&lt;/h2&gt;&#xA;&lt;p&gt;Prometheus 生态由多个组件共同组成，其中许多组件是可根据实际情况选择的，并且绝大部分由 Go 语言编写，在部署和构建上比较方便，如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Prometheus Server：&lt;a href=&#34;https://github.com/prometheus/prometheus&#34;&gt;Prometheus 服务端&lt;/a&gt;，用于收集指标和存储时间序列数据，并提供一系列的查询和设置接口。&lt;/li&gt;&#xA;&lt;li&gt;Client Libraries：&lt;a href=&#34;https://prometheus.io/docs/instrumenting/clientlibs/&#34;&gt;客户端库&lt;/a&gt;，用于帮助需要监控采集的服务暴露 metrics handler 给 Prometheus server。例如像 &lt;a href=&#34;https://github.com/prometheus/client_golang/blob/master/examples/simple/main.go&#34;&gt;例子&lt;/a&gt; 中直接调用 promhttp 暴露了一个 metrics 接口。&lt;/li&gt;&#xA;&lt;li&gt;Push Gateway：推送网关，Prometheus 服务端仅支持 HTTP pull 的采集方式，而有一些指存在的时间短，Prometheus 来 pull 前就结束了。又或是该类指标，就是要客户端自行上报的，这时候就可以采用 Push Gateway 的方式，客户端将指标 push 到 Push Gateway，再由 Prometheus Server 从 Pushgateway 上 pull。&lt;/li&gt;&#xA;&lt;li&gt;Exporters：用于暴露已有的第三方服务（HAProxy，StatsD，Graphite）的 metrics 给 Prometheus Server。&lt;/li&gt;&#xA;&lt;li&gt;Alertmanager：用于处理告警，从 Prometheus server 端接收到 alerts 后，会进行去重，分组，然后路由到对应的Receiver，发出报警。&lt;/li&gt;&#xA;&lt;li&gt;Support Tools：各种支持工具。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;prometheus-整体流程图&#34;&gt;Prometheus 整体流程图&lt;/h2&gt;&#xA;&lt;p&gt;Prometheus 的整体架构和生态组件组成，如下图所示：&lt;/p&gt;</description>
    </item>
    <item>
      <title>使用 Go 程序调用 Kubernetes API</title>
      <link>https://note.lican.site/posts/posts/kubernetes/2020-05-10-api/</link>
      <pubDate>Sun, 10 May 2020 21:20:26 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/kubernetes/2020-05-10-api/</guid>
      <description>&lt;p&gt;在前面的章节中，我们介绍了快速部署 Kubernetes 和应用程序的方法，接下来在本章节中我们将对 Kubernetes 的 API 进行了解，并且进行调用，这是开发人员最关注的一环之一。&lt;/p&gt;&#xA;&lt;p&gt;因为不论是 DevOps、基础架构，又或是自愈，都需要与 Kubernetes API 直接/间接接触，因此即使在你不懂 Kubernetes 的情况下，Kubernetes API 的知识点仍然属于必知必会，API 总得会调。&lt;/p&gt;&#xA;&lt;h2 id=&#34;查看-kubernetes-api&#34;&gt;查看 Kubernetes API&lt;/h2&gt;&#xA;&lt;h3 id=&#34;kube-apiserver-架构图&#34;&gt;kube-apiserver 架构图&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://d33wubrfki0l68.cloudfront.net/7016517375d10c702489167e704dcb99e570df85/7bb53/images/docs/components-of-kubernetes.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;（图来自 kubernetes.io）&lt;/p&gt;&#xA;&lt;p&gt;在 Kubernetes 的架构中，由 kube-apiserver 组件在主节点上提供 Kubernetes API 服务，kube-apiserver 是 Kubernetes 所有控制的前端，对外提供大量的 RESTful API。&lt;/p&gt;&#xA;&lt;p&gt;最常见的就是 kubelet 命令，实际上也是在调用 kube-apiserver 所提供的的 API。&lt;/p&gt;&#xA;&lt;h3 id=&#34;访问-api-和查看列表&#34;&gt;访问 API 和查看列表&lt;/h3&gt;&#xA;&lt;p&gt;在了解 Kubernetes 的基本架构和提供 API 的方式后，接下来我们需要知道 Kubernetes 到底提供了哪些 API。为了方便调试，首先我们需要在本地运行 &lt;code&gt;kubectl proxy&lt;/code&gt; 命令，kube-apiserver 就会在本地的 8001 端口上进行监听，也就是提供了一个 Kubernetes API 服务的 HTTP 代理。&lt;/p&gt;&#xA;&lt;p&gt;这个时候我们可以访问：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ curl http://localhost:8001/api/v1/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看所提供的对应 API‘s：&lt;/p&gt;</description>
    </item>
    <item>
      <title>在 Kubernetes 中部署应用程序</title>
      <link>https://note.lican.site/posts/posts/kubernetes/2020-05-03-deployment/</link>
      <pubDate>Sun, 03 May 2020 11:05:00 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/kubernetes/2020-05-03-deployment/</guid>
      <description>&lt;p&gt;在完成了本地 Kubernetes 的快速搭建（基于 Docker）后，我们已经可以正式的使用它了。对于我们平时最常见的需求，那就是往 Kubernetes 里部署应用程序，如果你没有看过 Kubernetes 相关的知识，这时候你可能会六神无主，但问题不大，我们就可以使用最经典的 Nginx 来小试身手。&lt;/p&gt;&#xA;&lt;h2 id=&#34;创建-deployment&#34;&gt;创建 Deployment&lt;/h2&gt;&#xA;&lt;p&gt;创建 nginx-deployment.yaml 文件：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;apps/v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deployment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx-deployment&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;replicas&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;selector&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;matchLabels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;template&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;labels&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;app&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#f92672&#34;&gt;containers&lt;/span&gt;:&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;image&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;nginx:1.18.0&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;应用 nginx-deployment.yaml 文件：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl apply -f nginx-deployment.yaml&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;deployment.apps/nginx-deployment created&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;查看运行状态&#34;&gt;查看运行状态&lt;/h2&gt;&#xA;&lt;p&gt;查看 Pod 运行情况：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get pods&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME                               READY   STATUS    RESTARTS   AGE&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nginx-deployment-9fbc65d67-9j68x   1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          1m&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nginx-deployment-9fbc65d67-nwbhj   1/1     Running   &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;          1m&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;查看 Deployment 部署情况：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ kubectl get deployment&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NAME               READY   UP-TO-DATE   AVAILABLE   AGE&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nginx-deployment   2/2     &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;            &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;           29m&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们也可以通过 describe 命令进行查看&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes 本地快速启动（基于 Docker）</title>
      <link>https://note.lican.site/posts/posts/kubernetes/2020-05-01-install/</link>
      <pubDate>Fri, 01 May 2020 11:25:52 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/kubernetes/2020-05-01-install/</guid>
      <description>&lt;p&gt;Kubernetes 在容器编排大战结束后已经在云原生中占据了明确的一席，最近几年越来越火热，目前搜索趋势：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/2583d073cc05df561c735564bb3e9e81.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Kubernetes 的热度很明显是不断地在上涨，因此学习和使用 Kubernetes 是一件相对正确的事，同时公司大多都在往容器化上接近，在拥抱 Kubernetes，所以我们所开发的应用也总是跑在容器环境中。更甚的是，需要对接 Kubernetes API 来做一些功能的开发。&lt;/p&gt;&#xA;&lt;p&gt;这个时候，我们就需要一个 Kubernetes 环境来进行开发和调试，但你准备开始时，又遇到了一个问题，虽然在 2020 年的现在，Kubernetes 的安装已经有了极大的简化，教程也满地跑，但 Kubernetes 的安装和运行依然有一定的要求，像我，就遇到了如下问题：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/9ee9dd19241bfc9099603abcc455787d.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;显然，我的小水管 Mac 承受不起，但是又需要对 Kubernetes 进行学习和使用，除了买云服务器，又或是再在台式机上搭虚拟机，还有没有什么办法呢。&lt;/p&gt;&#xA;&lt;p&gt;非运维开发的情况下，入门级中最简单的方式就是采用 Docker 所提供的 Kubernetes 支持。&lt;/p&gt;&#xA;&lt;h2 id=&#34;docker-for-macwindows-with-kubernetes&#34;&gt;Docker for Mac/Windows with Kubernetes&lt;/h2&gt;&#xA;&lt;p&gt;Docker 在 17.12.ce 起就提供了 Mac 版本的 &lt;a href=&#34;https://www.docker.com/blog/docker-mac-kubernetes/&#34;&gt;Kubernetes Beta&lt;/a&gt; 支持，在初始使用上来说非常的方便。首先我们检查 Docker 的版本，点击 Docker -&amp;gt; Check for Updates 确保你的 Docker 在最新版本。&lt;/p&gt;&#xA;&lt;h2 id=&#34;快速安装-kubernetes&#34;&gt;快速安装 Kubernetes&lt;/h2&gt;&#xA;&lt;p&gt;在升级完成后，我们可以点击 Docker -&amp;gt; Preferences -&amp;gt; Kubernetes，如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/85e953f790c6b6955aa307445a8cf67a.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;你会发现存在三个选项，分别是：Enable Kubernete、Deploy Docker Stacks to Kubernetes by default、Show system containers (advanced)。&lt;/p&gt;</description>
    </item>
    <item>
      <title>2020年下半年：读书清单</title>
      <link>https://note.lican.site/posts/posts/reading/2020-04-24-book/</link>
      <pubDate>Fri, 24 Apr 2020 22:00:45 +0800</pubDate>
      <guid>https://note.lican.site/posts/posts/reading/2020-04-24-book/</guid>
      <description>&lt;p&gt;2020 年的上半年因为一些事情耽搁了整体的进程，不过最近也快要到 Deadline 了，因此又愉快的能空出手了。&lt;/p&gt;&#xA;&lt;p&gt;回顾这几年在个人技能上，我随着公司的大泥球应用再到微服务化的飞速发展，经历了很多，突破了更多，有了不少新的感悟。因此今年打算再修修内功，认识一下自己的弱小，所以读书清单会比较偏基础方向，如下：&lt;/p&gt;&#xA;&lt;h2 id=&#34;必看&#34;&gt;必看&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;《图解 TCP/IP》&lt;/li&gt;&#xA;&lt;li&gt;《TCP/IP 详解 卷1：协议》&lt;/li&gt;&#xA;&lt;li&gt;《深入理解计算机系统》&lt;/li&gt;&#xA;&lt;li&gt;《大话数据结构》&lt;/li&gt;&#xA;&lt;li&gt;《算法（第4版）》&lt;/li&gt;&#xA;&lt;li&gt;《剑指 Offer》&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.bilibili.com/video/BV1js411b7vg&#34;&gt;《操作系统_清华大学》&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;可选&#34;&gt;可选&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;《Unix 环境高级编程（第3版）》&lt;/li&gt;&#xA;&lt;li&gt;《SRE Google 运维解密》：进行中，已经了看了不少。&lt;/li&gt;&#xA;&lt;li&gt;《Google 工作法》：进行中，已经了看了不少。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;所有的目标都需要有一个验收的标准和奖罚，否则所谓的目标意义不会特别大。我想，&lt;strong&gt;验收标准就是 &lt;a href=&#34;https://github.com/eddycjy/reread-cs-notes&#34;&gt;《重读 CS》&lt;/a&gt; 的基本成型&lt;/strong&gt;，其它不在该集合类的属于第二梯队，考虑释出读书笔记。&lt;/p&gt;&#xA;&lt;p&gt;惩罚的话，发红包还是送书呢，先想想。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go Modules 终极入门</title>
      <link>https://note.lican.site/posts/posts/go/go-moduels/2020-02-28-go-modules/</link>
      <pubDate>Fri, 28 Feb 2020 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-moduels/2020-02-28-go-modules/</guid>
      <description>&lt;p&gt;Go modules 是 Go 语言中正式官宣的项目依赖解决方案，Go modules（前身为vgo）于 Go1.11 正式发布，在 Go1.14 已经准备好，并且可以用在生产上（ready for production）了，Go官方也鼓励所有用户从其他依赖项管理工具迁移到 Go modules。&lt;/p&gt;&#xA;&lt;p&gt;而 Go1.14，在近期也终于正式发布，Go 官方亲自 “喊” 你来用：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/243fb2cca64972b2f36827f59b26d840.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此在今天这篇文章中，我将给大家带来 Go modules 的 “终极入门”，欢迎大家一起共同探讨。&lt;/p&gt;&#xA;&lt;p&gt;Go modules 是 Go 语言中正式官宣的项目依赖管理工具，Go modules（前身为vgo）于 Go1.11 正式发布，在 Go1.14 已经准备好，并且可以用在生产上（ready for production）了，鼓励所有用户从其他依赖项管理工具迁移到 Go modules。&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是go-modules&#34;&gt;什么是Go Modules&lt;/h2&gt;&#xA;&lt;p&gt;Go modules 是 Go 语言的依赖解决方案，发布于 Go1.11，成长于 Go1.12，丰富于 Go1.13，正式于 Go1.14 推荐在生产上使用。&lt;/p&gt;&#xA;&lt;p&gt;Go moudles 目前集成在 Go 的工具链中，只要安装了 Go，自然而然也就可以使用 Go moudles 了，而 Go modules 的出现也解决了在 Go1.11 前的几个常见争议问题：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Go 语言长久以来的依赖管理问题。&lt;/li&gt;&#xA;&lt;li&gt;“淘汰”现有的 GOPATH 的使用模式。&lt;/li&gt;&#xA;&lt;li&gt;统一社区中的其它的依赖管理工具（提供迁移功能）。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;gopath的那些点点滴滴&#34;&gt;GOPATH的那些点点滴滴&lt;/h2&gt;&#xA;&lt;p&gt;我们有提到 Go modules 的解决的问题之一就是“淘汰”掉 GOPATH，但是 GOPATH 又是什么呢，为什么在 Go1.11 前就使用 GOPATH，而 Go1.11 后就开始逐步建议使用 Go modules，不再推荐 GOPATH 的模式了呢？&lt;/p&gt;</description>
    </item>
    <item>
      <title>干货满满的 Go Modules 和 goproxy.cn</title>
      <link>https://note.lican.site/posts/posts/go/go-moduels/2019-09-29-goproxy-cn/</link>
      <pubDate>Sun, 29 Sep 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/go-moduels/2019-09-29-goproxy-cn/</guid>
      <description>&lt;p&gt;大家好，我是一只普通的煎鱼，周四晚上很有幸邀请到 goproxy.cn 的作者 @盛傲飞（@aofei） 到 Go 夜读给我们进行第 61 期 《Go Modules、Go Module Proxy 和 goproxy.cn》的技术分享。&lt;/p&gt;&#xA;&lt;p&gt;本次 @盛傲飞 的夜读分享，是对 Go Modules 的一次很好的解读，比较贴近工程实践，我必然希望把这块的知识更多的分享给大家，因此有了今天本篇文章，同时大家也可以多关注 Go 夜读，每周会通过 zoom 在线直播的方式分享 Go 相关的技术话题，希望对大家有所帮助。&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;Go 1.11 推出的模块（Modules）为 Go 语言开发者打开了一扇新的大门，理想化的依赖管理解决方案使得 Go 语言朝着计算机编程史上的第一个依赖乌托邦（Deptopia）迈进。随着模块一起推出的还有模块代理协议（Module proxy protocol），通过这个协议我们可以实现 Go 模块代理（Go module proxy），也就是依赖镜像。&lt;/p&gt;&#xA;&lt;p&gt;Go 1.13 的发布为模块带来了大量的改进，所以模块的扶正就是这次 Go 1.13 发布中开发者能直接感觉到的最大变化。而问题在于，Go 1.13 中的 GOPROXY 环境变量拥有了一个在中国大陆无法访问到的默认值 &lt;code&gt;proxy.golang.org&lt;/code&gt;，经过大家在 golang/go#31755 中激烈的讨论（有些人甚至将话提上升到了“自由世界”的层次），最终 Go 核心团队仍然无法为中国开发者提供一个可在中国大陆访问的官方模块代理。&lt;/p&gt;&#xA;&lt;p&gt;为了今后中国的 Go 语言开发者能更好地进行开发，七牛云推出了非营利性项目 &lt;code&gt;goproxy.cn&lt;/code&gt;，其目标是为中国和世界上其他地方的 Gopher 们提供一个免费的、可靠的、持续在线的且经过 CDN 加速的模块代理。可以预见未来是属于模块化的，所以 Go 语言开发者能越早切入模块就能越早进入未来。&lt;/p&gt;&#xA;&lt;p&gt;如果说 Go 1.11 和 Go 1.12 时由于模块的不完善你不愿意切入，那么 Go 1.13 你则可以大胆地开始放心使用。本次分享将讨论如何使用模块和模块代理，以及在它们的使用中会常遇见的坑，还会讲解如何快速搭建自己的私有模块代理，并简单地介绍一下七牛云推出的 &lt;code&gt;goproxy.cn&lt;/code&gt; 以及它的出现对于中国 Go 语言开发者来说重要在何处。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 应用内存占用太多，让排查？（VSZ篇）</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-09-24-why-vsz-large/</link>
      <pubDate>Tue, 24 Sep 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-09-24-why-vsz-large/</guid>
      <description>&lt;p&gt;前段时间，某同学说某服务的容器因为超出内存限制，不断地重启，问我们是不是有内存泄露，赶紧排查，然后解决掉，省的出问题。我们大为震惊，赶紧查看监控+报警系统和性能分析，发现应用指标压根就不高，不像有泄露的样子。&lt;/p&gt;&#xA;&lt;p&gt;那么问题是出在哪里了呢，我们进入某个容器里查看了 &lt;code&gt;top&lt;/code&gt; 的系统指标，结果如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PID       VSZ    RSS   ... COMMAND&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;67459&lt;/span&gt;     2007m  136m  ... ./eddycjy-server&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;从结果上来看，也没什么大开销的东西，主要就一个 Go 进程，一看，某同学就说 VSZ 那么高，而某云上的容器内存指标居然恰好和 VSZ 的值相接近，因此某同学就怀疑是不是 VSZ 所导致的，觉得存在一定的关联关系。&lt;/p&gt;&#xA;&lt;p&gt;而从最终的结论上来讲，上述的表述是不全对的，那么在今天，本篇文章将&lt;strong&gt;主要围绕 Go 进程的 VSZ 来进行剖析&lt;/strong&gt;，看看到底它为什么那么 &amp;ldquo;高&amp;rdquo;，而在正式开始分析前，第一节为前置的补充知识，大家可按顺序阅读。&lt;/p&gt;&#xA;&lt;h2 id=&#34;基础知识&#34;&gt;基础知识&lt;/h2&gt;&#xA;&lt;h3 id=&#34;什么是-vsz&#34;&gt;什么是 VSZ&lt;/h3&gt;&#xA;&lt;p&gt;VSZ 是该进程所能使用的虚拟内存总大小，它包括进程可以访问的所有内存，其中包括了被换出的内存（Swap）、已分配但未使用的内存以及来自共享库的内存。&lt;/p&gt;&#xA;&lt;h3 id=&#34;为什么要虚拟内存&#34;&gt;为什么要虚拟内存&lt;/h3&gt;&#xA;&lt;p&gt;在前面我们有了解到 VSZ 其实就是该进程的虚拟内存总大小，那&lt;strong&gt;如果我们想了解 VSZ 的话，那我们得先了解 “为什么要虚拟内存？”&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;本质上来讲，在一个系统中的进程是与其他进程共享 CPU 和主存资源的，而在现代的操作系统中，多进程的使用非常的常见，那么如果太多的进程需要太多的内存，那么在没有虚拟内存的情况下，物理内存很可能会不够用，就会导致其中有些任务无法运行，更甚至会出现一些很奇怪的现象，例如 “某一个进程不小心写了另一个进程使用的内存”，就会造成内存破坏，因此虚拟内存是非常重要的一个媒介。&lt;/p&gt;&#xA;&lt;h3 id=&#34;虚拟内存包含了什么&#34;&gt;虚拟内存包含了什么&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/3062dec8cd187490adadbdbcf50c17d4.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;而虚拟内存，又分为内核虚拟内存和进程虚拟内存，每一个进程的虚拟内存都是独立的， 呈现如上图所示。&lt;/p&gt;&#xA;&lt;p&gt;这里也补充说明一下，在内核虚拟内存中，是包含了内核中的代码和数据结构，而内核虚拟内存中的某些区域会被映射到所有进程共享的物理页面中去，因此你会看到 ”内核虚拟内存“ 中实际上是包含了 ”物理内存“ 的，它们两者存在映射关系。而在应用场景上来讲，每个进程也会去共享内核的代码和全局数据结构，因此就会被映射到所有进程的物理页面中去。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/3ba1352075ace855104f4bd57752a2ad.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;虚拟内存的重要能力&#34;&gt;虚拟内存的重要能力&lt;/h3&gt;&#xA;&lt;p&gt;为了更有效地管理内存并且减少出错，现代系统提供了一种对主存的抽象概念，也就是今天的主角，叫做虚拟内存（VM），虚拟内存是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件交互的地方，它为每个进程提供了一个大的、一致的和私有的地址空间，虚拟内存提供了三个重要的能力：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;它将主存看成是一个存储在磁盘上的地址空间的高速缓存，在主存中只保存活动区域，并根据需要在磁盘和主存之间来回传送数据，通过这种方式，它高效地使用了主存。&lt;/li&gt;&#xA;&lt;li&gt;它为每个进程提供了一致的地址空间，从而简化了内存管理。&lt;/li&gt;&#xA;&lt;li&gt;它保护了每个进程的地址空间不被其他进程破坏。&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;小结&#34;&gt;小结&lt;/h3&gt;&#xA;&lt;p&gt;上面发散的可能比较多，简单来讲，对于本文我们重点关注这些知识点，如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;虚拟内存它是有各式各样内存交互的地方，它包含的不仅仅是 &amp;ldquo;自己&amp;rdquo;，&lt;strong&gt;而在本文中，我们只需要关注 VSZ，也就是进程虚拟内存，它包含了你的代码、数据、堆、栈段和共享库&lt;/strong&gt;。&lt;/li&gt;&#xA;&lt;li&gt;虚拟内存作为内存保护的工具，能够保证进程之间的内存空间独立，不受其他进程的影响，因此每一个进程的 VSZ 大小都不一样，互不影响。&lt;/li&gt;&#xA;&lt;li&gt;虚拟内存的存在，系统给各进程分配的内存之和是可以大于实际可用的物理内存的，因此你也会发现你进程的物理内存总是比虚拟内存低的多的多。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;排查问题&#34;&gt;排查问题&lt;/h2&gt;&#xA;&lt;p&gt;在了解了基础知识后，我们正式开始排查问题，第一步我们先编写一个测试程序，看看没有什么业务逻辑的 Go 程序，它初始的 VSZ 是怎么样的。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.13 defer 的性能是如何提高的</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-09-07-go1.13-defer/</link>
      <pubDate>Sat, 07 Sep 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-09-07-go1.13-defer/</guid>
      <description>&lt;p&gt;最近 Go1.13 终于发布了，其中一个值得关注的特性就是 &lt;strong&gt;defer 在大部分的场景下性能提升了30%&lt;/strong&gt;，但是官方并没有具体写是怎么提升的，这让大家非常的疑惑。而我因为之前写过&lt;a href=&#34;https://book.eddycjy.com/golang/defer/defer.html&#34;&gt;《深入理解 Go defer》&lt;/a&gt; 和 &lt;a href=&#34;https://book.eddycjy.com/golang/talk/defer-loss.html&#34;&gt;《Go defer 会有性能损耗，尽量不要用？》&lt;/a&gt; 这类文章，因此我挺感兴趣它是做了什么改变才能得到这样子的结果，所以今天和大家一起探索其中奥妙。&lt;/p&gt;&#xA;&lt;h2 id=&#34;一测试&#34;&gt;一、测试&lt;/h2&gt;&#xA;&lt;h3 id=&#34;go112&#34;&gt;Go1.12&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test -bench=. -benchmem -run=none&#xA;goos: darwin&#xA;goarch: amd64&#xA;pkg: github.com/EDDYCJY/awesomeDefer&#xA;BenchmarkDoDefer-4      &#x9;20000000&#x9;        91.4 ns/op&#x9;      48 B/op&#x9;       1 allocs/op&#xA;BenchmarkDoNotDefer-4   &#x9;30000000&#x9;        41.6 ns/op&#x9;      48 B/op&#x9;       1 allocs/op&#xA;PASS&#xA;ok  &#x9;github.com/EDDYCJY/awesomeDefer&#x9;3.234s&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;go113&#34;&gt;Go1.13&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test -bench=. -benchmem -run=none&#xA;goos: darwin&#xA;goarch: amd64&#xA;pkg: github.com/EDDYCJY/awesomeDefer&#xA;BenchmarkDoDefer-4      &#x9;15986062&#x9;        74.7 ns/op&#x9;      48 B/op&#x9;       1 allocs/op&#xA;BenchmarkDoNotDefer-4   &#x9;29231842&#x9;        40.3 ns/op&#x9;      48 B/op&#x9;       1 allocs/op&#xA;PASS&#xA;ok  &#x9;github.com/EDDYCJY/awesomeDefer&#x9;3.444s&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在开场，我先以不标准的测试基准验证了先前的测试用例，确确实实在这两个版本中，&lt;code&gt;defer&lt;/code&gt; 的性能得到了提高，但是看上去似乎不是百分百提高 30 %。&lt;/p&gt;</description>
    </item>
    <item>
      <title>用 GODEBUG 看 GC</title>
      <link>https://note.lican.site/posts/posts/go/tools/2019-09-02-godebug-gc/</link>
      <pubDate>Mon, 02 Sep 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/tools/2019-09-02-godebug-gc/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/b07f55c7fd136392763729b9782f7776.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是-gc&#34;&gt;什么是 GC&lt;/h2&gt;&#xA;&lt;p&gt;在计算机科学中，垃圾回收（GC）是一种自动管理内存的机制，垃圾回收器会去尝试回收程序不再使用的对象及其占用的内存。而最早 John McCarthy 在 1959 年左右发明了垃圾回收，以简化 Lisp 中的手动内存管理的机制（来自 wikipedia）。&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么要-gc&#34;&gt;为什么要 GC&lt;/h2&gt;&#xA;&lt;p&gt;手动管理内存挺麻烦，管错或者管漏内存也很糟糕，将会直接导致程序不稳定（持续泄露）甚至直接崩溃。&lt;/p&gt;&#xA;&lt;h2 id=&#34;gc-带来的问题&#34;&gt;GC 带来的问题&lt;/h2&gt;&#xA;&lt;p&gt;硬要说会带来什么问题的话，也就数大家最关注的 Stop The World（STW），STW 代指在执行某个垃圾回收算法的某个阶段时，需要将整个应用程序暂停去处理 GC 相关的工作事项。例如：&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;行为&lt;/th&gt;&#xA;          &lt;th&gt;会不会 STW&lt;/th&gt;&#xA;          &lt;th&gt;为什么&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;标记开始&lt;/td&gt;&#xA;          &lt;td&gt;会&lt;/td&gt;&#xA;          &lt;td&gt;在开始标记时，准备根对象的扫描，会打开写屏障（Write Barrier） 和 辅助GC（mutator assist），而回收器和应用程序是并发运行的，因此会暂停当前正在运行的所有 Goroutine。&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;并发标记中&lt;/td&gt;&#xA;          &lt;td&gt;不会&lt;/td&gt;&#xA;          &lt;td&gt;标记阶段，主要目的是标记堆内存中仍在使用的值。&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;标记结束&lt;/td&gt;&#xA;          &lt;td&gt;会&lt;/td&gt;&#xA;          &lt;td&gt;在完成标记任务后，将重新扫描部分根对象，这时候会禁用写屏障（Write Barrier）和辅助GC（mutator assist），而标记阶段和应用程序是并发运行的，所以在标记阶段可能会有新的对象产生，因此在重新扫描时需要进行 STW。&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h2 id=&#34;如何调整-gc-频率&#34;&gt;如何调整 GC 频率&lt;/h2&gt;&#xA;&lt;p&gt;可以通过 GOGC 变量设置初始垃圾收集器的目标百分比值，对比的规则为当新分配的数值与上一次收集后剩余的实时数值的比例达到设置的目标百分比时，就会触发 GC，默认值为 GOGC=100。如果将其设置为 GOGC=off 可以完全禁用垃圾回收器，要不试试？&lt;/p&gt;&#xA;&lt;p&gt;简单来讲就是，GOGC 的值设置的越大，GC 的频率越低，但每次最终所触发到 GC 的堆内存也会更大。&lt;/p&gt;&#xA;&lt;h2 id=&#34;各版本-gc-情况&#34;&gt;各版本 GC 情况&lt;/h2&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;版本&lt;/th&gt;&#xA;          &lt;th&gt;GC 算法&lt;/th&gt;&#xA;          &lt;th&gt;STW 时间&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.0&lt;/td&gt;&#xA;          &lt;td&gt;STW（强依赖 tcmalloc）&lt;/td&gt;&#xA;          &lt;td&gt;百ms到秒级别&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.3&lt;/td&gt;&#xA;          &lt;td&gt;Mark STW, Sweep 并行&lt;/td&gt;&#xA;          &lt;td&gt;百ms级别&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.5&lt;/td&gt;&#xA;          &lt;td&gt;三色标记法, 并发标记清除。同时运行时从 C 和少量汇编，改为 Go 和少量汇编实现&lt;/td&gt;&#xA;          &lt;td&gt;10-50ms级别&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.6&lt;/td&gt;&#xA;          &lt;td&gt;1.5 中一些与并发 GC 不协调的地方更改，集中式的 GC 协调协程，改为状态机实现&lt;/td&gt;&#xA;          &lt;td&gt;5ms级别&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.7&lt;/td&gt;&#xA;          &lt;td&gt;GC 时由 mark 栈收缩改为并发，span 对象分配机制由 freelist 改为 bitmap 模式，SSA引入&lt;/td&gt;&#xA;          &lt;td&gt;ms级别&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.8&lt;/td&gt;&#xA;          &lt;td&gt;混合写屏障（hybrid write barrier）, 消除 re-scanning stack&lt;/td&gt;&#xA;          &lt;td&gt;sub ms&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Go 1.12&lt;/td&gt;&#xA;          &lt;td&gt;Mark Termination 流程优化&lt;/td&gt;&#xA;          &lt;td&gt;sub ms, 但几乎减少一半&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;注：资料来源于 @boya 在深圳 Gopher Meetup 的分享。&lt;/p&gt;</description>
    </item>
    <item>
      <title>用 GODEBUG 看调度跟踪</title>
      <link>https://note.lican.site/posts/posts/go/tools/2019-08-19-godebug-sched/</link>
      <pubDate>Mon, 19 Aug 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/tools/2019-08-19-godebug-sched/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/b01c2ce25e34f80d499f0488d034b00b.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;让 Go 更强大的原因之一莫过于它的 GODEBUG 工具，GODEBUG 的设置可以让 Go 程序在运行时输出调试信息，可以根据你的要求很直观的看到你想要的调度器或垃圾回收等详细信息，并且还不需要加装其它的插件，非常方便，今天我们将先讲解 GODEBUG 的调度器相关内容，希望对你有所帮助。&lt;/p&gt;&#xA;&lt;p&gt;不过在开始前，没接触过的小伙伴得先补补如下前置知识，便于更好的了解调试器输出的信息内容。&lt;/p&gt;&#xA;&lt;h2 id=&#34;前置知识&#34;&gt;前置知识&lt;/h2&gt;&#xA;&lt;p&gt;Go scheduler 的主要功能是针对在处理器上运行的 OS 线程分发可运行的 Goroutine，而我们一提到调度器，就离不开三个经常被提到的缩写，分别是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;G：Goroutine，实际上我们每次调用 &lt;code&gt;go func&lt;/code&gt; 就是生成了一个 G。&lt;/li&gt;&#xA;&lt;li&gt;P：处理器，一般为处理器的核数，可以通过 &lt;code&gt;GOMAXPROCS&lt;/code&gt; 进行修改。&lt;/li&gt;&#xA;&lt;li&gt;M：OS 线程&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这三者交互实际来源于 Go 的 M: N 调度模型，也就是 M 必须与 P 进行绑定，然后不断地在 M 上循环寻找可运行的 G 来执行相应的任务，如果想具体了解可以详细阅读 &lt;a href=&#34;https://speakerdeck.com/retervision/go-runtime-scheduler&#34;&gt;《Go Runtime Scheduler》&lt;/a&gt;，我们抽其中的工作流程图进行简单分析，如下:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/fb4c6c92c93af3bc2dfc4f13dc167cdf.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;当我们执行 &lt;code&gt;go func()&lt;/code&gt; 时，实际上就是创建一个全新的 Goroutine，我们称它为 G。&lt;/li&gt;&#xA;&lt;li&gt;新创建的 G 会被放入 P 的本地队列（Local Queue）或全局队列（Global Queue）中，准备下一步的动作。&lt;/li&gt;&#xA;&lt;li&gt;唤醒或创建 M 以便执行 G。&lt;/li&gt;&#xA;&lt;li&gt;不断地进行事件循环&lt;/li&gt;&#xA;&lt;li&gt;寻找在可用状态下的 G 进行执行任务&lt;/li&gt;&#xA;&lt;li&gt;清除后，重新进入事件循环&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;而在描述中有提到全局和本地这两类队列，其实在功能上来讲都是用于存放正在等待运行的 G，但是不同点在于，本地队列有数量限制，不允许超过 256 个。并且在新建 G 时，会优先选择 P 的本地队列，如果本地队列满了，则将 P 的本地队列的一半的 G 移动到全局队列，这其实可以理解为调度资源的共享和再平衡。&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 大杀器之跟踪剖析 trace</title>
      <link>https://note.lican.site/posts/posts/go/tools/2019-07-12-go-tool-trace/</link>
      <pubDate>Fri, 12 Jul 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/tools/2019-07-12-go-tool-trace/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/15/1x1phF.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;在 Go 中有许许多多的分析工具，在之前我有写过一篇 《Golang 大杀器之性能剖析 PProf》 来介绍 PProf，如果有小伙伴感兴趣可以去我博客看看。&lt;/p&gt;&#xA;&lt;p&gt;但单单使用 PProf 有时候不一定足够完整，因为在真实的程序中还包含许多的隐藏动作，例如 Goroutine 在执行时会做哪些操作？执行/阻塞了多长时间？在什么时候阻止？在哪里被阻止的？谁又锁/解锁了它们？GC 是怎么影响到 Goroutine 的执行的？这些东西用 PProf 是很难分析出来的，但如果你又想知道上述的答案的话，你可以用本文的主角 &lt;code&gt;go tool trace&lt;/code&gt; 来打开新世界的大门。目录如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/15/1x1P1J.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;初步了解&#34;&gt;初步了解&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime/trace&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;trace&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Start&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stderr&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;trace&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stop&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ch&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;生成跟踪文件：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go 2&amp;gt; trace.out&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;启动可视化界面：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go tool trace trace.out&#xA;2019/06/22 16:14:52 Parsing trace...&#xA;2019/06/22 16:14:52 Splitting trace...&#xA;2019/06/22 16:14:52 Opening browser. Trace viewer is listening on http://127.0.0.1:57321&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;查看可视化界面：&lt;/p&gt;</description>
    </item>
    <item>
      <title>从实践到原理，带你参透 gRPC</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-06-29-talking-grpc/</link>
      <pubDate>Sat, 29 Jun 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-06-29-talking-grpc/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/4a47a0db6e60853dedfcfdf08a5ca249.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;gRPC 在 Go 语言中大放异彩，越来越多的小伙伴在使用，最近也在公司安利了一波，希望这一篇文章能带你一览 gRPC 的巧妙之处，本文篇幅比较长，请做好阅读准备。本文目录如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/156005c5baf40ff51a327f1c34f2975b.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;简述&#34;&gt;简述&lt;/h2&gt;&#xA;&lt;p&gt;gRPC 是一个高性能、开源和通用的 RPC 框架，面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本，分别是：grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。&lt;/p&gt;&#xA;&lt;p&gt;gRPC 基于 HTTP/2 标准设计，带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特性。这些特性使得其在移动设备上表现更好，更省电和节省空间占用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;调用模型&#34;&gt;调用模型&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/10fb15c77258a991b0028080a64fb42d.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;1、客户端（gRPC Stub）调用 A 方法，发起 RPC 调用。&lt;/p&gt;&#xA;&lt;p&gt;2、对请求信息使用 Protobuf 进行对象序列化压缩（IDL）。&lt;/p&gt;&#xA;&lt;p&gt;3、服务端（gRPC Server）接收到请求后，解码请求体，进行业务逻辑处理并返回。&lt;/p&gt;&#xA;&lt;p&gt;4、对响应结果使用 Protobuf 进行对象序列化压缩（IDL）。&lt;/p&gt;&#xA;&lt;p&gt;5、客户端接受到服务端响应，解码请求体。回调被调用的 A 方法，唤醒正在等待响应（阻塞）的客户端调用并返回响应结果。&lt;/p&gt;&#xA;&lt;h2 id=&#34;调用方式&#34;&gt;调用方式&lt;/h2&gt;&#xA;&lt;h3 id=&#34;一unary-rpc一元-rpc&#34;&gt;一、Unary RPC：一元 RPC&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/09dd8c2662b96ce14928333f055c5580.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;server&#34;&gt;Server&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SearchService&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SearchService&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Search&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SearchRequest&lt;/span&gt;) (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SearchResponse&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SearchResponse&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Response&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetRequest&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34; Server&amp;#34;&lt;/span&gt;}, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PORT&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;9001&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grpc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewServer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RegisterSearchServiceServer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;SearchService&lt;/span&gt;{})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;lis&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;net&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Listen&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tcp&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PORT&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;server&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Serve&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;lis&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;创建 gRPC Server 对象，你可以理解为它是 Server 端的抽象对象。&lt;/li&gt;&#xA;&lt;li&gt;将 SearchService（其包含需要被调用的服务端接口）注册到 gRPC Server。 的内部注册中心。这样可以在接受到请求时，通过内部的 “服务发现”，发现该服务端接口并转接进行逻辑处理。&lt;/li&gt;&#xA;&lt;li&gt;创建 Listen，监听 TCP 端口。&lt;/li&gt;&#xA;&lt;li&gt;gRPC Server 开始 lis.Accept，直到 Stop 或 GracefulStop。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;client&#34;&gt;Client&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;grpc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Dial&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;PORT&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;grpc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;WithInsecure&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewSearchServiceClient&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;conn&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;resp&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;client&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Search&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Background&lt;/span&gt;(), &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;pb&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SearchRequest&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;Request&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gRPC&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    })&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;创建与给定目标（服务端）的连接句柄。&lt;/li&gt;&#xA;&lt;li&gt;创建 SearchService 的客户端对象。&lt;/li&gt;&#xA;&lt;li&gt;发送 RPC 请求，等待同步响应，得到回调后返回响应结果。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;二server-side-streaming-rpc服务端流式-rpc&#34;&gt;二、Server-side streaming RPC：服务端流式 RPC&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/8266e4bfeda1bd42d8f9794eb4ea0a13.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载四」gRPC&#43;gRPC Gateway 能不能不用证书？</title>
      <link>https://note.lican.site/posts/posts/go/grpc-gateway/2019-06-22-grpc-gateway-tls/</link>
      <pubDate>Sat, 22 Jun 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc-gateway/2019-06-22-grpc-gateway-tls/</guid>
      <description>&lt;p&gt;如果你以前有涉猎过 gRPC+gRPC Gateway 这两个组件，你肯定会遇到这个问题，就是 &lt;strong&gt;“为什么非得开 TLS，才能够实现同端口双流量，能不能不开？”&lt;/strong&gt; 又或是 &lt;strong&gt;“我不想用证书就实现这些功能，行不行？”&lt;/strong&gt;。我被无数的人问过无数次这些问题，也说服过很多人，但说服归说服，不代表放弃。前年不行，不代表今年不行，在今天我希望分享来龙去脉和具体的实现方式给你。&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3dLBAx.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;过去&#34;&gt;过去&lt;/h2&gt;&#xA;&lt;h3 id=&#34;为什么-h2-不行&#34;&gt;为什么 h2 不行&lt;/h3&gt;&#xA;&lt;p&gt;因为 &lt;code&gt;net/http2&lt;/code&gt; 仅支持 &amp;ldquo;h2&amp;rdquo; 标识，而 &amp;ldquo;h2&amp;rdquo; 标识 HTTP/2 必须使用传输层安全性（TLS）的协议，此标识符用于 TLS 应用层协议协商字段以及识别 HTTP/2 over TLS。&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，也就 &lt;code&gt;net/http2&lt;/code&gt; 必须使用 TLS 来交互。通俗来讲就要用证书，那么理所当然，也就无法支持非 TLS 的情况了。&lt;/p&gt;&#xA;&lt;h3 id=&#34;寻找-h2c&#34;&gt;寻找 h2c&lt;/h3&gt;&#xA;&lt;p&gt;那这条路不行，我们再想想别的路？那就是 HTTP/2 规范中的 &amp;ldquo;h2c&amp;rdquo; 标识了，&amp;ldquo;h2c&amp;rdquo; 标识允许通过明文 TCP 运行 HTTP/2 的协议，此标识符用于 HTTP/1.1 升级标头字段以及标识 HTTP/2 over TCP。&lt;/p&gt;&#xA;&lt;p&gt;但是这条路，早在 2015 年就已经有在 &lt;a href=&#34;https://github.com/golang/go/issues/13128#issuecomment-153193762&#34;&gt;issue&lt;/a&gt; 中进行讨论，当时 @bradfitz 明确表示 “不打算支持 h2c，对仅支持 TLS 的情况非常满意，一年后再问我一次”，原文回复如下：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;We do not plan to support h2c. I don&amp;rsquo;t want to receive bug reports from users who get bitten by transparent proxies messing with h2c. Also, until there&amp;rsquo;s widespread browser support, it&amp;rsquo;s not interesting. I am also not interested in being the chicken or the egg to get browser support going. I&amp;rsquo;m very happy with the TLS-only situation, and things like &lt;a href=&#34;https://LetsEncrypt.org/&#34;&gt;https://LetsEncrypt.org/&lt;/a&gt; will make TLS much easier (and automatic) soon.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go1.12 defer 会有性能损耗，尽量不要用？</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-06-16-defer-loss/</link>
      <pubDate>Sun, 16 Jun 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-06-16-defer-loss/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wuUYV.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;上个月在 @polaris @轩脉刃 的全栈技术群里看到一个小伙伴问 &lt;strong&gt;“说 defer 在栈退出时执行，会有性能损耗，尽量不要用，这个怎么解？”&lt;/strong&gt;。&lt;/p&gt;&#xA;&lt;p&gt;恰好前段时间写了一篇 &lt;a href=&#34;https://segmentfault.com/a/1190000019303572&#34;&gt;《深入理解 Go defer》&lt;/a&gt; 去详细剖析 &lt;code&gt;defer&lt;/code&gt; 关键字。那么这一次简单结合前文对这个问题进行探讨一波，希望对你有所帮助，但在此之前希望你花几分钟，自己思考一下答案，再继续往下看。&lt;/p&gt;&#xA;&lt;h2 id=&#34;测试&#34;&gt;测试&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DoDefer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DoNotDefer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;key&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;基准测试：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkDoDefer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;DoDefer&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://github.com/EDDYCJY/blog&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkDoNotDefer&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;DoNotDefer&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;煎鱼&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://github.com/EDDYCJY/blog&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go test -bench=. -benchmem -run=none&#xA;goos: darwin&#xA;goarch: amd64&#xA;pkg: github.com/EDDYCJY/awesomeDefer&#xA;BenchmarkDoDefer-4          20000000            91.4 ns/op        48 B/op          1 allocs/op&#xA;BenchmarkDoNotDefer-4       30000000            41.6 ns/op        48 B/op          1 allocs/op&#xA;PASS&#xA;ok      github.com/EDDYCJY/awesomeDefer 3.234s&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从结果上来，使用 &lt;code&gt;defer&lt;/code&gt; 后的函数开销确实比没使用高了不少，这损耗用到哪里去了呢？&lt;/p&gt;</description>
    </item>
    <item>
      <title>深入理解 Go defer</title>
      <link>https://note.lican.site/posts/posts/go/defer/2019-05-27-defer/</link>
      <pubDate>Mon, 27 May 2019 12:30:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/defer/2019-05-27-defer/</guid>
      <description>&lt;p&gt;在上一章节 《深入理解 Go panic and recover》中，我们发现了 &lt;code&gt;defer&lt;/code&gt; 与其关联性极大，还是觉得非常有必要深入一下。希望通过本章节大家可以对 &lt;code&gt;defer&lt;/code&gt; 关键字有一个深刻的理解，那么我们开始吧。你先等等，请排好队，我们这儿采取后进先出 LIFO 的出站方式&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;特性&#34;&gt;特性&lt;/h2&gt;&#xA;&lt;p&gt;我们简单的过一下 &lt;code&gt;defer&lt;/code&gt; 关键字的基础使用，让大家先有一个基础的认知&lt;/p&gt;&#xA;&lt;h3 id=&#34;一延迟调用&#34;&gt;一、延迟调用&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY.&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;end.&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go&#xA;2019/05/19 21:15:02 end.&#xA;2019/05/19 21:15:02 EDDYCJY.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;二后进先出&#34;&gt;二、后进先出&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Itoa&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;end.&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go&#xA;2019/05/19 21:19:17 end.&#xA;2019/05/19 21:19:17 EDDYCJY5.&#xA;2019/05/19 21:19:17 EDDYCJY4.&#xA;2019/05/19 21:19:17 EDDYCJY3.&#xA;2019/05/19 21:19:17 EDDYCJY2.&#xA;2019/05/19 21:19:17 EDDYCJY1.&#xA;2019/05/19 21:19:17 EDDYCJY0.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;三运行时间点&#34;&gt;三、运行时间点&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9; &lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;defer.EDDYCJY.&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;main.EDDYCJY.&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>深入理解 Go panic and recover</title>
      <link>https://note.lican.site/posts/posts/go/panic/2019-05-21-panic-and-recover/</link>
      <pubDate>Tue, 21 May 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/panic/2019-05-21-panic-and-recover/</guid>
      <description>&lt;p&gt;作为一个 gophper，我相信你对于 &lt;code&gt;panic&lt;/code&gt; 和 &lt;code&gt;recover&lt;/code&gt; 肯定不陌生，但是你有没有想过。当我们执行了这两条语句之后。底层到底发生了什么事呢？前几天和同事刚好聊到相关的话题，发现其实大家对这块理解还是比较模糊的。希望这篇文章能够从更深入的角度告诉你为什么，它到底做了什么事？&lt;/p&gt;&#xA;&lt;h2 id=&#34;思考&#34;&gt;思考&lt;/h2&gt;&#xA;&lt;h3 id=&#34;一为什么会中止运行&#34;&gt;一、为什么会中止运行&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;&#x9;panic(&amp;#34;EDDYCJY.&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go&#xA;panic: EDDYCJY.&#xA;&#xA;goroutine 1 [running]:&#xA;main.main()&#xA;&#x9;/Users/eddycjy/go/src/github.com/EDDYCJY/awesomeProject/main.go:4 +0x39&#xA;exit status 2&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请思考一下，为什么执行 &lt;code&gt;panic&lt;/code&gt; 后会导致应用程序运行中止？（而不是单单说执行了 &lt;code&gt;panic&lt;/code&gt; 所以就结束了这么含糊）&lt;/p&gt;&#xA;&lt;h3 id=&#34;二为什么不会中止运行&#34;&gt;二、为什么不会中止运行&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;&#x9;defer func() {&#xA;&#x9;&#x9;if err := recover(); err != nil {&#xA;&#x9;&#x9;&#x9;log.Printf(&amp;#34;recover: %v&amp;#34;, err)&#xA;&#x9;&#x9;}&#xA;&#x9;}()&#xA;&#xA;&#x9;panic(&amp;#34;EDDYCJY.&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go &#xA;2019/05/11 23:39:47 recover: EDDYCJY.&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;请思考一下，为什么加上 &lt;code&gt;defer&lt;/code&gt; + &lt;code&gt;recover&lt;/code&gt; 组合就可以保护应用程序？&lt;/p&gt;&#xA;&lt;h3 id=&#34;三不设置-defer-行不&#34;&gt;三、不设置 defer 行不&lt;/h3&gt;&#xA;&lt;p&gt;上面问题二是 &lt;code&gt;defer&lt;/code&gt; + &lt;code&gt;recover&lt;/code&gt; 组合，那我去掉 &lt;code&gt;defer&lt;/code&gt; 是不是也可以呢？如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>我要在栈上。不，你应该在堆上</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-05-20-stack-heap/</link>
      <pubDate>Mon, 20 May 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-05-20-stack-heap/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wK39K.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们在写代码的时候，有时候会想这个变量到底分配到哪里了？这时候可能会有人说，在栈上，在堆上。信我准没错&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;但从结果上来讲你还是一知半解，这可不行，万一被人懵了呢。今天我们一起来深挖下 Go 在这块的奥妙，自己动手丰衣足食&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Avatar&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetUserInfo&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;User&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;ID&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;13746731&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Avatar&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://avatars0.githubusercontent.com/u/13746731&amp;#34;&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;GetUserInfo&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;开局就是一把问号，带着问题进行学习。请问 main 调用 &lt;code&gt;GetUserInfo&lt;/code&gt; 后返回的 &lt;code&gt;&amp;amp;User{...}&lt;/code&gt;。这个变量是分配到栈上了呢，还是分配到堆上了？&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是堆栈&#34;&gt;什么是堆/栈&lt;/h2&gt;&#xA;&lt;p&gt;在这里并不打算详细介绍堆栈，仅简单介绍本文所需的基础知识。如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;堆（Heap）：一般来讲是人为手动进行管理，手动申请、分配、释放。一般所涉及的内存大小并不定，一般会存放较大的对象。另外其分配相对慢，涉及到的指令动作也相对多&lt;/li&gt;&#xA;&lt;li&gt;栈（Stack）：由编译器进行管理，自动申请、分配、释放。一般不会太大，我们常见的函数参数（不同平台允许存放的数量不同），局部变量等等都会存放在栈上&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;今天我们介绍的 Go 语言，它的堆栈分配是通过 Compiler 进行分析，GC 去管理的，而对其的分析选择动作就是今天探讨的重点&lt;/p&gt;&#xA;&lt;h2 id=&#34;什么是逃逸分析&#34;&gt;什么是逃逸分析&lt;/h2&gt;&#xA;&lt;p&gt;在编译程序优化理论中，逃逸分析是一种确定指针动态范围的方法，简单来说就是分析在程序的哪些地方可以访问到该指针&lt;/p&gt;&#xA;&lt;p&gt;通俗地讲，逃逸分析就是确定一个变量要放堆上还是栈上，规则如下：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;是否有在其他地方（非局部）被引用。只要&lt;strong&gt;有可能&lt;/strong&gt;被引用了，那么它&lt;strong&gt;一定&lt;/strong&gt;分配到堆上。否则分配到栈上&lt;/li&gt;&#xA;&lt;li&gt;即使没有被外部引用，但对象过大，无法存放在栈区上。依然有可能分配到堆上&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;对此你可以理解为，逃逸分析是编译器用于决定变量分配到堆上还是栈上的一种行为&lt;/p&gt;&#xA;&lt;h2 id=&#34;在什么阶段确立逃逸&#34;&gt;在什么阶段确立逃逸&lt;/h2&gt;&#xA;&lt;p&gt;在编译阶段确立逃逸，注意并不是在运行时&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么需要逃逸&#34;&gt;为什么需要逃逸&lt;/h2&gt;&#xA;&lt;p&gt;这个问题我们可以反过来想，如果变量都分配到堆上了会出现什么事情？例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;垃圾回收（GC）的压力不断增大&lt;/li&gt;&#xA;&lt;li&gt;申请、分配、回收内存的系统开销增大（相对于栈）&lt;/li&gt;&#xA;&lt;li&gt;动态分配产生一定量的内存碎片&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;其实总的来说，就是频繁申请、分配堆内存是有一定 “代价” 的。会影响应用程序运行的效率，间接影响到整体系统。因此 “按需分配” 最大限度的灵活利用资源，才是正确的治理之道。这就是为什么需要逃逸分析的原因，你觉得呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;怎么确定是否逃逸&#34;&gt;怎么确定是否逃逸&lt;/h2&gt;&#xA;&lt;p&gt;第一，通过编译器命令，就可以看到详细的逃逸分析过程。而指令集 &lt;code&gt;-gcflags&lt;/code&gt; 用于将标识参数传递给 Go 编译器，涉及如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;-m&lt;/code&gt; 会打印出逃逸分析的优化策略，实际上最多总共可以用 4 个 &lt;code&gt;-m&lt;/code&gt;，但是信息量较大，一般用 1 个就可以了&lt;/p&gt;</description>
    </item>
    <item>
      <title>为什么遍历 Go map 是无序的</title>
      <link>https://note.lican.site/posts/posts/go/map/2019-04-07-why-map-no-order/</link>
      <pubDate>Sun, 07 Apr 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map/2019-04-07-why-map-no-order/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://wx2.sinaimg.cn/large/006fVPCvly1g1s1ah84k8j30k70dvaac.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;有的小伙伴没留意过 Go map 输出顺序，以为它是稳定的有序的；有的小伙伴知道是无序的，但却不知道为什么？有的却理解错误？今天我们将通过本文，揭开 &lt;code&gt;for range map&lt;/code&gt; 的 “神秘” 面纱，看看它内部实现到底是怎么样的，输出顺序到底是怎么样？&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY2&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY3&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY4&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY5&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;k: %v, v: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;k&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;假设运行这段代码，输出结果是按顺序？还是无序输出呢？&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2019/04/03 23:27:29 k: 3, v: EDDYCJY4&#xA;2019/04/03 23:27:29 k: 4, v: EDDYCJY5&#xA;2019/04/03 23:27:29 k: 0, v: EDDYCJY1&#xA;2019/04/03 23:27:29 k: 1, v: EDDYCJY2&#xA;2019/04/03 23:27:29 k: 2, v: EDDYCJY3&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从输出结果上来讲，是非固定顺序输出的，也就是每次都不一样（标题也讲了）。但这是为什么呢？&lt;/p&gt;&#xA;&lt;p&gt;首先&lt;strong&gt;建议你先自己想想原因&lt;/strong&gt;。其次我在面试时听过一些说法。有人说因为是哈希的所以就是无（乱）序等等说法。当时我是有点 ？？？&lt;/p&gt;&#xA;&lt;p&gt;这也是这篇文章出现的原因，希望大家可以一起研讨一下，理清这个问题 ：）&lt;/p&gt;</description>
    </item>
    <item>
      <title>简单围观一下有趣的 //go: 指令</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-03-31-go-ins/</link>
      <pubDate>Sun, 31 Mar 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-03-31-go-ins/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;http://wx2.sinaimg.cn/large/006fVPCvly1g1m1bplu3mj30xc0m8myg.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;如果你平时有翻看源码的习惯，你肯定会发现。咦，怎么有的方法上面总是写着 &lt;code&gt;//go:&lt;/code&gt;  这类指令呢。他们到底是干嘛用的？&lt;/p&gt;&#xA;&lt;p&gt;今天我们一同揭开他们的面纱，我将简单给你介绍一下，它们都负责些什么&lt;/p&gt;&#xA;&lt;h2 id=&#34;golinkname&#34;&gt;go:linkname&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;//go:linkname localname importpath.name&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;该指令指示编译器使用 &lt;code&gt;importpath.name&lt;/code&gt; 作为源代码中声明为 &lt;code&gt;localname&lt;/code&gt; 的变量或函数的目标文件符号名称。但是由于这个伪指令，可以破坏类型系统和包模块化。因此只有引用了 unsafe 包才可以使用&lt;/p&gt;&#xA;&lt;p&gt;简单来讲，就是 &lt;code&gt;importpath.name&lt;/code&gt; 是 &lt;code&gt;localname&lt;/code&gt; 的符号别名，编译器实际上会调用 &lt;code&gt;localname&lt;/code&gt; 。但前提是使用了 &lt;code&gt;unsafe&lt;/code&gt; 包才能使用&lt;/p&gt;&#xA;&lt;h3 id=&#34;案例&#34;&gt;案例&lt;/h3&gt;&#xA;&lt;h4 id=&#34;timetimego&#34;&gt;time/time.go&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;...&#xA;func now() (sec int64, nsec int32, mono int64)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;runtimetimestubgo&#34;&gt;runtime/timestub.go&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;import _ &amp;#34;unsafe&amp;#34; // for go:linkname&#xA;&#xA;//go:linkname time_now time.now&#xA;func time_now() (sec int64, nsec int32, mono int64) {&#xA;&#x9;sec, nsec = walltime()&#xA;&#x9;return sec, nsec, nanotime() - startNano&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在这个案例中可以看到 &lt;code&gt;time.now&lt;/code&gt;，它并没有具体的实现。如果你初看可能会懵逼。这时候建议你全局搜索一下源码，你就会发现其实现在 &lt;code&gt;runtime.time_now&lt;/code&gt; 中&lt;/p&gt;&#xA;&lt;p&gt;配合先前的用法解释，可得知在 runtime 包中，我们声明了 &lt;code&gt;time_now&lt;/code&gt; 方法是 &lt;code&gt;time.now&lt;/code&gt; 的符号别名。并且在文件头引入了 &lt;code&gt;unsafe&lt;/code&gt; 达成前提条件&lt;/p&gt;</description>
    </item>
    <item>
      <title>深入理解 Go map：赋值和扩容迁移</title>
      <link>https://note.lican.site/posts/posts/go/map/2019-03-24-map-assign/</link>
      <pubDate>Sun, 24 Mar 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map/2019-03-24-map-assign/</guid>
      <description>&lt;h2 id=&#34;概要&#34;&gt;概要&lt;/h2&gt;&#xA;&lt;p&gt;在 &lt;a href=&#34;https://book.eddycjy.com/golang/map/map-access.html&#34;&gt;上一章节&lt;/a&gt; 中，数据结构小节里讲解了大量基础字段，可能你会疑惑需要 #&amp;amp;（！……#（！￥！ 来干嘛？接下来我们一起简单了解一下基础概念。再开始研讨今天文章的重点内容。我相信这样你能更好的读懂这篇文章&lt;/p&gt;&#xA;&lt;h3 id=&#34;哈希函数&#34;&gt;哈希函数&lt;/h3&gt;&#xA;&lt;p&gt;哈希函数，又称散列算法、散列函数。主要作用是通过特定算法将数据根据一定规则组合重新生成得到一个&lt;strong&gt;散列值&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;而在哈希表中，其生成的散列值常用于寻找其键映射到哪一个桶上。而一个好的哈希函数，应当尽量少的出现哈希冲突，以此保证操作哈希表的时间复杂度（但是哈希冲突在目前来讲，是无法避免的。我们需要 “解决” 它）&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;http://wx3.sinaimg.cn/large/006fVPCvly1g161h7r7hgj30is0dmjro.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;链地址法&#34;&gt;链地址法&lt;/h3&gt;&#xA;&lt;p&gt;在哈希操作中，相当核心的一个处理动作就是 “哈希冲突” 的解决。而在 Go map 中采用的就是 &amp;ldquo;链地址法 &amp;quot; 去解决哈希冲突，又称 &amp;ldquo;拉链法&amp;rdquo;。其主要做法是数组 + 链表的数据结构，其溢出节点的存储内存都是动态申请的，因此相对更灵活。而每一个元素都是一个链表。如下图：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;http://wx4.sinaimg.cn/large/006fVPCvly1g1dw2b8t0ej30e60cy747.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;桶溢出桶&#34;&gt;桶/溢出桶&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;buckets&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mapextra&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapextra&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;overflow&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;[]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;oldoverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;[]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nextOverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在上章节中，我们介绍了 Go map 中的桶和溢出桶的概念，在其桶中只能存储 8 个键值对元素。当超过 8 个时，将会使用溢出桶进行存储或进行扩容&lt;/p&gt;&#xA;&lt;p&gt;你可能会有疑问，hint 大于 8 又会怎么样？答案很明显，性能问题，其时间复杂度改变（也就是执行效率出现问题）&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;概要复习的差不多后，接下来我们将一同研讨 Go map 的另外三个核心行为：赋值、扩容、迁移。正式开始我们的研讨之旅吧 ：）&lt;/p&gt;&#xA;&lt;h2 id=&#34;赋值&#34;&gt;赋值&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;函数原型&#34;&gt;函数原型&lt;/h3&gt;&#xA;&lt;p&gt;在 map 的赋值动作中，依旧是针对 32/64 位、string、pointer 类型有不同的转换处理，总的函数原型如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>深入理解 Go map：初始化和访问元素</title>
      <link>https://note.lican.site/posts/posts/go/map/2019-03-05-map-access/</link>
      <pubDate>Tue, 05 Mar 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/map/2019-03-05-map-access/</guid>
      <description>&lt;p&gt;从本文开始咱们一起探索 Go map 里面的奥妙吧，看看它的内在是怎么构成的，又分别有什么值得留意的地方？&lt;/p&gt;&#xA;&lt;p&gt;第一篇将探讨&lt;strong&gt;初始化和访问元素&lt;/strong&gt;相关板块，咱们带着疑问去学习，例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;初始化的时候会马上分配内存吗？&lt;/li&gt;&#xA;&lt;li&gt;底层数据是如何存储的？&lt;/li&gt;&#xA;&lt;li&gt;底层是如何使用 key 去寻找数据的？&lt;/li&gt;&#xA;&lt;li&gt;底层是用什么方式解决哈希冲突的？&lt;/li&gt;&#xA;&lt;li&gt;数据类型那么多，底层又是怎么处理的呢？&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;数据结构&#34;&gt;数据结构&lt;/h2&gt;&#xA;&lt;p&gt;首先我们一起看看 Go map 的基础数据结构，先有一个大致的印象&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3dLgjH.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;hmap&#34;&gt;hmap&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;hmap&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;flags&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;         &lt;span style=&#34;color:#66d9ef&#34;&gt;uint8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;noverflow&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uint16&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;hash0&lt;/span&gt;     &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;buckets&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;oldbuckets&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pointer&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nevacuate&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;extra&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mapextra&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mapextra&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;overflow&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;[]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;oldoverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;[]&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nextOverflow&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;bmap&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;count：map 的大小，也就是 len() 的值。代指 map 中的键值对个数&lt;/li&gt;&#xA;&lt;li&gt;flags：状态标识，主要是 goroutine 写入和扩容机制的相关状态控制。并发读写的判断条件之一就是该值&lt;/li&gt;&#xA;&lt;li&gt;B：桶，最大可容纳的元素数量，值为 &lt;strong&gt;负载因子（默认 6.5） * 2 ^ B&lt;/strong&gt;，是 2 的指数&lt;/li&gt;&#xA;&lt;li&gt;noverflow：溢出桶的数量&lt;/li&gt;&#xA;&lt;li&gt;hash0：哈希因子&lt;/li&gt;&#xA;&lt;li&gt;buckets：保存当前桶数据的指针地址（指向一段连续的内存地址，主要存储键值对数据）&lt;/li&gt;&#xA;&lt;li&gt;oldbuckets，保存旧桶的指针地址&lt;/li&gt;&#xA;&lt;li&gt;nevacuate：迁移进度&lt;/li&gt;&#xA;&lt;li&gt;extra：原有 buckets 满载后，会发生扩容动作，在 Go 的机制中使用了增量扩容，如下为细项：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;overflow&lt;/code&gt; 为 &lt;code&gt;hmap.buckets&lt;/code&gt; （当前）溢出桶的指针地址&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;oldoverflow&lt;/code&gt; 为 &lt;code&gt;hmap.oldbuckets&lt;/code&gt; （旧）溢出桶的指针地址&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;nextOverflow&lt;/code&gt; 为空闲溢出桶的指针地址&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在这里我们要注意几点，如下：&lt;/p&gt;</description>
    </item>
    <item>
      <title>for-loop 与 json.Unmarshal 性能分析概要</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-02-17-for-loop-json-unmarshal/</link>
      <pubDate>Sun, 17 Feb 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-02-17-for-loop-json-unmarshal/</guid>
      <description>&lt;p&gt;在项目中，常常会遇到循环交换赋值的数据处理场景，尤其是 RPC，数据交互格式要转为 Protobuf，赋值是无法避免的。一般会有如下几种做法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;for&lt;/li&gt;&#xA;&lt;li&gt;for range&lt;/li&gt;&#xA;&lt;li&gt;json.Marshal/Unmarshal&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;这时候又面临 “选择困难症”，用哪个好？又想代码量少，又担心性能有没有影响啊&amp;hellip;&lt;/p&gt;&#xA;&lt;p&gt;为了弄清楚这个疑惑，接下来将分别编写三种使用场景。来简单看看它们的性能情况，看看谁更 “好”&lt;/p&gt;&#xA;&lt;h2 id=&#34;功能代码&#34;&gt;功能代码&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Person&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;name&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Age&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;age&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Avatar&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;avatar&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;type&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;name&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Age&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;age&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Avatar&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;avatar&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;type&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MAX&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;10000&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InitPerson&lt;/span&gt;() []&lt;span style=&#34;color:#a6e22e&#34;&gt;Person&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;persons&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Person&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;MAX&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;persons&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;persons&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Person&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;:   &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Age&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Avatar&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://github.com/EDDYCJY&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Type&lt;/span&gt;:   &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Person&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;persons&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ForStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Person&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ForRangeStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Person&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JsonToStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;againPerson&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt;) ([]&lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;json&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unmarshal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;againPerson&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;againPerson&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;JsonIteratorToStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;againPerson&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt;) ([]&lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jsonIter&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;jsoniter&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ConfigCompatibleWithStandardLibrary&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jsonIter&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unmarshal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;againPerson&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;againPerson&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;测试代码&#34;&gt;测试代码&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkForStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InitPerson&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; len(&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetTimer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ForStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;count&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkForRangeStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InitPerson&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetTimer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ForRangeStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkJsonToStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;InitPerson&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;againPersons&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;json&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Marshal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json.Marshal err: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetTimer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;JsonToStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;againPersons&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;BenchmarkJsonIteratorToStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;testing&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;B&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;InitPerson&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;againPersons&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;AgainPerson&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;json&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Marshal&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;person&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;json.Marshal err: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResetTimer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;N&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;JsonIteratorToStruct&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;againPersons&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;测试结果&#34;&gt;测试结果&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;BenchmarkForStruct-4              &#x9;  500000&#x9;      3289 ns/op&#x9;       0 B/op&#x9;       0 allocs/op&#xA;BenchmarkForRangeStruct-4         &#x9;  200000&#x9;      9178 ns/op&#x9;       0 B/op&#x9;       0 allocs/op&#xA;BenchmarkJsonToStruct-4           &#x9;     100&#x9;  19173117 ns/op&#x9; 2618509 B/op&#x9;   40036 allocs/op&#xA;BenchmarkJsonIteratorToStruct-4   &#x9;     300&#x9;   4116491 ns/op&#x9; 3694017 B/op&#x9;   30047 allocs/op&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从测试结果来看，性能排名为：for &amp;lt; for range &amp;lt; json-iterator &amp;lt; encoding/json。接下来我们看看是什么原因导致了这样子的排名？&lt;/p&gt;</description>
    </item>
    <item>
      <title>来，控制一下 goroutine 的并发数量</title>
      <link>https://note.lican.site/posts/posts/go/talk/2019-01-20-control-goroutine/</link>
      <pubDate>Sun, 20 Jan 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2019-01-20-control-goroutine/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wnOsJ.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;userCount&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;math&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MaxInt64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;userCount&lt;/span&gt;; &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;++&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;    &lt;span style=&#34;color:#75715e&#34;&gt;// 做一些各种各样的业务逻辑处理&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;go func: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sleep&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Second&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这里，假设 &lt;code&gt;userCount&lt;/code&gt; 是一个外部传入的参数（不可预测，有可能值非常大），有人会全部丢进去循环。想着全部都并发 goroutine 去同时做某一件事。觉得这样子会效率会更高，对不对！&lt;/p&gt;&#xA;&lt;p&gt;那么，你觉得这里有没有什么问题？&lt;/p&gt;&#xA;&lt;h2 id=&#34;噩梦般的开始&#34;&gt;噩梦般的开始&lt;/h2&gt;&#xA;&lt;p&gt;当然，在&lt;strong&gt;特定场景下&lt;/strong&gt;，问题可大了。因为在本文被丢进去同时并发的可是一个极端值。我们可以一起观察下图的指标分析，看看情况有多 “崩溃”。下图是上述代码的表现：&lt;/p&gt;&#xA;&lt;h3 id=&#34;输出结果&#34;&gt;输出结果&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;...&#xA;go func: 5839&#xA;go func: 5840&#xA;go func: 5841&#xA;go func: 5842&#xA;go func: 5915&#xA;go func: 5524&#xA;go func: 5916&#xA;go func: 8209&#xA;go func: 8264&#xA;signal: killed&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;如果你自己执行过代码，在 “输出结果” 上你会遇到如下问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;系统资源占用率不断上涨&lt;/li&gt;&#xA;&lt;li&gt;输出一定数量后：控制台就不再刷新输出最新的值了&lt;/li&gt;&#xA;&lt;li&gt;信号量：signal: killed&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;系统负载&#34;&gt;系统负载&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wnxd1.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;cpu&#34;&gt;CPU&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wuKW8.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go Slice 最大容量大小是怎么来的</title>
      <link>https://note.lican.site/posts/posts/go/slice/2019-01-06-why-slice-max/</link>
      <pubDate>Sun, 06 Jan 2019 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/slice/2019-01-06-why-slice-max/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wnHRU.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在《深入理解 Go Slice》中，我们提到了 “根据其类型大小去获取能够申请的最大容量大小” 的处理逻辑。今天我们将更深入地去探究一下，底层到底做了什么东西，涉及什么知识点？&lt;/p&gt;&#xA;&lt;p&gt;Go Slice 对应代码如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;makeslice&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;et&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;_type&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cap&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxElements&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxSliceCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;et&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; uintptr(&lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt;) &amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxElements&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cap&lt;/span&gt; &amp;lt; &lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;||&lt;/span&gt; uintptr(&lt;span style=&#34;color:#a6e22e&#34;&gt;cap&lt;/span&gt;) &amp;gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxElements&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mallocgc&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;et&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;size&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;uintptr(&lt;span style=&#34;color:#a6e22e&#34;&gt;cap&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;et&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;slice&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;p&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;len&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cap&lt;/span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;根据想要追寻的逻辑，定位到了 &lt;code&gt;maxSliceCap&lt;/code&gt; 方法，它会根据&lt;strong&gt;当前类型的大小获取到了所允许的最大容量大小&lt;/strong&gt;来进行阈值判断，也就是安全检查。这是浅层的了解，我们继续追下去看看还做了些什么？&lt;/p&gt;&#xA;&lt;h2 id=&#34;maxslicecap&#34;&gt;maxSliceCap&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxSliceCap&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;elemsize&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elemsize&lt;/span&gt; &amp;lt; uintptr(len(&lt;span style=&#34;color:#a6e22e&#34;&gt;maxElems&lt;/span&gt;)) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxElems&lt;/span&gt;[&lt;span style=&#34;color:#a6e22e&#34;&gt;elemsize&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;elemsize&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;maxelems&#34;&gt;maxElems&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;maxElems&lt;/span&gt; = [&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;uintptr&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;^uintptr(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;4&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;7&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;8&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;9&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;11&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;12&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;13&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;14&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;15&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;16&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;17&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;18&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;19&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;20&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;21&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;22&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;23&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;24&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;25&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;26&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;27&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;28&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;29&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;30&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;31&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;maxAlloc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;32&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;maxElems&lt;/code&gt; 是包含一些预定义的切片最大容量值的查找表，索引是切片元素的类型大小。而值看起来 “奇奇怪怪” 不大眼熟，都是些什么呢。主要是以下三个核心点：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;^uintptr(0)&lt;/li&gt;&#xA;&lt;li&gt;maxAlloc&lt;/li&gt;&#xA;&lt;li&gt;maxAlloc / typeSize&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;uintptr0&#34;&gt;^uintptr(0)&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;uintptr: %v\n&amp;#34;&lt;/span&gt;, uintptr(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^uintptr: %v\n&amp;#34;&lt;/span&gt;, ^uintptr(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>在 Go 中恰到好处的内存对齐</title>
      <link>https://note.lican.site/posts/posts/go/talk/2018-12-26-go-memory-align/</link>
      <pubDate>Wed, 26 Dec 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2018-12-26-go-memory-align/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3wuT0A.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Part1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在开始之前，希望你计算一下 &lt;code&gt;Part1&lt;/code&gt; 共占用的大小是多少呢？&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;bool size: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(bool(&lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;int32 size: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(int32(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;int8 size: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(int8(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;int64 size: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(int64(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;byte size: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(byte(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;)))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;string size: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;EDDYCJY&amp;#34;&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;bool size: 1&#xA;int32 size: 4&#xA;int8 size: 1&#xA;int64 size: 8&#xA;byte size: 1&#xA;string size: 16&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这么一算，&lt;code&gt;Part1&lt;/code&gt; 这一个结构体的占用内存大小为 1+4+1+8+1 = 15 个字节。相信有的小伙伴是这么算的，看上去也没什么毛病&lt;/p&gt;&#xA;&lt;p&gt;真实情况是怎么样的呢？我们实际调用看看，如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Part1&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;b&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int32&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int8&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;byte&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;part1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Part1&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;part1 size: %d, align: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sizeof&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;part1&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;unsafe&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Alignof&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;part1&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出结果：&lt;/p&gt;</description>
    </item>
    <item>
      <title>有点不安全却又一亮的 Go unsafe.Pointer</title>
      <link>https://note.lican.site/posts/posts/go/pkg/2018-12-15-unsafe/</link>
      <pubDate>Sat, 15 Dec 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/pkg/2018-12-15-unsafe/</guid>
      <description>&lt;p&gt;在上一篇文章《深入理解 Go Slice》中，大家会发现其底层数据结构使用了 &lt;code&gt;unsafe.Pointer&lt;/code&gt;。因此想着再介绍一下其关联知识&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在大家学习 Go 的时候，肯定都学过 “Go 的指针是不支持指针运算和转换” 这个知识点。为什么呢？&lt;/p&gt;&#xA;&lt;p&gt;首先，Go 是一门静态语言，所有的变量都必须为标量类型。不同的类型不能够进行赋值、计算等跨类型的操作。那么指针也对应着相对的类型，也在 Compile 的静态类型检查的范围内。同时静态语言，也称为强类型。也就是一旦定义了，就不能再改变它&lt;/p&gt;&#xA;&lt;h2 id=&#34;错误示例&#34;&gt;错误示例&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main(){&#xA;&#x9;num := 5&#xA;&#x9;numPointer := &amp;amp;num&#xA;&#xA;&#x9;flnum := (*float32)(numPointer)&#xA;&#x9;fmt.Println(flnum)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;输出结果：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# command-line-arguments&#xA;...: cannot convert numPointer (type *int) to type *float32&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在示例中，我们创建了一个 &lt;code&gt;num&lt;/code&gt; 变量，值为 5，类型为 &lt;code&gt;int&lt;/code&gt;。取了其对于的指针地址后，试图强制转换为 &lt;code&gt;*float32&lt;/code&gt;，结果失败&amp;hellip;&lt;/p&gt;&#xA;&lt;h2 id=&#34;unsafe&#34;&gt;unsafe&lt;/h2&gt;&#xA;&lt;p&gt;针对刚刚的 “错误示例”，我们可以采用今天的男主角 &lt;code&gt;unsafe&lt;/code&gt; 标准库来解决。它是一个神奇的包，在官方的诠释中，有如下概述：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;围绕 Go 程序内存安全及类型的操作&lt;/li&gt;&#xA;&lt;li&gt;很可能会是不可移植的&lt;/li&gt;&#xA;&lt;li&gt;不受 Go 1 兼容性指南的保护&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;简单来讲就是，不怎么推荐你使用。因为它是 unsafe（不安全的），但是在特殊的场景下，使用了它。可以打破 Go 的类型和内存安全机制，让你获得眼前一亮的惊喜效果 😄&lt;/p&gt;&#xA;&lt;h3 id=&#34;pointer&#34;&gt;Pointer&lt;/h3&gt;&#xA;&lt;p&gt;为了解决这个问题，需要用到 &lt;code&gt;unsafe.Pointer&lt;/code&gt;。它表示任意类型且可寻址的指针值，可以在不同的指针类型之间进行转换（类似 C 语言的 void * 的用途）&lt;/p&gt;</description>
    </item>
    <item>
      <title>深入理解 Go Slice</title>
      <link>https://note.lican.site/posts/posts/go/slice/2018-12-11-slice/</link>
      <pubDate>Tue, 11 Dec 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/slice/2018-12-11-slice/</guid>
      <description>&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3dXSeA.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;是什么&#34;&gt;是什么&lt;/h2&gt;&#xA;&lt;p&gt;在 Go 中，Slice（切片）是抽象在 Array（数组）之上的特殊类型。为了更好地了解 Slice，第一步需要先对 Array 进行理解。深刻了解 Slice 与 Array 之间的区别后，就能更好的对其底层一番摸索 😄&lt;/p&gt;&#xA;&lt;h2 id=&#34;用法&#34;&gt;用法&lt;/h2&gt;&#xA;&lt;h3 id=&#34;array&#34;&gt;Array&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt; = &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;nums: %v\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;n: %d\n&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;n&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可得知在 Go 中，数组类型需要指定长度和元素类型。在上述代码中，可得知 &lt;code&gt;[3]int{}&lt;/code&gt; 表示 3 个整数的数组，并进行了初始化。底层数据存储为一段连续的内存空间，通过固定的索引值（下标）进行检索&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://s2.ax1x.com/2020/02/27/3dXASS.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;数组在声明后，其元素的初始值（也就是零值）为 0。并且该变量可以直接使用，不需要特殊操作&lt;/p&gt;&#xA;&lt;p&gt;同时数组的长度是固定的，它的长度是类型的一部分，因此 &lt;code&gt;[3]int&lt;/code&gt; 和 &lt;code&gt;[4]int&lt;/code&gt; 在类型上是不同的，不能称为 “一个东西”&lt;/p&gt;&#xA;&lt;h4 id=&#34;输出结果&#34;&gt;输出结果&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;nums: [1 0 0]&#xA;n: 2&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;slice&#34;&gt;Slice&lt;/h3&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; [&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;] = &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;dnums&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nums&lt;/span&gt;[:]&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;dnums: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;dnums&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Slice 是对 Array 的抽象，类型为 &lt;code&gt;[]T&lt;/code&gt;。在上述代码中，&lt;code&gt;dnums&lt;/code&gt; 变量通过 &lt;code&gt;nums[:]&lt;/code&gt; 进行赋值。需要注意的是，Slice 和 Array 不一样，它不需要指定长度。也更加的灵活，能够自动扩容&lt;/p&gt;</description>
    </item>
    <item>
      <title>fmt 标准库 --- Print* 是怎么样输出的？</title>
      <link>https://note.lican.site/posts/posts/go/pkg/2018-12-04-fmt/</link>
      <pubDate>Tue, 04 Dec 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/pkg/2018-12-04-fmt/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package main&#xA;&#xA;import (&#xA;&#x9;&amp;#34;fmt&amp;#34;&#xA;)&#xA;&#xA;func main() {&#xA;&#x9;fmt.Println(&amp;#34;Hello World!&amp;#34;)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;标准开场见多了，那内部标准库又是怎么输出这段英文的呢？今天一起来围观下源码吧 🤭&lt;/p&gt;&#xA;&lt;h2 id=&#34;原型&#34;&gt;原型&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func Print(a ...interface{}) (n int, err error) {&#xA;&#x9;return Fprint(os.Stdout, a...)&#xA;}&#xA;&#xA;func Println(a ...interface{}) (n int, err error) {&#xA;&#x9;return Fprintln(os.Stdout, a...)&#xA;}&#xA;&#xA;func Printf(format string, a ...interface{}) (n int, err error) {&#xA;&#x9;return Fprintf(os.Stdout, format, a...)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;Print：使用默认格式说明符打印格式并写入标准输出。当两者都不是字符串时，在操作数之间添加空格&lt;/li&gt;&#xA;&lt;li&gt;Println：同上，不同的地方是始终在操作数之间添加空格，并附加换行符&lt;/li&gt;&#xA;&lt;li&gt;Printf：根据格式说明符进行格式化并写入标准输出&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;以上三类就是最常见的格式化 I/O 的方法，我们将基于此去进行拆解描述&lt;/p&gt;&#xA;&lt;h2 id=&#34;执行流程&#34;&gt;执行流程&lt;/h2&gt;&#xA;&lt;h3 id=&#34;案例一print&#34;&gt;案例一：Print&lt;/h3&gt;&#xA;&lt;p&gt;在这里我们使用 &lt;code&gt;Print&lt;/code&gt; 方法做一个分析，便于后面的加深理解 😄&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func Print(a ...interface{}) (n int, err error) {&#xA;&#x9;return Fprint(os.Stdout, a...)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;Print&lt;/code&gt; 使用默认格式说明符打印格式并写入标准输出。另外当两者都为非空字符串时将插入一个空格&lt;/p&gt;</description>
    </item>
    <item>
      <title>使用 Gomock 进行单元测试</title>
      <link>https://note.lican.site/posts/posts/go/talk/2018-11-25-gomock/</link>
      <pubDate>Sun, 25 Nov 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2018-11-25-gomock/</guid>
      <description>&lt;p&gt;在实际项目中，需要进行单元测试的时候。却往往发现有一大堆依赖项。这时候就是 &lt;a href=&#34;https://github.com/golang/mock&#34;&gt;Gomock&lt;/a&gt; 大显身手的时候了&lt;/p&gt;&#xA;&lt;p&gt;Gomock 是 Go 语言的一个 mock 框架，官方的那种 🤪&lt;/p&gt;&#xA;&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get -u github.com/golang/mock/gomock&#xA;$ go install github.com/golang/mock/mockgen&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;第一步：我们将安装 gomock 第三方库和 mock 代码的生成工具 mockgen。而后者可以大大的节省我们的工作量。只需要了解其使用方式就可以&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;第二步：输入 &lt;code&gt;mockgen&lt;/code&gt; 验证代码生成工具是否安装正确。若无法正常响应，请检查 &lt;code&gt;bin&lt;/code&gt; 目录下是否包含该二进制文件&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;用法&#34;&gt;用法&lt;/h3&gt;&#xA;&lt;p&gt;在 &lt;code&gt;mockgen&lt;/code&gt; 命令中，支持两种生成模式：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;source：从源文件生成 mock 接口（通过 -source 启用）&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mockgen -source=foo.go [other options]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol start=&#34;2&#34;&gt;&#xA;&lt;li&gt;reflect：通过使用反射程序来生成 mock 接口。它通过传递两个非标志参数来启用：导入路径和逗号分隔的接口列表&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mockgen database/sql/driver Conn,Driver&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;从本质上来讲，两种方式生成的 mock 代码并没有什么区别。因此选择合适的就可以了&lt;/p&gt;&#xA;&lt;h2 id=&#34;写测试用例&#34;&gt;写测试用例&lt;/h2&gt;&#xA;&lt;p&gt;在本文将模拟一个简单 Demo 来编写测试用例，熟悉整体的测试流程&lt;/p&gt;&#xA;&lt;h3 id=&#34;步骤&#34;&gt;步骤&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;想清楚整体逻辑&lt;/li&gt;&#xA;&lt;li&gt;定义想要（模拟）依赖项的 interface（接口）&lt;/li&gt;&#xA;&lt;li&gt;使用 &lt;code&gt;mockgen&lt;/code&gt; 命令对所需 mock 的 interface 生成 mock 文件&lt;/li&gt;&#xA;&lt;li&gt;编写单元测试的逻辑，在测试中使用 mock&lt;/li&gt;&#xA;&lt;li&gt;进行单元测试的验证&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;目录&#34;&gt;目录&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;├── mock&#xA;├── person&#xA;│   └── male.go&#xA;└── user&#xA;    ├── user.go&#xA;    └── user_test.go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;编写&#34;&gt;编写&lt;/h3&gt;&#xA;&lt;h4 id=&#34;interface-方法&#34;&gt;interface 方法&lt;/h4&gt;&#xA;&lt;p&gt;打开 person/male.go 文件，写入以下内容：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十」分布式链路追踪 gRPC &#43; Opentracing &#43; Zipkin</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-20-zipkin/</link>
      <pubDate>Sat, 20 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-20-zipkin/</guid>
      <description>&lt;p&gt;在实际应用中，你做了那么多 Server 端，写了 N 个 RPC 方法。想看看方法的指标，却无处下手？&lt;/p&gt;&#xA;&lt;p&gt;本文将通过 gRPC + Opentracing + Zipkin 搭建一个&lt;strong&gt;分布式链路追踪系统&lt;/strong&gt;来实现查看整个系统的链路、性能等指标。&lt;/p&gt;&#xA;&lt;h2 id=&#34;opentracing&#34;&gt;Opentracing&lt;/h2&gt;&#xA;&lt;h3 id=&#34;是什么&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;p&gt;OpenTracing 通过提供平台无关、厂商无关的API，使得开发人员能够方便的添加（或更换）追踪系统的实现&lt;/p&gt;&#xA;&lt;p&gt;不过 OpenTracing 并不是标准。因为 CNCF 不是官方标准机构，但是它的目标是致力为分布式追踪创建更标准的 API 和工具&lt;/p&gt;&#xA;&lt;h3 id=&#34;名词解释&#34;&gt;名词解释&lt;/h3&gt;&#xA;&lt;h4 id=&#34;trace&#34;&gt;Trace&lt;/h4&gt;&#xA;&lt;p&gt;一个 trace 代表了一个事务或者流程在（分布式）系统中的执行过程&lt;/p&gt;&#xA;&lt;h4 id=&#34;span&#34;&gt;Span&lt;/h4&gt;&#xA;&lt;p&gt;一个 span 代表在分布式系统中完成的单个工作单元。也包含其他 span 的 “引用”，这允许将多个 spans 组合成一个完整的 Trace&lt;/p&gt;&#xA;&lt;p&gt;每个 span 根据 OpenTracing 规范封装以下内容：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;操作名称&lt;/li&gt;&#xA;&lt;li&gt;开始时间和结束时间&lt;/li&gt;&#xA;&lt;li&gt;key:value span Tags&lt;/li&gt;&#xA;&lt;li&gt;key:value span Logs&lt;/li&gt;&#xA;&lt;li&gt;SpanContext&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;tags&#34;&gt;Tags&lt;/h4&gt;&#xA;&lt;p&gt;Span tags（跨度标签）可以理解为用户自定义的 Span 注释。便于查询、过滤和理解跟踪数据&lt;/p&gt;&#xA;&lt;h4 id=&#34;logs&#34;&gt;Logs&lt;/h4&gt;&#xA;&lt;p&gt;Span logs（跨度日志）可以记录 Span 内特定时间或事件的日志信息。主要用于捕获特定 Span 的日志信息以及应用程序本身的其他调试或信息输出&lt;/p&gt;&#xA;&lt;h4 id=&#34;spancontext&#34;&gt;SpanContext&lt;/h4&gt;&#xA;&lt;p&gt;SpanContext 代表跨越进程边界，传递到子级 Span 的状态。常在追踪示意图中创建上下文时使用&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载九」gRPC Deadlines</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-16-deadlines/</link>
      <pubDate>Tue, 16 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-16-deadlines/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在前面的章节中，已经介绍了 gRPC 的基本用法。那你想想，让它这么裸跑真的没问题吗？&lt;/p&gt;&#xA;&lt;p&gt;那么，肯定是有问题了。今天将介绍 gRPC Deadlines 的用法，这一个必备技巧。内容也比较简单&lt;/p&gt;&#xA;&lt;h2 id=&#34;deadlines&#34;&gt;Deadlines&lt;/h2&gt;&#xA;&lt;p&gt;Deadlines 意指截止时间，在 gRPC 中强调 TL;DR（Too long, Don&amp;rsquo;t read）并建议&lt;strong&gt;始终设定截止日期&lt;/strong&gt;，为什么呢？&lt;/p&gt;&#xA;&lt;h3 id=&#34;为什么要设置&#34;&gt;为什么要设置&lt;/h3&gt;&#xA;&lt;p&gt;当未设置 Deadlines 时，将采用默认的 DEADLINE_EXCEEDED（这个时间非常大）&lt;/p&gt;&#xA;&lt;p&gt;如果产生了阻塞等待，就会造成大量正在进行的请求都会被保留，并且所有请求都有可能达到最大超时&lt;/p&gt;&#xA;&lt;p&gt;这会使服务面临资源耗尽的风险，例如内存，这会增加服务的延迟，或者在最坏的情况下可能导致整个进程崩溃&lt;/p&gt;&#xA;&lt;h2 id=&#34;grpc&#34;&gt;gRPC&lt;/h2&gt;&#xA;&lt;h3 id=&#34;client&#34;&gt;Client&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func main() {&#xA;    ...&#xA;&#x9;ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Duration(5 * time.Second)))&#xA;&#x9;defer cancel()&#xA;&#xA;&#x9;client := pb.NewSearchServiceClient(conn)&#xA;&#x9;resp, err := client.Search(ctx, &amp;amp;pb.SearchRequest{&#xA;&#x9;&#x9;Request: &amp;#34;gRPC&amp;#34;,&#xA;&#x9;})&#xA;&#x9;if err != nil {&#xA;&#x9;&#x9;statusErr, ok := status.FromError(err)&#xA;&#x9;&#x9;if ok {&#xA;&#x9;&#x9;&#x9;if statusErr.Code() == codes.DeadlineExceeded {&#xA;&#x9;&#x9;&#x9;&#x9;log.Fatalln(&amp;#34;client.Search err: deadline&amp;#34;)&#xA;&#x9;&#x9;&#x9;}&#xA;&#x9;&#x9;}&#xA;&#xA;&#x9;&#x9;log.Fatalf(&amp;#34;client.Search err: %v&amp;#34;, err)&#xA;&#x9;}&#xA;&#xA;&#x9;log.Printf(&amp;#34;resp: %s&amp;#34;, resp.GetResponse())&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;context.WithDeadline：会返回最终上下文截止时间。第一个形参为父上下文，第二个形参为调整的截止时间。若父级时间早于子级时间，则以父级时间为准，否则以子级时间为最终截止时间&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {&#xA;&#x9;if cur, ok := parent.Deadline(); ok &amp;amp;&amp;amp; cur.Before(d) {&#xA;&#x9;&#x9;// The current deadline is already sooner than the new one.&#xA;&#x9;&#x9;return WithCancel(parent)&#xA;&#x9;}&#xA;&#x9;c := &amp;amp;timerCtx{&#xA;&#x9;&#x9;cancelCtx: newCancelCtx(parent),&#xA;&#x9;&#x9;deadline:  d,&#xA;&#x9;}&#xA;&#x9;propagateCancel(parent, c)&#xA;&#x9;dur := time.Until(d)&#xA;&#x9;if dur &amp;lt;= 0 {&#xA;&#x9;&#x9;c.cancel(true, DeadlineExceeded) // deadline has already passed&#xA;&#x9;&#x9;return c, func() { c.cancel(true, Canceled) }&#xA;&#x9;}&#xA;&#x9;c.mu.Lock()&#xA;&#x9;defer c.mu.Unlock()&#xA;&#x9;if c.err == nil {&#xA;&#x9;&#x9;c.timer = time.AfterFunc(dur, func() {&#xA;&#x9;&#x9;&#x9;c.cancel(true, DeadlineExceeded)&#xA;&#x9;&#x9;})&#xA;&#x9;}&#xA;&#x9;return c, func() { c.cancel(true, Canceled) }&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;context.WithTimeout：很常见的另外一个方法，是便捷操作。实际上是对于 WithDeadline 的封装&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {&#xA;&#x9;return WithDeadline(parent, time.Now().Add(timeout))&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;status.FromError：返回 GRPCStatus 的具体错误码，若为非法，则直接返回 &lt;code&gt;codes.Unknown&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;server&#34;&gt;Server&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type SearchService struct{}&#xA;&#xA;func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {&#xA;&#x9;for i := 0; i &amp;lt; 5; i++  {&#xA;&#x9;&#x9;if ctx.Err() == context.Canceled {&#xA;&#x9;&#x9;&#x9;return nil, status.Errorf(codes.Canceled, &amp;#34;SearchService.Search canceled&amp;#34;)&#xA;&#x9;&#x9;}&#xA;&#xA;&#x9;&#x9;time.Sleep(1 * time.Second)&#xA;&#x9;}&#xA;&#xA;&#x9;return &amp;amp;pb.SearchResponse{Response: r.GetRequest() + &amp;#34; Server&amp;#34;}, nil&#xA;}&#xA;&#xA;func main() {&#xA;&#x9;...&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而在 Server 端，由于 Client 已经设置了截止时间。Server 势必要去检测它&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载八」对 RPC 方法做自定义认证</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-14-per-rpc-credentials/</link>
      <pubDate>Sun, 14 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-14-per-rpc-credentials/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在前面的章节中，我们介绍了两种（证书算一种）可全局认证的方法：&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/EDDYCJY/blog/blob/master/grpc/grpc-tls.md&#34;&gt;TLS 证书认证&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/EDDYCJY/blog/blob/master/grpc/ca-tls.md&#34;&gt;基于 CA 的 TLS 证书认证&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/EDDYCJY/blog/blob/master/grpc/interceptor.md&#34;&gt;Unary and Stream interceptor&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;而在实际需求中，常常会对某些模块的 RPC 方法做特殊认证或校验。今天将会讲解、实现这块的功能点&lt;/p&gt;&#xA;&lt;h2 id=&#34;课前知识&#34;&gt;课前知识&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type PerRPCCredentials interface {&#xA;    GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)&#xA;    RequireTransportSecurity() bool&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 gRPC 中默认定义了 PerRPCCredentials，它就是本章节的主角，是 gRPC 默认提供用于自定义认证的接口，它的作用是将所需的安全认证信息添加到每个 RPC 方法的上下文中。其包含 2 个方法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;GetRequestMetadata：获取当前请求认证所需的元数据（metadata）&lt;/li&gt;&#xA;&lt;li&gt;RequireTransportSecurity：是否需要基于 TLS 认证进行安全传输&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;目录结构&#34;&gt;目录结构&lt;/h2&gt;&#xA;&lt;p&gt;新建 simple_token_server/server.go 和 simple_token_client/client.go，目录结构如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go-grpc-example&#xA;├── client&#xA;│   ├── simple_client&#xA;│   ├── simple_http_client&#xA;│   ├── simple_token_client&#xA;│   └── stream_client&#xA;├── conf&#xA;├── pkg&#xA;├── proto&#xA;├── server&#xA;│   ├── simple_http_server&#xA;│   ├── simple_server&#xA;│   ├── simple_token_server&#xA;│   └── stream_server&#xA;└── vendor&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;grpc&#34;&gt;gRPC&lt;/h2&gt;&#xA;&lt;h3 id=&#34;client&#34;&gt;Client&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;package main&#xA;&#xA;import (&#xA;&#x9;&amp;#34;context&amp;#34;&#xA;&#x9;&amp;#34;log&amp;#34;&#xA;&#xA;&#x9;&amp;#34;google.golang.org/grpc&amp;#34;&#xA;&#xA;&#x9;&amp;#34;github.com/EDDYCJY/go-grpc-example/pkg/gtls&amp;#34;&#xA;&#x9;pb &amp;#34;github.com/EDDYCJY/go-grpc-example/proto&amp;#34;&#xA;)&#xA;&#xA;const PORT = &amp;#34;9004&amp;#34;&#xA;&#xA;type Auth struct {&#xA;&#x9;AppKey    string&#xA;&#x9;AppSecret string&#xA;}&#xA;&#xA;func (a *Auth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {&#xA;&#x9;return map[string]string{&amp;#34;app_key&amp;#34;: a.AppKey, &amp;#34;app_secret&amp;#34;: a.AppSecret}, nil&#xA;}&#xA;&#xA;func (a *Auth) RequireTransportSecurity() bool {&#xA;&#x9;return true&#xA;}&#xA;&#xA;func main() {&#xA;&#x9;tlsClient := gtls.Client{&#xA;&#x9;&#x9;ServerName: &amp;#34;go-grpc-example&amp;#34;,&#xA;&#x9;&#x9;CertFile:   &amp;#34;../../conf/server/server.pem&amp;#34;,&#xA;&#x9;}&#xA;&#x9;c, err := tlsClient.GetTLSCredentials()&#xA;&#x9;if err != nil {&#xA;&#x9;&#x9;log.Fatalf(&amp;#34;tlsClient.GetTLSCredentials err: %v&amp;#34;, err)&#xA;&#x9;}&#xA;&#xA;&#x9;auth := Auth{&#xA;&#x9;&#x9;AppKey:    &amp;#34;eddycjy&amp;#34;,&#xA;&#x9;&#x9;AppSecret: &amp;#34;20181005&amp;#34;,&#xA;&#x9;}&#xA;&#x9;conn, err := grpc.Dial(&amp;#34;:&amp;#34;+PORT, grpc.WithTransportCredentials(c), grpc.WithPerRPCCredentials(&amp;amp;auth))&#xA;&#x9;...&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在 Client 端，重点实现 &lt;code&gt;type PerRPCCredentials interface&lt;/code&gt; 所需的方法，关注两点即可：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载七」让你的服务同时提供 HTTP 接口</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-12-grpc-http/</link>
      <pubDate>Fri, 12 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-12-grpc-http/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;接口需要提供给其他业务组访问，但是 RPC 协议不同无法内调，对方问能否走 HTTP 接口，怎么办？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;微信（公众号、小程序）等第三方回调接口只支持 HTTP 接口，怎么办&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;我相信你在实际工作中都会遇到如上问题，在 gRPC 中都是有解决方案的，本章节将会进行介绍 🤔&lt;/p&gt;&#xA;&lt;h2 id=&#34;为什么可以同时提供-http-接口&#34;&gt;为什么可以同时提供 HTTP 接口&lt;/h2&gt;&#xA;&lt;p&gt;关键一点，gRPC 的协议是基于 HTTP/2 的，因此应用程序能够在单个 TCP 端口上提供 HTTP/1.1 和 gRPC 接口服务（两种不同的流量）&lt;/p&gt;&#xA;&lt;h2 id=&#34;怎么同时提供-http-接口&#34;&gt;怎么同时提供 HTTP 接口&lt;/h2&gt;&#xA;&lt;h3 id=&#34;检测协议&#34;&gt;检测协议&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;if r.ProtoMajor == 2 &amp;amp;&amp;amp; strings.Contains(r.Header.Get(&amp;#34;Content-Type&amp;#34;), &amp;#34;application/grpc&amp;#34;) {&#xA;    server.ServeHTTP(w, r)&#xA;} else {&#xA;    mux.ServeHTTP(w, r)&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;流程&#34;&gt;流程&lt;/h3&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;检测请求协议是否为 HTTP/2&lt;/li&gt;&#xA;&lt;li&gt;判断 Content-Type 是否为 application/grpc（gRPC 的默认标识位）&lt;/li&gt;&#xA;&lt;li&gt;根据协议的不同转发到不同的服务处理&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h2 id=&#34;grpc&#34;&gt;gRPC&lt;/h2&gt;&#xA;&lt;h3 id=&#34;tls&#34;&gt;TLS&lt;/h3&gt;&#xA;&lt;p&gt;在前面的章节，为了便于展示因此没有简单封装&lt;/p&gt;&#xA;&lt;p&gt;在本节需复用代码，重新封装了，可详见：&lt;a href=&#34;https://github.com/EDDYCJY/go-grpc-example/tree/master/pkg/gtls&#34;&gt;go-grpc-example&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;目录结构&#34;&gt;目录结构&lt;/h3&gt;&#xA;&lt;p&gt;新建 simple_http_client、simple_http_server 目录，目录结构如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go-grpc-example&#xA;├── client&#xA;│   ├── simple_client&#xA;│   ├── simple_http_client&#xA;│   └── stream_client&#xA;├── conf&#xA;├── pkg&#xA;│   └── gtls&#xA;├── proto&#xA;├── server&#xA;│   ├── simple_http_server&#xA;│   ├── simple_server&#xA;│   └── stream_server&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;server&#34;&gt;Server&lt;/h3&gt;&#xA;&lt;p&gt;在 simple_http_server 目录下新建 server.go，写入文件内容：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载六」Unary and Stream interceptor</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-10-interceptor/</link>
      <pubDate>Wed, 10 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-10-interceptor/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;我想在每个 RPC 方法的前或后做某些事情，怎么做？&lt;/p&gt;&#xA;&lt;p&gt;本章节将要介绍的拦截器（interceptor），就能帮你在合适的地方实现这些功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;有几种方法&#34;&gt;有几种方法&lt;/h2&gt;&#xA;&lt;p&gt;在 gRPC 中，大类可分为两种 RPC 方法，与拦截器的对应关系是：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;普通方法：一元拦截器（grpc.UnaryInterceptor）&lt;/li&gt;&#xA;&lt;li&gt;流方法：流拦截器（grpc.StreamInterceptor）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;看一看&#34;&gt;看一看&lt;/h2&gt;&#xA;&lt;h3 id=&#34;grpcunaryinterceptor&#34;&gt;grpc.UnaryInterceptor&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func UnaryInterceptor(i UnaryServerInterceptor) ServerOption {&#xA;&#x9;return func(o *options) {&#xA;&#x9;&#x9;if o.unaryInt != nil {&#xA;&#x9;&#x9;&#x9;panic(&amp;#34;The unary server interceptor was already set and may not be reset.&amp;#34;)&#xA;&#x9;&#x9;}&#xA;&#x9;&#x9;o.unaryInt = i&#xA;&#x9;}&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;函数原型：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type UnaryServerInterceptor func(ctx context.Context, req interface{}, info *UnaryServerInfo, handler UnaryHandler) (resp interface{}, err error)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;通过查看源码可得知，要完成一个拦截器需要实现 &lt;code&gt;UnaryServerInterceptor&lt;/code&gt; 方法。形参如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;ctx context.Context：请求上下文&lt;/li&gt;&#xA;&lt;li&gt;req interface{}：RPC 方法的请求参数&lt;/li&gt;&#xA;&lt;li&gt;info *UnaryServerInfo：RPC 方法的所有信息&lt;/li&gt;&#xA;&lt;li&gt;handler UnaryHandler：RPC 方法本身&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;grpcstreaminterceptor&#34;&gt;grpc.StreamInterceptor&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func StreamInterceptor(i StreamServerInterceptor) ServerOption&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;函数原型：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载五」基于 CA 的 TLS 证书认证</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-08-ca-tls/</link>
      <pubDate>Mon, 08 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-08-ca-tls/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在上一章节中，我们提出了一个问题。就是如何保证证书的可靠性和有效性？你如何确定你 Server、Client 的证书是对的呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;ca&#34;&gt;CA&lt;/h2&gt;&#xA;&lt;p&gt;为了保证证书的可靠性和有效性，在这里可引入 CA 颁发的根证书的概念。其遵守 X.509 标准&lt;/p&gt;&#xA;&lt;h3 id=&#34;根证书&#34;&gt;根证书&lt;/h3&gt;&#xA;&lt;p&gt;根证书（root certificate）是属于根证书颁发机构（CA）的公钥证书。我们可以通过验证 CA 的签名从而信任 CA ，任何人都可以得到 CA 的证书（含公钥），用以验证它所签发的证书（客户端、服务端）&lt;/p&gt;&#xA;&lt;p&gt;它包含的文件如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;公钥&lt;/li&gt;&#xA;&lt;li&gt;密钥&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;生成-key&#34;&gt;生成 Key&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl genrsa -out ca.key 2048&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;生成密钥&#34;&gt;生成密钥&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl req -new -x509 -days 7200 -key ca.key -out ca.pem&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;填写信息&#34;&gt;填写信息&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Country Name (2 letter code) []:&#xA;State or Province Name (full name) []:&#xA;Locality Name (eg, city) []:&#xA;Organization Name (eg, company) []:&#xA;Organizational Unit Name (eg, section) []:&#xA;Common Name (eg, fully qualified host name) []:go-grpc-example&#xA;Email Address []:&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;server&#34;&gt;Server&lt;/h3&gt;&#xA;&lt;h4 id=&#34;生成-csr&#34;&gt;生成 CSR&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl req -new -key server.key -out server.csr&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h5 id=&#34;填写信息-1&#34;&gt;填写信息&lt;/h5&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Country Name (2 letter code) []:&#xA;State or Province Name (full name) []:&#xA;Locality Name (eg, city) []:&#xA;Organization Name (eg, company) []:&#xA;Organizational Unit Name (eg, section) []:&#xA;Common Name (eg, fully qualified host name) []:go-grpc-example&#xA;Email Address []:&#xA;&#xA;Please enter the following &amp;#39;extra&amp;#39; attributes&#xA;to be sent with your certificate request&#xA;A challenge password []:&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;CSR 是 Cerificate Signing Request 的英文缩写，为证书请求文件。主要作用是 CA 会利用 CSR 文件进行签名使得攻击者无法伪装或篡改原有证书&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载四」TLS 证书认证</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-10-07-grpc-tls/</link>
      <pubDate>Sun, 07 Oct 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-10-07-grpc-tls/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;在前面的章节里，我们介绍了 gRPC 的四种 API 使用方式。是不是很简单呢 😀&lt;/p&gt;&#xA;&lt;p&gt;此时存在一个安全问题，先前的例子中 gRPC Client/Server 都是明文传输的，会不会有被窃听的风险呢？&lt;/p&gt;&#xA;&lt;p&gt;从结论上来讲，是有的。在明文通讯的情况下，你的请求就是裸奔的，有可能被第三方恶意篡改或者伪造为“非法”的数据&lt;/p&gt;&#xA;&lt;h2 id=&#34;抓个包&#34;&gt;抓个包&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/15e68df2ba9aa7cace3e26e35c79f200.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/ebebd3ea7d306ad2fcd311f1d8b46cc0.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;嗯，明文传输无误。这是有问题的，接下将改造我们的 gRPC，以便于解决这个问题 😤&lt;/p&gt;&#xA;&lt;h2 id=&#34;证书生成&#34;&gt;证书生成&lt;/h2&gt;&#xA;&lt;h3 id=&#34;私钥&#34;&gt;私钥&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl ecparam -genkey -name secp384r1 -out server.key&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;自签公钥&#34;&gt;自签公钥&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;填写信息&#34;&gt;填写信息&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Country Name (2 letter code) []:&#xA;State or Province Name (full name) []:&#xA;Locality Name (eg, city) []:&#xA;Organization Name (eg, company) []:&#xA;Organizational Unit Name (eg, section) []:&#xA;Common Name (eg, fully qualified host name) []:go-grpc-example&#xA;Email Address []:&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;生成完毕&#34;&gt;生成完毕&lt;/h3&gt;&#xA;&lt;p&gt;生成证书结束后，将证书相关文件放到 conf/ 下，目录结构：&lt;/p&gt;</description>
    </item>
    <item>
      <title>log 标准库</title>
      <link>https://note.lican.site/posts/posts/go/pkg/2018-09-28-log/</link>
      <pubDate>Fri, 28 Sep 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/pkg/2018-09-28-log/</guid>
      <description>&lt;h2 id=&#34;日志&#34;&gt;日志&lt;/h2&gt;&#xA;&lt;h3 id=&#34;输出&#34;&gt;输出&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;2018/09/28 20:03:08 EDDYCJY Blog...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;构成&#34;&gt;构成&lt;/h3&gt;&#xA;&lt;p&gt;[日期]&amp;lt;空格&amp;gt;[时分秒]&amp;lt;空格&amp;gt;[内容]&amp;lt;\n&amp;gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;源码剖析&#34;&gt;源码剖析&lt;/h2&gt;&#xA;&lt;h3 id=&#34;logger&#34;&gt;Logger&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;type Logger struct {&#xA;&#x9;mu     sync.Mutex &#xA;&#x9;prefix string&#xA;&#x9;flag   int&#xA;&#x9;out    io.Writer&#xA;&#x9;buf    []byte&#xA;}&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&#xA;&lt;li&gt;mu：互斥锁，用于确保原子的写入&lt;/li&gt;&#xA;&lt;li&gt;prefix：每行需写入的日志前缀内容&lt;/li&gt;&#xA;&lt;li&gt;flag：设置日志辅助信息（时间、文件名、行号）的写入。可选如下标识位：&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;const (&#xA;&#x9;Ldate         = 1 &amp;lt;&amp;lt; iota       // value: 1&#xA;&#x9;Ltime                           // value: 2&#xA;&#x9;Lmicroseconds                   // value: 4&#xA;&#x9;Llongfile                       // value: 8&#xA;&#x9;Lshortfile                      // value: 16&#xA;&#x9;LUTC                            // value: 32&#xA;&#x9;LstdFlags     = Ldate | Ltime   // value: 3&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;Ldate：当地时区的格式化日期：2009/01/23&lt;/li&gt;&#xA;&lt;li&gt;Ltime：当地时区的格式化时间：01:23:23&lt;/li&gt;&#xA;&lt;li&gt;Lmicroseconds：在 Ltime 的基础上，增加微秒的时间数值显示&lt;/li&gt;&#xA;&lt;li&gt;Llongfile：完整的文件名和行号：/a/b/c/d.go:23&lt;/li&gt;&#xA;&lt;li&gt;Lshortfile：当前文件名和行号：d.go：23，会覆盖 Llongfile 标识&lt;/li&gt;&#xA;&lt;li&gt;LUTC：如果设置 Ldate 或 Ltime，且设置 LUTC，则优先使用 UTC 时区而不是本地时区&lt;/li&gt;&#xA;&lt;li&gt;LstdFlags：Logger 的默认初始值（Ldate 和 Ltime）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;ol start=&#34;4&#34;&gt;&#xA;&lt;li&gt;out：io.Writer&lt;/li&gt;&#xA;&lt;li&gt;buf：用于存储将要写入的日志内容&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h3 id=&#34;new&#34;&gt;New&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func New(out io.Writer, prefix string, flag int) *Logger {&#xA;&#x9;return &amp;amp;Logger{out: out, prefix: prefix, flag: flag}&#xA;}&#xA;&#xA;var std = New(os.Stderr, &amp;#34;&amp;#34;, LstdFlags)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;New 方法用于初始化 Logger，接受三个初始参数，可以定制化而在 log 包内默认会初始一个 std，它指向标准输入流。而默认的标准输出、标准错误就是显示器（输出到屏幕上），标准输入就是键盘。辅助的时间信息默认为 &lt;code&gt;Ldate | Ltime&lt;/code&gt;，也就是 &lt;code&gt;2009/01/23 01:23:23&lt;/code&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载三」gRPC Streaming, Client and Server</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-09-24-stream-client-server/</link>
      <pubDate>Mon, 24 Sep 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-09-24-stream-client-server/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;本章节将介绍 gRPC 的流式，分为三种类型：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Server-side streaming RPC：服务器端流式 RPC&lt;/li&gt;&#xA;&lt;li&gt;Client-side streaming RPC：客户端流式 RPC&lt;/li&gt;&#xA;&lt;li&gt;Bidirectional streaming RPC：双向流式 RPC&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;流&#34;&gt;流&lt;/h2&gt;&#xA;&lt;p&gt;任何技术，因为有痛点，所以才有了存在的必要性。如果您想要了解 gRPC 的流式调用，请继续&lt;/p&gt;&#xA;&lt;h3 id=&#34;图&#34;&gt;图&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/8812038d20ffece377c0e4901c9a9231.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;gRPC Streaming 是基于 HTTP/2 的，后续章节再进行详细讲解&lt;/p&gt;&#xA;&lt;h3 id=&#34;为什么不用-simple-rpc&#34;&gt;为什么不用 Simple RPC&lt;/h3&gt;&#xA;&lt;p&gt;流式为什么要存在呢，是 Simple RPC 有什么问题吗？通过模拟业务场景，可得知在使用 Simple RPC 时，有如下问题：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;数据包过大造成的瞬时压力&lt;/li&gt;&#xA;&lt;li&gt;接收数据包时，需要所有数据包都接受成功且正确后，才能够回调响应，进行业务处理（无法客户端边发送，服务端边处理）&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;为什么用-streaming-rpc&#34;&gt;为什么用 Streaming RPC&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;大规模数据包&lt;/li&gt;&#xA;&lt;li&gt;实时场景&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;模拟场景&#34;&gt;模拟场景&lt;/h4&gt;&#xA;&lt;p&gt;每天早上 6 点，都有一批百万级别的数据集要同从 A 同步到 B，在同步的时候，会做一系列操作（归档、数据分析、画像、日志等）。这一次性涉及的数据量确实大&lt;/p&gt;&#xA;&lt;p&gt;在同步完成后，也有人马上会去查阅数据，为了新的一天筹备。也符合实时性。&lt;/p&gt;&#xA;&lt;p&gt;两者相较下，这个场景下更适合使用 Streaming RPC&lt;/p&gt;&#xA;&lt;h2 id=&#34;grpc&#34;&gt;gRPC&lt;/h2&gt;&#xA;&lt;p&gt;在讲解具体的 gRPC 流式代码时，会&lt;strong&gt;着重在第一节讲解&lt;/strong&gt;，因为三种模式其实是不同的组合。希望你能够注重理解，举一反三，其实都是一样的知识点 👍&lt;/p&gt;&#xA;&lt;h3 id=&#34;目录结构&#34;&gt;目录结构&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ tree go-grpc-example&#xA;go-grpc-example&#xA;├── client&#xA;│   ├── simple_client&#xA;│   │   └── client.go&#xA;│   └── stream_client&#xA;│       └── client.go&#xA;├── proto&#xA;│   ├── search.proto&#xA;│   └── stream.proto&#xA;└── server&#xA;    ├── simple_server&#xA;    │   └── server.go&#xA;    └── stream_server&#xA;        └── server.go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;增加 stream_server、stream_client 存放服务端和客户端文件，proto/stream.proto 用于编写 IDL&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载二」gRPC Client and Server</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-09-23-client-and-server/</link>
      <pubDate>Sun, 23 Sep 2018 12:30:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-09-23-client-and-server/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;本章节将使用 Go 来编写 gRPC Server 和 Client，让其互相通讯。在此之上会使用到如下库：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;google.golang.org/grpc&lt;/li&gt;&#xA;&lt;li&gt;github.com/golang/protobuf/protoc-gen-go&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;&#xA;&lt;h3 id=&#34;grpc&#34;&gt;gRPC&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u google.golang.org/grpc&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;protocol-buffers-v3&#34;&gt;Protocol Buffers v3&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;wget https://github.com/google/protobuf/releases/download/v3.5.1/protobuf-all-3.5.1.zip&#xA;unzip protobuf-all-3.5.1.zip&#xA;cd protobuf-3.5.1/&#xA;./configure&#xA;make&#xA;make install&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;检查是否安装成功&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;protoc --version&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;若出现以下错误，执行 &lt;code&gt;ldconfig&lt;/code&gt; 命名就能解决这问题&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;protoc: error while loading shared libraries: libprotobuf.so.15: cannot open shared object file: No such file or directory&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;protoc-plugin&#34;&gt;Protoc Plugin&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u github.com/golang/protobuf/protoc-gen-go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;安装环境若有问题，可参考我先前的文章 &lt;a href=&#34;https://segmentfault.com/a/1190000013339403&#34;&gt;《介绍与环境安装》&lt;/a&gt; 内有详细介绍，不再赘述&lt;/p&gt;&#xA;&lt;h2 id=&#34;grpc-1&#34;&gt;gRPC&lt;/h2&gt;&#xA;&lt;p&gt;本小节开始正式编写 gRPC 相关的程序，一起上车吧 😄&lt;/p&gt;&#xA;&lt;h3 id=&#34;图示&#34;&gt;图示&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://image.eddycjy.com/415d9544fce1e774e1095ab99b6cc015.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;目录结构&#34;&gt;目录结构&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ tree go-grpc-example&#xA;go-grpc-example&#xA;├── client&#xA;├── proto&#xA;│   └── search.proto&#xA;└── server.go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;idl&#34;&gt;IDL&lt;/h3&gt;&#xA;&lt;h4 id=&#34;编写&#34;&gt;编写&lt;/h4&gt;&#xA;&lt;p&gt;在 proto 文件夹下的 search.proto 文件中，写入如下内容：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载一」gRPC及相关介绍</title>
      <link>https://note.lican.site/posts/posts/go/grpc/2018-09-22-install/</link>
      <pubDate>Sat, 22 Sep 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc/2018-09-22-install/</guid>
      <description>&lt;p&gt;项目地址：https://github.com/EDDYCJY/go-grpc-example&lt;/p&gt;&#xA;&lt;p&gt;作为开篇章，将会介绍 gRPC 相关的一些知识。简单来讲 gRPC 是一个 基于 HTTP/2 协议设计的 RPC 框架，它采用了 Protobuf 作为 IDL&lt;/p&gt;&#xA;&lt;p&gt;你是否有过疑惑，它们都是些什么？本文将会介绍一些常用的知识和概念，更详细的会给出手册地址去深入&lt;/p&gt;&#xA;&lt;h2 id=&#34;一rpc&#34;&gt;一、RPC&lt;/h2&gt;&#xA;&lt;h3 id=&#34;什么是-rpc&#34;&gt;什么是 RPC&lt;/h3&gt;&#xA;&lt;p&gt;RPC 代指远程过程调用（Remote Procedure Call），它的调用包含了传输协议和编码（对象序列号）协议等等。允许运行于一台计算机的程序调用另一台计算机的子程序，而开发人员无需额外地为这个交互作用编程&lt;/p&gt;&#xA;&lt;h4 id=&#34;实际场景&#34;&gt;实际场景：&lt;/h4&gt;&#xA;&lt;p&gt;有两台服务器，分别是 A、B。在 A 上的应用 C 想要调用 B 服务器上的应用 D，它们可以直接本地调用吗？&lt;br&gt;&#xA;答案是不能的，但走 RPC 的话，十分方便。因此常有人称使用 RPC，就跟本地调用一个函数一样简单&lt;/p&gt;&#xA;&lt;h3 id=&#34;rpc-框架&#34;&gt;RPC 框架&lt;/h3&gt;&#xA;&lt;p&gt;我认为，一个完整的 RPC 框架，应包含负载均衡、服务注册和发现、服务治理等功能，并具有可拓展性便于流量监控系统等接入&lt;br&gt;&#xA;那么它才算完整的，当然了。有些较单一的 RPC 框架，通过组合多组件也能达到这个标准&lt;/p&gt;&#xA;&lt;p&gt;你认为呢？&lt;/p&gt;&#xA;&lt;h3 id=&#34;常见-rpc-框架&#34;&gt;常见 RPC 框架&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://grpc.io/&#34;&gt;gRPC&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/apache/thrift&#34;&gt;Thrift&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/smallnest/rpcx&#34;&gt;Rpcx&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/apache/incubator-dubbo&#34;&gt;Dubbo&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;比较一下&#34;&gt;比较一下&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;\&lt;/th&gt;&#xA;          &lt;th&gt;跨语言&lt;/th&gt;&#xA;          &lt;th&gt;多 IDL&lt;/th&gt;&#xA;          &lt;th&gt;服务治理&lt;/th&gt;&#xA;          &lt;th&gt;注册中心&lt;/th&gt;&#xA;          &lt;th&gt;服务管理&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;gRPC&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Thrift&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Rpcx&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;Dubbo&lt;/td&gt;&#xA;          &lt;td&gt;×&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;          &lt;td&gt;√&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;h3 id=&#34;为什么要-rpc&#34;&gt;为什么要 RPC&lt;/h3&gt;&#xA;&lt;p&gt;简单、通用、安全、效率&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 大杀器之性能剖析 PProf</title>
      <link>https://note.lican.site/posts/posts/go/tools/2018-09-15-go-tool-pprof/</link>
      <pubDate>Sat, 15 Sep 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/tools/2018-09-15-go-tool-pprof/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;写了几吨代码，实现了几百个接口。功能测试也通过了，终于成功的部署上线了&lt;/p&gt;&#xA;&lt;p&gt;结果，性能不佳，什么鬼？😭&lt;/p&gt;&#xA;&lt;h2 id=&#34;想做性能分析&#34;&gt;想做性能分析&lt;/h2&gt;&#xA;&lt;h3 id=&#34;pprof&#34;&gt;PProf&lt;/h3&gt;&#xA;&lt;p&gt;想要进行性能优化，首先瞩目在 Go 自身提供的工具链来作为分析依据，本文将带你学习、使用 Go 后花园，涉及如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;runtime/pprof：采集程序（非 Server）的运行数据进行分析&lt;/li&gt;&#xA;&lt;li&gt;net/http/pprof：采集 HTTP Server 的运行时数据进行分析&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;是什么&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;p&gt;pprof 是用于可视化和分析性能分析数据的工具&lt;/p&gt;&#xA;&lt;p&gt;pprof 以 &lt;a href=&#34;https://github.com/google/pprof/blob/master/proto/profile.proto&#34;&gt;profile.proto&lt;/a&gt; 读取分析样本的集合，并生成报告以可视化并帮助分析数据（支持文本和图形报告）&lt;/p&gt;&#xA;&lt;p&gt;profile.proto 是一个 Protocol Buffer v3 的描述文件，它描述了一组 callstack 和 symbolization 信息， 作用是表示统计分析的一组采样的调用栈，是很常见的 stacktrace 配置文件格式&lt;/p&gt;&#xA;&lt;h3 id=&#34;支持什么使用模式&#34;&gt;支持什么使用模式&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Report generation：报告生成&lt;/li&gt;&#xA;&lt;li&gt;Interactive terminal use：交互式终端使用&lt;/li&gt;&#xA;&lt;li&gt;Web interface：Web 界面&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;可以做什么&#34;&gt;可以做什么&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;CPU Profiling：CPU 分析，按照一定的频率采集所监听的应用程序 CPU（含寄存器）的使用情况，可确定应用程序在主动消耗 CPU 周期时花费时间的位置&lt;/li&gt;&#xA;&lt;li&gt;Memory Profiling：内存分析，在应用程序进行堆分配时记录堆栈跟踪，用于监视当前和历史内存使用情况，以及检查内存泄漏&lt;/li&gt;&#xA;&lt;li&gt;Block Profiling：阻塞分析，记录 goroutine 阻塞等待同步（包括定时器通道）的位置&lt;/li&gt;&#xA;&lt;li&gt;Mutex Profiling：互斥锁分析，报告互斥锁的竞争情况&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;一个简单的例子&#34;&gt;一个简单的例子&lt;/h2&gt;&#xA;&lt;p&gt;我们将编写一个简单且有点问题的例子，用于基本的程序初步分析&lt;/p&gt;&#xA;&lt;h3 id=&#34;编写-demo-文件&#34;&gt;编写 demo 文件&lt;/h3&gt;&#xA;&lt;p&gt;（1）demo.go，文件内容：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;net/http/pprof&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-pprof-example/data&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Println&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;data&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;https://github.com/EDDYCJY&amp;#34;&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ListenAndServe&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0.0.0.0:6060&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;（2）data/d.go，文件内容：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十七」用Nginx部署Go应用</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-09-01-nginx/</link>
      <pubDate>Sat, 01 Sep 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-09-01-nginx/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Nginx。&lt;/li&gt;&#xA;&lt;li&gt;反向代理。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;简单部署后端服务。&lt;/p&gt;&#xA;&lt;h2 id=&#34;做什么&#34;&gt;做什么&lt;/h2&gt;&#xA;&lt;p&gt;在本章节，我们将简单介绍 Nginx 以及使用 Nginx 来完成对 &lt;a href=&#34;https://github.com/EDDYCJY/go-gin-example&#34;&gt;go-gin-example&lt;/a&gt; 的部署，会实现反向代理和简单负载均衡的功能。&lt;/p&gt;&#xA;&lt;h2 id=&#34;nginx&#34;&gt;Nginx&lt;/h2&gt;&#xA;&lt;h3 id=&#34;是什么&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;p&gt;Nginx 是一个 Web Server，可以用作反向代理、负载均衡、邮件代理、TCP / UDP、HTTP 服务器等等，它拥有很多吸引人的特性，例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;以较低的内存占用率处理 10,000 多个并发连接（每 10k 非活动 HTTP 保持活动连接约 2.5 MB ）&lt;/li&gt;&#xA;&lt;li&gt;静态服务器（处理静态文件）&lt;/li&gt;&#xA;&lt;li&gt;正向、反向代理&lt;/li&gt;&#xA;&lt;li&gt;负载均衡&lt;/li&gt;&#xA;&lt;li&gt;通过 OpenSSL 对 TLS / SSL 与 SNI 和 OCSP 支持&lt;/li&gt;&#xA;&lt;li&gt;FastCGI、SCGI、uWSGI 的支持&lt;/li&gt;&#xA;&lt;li&gt;WebSockets、HTTP/1.1 的支持&lt;/li&gt;&#xA;&lt;li&gt;Nginx + Lua&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;安装&#34;&gt;安装&lt;/h3&gt;&#xA;&lt;p&gt;请右拐谷歌或百度，安装好 Nginx 以备接下来的使用&lt;/p&gt;&#xA;&lt;h3 id=&#34;简单讲解&#34;&gt;简单讲解&lt;/h3&gt;&#xA;&lt;h4 id=&#34;常用命令&#34;&gt;常用命令&lt;/h4&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;nginx：启动 Nginx&lt;/li&gt;&#xA;&lt;li&gt;nginx -s stop：立刻停止 Nginx 服务&lt;/li&gt;&#xA;&lt;li&gt;nginx -s reload：重新加载配置文件&lt;/li&gt;&#xA;&lt;li&gt;nginx -s quit：平滑停止 Nginx 服务&lt;/li&gt;&#xA;&lt;li&gt;nginx -t：测试配置文件是否正确&lt;/li&gt;&#xA;&lt;li&gt;nginx -v：显示 Nginx 版本信息&lt;/li&gt;&#xA;&lt;li&gt;nginx -V：显示 Nginx 版本信息、编译器和配置参数的信息&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;涉及配置&#34;&gt;涉及配置&lt;/h4&gt;&#xA;&lt;p&gt;1、 proxy_pass：配置&lt;strong&gt;反向代理的路径&lt;/strong&gt;。需要注意的是如果 proxy_pass 的 url 最后为&#xA;/，则表示绝对路径。否则（不含变量下）表示相对路径，所有的路径都会被代理过去&lt;/p&gt;</description>
    </item>
    <item>
      <title>「番外」请入门 Makefile</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-08-26-makefile/</link>
      <pubDate>Sun, 26 Aug 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-08-26-makefile/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;写一个 Makefile&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;含一定复杂度的软件工程，基本上都是先编译 A，再依赖 B，再编译 C&amp;hellip;，最后才执行构建。如果每次都人为编排，又或是每新来一个同事就问你项目 D 怎么构建、重新构建需要注意什么&amp;hellip;等等情况，岂不是要崩溃？&lt;/p&gt;&#xA;&lt;p&gt;我们常常会在开源项目中发现 Makefile，你是否有过疑问？&lt;/p&gt;&#xA;&lt;p&gt;本章节会简单介绍 Makefile 的使用方式，最后建议深入学习。&lt;/p&gt;&#xA;&lt;h2 id=&#34;怎么解决&#34;&gt;怎么解决&lt;/h2&gt;&#xA;&lt;p&gt;对于构建编排，Docker 有 Dockerfile ，在 Unix 中有神器 &lt;a href=&#34;https://en.wikipedia.org/wiki/Make_%28software%29&#34;&gt;Make&lt;/a&gt; &amp;hellip;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;make&#34;&gt;Make&lt;/h2&gt;&#xA;&lt;h3 id=&#34;是什么&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;p&gt;Make 是一个构建自动化工具，会在当前目录下寻找 Makefile 或 makefile 文件。如果存在，会依据 Makefile 的&lt;strong&gt;构建规则&lt;/strong&gt;去完成构建&lt;/p&gt;&#xA;&lt;p&gt;当然了，实际上 Makefile 内都是你根据 make 语法规则，自己编写的特定 Shell 命令等&lt;/p&gt;&#xA;&lt;p&gt;它是一个工具，规则也很简单。在支持的范围内，编译 A， 依赖 B，再编译 C，完全没问题&lt;/p&gt;&#xA;&lt;h3 id=&#34;规则&#34;&gt;规则&lt;/h3&gt;&#xA;&lt;p&gt;Makefile 由多条规则组成，每条规则都以一个 target（目标）开头，后跟一个 : 冒号，冒号后是这一个目标的 prerequisites（前置条件）&lt;/p&gt;&#xA;&lt;p&gt;紧接着新的一行，必须以一个 tab 作为开头，后面跟随 command（命令），也就是你希望这一个 target 所执行的构建命令&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[target] ... : [prerequisites] ...&#xA;&amp;lt;tab&amp;gt;[command]&#xA;    ...&#xA;    ...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;target：一个目标代表一条规则，可以是一个或多个文件名。也可以是某个操作的名字（标签），称为&lt;strong&gt;伪目标（phony）&lt;/strong&gt;&lt;/li&gt;&#xA;&lt;li&gt;prerequisites：前置条件，这一项是&lt;strong&gt;可选参数&lt;/strong&gt;。通常是多个文件名、伪目标。它的作用是 target 是否需要重新构建的标准，如果前置条件不存在或有过更新（文件的最后一次修改时间）则认为 target 需要重新构建&lt;/li&gt;&#xA;&lt;li&gt;command：构建这一个 target 的具体命令集&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;简单的例子&#34;&gt;简单的例子&lt;/h3&gt;&#xA;&lt;p&gt;本文将以 &lt;a href=&#34;https://github.com/EDDYCJY/go-gin-example&#34;&gt;go-gin-example&lt;/a&gt; 去编写 Makefile 文件，请跨入 make 的大门&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十六」在图片上绘制文字</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-07-07-font/</link>
      <pubDate>Sat, 07 Jul 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-07-07-font/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;字体库使用&lt;/li&gt;&#xA;&lt;li&gt;图片合成&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;主要实现&lt;strong&gt;合并后的海报上绘制文字&lt;/strong&gt;的功能（这个需求也是常见的很了），内容比较简单。&lt;/p&gt;&#xA;&lt;h2 id=&#34;实现&#34;&gt;实现&lt;/h2&gt;&#xA;&lt;p&gt;这里使用的是 &lt;a href=&#34;https://github.com/EDDYCJY/go-gin-example/blob/master/runtime/fonts/msyhbd.ttc&#34;&gt;微软雅黑&lt;/a&gt; 的字体，请点击进行下载并&lt;strong&gt;存放到 runtime/fonts 目录&lt;/strong&gt;下（字体文件占 16 MB 大小）&lt;/p&gt;&#xA;&lt;h3 id=&#34;安装&#34;&gt;安装&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get -u github.com/golang/freetype&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;绘制文字&#34;&gt;绘制文字&lt;/h3&gt;&#xA;&lt;p&gt;打开 service/article_service/article_poster.go 文件，增加绘制文字的业务逻辑，如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DrawText&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;JPG&lt;/span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;draw&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Image&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Merged&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;File&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Title&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;X0&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Y0&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Size0&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;SubTitle&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;X1&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Y1&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Size1&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;float64&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ArticlePosterBg&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;DrawPoster&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;DrawText&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;fontName&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fontSource&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RuntimeRootPath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FontSavePath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fontName&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fontSourceBytes&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ioutil&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadFile&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fontSource&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;trueTypeFont&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;freetype&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ParseFont&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fontSourceBytes&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;freetype&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewContext&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetDPI&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;72&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetFont&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;trueTypeFont&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetFontSize&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Size0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetClip&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JPG&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bounds&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetDst&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JPG&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetSrc&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;image&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Black&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;pt&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;freetype&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pt&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;X0&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Y0&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DrawString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Title&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;pt&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetFontSize&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Size1&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;fc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DrawString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SubTitle&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;freetype&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Pt&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;X1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Y1&lt;/span&gt;))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;jpeg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Encode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Merged&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;d&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JPG&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里主要使用了 freetype 包，分别涉及如下细项：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十五」生成二维码、合并海报</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-07-05-image/</link>
      <pubDate>Thu, 05 Jul 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-07-05-image/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;图片生成&lt;/li&gt;&#xA;&lt;li&gt;二维码生成&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在文章的详情页中，我们常常会需要去宣传它，而目前最常见的就是发海报了，今天我们将实现如下功能：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;生成二维码&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;合并海报（背景图 + 二维码）&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;实现&#34;&gt;实现&lt;/h2&gt;&#xA;&lt;p&gt;首先，你需要在 App 配置项中增加二维码及其海报的存储路径，我们约定配置项名称为 &lt;code&gt;QrCodeSavePath&lt;/code&gt;，值为 &lt;code&gt;qrcode/&lt;/code&gt;，经过多节连载的你应该能够完成，若有不懂可参照 &lt;a href=&#34;https://github.com/EDDYCJY/go-gin-example/blob/master/conf/app.ini#L14&#34;&gt;go-gin-example&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;h2 id=&#34;生成二维码&#34;&gt;生成二维码&lt;/h2&gt;&#xA;&lt;h3 id=&#34;安装&#34;&gt;安装&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get -u github.com/boombuler/barcode&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;工具包&#34;&gt;工具包&lt;/h3&gt;&#xA;&lt;p&gt;考虑生成二维码这一动作贴合工具包的定义，且有公用的可能性，新建 pkg/qrcode/qrcode.go 文件，写入内容：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;qrcode&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image/jpeg&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/boombuler/barcode&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/boombuler/barcode/qr&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/pkg/file&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/pkg/setting&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/pkg/util&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;QrCode&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Width&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Height&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Ext&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Level&lt;/span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;qr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrorCorrectionLevel&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Mode&lt;/span&gt;   &lt;span style=&#34;color:#a6e22e&#34;&gt;qr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Encoding&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;EXT_JPG&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.jpg&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;NewQrCode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;level&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;qr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ErrorCorrectionLevel&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;mode&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;qr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Encoding&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCode&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCode&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Width&lt;/span&gt;:  &lt;span style=&#34;color:#a6e22e&#34;&gt;width&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Height&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;height&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Level&lt;/span&gt;:  &lt;span style=&#34;color:#a6e22e&#34;&gt;level&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Mode&lt;/span&gt;:   &lt;span style=&#34;color:#a6e22e&#34;&gt;mode&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Ext&lt;/span&gt;:    &lt;span style=&#34;color:#a6e22e&#34;&gt;EXT_JPG&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodePath&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCodeSavePath&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeFullPath&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RuntimeRootPath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCodeSavePath&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeFullUrl&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PrefixUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodePath&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeFileName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;util&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EncodeMD5&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCode&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeExt&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Ext&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCode&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;CheckEncode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeFileName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeExt&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CheckNotExist&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;false&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;QrCode&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;Encode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeFileName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetQrCodeExt&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CheckNotExist&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;qr&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Encode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;URL&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Level&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mode&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;barcode&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Scale&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Width&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;q&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Height&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;file&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustOpen&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;defer&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Close&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;jpeg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Encode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;f&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;path&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里主要聚焦 &lt;code&gt;func (q *QrCode) Encode&lt;/code&gt; 方法，做了如下事情：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十四」实现导出、导入 Excel</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-06-14-excel/</link>
      <pubDate>Thu, 14 Jun 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-06-14-excel/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;导出功能的实现&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在本节，我们将实现对标签信息的导出、导入功能，这是很标配功能了，希望你掌握基础的使用方式。&lt;/p&gt;&#xA;&lt;p&gt;另外在本文我们使用了 2 个 Excel 的包，excelize 最初的 XML 格式文件的一些结构，是通过 tealeg/xlsx 格式文件结构演化而来的，因此特意在此都展示了，你可以根据自己的场景和喜爱去使用。&lt;/p&gt;&#xA;&lt;h2 id=&#34;配置&#34;&gt;配置&lt;/h2&gt;&#xA;&lt;p&gt;首先要指定导出的 Excel 文件的存储路径，在 app.ini 中增加配置：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;[app]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExportSavePath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;export/&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;修改 setting.go 的 App struct：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;App&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;JwtSecret&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;PageSize&lt;/span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;PrefixUrl&lt;/span&gt;       &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;RuntimeRootPath&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ImageSavePath&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ImageMaxSize&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ImageAllowExts&lt;/span&gt; []&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExportSavePath&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;LogSavePath&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;LogSaveName&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;LogFileExt&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;TimeFormat&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这里需增加 ExportSavePath 配置项，另外将先前 ImagePrefixUrl 改为 PrefixUrl 用于支撑两者的 HOST 获取&lt;/p&gt;&#xA;&lt;p&gt;（注意修改 image.go 的 GetImageFullUrl 方法）&lt;/p&gt;&#xA;&lt;h2 id=&#34;pkg&#34;&gt;pkg&lt;/h2&gt;&#xA;&lt;p&gt;新建 pkg/export/excel.go 文件，如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;export&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/pkg/setting&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetExcelFullUrl&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PrefixUrl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetExcelPath&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;name&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetExcelPath&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ExportSavePath&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetExcelFullPath&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AppSetting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RuntimeRootPath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetExcelPath&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里编写了一些常用的方法，以后取值方式如果有变动，直接改内部代码即可，对外不可见&lt;/p&gt;</description>
    </item>
    <item>
      <title>用 Go 来了解一下 Redis 通讯协议</title>
      <link>https://note.lican.site/posts/posts/go/talk/2018-06-07-go-redis-protocol/</link>
      <pubDate>Thu, 07 Jun 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2018-06-07-go-redis-protocol/</guid>
      <description>&lt;p&gt;Go、PHP、Java&amp;hellip; 都有那么多包来支撑你使用 Redis，那你是否有想过&lt;/p&gt;&#xA;&lt;p&gt;有了服务端，有了客户端，他们俩是怎样通讯，又是基于什么通讯协议做出交互的呢？&lt;/p&gt;&#xA;&lt;h2 id=&#34;介绍&#34;&gt;介绍&lt;/h2&gt;&#xA;&lt;p&gt;基于我们的目的，本文主要讲解和实践 Redis 的通讯协议&lt;/p&gt;&#xA;&lt;p&gt;Redis 的客户端和服务端是通过 TCP 连接来进行数据交互， 服务器默认的端口号为 6379&lt;/p&gt;&#xA;&lt;p&gt;客户端和服务器发送的命令或数据一律以 \r\n （CRLF）结尾（这是一条约定）&lt;/p&gt;&#xA;&lt;h2 id=&#34;协议&#34;&gt;协议&lt;/h2&gt;&#xA;&lt;p&gt;在 Redis 中分为&lt;strong&gt;请求&lt;/strong&gt;和&lt;strong&gt;回复&lt;/strong&gt;，而请求协议又分为新版和旧版，新版统一请求协议在 Redis 1.2 版本中引入，最终在 Redis 2.0 版本成为 Redis 服务器通信的标准方式&lt;/p&gt;&#xA;&lt;p&gt;本文是基于新版协议来实现功能，不建议使用旧版（1.2 挺老旧了）。如下是新协议的各种范例：&lt;/p&gt;&#xA;&lt;h3 id=&#34;请求协议&#34;&gt;请求协议&lt;/h3&gt;&#xA;&lt;p&gt;1、 格式示例&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;*&amp;lt;参数数量&amp;gt; CR LF&#xA;$&amp;lt;参数 1 的字节数量&amp;gt; CR LF&#xA;&amp;lt;参数 1 的数据&amp;gt; CR LF&#xA;...&#xA;$&amp;lt;参数 N 的字节数量&amp;gt; CR LF&#xA;&amp;lt;参数 N 的数据&amp;gt; CR LF&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;在该协议下所有发送至 Redis 服务器的参数都是二进制安全（binary safe）的&lt;/p&gt;&#xA;&lt;p&gt;2、打印示例&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;*3&#xA;$3&#xA;SET&#xA;$5&#xA;mykey&#xA;$7&#xA;myvalue&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;3、实际协议值&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;#34;*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$7\r\nmyvalue\r\n&amp;#34;&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这就是 Redis 的请求协议规范，按照范例1编写客户端逻辑，最终发送的是范例3，相信你已经有大致的概念了，Redis 的协议非常的简洁易懂，这也是好上手的原因之一，你可以想想协议这么定义的好处在哪？&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十三」优化你的应用结构和实现Redis缓存</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-06-02-application-redis/</link>
      <pubDate>Sat, 02 Jun 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-06-02-application-redis/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;之前就在想，不少教程或示例的代码设计都是一步到位的（也没问题）&lt;/p&gt;&#xA;&lt;p&gt;但实际操作的读者真的能够理解透彻为什么吗？左思右想，有了今天这一章的内容，我认为实际经历过一遍印象会更加深刻&lt;/p&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在本章节，将介绍以下功能的整理：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;抽离、分层业务逻辑：减轻 routers.go 内的 api 方法的逻辑（但本文暂不分层 repository，这块逻辑还不重）。&lt;/li&gt;&#xA;&lt;li&gt;增加容错性：对 gorm 的错误进行判断。&lt;/li&gt;&#xA;&lt;li&gt;Redis 缓存：对获取数据类的接口增加缓存设置。&lt;/li&gt;&#xA;&lt;li&gt;减少重复冗余代码。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;问题在哪&#34;&gt;问题在哪？&lt;/h2&gt;&#xA;&lt;p&gt;在规划阶段我们发现了一个问题，这是目前的伪代码：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! &lt;span style=&#34;color:#a6e22e&#34;&gt;HasErrors&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ExistArticleByID&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteArticle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SUCCESS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ERROR_NOT_EXIST_ARTICLE&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;valid&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Errors&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;logging&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Message&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusOK&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;:  &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetMsg&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果加上规划内的功能逻辑呢，伪代码会变成：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; ! &lt;span style=&#34;color:#a6e22e&#34;&gt;HasErrors&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;exists&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ExistArticleByID&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;exists&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteArticle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;id&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;    &lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SUCCESS&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;    &lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ERROR_XXX&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ERROR_NOT_EXIST_ARTICLE&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ERROR_XXX&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;range&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;valid&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Errors&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;logging&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Info&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Message&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JSON&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;http&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusOK&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;H&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;code&amp;#34;&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;msg&amp;#34;&lt;/span&gt;:  &lt;span style=&#34;color:#a6e22e&#34;&gt;e&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetMsg&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;code&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;data&amp;#34;&lt;/span&gt;: make(&lt;span style=&#34;color:#66d9ef&#34;&gt;map&lt;/span&gt;[&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;]&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果缓存的逻辑也加进来，后面慢慢不断的迭代，岂不是会变成如下图一样？&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十二」优化配置结构及实现图片上传</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-05-27-config-upload/</link>
      <pubDate>Sun, 27 May 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-05-27-config-upload/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;重构、调整结构&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;这个应用程序跑了那么久了，越来越大，越来越壮，仿佛我们的产品一样，现在它需要进行小范围重构了，以便于后续的使用，这非常重要。&lt;/p&gt;&#xA;&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;一天，产品经理突然跟你说文章列表，没有封面图，不够美观，！）&amp;amp;￥&lt;em&gt;！&amp;amp;）#&amp;amp;￥&lt;/em&gt;！加一个吧，几分钟的事&lt;/p&gt;&#xA;&lt;p&gt;你打开你的程序，分析了一波写了个清单：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;优化配置结构（因为配置项越来越多）&lt;/li&gt;&#xA;&lt;li&gt;抽离 原 logging 的 File 便于公用（logging、upload 各保有一份并不合适）&lt;/li&gt;&#xA;&lt;li&gt;实现上传图片接口（需限制文件格式、大小）&lt;/li&gt;&#xA;&lt;li&gt;修改文章接口（需支持封面地址参数）&lt;/li&gt;&#xA;&lt;li&gt;增加 blog_article （文章）的数据库字段&lt;/li&gt;&#xA;&lt;li&gt;实现 http.FileServer&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;嗯，你发现要较优的话，需要调整部分的应用程序结构，因为功能越来越多，原本的设计也要跟上节奏&lt;/p&gt;&#xA;&lt;p&gt;也就是在适当的时候，及时优化&lt;/p&gt;&#xA;&lt;h2 id=&#34;优化配置结构&#34;&gt;优化配置结构&lt;/h2&gt;&#xA;&lt;h3 id=&#34;一讲解&#34;&gt;一、讲解&lt;/h3&gt;&#xA;&lt;p&gt;在先前章节中，采用了直接读取 KEY 的方式去存储配置项，而本次需求中，需要增加图片的配置项，总体就有些冗余了&lt;/p&gt;&#xA;&lt;p&gt;我们采用以下解决方法：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;映射结构体：使用 MapTo 来设置配置参数&lt;/li&gt;&#xA;&lt;li&gt;配置统管：所有的配置项统管到 setting 中&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;映射结构体示例&#34;&gt;映射结构体（示例）&lt;/h4&gt;&#xA;&lt;p&gt;在 go-ini 中可以采用 MapTo 的方式来映射结构体，例如：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Server&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;RunMode&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;HttpPort&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ReadTimeout&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;WriteTimeout&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Duration&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ServerSetting&lt;/span&gt; = &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Server&lt;/span&gt;{}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Cfg&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ini&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Load&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;conf/app.ini&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Fail to parse &amp;#39;conf/app.ini&amp;#39;: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;Cfg&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Section&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;MapTo&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ServerSetting&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Cfg.MapTo ServerSetting err: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这段代码中，可以注意 ServerSetting 取了地址，为什么 MapTo 必须地址入参呢？&lt;/p&gt;</description>
    </item>
    <item>
      <title>Go 的 fake-useragent 了解一下</title>
      <link>https://note.lican.site/posts/posts/go/talk/2018-05-21-go-fake-useragent/</link>
      <pubDate>Mon, 21 May 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2018-05-21-go-fake-useragent/</guid>
      <description>&lt;p&gt;有的网站会根据 User-Agent 的不同，跳转到不同（PC、M）的站点，也有根据版本的不同给出不一样的提示等等，而 User-Agent 的变化更是爬虫里的基础姿势&lt;/p&gt;&#xA;&lt;p&gt;使用 Go 编写网络爬虫或需要模拟浏览器头（User-Agent）的时候，你是否会觉得很麻烦，获取请求头（Request Headers）的 User-Agent 还得找来找去，挺繁琐。先前我也遇到了这个问题，因此有了这个项目 &lt;a href=&#34;https://github.com/EDDYCJY/fake-useragent&#34;&gt;fake-useragent&lt;/a&gt;，用来解决你我的痛点&lt;/p&gt;&#xA;&lt;p&gt;项目地址：https://github.com/EDDYCJY/fake-useragent&lt;/p&gt;&#xA;&lt;h2 id=&#34;支持&#34;&gt;支持&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;All User-Agent Random&lt;/li&gt;&#xA;&lt;li&gt;Chrome&lt;/li&gt;&#xA;&lt;li&gt;InternetExplorer (IE)&lt;/li&gt;&#xA;&lt;li&gt;Firefox&lt;/li&gt;&#xA;&lt;li&gt;Safari&lt;/li&gt;&#xA;&lt;li&gt;Android&lt;/li&gt;&#xA;&lt;li&gt;MacOSX&lt;/li&gt;&#xA;&lt;li&gt;IOS&lt;/li&gt;&#xA;&lt;li&gt;Linux&lt;/li&gt;&#xA;&lt;li&gt;IPhone&lt;/li&gt;&#xA;&lt;li&gt;IPad&lt;/li&gt;&#xA;&lt;li&gt;Computer&lt;/li&gt;&#xA;&lt;li&gt;Mobile&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;安装&#34;&gt;安装&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get github.com/EDDYCJY/fake-useragent&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;用法&#34;&gt;用法&lt;/h2&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/fake-useragent&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;main&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#75715e&#34;&gt;// 推荐使用&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;random&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Random&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Random: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;random&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;chrome&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Chrome&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Chrome: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;chrome&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;internetExplorer&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;InternetExplorer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;IE: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;internetExplorer&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;firefox&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Firefox&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Firefox: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;firefox&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;safari&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Safari&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Safari: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;safari&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;android&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Android&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Android: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;android&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;macOSX&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MacOSX&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;MacOSX: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;macOSX&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ios&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IOS&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;IOS: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ios&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;linux&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Linux&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Linux: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;linux&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;iphone&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IPhone&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;IPhone: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;iphone&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ipad&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IPad&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;IPad: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ipad&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;computer&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Computer&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Computer: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;computer&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mobile&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;browser&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Mobile&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Mobile: %s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;mobile&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;定制&#34;&gt;定制&lt;/h3&gt;&#xA;&lt;p&gt;你可以调整抓取数据源的最大页数、时间间隔以及最大超时时间。 如果不填写，则为默认值。&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十一」Cron定时任务</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-04-29-cron/</link>
      <pubDate>Sun, 29 Apr 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-04-29-cron/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;完成定时任务的功能&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在实际的应用项目中，定时任务的使用是很常见的。你是否有过 Golang 如何做定时任务的疑问，莫非是轮询，在本文中我们将结合我们的项目讲述 Cron。&lt;/p&gt;&#xA;&lt;h2 id=&#34;介绍&#34;&gt;介绍&lt;/h2&gt;&#xA;&lt;p&gt;我们将使用 &lt;a href=&#34;https://github.com/robfig/cron&#34;&gt;cron&lt;/a&gt; 这个包，它实现了 cron 规范解析器和任务运行器，简单来讲就是包含了定时任务所需的功能&lt;/p&gt;&#xA;&lt;h3 id=&#34;cron-表达式格式&#34;&gt;Cron 表达式格式&lt;/h3&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;字段名&lt;/th&gt;&#xA;          &lt;th&gt;是否必填&lt;/th&gt;&#xA;          &lt;th&gt;允许的值&lt;/th&gt;&#xA;          &lt;th&gt;允许的特殊字符&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;秒（Seconds）&lt;/td&gt;&#xA;          &lt;td&gt;Yes&lt;/td&gt;&#xA;          &lt;td&gt;0-59&lt;/td&gt;&#xA;          &lt;td&gt;* / , -&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;分（Minutes）&lt;/td&gt;&#xA;          &lt;td&gt;Yes&lt;/td&gt;&#xA;          &lt;td&gt;0-59&lt;/td&gt;&#xA;          &lt;td&gt;* / , -&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;时（Hours）&lt;/td&gt;&#xA;          &lt;td&gt;Yes&lt;/td&gt;&#xA;          &lt;td&gt;0-23&lt;/td&gt;&#xA;          &lt;td&gt;* / , -&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;一个月中的某天（Day of month）&lt;/td&gt;&#xA;          &lt;td&gt;Yes&lt;/td&gt;&#xA;          &lt;td&gt;1-31&lt;/td&gt;&#xA;          &lt;td&gt;* / , - ?&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;月（Month）&lt;/td&gt;&#xA;          &lt;td&gt;Yes&lt;/td&gt;&#xA;          &lt;td&gt;1-12 or JAN-DEC&lt;/td&gt;&#xA;          &lt;td&gt;* / , -&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;星期几（Day of week）&lt;/td&gt;&#xA;          &lt;td&gt;Yes&lt;/td&gt;&#xA;          &lt;td&gt;0-6 or SUN-SAT&lt;/td&gt;&#xA;          &lt;td&gt;* / , - ?&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Cron 表达式表示一组时间，使用 6 个空格分隔的字段&lt;/p&gt;</description>
    </item>
    <item>
      <title>了解一下Golang的市场行情</title>
      <link>https://note.lican.site/posts/posts/go/crawler/2018-04-28-go2018/</link>
      <pubDate>Sat, 28 Apr 2018 12:30:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/crawler/2018-04-28-go2018/</guid>
      <description>&lt;p&gt;项目地址：https://github.com/go-crawler/lagou_jobs&lt;/p&gt;&#xA;&lt;p&gt;如果对你有所帮助，欢迎 Star，给文章来波赞，这样可以让更多的人看见  :)&lt;/p&gt;&#xA;&lt;h2 id=&#34;目标&#34;&gt;目标&lt;/h2&gt;&#xA;&lt;p&gt;在工作中 Golang 已是一份子，想让大家了解一下 Golang 的市场行情，也想让更多的人熟悉它。因此主要是展示数据分析的结果&lt;/p&gt;&#xA;&lt;p&gt;目标站点是 &lt;a href=&#34;https://www.lagou.com/&#34;&gt;某招聘网站&lt;/a&gt; 的职位数据抓取和分析，爬取城市分别为 北京、上海、广州、深圳、杭州、成都，再得出一个结论&lt;/p&gt;&#xA;&lt;h3 id=&#34;分析&#34;&gt;分析&lt;/h3&gt;&#xA;&lt;p&gt;首先需要进行页面分析，找到我们的抓取方向&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/04/26/5ae1e28a3412a.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;搜索 golang 关键字，打开页面 F12 就能看到它发送了四个请求，留意 positionAjax.json 这个请求&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/04/26/5ae1efe538791.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们仔细研判这个接口的入参和出参&lt;/p&gt;&#xA;&lt;h3 id=&#34;入参&#34;&gt;入参&lt;/h3&gt;&#xA;&lt;p&gt;1、Query String Param&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;city：请求的城市&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;needAddtionalResult：是否需要补充额外的参数，这里默认 false&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;2、Form Data&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;first：是否首页&lt;/li&gt;&#xA;&lt;li&gt;pn：页码&lt;/li&gt;&#xA;&lt;li&gt;kd：关键字&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;出参&#34;&gt;出参&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/04/26/5ae1f4c9920a9.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;就是它了，从返回结果可得出许多有用的信息&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;companyFullName：公司全称&lt;/li&gt;&#xA;&lt;li&gt;companyLabelList：公司标签&lt;/li&gt;&#xA;&lt;li&gt;companyShortName：公司简称&lt;/li&gt;&#xA;&lt;li&gt;companySize：公司规模&lt;/li&gt;&#xA;&lt;li&gt;education：学历要求&lt;/li&gt;&#xA;&lt;li&gt;financeStage：融资阶段&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;等等~&lt;/p&gt;&#xA;&lt;h3 id=&#34;分页&#34;&gt;分页&lt;/h3&gt;&#xA;&lt;p&gt;在上面两张图中，可以发现在 content 节点中包含 pageNo、pageSize 字段，content.positionResult 节点有 totalCount 字段，可以得知当前是第几页，每页显示多少条，当前的职位总条数&lt;/p&gt;&#xA;&lt;p&gt;需要注意一下，分页的计算是要向上取整的&lt;/p&gt;&#xA;&lt;h2 id=&#34;模拟浏览器头&#34;&gt;模拟浏览器头&lt;/h2&gt;&#xA;&lt;p&gt;User-Agent 可以用 &lt;a href=&#34;https://github.com/EDDYCJY/fake-useragent&#34;&gt;fake-useragent&lt;/a&gt; 这个项目来随机生成 UA 头 😄&lt;/p&gt;&#xA;&lt;h2 id=&#34;数据&#34;&gt;数据&lt;/h2&gt;&#xA;&lt;h3 id=&#34;一分布图&#34;&gt;一、分布图&lt;/h3&gt;&#xA;&lt;p&gt;不同工作、工种，自然也会遍布在不同的工作区域，我们先了解一下各个城市的 Golang 工程师都主要在哪个区上班，心里留个底&lt;/p&gt;&#xA;&lt;h4 id=&#34;北京&#34;&gt;北京&lt;/h4&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/04/27/5ae291859667c.jpeg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载十」定制 GORM Callbacks</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-04-15-gorm-callback/</link>
      <pubDate>Sun, 15 Apr 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-04-15-gorm-callback/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;GORM&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;GORM itself is powered by Callbacks, so you could fully customize GORM as you want&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;GORM 本身是由回调驱动的，所以我们可以根据需要完全定制 GORM，以此达到我们的目的，如下：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;注册一个新的回调&lt;/li&gt;&#xA;&lt;li&gt;删除现有的回调&lt;/li&gt;&#xA;&lt;li&gt;替换现有的回调&lt;/li&gt;&#xA;&lt;li&gt;注册回调的顺序&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在 GORM 中包含以上四类 Callbacks，我们结合项目选用 “替换现有的回调” 来解决一个小痛点。&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;&#xA;&lt;p&gt;在 models 目录下，我们包含 tag.go 和 article.go 两个文件，他们有一个问题，就是 BeforeCreate、BeforeUpdate 重复出现了，那难道 100 个文件，就要写一百次吗？&lt;/p&gt;&#xA;&lt;p&gt;1、tag.go&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/04/14/5ad20efdba409.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;2、article.go&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/04/14/5ad20ebacc4c9.jpg&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;显然这是不可能的，如果先前你已经意识到这个问题，那挺 OK，但没有的话，现在开始就要改&lt;/p&gt;&#xA;&lt;h3 id=&#34;解决&#34;&gt;解决&lt;/h3&gt;&#xA;&lt;p&gt;在这里我们通过 Callbacks 来实现功能，不需要一个个文件去编写&lt;/p&gt;&#xA;&lt;h3 id=&#34;实现-callbacks&#34;&gt;实现 Callbacks&lt;/h3&gt;&#xA;&lt;p&gt;打开 models 目录下的 models.go 文件，实现以下两个方法：&lt;/p&gt;&#xA;&lt;p&gt;1、updateTimeStampForCreateCallback&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// updateTimeStampForCreateCallback will set `CreatedOn`, `ModifiedOn` when creating&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;updateTimeStampForCreateCallback&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;scope&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gorm&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Scope&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; !&lt;span style=&#34;color:#a6e22e&#34;&gt;scope&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;HasError&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;nowTime&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Unix&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;createTimeField&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scope&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FieldByName&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;CreatedOn&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;createTimeField&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IsBlank&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;createTimeField&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Set&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;nowTime&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;modifyTimeField&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;scope&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FieldByName&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ModifiedOn&amp;#34;&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;modifyTimeField&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IsBlank&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;modifyTimeField&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Set&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;nowTime&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这段方法中，会完成以下功能&lt;/p&gt;</description>
    </item>
    <item>
      <title>爬取汽车之家 二手车产品库</title>
      <link>https://note.lican.site/posts/posts/go/crawler/2018-04-01-cars/</link>
      <pubDate>Sun, 01 Apr 2018 12:30:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/crawler/2018-04-01-cars/</guid>
      <description>&lt;p&gt;项目地址：https://github.com/go-crawler/car-prices&lt;/p&gt;&#xA;&lt;h2 id=&#34;目标&#34;&gt;目标&lt;/h2&gt;&#xA;&lt;p&gt;最近经常有人在耳边提起汽车之家，也好奇二手车在国内的价格是怎么样的，因此本次的目标站点是 &lt;a href=&#34;https://car.autohome.com.cn/2sc/440399/index.html&#34;&gt;汽车之家&lt;/a&gt; 的二手车产品库&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/30/5abe47f82a01f.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;分析目标源：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一页共 24 条&lt;/li&gt;&#xA;&lt;li&gt;含分页，但这个老产品库，在 100 页后会存在问题，因此我们爬取 99 页&lt;/li&gt;&#xA;&lt;li&gt;可以获取全部城市&lt;/li&gt;&#xA;&lt;li&gt;共可爬取 19w+ 数据&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;开始&#34;&gt;开始&lt;/h2&gt;&#xA;&lt;p&gt;爬取步骤&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;获取全部的城市&lt;/li&gt;&#xA;&lt;li&gt;拼装全部城市 URL 入队列&lt;/li&gt;&#xA;&lt;li&gt;解析二手车页面结构&lt;/li&gt;&#xA;&lt;li&gt;下一页 URL 入队列&lt;/li&gt;&#xA;&lt;li&gt;循环拉取所有分页的二手车数据&lt;/li&gt;&#xA;&lt;li&gt;循环拉取队列中城市的二手车数据&lt;/li&gt;&#xA;&lt;li&gt;等待，确定队列中无新的 URL&lt;/li&gt;&#xA;&lt;li&gt;爬取的二手车数据入库&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;获取城市&#34;&gt;获取城市&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/31/5abeff11ef583.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;通过页面查看，可发现在城市筛选区可得到全部的二手车城市列表，但是你仔细查阅代码。会发现它是 JS 加载进来的，城市也统一放在了一个变量中&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/31/5abf056389cf0.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;有两种提取方法&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;分析 JS 变量，提取出来&lt;/li&gt;&#xA;&lt;li&gt;直接将 &lt;code&gt;areaJson&lt;/code&gt; 复制出来作为变量解析&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;在这里我们直接将其复制粘贴出来即可，因为这是比较少变动的值&lt;/p&gt;&#xA;&lt;h3 id=&#34;获取分页&#34;&gt;获取分页&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/31/5abf08ec812e2.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;通过分析页面可以得知分页链接是有一定规律的，例如：&lt;code&gt;/2sc/hangzhou/a0_0msdgscncgpi1ltocsp2exb4/&lt;/code&gt;，可以发现 &lt;code&gt;sp%d&lt;/code&gt;，&lt;code&gt;sp&lt;/code&gt; 后面为页码&lt;/p&gt;&#xA;&lt;p&gt;按照常理，可以通过预测所有分页链接，推入队列后 &lt;code&gt;go routine&lt;/code&gt; 一波 即可快速拉取&lt;/p&gt;&#xA;&lt;p&gt;但是在这老产品库存在一个问题，在超过 100 页后，下一页永远是 101 页&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/31/5abf0e1e623ec.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;因此我们采取比较传统的做法，通过拉取下一页的链接去访问，以便适应可能的分页链接改变； 100 页以后的分页展示也很奇怪，先忽视&lt;/p&gt;&#xA;&lt;h3 id=&#34;获取二手车数据&#34;&gt;获取二手车数据&lt;/h3&gt;&#xA;&lt;p&gt;页面结构较为固定，常规的清洗 HTML 即可&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetCars&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;goquery&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Document&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;cars&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;QcCar&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;cityName&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetCityName&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.piclist ul li:not(.line)&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Each&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;selection&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;goquery&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Selection&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selection&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.title a&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;price&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selection&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.detail .detail-r&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.colf8&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;kilometer&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selection&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.detail .detail-l&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Eq&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;year&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;selection&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.detail .detail-l&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;p&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Eq&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;kilometer&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Join&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;compileNumber&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindAllString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;kilometer&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;year&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Join&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;compileNumber&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindAllString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TrimSpace&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;year&lt;/span&gt;), &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;priceS&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ParseFloat&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;price&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;kilometerS&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ParseFloat&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;kilometer&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;64&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;yearS&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atoi&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;year&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;cars&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;cars&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;QcCar&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;CityName&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;cityName&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Title&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Price&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;priceS&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Kilometer&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;kilometerS&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Year&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;yearS&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cars&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;数据&#34;&gt;数据&lt;/h2&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/31/5abf1d8042196.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「番外」Golang 交叉编译</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-03-26-cgo/</link>
      <pubDate>Mon, 26 Mar 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-03-26-cgo/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;跨平台编译&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在 &lt;a href=&#34;https://segmentfault.com/a/1190000013960558&#34;&gt;连载九&lt;/a&gt; 讲解&lt;strong&gt;构建 Scratch 镜像&lt;/strong&gt;时，我们编译可执行文件用了另外一个形式的命令，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o go-gin-example .&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我想你可能会有疑问，今天本文会针对这块进行讲解。&lt;/p&gt;&#xA;&lt;h2 id=&#34;说明&#34;&gt;说明&lt;/h2&gt;&#xA;&lt;p&gt;我们将讲解命令各个参数的作用，希望你在阅读时，将每一项串联起来，你会发现这就是&lt;strong&gt;交叉编译相关的小知识&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;也就是 &lt;code&gt;Golang&lt;/code&gt; 令人心动的特性之一&lt;strong&gt;跨平台编译&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;一cgo_enabled&#34;&gt;一、CGO_ENABLED&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;作用：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;用于标识（声明） &lt;code&gt;cgo&lt;/code&gt; 工具是否可用&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;意义：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;存在交叉编译的情况时，&lt;code&gt;cgo&lt;/code&gt; 工具是不可用的。在标准 go 命令的上下文环境中，交叉编译意味着程序构建环境的目标计算架构的标识与程序运行环境的目标计算架构的标识不同，或者程序构建环境的目标操作系统的标识与程序运行环境的目标操作系统的标识不同&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;小结：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;结合案例来说，我们是在宿主机编译的可执行文件，而在 &lt;code&gt;Scratch&lt;/code&gt; 镜像运行的可执行文件；显然两者的计算机架构、运行环境标识你无法确定它是否一致（毕竟构建的 &lt;code&gt;docker&lt;/code&gt; 镜像还可以给他人使用），那么我们就要进行交叉编译，而交叉编译不支持 &lt;code&gt;cgo&lt;/code&gt;，因此这里要禁用掉它&lt;/p&gt;&#xA;&lt;p&gt;关闭 &lt;code&gt;cgo&lt;/code&gt; 后，在构建过程中会忽略 &lt;code&gt;cgo&lt;/code&gt; 并静态链接所有的依赖库，而开启 &lt;code&gt;cgo&lt;/code&gt; 后，方式将转为动态链接&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;补充：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;golang&lt;/code&gt; 是默认开启 &lt;code&gt;cgo&lt;/code&gt; 工具的，可执行 &lt;code&gt;go env&lt;/code&gt; 命令查看&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go env&#xA;GOARCH=&amp;#34;amd64&amp;#34;&#xA;GOBIN=&amp;#34;&amp;#34;&#xA;GOCACHE=&amp;#34;/root/.cache/go-build&amp;#34;&#xA;GOEXE=&amp;#34;&amp;#34;&#xA;GOHOSTARCH=&amp;#34;amd64&amp;#34;&#xA;GOHOSTOS=&amp;#34;linux&amp;#34;&#xA;GOOS=&amp;#34;linux&amp;#34;&#xA;...&#xA;GCCGO=&amp;#34;gccgo&amp;#34;&#xA;CC=&amp;#34;gcc&amp;#34;&#xA;CXX=&amp;#34;g++&amp;#34;&#xA;CGO_ENABLED=&amp;#34;1&amp;#34;&#xA;...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;二goos&#34;&gt;二、GOOS&lt;/h3&gt;&#xA;&lt;p&gt;用于标识（声明）程序构建环境的目标操作系统&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载九」将Golang应用部署到Docker</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-03-24-golang-docker/</link>
      <pubDate>Sat, 24 Mar 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-03-24-golang-docker/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Go + Docker&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;将我们的 &lt;code&gt;go-gin-example&lt;/code&gt; 应用部署到一个 Docker 里，你需要先准备好如下东西：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;你需要安装好 &lt;code&gt;docker&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;li&gt;如果上外网比较吃力，需要配好镜像源。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;docker&#34;&gt;Docker&lt;/h2&gt;&#xA;&lt;p&gt;在这里简单介绍下 Docker，建议深入学习&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://timgsa.baidu.com/timg?image&amp;amp;quality=80&amp;amp;size=b9999_10000&amp;amp;sec=1521800047226&amp;amp;di=28b2764fccca8a943aea7d79ad8aed98&amp;amp;imgtype=0&amp;amp;src=http%3A%2F%2Fwww.cww.net.cn%2FupLoadFile%2F2014%2F6%2F13%2F201461382247734.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Docker 是一个开源的轻量级容器技术，让开发者可以打包他们的应用以及应用运行的上下文环境到一个可移植的镜像中，然后发布到任何支持 Docker 的系统上运行。 通过容器技术，在几乎没有性能开销的情况下，Docker 为应用提供了一个隔离运行环境&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;简化配置&lt;/li&gt;&#xA;&lt;li&gt;代码流水线管理&lt;/li&gt;&#xA;&lt;li&gt;提高开发效率&lt;/li&gt;&#xA;&lt;li&gt;隔离应用&lt;/li&gt;&#xA;&lt;li&gt;快速、持续部署&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;接下来我们正式开始对项目进行 &lt;code&gt;docker&lt;/code&gt; 的所需处理和编写，每一个大标题为步骤大纲&lt;/p&gt;&#xA;&lt;h2 id=&#34;golang&#34;&gt;Golang&lt;/h2&gt;&#xA;&lt;h3 id=&#34;一编写-dockerfile&#34;&gt;一、编写 Dockerfile&lt;/h3&gt;&#xA;&lt;p&gt;在 &lt;code&gt;go-gin-example&lt;/code&gt; 项目根目录创建 Dockerfile 文件，写入内容&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;FROM golang:latest&#xA;&#xA;ENV GOPROXY https://goproxy.cn,direct&#xA;WORKDIR $GOPATH/src/github.com/EDDYCJY/go-gin-example&#xA;COPY . $GOPATH/src/github.com/EDDYCJY/go-gin-example&#xA;RUN go build .&#xA;&#xA;EXPOSE 8000&#xA;ENTRYPOINT [&amp;#34;./go-gin-example&amp;#34;]&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;作用&#34;&gt;作用&lt;/h4&gt;&#xA;&lt;p&gt;&lt;code&gt;golang:latest&lt;/code&gt; 镜像为基础镜像，将工作目录设置为 &lt;code&gt;$GOPATH/src/go-gin-example&lt;/code&gt;，并将当前上下文目录的内容复制到 &lt;code&gt;$GOPATH/src/go-gin-example&lt;/code&gt; 中&lt;/p&gt;&#xA;&lt;p&gt;在进行 &lt;code&gt;go build&lt;/code&gt; 编译完毕后，将容器启动程序设置为 &lt;code&gt;./go-gin-example&lt;/code&gt;，也就是我们所编译的可执行文件&lt;/p&gt;&#xA;&lt;p&gt;注意 &lt;code&gt;go-gin-example&lt;/code&gt; 在 &lt;code&gt;docker&lt;/code&gt; 容器里编译，并没有在宿主机现场编译&lt;/p&gt;</description>
    </item>
    <item>
      <title>爬取豆瓣电影 Top250</title>
      <link>https://note.lican.site/posts/posts/go/crawler/2018-03-21-douban-top250/</link>
      <pubDate>Wed, 21 Mar 2018 12:30:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/crawler/2018-03-21-douban-top250/</guid>
      <description>&lt;p&gt;爬虫是标配了，看数据那一刻很有趣。第一个就从最最最简单最基础的爬虫开始写起吧！&lt;/p&gt;&#xA;&lt;p&gt;项目地址：https://github.com/go-crawler/douban-movie&lt;/p&gt;&#xA;&lt;h2 id=&#34;目标&#34;&gt;目标&lt;/h2&gt;&#xA;&lt;p&gt;我们的目标站点是 &lt;a href=&#34;https://movie.douban.com/top250&#34;&gt;豆瓣电影 Top250&lt;/a&gt;，估计大家都很眼熟了&lt;/p&gt;&#xA;&lt;p&gt;本次爬取 8 个字段，用于简单的概括分析。具体的字段如下：&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/20/5ab11596b8810.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;简单的分析一下目标源&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;一页共 25 条&lt;/li&gt;&#xA;&lt;li&gt;含分页（共 10 页）且分页规则是正常的&lt;/li&gt;&#xA;&lt;li&gt;每一项的数据字段排序都是规则且不变&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;开始&#34;&gt;开始&lt;/h2&gt;&#xA;&lt;p&gt;由于量不大，我们的爬取步骤如下&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;分析页面，获取所有的分页&lt;/li&gt;&#xA;&lt;li&gt;分析页面，循环爬取所有页面的电影信息&lt;/li&gt;&#xA;&lt;li&gt;爬取的电影信息入库&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;安装&#34;&gt;安装&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get -u github.com/PuerkitoBio/goquery&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;运行&#34;&gt;运行&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go run main.go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;代码片段&#34;&gt;代码片段&lt;/h3&gt;&#xA;&lt;h4 id=&#34;1获取所有分页&#34;&gt;1、获取所有分页&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ParsePages&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;goquery&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Document&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;pages&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Page&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;pages&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;pages&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Page&lt;/span&gt;{&lt;span style=&#34;color:#a6e22e&#34;&gt;Page&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Url&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#content &amp;gt; div &amp;gt; div.article &amp;gt; div.paginator &amp;gt; a&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Each&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;goquery&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Selection&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;page&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strconv&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Atoi&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Attr&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;href&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;pages&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;pages&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;Page&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Page&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;page&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Url&lt;/span&gt;:  &lt;span style=&#34;color:#a6e22e&#34;&gt;url&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;pages&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h4 id=&#34;2分析豆瓣电影信息&#34;&gt;2、分析豆瓣电影信息&lt;/h4&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ParseMovies&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;goquery&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Document&lt;/span&gt;) (&lt;span style=&#34;color:#a6e22e&#34;&gt;movies&lt;/span&gt; []&lt;span style=&#34;color:#a6e22e&#34;&gt;Movie&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;doc&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;#content &amp;gt; div &amp;gt; div.article &amp;gt; ol &amp;gt; li&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Each&lt;/span&gt;(&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;goquery&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Selection&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;title&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.hd a span&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Eq&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;movieDesc&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Split&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;DescInfo&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;], &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;year&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TrimSpace&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;movieDesc&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;area&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TrimSpace&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;movieDesc&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;tag&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TrimSpace&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;movieDesc&lt;/span&gt;[&lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;])&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;star&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.bd .star .rating_num&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;comment&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TrimSpace&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.bd .star span&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Eq&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;compile&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;regexp&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MustCompile&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;[0-9]&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;comment&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;strings&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Join&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;compile&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FindAllString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;comment&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;), &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;quote&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;s&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Find&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.quote .inq&amp;#34;&lt;/span&gt;).&lt;span style=&#34;color:#a6e22e&#34;&gt;Text&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Printf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;i: %d, movie: %v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;i&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;movie&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;movies&lt;/span&gt; = append(&lt;span style=&#34;color:#a6e22e&#34;&gt;movies&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;movie&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;movies&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;数据&#34;&gt;数据&lt;/h3&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://i.loli.net/2018/03/21/5ab1309594741.png&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载八」为它加上Swagger</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-03-18-swagger/</link>
      <pubDate>Sun, 18 Mar 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-03-18-swagger/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Swagger&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;一个好的 &lt;code&gt;API&#39;s&lt;/code&gt;，必然离不开一个好的&lt;code&gt;API&lt;/code&gt;文档，如果要开发纯手写 &lt;code&gt;API&lt;/code&gt; 文档，不存在的（很难持续维护），因此我们要自动生成接口文档。&lt;/p&gt;&#xA;&lt;h2 id=&#34;安装-swag&#34;&gt;安装 swag&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get -u github.com/swaggo/swag/cmd/swag@v1.6.5&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;若 &lt;code&gt;$GOROOT/bin&lt;/code&gt; 没有加入&lt;code&gt;$PATH&lt;/code&gt;中，你需要执行将其可执行文件移动到&lt;code&gt;$GOBIN&lt;/code&gt;下&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mv $GOPATH/bin/swag /usr/local/go/bin&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;验证是否安装成功&#34;&gt;验证是否安装成功&lt;/h3&gt;&#xA;&lt;p&gt;检查 $GOBIN 下是否有 swag 文件，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ swag -v&#xA;swag version v1.6.5&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;安装-gin-swagger&#34;&gt;安装 gin-swagger&lt;/h2&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go get -u github.com/swaggo/gin-swagger@v1.2.0 &#xA;$ go get -u github.com/swaggo/files&#xA;$ go get -u github.com/alecthomas/template&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注：若无科学上网，请务必配置 Go modules proxy。&lt;/p&gt;&#xA;&lt;h2 id=&#34;初始化&#34;&gt;初始化&lt;/h2&gt;&#xA;&lt;h3 id=&#34;编写-api-注释&#34;&gt;编写 API 注释&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;Swagger&lt;/code&gt; 中需要将相应的注释或注解编写到方法上，再利用生成器自动生成说明文件&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;gin-swagger&lt;/code&gt; 给出的范例：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Summary Add a new pet to the store&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Description get string by ID&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Accept  json&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Produce  json&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Param   some_id     path    int     true        &amp;#34;Some ID&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Success 200 {string} string&#x9;&amp;#34;ok&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Failure 400 {object} web.APIError &amp;#34;We need ID!!&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Failure 404 {object} web.APIError &amp;#34;Can not find ID&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// @Router /testapi/get-string-by-int/{some_id} [get]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们可以参照 &lt;code&gt;Swagger&lt;/code&gt; 的注解规范和范例去编写&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载七」优雅的重启服务</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-03-15-reload-http/</link>
      <pubDate>Thu, 15 Mar 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-03-15-reload-http/</guid>
      <description>&lt;h2 id=&#34;知识点&#34;&gt;知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;信号量的了解。&lt;/li&gt;&#xA;&lt;li&gt;应用热更新。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在前面编写案例代码时，我相信你会想到，每次更新完代码，更新完配置文件后，就直接这么 &lt;code&gt;ctrl+c&lt;/code&gt; 真的没问题吗，&lt;code&gt;ctrl+c&lt;/code&gt;到底做了些什么事情呢？&lt;/p&gt;&#xA;&lt;p&gt;在这一节中我们简单讲述 &lt;code&gt;ctrl+c&lt;/code&gt; 背后的&lt;strong&gt;信号&lt;/strong&gt;以及如何在&lt;code&gt;Gin&lt;/code&gt;中&lt;strong&gt;优雅的重启服务&lt;/strong&gt;，也就是对 &lt;code&gt;HTTP&lt;/code&gt; 服务进行热更新。&lt;/p&gt;&#xA;&lt;h2 id=&#34;ctrl--c&#34;&gt;ctrl + c&lt;/h2&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;内核在某些情况下发送信号，比如在进程往一个已经关闭的管道写数据时会产生&lt;code&gt;SIGPIPE&lt;/code&gt;信号&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;在终端执行特定的组合键可以使系统发送特定的信号给此进程，完成一系列的动作&lt;/p&gt;&#xA;&lt;table&gt;&#xA;  &lt;thead&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;th&gt;命令&lt;/th&gt;&#xA;          &lt;th&gt;信号&lt;/th&gt;&#xA;          &lt;th&gt;含义&lt;/th&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/thead&gt;&#xA;  &lt;tbody&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;ctrl + c&lt;/td&gt;&#xA;          &lt;td&gt;SIGINT&lt;/td&gt;&#xA;          &lt;td&gt;强制进程结束&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;ctrl + z&lt;/td&gt;&#xA;          &lt;td&gt;SIGTSTP&lt;/td&gt;&#xA;          &lt;td&gt;任务中断，进程挂起&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;ctrl + \&lt;/td&gt;&#xA;          &lt;td&gt;SIGQUIT&lt;/td&gt;&#xA;          &lt;td&gt;进程结束 和 &lt;code&gt;dump core&lt;/code&gt;&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;ctrl + d&lt;/td&gt;&#xA;          &lt;td&gt;&lt;/td&gt;&#xA;          &lt;td&gt;EOF&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;      &lt;tr&gt;&#xA;          &lt;td&gt;&lt;/td&gt;&#xA;          &lt;td&gt;SIGHUP&lt;/td&gt;&#xA;          &lt;td&gt;终止收到该信号的进程。若程序中没有捕捉该信号，当收到该信号时，进程就会退出（常用于 重启、重新加载进程）&lt;/td&gt;&#xA;      &lt;/tr&gt;&#xA;  &lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;因此在我们执行&lt;code&gt;ctrl + c&lt;/code&gt;关闭&lt;code&gt;gin&lt;/code&gt;服务端时，&lt;strong&gt;会强制进程结束，导致正在访问的用户等出现问题&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;常见的 &lt;code&gt;kill -9 pid&lt;/code&gt; 会发送 &lt;code&gt;SIGKILL&lt;/code&gt; 信号给进程，也是类似的结果&lt;/p&gt;&#xA;&lt;h3 id=&#34;信号&#34;&gt;信号&lt;/h3&gt;&#xA;&lt;p&gt;本段中反复出现&lt;strong&gt;信号&lt;/strong&gt;是什么呢？&lt;/p&gt;&#xA;&lt;p&gt;信号是 &lt;code&gt;Unix&lt;/code&gt; 、类 &lt;code&gt;Unix&lt;/code&gt; 以及其他 &lt;code&gt;POSIX&lt;/code&gt; 兼容的操作系统中进程间通讯的一种有限制的方式&lt;/p&gt;&#xA;&lt;p&gt;它是一种异步的通知机制，用来提醒进程一个事件（硬件异常、程序执行异常、外部发出信号）已经发生。当一个信号发送给一个进程，操作系统中断了进程正常的控制流程。此时，任何非原子操作都将被中断。如果进程定义了信号的处理函数，那么它将被执行，否则就执行默认的处理函数&lt;/p&gt;&#xA;&lt;h3 id=&#34;所有信号&#34;&gt;所有信号&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kill -l&#xA; 1) SIGHUP   2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP&#xA; 6) SIGABRT  7) SIGBUS   8) SIGFPE   9) SIGKILL 10) SIGUSR1&#xA;11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM&#xA;16) SIGSTKFLT   17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP&#xA;21) SIGTTIN 22) SIGTTOU 23) SIGURG  24) SIGXCPU 25) SIGXFSZ&#xA;26) SIGVTALRM   27) SIGPROF 28) SIGWINCH    29) SIGIO   30) SIGPWR&#xA;31) SIGSYS  34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3&#xA;38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8&#xA;43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13&#xA;48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12&#xA;53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7&#xA;58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2&#xA;63) SIGRTMAX-1  64) SIGRTMAX&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;怎样算优雅&#34;&gt;怎样算优雅&lt;/h2&gt;&#xA;&lt;h3 id=&#34;目的&#34;&gt;目的&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;不关闭现有连接（正在运行中的程序）&lt;/li&gt;&#xA;&lt;li&gt;新的进程启动并替代旧进程&lt;/li&gt;&#xA;&lt;li&gt;新的进程接管新的连接&lt;/li&gt;&#xA;&lt;li&gt;连接要随时响应用户的请求，当用户仍在请求旧进程时要保持连接，新用户应请求新进程，不可以出现拒绝请求的情况&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;流程&#34;&gt;流程&lt;/h3&gt;&#xA;&lt;p&gt;1、替换可执行文件或修改配置文件&lt;/p&gt;</description>
    </item>
    <item>
      <title>聊一聊，Go 的相对路径问题</title>
      <link>https://note.lican.site/posts/posts/go/talk/2018-03-13-golang-relatively-path/</link>
      <pubDate>Tue, 13 Mar 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/talk/2018-03-13-golang-relatively-path/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;&#xA;&lt;p&gt;&lt;code&gt;Golang&lt;/code&gt; 中存在各种运行方式，如何&lt;strong&gt;正确的引用文件路径&lt;/strong&gt;成为一个值得商议的问题&lt;/p&gt;&#xA;&lt;p&gt;以 &lt;a href=&#34;https://github.com/EDDYCJY/go-gin-example&#34;&gt;gin-blog&lt;/a&gt; 为例，当我们在项目根目录下，执行 &lt;code&gt;go run main.go&lt;/code&gt; 时能够正常运行（&lt;code&gt;go build&lt;/code&gt;也是正常的）&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[$ gin-blog]# go run main.go&#xA;[GIN-debug] [WARNING] Running in &amp;#34;debug&amp;#34; mode. Switch to &amp;#34;release&amp;#34; mode in production.&#xA; - using env:    export GIN_MODE=release&#xA; - using code:    gin.SetMode(gin.ReleaseMode)&#xA;&#xA;[GIN-debug] GET    /api/v1/tags              --&amp;gt; gin-blog/routers/api/v1.GetTags (3 handlers)&#xA;...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;那么在不同的目录层级下，不同的方式运行，又是怎么样的呢，带着我们的疑问去学习&lt;/p&gt;&#xA;&lt;h2 id=&#34;问题&#34;&gt;问题&lt;/h2&gt;&#xA;&lt;p&gt;1、 go run&#xA;我们上移目录层级，到 &lt;code&gt;$GOPATH/src&lt;/code&gt; 下，执行 &lt;code&gt;go run gin-blog/main.go&lt;/code&gt;&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[$ src]# go run gin-blog/main.go&#xA;2018/03/12 16:06:13 Fail to parse &amp;#39;conf/app.ini&amp;#39;: open conf/app.ini: no such file or directory&#xA;exit status 1&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2、 go build，执行 &lt;code&gt;./gin-blog/main&lt;/code&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载三」Swagger了解一下</title>
      <link>https://note.lican.site/posts/posts/go/grpc-gateway/2018-03-04-swagger/</link>
      <pubDate>Sun, 04 Mar 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc-gateway/2018-03-04-swagger/</guid>
      <description>&lt;p&gt;在&lt;a href=&#34;https://segmentfault.com/a/1190000013408485&#34;&gt;上一节&lt;/a&gt;，我们完成了一个服务端同时支持&lt;code&gt;Rpc&lt;/code&gt;和&lt;code&gt;RESTful Api&lt;/code&gt;后，你以为自己大功告成了，结果突然发现要写&lt;code&gt;Api&lt;/code&gt;文档和前端同事对接= = 。。。&lt;/p&gt;&#xA;&lt;p&gt;你寻思有没有什么组件能够自动化生成&lt;code&gt;Api&lt;/code&gt;文档来解决这个问题，就在这时你发现了&lt;code&gt;Swagger&lt;/code&gt;，一起了解一下吧！&lt;/p&gt;&#xA;&lt;h2 id=&#34;介绍&#34;&gt;介绍&lt;/h2&gt;&#xA;&lt;h3 id=&#34;swagger&#34;&gt;Swagger&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;Swagger&lt;/code&gt;是全球最大的&lt;code&gt;OpenAPI&lt;/code&gt;规范（OAS）API开发工具框架，支持从设计和文档到测试和部署的整个API生命周期的开发&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Swagger&lt;/code&gt;是目前最受欢迎的&lt;code&gt;RESTful Api&lt;/code&gt;文档生成工具之一，主要的原因如下&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;跨平台、跨语言的支持&lt;/li&gt;&#xA;&lt;li&gt;强大的社区&lt;/li&gt;&#xA;&lt;li&gt;生态圈 Swagger Tools（&lt;a href=&#34;https://github.com/swagger-api/swagger-editor&#34;&gt;Swagger Editor&lt;/a&gt;、&lt;a href=&#34;https://github.com/swagger-api/swagger-codegen&#34;&gt;Swagger Codegen&lt;/a&gt;、&lt;a href=&#34;https://github.com/swagger-api/swagger-ui&#34;&gt;Swagger UI&lt;/a&gt; &amp;hellip;）&lt;/li&gt;&#xA;&lt;li&gt;强大的控制台&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;同时&lt;code&gt;grpc-gateway&lt;/code&gt;也支持&lt;code&gt;Swagger&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;[image]&lt;/p&gt;&#xA;&lt;h3 id=&#34;openapi规范&#34;&gt;&lt;code&gt;OpenAPI&lt;/code&gt;规范&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;OpenAPI&lt;/code&gt;规范是&lt;code&gt;Linux&lt;/code&gt;基金会的一个项目，试图通过定义一种用来描述API格式或API定义的语言，来规范&lt;code&gt;RESTful&lt;/code&gt;服务开发过程。&lt;code&gt;OpenAPI&lt;/code&gt;规范帮助我们描述一个API的基本信息，比如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;有关该API的一般性描述&lt;/li&gt;&#xA;&lt;li&gt;可用路径（/资源）&lt;/li&gt;&#xA;&lt;li&gt;在每个路径上的可用操作（获取/提交&amp;hellip;）&lt;/li&gt;&#xA;&lt;li&gt;每个操作的输入/输出格式&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;目前V2.0版本的&lt;a href=&#34;https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md&#34;&gt;OpenAPI规范&lt;/a&gt;（也就是SwaggerV2.0规范）已经发布并开源在github上。该文档写的非常好，结构清晰，方便随时查阅。&lt;/p&gt;&#xA;&lt;p&gt;注：&lt;code&gt;OpenAPI&lt;/code&gt;规范的介绍引用自&lt;a href=&#34;https://huangwenchao.gitbooks.io/swagger/content/&#34;&gt;原文&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;使用&#34;&gt;使用&lt;/h2&gt;&#xA;&lt;h3 id=&#34;生成swagger的说明文件&#34;&gt;生成&lt;code&gt;Swagger&lt;/code&gt;的说明文件&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;第一&lt;/strong&gt;，我们需要检查$GOBIN下是否包含&lt;code&gt;protoc-gen-swagger&lt;/code&gt;可执行文件&lt;/p&gt;&#xA;&lt;p&gt;若不存在则需要执行：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;等待执行完毕后，可在&lt;code&gt;$GOPATH/bin&lt;/code&gt;下发现该执行文件，将其移动到&lt;code&gt;$GOBIN&lt;/code&gt;下即可&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;第二&lt;/strong&gt;，回到&lt;code&gt;$GOPATH/src/grpc-hello-world/proto&lt;/code&gt;下，执行命令&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;protoc -I/usr/local/include -I. -I$GOPATH/src/grpc-hello-world/proto/google/api --swagger_out=logtostderr=true:. ./hello.proto&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;成功后执行&lt;code&gt;ls&lt;/code&gt;即可看到&lt;code&gt;hello.swagger.json&lt;/code&gt;文件&lt;/p&gt;&#xA;&lt;h3 id=&#34;下载swagger-ui文件&#34;&gt;下载&lt;code&gt;Swagger UI&lt;/code&gt;文件&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;Swagger&lt;/code&gt;提供可视化的&lt;code&gt;API&lt;/code&gt;管理平台，就是&lt;a href=&#34;https://github.com/swagger-api/swagger-ui&#34;&gt;Swagger UI&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;我们将其源码下载下来，并将其&lt;code&gt;dist&lt;/code&gt;目录下的所有文件拷贝到我们项目中的&lt;code&gt;$GOPATH/src/grpc-hello-world/third_party/swagger-ui&lt;/code&gt;去&lt;/p&gt;&#xA;&lt;h3 id=&#34;将swagger-ui转换为go源代码&#34;&gt;将&lt;code&gt;Swagger UI&lt;/code&gt;转换为&lt;code&gt;Go&lt;/code&gt;源代码&lt;/h3&gt;&#xA;&lt;p&gt;在这里我们使用的转换工具是&lt;a href=&#34;https://github.com/jteeuwen/go-bindata&#34;&gt;go-bindata&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;它支持将任何文件转换为可管理的&lt;code&gt;Go&lt;/code&gt;源代码。用于将二进制数据嵌入到&lt;code&gt;Go&lt;/code&gt;程序中。并且在将文件数据转换为原始字节片之前，可以选择压缩文件数据&lt;/p&gt;&#xA;&lt;h4 id=&#34;安装&#34;&gt;安装&lt;/h4&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u github.com/jteeuwen/go-bindata/...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;完成后，将&lt;code&gt;$GOPATH/bin&lt;/code&gt;下的&lt;code&gt;go-bindata&lt;/code&gt;移动到&lt;code&gt;$GOBIN&lt;/code&gt;下&lt;/p&gt;&#xA;&lt;h4 id=&#34;转换&#34;&gt;转换&lt;/h4&gt;&#xA;&lt;p&gt;在项目下新建&lt;code&gt;pkg/ui/data/swagger&lt;/code&gt;目录，回到&lt;code&gt;$GOPATH/src/grpc-hello-world/third_party/swagger-ui&lt;/code&gt;下，执行命令&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go-bindata --nocompress -pkg swagger -o pkg/ui/data/swagger/datafile.go third_party/swagger-ui/...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;检查&#34;&gt;检查&lt;/h4&gt;&#xA;&lt;p&gt;回到&lt;code&gt;pkg/ui/data/swagger&lt;/code&gt;目录，检查是否存在&lt;code&gt;datafile.go&lt;/code&gt;文件&lt;/p&gt;&#xA;&lt;h3 id=&#34;swagger-ui文件服务器对外提供服务&#34;&gt;&lt;code&gt;Swagger UI&lt;/code&gt;文件服务器（对外提供服务）&lt;/h3&gt;&#xA;&lt;p&gt;在这一步，我们需要使用与其配套的&lt;a href=&#34;https://github.com/elazarl/go-bindata-assetfs/&#34;&gt;go-bindata-assetfs&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载二」Hello World</title>
      <link>https://note.lican.site/posts/posts/go/grpc-gateway/2018-02-27-hello-world/</link>
      <pubDate>Tue, 27 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc-gateway/2018-02-27-hello-world/</guid>
      <description>&lt;p&gt;这节将开始编写一个复杂的Hello World，涉及到许多的知识，建议大家认真思考其中的概念&lt;/p&gt;&#xA;&lt;h2 id=&#34;需求&#34;&gt;需求&lt;/h2&gt;&#xA;&lt;p&gt;由于本实践偏向&lt;code&gt;Grpc&lt;/code&gt;+&lt;code&gt;Grpc Gateway&lt;/code&gt;的方面，我们的需求是&lt;strong&gt;同一个服务端支持&lt;code&gt;Rpc&lt;/code&gt;和&lt;code&gt;Restful Api&lt;/code&gt;&lt;/strong&gt;，那么就意味着&lt;code&gt;http2&lt;/code&gt;、&lt;code&gt;TLS&lt;/code&gt;等等的应用，功能方面就是一个服务端能够接受来自&lt;code&gt;grpc&lt;/code&gt;和&lt;code&gt;Restful Api&lt;/code&gt;的请求并响应&lt;/p&gt;&#xA;&lt;h2 id=&#34;一初始化目录&#34;&gt;一、初始化目录&lt;/h2&gt;&#xA;&lt;p&gt;我们先在$GOPATH中新建&lt;code&gt;grpc-hello-world&lt;/code&gt;文件夹，我们项目的初始目录目录如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;grpc-hello-world/&#xA;├── certs&#xA;├── client&#xA;├── cmd&#xA;├── pkg&#xA;├── proto&#xA;│   ├── google&#xA;│   │   └── api&#xA;└── server&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;certs&lt;/code&gt;：证书凭证&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;client&lt;/code&gt;：客户端&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;cmd&lt;/code&gt;：命令行&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;pkg&lt;/code&gt;：第三方公共模块&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;proto&lt;/code&gt;：&lt;code&gt;protobuf&lt;/code&gt;的一些相关文件（含&lt;code&gt;.proto&lt;/code&gt;、&lt;code&gt;pb.go&lt;/code&gt;、&lt;code&gt;.pb.gw.go&lt;/code&gt;)，&lt;code&gt;google/api&lt;/code&gt;中用于存放&lt;code&gt;annotations.proto&lt;/code&gt;、&lt;code&gt;http.proto&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;server&lt;/code&gt;：服务端&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;二制作证书&#34;&gt;二、制作证书&lt;/h2&gt;&#xA;&lt;p&gt;在服务端支持&lt;code&gt;Rpc&lt;/code&gt;和&lt;code&gt;Restful Api&lt;/code&gt;，需要用到&lt;code&gt;TLS&lt;/code&gt;，因此我们要先制作证书&lt;/p&gt;&#xA;&lt;p&gt;进入&lt;code&gt;certs&lt;/code&gt;目录，生成&lt;code&gt;TLS&lt;/code&gt;所需的公钥密钥文件&lt;/p&gt;&#xA;&lt;h3 id=&#34;私钥&#34;&gt;私钥&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl genrsa -out server.key 2048&#xA;&#xA;openssl ecparam -genkey -name secp384r1 -out server.key&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;openssl genrsa&lt;/code&gt;：生成&lt;code&gt;RSA&lt;/code&gt;私钥，命令的最后一个参数，将指定生成密钥的位数，如果没有指定，默认512&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;openssl ecparam&lt;/code&gt;：生成&lt;code&gt;ECC&lt;/code&gt;私钥，命令为椭圆曲线密钥参数生成及操作，本文中&lt;code&gt;ECC&lt;/code&gt;曲线选择的是&lt;code&gt;secp384r1&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;自签名公钥&#34;&gt;自签名公钥&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;openssl req&lt;/code&gt;：生成自签名证书，&lt;code&gt;-new&lt;/code&gt;指生成证书请求、&lt;code&gt;-sha256&lt;/code&gt;指使用&lt;code&gt;sha256&lt;/code&gt;加密、&lt;code&gt;-key&lt;/code&gt;指定私钥文件、&lt;code&gt;-x509&lt;/code&gt;指输出证书、&lt;code&gt;-days 3650&lt;/code&gt;为有效期，此后则输入证书拥有者信息&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;填写信息&#34;&gt;填写信息&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Country Name (2 letter code) [XX]:&#xA;State or Province Name (full name) []:&#xA;Locality Name (eg, city) [Default City]:&#xA;Organization Name (eg, company) [Default Company Ltd]:&#xA;Organizational Unit Name (eg, section) []:&#xA;Common Name (eg, your name or your server&amp;#39;s hostname) []:grpc server name&#xA;Email Address []:&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;三proto&#34;&gt;三、&lt;code&gt;proto&lt;/code&gt;&lt;/h2&gt;&#xA;&lt;h3 id=&#34;编写&#34;&gt;编写&lt;/h3&gt;&#xA;&lt;p&gt;1、 &lt;code&gt;google.api&lt;/code&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载一」gRPC介绍与环境安装</title>
      <link>https://note.lican.site/posts/posts/go/grpc-gateway/2018-02-23-install/</link>
      <pubDate>Fri, 23 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/grpc-gateway/2018-02-23-install/</guid>
      <description>&lt;p&gt;假定我们有一个项目需求，希望用&lt;code&gt;Rpc&lt;/code&gt;作为内部&lt;code&gt;API&lt;/code&gt;的通讯，同时也想对外提供&lt;code&gt;Restful Api&lt;/code&gt;，写两套又太繁琐不符合&lt;/p&gt;&#xA;&lt;p&gt;于是我们想到了&lt;code&gt;Grpc&lt;/code&gt;以及&lt;code&gt;Grpc Gateway&lt;/code&gt;，这就是我们所需要的&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://camo.githubusercontent.com/e75a8b46b078a3c1df0ed9966a16c24add9ccb83/68747470733a2f2f646f63732e676f6f676c652e636f6d2f64726177696e67732f642f3132687034435071724e5046686174744c5f63496f4a707446766c41716d35774c513067677149356d6b43672f7075623f773d37343926683d333730&#34; alt=&#34;image&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;准备环节&#34;&gt;准备环节&lt;/h2&gt;&#xA;&lt;p&gt;在正式开始我们的&lt;code&gt;Grpc&lt;/code&gt;+&lt;code&gt;Grpc Gateway&lt;/code&gt;实践前，我们需要先配置好我们的开发环境&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Grpc&lt;/li&gt;&#xA;&lt;li&gt;Protoc Plugin&lt;/li&gt;&#xA;&lt;li&gt;Protocol Buffers&lt;/li&gt;&#xA;&lt;li&gt;Grpc-gateway&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;grpc&#34;&gt;Grpc&lt;/h2&gt;&#xA;&lt;h3 id=&#34;是什么&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;p&gt;Google对&lt;code&gt;Grpc&lt;/code&gt;的定义：&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;A high performance, open-source universal RPC framework&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;也就是&lt;code&gt;Grpc&lt;/code&gt;是一个高性能、开源的通用RPC框架，具有以下特性：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;强大的&lt;code&gt;IDL&lt;/code&gt;，使用&lt;code&gt;Protocol Buffers&lt;/code&gt;作为数据交换的格式，支持&lt;code&gt;v2&lt;/code&gt;、&lt;code&gt;v3&lt;/code&gt;（推荐&lt;code&gt;v3&lt;/code&gt;）&lt;/li&gt;&#xA;&lt;li&gt;跨语言、跨平台，也就是&lt;code&gt;Grpc&lt;/code&gt;支持多种平台和语言&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;支持HTTP2&lt;/strong&gt;，双向传输、多路复用、认证等&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;安装&#34;&gt;安装&lt;/h3&gt;&#xA;&lt;p&gt;1、官方推荐（需科学上网）&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u google.golang.org/grpc&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;2、通过&lt;code&gt;github.com&lt;/code&gt;&lt;/p&gt;&#xA;&lt;p&gt;进入到第一个$GOPATH目录（因为&lt;code&gt;go get&lt;/code&gt; 会默认安装在第一个下）下，新建&lt;code&gt;google.golang.org&lt;/code&gt;目录，拉取&lt;code&gt;golang&lt;/code&gt;在&lt;code&gt;github&lt;/code&gt;上的镜像库：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd /usr/local/go/path/src   &#xA;&#xA;mkdir google.golang.org&#xA;&#xA;cd google.golang.org/&#xA;&#xA;git clone https://github.com/grpc/grpc-go&#xA;&#xA;mv grpc-go/ grpc/&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;目录结构：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;google.golang.org/&#xA;└── grpc&#xA;    ...&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而在&lt;code&gt;grpc&lt;/code&gt;下有许多常用的包，例如：&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gowalker.org/google.golang.org/grpc/metadata&#34;&gt;metadata&lt;/a&gt;：定义了&lt;code&gt;grpc&lt;/code&gt;所支持的元数据结构，包中方法可以对&lt;code&gt;MD&lt;/code&gt;进行获取和处理&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gowalker.org/google.golang.org/grpc/credentials&#34;&gt;credentials&lt;/a&gt;：实现了&lt;code&gt;grpc&lt;/code&gt;所支持的各种认证凭据，封装了客户端对服务端进行身份验证所需要的所有状态，并做出各种断言&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://gowalker.org/google.golang.org/grpc/codes&#34;&gt;codes&lt;/a&gt;：定义了&lt;code&gt;grpc&lt;/code&gt;使用的标准错误码，可通用&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;protoc-plugin&#34;&gt;Protoc Plugin&lt;/h2&gt;&#xA;&lt;h3 id=&#34;是什么-1&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;p&gt;编译器插件&lt;/p&gt;&#xA;&lt;h3 id=&#34;安装-1&#34;&gt;安装&lt;/h3&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u github.com/golang/protobuf/protoc-gen-go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;将&lt;code&gt;Protoc Plugin&lt;/code&gt;的可执行文件从$GOPATH中移动到$GOBIN下&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mv /usr/local/go/path/bin/protoc-gen-go /usr/local/go/bin/&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;protocol-buffers-v3&#34;&gt;Protocol Buffers v3&lt;/h2&gt;&#xA;&lt;h3 id=&#34;是什么-2&#34;&gt;是什么&lt;/h3&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Protocol buffers are a flexible, efficient, automated mechanism for serializing structured data – think XML, but smaller, faster, and simpler. You define how you want your data to be structured once, then you can use special generated source code to easily write and read your structured data to and from a variety of data streams and using a variety of languages. You can even update your data structure without breaking deployed programs that are compiled against the &amp;ldquo;old&amp;rdquo; format.&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载六」编写一个简单的文件日志</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-02-15-log/</link>
      <pubDate>Thu, 15 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-02-15-log/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;自定义 log。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在上一节中，我们解决了 API&amp;rsquo;s 可以任意访问的问题，那么我们现在还有一个问题，就是我们的日志，都是输出到控制台上的，这显然对于一个项目来说是不合理的，因此我们这一节简单封装&lt;code&gt;log&lt;/code&gt;库，使其支持简单的文件日志！&lt;/p&gt;&#xA;&lt;h2 id=&#34;新建logging包&#34;&gt;新建&lt;code&gt;logging&lt;/code&gt;包&lt;/h2&gt;&#xA;&lt;p&gt;我们在&lt;code&gt;pkg&lt;/code&gt;下新建&lt;code&gt;logging&lt;/code&gt;目录，新建&lt;code&gt;file.go&lt;/code&gt;和&lt;code&gt;log.go&lt;/code&gt;文件，写入内容：&lt;/p&gt;&#xA;&lt;h3 id=&#34;编写file文件&#34;&gt;编写&lt;code&gt;file&lt;/code&gt;文件&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;1、 file.go：&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;logging&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;os&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;LogSavePath&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;runtime/logs/&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;LogSaveName&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;LogFileExt&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;log&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;TimeFormat&lt;/span&gt; = &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;20060102&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getLogFilePath&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;LogSavePath&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getLogFileFullPath&lt;/span&gt;() &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;prefixPath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getLogFilePath&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;suffixPath&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s%s.%s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;LogSaveName&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;().&lt;span style=&#34;color:#a6e22e&#34;&gt;Format&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;TimeFormat&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;LogFileExt&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprintf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s%s&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;prefixPath&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;suffixPath&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;openLogFile&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;filePath&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;File&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Stat&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;filePath&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;switch&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IsNotExist&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;mkDir&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;IsPermission&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;):&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Permission :%v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;handle&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;OpenFile&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;filePath&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_APPEND&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_CREATE&lt;/span&gt; | &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_WRONLY&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;0644&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;log&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Fatalf&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Fail to OpenFile :%v&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;handle&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;mkDir&lt;/span&gt;() {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;dir&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;_&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Getwd&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;MkdirAll&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dir&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;getLogFilePath&lt;/span&gt;(), &lt;span style=&#34;color:#a6e22e&#34;&gt;os&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ModePerm&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;panic(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;os.Stat&lt;/code&gt;：返回文件信息结构描述文件。如果出现错误，会返回&lt;code&gt;*PathError&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;PathError&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Op&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Path&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;os.IsNotExist&lt;/code&gt;：能够接受&lt;code&gt;ErrNotExist&lt;/code&gt;、&lt;code&gt;syscall&lt;/code&gt;的一些错误，它会返回一个布尔值，能够得知文件不存在或目录不存在&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;os.IsPermission&lt;/code&gt;：能够接受&lt;code&gt;ErrPermission&lt;/code&gt;、&lt;code&gt;syscall&lt;/code&gt;的一些错误，它会返回一个布尔值，能够得知权限是否满足&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;os.OpenFile&lt;/code&gt;：调用文件，支持传入文件名称、指定的模式调用文件、文件权限，返回的文件的方法可以用于 I/O。如果出现错误，则为&lt;code&gt;*PathError&lt;/code&gt;。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;const&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_RDONLY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_RDONLY&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 以只读模式打开文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_WRONLY&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_WRONLY&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 以只写模式打开文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_RDWR&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_RDWR&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;// 以读写模式打开文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#75715e&#34;&gt;// The remaining values may be or&amp;#39;ed in to control behavior.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_APPEND&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_APPEND&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;// 在写入时将数据追加到文件中&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_CREATE&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_CREAT&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 如果不存在，则创建一个新文件&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_EXCL&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_EXCL&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;// 使用O_CREATE时，文件必须不存在&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_SYNC&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_SYNC&lt;/span&gt;   &lt;span style=&#34;color:#75715e&#34;&gt;// 同步IO&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;O_TRUNC&lt;/span&gt;  &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; = &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;O_TRUNC&lt;/span&gt;  &lt;span style=&#34;color:#75715e&#34;&gt;// 如果可以，打开时&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;os.Getwd&lt;/code&gt;：返回与当前目录对应的根路径名&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;os.MkdirAll&lt;/code&gt;：创建对应的目录以及所需的子目录，若成功则返回&lt;code&gt;nil&lt;/code&gt;，否则返回&lt;code&gt;error&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;os.ModePerm&lt;/code&gt;：&lt;code&gt;const&lt;/code&gt;定义&lt;code&gt;ModePerm FileMode = 0777&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;编写log文件&#34;&gt;编写&lt;code&gt;log&lt;/code&gt;文件&lt;/h3&gt;&#xA;&lt;p&gt;&lt;strong&gt;2、log.go&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载五」使用 JWT 进行身份校验</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-02-14-jwt/</link>
      <pubDate>Wed, 14 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-02-14-jwt/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;JWT&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;p&gt;在前面几节中，我们已经基本的完成了 API&amp;rsquo;s 的编写，但是，还存在一些非常严重的问题，例如，我们现在的 API 是可以随意调用的，这显然还不安全全，在本文中我们通过 &lt;a href=&#34;https://github.com/dgrijalva/jwt-go&#34;&gt;jwt-go&lt;/a&gt; （&lt;a href=&#34;https://godoc.org/github.com/dgrijalva/jwt-go&#34;&gt;GoDoc&lt;/a&gt;）的方式来简单解决这个问题。&lt;/p&gt;&#xA;&lt;h2 id=&#34;下载依赖包&#34;&gt;下载依赖包&lt;/h2&gt;&#xA;&lt;p&gt;首先，我们下载 jwt-go 的依赖包，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go get -u github.com/dgrijalva/jwt-go&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;编写-jwt-工具包&#34;&gt;编写 jwt 工具包&lt;/h2&gt;&#xA;&lt;p&gt;我们需要编写一个&lt;code&gt;jwt&lt;/code&gt;的工具包，我们在&lt;code&gt;pkg&lt;/code&gt;下的&lt;code&gt;util&lt;/code&gt;目录新建&lt;code&gt;jwt.go&lt;/code&gt;，写入文件内容：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;util&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/dgrijalva/jwt-go&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/pkg/setting&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jwtSecret&lt;/span&gt; = []byte(&lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;JwtSecret&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Claims&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Username&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;username&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Password&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;`json:&amp;#34;password&amp;#34;`&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StandardClaims&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GenerateToken&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;nowTime&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Now&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;expireTime&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;nowTime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Add&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;time&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Hour&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;claims&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Claims&lt;/span&gt;{&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;username&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;password&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StandardClaims&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;ExpiresAt&lt;/span&gt; : &lt;span style=&#34;color:#a6e22e&#34;&gt;expireTime&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Unix&lt;/span&gt;(),&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;Issuer&lt;/span&gt; : &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gin-blog&amp;#34;&lt;/span&gt;,&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;},&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;tokenClaims&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewWithClaims&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SigningMethodHS256&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;claims&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;token&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tokenClaims&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SignedString&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;jwtSecret&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;token&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ParseToken&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;token&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) (&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Claims&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#a6e22e&#34;&gt;tokenClaims&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ParseWithClaims&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;token&lt;/span&gt;, &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Claims&lt;/span&gt;{}, &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;token&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;jwt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Token&lt;/span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;interface&lt;/span&gt;{}, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;jwtSecret&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;})&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tokenClaims&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;claims&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tokenClaims&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Claims&lt;/span&gt;.(&lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;Claims&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;ok&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;tokenClaims&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Valid&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;claims&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#x9;&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这个工具包，我们涉及到&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载四」Gin搭建Blog API&#39;s （三）</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-02-13-api-03/</link>
      <pubDate>Tue, 13 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-02-13-api-03/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/gin-gonic/gin&#34;&gt;Gin&lt;/a&gt;：Golang 的一个微框架，性能极佳。&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/astaxie/beego/tree/master/validation&#34;&gt;beego-validation&lt;/a&gt;：本节采用的 beego 的表单验证库，&lt;a href=&#34;https://beego.me/docs/mvc/controller/validation.md&#34;&gt;中文文档&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/jinzhu/gorm&#34;&gt;gorm&lt;/a&gt;，对开发人员友好的 ORM 框架，&lt;a href=&#34;http://gorm.io/docs/&#34;&gt;英文文档&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/Unknwon/com&#34;&gt;com&lt;/a&gt;，一个小而美的工具包。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;完成博客的文章类接口定义和编写&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;定义接口&#34;&gt;定义接口&lt;/h2&gt;&#xA;&lt;p&gt;本节编写文章的逻辑，我们定义一下接口吧！&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;获取文章列表：GET(&amp;quot;/articles&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;获取指定文章：POST(&amp;quot;/articles/:id&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;新建文章：POST(&amp;quot;/articles&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;更新指定文章：PUT(&amp;quot;/articles/:id&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;删除指定文章：DELETE(&amp;quot;/articles/:id&amp;quot;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;编写路由逻辑&#34;&gt;编写路由逻辑&lt;/h2&gt;&#xA;&lt;p&gt;在&lt;code&gt;routers&lt;/code&gt;的 v1 版本下，新建&lt;code&gt;article.go&lt;/code&gt;文件，写入内容：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gin-gonic/gin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//获取单个文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetArticle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//获取多个文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetArticles&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//新增文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AddArticle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//修改文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EditArticle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//删除文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteArticle&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们打开&lt;code&gt;routers&lt;/code&gt;下的&lt;code&gt;router.go&lt;/code&gt;文件，修改文件内容为：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routers&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gin-gonic/gin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/routers/api/v1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/EDDYCJY/go-gin-example/pkg/setting&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InitRouter&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Engine&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Group&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/v1&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#f92672&#34;&gt;...&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//获取文章列表&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/articles&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetArticles&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//获取指定文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/articles/:id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetArticle&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//新建文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;POST&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/articles&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AddArticle&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//更新指定文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PUT&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/articles/:id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EditArticle&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//删除指定文章&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DELETE&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/articles/:id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteArticle&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当前目录结构：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载三」Gin搭建Blog API&#39;s （二）</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-02-12-api-02/</link>
      <pubDate>Mon, 12 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-02-12-api-02/</guid>
      <description>&lt;h2 id=&#34;涉及知识点&#34;&gt;涉及知识点&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/gin-gonic/gin&#34;&gt;Gin&lt;/a&gt;：Golang 的一个微框架，性能极佳。&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/astaxie/beego/tree/master/validation&#34;&gt;beego-validation&lt;/a&gt;：本节采用的 beego 的表单验证库，&lt;a href=&#34;https://beego.me/docs/mvc/controller/validation.md&#34;&gt;中文文档&lt;/a&gt;。&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/jinzhu/gorm&#34;&gt;gorm&lt;/a&gt;，对开发人员友好的 ORM 框架，&lt;a href=&#34;http://gorm.io/docs/&#34;&gt;英文文档&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/Unknwon/com&#34;&gt;com&lt;/a&gt;，一个小而美的工具包。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;完成博客的标签类接口定义和编写&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;定义接口&#34;&gt;定义接口&lt;/h2&gt;&#xA;&lt;p&gt;本节正是编写标签的逻辑，我们想一想，一般接口为增删改查是基础的，那么我们定义一下接口吧！&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;获取标签列表：GET(&amp;quot;/tags&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;新建标签：POST(&amp;quot;/tags&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;更新指定标签：PUT(&amp;quot;/tags/:id&amp;quot;)&lt;/li&gt;&#xA;&lt;li&gt;删除指定标签：DELETE(&amp;quot;/tags/:id&amp;quot;)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;编写路由空壳&#34;&gt;编写路由空壳&lt;/h2&gt;&#xA;&lt;p&gt;开始编写路由文件逻辑，在&lt;code&gt;routers&lt;/code&gt;下新建&lt;code&gt;api&lt;/code&gt;目录，我们当前是第一个 API 大版本，因此在&lt;code&gt;api&lt;/code&gt;下新建&lt;code&gt;v1&lt;/code&gt;目录，再新建&lt;code&gt;tag.go&lt;/code&gt;文件，写入内容：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gin-gonic/gin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//获取多个文章标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;GetTags&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//新增文章标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AddTag&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//修改文章标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;EditTag&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;//删除文章标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteTag&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;) {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;注册路由&#34;&gt;注册路由&lt;/h2&gt;&#xA;&lt;p&gt;我们打开&lt;code&gt;routers&lt;/code&gt;下的&lt;code&gt;router.go&lt;/code&gt;文件，修改文件内容为：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;package&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;routers&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;import&lt;/span&gt; (&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;github.com/gin-gonic/gin&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gin-blog/routers/api/v1&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;gin-blog/pkg/setting&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;InitRouter&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Engine&lt;/span&gt; {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;New&lt;/span&gt;()&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Use&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Logger&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Use&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Recovery&lt;/span&gt;())&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;gin&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetMode&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;setting&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;RunMode&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Group&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/api/v1&amp;#34;&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    {&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//获取标签列表&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GET&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tags&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;GetTags&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//新建标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;POST&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tags&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;AddTag&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//更新指定标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PUT&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tags/:id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;EditTag&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;//删除指定标签&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;apiv1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DELETE&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tags/:id&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;v1&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;DeleteTag&lt;/span&gt;)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;r&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当前目录结构：&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载二」Gin搭建Blog API&#39;s （一）</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-02-11-api-01/</link>
      <pubDate>Sun, 11 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-02-11-api-01/</guid>
      <description>&lt;h2 id=&#34;思考&#34;&gt;思考&lt;/h2&gt;&#xA;&lt;p&gt;首先，在一个初始项目开始前，大家都要思考一下&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;程序的文本配置写在代码中，好吗？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;API 的错误码硬编码在程序中，合适吗？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;db 句柄谁都去&lt;code&gt;Open&lt;/code&gt;，没有统一管理，好吗？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;获取分页等公共参数，谁都自己写一套逻辑，好吗？&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;显然在较正规的项目中，这些问题的答案都是&lt;strong&gt;不可以&lt;/strong&gt;，为了解决这些问题，我们挑选一款读写配置文件的库，目前比较火的有 &lt;a href=&#34;https://github.com/spf13/viper&#34;&gt;viper&lt;/a&gt;，有兴趣你未来可以简单了解一下，没兴趣的话等以后接触到再说。&lt;/p&gt;&#xA;&lt;p&gt;但是本系列选用 &lt;a href=&#34;https://github.com/go-ini/ini&#34;&gt;go-ini/ini&lt;/a&gt; ，它的 &lt;a href=&#34;https://ini.unknwon.io/&#34;&gt;中文文档&lt;/a&gt;。大家是必须需要要简单阅读它的文档，再接着完成后面的内容。&lt;/p&gt;&#xA;&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;编写一个简单的 API 错误码包。&lt;/li&gt;&#xA;&lt;li&gt;完成一个 Demo 示例。&lt;/li&gt;&#xA;&lt;li&gt;讲解 Demo 所涉及的知识点。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;介绍和初始化项目&#34;&gt;介绍和初始化项目&lt;/h2&gt;&#xA;&lt;h3 id=&#34;初始化项目目录&#34;&gt;初始化项目目录&lt;/h3&gt;&#xA;&lt;p&gt;在前一章节中，我们初始化了一个 &lt;code&gt;go-gin-example&lt;/code&gt; 项目，接下来我们需要继续新增如下目录结构：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;go-gin-example/&#xA;├── conf&#xA;├── middleware&#xA;├── models&#xA;├── pkg&#xA;├── routers&#xA;└── runtime&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&#xA;&lt;li&gt;conf：用于存储配置文件&lt;/li&gt;&#xA;&lt;li&gt;middleware：应用中间件&lt;/li&gt;&#xA;&lt;li&gt;models：应用数据库模型&lt;/li&gt;&#xA;&lt;li&gt;pkg：第三方包&lt;/li&gt;&#xA;&lt;li&gt;routers 路由逻辑处理&lt;/li&gt;&#xA;&lt;li&gt;runtime：应用运行时数据&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;添加-go-modules-replace&#34;&gt;添加 Go Modules Replace&lt;/h3&gt;&#xA;&lt;p&gt;打开 &lt;code&gt;go.mod&lt;/code&gt; 文件，新增 &lt;code&gt;replace&lt;/code&gt; 配置项，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;module github.com/EDDYCJY/go-gin-example&#xA;&#xA;go 1.13&#xA;&#xA;require (...)&#xA;&#xA;replace (&#xA;&#x9;&#x9;github.com/EDDYCJY/go-gin-example/pkg/setting =&amp;gt; ~/go-application/go-gin-example/pkg/setting&#xA;&#x9;&#x9;github.com/EDDYCJY/go-gin-example/conf    &#x9;  =&amp;gt; ~/go-application/go-gin-example/pkg/conf&#xA;&#x9;&#x9;github.com/EDDYCJY/go-gin-example/middleware  =&amp;gt; ~/go-application/go-gin-example/middleware&#xA;&#x9;&#x9;github.com/EDDYCJY/go-gin-example/models &#x9;  =&amp;gt; ~/go-application/go-gin-example/models&#xA;&#x9;&#x9;github.com/EDDYCJY/go-gin-example/routers &#x9;  =&amp;gt; ~/go-application/go-gin-example/routers&#xA;)&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可能你会不理解为什么要特意跑来加 &lt;code&gt;replace&lt;/code&gt; 配置项，首先你要看到我们使用的是完整的外部模块引用路径（&lt;code&gt;github.com/EDDYCJY/go-gin-example/xxx&lt;/code&gt;），而这个模块还没推送到远程，是没有办法下载下来的，因此需要用 &lt;code&gt;replace&lt;/code&gt; 将其指定读取本地的模块路径，这样子就可以解决本地模块读取的问题。&lt;/p&gt;</description>
    </item>
    <item>
      <title>「连载一」Go 介绍与环境安装</title>
      <link>https://note.lican.site/posts/posts/go/gin/2018-02-10-install/</link>
      <pubDate>Sat, 10 Feb 2018 12:00:00 +0000</pubDate>
      <guid>https://note.lican.site/posts/posts/go/gin/2018-02-10-install/</guid>
      <description>&lt;h2 id=&#34;本文目标&#34;&gt;本文目标&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;学会安装 Go。&lt;/li&gt;&#xA;&lt;li&gt;知道什么是 Go。&lt;/li&gt;&#xA;&lt;li&gt;知道什么是 Go modules。&lt;/li&gt;&#xA;&lt;li&gt;了解 Go modules 的小历史。&lt;/li&gt;&#xA;&lt;li&gt;学会简单的使用 Go modules。&lt;/li&gt;&#xA;&lt;li&gt;了解 Gin，并简单跑起一个 Demo。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;准备环节&#34;&gt;准备环节&lt;/h2&gt;&#xA;&lt;h3 id=&#34;安装-go&#34;&gt;安装 Go&lt;/h3&gt;&#xA;&lt;h4 id=&#34;centos&#34;&gt;Centos&lt;/h4&gt;&#xA;&lt;p&gt;首先，根据对应的操作系统选择安装包 &lt;a href=&#34;https://studygolang.com/dl&#34;&gt;下载&lt;/a&gt;，在这里我使用的是 Centos 64 位系统，如下：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ wget https://studygolang.com/dl/golang/go1.13.1.linux-amd64.tar.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar -zxvf go1.13.1.linux-amd64.tar.gz&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mv go/ /usr/local/&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置 /etc/profile&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;vi /etc/profile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;添加环境变量 GOROOT 和将 GOBIN 添加到 PATH 中&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export GOROOT&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;/usr/local/go&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PATH&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;$PATH:$GOROOT/bin&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;配置完毕后，执行命令令其生效&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source /etc/profile&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在控制台输入&lt;code&gt;go version&lt;/code&gt;，若输出版本号则&lt;strong&gt;安装成功&lt;/strong&gt;，如下：&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ go version&#xA;go version go1.13.1 linux/amd64&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;macos&#34;&gt;MacOS&lt;/h4&gt;&#xA;&lt;p&gt;在 MacOS 上安装 Go 最方便的办法就是使用 brew，安装如下：&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
