<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Reage blog</title>
 <link href="http://www.ireage.com/atom.xml" rel="self"/>
 <link href="http://www.ireage.com/"/>
 <updated>2026-05-06T07:28:36+00:00</updated>
 <id>http://www.ireage.com</id>
 <author>
   <name></name>
   <email></email>
 </author>

 
 <entry>
   <title>POST 和 GET 在中间件的处理差异（502错误分析）</title>
   <link href="http://www.ireage.com/%E6%B5%8B%E8%AF%95/http/2026/05/06/http-post-502-get-not-error.html"/>
   <updated>2026-05-06T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E6%B5%8B%E8%AF%95/http/2026/05/06/http-post-502-get-not-error</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;在做压测的时候，出现502错误. 但是将POST 改为GET 就没有问题。 排除项目代码问题。怀疑是中间件的问题。 
当前项目是Python的Django，使用gunicorn作为WSGI服务器，nginx作为反向代理服务器.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;环境：Django + gunicorn gthread + nginx&lt;br /&gt;
现象：高并发下 POST 请求偶发 502，GET 请求无此问题，两者业务逻辑完全相同&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;构造测试环境&quot;&gt;构造测试环境&lt;/h3&gt;

&lt;p&gt;在 200 并发用户、持续压测场景下：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;路径&lt;/th&gt;
      &lt;th&gt;请求数&lt;/th&gt;
      &lt;th&gt;失败数&lt;/th&gt;
      &lt;th&gt;失败率&lt;/th&gt;
      &lt;th&gt;失败类型&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[direct] GET&lt;/code&gt;（绕过 nginx）&lt;/td&gt;
      &lt;td&gt;2610&lt;/td&gt;
      &lt;td&gt;11&lt;/td&gt;
      &lt;td&gt;0.42%&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;status=0&lt;/code&gt;（TCP 断连）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[direct] POST&lt;/code&gt;（绕过 nginx）&lt;/td&gt;
      &lt;td&gt;2575&lt;/td&gt;
      &lt;td&gt;13&lt;/td&gt;
      &lt;td&gt;0.50%&lt;/td&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;status=0&lt;/code&gt;（TCP 断连）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[nginx] GET&lt;/code&gt;（经过 nginx）&lt;/td&gt;
      &lt;td&gt;2619&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0.00%&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[nginx] POST&lt;/code&gt;（经过 nginx）&lt;/td&gt;
      &lt;td&gt;2524&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;14&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;0.55%&lt;/strong&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;502 Bad Gateway&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;结论&lt;/strong&gt;：GET 和 POST 在 gunicorn 层面失败率相同（~0.5%），但经过 nginx 后，GET 失败全部消失，POST 失败变成 502 暴露给客户端。问题在 nginx 层，不在业务代码。&lt;/p&gt;

&lt;h3 id=&quot;结论&quot;&gt;结论&lt;/h3&gt;

&lt;h4 id=&quot;原因&quot;&gt;原因&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;gunicorn –max-requests=500 — worker 每处理 500 个请求后自动退出，关闭 TCP 连接&lt;/li&gt;
  &lt;li&gt;nginx upstream 收到 TCP RST（recv() failed: Connection reset by peer）&lt;/li&gt;
  &lt;li&gt;GET：nginx 认为 GET 是幂等的（RFC 7230），自动 retry 到下一个 worker → 客户端看到 200，无感知&lt;/li&gt;
  &lt;li&gt;POST：nginx 认为 POST 不可重试（非幂等，可能有副作用）→ 直接返回 502 Bad Gateway&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;解决方案&quot;&gt;解决方案&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--max-requests-jitter=100&lt;/code&gt;&lt;/strong&gt;：让多个 worker 的退出时间随机错开，避免同时退出导致大批连接同时失效。有效，但单次退出的窗口期依然存在。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--graceful-timeout=120&lt;/code&gt;&lt;/strong&gt;：控制 worker 等待 in-flight 线程完成的时间上限。对本场景无效——请求只有 50–100ms，30 秒默认值已足够，问题不在这里。&lt;/p&gt;

&lt;h5 id=&quot;效果&quot;&gt;效果&lt;/h5&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;方案&lt;/th&gt;
      &lt;th&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[nginx] POST&lt;/code&gt; 502 数&lt;/th&gt;
      &lt;th&gt;变化&lt;/th&gt;
      &lt;th&gt;说明&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;基线（原始配置）&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;14&lt;/strong&gt;（0.55%）&lt;/td&gt;
      &lt;td&gt;—&lt;/td&gt;
      &lt;td&gt;基准&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--max-requests-jitter=100&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--graceful-timeout=120&lt;/code&gt; + &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--keep-alive=5&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;9&lt;/strong&gt;（0.35%）&lt;/td&gt;
      &lt;td&gt;↓ 36%&lt;/td&gt;
      &lt;td&gt;jitter 错开退出时间，有效但不彻底&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;上述 + nginx &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;keepalive_timeout=4s&lt;/code&gt;（&amp;lt; gunicorn keepalive=5s）&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;14&lt;/strong&gt;（0.54%）&lt;/td&gt;
      &lt;td&gt;无改善&lt;/td&gt;
      &lt;td&gt;RST 来自进程退出，不是空闲超时，此方案无效&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;上述 + nginx &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy_next_upstream non_idempotent&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;10&lt;/strong&gt;（0.40%）&lt;/td&gt;
      &lt;td&gt;↓ 29%&lt;/td&gt;
      &lt;td&gt;部分 retry 成功，但单 upstream 时 retry 也可能踩 RST&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy_request_buffering on&lt;/code&gt;&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;2&lt;/strong&gt;（0.16%）&lt;/td&gt;
      &lt;td&gt;↓ 86%&lt;/td&gt;
      &lt;td&gt;nginx 先缓冲完整 body 再连接 upstream，大幅缩小时间窗口&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h3 id=&quot;过程&quot;&gt;过程&lt;/h3&gt;

&lt;h4 id=&quot;触发源gunicorn---max-requests500&quot;&gt;触发源：gunicorn &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--max-requests=500&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;gunicorn 配置了 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--max-requests=500&lt;/code&gt;，每个 worker 处理满 500 个请求后自动退出并由 arbiter 拉起新 worker。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;源码路径&lt;/strong&gt;（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gunicorn/workers/gthread.py&lt;/code&gt;）：&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;handle_request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_requests&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Autorestarting worker after current request.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;alive&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# 标记退出
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;resp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;force_close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# 当前响应加 Connection: close
&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# 继续正常处理当前请求，返回 200
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;日志证据&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[INFO] Autorestarting worker after current request.
[INFO] Worker exiting (pid: 10)
[INFO] Booting worker with pid: 522
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;第 500 个请求本身&lt;strong&gt;正常完成并返回 200&lt;/strong&gt;，worker 随后退出。&lt;/p&gt;

&lt;h4 id=&quot;rst-的产生os-强制清理-socket&quot;&gt;RST 的产生：OS 强制清理 socket&lt;/h4&gt;

&lt;p&gt;worker 进程退出时，OS 对该进程持有的&lt;strong&gt;所有未关闭 TCP socket&lt;/strong&gt; 执行强制清理。&lt;/p&gt;

&lt;p&gt;gunicorn 的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;util.close()&lt;/code&gt; 实现：&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# 直接 close，没有先 shutdown(SHUT_WR)
&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;pass&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;当 socket 接收缓冲区还有未读数据时（nginx 已发来新请求），直接 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;close()&lt;/code&gt; 导致 OS 发送 &lt;strong&gt;TCP RST&lt;/strong&gt;（而非优雅的 FIN）。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nginx 错误日志&lt;/strong&gt;：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;recv() failed (104: Connection reset by peer) while reading response header from upstream,
  request: &quot;POST /api/items/ HTTP/1.1&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;错误码 104 = &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ECONNRESET&lt;/code&gt; = TCP RST。&lt;/p&gt;

&lt;h4 id=&quot;出问题的是哪些请求&quot;&gt;出问题的是哪些请求&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;不是&lt;/strong&gt;第 500 个请求（它正常完成）。&lt;br /&gt;
&lt;strong&gt;是&lt;/strong&gt;第 501、502、503… 个请求——这些请求通过 nginx keepalive 连接池里的&lt;strong&gt;旧连接&lt;/strong&gt;路由到了已退出的 worker，被 OS 的进程退出清理发出的 RST 拒绝。&lt;/p&gt;

&lt;p&gt;时序：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;t=0    worker-A 处理完第 500 个请求，alive=False，进程退出
       OS 对 worker-A 持有的所有 TCP 连接发 RST

t=0+   nginx 连接池里有若干条 keep-alive 连接指向 worker-A（已死）
       这些连接变成&quot;僵尸连接&quot;

t=1    新请求到来，nginx 从连接池取出一条僵尸连接，发送请求
       OS 回 RST（进程已死）
       nginx 收到 104: Connection reset by peer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;nginx-的-getpost-处理差异&quot;&gt;nginx 的 GET/POST 处理差异&lt;/h4&gt;

&lt;p&gt;GET 和 POST 的不对称处理：nginx retry 策略&lt;/p&gt;

&lt;p&gt;nginx 对 upstream 连接失败的 retry 策略遵循 RFC 7230：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;方法&lt;/th&gt;
      &lt;th&gt;是否幂等&lt;/th&gt;
      &lt;th&gt;nginx 是否 retry&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;GET、HEAD&lt;/td&gt;
      &lt;td&gt;是&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;是&lt;/strong&gt;（自动重试到下一个可用连接）&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;POST、PUT、PATCH&lt;/td&gt;
      &lt;td&gt;否&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;否&lt;/strong&gt;（不重试，直接返回 502）&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;strong&gt;nginx 日志铁证&lt;/strong&gt;：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# GET：upstream 502 → nginx 自动重试 → 客户端看到 200
GET  status=200  upstream_status=502, 200  upstream_addr=...8000, ...8000

# POST：upstream 502 → nginx 不重试 → 客户端看到 502
POST status=502  upstream_status=502       upstream_addr=...8000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;同样的 RST 事件，GET 被 nginx 静默重试消化，POST 直接暴露为 502。&lt;/p&gt;

&lt;h4 id=&quot;为什么多-worker-也无法消除&quot;&gt;为什么多 worker 也无法消除&lt;/h4&gt;

&lt;p&gt;gunicorn 启动了 2 个 worker（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-w 2&lt;/code&gt;），但问题依然存在，原因如下：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TCP 连接是点对点绑定的&lt;/strong&gt;。一条连接通过 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;accept()&lt;/code&gt; 被某个 worker 接受后，就固定属于该 worker。nginx 的 keepalive 连接池按连接存储，不按 worker 负载均衡。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nginx 有 18 个 worker 进程（worker_processes auto，18 核）
每个 nginx worker 维护独立的 keepalive 连接池（keepalive=32）
总连接池 = 18 × 32 = 576 条连接，分布在 gunicorn worker-A 和 worker-B 上

worker-A 退出时：
  ~288 条连接（指向 worker-A）全部变成僵尸
  nginx 不知道 worker-A 已死，继续从池里取这些连接发请求
  → RST → POST 502
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;增加 worker 数量只能&lt;strong&gt;降低概率&lt;/strong&gt;（每个 worker 分摊的连接比例减小），无法消除：&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;worker 数&lt;/th&gt;
      &lt;th&gt;单次退出影响连接比例&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;~50%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;~25%&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;8&lt;/td&gt;
      &lt;td&gt;~12.5%&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gunicorn --max-requests=500
    ↓ worker 处理满 500 个请求后退出
    ↓ 进程退出时 OS 对所有 socket 执行强制 close()
    ↓ socket 接收缓冲区有未读数据 → OS 发 TCP RST（非优雅 FIN）
    ↓ nginx keepalive 连接池里的旧连接变成僵尸
    ↓ 新请求复用僵尸连接 → RST
        ├── GET：nginx 自动 retry（RFC 7230 幂等方法）→ 200，客户端无感知
        └── POST：nginx 不 retry（非幂等）→ 502 Bad Gateway
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这是 gunicorn gthread worker 的已知行为（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;util.close()&lt;/code&gt; 没有先 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shutdown(SHUT_WR)&lt;/code&gt;），结合 nginx 的 RFC 合规 retry 策略，导致 POST 独有的 502。&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>区分测试工具</title>
   <link href="http://www.ireage.com/go/2025/06/05/auto_add_header.html"/>
   <updated>2025-06-05T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/06/05/auto_add_header</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;在测试管理平台中，不同测试工具发起的 HTTP 请求需要通过 HTTP Header 携带特定标签，以便平台识别和分类处理。
如何在不修改测试代码的前提下，自动为所有 HTTP 请求注入自定义 Header 成为一个关键需求。&lt;/p&gt;

&lt;h4 id=&quot;关键技术结介绍&quot;&gt;关键技术结介绍&lt;/h4&gt;

&lt;p&gt;http proxy 工作原理：&lt;/p&gt;

&lt;p&gt;正向 HTTP 代理（Forward Proxy）是一种位于客户端和目标服务器之间的代理服务器。
客户端（如浏览器、App、测试程序）先把请求发送给代理服务器，再由代理服务器转发到目标网站，然后把响应返回给客户端。&lt;/p&gt;

&lt;p&gt;过程：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;所有请求先发到代理服务器。&lt;/li&gt;
  &lt;li&gt;代理服务器替你访问目标网站。&lt;/li&gt;
  &lt;li&gt;目标网站的响应返回到代理服务器，再由代理服务器转发给你。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;通俗讲类似货物发送， 商家-》买家， 比较近的时候，直接商家-》买家，太远了就给快递，负责中转。&lt;/p&gt;

&lt;h3 id=&quot;1-方案原理&quot;&gt;1. 方案原理：&lt;/h3&gt;
&lt;p&gt;通过设置本地 HTTP 代理服务器（如 127.0.0.1:8888）；
   所有流量（HTTP/HTTPS）都通过该代理转发；
   代理服务器拦截所有请求，在请求头部自动注入自定义 Header；
   对 HTTPS 需启用中间人攻击（MITM）模式，便于读写加密流量。&lt;/p&gt;
&lt;h3 id=&quot;2-关键步骤&quot;&gt;2. 关键步骤：&lt;/h3&gt;
&lt;p&gt;启动本地代理服务；
   设置环境变量HTTP_PROXY和HTTPS_PROXY指向代理服务地址；
   在代理服务内，对所有出站请求自动注入如X-Custom-Header: testops-auto；
   支持所有语言的测试代码透明接入，无需修改测试代码本身。&lt;/p&gt;

&lt;h3 id=&quot;3-优缺点&quot;&gt;3. 优缺点：&lt;/h3&gt;
&lt;p&gt;优点：
   透明注入 Header，用户无感知；
   支持任何语言（只要支持环境变量代理）。
   缺点：
   HTTPS 需开启 MITM，可能引发证书信任问题；
   适合于测试环境，需注意环境隔离和安全。
   用户自定义http client 头中的 net.Transport, 未设置代理相关配置，会失效&lt;/p&gt;

&lt;h3 id=&quot;4-关键代码&quot;&gt;4. 关键代码：&lt;/h3&gt;

&lt;h4 id=&quot;1go-http-代理服务&quot;&gt;1.go HTTP 代理服务&lt;/h4&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;log&quot;&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;github.com/elazarl/goproxy&quot;&lt;/span&gt;
   &lt;span class=&quot;s&quot;&gt;&quot;net/http&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goproxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewProxyHttpServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleConnect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;goproxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AlwaysMitm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DoFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;goproxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProxyCtx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Header&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;X-Custom-Header&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test-platform&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Verbose&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:8888&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;proxy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2配置环境变量&quot;&gt;2.配置环境变量：&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;HTTP_PROXY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:8888
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;HTTPS_PROXY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;http://127.0.0.1:8888

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;5-自定义nettransport-处理异常场景&quot;&gt;5. 自定义net.Transport 处理异常场景&lt;/h3&gt;

&lt;p&gt;没有设置Proxy或者 Proxy = nil 字段，则不会走代理。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;Proxy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ProxyFromEnvironment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 这行必须有&lt;/span&gt;
   &lt;span class=&quot;c&quot;&gt;// 其他配置 ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Golang  取地址对编译速度的影响</title>
   <link href="http://www.ireage.com/go/2025/05/06/get_addr_impact_instrumentation_build.html"/>
   <updated>2025-05-06T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/05/06/get_addr_impact_instrumentation_build</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;最近在在做关于流量维度的执行流水了， 需要对代码做插桩， 在业务的代码每一个执行分支（block）的起始位置做插桩。用来记录执行的时候，不同block 前后顺序。 
  我们在对项目代码做了插桩之后，go build 编译代码的时候非常慢。 从原来的分钟级别变为十分钟。&lt;/p&gt;

&lt;h3 id=&quot;问题定位&quot;&gt;问题定位&lt;/h3&gt;
&lt;p&gt;通过go build -work -x 查看编译过程。  go build 输出是没有时间输出。 我这里时间是公司Devops 平台的。&lt;br /&gt;
1.先定位到编译变慢行为, 我这里找到的是在compile  阶段.&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/usr/local/go/pkg/tool/linux_amd64/compile &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$WORK&lt;/span&gt;/b965/_pkg_.a &lt;span class=&quot;nt&quot;&gt;-trimpath&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$WORK&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/b919=&amp;gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; package &lt;span class=&quot;nt&quot;&gt;-lang&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;go1.15 &lt;span class=&quot;nt&quot;&gt;-complete&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-buildid&lt;/span&gt; xxx &lt;span class=&quot;nt&quot;&gt;-goversion&lt;/span&gt; go1.15.15 &lt;span class=&quot;nt&quot;&gt;-D&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-importcfg&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$WORK&lt;/span&gt;/b919/importcfg &lt;span class=&quot;nt&quot;&gt;-pack&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4 ./cover.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.通过 compile  命令中的-p 参数， 可以看到是编译的 package
3.分析这个package 下的代码
发现是插桩后生成代码， 这里主要记录文件与block的关系。 由于业务代码比较大。这个文件在6m左右；&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;var  allFiles &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;string&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;.......&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
var blocks &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;struct&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    Loc ....
    File &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;string
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;loc1,&amp;amp;allFiles[n]&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;loc2,&amp;amp;allFiles[n]&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;loc3,&amp;amp;allFiles[n]&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;4.通过分析代码，这里为了节省内存，对所有的文件名都是通过地址引用过去的&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Golang  精准测试-找到代码修改影响范围1</title>
   <link href="http://www.ireage.com/go/2025/03/18/go_code_impact.html"/>
   <updated>2025-03-18T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/03/18/go_code_impact</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;我们会发现业务修改的代码分散多个文件，甚至多个服务中，在测试过程中，我们很难确定影响到的上游或者那些case 可以用，
 这时候我们需要找到修改代码的影响范围和上游调用函数，以便我们可以更好的进行测试。&lt;/p&gt;

&lt;h3 id=&quot;主要思路&quot;&gt;主要思路&lt;/h3&gt;

&lt;p&gt;我们讲仓库的代码符号化，提取出来结构，interface，函数，变量等信息，然后通过代码对比，找到修改的代码的影响范围。&lt;/p&gt;

&lt;p&gt;主要是：&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;环境准备：执行依赖，比如：go mod tidy, wire gen&lt;/li&gt;
  &lt;li&gt;代码解析： SSA及AST&lt;/li&gt;
  &lt;li&gt;代码符号化： 描述结构体，函数，静态调用等信息&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;代码实现&quot;&gt;代码实现&lt;/h3&gt;

&lt;h4 id=&quot;load-仓库代码&quot;&gt;load 仓库代码&lt;/h4&gt;

&lt;p&gt;使用 package.Load 加载代码， 用获取AST及SSA 信息。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/fc/blob/master/code_anaylsis/scan.go#L108&quot;&gt;入口代码&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;分析函数body-中调用新&quot;&gt;分析函数body 中调用新&lt;/h4&gt;

&lt;p&gt;主要对ssa.Function 中的block 进行处理， 有以下需要注意的:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;这里需要注意匿名函数和在参数中的匿名函数&lt;/li&gt;
  &lt;li&gt;主要不同的调用方式， 比如通过通过interface 和结构体。 目前通过interface 分析还不够完善，需要进一步完善。（后续会支持根据依赖注入）&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;[代码](https://github.com/rentiansheng/fc/blob/master/code_anaylsis/function.go#L16】&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parserFuncBodyBlocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Blocks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 如果有匿名函数处理&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closuresFn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AnonFuncs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;itemC1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itemC2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parserFuncBodyCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;closuresFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itemC1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itemC2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Golang  精准测试-找到两次部署差异协助测试</title>
   <link href="http://www.ireage.com/go/2025/03/12/go_code_compare.html"/>
   <updated>2025-03-12T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/03/12/go_code_compare</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;在测试过程中，同一需求可能会经历多次部署，但部分部署的代码改动较小。如果每次都进行全量测试，成本较高。因此，我们希望通过代码分析来判断之前的测试或审查是否仍然有效。&lt;/p&gt;

&lt;p&gt;在代码对比过程中，需要忽略一些不影响逻辑的改动，例如：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;代码中的注释&lt;/li&gt;
  &lt;li&gt;代码中的空格和换行符&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;目标是实现精准测试，重点关注本次修改所影响的功能。对于已测试过的部分，可以降低测试关注度。例如：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;识别相关的测试用例（自动化、手动测试、流量回放）并重新执行或生成新的测试用例&lt;/li&gt;
  &lt;li&gt;合并覆盖率数据，确保改动代码已被测试
提供未改动代码的函数测试功能合并，指导测试过程，达到”改过即测过”的目标。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;注意：&lt;/em&gt; 修改一行代码，不是仅需要测试一行代码，他有一个影响范围，每一个函数是一个独立的功能，所以我们需要测试的是一个函数。 这里可以和增量代码结合&lt;/p&gt;

&lt;h3 id=&quot;主要对比思路&quot;&gt;主要对比思路&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;AST 解析：通过 go/parser 解析 Go 代码，生成 AST（抽象语法树）。&lt;/li&gt;
  &lt;li&gt;获取函数信息：提取所有函数的签名及其 AST 结构。&lt;/li&gt;
  &lt;li&gt;对比函数：
    &lt;ol&gt;
      &lt;li&gt;通过函数签名匹配相同名称的函数&lt;/li&gt;
      &lt;li&gt;忽略无关信息（如注释、空格、换行、位置信息, 调用其他函数等）&lt;/li&gt;
      &lt;li&gt;对比 AST 结构，判断函数逻辑是否一致&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;识别影响范围：
    &lt;ol&gt;
      &lt;li&gt;找出修改过的函数，并确定其影响的测试范围&lt;/li&gt;
      &lt;li&gt;对未修改的函数复用测试结果，减少回归测试开销&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;注意：&lt;/em&gt;  这里需要忽律一些对比字段值，比如： 位置信息，第三方调用的函数(AST 将所有信息关联起来，如果存在调用，本地AST 其他对象，这里也会受影响的)&lt;/p&gt;

&lt;h3 id=&quot;效果&quot;&gt;效果&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c&quot;&gt;// file1.go 内容&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;same1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;/*xxxx*/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;same2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;same1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;same2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// file2.go 内容&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;same2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;same1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;methodFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;same1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;same2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diff1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;对比结果如下：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;methodFunc.same1,methodFunc.same2,same1,same2 等四个函数在file1.go 和file2.go 内容是一样的&lt;/li&gt;
  &lt;li&gt;methodFunc.diff1,methodFunc.diff2,diff1,diff2 等四个函数在file1.go 和file2.go 内容是不一样的&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;根据结果我们发现，注释和位置信息不影响结果判断。&lt;/p&gt;

&lt;h3 id=&quot;具体是实现&quot;&gt;具体是实现&lt;/h3&gt;

&lt;p&gt;具体代码在: &lt;a href=&quot;https://github.com/rentiansheng/fc/tree/master/code&quot;&gt;code compare&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>go  插桩技术</title>
   <link href="http://www.ireage.com/go/2025/03/09/go_code_instrument.html"/>
   <updated>2025-03-09T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/03/09/go_code_instrument</id>
   <content type="html">&lt;h2 id=&quot;1插桩技术&quot;&gt;1.插桩技术&lt;/h2&gt;
&lt;p&gt;一种在程序执行过程中插入额外代码的技术，通常用于性能分析、日志记录、调试和安全监控等场景。它可以在程序的不同阶段（编译期、链接期、运行时）进行插入，具体方式包括手动插桩、编译器插桩、动态插桩等。&lt;/p&gt;

&lt;h3 id=&quot;11--插桩技术&quot;&gt;1.1  插桩技术&lt;/h3&gt;
&lt;h4 id=&quot;111-静态插桩&quot;&gt;1.1.1 静态插桩&lt;/h4&gt;
&lt;p&gt;在编译期或链接期，直接修改源代码或二进制文件，在关键函数或代码路径插入额外的分析代码。例如：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;编译期插桩：通过修改源代码或借助编译器提供的功能（如 GCC 插桩 -finstrument-functions）在函数入口和出口插入分析代码。 https://github.com/qiniu/goc https://github.com/alibaba/opentelemetry-go-auto-instrumentation&lt;/li&gt;
  &lt;li&gt;链接期插桩：使用链接器（如 LLVM Pass、Go 的 -cover 选项）修改目标文件或可执行文件，插入额外代码。  https://github.com/golang/go/blob/master/src/cmd/cover/cover.go
    &lt;h4 id=&quot;112-动态插桩&quot;&gt;1.1.2. 动态插桩&lt;/h4&gt;
    &lt;p&gt;在程序运行时，利用动态代码修改技术，在目标程序中插入代码，常见方法包括：&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;使用调试 API（如 ptrace，GDB 插桩）&lt;/li&gt;
  &lt;li&gt;使用 JIT 代码重写（如 DynInst，Golang runtime 插桩） https://medium.com/kokster/writing-a-jit-compiler-in-golang-964b61295f&lt;/li&gt;
  &lt;li&gt;二进制修改（如 frida、Pin、eBPF 在内核态/用户态插桩）  github.com/cilium/ebpf&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;12-golang-插桩技术应用及选择&quot;&gt;1.2 golang 插桩技术应用及选择&lt;/h3&gt;
&lt;p&gt;主要有浸入式和非侵入。 
浸入式， 比如：metrics, tracing, logging
非侵入式，  比如： go test 代码覆盖率&lt;/p&gt;

&lt;p&gt;注意， 现在go 所谓非侵入式的插桩， 都是在编译期间插入的， 也就是静态插桩。&lt;/p&gt;

&lt;h2 id=&quot;2-golang-插桩技术应用&quot;&gt;2. golang 插桩技术应用&lt;/h2&gt;

&lt;h3 id=&quot;21-浸入式插桩&quot;&gt;2.1 浸入式插桩&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;metrics
    &lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;metrics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;USS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Download&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;tracing
    &lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tracing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StartSpanFromContext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Finish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;logging
    &lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;service&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;download&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;success&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;21-golang-非侵入式&quot;&gt;2.1 golang 非侵入式&lt;/h3&gt;

&lt;p&gt;golang 非侵入式插桩， 就是在编译期间插入的， 也就是静态插桩。&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cover&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;out&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;22-golang-市场常见的插桩工具&quot;&gt;2.2 golang 市场常见的插桩工具&lt;/h3&gt;

&lt;p&gt;golang 场景的非侵入式插桩工具，是在go build 前， 通过对源代码预处理（Preprocess）和代码注入（Instrument）完成。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/qiniu/goc&quot;&gt;goc&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/alibaba/opentelemetry-go-auto-instrumentation&quot;&gt;opentelemetry&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;因为目前在go 文件编译二进制的过程中，未暴露出来任何hook功能， 
golang 具体编译如下:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;源码解析：Golang编译器会先解析源代码文件，将其转化为抽象语法树（AST）。&lt;/li&gt;
  &lt;li&gt;类型检查：解析后会进行类型检查，确保代码符合Golang的类型系统。&lt;/li&gt;
  &lt;li&gt;语义分析：对程序的语义进行分析，包括变量的定义和使用、包导入等。(SSA)&lt;/li&gt;
  &lt;li&gt;编译优化：将语法树转化为中间表示， 进行各种优化，提高代码执行效率。&lt;/li&gt;
  &lt;li&gt;代码生成：生成目标平台的机器代码。&lt;/li&gt;
  &lt;li&gt;链接：将不同包和库链接成一个单一的可执行文件。&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;23-如何实现编译前插桩&quot;&gt;2.3 如何实现编译前插桩&lt;/h3&gt;

&lt;p&gt;通过 AST 解析代码结构，将插桩代码注入到源代码中，然后再进行编译。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_importPath&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;github.com/rentiansheng/instrumentation-func/demo_log&quot;&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;//  gen import  &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ImportFunctrace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;importFlag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Imports&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_importPath&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;importFlag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 如果没有导入包,  导入包&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;importFlag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;astutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AddImport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_importPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// 生成defer 代码&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;genDefer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packageName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DeferStmt&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sliceParams&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CompositeLit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ArrayType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Elt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 空接口&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Methods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FieldList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Elts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;callExpr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CallExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Fun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CallExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Fun&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SelectorExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;X&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewIdent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;demo_log&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;Sel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewIdent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Duration&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BasicLit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Kind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STRING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;packageName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;			    
                &lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BasicLit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Kind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STRING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DeferStmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;Call&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callExpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;genFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	
    &lt;span class=&quot;c&quot;&gt;// 插入defer函数&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Decls&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;funcDel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FuncDecl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;deferStmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;genDefer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcDel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;funcDel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deferStmt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcDel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>func 绑定</title>
   <link href="http://www.ireage.com/go/2025/02/14/go_link_name.html"/>
   <updated>2025-02-14T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/02/14/go_link_name</id>
   <content type="html">&lt;h1 id=&quot;1go-linkname-介绍&quot;&gt;1.go linkname 介绍&lt;/h1&gt;

&lt;p&gt;//go:linkname 是 Go 语言中的一个特殊编译指令，用来在编译期间将一个标识符链接到另一个标识符，特别是用于访问未公开（未导出）的标识符。这种指令允许在 Go 代码中跨包访问原本无法直接访问的非公开成员，通常用于优化或者底层的调试操作。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;//go:linkname &amp;lt;新标识符&amp;gt; &amp;lt;包名&amp;gt;.&amp;lt;原始标识符&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;新标识符&gt;：指定你在当前包中希望使用的名称。
&lt;/新标识符&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;包名&gt;.&lt;原始标识符&gt;：指定要链接的目标符号，通常是其他包中的私有成员（如非公开的结构体或函数）。

&lt;/原始标识符&gt;&lt;/包名&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;2使用场景&quot;&gt;2.使用场景&lt;/h1&gt;

&lt;ul&gt;
  &lt;li&gt;访问私有符号：某些情况下，Go 的标准库或第三方库中的标识符是未公开的，但你希望访问它们。这时可以使用 //go:linkname 来绕过 Go 的访问控制限制。&lt;/li&gt;
  &lt;li&gt;跨包共享实现：有时你希望在多个包之间共享内部实现，//go:linkname 可以帮助你在不暴露 API 的情况下实现这一目标。&lt;/li&gt;
  &lt;li&gt;性能优化或低级调试：如果你需要访问底层的实现，或者调试一些低级别的行为，可以使用此指令来确保可以直接访问特定的符号。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;3-注意事项&quot;&gt;3. 注意事项&lt;/h1&gt;

&lt;p&gt;live 环境不要使用， 仅用于做测试， 使用会被go 官方嫌弃&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;仅限编译期使用：//go:linkname 只在编译时有效，它不会在运行时对代码产生任何影响。&lt;/li&gt;
  &lt;li&gt;绕过访问控制：它绕过了 Go 语言的访问控制（即大写字母表示导出、以小写字母开头表示未导出）。这意味着你可以访问通常无法访问的私有符号，但这也可能导致不安全的代码实践。&lt;/li&gt;
  &lt;li&gt;不推荐用于生产环境：虽然 //go:linkname 是 Go 编译器支持的，但它通常不适合生产环境中的日常使用，因为它违反了 Go 语言的封装和模块化原则。&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;4示例&quot;&gt;4.示例&lt;/h1&gt;

&lt;p&gt;参考： https://github.com/rentiansheng/go/blob/release/src/routine/routine.go&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goroutineDoneFn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:linkname Id runtime.GoID&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:linkname Split runtime.GoSplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:linkname Value runtime.GoValue&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:linkname Set runtime.GoSetValue&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:linkname WithDone runtime.GoWithDone&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WithDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goroutineDoneFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:linkname IsDone runtime.GoIsDone&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IsDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>通过修改GO 源代码，支持goroutine  自动done</title>
   <link href="http://www.ireage.com/go/2025/02/13/goroutine_auto_done.html"/>
   <updated>2025-02-13T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/02/13/goroutine_auto_done</id>
   <content type="html">&lt;h2 id=&quot;1-原理&quot;&gt;1. 原理&lt;/h2&gt;

&lt;p&gt;在goroutine 执行过程中，在做协程调度的时候，我们需要判断协程是否执行完成。如果没有执行完成，我们需要继续调度。如果执行完成，抛出异常。&lt;/p&gt;

&lt;h2 id=&quot;2实现&quot;&gt;2.实现&lt;/h2&gt;

&lt;h3 id=&quot;21-在runtime2go-文件中添加字段-用来帮助调度协程是否执行完成&quot;&gt;2.1 在runtime2.go 文件中添加字段 用来帮助调度协程是否执行完成&lt;/h3&gt;

&lt;p&gt;文件具体位置在 $GOPATH/src/go/src/runtime/runtime2.go 文件中&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//  done chan&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goroutineDoneFn&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goroutineDoneFn&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h3 id=&quot;22-在procgo-文件中添加控制方法和自动检查逻辑&quot;&gt;2.2 在proc.go 文件中添加控制方法和自动检查逻辑&lt;/h3&gt;

&lt;p&gt;文件具体位置在 $GOPATH/src/go/src/runtime/proc.go 文件中。我们需要在创建协程的时候，继承来自父协程的done chan。&lt;/p&gt;

&lt;p&gt;在调用的时候，我们需要判断done chan 是否关闭。如果关闭，说明协程执行完成，发出异常。否则继续调度。&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c&quot;&gt;/*** goroutine schedule check is done ***/&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inheritTime&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goIsDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;execute: goroutine is done&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;/***  控制方法 ***/&lt;/span&gt;


&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoSplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoWithDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goroutineDoneFn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoIsDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goIsDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goIsDone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;c&quot;&gt;/***  创建协程时候，继承数据 ***/&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newproc1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;funcval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callergp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callerpc&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parked&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;waitreason&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;waitReason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;newg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callergp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;done&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newg&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4编译源代码&quot;&gt;4.编译源代码&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/src/go/src
./make.bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;5测试example&quot;&gt;5.测试example&lt;/h2&gt;

&lt;p&gt;测试样例在 $GOPATH/src/go/reage/main.go 文件中&lt;/p&gt;

&lt;p&gt;执行的时候 会抛出异常，说明协程执行完成。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Hello, word 1
Hello, word 18 test
Hello, word 19 &amp;lt;nil&amp;gt;
Hello, word 20 &amp;lt;nil&amp;gt;
fatal error: execute: goroutine is done

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>通过修改GO 源代码，支持获取goroutine id 和 协程调用链全局上下文</title>
   <link href="http://www.ireage.com/go/2025/01/08/goroutine_id_and_global_context.html"/>
   <updated>2025-01-08T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2025/01/08/goroutine_id_and_global_context</id>
   <content type="html">&lt;h2 id=&quot;1背景&quot;&gt;1.背景&lt;/h2&gt;

&lt;p&gt;在开发过程中，我们经常需要获取goroutine id 和全局上下文。但是go runtime 并没有提供这样的接口。我们可以通过修改go runtime 源码，添加这样的接口。&lt;/p&gt;

&lt;h2 id=&quot;2下载源代码&quot;&gt;2.下载源代码&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/src
git clone https://github.com/rentiansheng/go.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;go
git fetch &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git checkout &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; toy_context
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;src
&lt;span class=&quot;c&quot;&gt;## 编译命令&lt;/span&gt;
./make.bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;3修改源代码&quot;&gt;3.修改源代码&lt;/h2&gt;

&lt;p&gt;如果想要获取goroutine id 和 实现协程调用链全局上下文， 我们需要找到协程定义的结构及提供对应的访问API。
我们需要在协程创建的时候，自动继承父goroutine上下文信息, 同时支持设置上下文信息，或者重置上下文信息。&lt;/p&gt;

&lt;p&gt;协程定义在 $GOPATH/src/go/src/runtime/runtime2.go 文件中。我们需要未他加一个字段，用来存储上下文信息&lt;/p&gt;

&lt;p&gt;协程管理在 $GOPATH/src/go/src/runtime/proc.go 文件中。我们需要在创建协程的时候将上下文信息传递给协程。&lt;/p&gt;

&lt;p&gt;具体修改如下：&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;在runtime2.go 文件中添加字段&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// global context &lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ol&gt;
  &lt;li&gt;在proc.go 文件中添加上下文传递&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;goid&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoSplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;//go:nosplit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GoSetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;getg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newproc1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;funcval&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callergp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callerpc&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uintptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parked&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;waitreason&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;waitReason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;g&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;newg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callergp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newg&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4编译源代码&quot;&gt;4.编译源代码&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/src/go/src
./make.bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;5测试example&quot;&gt;5.测试example&lt;/h2&gt;

&lt;p&gt;测试样例在 $GOPATH/src/go/reage/main.go 文件中&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;runtime&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;time&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, word&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoSpilt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoSetValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gSplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, word&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gSplit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoSpilt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, word&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello, word&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GoValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;go源代码编译成功后，运行测试样例， 具体命令如下：&lt;/p&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/src/go/

&lt;span class=&quot;nv&quot;&gt;GOROOT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/Users/tiansheng.ren/goDev/src/go  ./bin/go   run ./reage/main.go

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;输出结果如下(其中数字是协程id，每次执行会有差异)：&lt;/p&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Hello, word 1
Hello, word 20 &amp;lt;nil&amp;gt;
Hello, word 21 &amp;lt;nil&amp;gt;
Hello, word 19 &lt;span class=&quot;nb&quot;&gt;test
&lt;/span&gt;Hello, word 22 &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>通过LSP分析代码函数调用链路</title>
   <link href="http://www.ireage.com/code%20anaylsis/2024/05/11/function-call-trace.html"/>
   <updated>2024-05-11T00:00:00+00:00</updated>
   <id>http://www.ireage.com/code%20anaylsis/2024/05/11/function-call-trace</id>
   <content type="html">&lt;h1 id=&quot;背景&quot;&gt;背景&lt;/h1&gt;
&lt;p&gt;在衡量测试质量时候，需要考虑核心链路是否被覆盖。避免核心链路出现问题。
需要通过入API 路由找到所有被调用的含漱液。&lt;/p&gt;

&lt;p&gt;目前函数调用链数实现方案：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;代码静态分析&lt;/li&gt;
  &lt;li&gt;日志分析&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;两种方法各有缺点，链路的准确性及完整性难以保证。
同时采用AST 分析源码得到代码抽象语法树，
通过对代码文件的static anaylsis找到函数定义及函数调用位置。 
直接基于代码static code anaylsis分析缺少上下问信息。对于动态调用无法处理，
动态调用需要通过当前package 到import 与 interface 约束签名才能找到对应的关系。否则调用链路噪点太多。&lt;/p&gt;

&lt;h1 id=&quot;新思路&quot;&gt;新思路&lt;/h1&gt;

&lt;p&gt;经过对比发现IDE(goland,vscode)中跳转是一样的。
通过查找资料发现使用的gopls工具，一个叫LSP 协议。
通过几个命令串联即可以完成任务。&lt;/p&gt;

&lt;p&gt;LSP 协议地址。 https://microsoft.github.io/language-server-protocol/&lt;/p&gt;

&lt;p&gt;gopls 提供基于socket 的通信。&lt;/p&gt;

&lt;h2 id=&quot;lsp-用到协议&quot;&gt;LSP 用到协议&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;用workspace_symbol找到入口函数&lt;/li&gt;
  &lt;li&gt;使用semtok 获取文件语义&lt;/li&gt;
  &lt;li&gt;根据semtok 找到函数调用的位置&lt;/li&gt;
  &lt;li&gt;调用implementation 找具体的实现&lt;/li&gt;
  &lt;li&gt;跳转2. 直到被调用的文件，不是项目内代码&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;workspace_symbol&quot;&gt;workspace_symbol:&lt;/h3&gt;

&lt;p&gt;用于在工作区中搜索符号（symbol）。符号可以是函数、变量、类等代码实体的名称。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gopls workspace_symbol &apos;UserServiceImpl.QueryUserByUserEmail&apos;

/Users/reage/goplsDev/src/test/service/user.go:72:29-49 UserServiceImpl.QueryUserByUserEmail Method
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;symbols&quot;&gt;symbols:&lt;/h3&gt;

&lt;p&gt;显示所选文件的符号&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gopls symbols  service/user.go

UserService Interface 21:6-21:17
CreateUser Method 23:2-23:12
CreateUserPretty Method 24:2-24:18
DeleteUser Method 27:2-27:12
ModifyUser Method 25:2-25:12
ModifyUserPretty Method 26:2-26:18
QueryUser Method 22:2-22:11
QueryUserByUserEmail Method 28:2-28:22
UserServiceImpl Struct 31:6-31:21
departmentRpo Field 33:2-33:15
repo Field 32:2-32:6
NewUserServiceImpl Function 36:6-36:24
(*UserServiceImpl).QueryUser Method 40:29-40:38
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;implementation&quot;&gt;implementation:&lt;/h3&gt;

&lt;p&gt;显示所选标识符的实现， 跳转到实现&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gopls implementation  test/role.go:10:11

/Users/reage/goplsDev/src/test/service/role.go:14:6-21
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;definition&quot;&gt;definition:&lt;/h3&gt;

&lt;p&gt;显示所选标识符的声明， 转到定义&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gopls definition test/service/role.go:25:35
/Users/reage/goplsDev/src/test/define/role.go:7:6-14: defined here as type RoleInfo struct {
    Id       uint64 `json:&quot;id&quot;`
    RoleName string `json:&quot;role_name&quot;`
    RoleDesc string `json:&quot;role_desc&quot;`
    Status   uint8  `json:&quot;status&quot;`
}


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;semtok&quot;&gt;semtok:&lt;/h3&gt;

&lt;p&gt;显示指定文件的语义标记， 文件中不同位置的语义信息，用来做高亮显示&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gopls semtok  test/service/role.go

/*⇒7,keyword,[]*/package /*⇒7,namespace,[]*/service

/*⇒6,keyword,[]*/import (
&quot;context&quot;/*⇐7,namespace,[]*/

	&quot;github.com/rentiansheng/test/define&quot;/*⇐6,namespace,[]*/
	&quot;github.com/rentiansheng/test/repository&quot;/*⇐10,namespace,[]*/
)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;highlight&quot;&gt;highlight:&lt;/h3&gt;

&lt;p&gt;显示所选标识符的突出显示, 找到被引用的位置&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gopls highlight  test/service/role.go:28:9
 /Users/reage/goplsDev/src/test/service/role.go:28:2-10
 /Users/reage/goplsDev/src/test/service/role.go:29:26-34
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>ChatGLM2-6B install</title>
   <link href="http://www.ireage.com/other/2023/12/22/chatglm2-6b-install.html"/>
   <updated>2023-12-22T00:00:00+00:00</updated>
   <id>http://www.ireage.com/other/2023/12/22/chatglm2-6b-install</id>
   <content type="html">&lt;h3 id=&quot;准备环境&quot;&gt;准备环境&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;python3 (miniconda)
    &lt;h3 id=&quot;下载代码和模型&quot;&gt;下载代码和模型&lt;/h3&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#  workspace = pwd&lt;/span&gt;
git clone https://github.com/THUDM/ChatGLM2-6B

&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;ChatGLM2-6B

&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;THUDM
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;THUDM

&lt;span class=&quot;c&quot;&gt;# git lfs not found,  &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# brew update&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# brew install git-lfs&lt;/span&gt;
git lfs &lt;span class=&quot;nb&quot;&gt;install

&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GIT_LFS_SKIP_SMUDGE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1


git clone https://huggingface.co/THUDM/chatglm2-6b

&lt;span class=&quot;c&quot;&gt;# if you want to clone without large files – just their pointers&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# prepend your git clone with the following env var:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;安装依赖&quot;&gt;安装依赖&lt;/h3&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c&quot;&gt;# 回到 ${workspace}目录， 也有ChatGLM2-6B 目录&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ..

&lt;span class=&quot;c&quot;&gt;# 如果网络不好可以切换镜像  &lt;/span&gt;
pip3.9 &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; requirements.txt


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;demo-配置&quot;&gt;demo 配置&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;注意 THUDM/chatglm2-6b  表示在${workspace}目录 下路径。 如果嫌烦直接用却对路径即可。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;配置不同算力&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# GPU&lt;/span&gt;
model &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoModel.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.cuda&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# CPU &lt;/span&gt;
model &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoModel.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.float&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# mac &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 对于搭载了 Apple Silicon 或者 AMD GPU 的Mac，可以使用 MPS 后端来在 GPU 上运行 ChatGLM-6B。需要参考 Apple 的 官方说明 安装 PyTorch-Nightly（正确的版本号应该是2.1.0.dev2023xxxx，而不是2.0.0）。&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#目前在 MacOS 上只支持从本地加载模型。将代码中的模型加载改为从本地加载，并使用 mps 后端：&lt;/span&gt;
model &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoModel.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.half&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;.to&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;mps&apos;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;web-ui&quot;&gt;web ui&lt;/h4&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 以web_demo.py 为例子&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;#  关注 以下两行&lt;/span&gt;

tokenizer &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoTokenizer.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
model &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoModel.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.cuda&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;term&quot;&gt;term&lt;/h4&gt;
&lt;p&gt;参考链接： https://huggingface.co/THUDM/chatglm2-6b&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;python3.9
from transformers import AutoTokenizer, AutoModel
tokenizer &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoTokenizer.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
model &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; AutoModel.from_pretrained&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;THUDM/chatglm2-6b&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;trust_remote_code&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;True&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.float&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
model &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; model.eval&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
response, &lt;span class=&quot;nb&quot;&gt;history&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; model.chat&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;tokenizer, &lt;span class=&quot;s2&quot;&gt;&quot;你好&quot;&lt;/span&gt;, &lt;span class=&quot;nb&quot;&gt;history&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=[])&lt;/span&gt;
print&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;遇到的问题&quot;&gt;遇到的问题&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;AttributeError: ‘Textbox’ object has no attribute ‘style’&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;user_input &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; gr.Textbox&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;show_label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;False, &lt;span class=&quot;nv&quot;&gt;placeholder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Input...&quot;&lt;/span&gt;, &lt;span class=&quot;nv&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;10&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;.style&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
AttributeError: &lt;span class=&quot;s1&quot;&gt;&apos;Textbox&apos;&lt;/span&gt; object has no attribute &lt;span class=&quot;s1&quot;&gt;&apos;style&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;解决方法：
重新安全 gradio 为 3.50.0&lt;/p&gt;

&lt;p&gt;https://github.com/THUDM/ChatGLM-6B/issues/1417&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pip3.9 uninstall gradio
pip3.9 &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;gradio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;3.40.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ol&gt;
  &lt;li&gt;ModuleNotFoundError: No module named ‘transformers_modules.THUDM/chatglm2-6b’
```shell
  File “&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 1050, in _gcd_import
  File &quot;&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 1027, in _find_and_load
  File &quot;&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 992, in _find_and_load_unlocked
  File &quot;&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 241, in _call_with_frames_removed
  File &quot;&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 1050, in _gcd_import
  File &quot;&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 1027, in _find_and_load
  File &quot;&lt;frozen importlib._bootstrap=&quot;&quot;&gt;&quot;, line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named &apos;transformers_modules.THUDM/chatglm2-6b&apos;&lt;/frozen&gt;&lt;/frozen&gt;&lt;/frozen&gt;&lt;/frozen&gt;&lt;/frozen&gt;&lt;/frozen&gt;&lt;/frozen&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transformers 可能过高

解决方法：
```shell
pip uninstall transformers
pip install transformers==4.26.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>reflect 使用总结</title>
   <link href="http://www.ireage.com/golang/2022/12/12/go_reflect.md.html"/>
   <updated>2022-12-12T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2022/12/12/go_reflect.md</id>
   <content type="html">&lt;h2 id=&quot;1-如何确定数据类型&quot;&gt;1 如何确定数据类型&lt;/h2&gt;

&lt;p&gt;使用 reflect.Kind 或者reflect.Type&lt;/p&gt;

&lt;h3 id=&quot;11-reflectkind&quot;&gt;1.1 reflect.Kind&lt;/h3&gt;

&lt;p&gt;go的基础类型, 类型是有限，可以被穷举。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;type My string  kind=string
type kv map[string]interface{}  kind=map
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;12--reflecttype&quot;&gt;1.2  reflect.Type&lt;/h3&gt;

&lt;p&gt;用户定义的类型, 内置类型及用户type 定义类型及闭包类型，&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;type myStr string   type= main.myStr
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;2-如何操作数据&quot;&gt;2 如何操作数据&lt;/h2&gt;

&lt;p&gt;注意： reflect 操作需要开发去考虑边界情况，出现数据类型不匹配，越界，未初始化，非类型操作函数等情况会直接panic。&lt;/p&gt;

&lt;p&gt;reflect 提供一系列操作基础数据的操作 比如： GetXXX,SetXXX.&lt;/p&gt;

&lt;p&gt;reflect 对一些操作做聚合，比如：Elem(),Key(), Len(),数字操作int,int8,int16,int32,int64 使用Int(), SetInt(x)&lt;/p&gt;

&lt;p&gt;reflect 对数据操作是一个超集合，需要根据类型使用不同函数&lt;/p&gt;

&lt;h3 id=&quot;21-访问数据需要注意&quot;&gt;2.1 访问数据需要注意&lt;/h3&gt;

&lt;p&gt;Elem() ： 用来获取复杂数据类项目的值， 比如： 指针，slice，array, map 的Value,
Map 操作： 方法 map 的key 可以用reflect.ValueOf(kv{}).Type().Key() 来确定类型， MapKeys(), MapRange(),MapIndex() 来访问
Struct 操作： 需要注意inline 结构体及私有对象操作, 需要递归处理，无法用Field获取到对应Field&lt;/p&gt;

&lt;h3 id=&quot;22-修改数据需要注意&quot;&gt;2.2 修改数据需要注意&lt;/h3&gt;
&lt;p&gt;CanXXX 方法提供数据类型是否配置校验
操作的对象必须是指针对象， 可以用 CanSet() 方法判读
reflect.New 出来的是指针类型，赋值时候需要注意， 
Array 对象操作需要注意，不能append。需要用index 修改
Struct 操作的时候， FIeld,FieldByIndex无法处理inline struct 字段， 私有字段不允许修改，如果需要修改可以与unsafe.Pointer
IsZero() 与IsNil() 区别。 IsZero()对所有数据类型有效，默认值及nil 为true， InNil()仅对 chan, func, interface, map, pointer, or slice 有效&lt;/p&gt;

&lt;h2 id=&quot;3-使用样例&quot;&gt;3. 使用样例&lt;/h2&gt;

&lt;p&gt;golang 数据深拷贝的类库，支持数据自动映射。 map to struct, struct to map, struct to struct.
https://github.com/rentiansheng/mapper&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>golang mapper 数据深拷贝</title>
   <link href="http://www.ireage.com/golang/2022/10/27/go_mapper.html"/>
   <updated>2022-10-27T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2022/10/27/go_mapper</id>
   <content type="html">&lt;h2 id=&quot;mapper&quot;&gt;Mapper&lt;/h2&gt;
&lt;p&gt;golang 数据深拷贝的类库，支持数据自动映射。 map to struct, struct to map, struct to struct.&lt;/p&gt;

&lt;h3 id=&quot;install&quot;&gt;Install&lt;/h3&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;github&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rentiansheng&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;getting-started&quot;&gt;Getting Started&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;context&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;

	&lt;span class=&quot;s&quot;&gt;&quot;github.com/rentiansheng/mapper&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testCopyStructInline&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testCopyStructSrc&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;           &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;AliasCopy&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;alias_copy&quot;`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;privateString&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;testCopyStructInline&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testCopyStructDst&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;           &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Copy&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;alias_copy&quot;`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;privateString&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;testCopyStructInline&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testCopyStructSrc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;           &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;AliasCopy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;&quot;alias copy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;privateString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;item&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;testCopyStructInline&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testCopyStructInline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;inline a&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;inline b private&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testCopyStructDst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mapper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AllMapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TODO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.Int field                    &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.AliasCopy field              &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AliasCopy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.privateString field          &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;privateString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;privateString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.Strings field                &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.testCopyStructInline.A field &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.testCopyStructInline.B field &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// test deep copy&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;change item&quot;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;struct.Strings deep copy test       &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Strings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;features&quot;&gt;Features&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;支持struct私有字段自动映射&lt;/li&gt;
  &lt;li&gt;支持slice 自动映射&lt;/li&gt;
  &lt;li&gt;支持按照字段名自动映射&lt;/li&gt;
  &lt;li&gt;支持按照tag 自动映射&lt;/li&gt;
  &lt;li&gt;支持struct 到map 自动映射&lt;/li&gt;
  &lt;li&gt;支持map 到 struct 自动映射&lt;/li&gt;
  &lt;li&gt;支持[]byte to string&lt;/li&gt;
  &lt;li&gt;数据类型自动识别&lt;/li&gt;
  &lt;li&gt;支持 数据 to interface 自动映射&lt;/li&gt;
  &lt;li&gt;实现[]*Type to []Type&lt;/li&gt;
  &lt;li&gt;实现[]Type to []*Type&lt;/li&gt;
  &lt;li&gt;使用struct tag 别名拷贝 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;json:&quot;aa,copy=bb&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>golang 通用指标框架之数据展示-代码约束</title>
   <link href="http://www.ireage.com/golang/2022/09/29/metric_calculate_code.html"/>
   <updated>2022-09-29T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2022/09/29/metric_calculate_code</id>
   <content type="html">&lt;h2 id=&quot;1-任务定义&quot;&gt;1. 任务定义&lt;/h2&gt;
&lt;p&gt;通过对任务属性抽象和集合， 将任务定义分为， meta信息， 任务周期信息， 插件信息，任务执行动态信息&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;meta信息： 主要就是任务名字，状态&lt;/li&gt;
  &lt;li&gt;任务周期信息： 周期类型，周期计算方式，需要计算的周期数&lt;/li&gt;
  &lt;li&gt;插架信息： 任务需要使用到插件及插件的配置&lt;/li&gt;
  &lt;li&gt;任务执行动态信息： 任务开始周期，最后一次执行完成时间&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/calculate_metric/blob/master/src/define/task.go&quot;&gt;代码位置 task.go&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MetricTask&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 任务的名字，同时也是指标名字&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;TaskName&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;task_name&quot;  gorm:&quot;column:task_name&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 指标周期（1年，2季，3月，4周，5日，6时）（接口必须）&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;TaskCycle&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int8&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;task_cycle&quot; gorm:&quot;column:task_cycle&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 周期执行方式，1 周期结束后执行，2周期中每天计算一次&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;CycleMode&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;CycleModeType&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;cycle_mode&quot; gorm:&quot;column:cycle_mode&quot;`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;CalculateCycle&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8&lt;/span&gt;         &lt;span class=&quot;s&quot;&gt;`json:&quot;calculate_cycle&quot; gorm:&quot;column:calculate_cycle&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 任务状态， 1 正常，可以允许， 2. 暂停，不被执行 3. 待删除&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;TaskStatus&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;StatusEnumType&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;task_status&quot; gorm:&quot;column:task_status&quot;`&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// TaskStart 任务采集数据的开始时间， 有start+cycle 可以得到结束时间&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;TaskStart&lt;/span&gt;   &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt;                              &lt;span class=&quot;s&quot;&gt;`json:&quot;task_start&quot; gorm:&quot;column:task_start&quot;`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Collect&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;MetricTaskPluginCollectConfig&lt;/span&gt;       &lt;span class=&quot;s&quot;&gt;`json:&quot;collect&quot; gorm:&quot;column:collect&quot;`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Filters&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;MetricTaskPluginConfigArr&lt;/span&gt;           &lt;span class=&quot;s&quot;&gt;`json:&quot;filters&quot; gorm:&quot;column:filters&quot;`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Aggregators&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MetricTaskPluginAggregatorConfigArr&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;aggregators&quot; gorm:&quot;column:aggregators&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Output 使用到output 插件&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;MetricTaskPluginOutputConfig&lt;/span&gt;        &lt;span class=&quot;s&quot;&gt;`json:&quot;output&quot; gorm:&quot;column:output&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//Power          MetricPower                         `json:&quot;power&quot; gorm:&quot;column:power&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// LastFinishTime 任务上一次完成时间 &lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;LastFinishTime&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;last_finish_time&quot; gorm:&quot;column:last_finish_time&quot;`&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// OutputIndexName 存储output 插件返回存储的信息&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;OutputIndexName&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;output_index_name&quot; gorm:&quot;column:output_index_name&quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;2-插架之间数据交换约束&quot;&gt;2. 插架之间数据交换约束&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/calculate_metric/blob/master/src/define/data.go&quot;&gt;代码位置 data.go&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;将任务执行分为数据处理和存储两个阶段。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;数据处理：包含获取周期内数据，数据过滤，数据聚合&lt;/li&gt;
  &lt;li&gt;存储结果：将指标和符合指标数据持久化&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;21-数据处理约束-record&quot;&gt;2.1 数据处理约束-Record&lt;/h3&gt;
&lt;p&gt;用来约束collect,filter,aggregator之间数据交换。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Data() 是用来做数据对比的数据&lt;/li&gt;
  &lt;li&gt;Update() 用来提供对原始更新，设计上是留给filter来做数据处理&lt;/li&gt;
  &lt;li&gt;Field() 用来做统计的数据&lt;/li&gt;
  &lt;li&gt;UUID()  框架中用来做数据去重使用&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Record&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;22-存储结果约束-metricdata&quot;&gt;2.2 存储结果约束-MetricData&lt;/h3&gt;

&lt;p&gt;传给output 插件的数据，计算的结果数据&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// MetricData 计算产生的数据&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MetricData&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;MetricKey&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;`json:&quot;value&quot;`&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Extra&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;extra&quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;3--插架约束&quot;&gt;3.  插架约束&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/calculate_metric/blob/master/src/define/plugins.go&quot;&gt;代码位置 define.go&lt;/a&gt;
实现自定义插件的时候，需要实现的代码约束&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Collect 收集数据插件&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Collect&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Name 插件的名字，必须全局唯一&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Keys 用做计算的维度，可以任务是group by 中分组的名字&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Run 执行统计任务， 这个有框架控制并发执行的&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// SetConfig 修改配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SetConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Description 用来描述配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// GetHooks 获取注入插件，用来放到流程不同流程执行&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//GetHooks() Hooks&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Filter data transform&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Filter&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Name 插件的名字，必须全局唯一&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Run 执行&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// SetConfig 初始化的时候，用来放入配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SetConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Description 用来描述配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Aggregator calculate metric&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Aggregator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Name 插件的名字，必须全局唯一&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Run 执行&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// SetConfig 初始化的时候，用来放入配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SetConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Description 用来描述配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Metric 存储的时候，获取当前插件计算的值&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Metric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;MetricExtra&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SetMetricMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MetricMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// Output record to storage&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Name 插件的名字，必须全局唯一&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Write 输出数据到目标&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OutputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Exists 判断key 在周期内是否已经执行过，任务分片后，判断是否需要跳过的依据&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;metricKey&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Description 用来描述配置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// IndexName string&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;IndexName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SetMetricMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MetricMetadata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>golang 通用指标框架之数据展示</title>
   <link href="http://www.ireage.com/golang/2022/08/29/metric_calculate.html"/>
   <updated>2022-08-29T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2022/08/29/metric_calculate</id>
   <content type="html">&lt;h2 id=&quot;1-背景&quot;&gt;1. 背景&lt;/h2&gt;
&lt;p&gt;最近在做一个研发效能指标展示的项目，该项目主要的功能收集第三方系统数据，按照周期计算，展示图表。&lt;/p&gt;

&lt;p&gt;系统主要业务逻辑在数据同步，周期数据聚合，数据计算，结果存储等几方面。&lt;/p&gt;

&lt;p&gt;业务需求主要是在指标规则和数据范围频繁发生，变化？ 迫切需要标准化计算框架。
降低统计指标开发难度，提高统计指标任务开发效率，实现统计流程与业务逻辑解构及指标计算过程配置化和插件化。&lt;/p&gt;

&lt;h2 id=&quot;2-面临的问题&quot;&gt;2. 面临的问题&lt;/h2&gt;
&lt;p&gt;设计面临的问题：
&lt;img src=&quot;/img/metrics/metric_calculate_question.jpg&quot; alt=&quot;metric_calculate_question&quot; /&gt;&lt;/p&gt;

&lt;p&gt;业务层面：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;任务执行失败，如何重试机制
任务调度和负载
任务并发执行协调
任务分批执行
公共逻辑没有复用，比如： 周期计算，数据统计，结果存储
数据，业务。流程逻辑解耦
指标结果存储优化。（分表，数据清理，历史记录）
指标重复计算
数据去重
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;3-如何设计解决问题&quot;&gt;3. 如何设计解决问题？&lt;/h2&gt;

&lt;h3 id=&quot;31-采用配置流水线及插件定义完成指标计算过程&quot;&gt;3.1 采用配置，流水线及插件定义完成指标计算过程&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/img/metrics/metric_plugins_config.png&quot; alt=&quot;metric_plugins_config&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;32-框架设计&quot;&gt;3.2 框架设计&lt;/h3&gt;
&lt;p&gt;在开发角度一个指标任务执行流程
&lt;img src=&quot;/img/metrics/metric_arch.png&quot; alt=&quot;metric_calculate_arch&quot; /&gt;
在机器的角度
&lt;img src=&quot;/img/metrics/metric_framework_workers.png&quot; alt=&quot;metric_framework_workers&quot; /&gt;&lt;/p&gt;

&lt;p&gt;用户参与功能及框架功能角度
&lt;img src=&quot;/img/metrics/metric_framework_function.png&quot; alt=&quot;metric_framework_function&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;321-用户参与的功能&quot;&gt;3.2.1 用户参与的功能&lt;/h4&gt;
&lt;p&gt;用户参与的功能。主要是在plugins， 插件也是可以公用的.
数据在按照collect → filter → aggregate → filter → output   单方向顺序执行
同类型的多个插件按照顺序执行&lt;/p&gt;

&lt;h5 id=&quot;3211-数据收集collect&quot;&gt;3.2.1.1 数据收集(collect)&lt;/h5&gt;
&lt;p&gt;用来获取周期内需要统计的数据，数据来源不限，可以是mysql，es，第三方服务。&lt;/p&gt;

&lt;h5 id=&quot;3211-数据处理filter&quot;&gt;3.2.1.1 数据处理(filter)&lt;/h5&gt;
&lt;p&gt;用来实现统计数据进行转换和过滤，比如： 对已有字段拆分，合并，去重等。&lt;/p&gt;

&lt;h5 id=&quot;3211-统计数据aggregator&quot;&gt;3.2.1.1 统计数据(aggregator)&lt;/h5&gt;
&lt;p&gt;按照条件进行数据统计， 比如 计数(count), 平均(avg), 最小值(min),最大值(min)&lt;/p&gt;

&lt;h5 id=&quot;3211-数据处理filter-1&quot;&gt;3.2.1.1 数据处理(filter)&lt;/h5&gt;
&lt;p&gt;用来实现统计结果进行转换， 比如： 对已有字段拆分，合并等。&lt;/p&gt;

&lt;h5 id=&quot;3211-结果output&quot;&gt;3.2.1.1 结果(output)&lt;/h5&gt;
&lt;p&gt;将统计结果持久化。比如：mysql&lt;/p&gt;

&lt;h4 id=&quot;322-框架功能&quot;&gt;3.2.2 框架功能&lt;/h4&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;任务分片
任务重试
并发处理
任务协调
数据去重
周期管理
结果分表
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;4-代码及约束&quot;&gt;4 代码及约束&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://www.ireage.com/golang/2022/09/29/metric_calculate_code.html&quot;&gt;请看golang 通用指标框架之数据展示-代码约束&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>golang bytes.Buffer 数据浅拷贝带来的问题</title>
   <link href="http://www.ireage.com/golang/2022/08/22/golang_shallow_copy.html"/>
   <updated>2022-08-22T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2022/08/22/golang_shallow_copy</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;项目中定时任务获取数据，在执行过程中未对cache 的内容做变更，但是值发生了变化。&lt;/p&gt;

&lt;p&gt;最后定位是浅拷贝造成，在做数据交互过程中用到bytes.Buffer 做缓存区用来，包含read,write。 为了性能考虑， 缓冲区会重复使用。
同时使用byte.Buffer 和 decode，主要浅拷贝的问题. eg: 自定义json,mysql的Marshal等。&lt;/p&gt;

&lt;p&gt;常见的常见如下：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;bytes&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;encoding/json&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;errors&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;reflect&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;unsafe&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

 

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Buffer&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tBytes&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;     &lt;span class=&quot;s&quot;&gt;`json:&quot;name&quot;`&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 浅拷贝&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;bytesType&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;`json:&quot;config&quot;`&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 深拷贝&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Config1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytesType1&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;config1&quot;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytesType&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytesType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnmarshalJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;json.RawMessage: UnmarshalJSON on nil pointer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytesType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytesType1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bytesType1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UnmarshalJSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;json.RawMessage: UnmarshalJSON on nil pointer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;jsonStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{&quot;name&quot;:&quot;marshal byte test&quot;, &quot;config&quot;:{&quot;aa&quot;:1}, &quot;config1&quot;:{&quot;aa&quot;:1}}`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jsonStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Unmarshal&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 输出结果： before reset buffer marshal byte test {&quot;aa&quot;:1} {&quot;aa&quot;:1}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;before reset buffer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;jsonStrNew&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{&quot;name&quot;:&quot;marshal byte test&quot;, &quot;config&quot;:{&quot;aa&quot;:3}, &quot;config&quot;:{&quot;aa&quot;:3}}`&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;jsonStrNew&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// content 没有做任何修改，但是值已经变化未最新buffer的内容&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 输出结果：after reset buffer marshal byte test {&quot;aa&quot;:3} {&quot;aa&quot;:1}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;after reset buffer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;byteInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12121`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;byteInfoStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byteInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;sliceHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SliceHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byteInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;stringHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byteInfoStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// byteInfo 与byteInfoStr 的data 字段地址不同，数据没有关联&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 824634990083 824634990088&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sliceHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stringHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;byteInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;&apos;9&apos;&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 对byteInfo 修改，无法影响到强制转换后byteInfoStr&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 92121 12121&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;byteInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;byteInfoStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 注意slice 与 array 的差异, array 对象不受影响， 将array转换到reflect.StringHeader 也深拷贝（是编译器实现？） &lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;zeroCopyByteInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`12121`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;zeroCopySliceHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SliceHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeroCopyByteInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;zeroCopyStringHeader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zeroCopySliceHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;zeroCopySliceHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;zeroCopyByteInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;&apos;8&apos;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;zeroCopyConv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unsafe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeroCopyStringHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 82121&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zeroCopyConv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>telegraf agent 源码分析</title>
   <link href="http://www.ireage.com/telegraf/2021/11/22/telegraf_agent.html"/>
   <updated>2021-11-22T00:00:00+00:00</updated>
   <id>http://www.ireage.com/telegraf/2021/11/22/telegraf_agent</id>
   <content type="html">&lt;h1 id=&quot;1-telegraf&quot;&gt;1 telegraf&lt;/h1&gt;

&lt;p&gt;telegraf 是开源agent服务，可收集系统和服务的metric数据. 
telegraf 从数据的collecting, processing, aggregating, and writing 都采用插件的设计，非常灵活，易扩展。
可以通过官方和自定义插件完成业务功能。&lt;/p&gt;

&lt;p&gt;有四种不同类型的插件：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Input Plugins collect metrics from the system, services, or 3rd party APIs&lt;/li&gt;
  &lt;li&gt;Processor Plugins transform, decorate, and/or filter metrics&lt;/li&gt;
  &lt;li&gt;Aggregator Plugins create aggregate metrics (e.g. mean, min, max, quantiles, etc.)&lt;/li&gt;
  &lt;li&gt;Output Plugins write metrics to various destinations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;telegraf 设计是非常优秀，通过插件系统，将业务逻辑，数据差异放到不同流程的插件中处理，流程之间通过channel进行数据交互，解耦非常彻底。
agent 只需要完成插件管理，数据流向，插件调度。&lt;/p&gt;

&lt;h1 id=&quot;2-telegraf-agent&quot;&gt;2 telegraf agent&lt;/h1&gt;

&lt;h2 id=&quot;21-agent-如何管理数据&quot;&gt;2.1 agent 如何管理数据？&lt;/h2&gt;
&lt;p&gt;telegraf/agent/agent.go  做为agent 功能核心代码。 
主要通过 Agent,inputUnit,processorUnit,aggregatorUnit,outputUnit结构体来完成agent 的功能。
建议看源码，注释写非常明确。&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;agent 用来管理agent 配置，&lt;/li&gt;
  &lt;li&gt;inputUnit 用来管理Input 插件&lt;/li&gt;
  &lt;li&gt;processorUnit 用来管理Processor 插件&lt;/li&gt;
  &lt;li&gt;aggregatorUnit 用来管理Aggregator 插件&lt;/li&gt;
  &lt;li&gt;outputUnit 用来管理Output 插件&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;22-agent-如何约束插件&quot;&gt;2.2 agent 如何约束插件？&lt;/h2&gt;

&lt;h3 id=&quot;221-agent-插件全局约束&quot;&gt;2.2.1 agent 插件全局约束&lt;/h3&gt;
&lt;p&gt;全局约束是所有类型插件都适用的。&lt;/p&gt;

&lt;h4 id=&quot;2211-必须约束如下&quot;&gt;2.2.1.1 必须约束如下&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;PluginDescriber 用来描述插件，SampleConfig()在./telegraf –sample-config 可以看到&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c&quot;&gt;// PluginDescriber 插件描述&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PluginDescriber&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// SampleConfig returns the default configuration of the Processor&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SampleConfig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Description returns a one-sentence description on the Processor&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2212-可选约束&quot;&gt;2.2.1.2 可选约束&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;Initializer 初始化插件的操作&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Initializer 插件初始化约束&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Initializer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Init performs one time setup of the plugin and returns an error if the&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// configuration is invalid.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;231-agent-插件约束&quot;&gt;2.3.1 agent 插件约束&lt;/h3&gt;

&lt;p&gt;实现自定义插件的时候，需要根据插件类型的约束做实现， 
实现后还需要注册插件， 需要配合导入包的方式。具体可以看 telegraf/{inputs/outputs/processors/aggregators}/all/aal.go&lt;/p&gt;
&lt;h4 id=&quot;2311-input-插件&quot;&gt;2.3.1.1 Input 插件&lt;/h4&gt;
&lt;p&gt;telegraf/input.go&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Input&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;PluginDescriber&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Gather takes in an accumulator and adds the metrics that the Input&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// gathers. This is called every agent.interval&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 实现数据的收集功能，metric数据输入&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Gather&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2312-processor-插件&quot;&gt;2.3.1.2 Processor 插件&lt;/h4&gt;
&lt;p&gt;telegraf/processor.go&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Processor is a processor plugin interface for defining new inline processors.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// these are extremely efficient and should be used over StreamingProcessor if&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;// you do not need asynchronous metric writes.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Processor&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;PluginDescriber&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Apply the filter to the given metric.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Metric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Metric&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2313-aggregator-插件&quot;&gt;2.3.1.3 aggregator 插件&lt;/h4&gt;
&lt;p&gt;telegraf/processor.go&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Aggregator&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;PluginDescriber&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Add the metric to the aggregator.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Metric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Push pushes the current aggregates to the accumulator.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Accumulator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Reset resets the aggregators caches and aggregates.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Reset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2314-output-插件&quot;&gt;2.3.1.4 Output 插件&lt;/h4&gt;
&lt;p&gt;telegraf/output.go&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Output&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;PluginDescriber&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// Connect to the Output; connect is only called once when the plugin starts&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Close any connections to the Output. Close is called once when the output&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// is shutting down. Close will not be called until all writes have finished,&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// and Write() will not be called once Close() has been, so locking is not&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// necessary.&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Write takes in group of points to be written to the Output&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metrics&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Metric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;23-agent-代码&quot;&gt;2.3 agent 代码&lt;/h2&gt;

&lt;p&gt;telegraf/agent/agent.go 关于agent 的代码，需要注意插件启动顺序，插件的管理，采集异常处理。&lt;/p&gt;
&lt;h3 id=&quot;231-agent-run&quot;&gt;2.3.1 agent Run&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// Run starts and runs the Agent until the context is done.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Agent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 执行插件的初始化，前提是插件实现telegraf.Initializer&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initPlugins&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    
    &lt;span class=&quot;c&quot;&gt;// 启动ouput，这里主要是执行（*output).connectOutput 方法，&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;// 设计来源类似linux将一切皆文件的思想，connectOutput类似的open。&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ou&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startOutputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Outputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// next chan telegraf.Metric 类型，用来不同流程插件间数据交互&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;apu&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;processorUnit&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;au&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aggregatorUnit&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Aggregators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;aggC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggProcessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;c&quot;&gt;// startProcessors 注意processors 多个插件数据的交互，多个插件之间是有序的数据交互&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;aggC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;apu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startProcessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AggProcessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;c&quot;&gt;// aggC 和next 一致， 注意AggProcessors与Processors 却别&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;au&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startAggregators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aggC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Aggregators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pu&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;processorUnit&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	    &lt;span class=&quot;c&quot;&gt;// startProcessors 注意processors 多个插件数据的交互，多个插件之间是有序的数据交互&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startProcessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Processors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

     &lt;span class=&quot;c&quot;&gt;// 执行插件的初始化，前提是插件实现telegraf.ServiceInput&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;// 注意input插件的init 和start区别， &lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;iu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startInputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Inputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	
	
	&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runOutputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ou&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runProcessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;apu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runAggregators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;au&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runProcessors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// runInputs 主要就是通过a.gatherLoop来实现定时收集数据&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;runInputs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startTime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>go exec.Command使用pipe做数据交换遇到的问题</title>
   <link href="http://www.ireage.com/go/2021/08/19/go_fork_pipe.html"/>
   <updated>2021-08-19T00:00:00+00:00</updated>
   <id>http://www.ireage.com/go/2021/08/19/go_fork_pipe</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;使用exec.Command 实现syscall.ForkExec功能，为了让master与child数据交互的能力，
最终exec.Command.ExtraFiles 来传递pipe 的fd 来实现，
但是实际使用遇到几个奇怪的问题，感觉和系统实现的有些差别。
使用不好会卡到数据交互。比如卡到数据的读，读到数据为空&lt;/p&gt;

&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;ioutil.ReadAll 需要读到EOF 才会结束， 如果使用pipe，就需要关闭 write 通道&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;例子&quot;&gt;例子&lt;/h3&gt;
&lt;p&gt;也不知道怎么描述， 直接上代码&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;io/ioutil&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;os&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;os/exec&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execChildFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;aa&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;aa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aa&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;readFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;test success&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;paramBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;readFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paramBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;masterRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;childRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;masterWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;masterRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;childRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;masterWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// fork&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execChildFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Executable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;get self path error.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;masterRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;childWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;childRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;masterWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pipe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;pipe init error.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;masterWrite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; test master params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Env&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;aa=2222222&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExtraFiles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;childWrite&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;childRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 必须关闭，会卡到masterRead read 位置&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;childWrite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 关不关闭对流程没有影响&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;childRead&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 不关闭  会卡子进程read 数据， 子进程无法退出&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;masterWrite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masterRead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;read child result error.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;child result : &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>遇到问题集合</title>
   <link href="http://www.ireage.com/qa/2021/04/02/qa.html"/>
   <updated>2021-04-02T00:00:00+00:00</updated>
   <id>http://www.ireage.com/qa/2021/04/02/qa</id>
   <content type="html">&lt;h3 id=&quot;1-linux-执行命令卡住&quot;&gt;1. linux 执行命令卡住&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;执行ps -aux 卡住没有返回&lt;/li&gt;
  &lt;li&gt;执行ps -ef 卡住没有返回&lt;/li&gt;
  &lt;li&gt;ls -lha /proc/pid/ 卡住没有返回&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;使用 strace 查看后发现卡住在 read(“/prox/pid/cmdline”, …..&lt;/p&gt;

&lt;p&gt;cd /proc/pid&lt;/p&gt;

&lt;p&gt;cat status&lt;/p&gt;

&lt;p&gt;看下State 字段值：&lt;/p&gt;

&lt;p&gt;State:	D (disk sleep)&lt;/p&gt;

&lt;p&gt;解决方案：
https://bugs.centos.org/view.php?id=15252&lt;/p&gt;

&lt;h3 id=&quot;2-mongodb-用户权限的问题&quot;&gt;2. mongodb 用户权限的问题&lt;/h3&gt;

&lt;p&gt;mongodb 用户是属于db， 在这个库里面创建的账号，其他db 是不可见的。&lt;/p&gt;

&lt;p&gt;比如。 在db1, db2 都创建了user 帐户， 使用user 连接db1. 并没有操作db2权限&lt;/p&gt;

&lt;p&gt;在db1中执行下面的命令。帐户就可以db1,db2：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bazaar&quot;&gt;db.createUser({user: &quot;user&quot;,pwd: &quot;pwd&quot;,roles: [ { role: &quot;readWrite&quot;, db: &quot;db1&quot; },{ role: &quot;readWrite&quot;, db: &quot;db1&quot; } ]})

&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;3-go-mod-遇到的问题&quot;&gt;3. go mod 遇到的问题&lt;/h3&gt;

&lt;p&gt;go mod edit  -replace=xx=xx
编译报”is replaced in go.mod, but not marked as replaced in？”
原因：
编译或者运行的时，使用 -mod=vendor， 在这中情况下需要更新项目的vendor 目录。
执行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;go mod vendor&lt;/code&gt; 需要将go mod edit replace 相关的内容更新到vendor中
包含modules.txt和 项目代码.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;github.com/rs/cors@v1.7.0: is explicitly required in go.mod, but not marked as explicit in vendor/modules.txt
        github.com/rs/cors@v1.7.0: is replaced in go.mod, but not marked as replaced in vendor/modules.txt

        To ignore the vendor directory, use -mod=readonly or -mod=mod.
        To sync the vendor directory, run:
                go mod vendor
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;4-ls--文件权限描述中出现at符号的含义&quot;&gt;4. ls  文件权限描述中出现at(@)符号的含义&lt;/h3&gt;

&lt;p&gt;at(@) symbol in the description of ls file permissions
eg:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;-rwxr-xr-x@
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用来表示文件有metadata 描述， 可以xattr 命令来查看&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;# Disply the metadata attributes
xattr -l &amp;lt;file ...&amp;gt;
    
# Remove the metadata attributes
xattr -c &amp;lt;file ...&amp;gt;

# Remove the file ACL(s)
chmod -N &amp;lt;file ...&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;5-couldnt-start-listener-listen-tcp-ipport-bind-cant-assign-requested-address&quot;&gt;5. couldn’t start listener: listen tcp ip:port: bind: can’t assign requested address&lt;/h3&gt;

&lt;p&gt;再使用goland debug的时候出现的问题。 这个问题一般是本地host中缺少了当前机器与IP的配置。 
在终端执行 hostname， 在/etc/hosts 中新加  一行写入 127.0.0.1 （hostname 结果)&lt;/p&gt;

&lt;h3 id=&quot;6-cpu-过高-pprofprofile-提示-runtimesiftdowntimer-占比比较高&quot;&gt;6. CPU 过高， pprof/profile 提示 runtime.siftdownTimer 占比比较高&lt;/h3&gt;
&lt;p&gt;原因：Ticker 对象没有释放。 Ticker是需要手动stop的，不然它会一直在timers对象内工作，导致gc无法释放。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>解决monstache在启动的时候无法将mongodb分表的同步到Elasticsearch</title>
   <link href="http://www.ireage.com/monstache/2021/03/19/monstache_split_table_conf.html"/>
   <updated>2021-03-19T00:00:00+00:00</updated>
   <id>http://www.ireage.com/monstache/2021/03/19/monstache_split_table_conf</id>
   <content type="html">&lt;h3 id=&quot;1-背景&quot;&gt;1. 背景&lt;/h3&gt;

&lt;p&gt;目前所在做的项目是做资产管理， 随着变化数据越来越多， 单一类型的资产数据无法在同一张表存储，后需经过使用多个表， 
之前为了实现全局的全文搜索， 是通过monstache将mongodb 中资产的实例的数据同步到Elasticsearch。&lt;/p&gt;

&lt;p&gt;分表后在使用monstache 出现两个：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;不支持按照mongodb collection 名字前缀进行数据&lt;/li&gt;
  &lt;li&gt;monstache mapping 建立Elasticsearch 索引的时候不支持按collection 名字前缀进行聚合&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-如何解决问题&quot;&gt;2 如何解决问题？&lt;/h3&gt;

&lt;h4 id=&quot;21-解决-monstache-无法按照-mongodb-collection-名字前缀进行数据的问题&quot;&gt;2.1 解决 monstache 无法按照 mongodb collection 名字前缀进行数据的问题？&lt;/h4&gt;

&lt;p&gt;monstache 在启动的时候是支持按正则来过滤不同步的collection 名字的配置项目（direct-read-dynamic-exclude-regex ），&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;方法1：使用正则中的非来完成按照前缀的同步。 例如： “?!prefix” 正则表示所有非pregfix 前缀名字的collection都不同步。 
但是golang regex panic 不支持。&lt;/li&gt;
  &lt;li&gt;方法2： 将所有不需要同步的表名字全写direct-read-dynamic-exclude-regex， 耦合太紧，后需需要新加表都需要改配置&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;最终方案： 
在和monstache 作者沟通后，作者也认为上面的解决方案不可取，可以新建相应的功能。最后新加一个配置 direct-read-dynamic-include-regex
用来配置再启动的时候，按照配置的正则将符合条件名字的collection 中的数据同步到Elasticsearch中。
已提交PR， 并且合并&lt;a href=&quot;https://github.com/rwynn/monstache/pull/491&quot;&gt;https://github.com/rwynn/monstache/pull/491&lt;/a&gt;. 
欢迎大家使用&lt;/p&gt;

&lt;h4 id=&quot;22-解决-monstache-无法按照-mongodb-collection-名字前缀进行数据的问题&quot;&gt;2.2 解决 monstache 无法按照 mongodb collection 名字前缀进行数据的问题？&lt;/h4&gt;

&lt;p&gt;monstache 在将mongodb collection中同步到Elasticsearch中的时候， 默认情况下会使用mongodb collection namespace 作为索引名字。 
也可以通过配置mapping 来做 mongodb collection namespace 到指定Elasticsearch索引中， 但是mapping 不支持按照正则或者前缀的方式。&lt;/p&gt;

&lt;p&gt;但是我们可以通过插件的方式来实现。 目前monstache 支持js和golang 开发的插件
为了降低部署成本。我这边使用的是js 的插件。直接在配置文件中写即可：&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;
enable-patches = true

[[script]]
# namespace 限定js 插件处理的范围， 不填写的时候，是所有的表
#namespace = &quot;&quot;

routing = true 
script = &quot;&quot;&quot;

var re = new RegExp(&quot;prefix&quot;)
module.exports = function(doc, ns, updateDesc) {

    // 找到满足条件的表
    if(re.test(ns)) {
        // _meta_monstache key是 monstache 自己描述字段， 其中的index 表示这个doc数据写到Elasticsearch用的索引
        doc[&quot;_meta_monstache&quot;] = {&quot;index&quot;:&quot;es_index&quot;};
    }
    
    return  doc 
}
&quot;&quot;&quot;


&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>golang 动态结构体</title>
   <link href="http://www.ireage.com/golang%20%E5%8A%A8%E6%80%81%E7%BB%93%E6%9E%84%E4%BD%93/2021/02/10/golang_dynamic_struct.html"/>
   <updated>2021-02-10T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang%20%E5%8A%A8%E6%80%81%E7%BB%93%E6%9E%84%E4%BD%93/2021/02/10/golang_dynamic_struct</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;语言： golang&lt;/p&gt;

&lt;p&gt;目前项目允许业务自定自己业务下私有字段。 造成同一类型实例数据，在不同的业务下字段是不一样。 在实际处理中无法使用struct来定义。
当实例数据在不同服务之间数据传递， 只能用key-val结构(map[string]interface{})来描述，在实际处理中非常不变，
需要大量判断数据类型和类型转换代码，整体使用起来比较麻烦。&lt;/p&gt;

&lt;p&gt;eg:&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;inst&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;....&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; 
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;iName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ok&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;invalid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
   


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;如何解决大量类型转换和判断数据类型这个问题&quot;&gt;如何解决大量类型转换和判断数据类型这个问题？&lt;/h3&gt;

&lt;p&gt;struct 在我们使用的时候之所以方便，简洁就是在做反序列的时候根据结构的定义字段和类型。 因此在使用的可以不用在做类型判断和数据校验
如果可以做一个dynamic struct，这个struct字段是根据执行逻辑动态调整字段和字段类型即可。&lt;/p&gt;

&lt;h3 id=&quot;最终实现&quot;&gt;最终实现&lt;/h3&gt;

&lt;p&gt;最终的实现定一个DStruct 结构， 给DStruct结构实现基于byte stream json 反序列， 利用golang可以自定义struct UnmarshalJSON的特性，
当做json Unmarshal调用DStruct 根据用户定义的配置项目反序列化。 &lt;a href=&quot;https://github.com/rentiansheng/dstruct&quot;&gt;项目地址&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;eg:&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
 
	&lt;span class=&quot;n&quot;&gt;testStrJSONBytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{&quot;int&quot;:1,&quot;str&quot;:&quot;str&quot;,&quot;bl&quot;:true, &quot;arr_str&quot;:[&quot;1&quot;,&quot;2&quot;],&quot;arr_int&quot;:[1,2], &quot;map&quot;:{&quot;a&quot;:1,&quot;b&quot;:64}, `&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;`&quot;test_struct&quot;:{&quot;str&quot;:&quot;string&quot;, &quot;int&quot;:1},&quot;interface&quot;:{&quot;str&quot;:&quot;string&quot;, &quot;bl&quot;:true}}`&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// define a dynamic structure&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// define the fields of the dynamic structure&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;int&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;TypeInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;str&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;TypeString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;bl&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;TypeBool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;arr_str&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;TypeArrayStr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;arr_int&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;TypeArrayInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;map&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;         &lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypeOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}),&lt;/span&gt;
		&lt;span class=&quot;s&quot;&gt;&quot;interface&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypeOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// Unmarshal dynamic structure, you can directly use golang official&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testStrJSONBytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;intVal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int test, err: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;val: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intVal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;str&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;str test, err: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;val: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ds&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;interface&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;exist field: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;val: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>golang 泛型</title>
   <link href="http://www.ireage.com/golang%E6%B3%9B%E5%9E%8B/2021/01/17/golang_generics.html"/>
   <updated>2021-01-17T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang%E6%B3%9B%E5%9E%8B/2021/01/17/golang_generics</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;目前所在项目是关于资产管理，经常会有各种数据做各种操作，比如，各类数值型Join, Sort, Unique等很多操作。&lt;/p&gt;

&lt;p&gt;由于在目前的golang 版本不支持多态， 只能人工的方式来实现。效果如下：
&lt;img src=&quot;https://lh3.googleusercontent.com/-5Vz_puoHe7o/WMJukhX878I/AAAAAAAADRI/9nn3cse3gkYrZ--aVfWaofUFGaRb49MtACLcB/s1600/Animation.gif&quot; alt=&quot;人工泛型&quot; /&gt;
（图片来源）https://groups.google.com/g/golang-nuts/c/j_3n5wAZaXw/m/YkOdbCppAQAJ&lt;/p&gt;

&lt;h3 id=&quot;泛型实现&quot;&gt;泛型实现&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;多态&lt;/li&gt;
  &lt;li&gt;类型推导&lt;/li&gt;
  &lt;li&gt;操作符重载&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;golang-实现&quot;&gt;golang 实现&lt;/h3&gt;

&lt;p&gt;golang 目前完成的主要是类型推导&lt;/p&gt;

&lt;h3 id=&quot;如何使用golang&quot;&gt;如何使用golang&lt;/h3&gt;

&lt;h5 id=&quot;编译支持golang的版本&quot;&gt;编译支持golang的版本&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&quot;language-angular2html&quot;&gt;git clone https://github.com/golang/go
git checkout dev.go2go
cd src
./all.bash 

go tool go2go run xx.go2
&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id=&quot;例子&quot;&gt;例子&lt;/h5&gt;

&lt;p&gt;(https://go2goplay.golang.org/)[官方实例]&lt;/p&gt;

&lt;p&gt;数据类型的Join. file name: intJoin.go2&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;strings&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int64&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int32&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JoinNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int64&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JoinNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;int32&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// NOTICE: ERROR. 类型不匹配时候的问题&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;/* 
	str = JoinNumber([]string{&quot;1&quot;,&quot;2&quot;,&quot;3&quot;,&quot;4&quot;});
	fmt.Println(&quot;int32&quot;, str) 
	*/&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s,%v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numeric&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;uint64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;JoinNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numeric&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s,%v&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Trim&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;数组结构体多态实例， file: struct.go2&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;fmt&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Val&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MapArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MapArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MapArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot; info:(id: %s, val:%v)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MapArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]{}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]{}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;str,int&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;kvArr1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MapArr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]{}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pair&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]{}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;v1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;k2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;v2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;str,str&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;kvArr1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>使用mgo.v2 出现 i/o timeout session 问题</title>
   <link href="http://www.ireage.com/mgo.v2/2021/01/14/golang_mgo_session_timeout.html"/>
   <updated>2021-01-14T00:00:00+00:00</updated>
   <id>http://www.ireage.com/mgo.v2/2021/01/14/golang_mgo_session_timeout</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;使用mgo.v2 操作数据库，一直报 i/o timeout session 问题出错如下:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-code&quot;&gt;read tcp 127.0.0.1:42577-&amp;gt;127.0.0.1:27017: i/o timeout
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;原因&quot;&gt;原因&lt;/h3&gt;

&lt;p&gt;再上层使用的时候， 先connect mongodb server , 然后 cache connect session.&lt;/p&gt;

&lt;p&gt;再使用mgo.v2 去操作mongodb 的时候，我门都设置操作执行的超时时间， 再超时后mgo.v2 回关闭这个连接，
mgo.v2 只是关闭这个连接，后需通过这个session 或者是 Clone出来的session都是回出现i/o timeout，
mongodb server 日志会有 ` Error sending response to client: SocketException: Broken pipe.` 的错误&lt;/p&gt;

&lt;p&gt;参考代码：&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;m&quot;&gt;1.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;获取网络数据失败或者超时错误&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;，&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;readLoop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;//github.com/go-mgo/mgo/blob/v2/socket.go#L551&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;2.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;处理出错连接&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;，&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;kill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;abend&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;//github.com/go-mgo/mgo/blob/v2/socket.go#L319&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;3.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;再连接上执行语句直接报错的位置&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;，&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ops&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;，&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;c&quot;&gt;//github.com/go-mgo/mgo/blob/v2/socket.go#L491&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;解决方案&quot;&gt;解决方案&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;m&quot;&gt;1.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;获取session&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;的时候&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;不使用原有session上Clone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;使用Copy&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;方法获取&lt;/span&gt;
&lt;span class=&quot;m&quot;&gt;2.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;获取session&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;的时候&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;，&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;通过原有session&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;上clone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;出来的&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;，&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;需要是用Refresh&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;方法&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;，&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上的方法存在性能问题， 每次获取session 都需要和mongodb 进行一次认证服务。 （之前遇到的问题，当时的数据忘记留存了，QPS增高后，严重性能下降）&lt;/p&gt;

&lt;p&gt;专用解决方案：
为了快速解决这个问题，并且少修改业务代码和mgo.v2 的代码。
为了保证性能， 对mgo.v2  session 进行扩展， 可以获取session 对应的连接是否已经关闭， 如果关闭再Refresh session。&lt;/p&gt;

&lt;p&gt;在mgo.v2/session.go 新加方法&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// 检查session 中连接是否已经dead&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IsDead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masterSocket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masterSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masterSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dead&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masterSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;masterSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slaveSocket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slaveSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slaveSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dead&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slaveSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;slaveSocket&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unlock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;具体使用方法：&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;//  如果发现session 中 conn 对象已经dead， 刷新下连接&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;MyMongo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;refreshDBSess&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mgo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mgo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Session&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IsDead&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Refresh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sess&lt;/span&gt;	
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;	

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;其他问题&quot;&gt;其他问题&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;clone session 扩散I/O timeout 和设置 readPreference 也有关， Eventual 不会出现问题（没太关注这个逻辑，按照mgo.v2 通用处理的逻辑，这个是有性能问题）&lt;/li&gt;
  &lt;li&gt;clone session 在mongodb server 重新选择也会有问题。 也可以按照上面的方案解决&lt;/li&gt;
  &lt;li&gt;没有看到mgo.v2 连接池的作用&lt;/li&gt;
&lt;/ol&gt;

</content>
 </entry>
 
 <entry>
   <title>Use mongodb driver to solve distributed transactions</title>
   <link href="http://www.ireage.com/%E9%A1%B9%E7%9B%AE%E4%BD%BF%E7%94%A8/2021/01/03/mongodb_go_driver_distributed_transaction_en.html"/>
   <updated>2021-01-03T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E9%A1%B9%E7%9B%AE%E4%BD%BF%E7%94%A8/2021/01/03/mongodb_go_driver_distributed_transaction_en</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;mongodb_go_driver_distributed_transaction_cn.html&quot;&gt;中文&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;use-mongodb-driver-to-solve-distributed-transactions&quot;&gt;Use mongodb driver to solve distributed transactions&lt;/h2&gt;

&lt;h4 id=&quot;solving-distributed-transaction-scenarios&quot;&gt;Solving distributed transaction scenarios&lt;/h4&gt;

&lt;p&gt;This project can only solve distributed transactions in multiple tables in the same database in the same replica-set in mongodb.&lt;/p&gt;

&lt;h4 id=&quot;main-principles&quot;&gt;Main principles&lt;/h4&gt;

&lt;p&gt;The mongodb server does not strictly bind the transaction in which the transaction is in, and the mongodb driver can initiate transactions to achieve this.
Changing this solution will extend the mongodb golang driver code,
It can be used for verification in mongodb driver 1.1.2 release and mongodb 4.0.x-4.2.x replica-set mode&lt;/p&gt;

&lt;h6 id=&quot;mongodb-golang-driver-code-extension-content&quot;&gt;mongodb golang driver code extension content&lt;/h6&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/mongodb_driver_transcation/commit/314f4f3263953ea9e6588993975c44cb894e9831&quot;&gt;The specific code is at https://github.com/rentiansheng/mongodb_driver_transaction/commit/314f4f3263953ea9e6588993975c44cb894e9831&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Extension code:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; mongo/session_exposer.go
 x/mongo/driver/session/session_ext.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The extension code is mainly the underlying logic, used to activate the transaction and bind the transaction. Does not contain business logic&lt;/p&gt;

&lt;p&gt;Related test cases:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transcation/transaction_test.go

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Upper-level use logic:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transcation/transaction.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Encapsulate business logic, realize business-level management interfaces such as opening, committing, and rolling back transactions, and provide an operation interface for the transaction uuid and the cursor id record operation of the statement execution within the transaction.
In actual use, the transaction uuid and in-service statement execution cursor id need to be stored centrally, and all service instances need to be available and used. You can use redis and mysql as central storage&lt;/p&gt;

&lt;p&gt;Now that the real transaction id of mongodb is directly exposed, there may be security risks in passing between different service nodes.&lt;/p&gt;

&lt;h6 id=&quot;specific-implementation&quot;&gt;Specific implementation&lt;/h6&gt;

&lt;ol&gt;
  &lt;li&gt;Activate a transaction, generate a transaction uuid (mongodb driver provides the generation method), transaction/transaction.go: StartTransaction&lt;/li&gt;
  &lt;li&gt;Activate a session through the uuid of the transaction and join a transaction of the mongodb server, transaction/transaction.go: ReloadSession&lt;/li&gt;
  &lt;li&gt;Bind the transaction to the session, get the SessionContext, mongo/session_exposer.go:TxnContextWithSession&lt;/li&gt;
  &lt;li&gt;Perform curl operations&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;solution-implementation&quot;&gt;Solution implementation&lt;/h4&gt;

&lt;p&gt;Use items:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Tencent/bk-cmdb&quot;&gt;Blueking Configuration Platform&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;drainage&quot;&gt;Drainage&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/bson-register&quot;&gt;bson decode register&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bson decoding interface priority uses the actual type as the final object, such as slice, map
In the mongodb golang official driver, when bson uses interface at the top level, it puts slice and map in an object called primitive.D (golang []interface type).&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>使用mongodb driver 解决分布式事务</title>
   <link href="http://www.ireage.com/%E9%A1%B9%E7%9B%AE%E4%BD%BF%E7%94%A8/2021/01/03/mongodb_go_driver_distributed_transaction.html"/>
   <updated>2021-01-03T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E9%A1%B9%E7%9B%AE%E4%BD%BF%E7%94%A8/2021/01/03/mongodb_go_driver_distributed_transaction</id>
   <content type="html">&lt;h2 id=&quot;使用mongodb-driver-解决分布式事务&quot;&gt;使用mongodb driver 解决分布式事务&lt;/h2&gt;

&lt;h4 id=&quot;解决分布式事务的场景&quot;&gt;解决分布式事务的场景&lt;/h4&gt;

&lt;p&gt;本项目只能解决在mongodb 同一个replica-set 中同一个database中多个表中的分布式事务。&lt;/p&gt;

&lt;h4 id=&quot;主要原理&quot;&gt;主要原理&lt;/h4&gt;

&lt;p&gt;mongodb server对事务所在的session没有严格绑定和 mongodb driver 可以发起事务的规则来实现。
改该解决方案会对mongodb golang driver 代码扩展，
在mongodb driver 1.1.2 release 与mongodb 4.0.x-4.2.x replica-set 模式验证可以使用&lt;/p&gt;

&lt;h6 id=&quot;mongodb-golang-driver-代码扩展内容&quot;&gt;mongodb golang driver 代码扩展内容&lt;/h6&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/mongodb_driver_transaction/commit/314f4f3263953ea9e6588993975c44cb894e9831&quot;&gt;具体代码在 https://github.com/rentiansheng/mongodb_driver_transaction/commit/314f4f3263953ea9e6588993975c44cb894e9831&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;扩展代码：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; mongo/session_exposer.go
 x/mongo/driver/session/session_ext.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;扩展代码主要是底层逻辑，用来激活事务， 绑定事务。 不包含业务逻辑&lt;/p&gt;

&lt;p&gt;相关测试用例：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transaction/transaction_test.go

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上层使用逻辑：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;transaction/transaction.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;封装业务逻辑，实现业务层面需要开启，提交，回滚事务等管理接口， 并且提供一个关于事务uuid 与 事务内语句执行游标id记录操作接口。
在实际使用的时候， 事务uuid 和务内语句执行游标id 要做中心化存储，需要刚让所有服务实例可以获取和使用。 可以用redis， mysql 作为中心存储&lt;/p&gt;

&lt;p&gt;现在直接将mongodb 真是的事务id暴露出来，在不同服务节点之间传递可能存在安全风险。&lt;/p&gt;

&lt;h6 id=&quot;具体的实现&quot;&gt;具体的实现&lt;/h6&gt;

&lt;ol&gt;
  &lt;li&gt;激活一个事务， 生成一个事务uuid（mongodb driver 提供生成方法）, transaction/transaction.go: StartTransaction&lt;/li&gt;
  &lt;li&gt;通过事务的uuid， 激活一个session， 加入mongodb server 的一个事务中，transaction/transaction.go: ReloadSession&lt;/li&gt;
  &lt;li&gt;将事务与session绑定， 获取SessionContext， mongo/session_exposer.go:TxnContextWithSession&lt;/li&gt;
  &lt;li&gt;执行curl 操作&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;方案落地&quot;&gt;方案落地&lt;/h4&gt;

&lt;p&gt;使用项目：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Tencent/bk-cmdb&quot;&gt;蓝鲸配置平台&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;引流&quot;&gt;引流&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/bson-register&quot;&gt;bson decode register&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;bson解码interface优先级使用实际类型最为最终对象， 比如：slice，map
mongodb golang 官方driver中bson在顶层使用interface的时候，会将slice, map 放到一个叫primitive.D的对象中（golang []interface类型）。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>多个不兼容版本数据同步（mysql 向 mongodb 数据同步）</title>
   <link href="http://www.ireage.com/%E9%A1%B9%E7%9B%AE%E4%BD%BF%E7%94%A8/2020/12/23/mysql_binlog_event.html"/>
   <updated>2020-12-23T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E9%A1%B9%E7%9B%AE%E4%BD%BF%E7%94%A8/2020/12/23/mysql_binlog_event</id>
   <content type="html">&lt;h4 id=&quot;背景&quot;&gt;背景&lt;/h4&gt;

&lt;p&gt;客观原因项目项目多版本共存，并且用户短时间内无法迁移到新版本上面并且数据会按照一定纬度（项目中成为业务）灰度到新版使用。
最终解决方案：业务数据未灰度前，只在旧版中对数据修改， 但是修改的结果在新旧版本中同时生效， 
具体操作是未灰度到新版本中业务的数据修改操作都在旧版本中操作， 将变更的内容同步到新版中。&lt;/p&gt;

&lt;h4 id=&quot;解决方案&quot;&gt;解决方案&lt;/h4&gt;

&lt;p&gt;主要面临的问题是以下：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;旧系统数据变化同步实时性&lt;/li&gt;
  &lt;li&gt;数据关系的处理&lt;/li&gt;
  &lt;li&gt;边界数据的修改&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;旧系统数据变化同步&quot;&gt;旧系统数据变化同步&lt;/h5&gt;

&lt;p&gt;在版本灰度方案，给周边系统的承诺数据在新版本中生效的时间&amp;lt;=15s的前提下， 下面的方案都是不可用的：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;由于旧系统使用的是mysql， 不提供数据变更通知功能&lt;/li&gt;
  &lt;li&gt;且旧版本本身数据变更推送服务是异步任务， 修改变更后从操作日志中提取变更再推送，延时比较大且推送事件的数据缺少部分数据无法使用。&lt;/li&gt;
  &lt;li&gt;定时全量同步更不符合预期， 原因：mysql中需要同步的数据总量多余5kw, 对于数据库压力过大和数据的实时性太低。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;基于数据实时性的要求，必须要找一个基于事件数据增量同步的方案， 经过查找资料发现一个能实时读取MySQL二进制日志binlog，
并生成 JSON 格式的数据的工具maxwell。 maxwell 完全可以数据的变更推送出来做增量同步。&lt;/p&gt;

&lt;p&gt;目前，关于数据同步实时性的可度量指标还没有收集， 正在开发中。实际使用统计数据同步小于1s。&lt;/p&gt;

&lt;h5 id=&quot;数据关系的处理&quot;&gt;数据关系的处理&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;数据合并及分裂， 主要新旧版数据字典定义差异， 造成多个table数据合并，分离，&lt;/li&gt;
  &lt;li&gt;数据形态发生变化，主要由于业务形态的变化，数据出现不兼容的情况&lt;/li&gt;
  &lt;li&gt;关联数据的变更，  主要是数据变更印象到所有相关联的节点数据。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这个主要是业务逻辑，需要基于一个数据为中心处理新旧系统数据库中多表， 特别是树形关联关系中某个节点删除后，下级节点数据处理。&lt;/p&gt;

&lt;h5 id=&quot;边界数据的修改&quot;&gt;边界数据的修改&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;新旧版本数据交换， 新-&amp;gt; 旧， 旧-&amp;gt;新&lt;/li&gt;
  &lt;li&gt;未灰度业务的数据，在新版本修改，删除，新加数据&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;这个主要是业务逻辑，主要是确定一个规则，需要在开发前与PM，使用方确定好即可&lt;/p&gt;

&lt;h4 id=&quot;开发中遇到问题&quot;&gt;开发中遇到问题&lt;/h4&gt;

&lt;h5 id=&quot;实时性如何保证&quot;&gt;实时性如何保证？&lt;/h5&gt;

&lt;p&gt;maxwell能实时读取MySQL二进制日志binlog， maxwell 是以slave db instance 连接到mysql master db 上面直接获取binlog&lt;/p&gt;

&lt;h5 id=&quot;如何保证mysql-数据变更事件不丢失&quot;&gt;如何保证mysql 数据变更事件不丢失&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;binlog 事件不丢失
maxwell 会落地存储当前处理mysql binlog offset， 重启后根据落地offset 继续处理 mysql binlog ，&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;事件处理不丢失
maxwell 支持将binlog 变更内容推动 kafka, RabbitMQ, Redis 等多种中间中，目前，使用是将数据推送到redis list，使用redis 两个list 做推送事件的ack，&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;redis ack 队列的实现：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 1. maxwell push event redis list key1
 2. 使用 redis  RPopLPush 命令同获取到数据的同时放到 第二个list key2的队列中
 3. 事件处理完成后，删除第二list key2中的数据， 如果出现意外情况，等待事件补偿方法处理list key2的事件
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;数据全量同步&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;作为一种补偿机制，每周执行一次，保证数据的准确性，
用户也可以强制发起基于业务的下数据同步&lt;/p&gt;

&lt;h5 id=&quot;如何全量同步和增量同步数据冲&quot;&gt;如何全量同步和增量同步数据冲？&lt;/h5&gt;

&lt;p&gt;全量同步时候， 暂停增量事件同步&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>蓝鲸配置平台-蓝鲸cmdb接入层支持对第三方组件访问的转发开发</title>
   <link href="http://www.ireage.com/bk-cmdb/2020/10/11/bk_cmdb_apiserver_proxy.html"/>
   <updated>2020-10-11T00:00:00+00:00</updated>
   <id>http://www.ireage.com/bk-cmdb/2020/10/11/bk_cmdb_apiserver_proxy</id>
   <content type="html">&lt;h4 id=&quot;前提&quot;&gt;前提&lt;/h4&gt;

&lt;p&gt;蓝鲸配置平台（bk-CMDB）是一个面向资产及应用的企业级配置管理平台。
是蓝鲸运维体系一部分，蓝鲸社区版本是免费，社区地址&lt;a href=&quot;&quot;&gt;https://bk.tencent.com/&lt;/a&gt;
并且蓝鲸很多组件已经开源，蓝鲸cmdb就是其中之一，&lt;/p&gt;

&lt;p&gt;蓝鲸配置平台接入层API server目前仅支持对场景层开发，无法对第三方开发的场景层做代理转发。&lt;/p&gt;

&lt;h4 id=&quot;目标&quot;&gt;目标&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;实现项目模块&lt;/li&gt;
  &lt;li&gt;降低模块接入成本&lt;/li&gt;
  &lt;li&gt;完善模块文档&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;需要做的工作&quot;&gt;需要做的工作&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;服务的动态发现&lt;/li&gt;
  &lt;li&gt;根据规则转发请求&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;接入层apiserver-对第三方组件访问的转发开发实例&quot;&gt;接入层（apiserver） 对第三方组件访问的转发开发实例&lt;/h4&gt;

&lt;p&gt;代码放到 src/apiserver/service/match/目录中即可&lt;/p&gt;

&lt;h6 id=&quot;使用服务发现发现服务&quot;&gt;使用服务发现发现服务&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	RegisterService(服务名字, 实现URL匹配方法)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;实现url匹配方法&quot;&gt;实现URL匹配方法&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;func MatchMigrate(req *restful.Request) (from, to string, isHit bool) 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;eg:&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;strings&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;configcenter/src/common/types&quot;&lt;/span&gt;
	&lt;span class=&quot;s&quot;&gt;&quot;github.com/emicklei/go-restful&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;RegisterService&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;types&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CC_MODULE_MIGRATE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MatchMigrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MatchMigrate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;req&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;restful&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isHit&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RequestURI&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RootPath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;/migrate/v3&quot;&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HasPrefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RootPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/authcenter/init&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 将请求URL未/api/v3/authcenter/init，转发到当前服务&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;isHit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;strings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HasPrefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RootPath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/find/system/config_admin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// 将请求URL未/api/v3/find/system/config_admin，转发到当前服务&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;isHit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;isHit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;isHit&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>read preference in a transaction must be primary</title>
   <link href="http://www.ireage.com/http/2020/09/20/mongodb_read_preference_in_a_transaction_must_be_primary.html"/>
   <updated>2020-09-20T00:00:00+00:00</updated>
   <id>http://www.ireage.com/http/2020/09/20/mongodb_read_preference_in_a_transaction_must_be_primary</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;项目中mongodb数据库负载比较高，现在想将读请求放到secondary节点中， 但是将ReadPreference设置为SecondaryPreferred， 
事务中的查询语句会出现read preference in a transaction must be primary的问题&lt;/p&gt;

&lt;h3 id=&quot;解决方案&quot;&gt;解决方案&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;修改操作数据的逻辑&lt;/li&gt;
  &lt;li&gt;修改mongodb driver事务内节点直接使用primary 节点操作&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;修改操作数据的逻辑&quot;&gt;修改操作数据的逻辑&lt;/h4&gt;

&lt;p&gt;思想：&lt;/p&gt;

&lt;p&gt;mongodb driver 在对mongodb driver 中的 DataBase,Collection的对象操作的时候允许通过Option 来在设定执行的ReadPrefernce的。&lt;/p&gt;

&lt;p&gt;mongodb driver 关于DataBase，Collection 对象操作的定义如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Database(name string, opts ...*options.DatabaseOptions) *Database
Collection(name string, opts ...*options.CollectionOptions) *Collection
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;具体实现 ：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;ol&gt;
      &lt;li&gt;修改连接方法， 设置连接mongodb 使用Option 中的ReadPrefernce值为SecondaryPreferred&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;ol&gt;
      &lt;li&gt;根据ctx 判断当前是否位事务， 如果是设置  DataBase或Collection的Option中的ReadPrefernce值为SecondaryPreferred&lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;方案优点：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;逻辑简单&lt;/li&gt;
  &lt;li&gt;对业务逻辑没有侵入性&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;方案确定：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;可移植性差&lt;/li&gt;
  &lt;li&gt;不支持标准事务&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;修改mongodb-driver&quot;&gt;修改mongodb driver&lt;/h4&gt;

&lt;p&gt;思想：&lt;/p&gt;

&lt;p&gt;ReadPrefernce 配置主要设置mongodb driver 在query 数据的时候选择使用连接的策略。 理论上事务内的查询和写操作是一样，必须要走Primary节点， 所以可以在driver中将事务的查询的方法强制设置位Primary即可。&lt;/p&gt;

&lt;p&gt;代码如下：
&lt;a href=&quot;https://github.com/mongodb/mongo-go-driver/pull/501&quot;&gt;修改代码连接&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;方案优点：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;对业务逻辑没有侵入性&lt;/li&gt;
  &lt;li&gt;可移植性&lt;/li&gt;
  &lt;li&gt;支持标准事务&lt;/li&gt;
  &lt;li&gt;逻辑简单&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;方案确定：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;非官方修改，兼容性未知&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>调用第三方接口返回过慢的分析过程</title>
   <link href="http://www.ireage.com/http/2020/08/08/http_request_slow.html"/>
   <updated>2020-08-08T00:00:00+00:00</updated>
   <id>http://www.ireage.com/http/2020/08/08/http_request_slow</id>
   <content type="html">&lt;h3 id=&quot;背景&quot;&gt;背景&lt;/h3&gt;

&lt;p&gt;最近在对第三方系统过程中经常某一个请求耗时很长（请求到返回超过2m）。通过验证发现请求流程中网络传输和业务逻辑处理的耗时并不长。那么时间都耗费到什么时间了？&lt;/p&gt;

&lt;h3 id=&quot;查找问题的流程&quot;&gt;查找问题的流程&lt;/h3&gt;

&lt;p&gt;按照个人经验HTTP 的请求流程的耗时是在网络传输和业务逻辑的处理中，现在根据这个流程来确定问题。&lt;/p&gt;

&lt;h4 id=&quot;确定是否网络问题&quot;&gt;确定是否网络问题&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;通过长时间的ping 发现网络质量比较稳定，时间都在3ms 之内。&lt;/li&gt;
  &lt;li&gt;通过用strace -p pid 发下connect 并没有失败，一直在等待数据数据返回&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;确定是否业务逻辑处理较慢&quot;&gt;确定是否业务逻辑处理较慢&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;日志中返回较慢的请求参数。单独拿出来多次执行，返回情况正常。&lt;/li&gt;
  &lt;li&gt;与第三方系统沟通，发现出现问题请求的执行逻辑耗时相对比较短，不存在执行比较慢的情况&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;请求时间究竟消耗在什么位置&quot;&gt;请求时间究竟消耗在什么位置&lt;/h3&gt;

&lt;p&gt;整个请求过程中，网络和业务逻辑耗时都没有问题， 但是还是缺少一个环节，因为现在服务都是只负责处理业务逻辑，accept连接和读取HTTP请求的内容，都是有框架或者第三方服务完成. 在上面查找问题缺少的环节就是server端accept请求后，将请求的内容发给服务的时间。 这个部分时间不再网络传输和业务逻辑中提现。因为这一时刻网络已经建立成功， 还没有到业务里面，所以业务逻辑的日志没有&lt;/p&gt;

&lt;p&gt;比如：&lt;/p&gt;

&lt;p&gt;php中 nginx -&amp;gt; php-fpm&lt;/p&gt;

&lt;p&gt;golang 中的net/http中的处理逻辑&lt;/p&gt;

&lt;h4 id=&quot;示例代码&quot;&gt;示例代码&lt;/h4&gt;

&lt;p&gt;我用golang 做了例子&lt;/p&gt;

&lt;p&gt;服务端代码：&lt;/p&gt;
&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 这里是业务中执行的耗时&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 限制golang 协程的处理能力&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GOMAXPROCS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;:51511&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;客户端：&lt;/p&gt;
&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exitWait&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WaitGroup&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;exitWait&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://127.0.0.1:51511&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;application/json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;respBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ReadAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;nb&quot;&gt;panic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ts&lt;/span&gt;

			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;request time(s):&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;server handle time(s):&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;respBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;exitWait&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;exitWait&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Wait&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;通过执行发现：
服务端执行在毫秒级别，但是整个请求耗时是在10s&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/http_request_slow_20200807.png&quot; alt=&quot;内存组织图&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>蓝鲸配置平台-蓝鲸cmdb开发登录插件</title>
   <link href="http://www.ireage.com/bk-cmdb/2020/03/06/bk_cmdb_login_plugin.html"/>
   <updated>2020-03-06T00:00:00+00:00</updated>
   <id>http://www.ireage.com/bk-cmdb/2020/03/06/bk_cmdb_login_plugin</id>
   <content type="html">&lt;h4 id=&quot;前提&quot;&gt;前提&lt;/h4&gt;

&lt;p&gt;蓝鲸配置平台（bk-CMDB）是一个面向资产及应用的企业级配置管理平台。
是蓝鲸运维体系一部分，蓝鲸社区版本是免费，社区地址&lt;a href=&quot;&quot;&gt;https://bk.tencent.com/&lt;/a&gt;
并且蓝鲸很多组件已经开源，蓝鲸cmdb就是其中之一，&lt;/p&gt;

&lt;p&gt;蓝鲸配置平台作为蓝鲸一部分登录及用户管理依赖蓝鲸登录及用户组件， 
如果需要蓝鲸cmdb使用其他登录系统，就需要进行第三方开发。&lt;/p&gt;

&lt;h4 id=&quot;准备&quot;&gt;准备&lt;/h4&gt;

&lt;p&gt;开发前，我们需要了解下面的问题：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;bk-cmdb是如何判断用户已经登录？&lt;/li&gt;
  &lt;li&gt;bk-cmdb是如何跳转到登录系统？&lt;/li&gt;
  &lt;li&gt;bk-cmdb是如何选择登录组件？&lt;/li&gt;
  &lt;li&gt;bk-cmdb登录组件需要实现那些接口？&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;bk-cmdb-登录流程如下&quot;&gt;bk-cmdb 登录流程如下：&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;先判断用户session在bk-cmdb是否已经存？&lt;/li&gt;
  &lt;li&gt;已经存在，且session中的bk_token和cookie相等，转发请求。其他情况执行下一步。&lt;/li&gt;
  &lt;li&gt;根据配置选择对应登录系统&lt;/li&gt;
  &lt;li&gt;调用登录系统判断用户是否登录？&lt;/li&gt;
  &lt;li&gt;如果用户已经登录，转发请求。否则执行下一步&lt;/li&gt;
  &lt;li&gt;如果没有登录，返回登录系统跳转的地址。&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;配置文件讲解&quot;&gt;配置文件讲解，&lt;/h4&gt;

&lt;p&gt;登录系统的配置都在web.conf&lt;/p&gt;

&lt;p&gt;开源版本在cmdb_adminserver/configures&lt;/p&gt;

&lt;p&gt;文件内容解释：（v3.8.x分支，只写出用到参数）&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;site bk-cmdb网站相关的配置&lt;/p&gt;

    &lt;p&gt;site.domain_url bk-cmdb的域名，用来做跳转使用&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;login 登录系统相关的配置&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;
        &lt;p&gt;login.version 当前系统系统使用的登录方式，现在支持两种blueking,skip-login,
 默认是blueking，蓝鲸登录，skip-login 表示没有登录系统，所有请求都是admin账户&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;login配置下其他子项，都是登录系统用到其他的配置，可以根据登录方式组件的需要来配置，
 建议有检查是否登录，登录系统跳转的url等相关配置&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;示例:&lt;/p&gt;
&lt;div class=&quot;language-ini highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;nn&quot;&gt;[site]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;domain_url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://127.0.0.1:80&lt;/span&gt;

&lt;span class=&quot;nn&quot;&gt;[login]&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;skip-login  &lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;check_url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://127.0.0.1/login/accounts/get_user/?bk_token=&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;bk_login_url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http://127.0.0.1/login/?app_id=%s&amp;amp;c_url=%s&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;开发登录插件&quot;&gt;开发登录插件&lt;/h4&gt;

&lt;p&gt;需要实现功能：&lt;/p&gt;

&lt;p&gt;interface 定义的位置：src/web_server/middleware/user/plugins/manager/manager.go&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-interface&quot;&gt;
	LoginUser(c *gin.Context, config map[string]string, isMultiOwner bool) (user *LoginUserInfo, loginSucc bool)
	GetUserList(c *gin.Context, config map[string]string, params map[string]string) ([]*LoginSystemUserInfo, error)
	GetLoginUrl(c *gin.Context, config map[string]string, input *LogoutRequestParams) string



&lt;/code&gt;&lt;/pre&gt;

&lt;h6 id=&quot;loginuser-判断用户是否登录&quot;&gt;LoginUser 判断用户是否登录&lt;/h6&gt;

&lt;p&gt;参数：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;c  gin 框架请求相关信息，用来获取request header和cookie信息。&lt;/li&gt;
  &lt;li&gt;config  web.conf 配置文件内容， eg: map[string]string{“sit.domain_url”:”xx”, “login.version”:”xxxx”}&lt;/li&gt;
  &lt;li&gt;isMultiOwner 保留项目，暂时未启用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;返回值：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;user 返回当前登录用户的信息&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoginUserInfo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;UserName&lt;/span&gt;      &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;username&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 用户的英文名，&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ChName&lt;/span&gt;        &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;chname&quot;`&lt;/span&gt;   &lt;span class=&quot;c&quot;&gt;// 用户的中文名&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Phone&lt;/span&gt;         &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;phone&quot;`&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// 电话号码&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Email&lt;/span&gt;         &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;email&quot;`&lt;/span&gt;    &lt;span class=&quot;c&quot;&gt;// 用户的邮箱 &lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Role&lt;/span&gt;          &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;-&quot;`&lt;/span&gt;        &lt;span class=&quot;c&quot;&gt;// 已废弃字段&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;BkToken&lt;/span&gt;       &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;bk_token&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// bk_token 用来写入session&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;OnwerUin&lt;/span&gt;      &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;current_supplier&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;//预留字段&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;OwnerUinArr&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LoginUserInfoOwnerUinList&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;supplier_list&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;//预留字段&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;IsOwner&lt;/span&gt;       &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;                        &lt;span class=&quot;s&quot;&gt;`json:&quot;-&quot;`&lt;/span&gt;             &lt;span class=&quot;c&quot;&gt;// 预留字段&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Extra&lt;/span&gt;         &lt;span class=&quot;k&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;      &lt;span class=&quot;s&quot;&gt;`json:&quot;extra&quot;`&lt;/span&gt;         &lt;span class=&quot;c&quot;&gt;// 预留字段&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Language&lt;/span&gt;      &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;-&quot;`&lt;/span&gt;             &lt;span class=&quot;c&quot;&gt;// 用户在在登录系统中的语言，zh-cn,en. zh-cn中文，en英文，默认值zh-cn&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;AvatarUrl&lt;/span&gt;     &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;                      &lt;span class=&quot;s&quot;&gt;`json:&quot;avatar_url&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;//用户头像&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;SupplierID&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;int64&lt;/span&gt;                       &lt;span class=&quot;s&quot;&gt;`json:&quot;supplier_id&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 预留字段，默认值即可&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;MultiSupplier&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;                        &lt;span class=&quot;s&quot;&gt;`json:&quot;multi_supplier&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;// 预留字段，默认值即可&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;ul&gt;
  &lt;li&gt;loginSucc 是否登录成功&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;其他：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;登录系统无法在当前bk-cmdb域名的cookie写入bk_token的的时候，可以在这里完成。&lt;/li&gt;
&lt;/ul&gt;

&lt;h6 id=&quot;getuserlist-从登录系统获取用户列表&quot;&gt;GetUserList 从登录系统获取用户列表&lt;/h6&gt;

&lt;p&gt;参数：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;c  gin 框架请求相关信息，用来获取request header和cookie信息。&lt;/li&gt;
  &lt;li&gt;config  web.conf 配置文件内容， eg: map[string]string{“sit.domain_url”:”xx”, “login.version”:”xxxx”}&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;返回值:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;[]*LoginSystemUserInfo&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LoginSystemUserInfo&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;CnName&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;chinese_name&quot;`&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;中文名&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;EnName&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;english_name&quot;`&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;###&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;英文名&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;error 错信息&lt;/li&gt;
&lt;/ul&gt;

&lt;h6 id=&quot;getloginurl-获取登录系统的地址&quot;&gt;GetLoginUrl 获取登录系统的地址&lt;/h6&gt;

&lt;p&gt;参数：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;c  gin 框架请求相关信息，用来获取request header和cookie信息。&lt;/li&gt;
  &lt;li&gt;config  web.conf 配置文件内容， eg: map[string]string{“sit.domain_url”:”xx”, “login.version”:”xxxx”}&lt;/li&gt;
  &lt;li&gt;input 使用的协议， https, http&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;返回值:&lt;/p&gt;

&lt;p&gt;string 跳转到登录系统的地址，&lt;/p&gt;

&lt;p&gt;建议：
登录系统都支持登录成功后跳转回原有系统，这个要设置好。&lt;/p&gt;

&lt;h5 id=&quot;注册登录插件&quot;&gt;注册登录插件&lt;/h5&gt;

&lt;pre&gt;&lt;code class=&quot;language-glang&quot;&gt;package blueking

import (
	&quot;configcenter/src/web_server/middleware/user/plugins/manager&quot;
)

func init() {
	plugin := &amp;amp;metadata.LoginPluginInfo{
		Name:       &quot;my bk-cmdb login system&quot;, //登录组件的描述
		Version:    &quot;my-login&quot;,  // 登录组件的名字
		HandleFunc: &amp;amp;user{},  //提供服务集合, 提供LoginUser，GetUserList，GetLoginUrl功能。
	}
	manager.RegisterPlugin(plugin) //想插件管理注册插件
}

&lt;/code&gt;&lt;/pre&gt;

&lt;h5 id=&quot;提供服务&quot;&gt;提供服务&lt;/h5&gt;

&lt;p&gt;去 src/web_server/middleware/user/plugins/register 目录中新加一个文件。导入注册登录插件所在的package&lt;/p&gt;

&lt;p&gt;可以参看blueking的方式。&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;manager&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;configcenter/src/web_server/middleware/user/plugins/method/blueking&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;查看效果&quot;&gt;查看效果&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;重新编译webserver服务&lt;/li&gt;
  &lt;li&gt;修改web.conf的login.version配置项的值等于注册登录插件中的plugin.Version&lt;/li&gt;
  &lt;li&gt;重启cmdb_adminserver使配置生效&lt;/li&gt;
  &lt;li&gt;重启cmdb_webserver查看效果&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>docker mongodb 集群模式Golang连接不上的问题</title>
   <link href="http://www.ireage.com/tcp/network/2020/03/02/mongoset_con.html"/>
   <updated>2020-03-02T00:00:00+00:00</updated>
   <id>http://www.ireage.com/tcp/network/2020/03/02/mongoset_con</id>
   <content type="html">&lt;h4 id=&quot;场景&quot;&gt;场景&lt;/h4&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;server selection error: server selection &lt;span class=&quot;nb&quot;&gt;timeout
&lt;/span&gt;current topology: Type: ReplicaSetNoPrimary
Servers:
Addr: mongosecond2:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mongosecond2:27017[-2108]&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; connection is closed
Addr: mongosecond3:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mongosecond3:27017[-2110]&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; connection is closed
Addr: mongoprimary:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mongoprimary:27017[-2109]&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; connection is closed
Addr: mongosecond1:27017, Type: Unknown, State: Connected, Average RTT: 0, Last error: connection&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;mongosecond1:27017[-2107]&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; connection is closed

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在终端使用使用mongo client 连接操作没有问题。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rs0:PRIMARY&amp;gt; db.test.insert({&quot;aa&quot;:&quot;111&quot;});
WriteResult({ &quot;nInserted&quot; : 1 })
rs0:PRIMARY&amp;gt; db.test.find();
{ &quot;_id&quot; : ObjectId(&quot;5e5cb62d5a5225dfab47ed44&quot;), &quot;aa&quot; : &quot;111&quot; }
rs0:PRIMARY&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;分析问题过程&quot;&gt;分析问题过程&lt;/h4&gt;

&lt;p&gt;背景：&lt;/p&gt;

&lt;p&gt;我的项目在宿主机上面运行，数据库mongodb在docker中进行。 mongodb共有四个容器提供服务， 其中一个台是协调者。
项目中mongodb 的配置都是127.0.0.1地址和mongodb 容器在宿主机上暴露的端口&lt;/p&gt;

&lt;p&gt;eg:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;127.0.0.1:27017
127.0.0.1:27018
127.0.0.1:27019
127.0.0.1:27020
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;可能出现的问题一&quot;&gt;可能出现的问题一&lt;/h6&gt;

&lt;p&gt;项目中配置的是IP:PORT，但是错误提示中出现是hostname:port.&lt;/p&gt;

&lt;p&gt;hostname 是容器的hostname或者是容器的IP， 再容器外是访问到mongodb服务的&lt;/p&gt;

&lt;h6 id=&quot;可能出现的问题二&quot;&gt;可能出现的问题二&lt;/h6&gt;

&lt;p&gt;我的容器是用docker-compose build 出来. 我在其中使用了
expose和ports暴露容器的端口, 我本意是expose的端口用来mognodb 集群使用，
ports的端口给服务使用。 但是具体使用的时候，提示出现了expose的端口。&lt;/p&gt;

&lt;h4 id=&quot;总结&quot;&gt;总结&lt;/h4&gt;

&lt;p&gt;出现问题的原因： mongodb golang 的driver再使用rs 集群模式的情况下，只是通过配置mongodb 地址来连接服务，
然后再通过连接到mongodb server， 取出mongodb rs相关配置， 找到mongodb server 的节点，&lt;/p&gt;

&lt;h5 id=&quot;解决防范&quot;&gt;解决防范：&lt;/h5&gt;
&lt;p&gt;就是将mongodb 配置rs配置地址， 让服务所再机器的网络可以访问rs 配置的地址即可。&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>调用出现网络错误分析的过程</title>
   <link href="http://www.ireage.com/tcp/network/2020/01/20/http_put_request_abort.html"/>
   <updated>2020-01-20T00:00:00+00:00</updated>
   <id>http://www.ireage.com/tcp/network/2020/01/20/http_put_request_abort</id>
   <content type="html">&lt;h4 id=&quot;场景&quot;&gt;场景&lt;/h4&gt;
&lt;p&gt;描述：HTTP 的PUT 调用提示网络错误。&lt;/p&gt;

&lt;p&gt;具体情况：
有用户反馈，在使用系统的时候，更新数据出现网络错误。 鉴于其他操作都没有问题，
由于是更新使用的是HTTP 的PUT 方式，怀疑用户使用的代理或者网络中间件拦截。
告知用户后，用户说没有使用代理和网络中间件，只能继续找证据，
最后是网络中的防火墙拦截了。希望对以后类似问题有帮助。 下面记录查找问题的过程。&lt;/p&gt;

&lt;h4 id=&quot;处理过程&quot;&gt;处理过程&lt;/h4&gt;

&lt;h5 id=&quot;查询日志&quot;&gt;查询日志&lt;/h5&gt;
&lt;p&gt;其实这一步是多余的。 服务端根本没有收到请求&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;没有错误日志，没有访问日志。怀疑HTTP 请求被转发错误机器。&lt;/li&gt;
  &lt;li&gt;但是使用curl 在服务说在内网调用，操作正常，&lt;/li&gt;
  &lt;li&gt;再用的机器，用POSTMAN直接指定IP还是没有请求到服务端，基本确定是代理或者网络中间的问题&lt;/li&gt;
&lt;/ul&gt;

&lt;h5 id=&quot;查看web浏览器中network相关信息&quot;&gt;查看web浏览器中network相关信息&lt;/h5&gt;

&lt;p&gt;发现浏览器给出的错误信息是 Failed to load resource: net::ERR_CONNECTION_ABORTED的错误&lt;/p&gt;

&lt;h5 id=&quot;使用wireshark-抓包查看具体的错误&quot;&gt;使用wireshark 抓包查看具体的错误&lt;/h5&gt;

&lt;p&gt;发现抓中包含多个 TCP Retransmission 相关信息. 这里感觉很怪，因为其他请求都没有问题，
网络也是稳定，所以肯定是网络中间件的问题。&lt;/p&gt;

&lt;h5 id=&quot;查看tcp连接链路&quot;&gt;查看TCP连接链路&lt;/h5&gt;

&lt;p&gt;windows 使用tracert , linux 使用traceroute&lt;/p&gt;

&lt;p&gt;拿到结果后，找到网络管理员，发现在其中的一台中的防火墙中策略是不允许PUT请求。&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>golang  http client 遇到的问题</title>
   <link href="http://www.ireage.com/golang/http/client/2019/12/31/golang_http_client.html"/>
   <updated>2019-12-31T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/http/client/2019/12/31/golang_http_client</id>
   <content type="html">&lt;p&gt;记录最近在使用golang http client 遇到的问题&lt;/p&gt;

&lt;h3 id=&quot;response-body-乱码&quot;&gt;response body 乱码&lt;/h3&gt;

&lt;p&gt;服务线上没有问题， 但是在开发阶段调用第三服务出现返回无法解析的情况。&lt;/p&gt;

&lt;p&gt;最后发现是数据被压缩造成。&lt;/p&gt;

&lt;p&gt;golang HTTP client 在收到数据的时候，在http response 在Context-Encoding=[giz|deflate|br]的时候也不去解压response body的内容，需要业务方自己去解压。 注意在golang自带有关压缩的实现，没有看到与br压缩的相关类库。&lt;/p&gt;

&lt;h3 id=&quot;http-client-发送请求连接不上服务&quot;&gt;http client 发送请求连接不上服务&lt;/h3&gt;

&lt;p&gt;在terminal,浏览器发送请求都可以正常访问，但是在golang服务中的HTTP 请求返回连接不上服务(i/o timeout)。这种情况查看下使用的HTTP 的client中的transport的Proxy 属性是不是给设置为nil，golang的http package中有一个叫ProxyFromEnvironment方法。改方法是从环境变量中获取配置的代理信息的。如果你需要使用系统配置的Proxy可以使用http.ProxyFromEnvironment方法,否则可以实现自己的proxy方法。&lt;/p&gt;

&lt;h3 id=&quot;出现io-read-timeout&quot;&gt;出现I/O read timeout&lt;/h3&gt;

&lt;p&gt;这个有可能不是服务端引起的。 检查下是否的连接池的中连接是否设置连接的SetReadDeadline的值。 该方法再golang的net package 中的 conn.go 中的Conn对象中&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>golang http 优雅重启</title>
   <link href="http://www.ireage.com/golang/graceful/2019/10/13/golang_http_graceful.html"/>
   <updated>2019-10-13T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/graceful/2019/10/13/golang_http_graceful</id>
   <content type="html">&lt;h3 id=&quot;目标&quot;&gt;目标&lt;/h3&gt;
&lt;ol&gt;
  &lt;li&gt;停止服务（正在处理HTTP 请求不受影响，需要等待其完成）&lt;/li&gt;
  &lt;li&gt;启动服务&lt;/li&gt;
  &lt;li&gt;服务不中断&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;遇到的问题&quot;&gt;遇到的问题&lt;/h3&gt;

&lt;h4 id=&quot;1-如何知道http-请求是否已经处理结束&quot;&gt;1. 如何知道HTTP 请求是否已经处理结束&lt;/h4&gt;

&lt;p&gt;这里主要使用Server.Shutdown 方法。 
使用Shutdown方法要注意一下问：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;golang 版本必须是1.8及其以上的版本。&lt;/li&gt;
  &lt;li&gt;参数context 使用WithTimeout 生成的时候，如果调用Shutdown后HTTP 请求处理时间， 将不会等待&lt;/li&gt;
  &lt;li&gt;调用shutdown后， 不会接受新的请求， http.Server会收到 http.ErrServerClosed&lt;/li&gt;
  &lt;li&gt;Shutdown 只是关闭socket接受新的请求。 如果有新的请求发来，不会直接拒绝。&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;2-如何解决在等待http服务结束无法启动服务的问题&quot;&gt;2. 如何解决在等待HTTP服务结束，无法启动服务的问题？&lt;/h4&gt;

&lt;p&gt;使用以下的方法解决问题：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;exec.Command开启新的服务&lt;/li&gt;
  &lt;li&gt;scoket file descriptor 共享监听&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;具体实现&quot;&gt;具体实现&lt;/h3&gt;

&lt;h4 id=&quot;优点&quot;&gt;优点&lt;/h4&gt;
&lt;ul&gt;
  &lt;li&gt;对自我的更新&lt;/li&gt;
  &lt;li&gt;服务不中断
    &lt;h4 id=&quot;缺点&quot;&gt;缺点&lt;/h4&gt;
  &lt;/li&gt;
  &lt;li&gt;无法使用supervisor管理&lt;/li&gt;
  &lt;li&gt;通过graceful更新的进程父进程会变成init进程&lt;/li&gt;
  &lt;li&gt;在执行shutdown 会有两个进程&lt;/li&gt;
  &lt;li&gt;ps 查看进程，参数会发生变化&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/golang-graceful-restart-demo/blob/master/graceful/graceful.go&quot; title=&quot;完整的代码&quot;&gt;查看完整的代码&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;主要代码如下：&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 等待更新命令&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 是否通过程序自身完成优雅的重启&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BoolVar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;graceful&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;graceful start&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:9999&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// 使用共享的listen fd， 在执行shutdown的过程中， &lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// 启动不会收到listen tcp :8080: bind: address already in use&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// why fd = 3. &lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// ExtraFiles specifies additional open files to be inherited by the&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// new process. It does not include standard input, standard output, or&lt;/span&gt;
        &lt;span class=&quot;c&quot;&gt;// standard error. If non-nil, entry i becomes file descriptor 3+i.&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// 首次启动， 需要建立socket 链接&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;tcp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;:9999&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TCPListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;httServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// runWorker 启动新的worker 来接受HTTP 请求&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;runWorker&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 等待更新命令&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;execute start&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;c&quot;&gt;// 使用新的二进制更新本身&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execFile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;./graceful&quot;&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;execFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-graceful=true&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 共享 stdout, stderr&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stdout&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stderr&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 共享socket 链接&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ExtraFiles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;listenFile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 父进程退出，子进程可以接续执行&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SysProcAttr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syscall&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SysProcAttr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Setpgid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 这里是阻塞，需要注意&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execCmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 这里如果想知道进程是否准备好，可以接受新的任务。 &lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 可以在xecCmd.ExtraFiles 多传入一个file，来处理。相对比较麻烦&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;//  或者通过信号量&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;execute end&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FileListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, pid:%d, path:%s, time:%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EscapeString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 执行优雅的重启 HTTP api&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/graceful&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, graceful  pid:%s, time:%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/sleep&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;50&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello, graceful pid:%d,  time:%s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Getpid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Serve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;c&quot;&gt;// http.ErrServerClosed 是有http shutdown 引起&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ErrServerClosed&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatalf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;listen %s error. err:%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shutdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 执行优雅的的命令&lt;/span&gt;
	&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;graceful&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;// 这里最好有sleep， 保证接受新服务已经启动,&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Server is shutting down...&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetKeepAlivesEnabled&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Shutdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatalf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Could not gracefully shutdown the server: %v &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;quitChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;make&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;quitChan&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quitChan&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>mysql this authentication plugin is not supported</title>
   <link href="http://www.ireage.com/golang/mysql/2019/04/29/golang_mysql_conn_err.html"/>
   <updated>2019-04-29T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/mysql/2019/04/29/golang_mysql_conn_err</id>
   <content type="html">&lt;p&gt;出现这个是因为你使用MySql 5.7及以上的版本。如果不是就不用继续看了。这篇文章对你没有帮助。&lt;/p&gt;

&lt;p&gt;出现问题原因：
mysql5.7中user表的password字段已被取消，取而代之的事 authentication_string 字段。
mysql.user 表中的plugin字段值不对。如果用户对应plugin=caching_sha2_password. 我们遇到的问题是一样的。&lt;/p&gt;

&lt;p&gt;确认方式如下：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mysql&amp;gt; use mysql&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
mysql&amp;gt; &lt;span class=&quot;k&quot;&gt;select &lt;/span&gt;host,user,plugin from mysql.user&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
+-----------+------------------+-----------------------+
| host      | user             | plugin                |
+-----------+------------------+-----------------------+
| %         | root             | caching_sha2_password |
| localhost | mysql.infoschema | caching_sha2_password |
| localhost | mysql.session    | caching_sha2_password |
| localhost | mysql.sys        | caching_sha2_password |
+-----------+------------------+-----------------------+
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;修复问题方式如下：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mysql&amp;gt; use mysql&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
mysql&amp;gt; ALTER USER &lt;span class=&quot;s1&quot;&gt;&apos;user name&apos;&lt;/span&gt;@&lt;span class=&quot;s1&quot;&gt;&apos;host&apos;&lt;/span&gt; IDENTIFIED WITH mysql_native_password BY &lt;span class=&quot;s1&quot;&gt;&apos;user new password&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
mysql&amp;gt; flush privileges&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;确认方案：&lt;/p&gt;

&lt;p&gt;修改样例（我修改的root用户）：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mysql&amp;gt; use mysql;
mysql&amp;gt; ALTER USER &apos;root&apos;@&apos;%&apos; IDENTIFIED WITH mysql_native_password BY &apos;newpassword&apos;;
mysql&amp;gt; flush privileges; 

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;mysql.user 表中用户对应的plugin 字段是否改变为mysql_native_password&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mysql&amp;gt; use mysql&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
mysql&amp;gt; &lt;span class=&quot;k&quot;&gt;select &lt;/span&gt;host,user,plugin from mysql.user&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
+-----------+------------------+-----------------------+
| host      | user             | plugin                |
+-----------+------------------+-----------------------+
| %         | root             | mysql_native_password |
| localhost | mysql.infoschema | caching_sha2_password |
| localhost | mysql.session    | caching_sha2_password |
| localhost | mysql.sys        | caching_sha2_password |
+-----------+------------------+-----------------------+

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>web 服务error的设计</title>
   <link href="http://www.ireage.com/web/2019/04/24/web_error_design.html"/>
   <updated>2019-04-24T00:00:00+00:00</updated>
   <id>http://www.ireage.com/web/2019/04/24/web_error_design</id>
   <content type="html">&lt;h2 id=&quot;1-为什么要设计系统自己的error&quot;&gt;1. 为什么要设计系统自己的error&lt;/h2&gt;

&lt;p&gt;我们为什么要设计的系统自己的error，就为了重复造轮子？&lt;/p&gt;

&lt;p&gt;每个语言都有自己的error系统，为什么不使用？&lt;/p&gt;

&lt;p&gt;要回答这些问题。需要先了解error出现和使用的场景。&lt;/p&gt;

&lt;p&gt;error 是当服务在链接第三方服务，校验数据，处理逻辑异常的时候用于提示用户，查找出错原因第一手资料。&lt;/p&gt;

&lt;p&gt;用户的提示：简单易懂&lt;/p&gt;

&lt;p&gt;开发人员： 需要详细的上下信息&lt;/p&gt;

&lt;p&gt;面向第三方系统： 错误归类，判断。&lt;/p&gt;

&lt;p&gt;所以当以错误产生的时刻需要将错误处理为面向用户，面向开发人员和第三方系统的格式。&lt;/p&gt;

&lt;p&gt;语言本身的系统error或exception 适用于开发人员。带有很强的专业性。不适宜展示给用户或者第三方系统。 语言本的系统error或exception 也缺乏去多语言，多长场景的支持。&lt;/p&gt;

&lt;h3 id=&quot;2-error-内容&quot;&gt;2. error 内容&lt;/h3&gt;

&lt;p&gt;error_code  与第三方系统交互实用&lt;/p&gt;

&lt;p&gt;error_messsage  提示用户使用&lt;/p&gt;

&lt;p&gt;request_id  聚合日志使用&lt;/p&gt;

&lt;p&gt;http_code  http response 状态码&lt;/p&gt;

&lt;h3 id=&quot;3-error-带有的方法&quot;&gt;3. error 带有的方法&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;error  code 对应一个format 格式字符串&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code class=&quot;language-code&quot;&gt;
// 根据错误码和参数生成error
Errorf(code int, .... interface{}) 

// 根据错误生成error
Error(code int)

// 根据第三方系统的error code 和error message 生成error
New(code int, msg string)

// 打印日志使用
String ()  string 

// error code 
Code() int

// error message

Message() string

&lt;/code&gt;&lt;/pre&gt;
</content>
 </entry>
 
 <entry>
   <title>golang json</title>
   <link href="http://www.ireage.com/golang/2019/03/16/jsontag.html"/>
   <updated>2019-03-16T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2019/03/16/jsontag</id>
   <content type="html">&lt;h3 id=&quot;json-序列化反序列化规则&quot;&gt;json 序列化/反序列化规则&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bool  for JSON booleans
float64 for JSON numbers（包含 int,int64,int32,int16 ...）
string, for JSON strings (包含字符串，时间)
[]interface{}, for JSON arrays(数字，字符串，对象等组成的数组，json )
map[string]interface{}, for JSON objects 
nil for JSON null
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;golang-为什么要有jsontag&quot;&gt;golang 为什么要有jsontag&lt;/h3&gt;

&lt;p&gt;由于golang使用大小作为是否导出属性，方法的定义的规则。
造成golang json Unmarshal 无法将小写开头的json的key解析到struct结构。
例如：&lt;/p&gt;
&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{&quot;a&quot;:2}`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aStruct&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;json Unmarshal 后, A/a 字段中都是空值。 在给结构的key 加上tag后就可以取出
小写字段的key&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`{&quot;a&quot;:2,&quot;aa&quot;:4}`&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aStruct&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;a&quot;`&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;`json:&quot;aa&quot;`&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;//小写属性加tag是无意义的。值解析不上的&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;golang-内置tag&quot;&gt;golang 内置tag&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;omitempty：如果字段的值为空
（boolean as false, number as 0,  nil pointer, a nil interface value, and any empty array, slice, map, or string）
在序列化时该字段不存
-：该字段在json 序列化/反序列忽律
string：将字段值在编码过程中转换成 JSON 中的字符串类型，只有当字段类型是 string, floating point, integer, or boolean 的情况下才会转换。

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;golang-tag-作用&quot;&gt;golang tag 作用&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;反序列化支持json小写key反写到struct 的key中&lt;/li&gt;
  &lt;li&gt;支持json中的key转化
```
type Login struct {
 User   string &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;json:&quot;usr&quot;&lt;/code&gt;
 Password string    &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;json:&quot;pwd&quot; &lt;/code&gt;
}&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
### golang json 反序列一个key支持多种数据类型

由于golang 是一种强类型语言。struct对象的key类型是固定的。
但是在弱类型语言中对就不一样了。 

例如：PHP （支持key为字符串）
如果 PHP array是空的时候，序列化出来是[]。
但是不为空的时候，序列化出来的是{&quot;key&quot;:&quot;value&quot;}或者是[&quot;val1&quot;,&quot;val2&quot;]
我们需要把 [] 当成 {} 处理。


这种情况我们可以使用重载UnmarshalJson的方法来实现

```golang 
代码：
package main

import (
	&quot;encoding/json&quot;
	&quot;fmt&quot;
	&quot;strings&quot;
)

type AField struct {
	A map[string]interface{}
	B []string
}

func (a *AField) UnmarshalJSON(b []byte) error {
	str := strings.TrimSpace(string(b))
	if str == &quot;&quot; || str == &quot;[]&quot; {
		a.A = nil
		return nil
	}
	if err := json.Unmarshal(b, &amp;amp;a.B); err == nil {
		return nil
	}
	return json.Unmarshal(b, &amp;amp;a.A)
}

type tmpStruct struct {
	A AField `json:&quot;a&quot;`
}

func main() {
	strArr := `{&quot;a&quot;:[&quot;b&quot;,&quot;b&quot;]}`
	strMap := `{&quot;a&quot;:{&quot;aa&quot;:&quot;11&quot;}}`

	t1 := new(tmpStruct)
	t2 := new(tmpStruct)
	json.Unmarshal([]byte(strArr), t1)
	json.Unmarshal([]byte(strMap), t2)

	fmt.Println(fmt.Sprintf(&quot;%#v&quot;, t1))
	fmt.Println(fmt.Sprintf(&quot;%#v&quot;, t2))
}
结果：

&amp;amp;main.tmpStruct{A:main.AField{A:map[string]interface {}(nil), B:[]string{&quot;b&quot;, &quot;b&quot;}}}
&amp;amp;main.tmpStruct{A:main.AField{A:map[string]interface {}{&quot;aa&quot;:&quot;11&quot;}, B:[]string(nil)}}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>为什么要使用request id</title>
   <link href="http://www.ireage.com/%E5%85%B6%E4%BB%96/2018/12/16/request_id.html"/>
   <updated>2018-12-16T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E5%85%B6%E4%BB%96/2018/12/16/request_id</id>
   <content type="html">&lt;h4 id=&quot;1-request-id-是为了解决下面问题&quot;&gt;1. request id 是为了解决下面问题&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;问题一： 客户端访问的Web服务时，如何将客户端请求与服务端日志关联 
问题二： 微服务架构下，访问日志如何查询
问题三： 不同项目交互出现异常，如何做日志关联
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2-request-id-vs-没有request-id&quot;&gt;2. request id vs 没有request id&lt;/h4&gt;

&lt;h5 id=&quot;没有request-id-请求&quot;&gt;没有request id 请求&lt;/h5&gt;

&lt;p&gt;只能根据调用函数日志关键，在根据用户的输入的参数，时间来确定相关的日志。
 如果项目是以分布式，微服务架构来实现， 上面查日志方式帮助很小。&lt;/p&gt;

&lt;p&gt;原因如下&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;代码层层封装后，无法通过日志关键与用户请求关联&lt;/li&gt;
  &lt;li&gt;微服务架构下，用户请求逻辑层分解多个子任务给下层服务处理，下层服务无法与用户请求关联&lt;/li&gt;
  &lt;li&gt;不同项目交互，如何在并发，错误重试，参数相同的情况下，无法通过关键字，时间来确定日志&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;request-id&quot;&gt;request id&lt;/h5&gt;

&lt;ol&gt;
  &lt;li&gt;当前项目，根据request id 可以找到所有与请求相关的日志&lt;/li&gt;
  &lt;li&gt;不同项目，可以根据request id 确定唯一的请求&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;3-request-id-好处&quot;&gt;3. request id 好处&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;用户请求日志关联&lt;/li&gt;
  &lt;li&gt;项目间请求日志关联&lt;/li&gt;
  &lt;li&gt;多服务间日志聚合&lt;/li&gt;
  &lt;li&gt;调用关系分析&lt;/li&gt;
  &lt;li&gt;日志分析&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;4-request-id-依赖&quot;&gt;4. request id 依赖&lt;/h4&gt;

&lt;ol&gt;
  &lt;li&gt;使用request id，要有配套日志记录系统&lt;/li&gt;
  &lt;li&gt;周边系统支持，保持统一&lt;/li&gt;
  &lt;li&gt;request id 每次用户请求，必须保证唯一。&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;5-高级用法&quot;&gt;5. 高级用法&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://ai.google/research/pubs/pub36356&quot;&gt;Google Dapper&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://zipkin.io/&quot;&gt;Google Dapper 实现 zipkin&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>git comMit messge 消息格式规范</title>
   <link href="http://www.ireage.com/git/2018/12/07/git_commit_format.html"/>
   <updated>2018-12-07T00:00:00+00:00</updated>
   <id>http://www.ireage.com/git/2018/12/07/git_commit_format</id>
   <content type="html">&lt;p&gt;根据外部文档总结出来git commit 提交的格式规范&lt;/p&gt;

&lt;h1 id=&quot;git-commit-messge-消息格式&quot;&gt;git commit messge 消息格式&lt;/h1&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  type:messsge issue 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;样例&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  # 新加一个文档 
  git commit -m &quot;docs: add readme document issue #1 #2&quot;  readme.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;type-取值范围&quot;&gt;type 取值范围&lt;/h2&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;标记&lt;/th&gt;
      &lt;th&gt;含义&lt;/th&gt;
      &lt;th&gt;加入版本&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;feature&lt;/td&gt;
      &lt;td&gt;新功能&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;fix&lt;/td&gt;
      &lt;td&gt;错误修复&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;docs&lt;/td&gt;
      &lt;td&gt;文档更改&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;style&lt;/td&gt;
      &lt;td&gt;（格式化，缺少半冒号等;没有代码更改）&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;refactor&lt;/td&gt;
      &lt;td&gt;代码重构重构&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;test&lt;/td&gt;
      &lt;td&gt;添加缺失的测试，重构测试;没有生产代码更改&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;chore&lt;/td&gt;
      &lt;td&gt;构建脚本，任务等相关代码&lt;/td&gt;
      &lt;td&gt;v1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;depend&lt;/td&gt;
      &lt;td&gt;依赖的第三方代码&lt;/td&gt;
      &lt;td&gt;v2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;lib&lt;/td&gt;
      &lt;td&gt;公共类库代码&lt;/td&gt;
      &lt;td&gt;v2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;define&lt;/td&gt;
      &lt;td&gt;公共变量定义&lt;/td&gt;
      &lt;td&gt;v2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;merge&lt;/td&gt;
      &lt;td&gt;不同分支之间的代码合并, issue 内容可以忽略&lt;/td&gt;
      &lt;td&gt;v2&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;info&lt;/td&gt;
      &lt;td&gt;注释等描述类型内容&lt;/td&gt;
      &lt;td&gt;v3&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h2 id=&quot;message&quot;&gt;message&lt;/h2&gt;
&lt;p&gt;本次提交的描述&lt;/p&gt;

&lt;h2 id=&quot;issue&quot;&gt;issue&lt;/h2&gt;
&lt;p&gt;本次提交相关的issue ,可以有多个&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>net/http timeout awaiting response headers</title>
   <link href="http://www.ireage.com/golang/2018/10/08/golang_net_http_timeout_awaiting_response_headers.html"/>
   <updated>2018-10-08T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2018/10/08/golang_net_http_timeout_awaiting_response_headers</id>
   <content type="html">&lt;h3 id=&quot;前提&quot;&gt;前提&lt;/h3&gt;

&lt;p&gt;在做系统压测的是发现有部分接口，返回 &lt;strong&gt;net/http: timeout awaiting response headers&lt;/strong&gt; 错误，&lt;/p&gt;

&lt;h3 id=&quot;分析&quot;&gt;分析&lt;/h3&gt;

&lt;p&gt;看到错误首先想到的是http请求超时， 修改http client的timeout发下没有任何效果。&lt;/p&gt;

&lt;p&gt;但是这个错误就是http client 超时引起。是http client 在一定时间内没有返回数据，
客户端取消连接引起。 这个是由于http.Client的transport中ResponseHeaderTimeout 设置不合理引起的。&lt;/p&gt;

&lt;h3 id=&quot;相关知识&quot;&gt;相关知识&lt;/h3&gt;

&lt;p&gt;net.Dialer.Timeout 限制建立TCP连接的时间&lt;/p&gt;

&lt;p&gt;http.Transport.TLSHandshakeTimeout 限制 TLS握手的时间&lt;/p&gt;

&lt;p&gt;http.Transport.ResponseHeaderTimeout 限制读取response 返回内容的时间&lt;/p&gt;

&lt;p&gt;http.Transport.ExpectContinueTimeout 限制client在发送包含 Expect: 100-continue的header到收到继续发送body的response之间的时间等待。注意在1.6中设置这个值会禁用HTTP/2(DefaultTransport自1.6.2起是个特例)&lt;/p&gt;

&lt;h3 id=&quot;场景重现代码&quot;&gt;场景重现代码&lt;/h3&gt;

&lt;p&gt;使用下面代码中的client 调用服务端即可&lt;/p&gt;

&lt;div class=&quot;language-golang highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;c&quot;&gt;// server code &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpServer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;srv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Server&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;ReadTimeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;WriteTimeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;Addr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;         &lt;span class=&quot;s&quot;&gt;&quot;:65530&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

	&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandleFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseWriter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;{}&quot;&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;go&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;srv&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ListenAndServe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;}()&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;// client code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;transport&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;TLSHandshakeTimeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;TLSClientConfig&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;Dial&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dialer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;m&quot;&gt;500&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
				&lt;span class=&quot;n&quot;&gt;KeepAlive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;30&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Dial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;ResponseHeaderTimeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;Timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;m&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;Transport&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;transport&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
		&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://127.0.0.1:65530/aa&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
			&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;


	&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;其他&quot;&gt;其他&lt;/h3&gt;

&lt;p&gt;虽然client 出现net/http: timeout awaiting response headers 错误， 但是后端服务还在继续执行，返回数据会出现SIGPIPE，因为该链接已经断开&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>共享分布式锁</title>
   <link href="http://www.ireage.com/distributed%20lock/2018/09/02/distributedlock.html"/>
   <updated>2018-09-02T00:00:00+00:00</updated>
   <id>http://www.ireage.com/distributed%20lock/2018/09/02/distributedlock</id>
   <content type="html">&lt;h4 id=&quot;前提&quot;&gt;前提&lt;/h4&gt;

&lt;p&gt;分布式锁是在分布式系统中，我们为了保证分布式系统的效率和数据的正确性，在相同工作的多个节点中不被重复处理而采用的技术的。&lt;/p&gt;

&lt;h4 id=&quot;使用场景&quot;&gt;使用场景&lt;/h4&gt;

&lt;p&gt;现在看网上的分布式锁都是现在资源限制。 锁的使用者限定到当前服务使用者。 在分层的web锁无法继承。
在系统设计中我们经常会才分层设计， 会有负责处理逻辑的层，处理数据的存储层。为了保证服务的高可用每一个服务我们都会部署多个实例。 
为了保证数据的完整性，我们需要在逻辑锁住资源， 在数据处理层修改数据。   这里面就涉及到两个问题&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;锁如何共享？&lt;/li&gt;
  &lt;li&gt;如何获取锁？&lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;实现&quot;&gt;实现&lt;/h4&gt;

&lt;h6 id=&quot;分布式锁实现&quot;&gt;分布式锁实现&lt;/h6&gt;

&lt;p&gt;为了保证分布式锁的正确性，我们可以选择以下方案。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;redis SETNX 方案&lt;/li&gt;
  &lt;li&gt;redisLock 方案&lt;/li&gt;
  &lt;li&gt;zookeeper 顺序节点&lt;/li&gt;
&lt;/ol&gt;

&lt;h5 id=&quot;锁的结构设计&quot;&gt;锁的结构设计&lt;/h5&gt;

&lt;p&gt;注解：由于锁是在分布式事务中事务，其中定义变量与实务相关, 代码是golang&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
锁的结构

type Lock struct {
	//  当前锁的标记。 是开启事务得到的事务ID， 事务主ID，不可以为空
	TxnID string `json:&quot;txnID&quot;`

	// 锁资源的子事务ID， 可以为空， 为空将自动生成改项目
	SubTxnID string `json:&quot;subTxnID&quot;`

	// 被锁资源的标记或者名字
	LockName string `json:&quot;lockName&quot;`

	
	// 锁的超时时间
    Expire time.Duration `json:&quot;expire&quot;`

    // 锁的创建时间
	Createtime time.Time `json:&quot;createTime&quot;`
}


锁的返回值， 无法锁住资源时，返回nil （就是空NULL）
type LockResult struct {
	// 锁资源的子事务ID， 
	SubTxnID string `json:&quot;subTxnID&quot;`

	// 获取lock 传入的TxnID事务中是否有子事务拥有锁，
	Locked bool `json:&quot;locked&quot;`

	// 拥有锁的子事务ID， 及时第一lock资源的子事务ID
	LockSubTxnID string `json:&quot;lockSubTxnID&quot;`
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;如何获取锁&quot;&gt;如何获取锁&lt;/h5&gt;

&lt;ul&gt;
  &lt;li&gt;用户需要携带TxnID 和 SubTxnID, TxnID必填， SubTxnID非必填，如果SubTxnID没有填写，则自动生成。&lt;/li&gt;
  &lt;li&gt;使用原子操作写入原子锁， 如果写入成功，则表示当前TxnID和SubTxnID拥有锁。&lt;/li&gt;
  &lt;li&gt;使用原子操作写入原子锁， 如果写入失败，获取当前锁的内容， 先判断锁中的TxnID是否与传入的TxnID相等， 如何不等于返回无法锁住资源， &lt;br /&gt;
否则TxnID等于TxnID， 继续执行&lt;/li&gt;
  &lt;li&gt;判断SubTxnID是否等于传入的SubTxnID， 等于则返回当前TxnID和SubTxnID拥有锁， 否则返回TxnID拥有锁， SubTxnID不拥有锁&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;如何共享锁&quot;&gt;如何共享锁&lt;/h4&gt;

&lt;p&gt;逻辑层调用存储层的时候通过HTTP header 将TxnID 透传下去&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>优雅的写go test</title>
   <link href="http://www.ireage.com/golang/go%20test/2018/07/24/gotest.html"/>
   <updated>2018-07-24T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/go%20test/2018/07/24/gotest</id>
   <content type="html">&lt;h3 id=&quot;go-test-介绍&quot;&gt;go test 介绍&lt;/h3&gt;

&lt;p&gt;go语言的单元测试采用内置的测试框架,通过引入testing包以及go test来提供测试功能。
go语言的单元测试是一个个单独的文件。 每一个单元测试文件是与源代码同名加上_test.go的文件，
没有单元测试的文件必须以_test.go结尾&lt;/p&gt;

&lt;p&gt;eg:代码文件是 aa.go, 单元测试的文件就应该是aa_test.go&lt;/p&gt;

&lt;p&gt;go test 执行会主动调用当前执行go test 命令目录及子目录中所有已_test.go结尾文件中的
的以Test开头函数(谨记Test后的第一字母需要是大写)， 
当go test 带有-benchmem参数时， 会调用已Benchmark开头函数(谨记Benchmark后的第一字母需要是大写)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>excel文件实现包含xml的详情</title>
   <link href="http://www.ireage.com/excel/2018/07/15/excel_xml.html"/>
   <updated>2018-07-15T00:00:00+00:00</updated>
   <id>http://www.ireage.com/excel/2018/07/15/excel_xml</id>
   <content type="html">&lt;h3 id=&quot;excel-文件描述&quot;&gt;excel 文件描述&lt;/h3&gt;

&lt;p&gt;excel 是一个包含多个xml文件目录的zip压缩文件。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/表示为excel文件解压后的根目录
/docProps 文档相关的属性
/xl excel  数据相关厨房目录
/xl/charts excel 图表相关都存在这里
/xl/drawings excel 图表定义 
/xl/worksheets excel工作簿下sheet存放目录
/xl/media 用来excel中导入的图片，声音，视频等地方资源
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;excel-文件组成部分&quot;&gt;excel 文件组成部分&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/_rels/.rels  包关系项

/[Content_Types].xml  内容类型项

/docProps/app.xml  应用程序定义的文件属性部分，sheet与sheet名字关系，

/docProps/core.xml   核心文件属性部分

/xl/workbook.xml   工作簿部分相关定义

/xl/_rels/workbook.xml.rels 部分关系项


/xl/sharedStrings.xml   共享字符串表部分，用户输入内容

/xl/styles.xml   样式部分，关于font，boder,fill 相关定义


/xl/worksheets/sheetX.xml   excel中sheet中单元格与样式的关系，内容，数据校验等相关

/xl/theme/themeX.xml   sheetX的主题部分，themeX中的**X**表示的是工作X（数字）的主题，eg:1,2,3 

/xl/media/nameX.xml excel引入外部资源的定义
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;必须的xml文件&quot;&gt;必须的xml文件&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/_rels/.rels

/docProps/app.xml

/docProps/core.xml

/xl/sharedStrings.xml

/xl/styles.xml

/xl/thene/themeX.xml

/xl/workbook.xml

/xl/worksheets/sheetX.xml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;stylexml&quot;&gt;style.xml&lt;/h4&gt;

&lt;p&gt;style有font,fill, border,cellXfs等四部分组成。&lt;/p&gt;

&lt;p&gt;font 表示字体相关的描述&lt;/p&gt;

&lt;p&gt;fill 表示填充颜色及样式&lt;/p&gt;

&lt;p&gt;border 表示边框颜色及样式&lt;/p&gt;

&lt;p&gt;cellXfs有font,fill,border组成，来描述一个具体对象的样式&lt;/p&gt;

&lt;p&gt;每一个xml节点的count属性表示共有多少个子对象&lt;/p&gt;
&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;styleSheet&amp;gt;&lt;/span&gt; 
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;font&amp;gt;&amp;lt;/font&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;fills&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;count=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
       &lt;span class=&quot;nt&quot;&gt;&amp;lt;fill&amp;gt;&amp;lt;/fill&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;/fills&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;borders&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;count=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
       &lt;span class=&quot;nt&quot;&gt;&amp;lt;border&amp;gt;&amp;lt;/border&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;/borders&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;cellXfs&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;count=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
	   &lt;span class=&quot;nt&quot;&gt;&amp;lt;xf&amp;gt;&amp;lt;/xf&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;/cellXfs&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/styleSheet&amp;gt;&lt;/span&gt;
 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;font-组成&quot;&gt;font 组成&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;font&amp;gt;
   &amp;lt;b/&amp;gt;加粗
   &amp;lt;i/&amp;gt; 倾斜
   &amp;lt;u val=&quot;double|single&quot;/&amp;gt; 下划线，单|双
   &amp;lt;sz val=&quot;x&quot;/&amp;gt; 字体大小， val=size
   &amp;lt;name val=&quot;&quot;/&amp;gt; 字体名
   &amp;lt;family val=&quot;&quot;&amp;gt; 此元素指定当前字体的字体系列。 此信息可以按字体定义使用
当此字体不可用时，替换逻辑以找到适当的替代字体。 这个信息是
通过在存在时查询字体来确定，并且在字体不可用时不应修改。
&amp;lt;/font&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h6 id=&quot;fill-组成&quot;&gt;fill 组成&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&amp;lt;fill&amp;gt;
		&amp;lt;patternFill patternType=&quot;solid&quot;&amp;gt;  patternType表示填充的类型
			&amp;lt;fgColor rgb=&quot;AARRGGBB&quot; /&amp;gt;   前景色，AARRGGBB, AA表示是透明度，RR红色，GG绿色，BB蓝色，每一位都一个16进制数字
			&amp;lt;bgColor rgb=&quot;AARRGGBB&quot; /&amp;gt;  背景色， AARRGGBB
		&amp;lt;/patternFill&amp;gt;
	&amp;lt;/fill&amp;gt;
	
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;border diagonalUp=&quot;1&quot; diagonalDown=&quot;1&quot;&gt;
   &lt;left /&gt;
   &lt;right style=&quot;thin&quot;&gt;
    &lt;color rgb=&quot;FFFF0000&quot; /&gt;
   &lt;/right&gt;
   &lt;top /&gt;
   &lt;bottom /&gt;
   &lt;diagonal style=&quot;thin&quot;&gt;
    &lt;color rgb=&quot;FFFF0000&quot; /&gt;
   &lt;/diagonal&gt;
  &lt;/border&gt;

&lt;h6 id=&quot;border-组成&quot;&gt;border 组成&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &amp;lt;border&amp;gt;    
     &amp;lt;left /&amp;gt; 左边框
     &amp;lt;right /&amp;gt; 右边框
     &amp;lt;top /&amp;gt;  上边框
     &amp;lt;bottom /&amp;gt;  下边框
     &amp;lt;diagonal /&amp;gt; 对角线
  &amp;lt;/border&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;border 节点可以有属性diagonalUp，diagonalDown 这两个属性是border中孩子节点diagonal描述，表示对角线话的放心，
left,right,top,bottom四个节点可以有color子节点及style属性，color子节点有一个rgb属性用来描述颜色值， style表示边框的样式&lt;/p&gt;

&lt;h6 id=&quot;xf组成&quot;&gt;xf组成&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &amp;lt;xf numFmtId=&quot;&quot; fontId=&quot;&quot; fillId=&quot;&quot; borderId=&quot;&quot; xfId=&quot;&quot;&amp;gt;
   &amp;lt;alignment vertical=&quot;&quot;  horizontal=&quot;&quot; textRotation=&quot;&quot; wrapText=&quot;&quot; /&amp;gt; 
  &amp;lt;/xf&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;numFmtId 单元格格式&lt;/p&gt;

&lt;p&gt;fontId fonts节点的子节点index&lt;/p&gt;

&lt;p&gt;fillId fills节点的子节点index&lt;/p&gt;

&lt;p&gt;borderId borders节点的子节点indx&lt;/p&gt;

&lt;p&gt;vertical cell内容的对齐方式&lt;/p&gt;

&lt;p&gt;horizontal cell内容的对齐方式&lt;/p&gt;

&lt;p&gt;textRotation cell内容文字的旋转方式&lt;/p&gt;

&lt;p&gt;wrapText 文字环绕方式&lt;/p&gt;

&lt;p&gt;部分字段可选值&lt;/p&gt;

&lt;p&gt;vertical,horizontal 的部分值&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;left
center
right
fill
justify
centerContinuous
distributed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;numFmtId 的部分值
0  通用格式
1  整数
18 时间， 格式是h:mm AM/PM
19 时间， 格式是h:mm:ss AM/PM
20 时间， 格式是h:mm
21 时间， 格式是h:mm:ss
22 日期，格式是m/d/yy h:mm
49 文字&lt;/p&gt;

&lt;h4 id=&quot;sheetxxml&quot;&gt;sheetX.xml&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;worksheet&amp;gt;
   &amp;lt;dimension ref=&quot;&quot; /&amp;gt;
   &amp;lt;sheetViews&amp;gt;
  &amp;lt;sheetView windowProtection=&quot;&quot; showFormulas=&quot;&quot; showGridLines=&quot;&quot; showRowColHeaders=&quot;&quot; showZeros=&quot;&quot; rightToLeft=&quot;false&quot; tabSelected=&quot;&quot; showOutlineSymbols=&quot;true&quot; defaultGridColor=&quot;true&quot; view=&quot;normal&quot; topLeftCell=&quot;A1&quot; colorId=&quot;64&quot; zoomScale=&quot;&quot; zoomScaleNormal=&quot;&quot; zoomScalePageLayoutView=&quot;&quot; workbookViewId=&quot;&quot;&amp;gt;
       &amp;lt;/sheetView&amp;gt;
   &amp;lt;/sheetViews&amp;gt;
   &amp;lt;sheetFormatPr /&amp;gt;
   &amp;lt;col collapsed=&quot;&quot; hidden=&quot;&quot; min=&quot;&quot; max=&quot;&quot; width=&quot;&quot; style=&quot;&quot; customWidth=&quot;&quot; /&amp;gt;
   &amp;lt;sheetData&amp;gt;
      &amp;lt;row r=&quot;&quot; spans=&quot;&quot;&amp;gt;
         &amp;lt;c r=&quot;&quot; t=&quot;&quot;&amp;gt;
             &amp;lt;v&amp;gt;&amp;lt;/v&amp;gt;
         &amp;lt;/c&amp;gt;
      &amp;lt;/row&amp;gt;
   &amp;lt;/sheetData&amp;gt; 
   &amp;lt;dataValidations count=&quot;2&quot;&amp;gt;
     &amp;lt;dataValidation type=&quot;&quot; allowBlank=&quot;&quot; showInputMessage=&quot;&quot; showErrorMessage=&quot;&quot; sqref=&quot;&quot;&amp;gt;
       &amp;lt;formula1&amp;gt;
        &quot;&quot;
       &amp;lt;/formula1&amp;gt;
 	   &amp;lt;formula2&amp;gt;
        &quot;&quot;
       &amp;lt;/formula2&amp;gt;
     &amp;lt;/dataValidation&amp;gt;
    &amp;lt;/dataValidations&amp;gt;

   &amp;lt;pageMargins left=&quot;&quot; top=&quot;&quot; bottom=&quot;&quot; header=&quot;&quot; footer=&quot;&quot; /&amp;gt;
   &amp;lt;pageSetup paperSize=&quot;&quot; orientation=&quot;&quot; verticalDpi=&quot;&quot;  /&amp;gt;
   &amp;lt;drawing /&amp;gt;
   &amp;lt;extLst&amp;gt;
     &amp;lt;ext&amp;gt;
     &amp;lt;/ext&amp;gt;
   &amp;lt;/extLst&amp;gt;

&amp;lt;/worksheet&amp;gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>The Golang operation EXCEL  library  for columns and cell  supports data validation  (drop-down list, numeric text length check)</title>
   <link href="http://www.ireage.com/golang/2018/04/29/golangexceldatavalidation_en.html"/>
   <updated>2018-04-29T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2018/04/29/golangexceldatavalidation_en</id>
   <content type="html">&lt;h3 id=&quot;completed-function&quot;&gt;completed function&lt;/h3&gt;

&lt;p&gt;   1. Cell, column support drop-down list selection&lt;/p&gt;

&lt;p&gt;   2. Cell, column support range check&lt;/p&gt;

&lt;p&gt;   3. Open Excel support cell, column data check read&lt;/p&gt;

&lt;p&gt;  &lt;/p&gt;
&lt;h3 id=&quot;items-to-pay-attention-to&quot;&gt;Items to pay attention to&lt;/h3&gt;
&lt;p&gt;  
   1. Excel data validation supports setting the length of the check character to 255,&lt;/p&gt;

&lt;p&gt;   2. Excel is not supported as a check condition by selecting cells in the workbook&lt;/p&gt;

&lt;h2 id=&quot;1-remise&quot;&gt;1. remise&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;Recently used in Golang development projects used excel import, export. Data export is no problem, just write excel on the line. However, importing templates has encountered some problems.&lt;/p&gt;

&lt;p&gt;Questions are as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. The data in db is defined as a string. If the field is filled with numbers, the field is a number when the data is acquired. The backend conversion is required.
2. Enumerate the type fields, fill in too difficult. Users need to know the corresponding value
3. The field range value, fill in more difficult, (such as user, type, etc.)
3  can not limit the length of the field to fill in the content
4. Cannot limit the range of numbers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Why not directly put an excel file, the data in the project is imported, the export field is not fixed, you need to import according to the personal configuration real field, export&lt;/p&gt;

&lt;h2 id=&quot;2-golang-excel-class-library-selection&quot;&gt;2. Golang EXCEL Class Library Selection&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;After the Internet search found two more use now more golang operation excel class library&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/360EntSecGroup-Skylar/excelize&quot;&gt;excelize&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tealeg/xlsx&quot;&gt;xlsx&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In most cases, xlsx is selected, and xlsx is more in star and fork than excelle. However, excelize is more active in recent activity and the document is more detailed (in Chinese)&lt;/p&gt;

&lt;h2 id=&quot;3-use-excel-data-validation&quot;&gt;3. Use EXCEL data validation&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;In the use of xlsx, there is no problem with basic functions, but when doing advanced functions, it is found that many advanced functions do not have time, and some implementations are too rude. The data verification function is not implemented at all. Originally wanted to copy excelize the code, and found that they did not achieve, still lying in the todo list. Helplessness can only be implemented on xlsx itself.&lt;/p&gt;

&lt;p&gt;Now it’s simple and crude to implement the list of excel data validation, rang validation (time, date need to be converted to numbers, now unimplemented) has confirmed that available data validation has list (display dorp box), rang (number, decimal, text length ), User input will be prompted for incorrect content.&lt;/p&gt;

&lt;p&gt;An example of a test code for data validation is at &lt;a href=&quot;https://github.com/rentiansheng/xlsx/blob/dev_master/datavalidation_test.go&quot;&gt;data validation test code&lt;/a&gt;
You can go test to view the production excel content.&lt;/p&gt;

&lt;h2 id=&quot;4-need-to-prepare-for-the-development-of-excel&quot;&gt;4. Need to prepare for the development of EXCEL&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;Excel is a zip file described by openxml.
The files in the office are all similar. Microsoft has published the document.&lt;/p&gt;

&lt;p&gt;tool:
Open xml sdk 2.0 tool, can view the openxml code of excel file, provide verification, documentation, generate code function (not golang)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Golang EXCEL 操作类库支持列，单元格新加数据验证功能(下拉列表，数字文本长度校验)</title>
   <link href="http://www.ireage.com/golang/2018/04/29/golangexceldatavalidation.html"/>
   <updated>2018-04-29T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2018/04/29/golangexceldatavalidation</id>
   <content type="html">&lt;h2 id=&quot;完成的功能&quot;&gt;完成的功能&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;单元格，列支持下拉列表选择&lt;/li&gt;
  &lt;li&gt;单元格，列支持范围校验&lt;/li&gt;
  &lt;li&gt;打开Excel支持单元格，列数据校验读取&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;需要注意的项目&quot;&gt;需要注意的项目&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Excel 数据校验支持设置校验字符的长度为255，&lt;/li&gt;
  &lt;li&gt;不支持Excel通过选择工作簿中的单元格作为校验条件&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;1-前提&quot;&gt;1. 前提&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;最近Golang开发的项目中用到excel 导入，导出。数据导出没什么问题， 直接写excel 就行了。但是导入模版遇到一些问题。&lt;/p&gt;

&lt;p&gt;问题如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. db中数据定义为字符串，字段如果用户填写都是数字，获取数据的时候，该字段就是数字，需要后端转换
2. 枚举类型字段，填写难度过大。用户需要知道对应的值
3. 字段范围值，填写比较困难，（如用户，类型等）
3. 无法限定字段填写内容的长度
4. 无法限定数字填写范围
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;为什么不直接放一个excel文件， 项目中数据导入，导出字段是不固定，需要根据个人的配置实字段来导入，导出&lt;/p&gt;

&lt;h2 id=&quot;2-golang-excel-类库选择&quot;&gt;2. Golang EXCEL 类库选择&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;经过上网查找发现两个现在使用比较多golang 操作 excel 类库&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/360EntSecGroup-Skylar/excelize&quot;&gt;excelize&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/tealeg/xlsx&quot;&gt;xlsx&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;最总，选择了xlsx, xlsx在star 和fork 比 excelle多。但是excelize最近活跃度上更活跃，文档更详细（有中文）&lt;/p&gt;

&lt;h2 id=&quot;3-使用excel-数据验证&quot;&gt;3. 使用EXCEL 数据验证&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;xlsx在使用中，基本功能没什么问题，但是在做高级功能的时候，发现很多高级功能没有时间，有的实现过于粗暴。 数据校验功能根本没有实现。本来想去copy excelize的代码，结果，发现他们也没有实现， 还在todo列表中躺着。无奈只能基于xlsx自己实现。&lt;/p&gt;

&lt;p&gt;现在简单粗暴的实现 excel 数据校验中的list，rang 验证（时间，日期 需要转换成数字，现在未实现）已经确认可用数据校验有 list（展示dorp box ），rang(数字，小数，文本长度)， 用户输入的内容不对会有提示。&lt;/p&gt;

&lt;p&gt;关于数据校验的代码的测试例子在&lt;a href=&quot;https://github.com/rentiansheng/xlsx/blob/dev_master/datavalidation_test.go&quot;&gt;数据验证test代码&lt;/a&gt;
可以go test 查看生产excel内容。&lt;/p&gt;

&lt;h2 id=&quot;4-开发excel-需要准备的&quot;&gt;4. 开发EXCEL 需要准备的&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;excel 是openxml 来描述的一个zip压缩文件。
office中的文件都是类似的。 微软已经将文档公开。&lt;/p&gt;

&lt;p&gt;工具：
open xml sdk 2.0 的工具，可以查看excel 文件的openxml代码，提供校验，文档，生成代码功能（不是golang）&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>golang 下载文件格式错误</title>
   <link href="http://www.ireage.com/golang/2018/03/16/godownfilecontenttype.html"/>
   <updated>2018-03-16T00:00:00+00:00</updated>
   <id>http://www.ireage.com/golang/2018/03/16/godownfilecontenttype</id>
   <content type="html">&lt;h3 id=&quot;场景&quot;&gt;场景&lt;/h3&gt;

&lt;p&gt;最近在使用golang做一个cmdb，系统中有大量的数据需要导出下载。
在功能开发完成后， 系统在开发和测试环境运行正常。但是部署到环境后，
在下载数据的时候，文件下载下来会变成zip或者没有后缀等两种情况。&lt;/p&gt;

&lt;h3 id=&quot;问题分析&quot;&gt;问题分析&lt;/h3&gt;

&lt;p&gt;文件下载格式不正确，首先，想到的是http response的header中的
content-type格式不对， 使用curl -v 请求后发现返回数据如下&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-curl&quot; data-lang=&quot;curl&quot;&gt;&amp;gt; POST /hosts/export HTTP/1.1
&amp;gt; Accept: */*
&amp;gt; Cache-Control: no-cache
&amp;gt; Content-Length: 246
&amp;gt; content-type: multipart/form-data; 
&amp;gt;
&amp;lt; HTTP/1.1 100 Continue
&amp;lt; HTTP/1.1 200 OK
&amp;lt; Date: Wed, 14 Mar 2018 09:49:55 GMT
&amp;lt; Content-Type: application/zip
&amp;lt; Content-Length: 7795&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;通过curl 调用确认了是content-type的问题。
看了golang关于http package的介绍没有设置mime.type的地方。
因为go语言使用的是系统的mime，不像nginx，apache有自己的mime配置文件。 
所以使用golang 的http package功能在不同系统上由于系统的mime.types
差异影响系统功能。 系统的mime.types在/etc/mime.types大家可以自由查看&lt;/p&gt;

&lt;h3 id=&quot;解决方法&quot;&gt;解决方法&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;更新系统的/etc/mime.types&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;通过代码解决&lt;/p&gt;

    &lt;p&gt;熟悉HTTP协议的同学应该知道，HTTP response header中的content-type
是可以指定下载文件的格式。
虽然相信golang作为一门优秀的语言一定会按照HTTP协议实现，
但是还是翻了下源码，
http.ServeFile -&amp;gt; serveFile-&amp;gt; serveContent&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-code&quot; data-lang=&quot;code&quot;&gt;   func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker) {
    ...... 
    ctype := w.Header().Get(&quot;Content-Type&quot;)
   	if !haveType {
   		ctype = mime.TypeByExtension(filepath.Ext(name))
   		if ctype == &quot;&quot; {
   			// read a chunk to decide between utf-8 text and binary
   			var buf [sniffLen]byte
   			n, _ := io.ReadFull(content, buf[:])
   			ctype = DetectContentType(buf[:n])
   			_, err := content.Seek(0, io.SeekStart) // rewind to output whole file
   			if err != nil {
   				Error(w, &quot;seeker can&apos;t seek&quot;, StatusInternalServerError)
   				return
   			}
   		}
   		w.Header().Set(&quot;Content-Type&quot;, ctype)
   	} else if len(ctypes) &amp;gt; 0 {
   		ctype = ctypes[0]
   	}
   
     ....
   } 

   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;http头部的设置规则&quot;&gt;HTTP头部的设置规则&lt;/h3&gt;

&lt;p&gt;Content-Type: application/vnd.ms-excel   #excel 2003-2007的格式&lt;/p&gt;

&lt;p&gt;Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet  #excel 2007以后的格式&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>服务治理</title>
   <link href="http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/11/16/servicemangger.html"/>
   <updated>2016-11-16T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/11/16/servicemangger</id>
   <content type="html">&lt;h1 id=&quot;服务治理&quot;&gt;服务治理&lt;/h1&gt;

&lt;h2 id=&quot;为什么要做服务治理&quot;&gt;为什么要做服务治理&lt;/h2&gt;

&lt;p&gt;一个系统在开发之初，功能简单，规模较小。 随着业务需求的变化和增加，
系统的功能和规模会变得庞大。&lt;/p&gt;

&lt;p&gt;将会出现以下问题：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;维护、开发、部署将变得困难&lt;/li&gt;
  &lt;li&gt;水平扩展困难&lt;/li&gt;
  &lt;li&gt;功能及技术迭代困难
（注：技术迭代指的是替换使用的语言、第三方工具等）&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;为了解决上述的问题，我们将会采取分拆系统的方法，将一个庞大的系统拆分成N个小系统。&lt;/p&gt;

&lt;p&gt;拆分会带来以下的好处：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;独立部署，方便水平扩展&lt;/li&gt;
  &lt;li&gt;系统隔离&lt;/li&gt;
  &lt;li&gt;快速的迭代（每个系统可以根据业务场景来决定使用最优的开发语言和第三方工具）&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;但是，拆分并没有从根本上解决问题，随着业务发展，我们拆分出来的N个小系统会继续添加相关的业务，
随着时间的发展也变的复杂和庞大。我们又继续使用拆分的方案， 然后拆分出来的系统又随着业务的变化和发展，
开始从简单变得复杂，我们一遍又一遍做着重复拆分的事情。&lt;/p&gt;

&lt;p&gt;解决问题的方法是：&lt;/p&gt;

&lt;p&gt;在接到开发任务之初，将任务做成一个或者多个独立的服务单元（服务单元:请看下面注释），
每个服务单元单独部署和迭代开发，禁止添加其它非必要的功能。&lt;/p&gt;

&lt;p&gt;注解：&lt;/p&gt;

&lt;p&gt;服务单元：尽可能小的服务集合，只包含对于一个抽象属性的增删改查，杜绝添加其他相关联的功能和业务。&lt;/p&gt;

&lt;p&gt;随之带来的问题是：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;独立的服务单元越来越多，如何对服务单元做管理&lt;/li&gt;
  &lt;li&gt;如何做负载均衡&lt;/li&gt;
  &lt;li&gt;如何做服务信息的修改及快速生效&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;最开始的解决方案是由OP和RD配合来做的。
通过DNS,NGINX,CONFIG文件来配合完成任务。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;DNS，NGINX都可以做负载均衡的功能。

DNS,NGINX,CONFIG都可以用来管理服务单元信息的变更
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;上述的方法，虽然可以解决问题，但是每次必须修改配置，然后重新加载配置才会生效。
无法实现立即生效，避免错误继续扩大的问题。为了解决这些问题，就要使用有效的服务治理方案。&lt;/p&gt;

&lt;h2 id=&quot;服务治理-1&quot;&gt;服务治理&lt;/h2&gt;

&lt;p&gt;服务治理主要是对服务信息进行管理的一系列的系统。为了实现这个系统，
我们需要一个高可用、低延迟的数据存储工具。&lt;/p&gt;

&lt;p&gt;经过筛选我们最终选择了zookeeper。
我们先来看下zookeeper官方的定义：&lt;/p&gt;

&lt;p&gt;ZooKeeper is a centralized service for maintaining configuration information,
 naming, providing distributed synchronization, and providing group services.&lt;/p&gt;

&lt;p&gt;使用zookeeper原因：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;公司已经有zookeeper集群，具备运维能力&lt;/li&gt;
  &lt;li&gt;zookeeper 使用范围比较广，&lt;/li&gt;
  &lt;li&gt;zookeeper watcher机制能够及时通知修改，保证信息一直&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;虽然，我们可以通过zookeeper来解决存储数据的问题，
但是服务的信息并不会自动出现在zookeeper中，我们需要开发一个关于服务治理的系统。&lt;/p&gt;

&lt;p&gt;服务治理具备功能：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;服务发现&lt;/p&gt;

    &lt;p&gt;主动注册和第三方注册两种服务发现方式，我们现在使用的是第三方注册的方式，
 因为调用方和服务方都是PHP编写的，主动注册实现复杂&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;服务管理&lt;/p&gt;

    &lt;p&gt;服务状态的统计信息、服务信息管理、授权查看，在使用第三方注册时候，提供服务注册和修改功能&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;通信&lt;/p&gt;

    &lt;p&gt;异步通信和同步通信，现在只实现同步通信&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;访问控制&lt;/p&gt;

    &lt;p&gt;限制调用方使用的key对服务方访问频次、是否具有访问权限等检查&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;数据交互协议适配&lt;/p&gt;

    &lt;p&gt;调用方不用关注服务方提供服务使用的协议。目前支持http下json、yar-msgpack相互转换&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;如何去做&quot;&gt;如何去做&lt;/h2&gt;

&lt;p&gt;到目前为止，我找到解决问题的方法和需要实现的功能的。
根据上面的信息，我们给出了具体是的设计方案。如下图所示：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/zkmanagerservice.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;整个设计共分五部分：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;调用者&lt;/p&gt;

    &lt;p&gt;通过HTTP或YAR访问Gateway， 将需要调用的服务信息和参数告诉 Gateway，&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;服务方&lt;/p&gt;

    &lt;p&gt;a) 提供服务&lt;/p&gt;

    &lt;p&gt;b) 将自己的信息通过管理平台注册到zookeeper中&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  1. 服务名、状态
  2. 地址信息、机房、权重及状态
  3. 服务下接口的列表
      a) 接口名
      b) 接口路径
      c) 输出数据的编码（json或者yar-msgpack）
      d) 状态
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Gateway&lt;/p&gt;

    &lt;p&gt;a) 请求的转发&lt;/p&gt;

    &lt;p&gt;b) 快速失败&lt;/p&gt;

    &lt;p&gt;c) 对发送的数据做编码（json或者yar-msgpack）&lt;/p&gt;

    &lt;p&gt;d) 负载均衡&lt;/p&gt;

    &lt;p&gt;e) 将服务和接口的信息缓存到内存中&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;管理平台&lt;/p&gt;

    &lt;p&gt;a) 服务及接口的注册&lt;/p&gt;

    &lt;p&gt;b) 服务及接口的查看&lt;/p&gt;

    &lt;p&gt;c) 服务及接口的修改&lt;/p&gt;

    &lt;p&gt;d) 统计信息查看&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;ZooKeeper&lt;/p&gt;

    &lt;p&gt;ZooKeeper在整个服务治理的设计中是最重要的组成部分。
在使用zookeeper之前。我们先来看下zookeeper存储数据的原理。
下面是zookeeper官方的介绍:&lt;/p&gt;

    &lt;p&gt;The name space provided by ZooKeeper is much like that of a standard file system. 
A name is a sequence of path elements separated by a slash (/). 
Every node in ZooKeeper’s name space is identified by a path.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;http://zookeeper.apache.org/doc/r3.1.1/images/zknamespace.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;zookeeper就像一个树，用每一个”/{name}”表示节点及节点名。每一个节点可以有子节点和存储少量的内容。&lt;/p&gt;

&lt;p&gt;我们在zookeeper中存储的信息有服务信息、地址信息、接口信息。具体格式如下：&lt;/p&gt;

&lt;p&gt;服务信息：/service/{服务名}&lt;/p&gt;

&lt;p&gt;地址信息：/address/{服务名}&lt;/p&gt;

&lt;p&gt;接口信息：/api/{服务名}/{接口名}&lt;/p&gt;

&lt;p&gt;为什么要将zookeeper中存储数据的结构设计为上面描述格式， 是因为zookeeper在watcher机制的处理中给出了
   两个关于wather 通知使用的API（golang zk）
   一个是关注子节点变化ChildrenW函数，另外一个是关注节点本身内容变化GetW函数。
   我们设计的方案在实现上让每个节点功watcher更加简单。
   我们现在来看一个具体的例子：假设有一个服务s，下面有A,B两个接口
&lt;img src=&quot;/img/zkstoragestructrue.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;出现的问题如何保证缓存信息和zookeeper中的内容一致&quot;&gt;出现的问题（如何保证缓存信息和zookeeper中的内容一致）&lt;/h2&gt;

&lt;p&gt;Gateway 为了做到低延迟和高可用性，在Gateway 中缓存zookeeper中的数据。
在Gateway中缓存数据的格式与zookeeper中的结构一致。
我们是如何保证缓存的信息是正确可用的,
就需要用到zookeeper的watcher机制。在zookeeper中内容中修改时，
通过watcher机制通知Gateway 来更新缓存&lt;/p&gt;

&lt;p&gt;具体的设计如下图（具体实现的流程图在最后）：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/zkwatcherdesign.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;看了设计图可能会有下列的疑问：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;为什么收到通知后不直接去更新缓存？&lt;/p&gt;

    &lt;p&gt;这个问题就需要了解zookeeper关于watcher机制的原理，zookeeper的watcher机制是一次性的，
 在收到watcher的通知后，watcher就消失了。为了避免在更新缓存时zookeeper的
 数据再次变化无法收到通知，因为这个时候watcher机制已经没有，
 zookeeper已经没有通知Gateway机制，这样缓存中的数据和zookeeper中的数据将会不一致。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;为什么致命错误需要重新初始化缓存？&lt;/p&gt;

    &lt;p&gt;下面的介绍的内容会跟开发使用的语言和zookeeper的sdk有一定的关系。&lt;/p&gt;

    &lt;p&gt;开发语言：golang   — SDK：samuel/go-zookeeper/zk&lt;/p&gt;

    &lt;p&gt;我们先来看下SDK是如何处理错误，
 个人将SDK的错误分为非致命错误和致命错误错误两种（个人观点）。&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 非致命错误：ErrNoAuth、ErrAPIError、ErrAuthFailed等

 致命错误：ErrSessionMoved、ErrSessionExpired等
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;非致命错误是与zookeeper集群通信时，使用的参数及上下文环境出现问题返回的错误，
 影响范围只有本次调用。&lt;/p&gt;

    &lt;p&gt;致命错误通常是与zookeeper集群的通信出现网络故障，影响与zookeeper集群的所有通信。
 但是SDK(go-zookeeper)并不会在问题出现时刻立即报错，
 SDK会自动尝试建立新的可以使用的session，
 SDK在session建立成功后将给所有的watcher发送一个错误通知。&lt;/p&gt;

    &lt;p&gt;ErrSessionMoved: 是与zookeeper集群的某个实例session失效后，
 下次与zookeeper成功建立session发送给所有watcher。&lt;/p&gt;

    &lt;p&gt;ErrSessionExpired:是与整个zookeeper集群session失效后，
 下次与zookeeper成功建立session发送给所有watcher。&lt;/p&gt;

    &lt;p&gt;收到致命错误后，我们无法知道在于zookeeper集群session断开的时间段中，
 zookeeper中的数据数据变化情况。如果只是更新和新加，
 我们可以在初始化的时候将节点的内容缓存即可，
 但是如果有删除的话。我们就需要遍历所有的缓存内容来删除不需要的缓存。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;具体实现的流程图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/zkwatcherprocess.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>服务治理之zookeeper使用中遇到的问题及设计</title>
   <link href="http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/11/08/service_zookeeper.html"/>
   <updated>2016-11-08T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/11/08/service_zookeeper</id>
   <content type="html">&lt;h1 id=&quot;如何规划需要管理配置&quot;&gt;如何规划需要管理配置&lt;/h1&gt;

&lt;p&gt;根据需求将所有的信息分成四类&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 分类

    /classify下每个节点是一个分类名，内容是分类描述，分类属于辅助信息，没有太大意义。

    eg: /classify/c1  分类名c1, /classify/c1节点内容为c1的描述

2. 服务信息

    /service下每个节点都是一个服务

    eg: /service/srv1  服务名为srv1，/service/c1节点内容服务srv1具体内容

3. 服务地址

    /address 下每个节点都是一个服务

    eg: /service/srv1  服务名为srv1，/service/c1节点内容服务srv1具体内容

4. 服务下的API

    /api下每一个节点是一个服务，服务下节点是API的命名的节点

    eg: /api/srv1/api1   /api/srv1下的子节点是srv1服务下的所有API，/api/srv1/api1  服务srv1下api1的内容
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;问题&quot;&gt;问题&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. zk reconnect后授权问题

2. zk session 过期

3. zk reconnect 数据同步的问题

2. watcher 消失后修改的问题
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;功能设计&quot;&gt;功能设计&lt;/h1&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;模块&lt;/th&gt;
      &lt;th&gt;功能&lt;/th&gt;
      &lt;th&gt; &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;zk&lt;/td&gt;
      &lt;td&gt;1.管理节点&lt;br /&gt; 2.内容节点&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;watcher&lt;/td&gt;
      &lt;td&gt;1.关注子节点变化&lt;br /&gt; 2.关注本身变化&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;queue&lt;/td&gt;
      &lt;td&gt;1.处理错误&lt;br /&gt; 2.重新初始化监控&lt;br /&gt; 3.初始化缓存&lt;br /&gt; 4.通知cache变更&lt;/td&gt;
      &lt;td&gt; &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;cache&lt;/td&gt;
      &lt;td&gt;1.根据类型更新缓存&lt;/td&gt;
      &lt;td&gt;所有缓存相关的操作&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1 id=&quot;好处&quot;&gt;好处&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 各模块职责单一

2. 统一的错误处理

3. 收敛缓存处理逻辑

4. 方便扩展
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;解决问题方法&quot;&gt;解决问题方法&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;zk reconnect后授权问题&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;zk session 过期&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;zk reconnect 数据同步的问题&lt;/p&gt;

    &lt;p&gt;问题1、2、3 在queue模块中添加统一的错误处理逻辑&lt;/p&gt;

    &lt;ol&gt;
      &lt;li&gt;
        &lt;p&gt;添加授权信息&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;关闭原有的watcher&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;初始化watcher进程&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;watcher 消失后修改的问题&lt;/p&gt;

    &lt;p&gt;通过设计queue和cache模块，分开实现，延时获取数据的。&lt;/p&gt;

    &lt;p&gt;具体流程，见下图&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;http://7xi8r0.com1.z0.glb.clouddn.com/watcher_note.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>服务治理之服务管理</title>
   <link href="http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/11/07/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E4%B9%8B%E6%9C%8D%E5%8A%A1%E7%AE%A1%E7%90%86.html"/>
   <updated>2016-11-07T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/11/07/服务治理之服务管理</id>
   <content type="html">&lt;h2 id=&quot;如何管理服务&quot;&gt;如何管理服务&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;需要考虑的问题：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;* 1. 服务信息注册

* 2. 如何保证服务信息一致
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;服务信息是服务发现很重要的部分，它是包含服务提供者的地址信息和提供服务的接口。
服务信息需要高可用而且随时更新。gateway可以缓存从服务信息。
然而，这些信息最终会变得过时，客户端也无法发现服务实例。
因此，服务信息必须保证是一个一个分布式可用。&lt;/p&gt;

&lt;h6 id=&quot;目前可以使用的组件有&quot;&gt;目前可以使用的组件有：&lt;/h6&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;etcd

consul

zookeeper

Kubernetes

eureka
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;最后，根据公司运维等方面考虑选择使用zookeeper&lt;/p&gt;

&lt;h2 id=&quot;主要实现功能&quot;&gt;主要实现功能&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 服务发现

   主动注册和被动注册，我使用的是被动注册，因为调用方和服务方都是PHP，主动注册不方便

2. 服务管理

  由于是被动注册，需要提供一个注册平台，主要提服务注册、授权、地址等信息管理

3. 通信

   异步通信和同步通信，现在只实现同步通信

4. 访问控制

   限制调用放key对服务方QPS、接口、有效时长

5. 数据交换编码

    目前支持http下json、yar-msgpack相互转换
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;基于zookeeper服务管理的实现&quot;&gt;基于zookeeper服务管理的实现&lt;/h2&gt;
&lt;hr /&gt;

&lt;p&gt;&lt;img src=&quot;/img/zkmanagerservice.png&quot; alt=&quot;基于zookeeper服务管理的实现图&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>服务治理之开发环境配置解决</title>
   <link href="http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/10/06/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E4%B9%8B%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE.html"/>
   <updated>2016-10-06T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86/2016/10/06/服务治理之开发环境配置</id>
   <content type="html">&lt;h3 id=&quot;出现的问题&quot;&gt;出现的问题&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;新搭建的开发环境如何快速使用&lt;/li&gt;
  &lt;li&gt;如何解决开发中路由问题（同一个服务或者接口不同调用者调用不同服务方）&lt;/li&gt;
  &lt;li&gt;如何解决开发中使用host的问题&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;为什么测试环境和生产环境没有问题&quot;&gt;为什么测试环境和生产环境没有问题&lt;/h3&gt;

&lt;p&gt;测试和生产环境在服务和接口的环境调用比较简单，都是一一对应的。
在使用的过程中，服务治理这不需要关注调用者身份，只需根据服务中配置的
地址信息，选择一个可用的服务者来转发这个请求即可。&lt;/p&gt;

&lt;p&gt;但是在开发环境中，服务和接口调用者关系比较复杂。我将调用者分成两种类型，
直接调用者和间接调用者。间接调用者的需求是最简单的，这个服务或者接口
我不需要关心，只要能返回结果。 直接调用者需求是最复杂的，直接调用者有非常
明确的服务提供者，有可能是整个服务下的接口，也有可能是服务下摸个接口。&lt;/p&gt;

&lt;h3 id=&quot;没有服务治理之前怎么解决&quot;&gt;没有服务治理之前怎么解决&lt;/h3&gt;

&lt;h6 id=&quot;使用服务治理前&quot;&gt;使用服务治理前&lt;/h6&gt;

&lt;p&gt;调用者和服务方是直接通信的，所有环境的配置都是在代码配置文件中，调用者可以
直接指定服务方地址。可以同修改配置文件和/etc/hosts文件来决定服务方&lt;/p&gt;

&lt;h6 id=&quot;使用服务治后&quot;&gt;使用服务治后&lt;/h6&gt;

&lt;p&gt;调用者和服务方是间接通信的， 服务治理做为中间方。调用者和服务方直接通信都是
服务治理的提供者。修改本地配置失效。&lt;/p&gt;

&lt;h3 id=&quot;解决方法&quot;&gt;解决方法&lt;/h3&gt;

&lt;p&gt;服务治理只在服务信息和接口信息中新加路由表&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;调用者&lt;/th&gt;
      &lt;th&gt;调用者IP&lt;/th&gt;
      &lt;th&gt;服务者&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;测试ip1&lt;/td&gt;
      &lt;td&gt;127.0.0.1&lt;/td&gt;
      &lt;td&gt;http://apiv1.ireage.com&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;测试ip2&lt;/td&gt;
      &lt;td&gt;127.0.0.2&lt;/td&gt;
      &lt;td&gt;http://apiv2.ireage.com&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;在服务信息中新加域名信息domain: http://api.ireage.com&lt;/p&gt;

&lt;h6 id=&quot;1-新搭建的开发环境如何快速使用&quot;&gt;1. 新搭建的开发环境如何快速使用&lt;/h6&gt;
&lt;p&gt;每一个服务需要一个默认可以使用的地址&lt;/p&gt;

&lt;h6 id=&quot;2-如何解决开发中路由问题同一个服务或者接口不同调用者调用不同服务方&quot;&gt;2. 如何解决开发中路由问题（同一个服务或者接口不同调用者调用不同服务方）&lt;/h6&gt;
&lt;p&gt;服务和接口分别有host的配置，通过调者IP地址来决定服务方的地址&lt;/p&gt;

&lt;h6 id=&quot;3-如何解决开发中使用host的问题&quot;&gt;3. 如何解决开发中使用host的问题&lt;/h6&gt;

&lt;p&gt;为服务配置一个域名，在http的头部添加host即可。&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>react</title>
   <link href="http://www.ireage.com/react/2016/09/27/reacterr.html"/>
   <updated>2016-09-27T00:00:00+00:00</updated>
   <id>http://www.ireage.com/react/2016/09/27/reacterr</id>
   <content type="html">&lt;h3 id=&quot;同一个commpont多次使用出现的错误&quot;&gt;同一个commpont多次使用出现的错误&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;错误提示如下：
 Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component&apos;s `render` method, or you have multiple copies of React loaded

 解决方法如下
 npm uninstall react react-dom
 npm install react react-dom --save
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;setstate有延时&quot;&gt;setState有延时&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;this.setState(params:{page:2});
随后使用fetch将this.state.params作为参数获取数据的时候，竟然是之前的数据
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;同一组件在url参数改变时未重新加载数据&quot;&gt;同一组件，在URL参数改变时，未重新加载数据&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;使用组件componentWillReceiveProps事件即可。
componentWillMount和componentDidMount只有在组件切换时执行，同一组件在不同参数下不会触发。
例如：http::/ireage.com/test#/list/1 变为 http::/ireage.com/test#/list/2 不触发componentWillMount和componentDidMount事件。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>PHP VS GO</title>
   <link href="http://www.ireage.com/%E6%9D%82%E8%B0%88/2016/08/30/phpvsgo.html"/>
   <updated>2016-08-30T00:00:00+00:00</updated>
   <id>http://www.ireage.com/%E6%9D%82%E8%B0%88/2016/08/30/phpvsgo</id>
   <content type="html">&lt;h4 id=&quot;整体印象&quot;&gt;整体印象&lt;/h4&gt;
&lt;p&gt;PHP：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 不用编译，写完代码就可以直接看
2. 只要本次执行的代码没有fatal就可以执行，即使优点也是缺点。
3. 弱类型超牛B，一个变量随便用，不用声明，数组随意递归没有格式限制。 即使优点也是缺点
4. 特别讨厌$，
5. 强大string，array操作
6. 成熟访问权限控制public,private,protected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;GO：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 每次写完都需要编译。 需要检查整个项目编译，整个项目没有错误。
2. 严格的格式，强类型。 变量定义必须使用，代码格式etc
3. 简介的格式
4. 强大的协程
5. 完善的网络库
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;语法相关&quot;&gt;语法相关&lt;/h4&gt;
&lt;p&gt;PHP：&lt;/p&gt;

&lt;p&gt;觉得自己不是一个合格PHPer,使用两年多了，竟然总结不出来。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 自由灵活，变量，命名，语法灵活
2. 入门简单
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;GO:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 访问权限，通过大小写控制，小写内部函数，大写外部函数。（刚开始特别坑，让我一个经常使用驼峰命名的人很不习惯）
2. defer个人感觉超级好用，可以用来做释放资源，后期处理。
3. 变量，类型超级丰富，觉得虽然和接触的语言都不一样，但是感觉超级习惯，var xxx type
4. 函数定义，丰富的数据传递参数，个人理解一个最完整 func (共有数据) 函数名(函数私有数据)（返回数据），
5. 没有类，但是可以使用struct 和 interface 来完成。interface在GO里面很重要的
6. channel，协程为并发而生。
7. 把异步搞的和同步一样
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;适用场景&quot;&gt;适用场景&lt;/h4&gt;

&lt;p&gt;PHP:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. WEB开发
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;GO:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 1. WEB开发
 2. 服务开发
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;题外话&quot;&gt;题外话&lt;/h4&gt;

&lt;h6 id=&quot;进程线程协程&quot;&gt;进程、线程、协程&lt;/h6&gt;
&lt;p&gt;进程和线程比较常见，操作系统课上都讲过，协程虽然没有讲过，如果知道nginx原理相信会觉得似曾相识
其实可以从调度、并发性、系统开销、拥有资源等发面作比较&lt;/p&gt;

&lt;p&gt;进程：&lt;/p&gt;

&lt;p&gt;进程被称为重量级别进程（HWP）。进程也可看做一个线程的集合，在我看来进程管理者是操作系统
进程的调度是有OS来调度和管理。所以进程的调度，并发，系统开销、资源拥有都是系统层面。&lt;/p&gt;

&lt;p&gt;线程：&lt;/p&gt;

&lt;p&gt;线程被称为轻量级别的进程（LWP）是CPU调度和分配的基本单元。在我看来线程是一个CPU执行的实例。是一个进程获取到执行时内部调度，并发。&lt;/p&gt;

&lt;p&gt;进程和线程intel网站上有一份超级详细和全面的资料。&lt;a href=&quot;https://software.intel.com/sites/default/files/m/5/7/f/a/b/12568-2.1.1_e7_ba_bf_e7_a8_8b_e4_b8_8e_e8_bf_9b_e7_a8_8b_e7_9a_84_e5_8c_ba_e5_88_ab.pdf&quot;&gt;process vs threads.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;协程:
协程是一个不能被操作系统和CPU调度的玩意，全靠语言本身来控制。不关是进程，线程调度的时候都要进行上下文切换， 协程这玩意不涉及系统和CPU的上下文切换，协程个人感觉是就是异步和内存切换。
附带一篇不错协程介绍&lt;a href=&quot;http://blog.imisko.com/2017/08/02/golang-coroutine/&quot;&gt;Golang协程之殇&lt;/a&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>c pointer</title>
   <link href="http://www.ireage.com/c/2016/08/21/cpointer.html"/>
   <updated>2016-08-21T00:00:00+00:00</updated>
   <id>http://www.ireage.com/c/2016/08/21/cpointer</id>
   <content type="html">&lt;h3 id=&quot;指针相关&quot;&gt;指针相关&lt;/h3&gt;
&lt;hr /&gt;

&lt;h4 id=&quot;1-glibc-detected--19-munmap_chunk-invalid-pointer-0x00007ffff5cc97b0-&quot;&gt;1.&lt;em&gt;** glibc detected **&lt;/em&gt; ./19: munmap_chunk(): invalid pointer: 0x00007ffff5cc97b0 ***&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; a) free释放内存出现，注意free只能释放malloc分配的内存，在function中看到是指针，这个指针有可能是定义的数组，无法释放
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;2-二维数组和指针的指针区别-type-与-type-&quot;&gt;2. 二维数组和指针的指针区别( type [][]与 type **)&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  虽然两种方式在使用的时候访问方式是通用的，差异主要在内存组织

  二维数组是一个连续的区域，如char a[2][3] 实际上是一个连续的sizeof(char)*2*3的内存区域。在变量定义时候已经确立整数组存储数据集合容纳数据大小，
  并且没一行数据的个数必须一样，无法扩容;


  指针指针是是通过先分配type * 来存储二维数组中一维，然后在分配type 来维持二维数组二维。存储数据集合和动态调整，没一行的个数可以不同。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;eg:内存组织图，type标识数据类型&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/arrayandpointerpointer.png&quot; alt=&quot;内存组织图&quot; /&gt;&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>iterm2 快捷键</title>
   <link href="http://www.ireage.com/iterm2/2016/08/11/iterm2keys.html"/>
   <updated>2016-08-11T00:00:00+00:00</updated>
   <id>http://www.ireage.com/iterm2/2016/08/11/iterm2keys</id>
   <content type="html">&lt;p&gt;最近买了一个键盘，操作触控就不方便了，只能在键盘下功夫了。&lt;/p&gt;

&lt;p&gt;本人系统shell是zsh&lt;/p&gt;

&lt;h4 id=&quot;光标操作&quot;&gt;&lt;strong&gt;光标操作&lt;/strong&gt;&lt;/h4&gt;
&lt;hr /&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ctrl + a: 到行首

ctrl + e: 行末

ctrl + f/b: 前进后退，相当于左右方向键。

ctrl + p: 上一条命令，相当于方向键上

ctrl + r: 搜索命令历史，这个大家都应该很熟悉了

ctrl + d: 删除当前字符

ctrl + h: 删除之前的字符

ctrl + w: 删除光标前的单词

ctrl + k: 删除到文本末尾

ctrl + t: 交换光标处文本

ctrl + u: 删除一行

command + —/+/0: +字体变大，-字体变小， 0 恢复到默认值，如果分屏了只调整活动窗口字体大小

command + r:清屏，其实是滚到新的一屏，并没有清空。ctrl + l 也可以做到。对 ⌘ + f没有影响
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;窗口操作&quot;&gt;&lt;strong&gt;窗口操作&lt;/strong&gt;&lt;/h3&gt;
&lt;hr /&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;shift + command + d: 水平拆分窗口

shift + d: 垂直拆分窗口

command + shift + w: 关闭当前活动终端窗口

command + `/~ : 前一个/后一个窗口, 这里的窗口不是tab页面，而是通过new window打开的多个终端窗口

command + t: 在活动终端新建一个tab标签

command + w: 关闭当前tab窗口

command + option + 上下左右: 在当前活动的tab标签切换到上/下/左/右面板，面板指的是水平/垂直拆分的窗口

command + enter: 进去/退出全屏木事

Command + u: 开启/关闭背景透明

shift + command + [/]: 前一个/后一个标签页

command + option + +: 进入/退出铺满屏幕

 command + ctrl+ 上/下/左/右 : 调整当前分屏边框大小，
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;其他&quot;&gt;&lt;strong&gt;其他&lt;/strong&gt;&lt;/h4&gt;
&lt;hr /&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;command + shift + m: 新建书签

command + shift + j: 回到最后一次简历书签的位置


command + shift + h: 展示粘贴历史，支持模糊检索

command + option + b: 打开即使回放

command + /: 显示光标的位置
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>json_decode解析失败</title>
   <link href="http://www.ireage.com/php/2016/02/24/json_decode.html"/>
   <updated>2016-02-24T00:00:00+00:00</updated>
   <id>http://www.ireage.com/php/2016/02/24/json_decode</id>
   <content type="html">&lt;p&gt;最近，一直在使用的系统突然出现一个奇怪的问题。一个商户信息总是没法展示的，两个系统采用json做的数据交换，
线上日志记录到模块是接受导数据，但是在后面的日志中，发现数据为空。经过在线上加log发现json_decode失败的返回值为NULL。
随后把log中的日志拿出来，json_decode没有问题的。&lt;/p&gt;

&lt;p&gt;首先想到的问题是：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;json格式的问题&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;内存限制&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;编码问题&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;上面的问题，很容就可以检查结果了。到底是不是这些原因的。不幸的事情发生了。这些都不是的，太奇葩了。&lt;/p&gt;

&lt;p&gt;虽有用json_decode解码失败搜索发现，有人说是因为json串有\t等特殊字符的问题的（之所以copy后解析成功，是因为不同的编辑器和编码格式会对特殊字符做处理）。&lt;/p&gt;

&lt;p&gt;在不同的终端下查看数据，发现数据中有特符符号。但是并不是\t,而是编码格式为\u0014\u0017数据。最好建议大家不要对数据进行解码查看，要看查看最原始的数据。因为不同的编码会对特殊符号做处理，在不同的编码下，特殊符号可能会显示为空白，不显示，显示为不同的符号等。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>php extensions(二) phpinfo输出内容</title>
   <link href="http://www.ireage.com/php%20extension/c/%E5%BC%80%E6%BA%90/2015/04/18/php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0(%E4%BA%8C)phpinfo%E6%B7%BB%E5%8A%A0%E4%BF%A1%E6%81%AF.html"/>
   <updated>2015-04-18T00:00:00+00:00</updated>
   <id>http://www.ireage.com/php%20extension/c/%E5%BC%80%E6%BA%90/2015/04/18/php扩展开发学习(二)phpinfo添加信息</id>
   <content type="html">&lt;h3 id=&quot;php-extensions二--phpinfo输出内容&quot;&gt;php extensions(二)  phpinfo输出内容&lt;/h3&gt;

&lt;h4 id=&quot;引言&quot;&gt;引言&lt;/h4&gt;

&lt;p&gt;我们在使用一个PHP扩展的时候，首先，将编译后的扩展放到PHP的扩展加载目录下，使用phpinfo函数来查看插件是否已经加载。&lt;/p&gt;

&lt;h4 id=&quot;代码实现&quot;&gt;代码实现&lt;/h4&gt;

&lt;p&gt;在phpinfo函数添加内容特别简单的。
   1.首先修改module entry&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;         &lt;span class=&quot;n&quot;&gt;zend_module_entry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reage_module_entry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
             &lt;span class=&quot;no&quot;&gt;STANDARD_MODULE_HEADER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
             &lt;span class=&quot;s2&quot;&gt;&quot;reage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//扩展的名字&lt;/span&gt;
             &lt;span class=&quot;kc&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// functions&lt;/span&gt;
             &lt;span class=&quot;kc&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// minit&lt;/span&gt;
             &lt;span class=&quot;kc&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//mshutdown&lt;/span&gt;
             &lt;span class=&quot;kc&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//rinit&lt;/span&gt;
             &lt;span class=&quot;kc&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//rshutdown&lt;/span&gt;
             &lt;span class=&quot;nf&quot;&gt;PHP_MINFO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reage_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//注册在phpinfo函数中输出内容的函数,reage_info&lt;/span&gt;
             &lt;span class=&quot;s2&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//版本号&lt;/span&gt;
             &lt;span class=&quot;no&quot;&gt;STANDARD_MODULE_PROPERTIES&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;2.输出内容函数的实现&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;        &lt;span class=&quot;nf&quot;&gt;PHP_MINFO_FUNCTION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reage_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
           &lt;span class=&quot;nf&quot;&gt;php_info_print_table_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
           &lt;span class=&quot;nf&quot;&gt;php_info_print_table_header&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;key&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
           &lt;span class=&quot;nf&quot;&gt;php_info_print_table_row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Reage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
           &lt;span class=&quot;nf&quot;&gt;php_info_print_table_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
   &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h4 id=&quot;使用到的函数&quot;&gt;使用到的函数&lt;/h4&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;php_info_print_table_start();
php_info_print_table_header();
php_info_print_table_row();
php_info_print_table_end();

除了这些函数，还有很多函数，需要的话请自行查阅
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;####  源代码&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/php-extension-learn/tree/master/learn2(phpinfo)&quot;&gt;https://github.com/rentiansheng/php-extension-learn/tree/master/learn2(phpinfo)&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;特别说明&quot;&gt;特别说明&lt;/h4&gt;

&lt;p&gt;在搜索资料时，发现一个写的特别好的php扩展开发系列文章，希望对大家有用&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.walu.cc/phpbook/index.md&quot;&gt;PHP扩展开发及内核应用&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>php extensions(-) 代码目录结构</title>
   <link href="http://www.ireage.com/php%20extension/c/%E5%BC%80%E6%BA%90/2015/04/08/php%E6%89%A9%E5%B1%95%E5%BC%80%E5%8F%91%E5%AD%A6%E4%B9%A0(-).html"/>
   <updated>2015-04-08T00:00:00+00:00</updated>
   <id>http://www.ireage.com/php%20extension/c/%E5%BC%80%E6%BA%90/2015/04/08/php扩展开发学习(-)</id>
   <content type="html">&lt;h3 id=&quot;php-extensions--代码目录结构&quot;&gt;php extensions(-) 代码目录结构&lt;/h3&gt;

&lt;h4 id=&quot;引言&quot;&gt;引言&lt;/h4&gt;
&lt;p&gt;每一个php extension的目录中最少要包含config.m4、config.w32、php_extension.h、extension.c。php_extension.h和extension.c文件是以后编写php extension主要用到文件，这里就不介绍了。下面我们开一个叫reage的php extension。&lt;/p&gt;

&lt;h4 id=&quot;1-扩展的配置文件configm4和configw32&quot;&gt;1. 扩展的配置文件config.m4和config.w32&lt;/h4&gt;

&lt;p&gt;config.m4用户Unix、Linux等系统。config.m4文件告诉 UNIX 构建系统哪些扩展 configure 选项是支持的，你需要哪些扩展库，以及哪些源文件要编译成它的一部分。&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  config.m4配置函数PHP_ARG_WITH()和 PHP_ARG_ENABLE()的区别在于编译的时候使用 --with-* 选项还是 --enable-* 。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;http://php.net/manual/zh/internals2.structure.files.php&quot;&gt;关于配置文件的详细内容&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;下面是我的一个例子&lt;/p&gt;

&lt;p&gt;dnl在config.m4是注释的意思&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;nf&quot;&gt;PHP_ARG_WITH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;support&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Make&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sure&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aligned&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt;             &lt;span class=&quot;k&quot;&gt;Include&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;support&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;dnl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;检测扩展是否已启用&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$PHP_REAGE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;no&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;PHP_SUBST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;REAGE_SHARED_LIBADD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;PHP_NEW_EXTENSION&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$ext_shared&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;config.w32 是windows下的扩展的配置文件的，&lt;a href=&quot;http://php.net/manual/zh/internals2.structure.files.php&quot;&gt;具体使用查看&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;####2. php_reage.h&lt;/p&gt;

&lt;p&gt;php_reage.h其实不是必须的，但是一般的都C语言项目都是包含.h和.c文件的。为了让代码看起来更加的正规，我们也使用.h文件。.h文件一般只包含函数的定义、结构体的定义。&lt;/p&gt;

&lt;p&gt;下面是我的一个例子：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#ifndef REAGE_H
#define REAGE_H
&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;php.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#define phpext_reage_ptr &amp;amp;reage_module_entry;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;zend_module_entry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reage_module_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;####3. reage.c
reage.c是具体的代码文件的。
下面是我的一个例子：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-c&quot; data-lang=&quot;c&quot;&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;php_reage.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;ext/standard/info.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//加载config.h,如果有配置项&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#ifdef HAVE_CONFIG_H
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&quot;config.h&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#endif
&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//module entry&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;zend_module_entry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reage_module_entry&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;STANDARD_MODULE_HEADER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;reage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;//扩展的名字&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// functions&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// minit&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//mshutdown&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//rinit&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//rshutdown&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&quot;0.0.1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//版本号&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;STANDARD_MODULE_PROPERTIES&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;#ifdef COMPILE_DL_REAGE
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ZEND_GET_MODULE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;####4. 编译php extension
   在php extension的目录下，执行一下命名:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   1. phpize
   2. ./configure
   3. make
   4. make test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;####5. test 
    将modules/reage.so 拷贝到你php的extension路径中。不知道路径的话，看下phpinfo()中extension_dir的值就可以了。然后修改php.ini添加extension=reage.so。如果没有问题，在phpinfo()中会现实reage及其版本。&lt;/p&gt;

&lt;p&gt;####6. ext_skel
  ext_skel工具是专门用来生成php extension 目录结构的。ext_skel在php源码下的ext目录下。
  使用ext_skel工具生成目录结构后，需要修改config.m4中大约10-20行，是关于PHP_ARG_WITH和PHP_ARG_ENABLE的。根据自己的需要将前面的注释符号（dnl）去掉&lt;/p&gt;

&lt;p&gt;####7. 源代码
&lt;a href=&quot;https://github.com/rentiansheng/php-extension-learn/tree/master/learn1&quot;&gt;https://github.com/rentiansheng/php-extension-learn/tree/master/learn1&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>mysql 优化基础知识（-）</title>
   <link href="http://www.ireage.com/mysql/2015/03/30/mysql%E4%BC%98%E5%8C%96%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86(-).html"/>
   <updated>2015-03-30T00:00:00+00:00</updated>
   <id>http://www.ireage.com/mysql/2015/03/30/mysql优化基础知识(-)</id>
   <content type="html">&lt;h4 id=&quot;1-primary-key&quot;&gt;1. primary key&lt;/h4&gt;
&lt;p&gt;primary key是聚簇索引，聚簇索引适用I/O密集型的应用，由于底层存储及实现的原因，聚簇索引严重依赖顺序存储，聚簇索引列更新代价比较高，聚簇索引列在尾部以外插入新的row代价比较高的
  综上所述，在使用primary key列一般都是用int类型auto_increment，这样保证所有的值都是顺序插入的，auto_increment在高并发的应用下肯定会有争用问题。
  主键的优点在于不管表中有多少行数据。通过primary key获取数据都非常快&lt;/p&gt;

&lt;h4 id=&quot;2索引在存储时都是正序存储&quot;&gt;2.索引在存储时都是正序存储&lt;/h4&gt;
&lt;p&gt;因此，就算建立 index idx_score_course(score,course) 索引，使用explain “select * from test order by score desc, course asc”你就会发现并没有到idx_score_course索引，在Extra用的是Using filesort&lt;/p&gt;

&lt;h4 id=&quot;3-where-in&quot;&gt;3. where in&lt;/h4&gt;
&lt;p&gt;mysql中的where in与or是不同的，mysql不回将where in转换成or，mysql会对where in的条件进行排序，然后做二分查找，这是一个时间复杂度为o(log n)的操作，等价转换成or的查询时间复杂度为o(n)&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>codeigniter rabbitmq lirary</title>
   <link href="http://www.ireage.com/php/2014/11/28/codeigniter-rabbitmq-library.html"/>
   <updated>2014-11-28T00:00:00+00:00</updated>
   <id>http://www.ireage.com/php/2014/11/28/codeigniter rabbitmq library</id>
   <content type="html">&lt;p&gt;简介
&lt;strong&gt;__&lt;/strong&gt;&lt;strong&gt;__&lt;/strong&gt;&lt;strong&gt;__&lt;/strong&gt;_&lt;/p&gt;

&lt;p&gt;针对CI 封装的一个简单的rabbitmq，只有基本功能的&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng//ci-rabbitmq&quot;&gt;项目地址：https://github.com/rentiansheng//ci-rabbitmq&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;代码结构&quot;&gt;代码结构&lt;/h2&gt;
&lt;p&gt;1.文件介绍&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  1.src/src/libraries/rabbitmq.php  rabbitmq操作代码
  2.src/src/config/rabbitmq.php     rabbitmq配置文件
  3.src/src/models/rabbitmqmodel.php   consume回调函数代码
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.将需要的PHP代码文件放到制定位置&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  1. cp src/src/libraries/rabbitmq.php   项目代码/application/libraries/
  2. cp src/src/config/rabbitmq.php   项目代码/application/config/
  3. cp src/src/models/rabbitmqmodel.php   项目代码/application/models/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;函数&quot;&gt;函数&lt;/h2&gt;

&lt;p&gt;1.queue  declare一个queue&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   参数
       name 队列的名字
       durable queue是否持久化，true，是，false 否 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;2.sendMsg 向队列中add内容&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    参数
        msg 消息的内容
        exchangeName 发送消息使用的exchangeName
        queueName 接受消息的queue
        durable   queueName队列是否持久话，要与declare queue保持一直，负责回出错的
        exchangeType exchage type 我一般用直接写入，
                      你可以选择一下模式， AMQP_EX_TYPE_DIRECT,
                      AMQP_EX_TYPE_FANOUT,
                      AMQP_EX_TYPE_HEADER or AMQP_EX_TYPE_TOPIC
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;3.getMsg 获取消息&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   参数 
        queueName 获取内容的queue的name
        autoack   是否自动ack，autoack ＝ true，消息将从队列删除，
                  autoack ＝ false；时，需要用ack或者nack来回应给rabbitmq，否则，队列将无法工作
        durable   queueName队列是否持久话，要与declare queue保持一直，负责回出错的
    备注
        从队列中的下一个可用的消息。如果没有消息存在于队列中，该函数将立即返回FALSE，
        这种方式比较消耗CPU,不建议使用的。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;4.consume 获取消息，推荐&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    参数
        queueName 获取内容的queue的name
        callback  回调函数的名字，注意这个是函数名字的，对应名字的函数必须在models/rabbitmqmodel.php中实现的
        autoack   是否自动ack，autoack ＝ true，消息将从队列删除，
                  autoack ＝ false；时，需要用ack或者nack来回应给rabbitmq，否则，队列将无法工作
        durable   queueName队列是否持久话，要与declare queue保持一直，负责回出错的
    备注
        callback回调函数的名字，注意这个是函数名字的，对应名字的函数必须在models/rabbitmqmodel.php中实现的
        回调函数将会有两个参数，
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;5.consume回调函数格式&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
   function test(envelope, $queue) {}
    参数
       envelope  与消息相关的对象，具体的查看&amp;lt;a href=&quot;http://php.net/manual/pl/class.amqpenvelope.php&quot;&amp;gt;http://php.net/manual/pl/class.amqpenvelope.php&amp;lt;/a&amp;gt;
       queue  queue的对象
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;demo-目录下是示例代码&quot;&gt;demo 目录下是示例代码&lt;/h2&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1. 将demo/controllers/taskqueue.php 项目代码/application/controllers/taskqueue.php
2.  运行例子，最好可以terminal运行,首先转到项目文件所在的路径
    已发送消息作为例子
    sudo [可选择加上php env]  php所在位置 index.php taskqueue   sendMsg 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;我遇到的问题&quot;&gt;我遇到的问题&lt;/h2&gt;
&lt;p&gt;1.在执行一段时间后无法从redis获取内容&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    我使用的是ci的cache库操作redis，由于cache 初始化是在controller开始的位置，时间久了，会自动断开链接请注意。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;2.请不要在浏览器中运行consume， php-fpm有可会出现问题，&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>览器桌面通知（notifications）</title>
   <link href="http://www.ireage.com/js/2014/05/28/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%A1%8C%E9%9D%A2%E9%80%9A%E7%9F%A5-notifications.html"/>
   <updated>2014-05-28T00:00:00+00:00</updated>
   <id>http://www.ireage.com/js/2014/05/28/浏览器桌面通知（notifications）</id>
   <content type="html">&lt;h1 id=&quot;chrome-浏览器桌面通知&quot;&gt;chrome 浏览器桌面通知&lt;/h1&gt;

&lt;p&gt;最近在做公司后台管理系统，当有任务到来时，需要通知当事人，但是，当事人有可能在做别的事情，更糟糕的是浏览器有可能会被最小化，
这样就很难看到通知了。经过查找发现有些浏览器可以使用noitfications，
可以在桌面的通知区域内显示一个提示框，并且显示在桌面的最前面，很方便就能看到了。我就将它简单的封装一下，使其符合常用的使用场景。
功能效果类似webQQ的消息提示通知。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/rentiansheng/notification&quot;&gt;项目地址：https://github.com/rentiansheng/notification&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;

&lt;p&gt;用于其余B/S下的网络办公提醒功能。
页面最小化的状态下发送通知
依然显示在屏幕的右下角，马上可以看到内容&lt;/p&gt;

&lt;h2 id=&quot;依赖&quot;&gt;依赖&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;PC chrome浏览器。&lt;/li&gt;
  &lt;li&gt;手机android 海豚浏览器&lt;/li&gt;
  &lt;li&gt;firefox 可用但是智能展示一个通知（不建议使用，不同版本存在差异）&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;注意事项&quot;&gt;注意事项&lt;/h2&gt;

&lt;p&gt;通知权限是基于网站（或者域名），同一个网站下面的页面只需要获取一次权限即可。
如果别禁用了。将不会显示通知的，也无法再次获取权限了。
可以同浏览器的菜单查看权限。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-HTML&quot;&gt;设置-》隐私设选下面的 “内容设置”-》通知
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果你关闭或者刷新页面了。之前的通知就没法控制了 。&lt;/p&gt;

&lt;h2 id=&quot;使用&quot;&gt;使用&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;引用notify.js文件&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &amp;lt;script src=&quot;notifiy.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;浏览器配置&lt;/p&gt;

    &lt;p&gt;检查浏览器是否支持桌面通知功能&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.HasSupport();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;获取允许桌面通知权限&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.RequestPermission();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;设置通知显示方式（可选。不设置采用默认模式）&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.ModelAll();       //默认方式，显示所有的。在linux一般为三个。在window显示在通知区域。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.ModelUpdate();    //更新模式，显示在上一个通知的位置，
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.ModelCount(c);    //限制当前页面显示的通知个数，默认为三个(可以通过参数c改变个数)。超出限制时关闭最早的通知，
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; NOtifier.firefox 可用但是智能展示一个通知（不建议使用，不同版本存在差异）(ct); //超时消失模式。显示一定时间自动消失。
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;发送通知&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Notifier.Notify(icon, title, message); //显示桌面通知，icon：图片的地址  title:通知的标题 message：通知的内容
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;关闭的方法&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  Notifier.Clse(type);    //type=1 关闭上一个 其他值 关闭最早打开的
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  Notifier.ClosePre();    //关闭最近个打开的通知
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  Notifier.CloseLast();   //关闭最早显示的通知
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  NOtifier.CloseAll();    //关闭所有通知
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;其他方法&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.GetPermission();   //获取关于通知使用权限，0，已经得到权限 1，需要获取权限 2，禁止使用
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.IsGetPermission(); //是否已经获取通知的使用权限
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; Notifier.Disable();         //是否禁用通知
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

</content>
 </entry>
 
 <entry>
   <title>c语言 sizeof函数认知</title>
   <link href="http://www.ireage.com/c/2012/09/06/c-sizeof%E5%87%BD%E6%95%B0%E7%9A%84%E8%AE%A4%E7%9F%A5.html"/>
   <updated>2012-09-06T00:00:00+00:00</updated>
   <id>http://www.ireage.com/c/2012/09/06/c sizeof函数的认知</id>
   <content type="html">&lt;p&gt;下面仅为个人理解，编译器中验证外，没有任何理论依靠，若有错误请指出。&lt;/p&gt;

&lt;p&gt;## 首先
 —
 sizeof是一个关键字并不是一个函数。或许你有疑问，既然是一个关键字，为什么出现sizeof的时候后面操作对象都加上括号哪？原因如下。&lt;/p&gt;

&lt;h2 id=&quot;sizeof函数证明&quot;&gt;sizeof函数证明&lt;/h2&gt;
&lt;hr /&gt;
&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;sizeof int ，结果为4，说明 sizeof说明他不是一个函数。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;siezof(int )是关键字，为什么分开标记，比方 int i；int i，j；使用空格、逗号区分关键字和操作对象， 请测试 int(i)，你很惊
奇的发现这句话竟然可以编译通过没有报错，这句话的作用是相当于 int i，原因如下，int i，我们从原理上分析这句话，空格起
的是一个分割的作用，有用区分变量和变量类型。 int(i)同样也起到了区分变量和变量类型的，由于()的优先级别高，所以括号里边、外边成为两部分，这样与 int i；的功能相同&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;sizeof后面为什么一直有括号
sizeof struct  student；这一句话将会，编译失败，因为 sizeof 将 struct作为操作数，而并非将整个 struct  student 作为操作数，
这是因为优先级别的问题，
int a；sizeof a+1；结果值为5； 原因如下 sizeof(a)+1;
在sizeof后面加上括号，很容易区分操作对象，不容易出现歧义，去除优先级别错误&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;sizeof容易出差的地方&quot;&gt;sizeof容易出差的地方&lt;/h2&gt;
&lt;hr /&gt;
&lt;p&gt;char a[100]=”三月软件工作室—-Reage”;
char &lt;em&gt;p，&lt;/em&gt;p1=a；&lt;/p&gt;

&lt;p&gt;sizeof p；或许你认为结果为1，可是错了，结果是一个4,因为p是一个指针，是一个地址，地址一个unsigned long型的变量，&lt;/p&gt;

&lt;p&gt;所以结果为4；&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;sizeof p1;  值为4， 这个你或许认为没有意义，但是我是为下面一个做铺垫的&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;sizeof(a) =100；  ？？为什么 sizeof(p1)为4，这里面涉及到汇编知识，a[100]在汇编中应该定义为  a .fill 100 0；所以测试a的值是一个应该是一个100，而p1的值不是&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;sizeof( &amp;amp;a)  vc= 100 ，gcc= 4； 我个人认为gcc的值是正确的，应为&amp;amp;a的地址得到的是一个地址的地址，还是地址 所以值
　　应该为4&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;sizeof(&amp;amp;a[0])  4；没有疑问&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;del&gt;struct b{}；sizeof(b) ；vc=1，gcc=0；//应b是一个变量类型，定义一个b类型的数据，虽然他什么也没有但是他是存在
不能不占内存吧，所以编译器设置大小为1；gcc中为0是实际大小，但是我觉是错误的，因为这个变量占用了内存,
虽然是在代码段，而不是数据段；（这个是错误的。请大家谅解) &lt;/del&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;struct b{char c};sizeof(b)=1;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 

</feed>
