<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>风向标 | 分享与创造</title>
  
  
  <link href="https://sbcoder.cn/atom.xml" rel="self"/>
  
  <link href="https://sbcoder.cn/"/>
  <updated>2026-02-28T07:44:20.000Z</updated>
  <id>https://sbcoder.cn/</id>
  
  <author>
    <name>ai0by</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>Windows WSL Ubuntu 部署OpenClaw</title>
    <link href="https://sbcoder.cn/2026/02/28/wsl-openclaw.html"/>
    <id>https://sbcoder.cn/2026/02/28/wsl-openclaw.html</id>
    <published>2026-02-28T06:33:37.000Z</published>
    <updated>2026-02-28T07:44:20.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="WSL准备"><a href="#WSL准备" class="headerlink" title="WSL准备"></a>WSL准备</h2><p>搭建时使用WSL2，预期通过宿主机访问虚拟机的OpenClaw，通过虚拟机OpenClaw操作生成文档等，以及自动创建项目生成代码</p><p>需支持hyper-v，安装wsl2</p><p>安装环境为ubuntu22.04</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://cdn.jsdelivr.net/gh/ai0by/imgurl/2026/ScreenShot_2026-02-28_143618_895.png" alt="" title="">                </div>                <div class="image-caption"></div>            </figure><h2 id="部署"><a href="#部署" class="headerlink" title="部署"></a>部署</h2><h3 id="安装nmv"><a href="#安装nmv" class="headerlink" title="安装nmv"></a>安装nmv</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.6/install.sh | bash</span><br><span class="line">source ~/.bashrc</span><br></pre></td></tr></table></figure><h3 id="安装node-js"><a href="#安装node-js" class="headerlink" title="安装node.js"></a>安装node.js</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">nvm install 22</span><br><span class="line">nvm use 22</span><br><span class="line">node -v</span><br></pre></td></tr></table></figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://cdn.jsdelivr.net/gh/ai0by/imgurl/2026/ScreenShot_2026-02-28_151902_283.png" alt="" title="">                </div>                <div class="image-caption"></div>            </figure><h3 id="安装OpenClaw"><a href="#安装OpenClaw" class="headerlink" title="安装OpenClaw"></a>安装OpenClaw</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -fsSL https://openclaw.ai/install.sh | bash</span><br></pre></td></tr></table></figure><h2 id="OpenClaw终端常用命令"><a href="#OpenClaw终端常用命令" class="headerlink" title="OpenClaw终端常用命令"></a>OpenClaw终端常用命令</h2><h3 id="常见指令集"><a href="#常见指令集" class="headerlink" title="常见指令集"></a>常见指令集</h3><p>检查服务状态</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openclaw status</span><br></pre></td></tr></table></figure><p>运行配置向导</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openclaw onboard </span><br></pre></td></tr></table></figure><p>查看控制台</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openclaw dashboard</span><br></pre></td></tr></table></figure><p>配置其他模型(deepseek示例)</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">openclaw config set models.providers.deepseek &#x27;&#123;</span><br><span class="line">  &quot;baseUrl&quot;: &quot;https://api.deepseek.com/v1&quot;,</span><br><span class="line">  &quot;apiKey&quot;: &quot;你的API_KEY&quot;,</span><br><span class="line">  &quot;api&quot;: &quot;openai-completions&quot;,</span><br><span class="line">  &quot;models&quot;: [</span><br><span class="line">    &#123;</span><br><span class="line">      &quot;id&quot;: &quot;deepseek-chat&quot;,</span><br><span class="line">      &quot;name&quot;: &quot;DeepSeek Chat (V3)&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      &quot;id&quot;: &quot;deepseek-reasoner&quot;,</span><br><span class="line">      &quot;name&quot;: &quot;DeepSeek Reasoner (R1)&quot;</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;&#x27;</span><br></pre></td></tr></table></figure><p>查看可用模型列表</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openclaw models list --all</span><br></pre></td></tr></table></figure><p>设置默认模型</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openclaw config set agents.defaults.model.primary &quot;deepseek/deepseek-chat&quot;</span><br></pre></td></tr></table></figure><h3 id="基础指令集"><a href="#基础指令集" class="headerlink" title="基础指令集"></a>基础指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>查看版本</td><td>查看当前 OpenClaw 的安装版本</td><td>openclaw –version</td><td>openclaw –version</td></tr><tr><td>查看帮助</td><td>查看所有 CLI 命令的帮助信息</td><td>openclaw –help</td><td>openclaw –help</td></tr><tr><td>状态概览</td><td>查看 OpenClaw 的整体状态，包括 Gateway、模型、频道等信息</td><td>openclaw status</td><td>openclaw status</td></tr><tr><td>完整诊断</td><td>查看详细的状态信息，适合调试和分享</td><td>openclaw status –all</td><td>openclaw status –all</td></tr><tr><td>健康检查</td><td>检查系统的健康状态，检测潜在问题</td><td>openclaw health</td><td>openclaw health</td></tr><tr><td>深度健康检查</td><td>进行更全面的健康检测，排查深层问题</td><td>openclaw status –deep</td><td>openclaw status –deep</td></tr></tbody></table><h3 id="网关指令集"><a href="#网关指令集" class="headerlink" title="网关指令集"></a>网关指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>启动 Gateway</td><td>启动 Gateway 服务</td><td>openclaw gateway start</td><td>openclaw gateway start</td></tr><tr><td>停止 Gateway</td><td>停止 Gateway 服务</td><td>openclaw gateway stop</td><td>openclaw gateway stop</td></tr><tr><td>重启 Gateway</td><td>重启 Gateway 服务</td><td>openclaw gateway restart</td><td>openclaw gateway restart</td></tr><tr><td>查看 Gateway 状态</td><td>查看 Gateway 的运行状态</td><td>openclaw gateway status</td><td>openclaw gateway status</td></tr><tr><td>前台运行 Gateway</td><td>手动在前台运行 Gateway，用于调试，显示详细日志</td><td>openclaw gateway –port &lt;端口&gt; –verbose</td><td>openclaw gateway –port 18789 –verbose</td></tr><tr><td>设置绑定模式</td><td>指定 Gateway 的网络绑定模式，控制访问范围</td><td>openclaw gateway –bind &lt;模式&gt;</td><td>openclaw gateway –bind loopback（本地回环，默认）openclaw gateway –bind lan（局域网）openclaw gateway –bind tailnet（<a href="https://zhida.zhihu.com/search?content_id=270073209&content_type=Article&match_order=1&q=Tailscale+%E7%BD%91%E7%BB%9C&zhida_source=entity">Tailscale 网络</a>）</td></tr></tbody></table><h3 id="配置指令集"><a href="#配置指令集" class="headerlink" title="配置指令集"></a>配置指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>交互式配置</td><td>进入交互式配置向导，逐步设置系统参数</td><td>openclaw configure</td><td>openclaw configure</td></tr><tr><td>查看完整配置</td><td>查看当前的所有配置信息</td><td>openclaw config get</td><td>openclaw config get</td></tr><tr><td>查看特定配置</td><td>查看指定部分的配置信息</td><td>openclaw config get &lt;配置路径&gt;</td><td>openclaw config get agents.defaultsopenclaw config get channels.telegram</td></tr><tr><td>设置配置值</td><td>设置指定配置项的值</td><td>openclaw config set &lt;配置路径&gt; &lt;值&gt;</td><td>openclaw config set gateway.port 18789openclaw config set agents.defaults.workspace ~&#x2F;.openclaw&#x2F;workspace</td></tr><tr><td>删除配置项</td><td>删除指定的配置项</td><td>openclaw config unset &lt;配置路径&gt;</td><td>openclaw config unset gateway.port</td></tr><tr><td>查看配置文件位置</td><td>配置文件默认路径：~&#x2F;.openclaw&#x2F;openclaw.json</td><td>-</td><td>-</td></tr></tbody></table><h3 id="模型管理指令集"><a href="#模型管理指令集" class="headerlink" title="模型管理指令集"></a>模型管理指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>查看可用模型</td><td>列出所有支持的 AI 模型</td><td>openclaw models list</td><td>openclaw models list</td></tr><tr><td>查看模型状态</td><td>查看已配置模型的状态，包括 API Key 有效性等</td><td>openclaw models status</td><td>openclaw models status</td></tr><tr><td>扫描可用模型</td><td>扫描系统中可用的 AI 模型</td><td>openclaw models scan</td><td>openclaw models scan</td></tr><tr><td>设置默认模型</td><td>设置默认使用的 AI 模型</td><td>openclaw models set &lt;模型名&gt;</td><td>openclaw models set anthropic&#x2F;claude-sonnet-4-0</td></tr><tr><td>测试模型连接</td><td>测试指定模型的连接是否正常</td><td>openclaw models probe &lt;模型名&gt;</td><td>openclaw models probe claude-opus-4-5</td></tr></tbody></table><h3 id="频道管理指令集"><a href="#频道管理指令集" class="headerlink" title="频道管理指令集"></a>频道管理指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>频道登录</td><td>登录指定的即时通讯频道，如 WhatsApp（需要扫描二维码）</td><td>openclaw channels login</td><td>openclaw channels login</td></tr><tr><td>频道登出</td><td>退出登录的频道</td><td>openclaw channels logout</td><td>openclaw channels logout</td></tr><tr><td>查看频道状态</td><td>查看所有已配置频道的状态</td><td>openclaw channels status</td><td>openclaw channels status</td></tr><tr><td>探测频道连通性</td><td>测试频道的连通性，检查是否可以正常使用</td><td>openclaw channels status –probe</td><td>openclaw channels status –probe</td></tr></tbody></table><h3 id="配对管理指令集"><a href="#配对管理指令集" class="headerlink" title="配对管理指令集"></a>配对管理指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>查看待处理配对</td><td>查看指定频道的待处理配对请求</td><td>openclaw pairing list &lt;频道名&gt;</td><td>openclaw pairing list whatsappopenclaw pairing list telegram</td></tr><tr><td>批准配对</td><td>批准指定的配对请求，允许用户和 OpenClaw 交互</td><td>openclaw pairing approve &lt;频道名&gt; &lt;配对码&gt;</td><td>openclaw pairing approve whatsapp ABC123</td></tr><tr><td>拒绝配对</td><td>拒绝指定的配对请求</td><td>openclaw pairing deny &lt;频道名&gt; &lt;配对码&gt;</td><td>openclaw pairing deny telegram XYZ789</td></tr></tbody></table><h3 id="消息发送指令集"><a href="#消息发送指令集" class="headerlink" title="消息发送指令集"></a>消息发送指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>发送文本消息</td><td>向指定目标发送文本消息</td><td>openclaw message send –target &lt;目标&gt; –message &lt;消息内容&gt;</td><td>openclaw message send –target +15555550123 –message “Hello from OpenClaw”</td></tr><tr><td>发送文件</td><td>向指定目标发送文件</td><td>openclaw message send –target &lt;目标&gt; –file &lt;文件路径&gt;</td><td>openclaw message send –target +15555550123 –file &#x2F;path&#x2F;to&#x2F;file.txt</td></tr></tbody></table><h3 id="代理（agent）指令集"><a href="#代理（agent）指令集" class="headerlink" title="代理（agent）指令集"></a>代理（agent）指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>查看代理列表</td><td>列出所有已创建的代理</td><td>openclaw agents list</td><td>openclaw agents list</td></tr><tr><td>添加新代理</td><td>创建新的代理实例，指定工作区</td><td>openclaw agents add &lt;代理名&gt; –workspace &lt;工作区路径&gt;</td><td>openclaw agents add work –workspace ~&#x2F;.openclaw&#x2F;work</td></tr><tr><td>查看代理状态</td><td>查看指定代理的状态</td><td>openclaw agents status &lt;代理名&gt;</td><td>openclaw agents status work</td></tr></tbody></table><h3 id="会话指令集"><a href="#会话指令集" class="headerlink" title="会话指令集"></a>会话指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>查看活跃会话</td><td>列出当前活跃的聊天会话</td><td>openclaw sessions list</td><td>openclaw sessions list</td></tr><tr><td>查看会话历史</td><td>查看指定会话的聊天历史</td><td>openclaw sessions history &lt;会话ID&gt;</td><td>openclaw sessions history session-123</td></tr><tr><td>重置会话</td><td>重置指定的会话，清空历史记录</td><td>openclaw sessions reset &lt;会话ID&gt;</td><td>openclaw sessions reset session-123</td></tr></tbody></table><h3 id="技能指令集"><a href="#技能指令集" class="headerlink" title="技能指令集"></a>技能指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>列出已安装技能</td><td>查看所有已安装的技能</td><td>openclaw skills list</td><td>openclaw skills list</td></tr><tr><td>安装技能</td><td>安装指定的技能</td><td>openclaw skills install &lt;技能名&gt;</td><td>openclaw skills install weather</td></tr><tr><td>查看技能配置</td><td>查看指定技能的配置信息</td><td>openclaw skills config &lt;技能名&gt;</td><td>openclaw skills config weather</td></tr><tr><td>更新技能</td><td>更新指定的技能到最新版本</td><td>openclaw skills update &lt;技能名&gt;</td><td>openclaw skills update weather</td></tr></tbody></table><h3 id="日志、诊断指令集"><a href="#日志、诊断指令集" class="headerlink" title="日志、诊断指令集"></a>日志、诊断指令集</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>实时查看日志</td><td>实时跟踪 Gateway 的日志输出</td><td>openclaw logs –follow</td><td>openclaw logs –follow</td></tr><tr><td>查看最近日志</td><td>查看最近指定行数的日志</td><td>openclaw logs –limit &lt;行数&gt;</td><td>openclaw logs –limit 100</td></tr><tr><td>诊断和修复</td><td>自动诊断系统问题并尝试修复</td><td>openclaw doctor</td><td>openclaw doctoropenclaw doctor –fix（自动修复）</td></tr></tbody></table><h3 id="更新升级"><a href="#更新升级" class="headerlink" title="更新升级"></a>更新升级</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>检查更新</td><td>查看当前版本和最新版本信息</td><td>openclaw –version</td><td>openclaw –version</td></tr><tr><td>自动更新</td><td>通过官方安装脚本更新 OpenClaw</td><td>curl -fsSL <a href="https://openclaw.ai/install.sh">https://openclaw.ai/install.sh</a> | bash</td><td>curl -fsSL <a href="https://openclaw.ai/install.sh">https://openclaw.ai/install.sh</a> | bash</td></tr><tr><td>从源码更新</td><td>如果从源码安装，通过 git 更新</td><td>git pull origin main &amp;&amp; pnpm install &amp;&amp; pnpm build</td><td>git pull origin main &amp;&amp; pnpm install &amp;&amp; pnpm build</td></tr></tbody></table><h3 id="安全相关"><a href="#安全相关" class="headerlink" title="安全相关"></a>安全相关</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>安全审计</td><td>审计系统的安全配置，检测潜在风险</td><td>openclaw security audit</td><td>openclaw security audit</td></tr><tr><td>深度安全审计</td><td>进行更全面的安全审计</td><td>openclaw security audit –deep</td><td>openclaw security audit –deep</td></tr></tbody></table><h2 id="OpenClaw聊天常用命令"><a href="#OpenClaw聊天常用命令" class="headerlink" title="OpenClaw聊天常用命令"></a>OpenClaw聊天常用命令</h2><h3 id="基础命令"><a href="#基础命令" class="headerlink" title="基础命令"></a>基础命令</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>新开对话</td><td>重置当前会话，清空历史记录，节省 Token 消耗</td><td>&#x2F;new</td><td>&#x2F;new</td></tr><tr><td>新开对话并切换模型</td><td>重置会话并切换到指定模型</td><td>&#x2F;new &lt;模型名&gt;</td><td>&#x2F;new haiku&#x2F;new claude-sonnet-4-5</td></tr><tr><td>查看会话状态</td><td>查看当前会话的状态，包括模型、Token 使用量、预估成本</td><td>&#x2F;status</td><td>&#x2F;status</td></tr><tr><td>查看帮助</td><td>查看所有斜杠命令的帮助信息</td><td>&#x2F;help</td><td>&#x2F;help</td></tr><tr><td>查看命令列表</td><td>查看所有可用的斜杠命令</td><td>&#x2F;commands</td><td>&#x2F;commands</td></tr></tbody></table><h3 id="模型和上下文"><a href="#模型和上下文" class="headerlink" title="模型和上下文"></a>模型和上下文</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>切换模型</td><td>切换当前会话使用的 AI 模型</td><td>&#x2F;model &lt;模型名&gt;</td><td>&#x2F;model haiku&#x2F;model opus&#x2F;model claude-opus-4-5</td></tr><tr><td>查看可用模型</td><td>列出所有可用的 AI 模型</td><td>&#x2F;model list</td><td>&#x2F;model list</td></tr><tr><td>查看模型状态</td><td>查看当前使用的模型的详细状态</td><td>&#x2F;model status</td><td>&#x2F;model status</td></tr><tr><td>压缩上下文</td><td>将历史对话压缩成摘要，减少 Token 消耗，同时保留关键信息</td><td>&#x2F;compact</td><td>&#x2F;compact</td></tr><tr><td>带指令压缩上下文</td><td>指定压缩规则，告诉 AI 保留哪些信息</td><td>&#x2F;compact &lt;压缩指令&gt;</td><td>&#x2F;compact 保留代码相关的讨论，其他可以简化</td></tr><tr><td>查看用量</td><td>控制 Token 和成本的显示方式</td><td>&#x2F;usage &lt;模式&gt;</td><td>&#x2F;usage off（关闭用量显示）&#x2F;usage tokens（只显示 Token 数量）&#x2F;usage full（显示完整用量详情）&#x2F;usage cost（显示成本统计）</td></tr><tr><td>查看上下文详情</td><td>查看当前上下文的详细信息，包括 Token 分布</td><td>&#x2F;context</td><td>&#x2F;context&#x2F;context list（列出上下文组件）&#x2F;context detail（显示详细 Token 分布）&#x2F;context json（JSON 格式输出）</td></tr></tbody></table><h3 id="命令控制"><a href="#命令控制" class="headerlink" title="命令控制"></a>命令控制</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>执行控制</td><td>控制 OpenClaw 执行系统命令的权限和方式</td><td>&#x2F;exec</td><td>&#x2F;exec（查看当前设置）&#x2F;exec host&#x3D;&lt;sandbox | gateway | node&gt;（设置执行主机）<br>&#x2F;exec security&#x3D;&lt;deny | allowlist&gt;</td></tr><tr><td>批准操作</td><td>批准 OpenClaw 需要权限的操作</td><td>&#x2F;approve &lt;操作ID&gt; &lt;权限&gt;</td><td>&#x2F;approve abc123 allow-once（允许本次操作）&#x2F;approve abc123 allow-always（永久允许此类操作）&#x2F;approve abc123 deny（拒绝操作）</td></tr><tr><td>提升权限模式</td><td>控制是否需要频繁确认操作</td><td>&#x2F;elevated &lt;模式&gt;</td><td>&#x2F;elevated on（启用提升权限，减少询问）&#x2F;elevated full（完全跳过询问，谨慎使用）&#x2F;elevated off（关闭提升权限）</td></tr></tbody></table><h3 id="语音和子代理"><a href="#语音和子代理" class="headerlink" title="语音和子代理"></a>语音和子代理</h3><table><thead><tr><th>命令</th><th>说明</th><th>语法</th><th>示例</th></tr></thead><tbody><tr><td>语音合成控制</td><td>控制 <a href="https://zhida.zhihu.com/search?content_id=270073209&content_type=Article&match_order=1&q=TTS&zhida_source=entity">TTS</a>（文本转语音）功能</td><td>&#x2F;tts &lt;模式&gt;</td><td>&#x2F;tts off（关闭语音合成）&#x2F;tts always（所有回复都用语音播放）&#x2F;tts inbound（仅对语音输入的回复用语音播放）&#x2F;tts tagged（仅播放标记的内容）&#x2F;tts status（查看当前 TTS 状态）&#x2F;tts provider（查看或切换 TTS 提供商）</td></tr><tr><td>子代理管理</td><td>管理后台运行的子代理，处理并行任务</td><td>&#x2F;subagents &lt;操作&gt;</td><td>&#x2F;subagents list（列出所有子代理）&#x2F;subagents stop &lt;代理ID&gt;（停止指定子代理）&#x2F;subagents log &lt;代理ID&gt;（查看子代理日志）&#x2F;subagents info &lt;代理ID&gt;（查看子代理详情）&#x2F;subagents send &lt;代理ID&gt; &lt;消息&gt;（向子代理发送消息）</td></tr></tbody></table><h3 id="常用命令速查"><a href="#常用命令速查" class="headerlink" title="常用命令速查"></a>常用命令速查</h3><table><thead><tr><th>场景</th><th>推荐命令</th></tr></thead><tbody><tr><td>日常状态检查</td><td>openclaw status、&#x2F;status</td></tr><tr><td>启动 &#x2F; 停止服务</td><td>openclaw gateway start、openclaw gateway stop</td></tr><tr><td>切换模型</td><td>&#x2F;model haiku、&#x2F;model opus</td></tr><tr><td>节省 Token</td><td>&#x2F;new、&#x2F;compact</td></tr><tr><td>成本监控</td><td>&#x2F;usage full、openclaw status –all</td></tr><tr><td>调试问题</td><td>openclaw logs –follow、openclaw doctor</td></tr><tr><td>批准用户配对</td><td>openclaw pairing approve &lt;频道&gt; &lt;配对码&gt;</td></tr></tbody></table><h2 id="附件"><a href="#附件" class="headerlink" title="附件"></a>附件</h2><p><a href="https://docs.openclaw.ai/">docs.openclaw.ai-OpenClaw Docs</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;WSL准备&quot;&gt;&lt;a href=&quot;#WSL准备&quot; class=&quot;headerlink&quot; title=&quot;WSL准备&quot;&gt;&lt;/a&gt;WSL准备&lt;/h2&gt;&lt;p&gt;搭建时使用WSL2，预期通过宿主机访问虚拟机的OpenClaw，通过虚拟机OpenClaw操作生成文档等，以及自动创</summary>
      
    
    
    
    <category term="AI" scheme="https://sbcoder.cn/categories/AI/"/>
    
    
    <category term="AI" scheme="https://sbcoder.cn/tags/AI/"/>
    
  </entry>
  
  <entry>
    <title>博客迁移说明</title>
    <link href="https://sbcoder.cn/2026/02/09/Hello_world.html"/>
    <id>https://sbcoder.cn/2026/02/09/Hello_world.html</id>
    <published>2026-02-09T02:07:27.740Z</published>
    <updated>2021-11-30T02:47:36.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="关于迁移"><a href="#关于迁移" class="headerlink" title="关于迁移"></a>关于迁移</h2><p>博客总是在起起伏伏，关了又开，开了又关中反复，这一次，我将风向标博客放在了Github Page上。<br>程序采用了当下比较流行的静态博客程序 Hexo ，Hexo其实是一个非常好的程序，但由于我经常换电脑，以前用hexo搭建的博客数据丢失了很多次，后经过更换为Wordpress，Typecho之类的开源博客程序后，我又回到了 Hexo 的怀抱，可能是真的懒得折腾了，上了年纪？<br>这次我将源代码都备份好了，应该会长期更新，有什么好的东西我应该会分享出来，主打原创~<br>可能之前认识我的人也很少，但我这个域名还是很好记的，sb coder 也是一种自嘲吧，有想跟我交流技术或者有外包工作介绍给我的，我的微信与域名同号~<br>多的不说了，我将尽我所能，一周至少写一篇文章，可能有时候晚上回家写一点，一天写一点，一周下来也能写不少，希望各位监督~</p><h2 id="关于我"><a href="#关于我" class="headerlink" title="关于我"></a>关于我</h2><p>我是谁，职业是Go,PHP，目前全职Go开发，爱好Python，云服务器爱好者<br>有想法的朋友可以联系我 Telegram : ai0by</p><h2 id="承接业务"><a href="#承接业务" class="headerlink" title="承接业务"></a>承接业务</h2><p>运维及开发，个人有团队可承接业务</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;关于迁移&quot;&gt;&lt;a href=&quot;#关于迁移&quot; class=&quot;headerlink&quot; title=&quot;关于迁移&quot;&gt;&lt;/a&gt;关于迁移&lt;/h2&gt;&lt;p&gt;博客总是在起起伏伏，关了又开，开了又关中反复，这一次，我将风向标博客放在了Github Page上。&lt;br&gt;程序采用了当下比</summary>
      
    
    
    
    
    <category term="ai0by" scheme="https://sbcoder.cn/tags/ai0by/"/>
    
  </entry>
  
  <entry>
    <title>自定义过滤网络请求 - nfqueue</title>
    <link href="https://sbcoder.cn/2022/10/21/nfqueue.html"/>
    <id>https://sbcoder.cn/2022/10/21/nfqueue.html</id>
    <published>2022-10-21T08:07:51.000Z</published>
    <updated>2022-10-25T09:55:54.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>基于iptables的内核通讯大杀器，使用nfnetlink协议与内核通信。</p><p>他可以通过iptables定义的规则去拦截相应的网络报文，他可以基于iptables前或者后去自定义拦截这些报文，也可以通过解析这些报文做一些审计之类的工作，也可以通过这些报文来形成一个阻断功能</p><p>NFQUEU 的源代码分为 <code>nf_queue</code> 和 <code>nfnetlink_queue</code> 两部分。<code>nf_queue</code> 是 <code>iptables</code> 的一部分，<code>nfnetlink_queue</code> 是<code>netfilter</code> 的一个子模块。</p><p><code>nfnetlink_queue</code> 是 <code>nf_queue</code> 跟用户程序之间的桥梁，是基于 <code>nfnetlink</code> 的专门用于 NFQUEUE 的通信机制；而 <code>nfnetlink</code> 是一套基于 netlink的专门用于 <code>netfilter</code> 的通信机制。</p><h2 id="安全性"><a href="#安全性" class="headerlink" title="安全性"></a>安全性</h2><p>nfqueue是一个队列，程序通过队列的形式来处理报文，默认这个队列的长度是1024，超出此队列的报文默认会丢弃，正常环境下，要控制好这些流量。在内核 3.6 之后，可以使用 <code>--fail-open</code> 选项将这默认丢包改为默认接收。在 <code>/proc/net/netfilter/nfnetlink_queue</code> 中可以看到丢包统计。</p><p>NFQUEUE 很容易地为任意入队的包做包重排序。然而，需要注意的是内核是使用链式列表来排队包的；所以，乱序判决会带来一定的损耗。</p><h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><p>按照iptables的四表五链配置规则即可</p><p>例如：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -t raw -I PREROUTING -p tcp --syn -j NFQUEUE --queue-num=1 --queue-bypass</span><br></pre></td></tr></table></figure><ul><li>–queue-num 代表队列号</li><li>–queue-bypass 默认情况下，如果没有用户空间程序正在监听 NFQUEUE，那么将丢弃所有要排队的数据包。使用此选项时，NFQUEUE 规则的行为类似于 ACCEPT，数据包将转移到下一个表。但此规则要求 内核 &gt;&#x3D; 2.6.39，iptables &gt;&#x3D; 1.4.11</li></ul><p>同时，为了防止丢包，也有负载均衡的配置</p><p><code>--queue-balance</code> 是 NFQUEUE 选项，由 Florian Westphal 实现，实现了同一条 iptables 规则的网络包负载均衡到多个队列。用法非常简单。比如，负载均衡 INPUT 流量到 0-3 队列的规则如下，注意，负载均衡是基于流实现的（made with respect to the flow），一条流的所有网络包会发送到同一个队列。但此规则要求 Linux 内核 &gt;&#x3D; 2.6.31，iptables &gt;&#x3D; 1.4.5</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -A INPUT -j NFQUEUE --queue-balance 0:3</span><br></pre></td></tr></table></figure><p>其他iptables配置可以参照 <a href="https://blog.csdn.net/weixin_69543697/article/details/125839732">iptables 配置</a></p><h2 id="代码参考"><a href="#代码参考" class="headerlink" title="代码参考"></a>代码参考</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;os&quot;</span></span><br><span class="line"><span class="string">&quot;github.com/subgraph/go-nfnetlink/nfqueue&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line">q := nfqueue.NewNFQueue(<span class="number">1</span>) <span class="comment">// 此处参数1需要改为绑定的对列号</span></span><br><span class="line">ps, err := q.Open()</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Printf(<span class="string">&quot;Error opening NFQueue: %v\n&quot;</span>, err)</span><br><span class="line">os.Exit(<span class="number">1</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">defer</span> q.Close()</span><br><span class="line">fmt.Println(<span class="string">&quot;Start Listen ...&quot;</span>)</span><br><span class="line"><span class="keyword">for</span> p := <span class="keyword">range</span> ps &#123;</span><br><span class="line">fmt.Println(p.Packet.String())</span><br><span class="line">err = p.Accept()</span><br><span class="line"><span class="keyword">if</span> err != <span class="literal">nil</span> &#123;</span><br><span class="line">fmt.Println(err)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;简介&quot;&gt;&lt;a href=&quot;#简介&quot; class=&quot;headerlink&quot; title=&quot;简介&quot;&gt;&lt;/a&gt;简介&lt;/h2&gt;&lt;p&gt;基于iptables的内核通讯大杀器，使用nfnetlink协议与内核通信。&lt;/p&gt;
&lt;p&gt;他可以通过iptables定义的规则去拦截相应的</summary>
      
    
    
    
    <category term="Linux" scheme="https://sbcoder.cn/categories/Linux/"/>
    
    
    <category term="攻防" scheme="https://sbcoder.cn/tags/%E6%94%BB%E9%98%B2/"/>
    
    <category term="审计" scheme="https://sbcoder.cn/tags/%E5%AE%A1%E8%AE%A1/"/>
    
  </entry>
  
  <entry>
    <title>Linux 探针技术 - Audit</title>
    <link href="https://sbcoder.cn/2022/06/30/Linux-EDR-Agent-Audit.html"/>
    <id>https://sbcoder.cn/2022/06/30/Linux-EDR-Agent-Audit.html</id>
    <published>2022-06-30T02:53:00.000Z</published>
    <updated>2022-09-03T08:46:30.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Audit是什么"><a href="#Audit是什么" class="headerlink" title="Audit是什么"></a>Audit是什么</h2><p>Audit是Linux中的审计程序，主要的作用可以看做审计日志，功能全面，可以说市面上大部分Linux探针都绕不开Audit，且Audit有着实时性很强的特性，因此可以替代部分Linux Hook操作及监控操作。</p><p>Audit主要监测的内容包含但不限于</p><ul><li>文件监控（文件操作日志，创建，删除，增加，修改，权限 …）</li><li>网络监控 （connect，close，bind）</li><li>进程监控 （execve）（按pid监控）</li></ul><p>本文主体也按照如上几种常见探针功能描述</p><h2 id="Audit使用方式"><a href="#Audit使用方式" class="headerlink" title="Audit使用方式"></a>Audit使用方式</h2><h3 id="audit-启动"><a href="#audit-启动" class="headerlink" title="audit 启动"></a>audit 启动</h3><p>如何使用肯定是第一话题，现在绝大部分的Linux主机都内置了Audit</p><p>通过命令启动即可 <code>/etc/init.d/auditd start</code></p><p>audit会在目录 <code>/var/log/audit/</code> 下生成log文件，通过解析audit的原始log可以拿到非常多的审计日志信息</p><p>Netlink监控，通过netlink也可以监控audit信息</p><h3 id="audit-日志配置"><a href="#audit-日志配置" class="headerlink" title="audit 日志配置"></a>audit 日志配置</h3><p>列举一些常见配置</p><p>监控execve，也可用作进程启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a exit,always -F arch=b64 -S execve -k ProcStart</span><br></pre></td></tr></table></figure><p>系统关键目录监控</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">-w /etc/hosts -p w -k HostChange</span><br><span class="line">-w /etc/services -p w -k ServicesChange</span><br><span class="line">-w /etc/sysconfig/network-devices/ -p w -k NetCardChange</span><br></pre></td></tr></table></figure><p>套接字监控</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a always,exit -F arch=b64 -S socket -k SocketChange</span><br></pre></td></tr></table></figure><p>连接监控</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a always,exit -F arch=b64 -S connect -k ConnectChange</span><br></pre></td></tr></table></figure><p>发送消息监控</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a always,exit -F arch=b64 -S sendmsg -k SendMsgChange</span><br></pre></td></tr></table></figure><p>绑定监控</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a always,exit -F arch=b64 -S bind -k BindChange</span><br></pre></td></tr></table></figure><p>接收消息监控</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a always,exit -F arch=b64 -S recvmsg -k RecvMsgChange</span><br></pre></td></tr></table></figure><p>关闭操作监控(量大)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">-a always,exit -F arch=b64 -S close -k CloseChange</span><br></pre></td></tr></table></figure><p>过滤日志</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"># 参照如下写法</span><br><span class="line">-A exit,never -F path=/bin/ls -F perm=x</span><br></pre></td></tr></table></figure><p>以上部分监控项实则为监控系统调用，查看整个系统的调用可以查看 <code>ausyscall --dump</code>，不同机型监控也不同</p><h3 id="audit-日志配置-1"><a href="#audit-日志配置-1" class="headerlink" title="audit 日志配置"></a>audit 日志配置</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">#  设置日志文件</span><br><span class="line">log_file = /var/log/audit/audit.log</span><br><span class="line">log_group = root</span><br><span class="line">log_format = ENRICHED</span><br><span class="line">flush = INCREMENTAL_ASYNC</span><br><span class="line">freq = 50</span><br><span class="line">#  设置日志文件大小，单位是MB</span><br><span class="line">max_log_file = 8</span><br><span class="line">#  日志文件滚动的数目，如果设置为小于 2，则不会循环记录。没设置则位0，不循环日志文件</span><br><span class="line">num_logs = 5</span><br><span class="line">priority_boost = 4</span><br><span class="line">name_format = NONE</span><br><span class="line">##name = mydomain</span><br><span class="line">#  日志文件到达最大值后的动作，ROTATE是滚动记录</span><br><span class="line">max_log_file_action = ROTATE</span><br></pre></td></tr></table></figure><h2 id="Audit监控文件"><a href="#Audit监控文件" class="headerlink" title="Audit监控文件"></a>Audit监控文件</h2><h3 id="为什么不选择Inotify"><a href="#为什么不选择Inotify" class="headerlink" title="为什么不选择Inotify"></a>为什么不选择Inotify</h3><p>inotify应该是应用最广泛的文件监控工具了，针对Linux的思想，一切皆文件，Inotify确实是得天独厚</p><p>inotify适用的场景不同，inotify使用epoll，性能更佳，但inotify只能监控文件的部分信息，无法做到审计，也就是操作进程的信息和操作用户信息，作为一个优秀的EDR，必然需要审计分析能力，因此Inotify只能作为部分监控项所用，如果需要溯源，audit更适合</p><h3 id="如何判断文件的操作行为"><a href="#如何判断文件的操作行为" class="headerlink" title="如何判断文件的操作行为"></a>如何判断文件的操作行为</h3><p>根据不同的文件制定不同的key，如果key是唯一的那么可以通过key来识别文件，或者根据audit日志中的path来识别</p><p>操作行为可以通过系统的syscall来判断 增删改查，需要监控文件时增加文件监控属性 <code>-p rwax</code></p><h2 id="Audit监控网络访问"><a href="#Audit监控网络访问" class="headerlink" title="Audit监控网络访问"></a>Audit监控网络访问</h2><p>必须配置对应的采集配置</p><h2 id="Audit监控进程启动"><a href="#Audit监控进程启动" class="headerlink" title="Audit监控进程启动"></a>Audit监控进程启动</h2><p>必须配置对应的采集配置</p><p>进程监控建议增加过滤，否则会积压很多Audit日志</p><h2 id="关于探针"><a href="#关于探针" class="headerlink" title="关于探针"></a>关于探针</h2><p>探针采集内容目前非常稳定，各类进程，网络，文件，防火墙（适配多种主流防火墙），系统信息，系统状态，外设，硬件设备….</p><p>欢迎交流~</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Audit是什么&quot;&gt;&lt;a href=&quot;#Audit是什么&quot; class=&quot;headerlink&quot; title=&quot;Audit是什么&quot;&gt;&lt;/a&gt;Audit是什么&lt;/h2&gt;&lt;p&gt;Audit是Linux中的审计程序，主要的作用可以看做审计日志，功能全面，可以说市面上大部分</summary>
      
    
    
    
    <category term="Linux" scheme="https://sbcoder.cn/categories/Linux/"/>
    
    
    <category term="攻防" scheme="https://sbcoder.cn/tags/%E6%94%BB%E9%98%B2/"/>
    
    <category term="审计" scheme="https://sbcoder.cn/tags/%E5%AE%A1%E8%AE%A1/"/>
    
  </entry>
  
  <entry>
    <title>设计高可用安全的协程池kd-schedule</title>
    <link href="https://sbcoder.cn/2022/01/29/kd-schedule.html"/>
    <id>https://sbcoder.cn/2022/01/29/kd-schedule.html</id>
    <published>2022-01-29T01:11:58.000Z</published>
    <updated>2022-01-29T01:28:58.000Z</updated>
    
    <content type="html"><![CDATA[<h1 id="kd-schedule"><a href="#kd-schedule" class="headerlink" title="kd-schedule"></a>kd-schedule</h1><ul><li>限制并发，使程序可控</li><li>错峰处理，使程序平衡性更强，性能占用可控（自动错峰，如果用户不配置错峰处理，则程序自动错峰处理，区间可配置最少为1秒）</li><li>定时发送任务，周期型任务（按分钟），单项程序管控，使得程序定时器结束后立刻增加权重，并在结束后恢复其权重重新排序</li></ul><h2 id="协程控制"><a href="#协程控制" class="headerlink" title="协程控制"></a>协程控制</h2><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2022/01/25/77sPsK.png" alt="77sPsK.png" title="">                </div>                <div class="image-caption">77sPsK.png</div>            </figure><h2 id="权重配比说明"><a href="#权重配比说明" class="headerlink" title="权重配比说明"></a>权重配比说明</h2><p>参考了CPU及GMP的调度算法，增加了权重的配置，权重可以使程序不断地插队</p><p>建议增加任务时按大到小形式增加任务，且权重尽可能不重复，重复权重会依次排序</p><h2 id="TODO"><a href="#TODO" class="headerlink" title="TODO"></a>TODO</h2><p>轮询任务，定时器监控</p><p>增加定时增加权重，轮询任务增加权重，避免一个任务长期被插队无法执行</p><h2 id="设计"><a href="#设计" class="headerlink" title="设计"></a>设计</h2><p>每个控制器被称作一个worker，每个worker可以控制协程数，由于各个参数不同因此不支持带参数的任务</p><p>程序在worker初始化时开启一个协程去监听add操作，并在start后退出该协程，之后所有的任务都以动态加载形式增加</p><p>任务使用链表形式存储，为了按权重插队，插队速度更快</p><p>每个worker都有一个入口workerentry，用来控制任务链表，每个workerentry都是一个协程</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2022/01/27/7XcVlF.png" alt="7XcVlF.png" title="">                </div>                <div class="image-caption">7XcVlF.png</div>            </figure><p>worker在add的时候会再workerentry中按大到小顺序添加任务，但多个workerentry不能排序因此需要用户自行按从大到小增加任务，否则权重可能不生效</p><p>循环worker中的workerentry增加任务，到头后停止增加并从第一个workerentry重新添加</p><p>workerentry中遇到相同的权重任务时会将后加入的任务权重自动后排</p><p>删除任务时只能通过权重删除，因此权重也被视为一个编号，尽可能不要重复</p><p>head只作为链表头部，执行从head后面开始执行</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2022/01/27/7Xcnm9.png" alt="7Xcnm9.png" title="">                </div>                <div class="image-caption">7Xcnm9.png</div>            </figure><h2 id="kd-edr-中的应用"><a href="#kd-edr-中的应用" class="headerlink" title="kd-edr 中的应用"></a>kd-edr 中的应用</h2><p>edr-agent作为系统底层硬件监控，需要对其限制性能，性能瓶颈时做出告警行为，这是 <code>kd-schedule</code> 的作用</p><p>edr-agent希望 <code>kd-schedule</code> 在初始化结束后启用动态加载的形式给链表重新排队，但当队列出现延时过高时提示错误，并重新分配协程任务</p><p>同时在任务中增加定时器概念，使得不使用重新排队也可以让任务继续执行，定时器只能保证单个entry，重新排队需要手动调用或者等待程序自动调用</p><h2 id="不同于协程池"><a href="#不同于协程池" class="headerlink" title="不同于协程池"></a>不同于协程池</h2><p>协程池是一个worker从池子里取任务，控制协程数不超过一个阈值，但权重排序问题比较麻烦，而且协程池无法控制程序周期</p><p>链表结构保证了可以由程序控制下一个执行的方法，支持了动态加载</p><h2 id="动态加载（插队）"><a href="#动态加载（插队）" class="headerlink" title="动态加载（插队）"></a>动态加载（插队）</h2><p>动态加载时给每个workerentry一个标记，当workerentry队列为空的时候，将动态加载的任务送给这个workerentry</p><p>任务自动加载，任务在初始阶段给定一个数值，标记其需要执行的次数，并增加定时，0为不限制次数，默认为1</p><h2 id="示例代码"><a href="#示例代码" class="headerlink" title="示例代码"></a>示例代码</h2><figure class="highlight go"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">&quot;fmt&quot;</span></span><br><span class="line"><span class="string">&quot;github.com/ai0by/kd-schedule/schedule&quot;</span></span><br><span class="line"><span class="string">&quot;time&quot;</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> edr <span class="keyword">struct</span> &#123;</span><br><span class="line">Num <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> edr2 <span class="keyword">struct</span> &#123;</span><br><span class="line">Num <span class="type">int</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> &#123;</span><br><span class="line"><span class="keyword">var</span> edrS = &amp;edr&#123;Num:<span class="number">0</span>&#125;</span><br><span class="line"><span class="keyword">var</span> edr2 = &amp;edr2&#123;Num:<span class="number">0</span>&#125;</span><br><span class="line">wk := schedule.NewWorker(<span class="number">1</span>, <span class="number">100</span>)</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">1</span>; i &lt; <span class="number">9999</span>; i++ &#123;</span><br><span class="line">_ = wk.Add(<span class="type">uint8</span>(i), <span class="number">50</span>, edrS)</span><br><span class="line">&#125;</span><br><span class="line">wk.Start()</span><br><span class="line"><span class="comment">// 实现接口增加任务</span></span><br><span class="line">wk.Add(<span class="number">200</span>,<span class="number">50</span>, edr2)</span><br><span class="line"><span class="comment">// 闭包带参数任务</span></span><br><span class="line">wk.AddClosureFunc(<span class="number">199</span>,<span class="number">50</span>, <span class="function"><span class="keyword">func</span><span class="params">(args ...<span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line"><span class="keyword">for</span> _,v := <span class="keyword">range</span> args&#123;</span><br><span class="line">fmt.Println(v.(<span class="type">string</span>))</span><br><span class="line">&#125;</span><br><span class="line">&#125;,<span class="string">&quot;~~~~~~~~~~~~~~~~~~~~~~~~~~~~&quot;</span>)</span><br><span class="line">wk.AddClosureFunc(<span class="number">199</span>,<span class="number">50</span>, <span class="function"><span class="keyword">func</span><span class="params">(args ...<span class="keyword">interface</span>&#123;&#125;)</span></span> &#123;</span><br><span class="line"><span class="keyword">for</span> _,v := <span class="keyword">range</span> args&#123;</span><br><span class="line">fmt.Println(v.(<span class="type">string</span>))</span><br><span class="line">&#125;</span><br><span class="line">&#125;,<span class="string">&quot;---------------------------&quot;</span>)</span><br><span class="line">time.Sleep(<span class="number">2</span> * time.Second)</span><br><span class="line"><span class="comment">//wk.Stop()</span></span><br><span class="line"><span class="keyword">var</span> cc = <span class="built_in">make</span>(<span class="keyword">chan</span> <span class="type">int</span>)</span><br><span class="line">&lt;-cc</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *edr)</span></span>TaskFunc(args ...<span class="keyword">interface</span>&#123;&#125;) &#123;</span><br><span class="line">fmt.Println(<span class="string">&quot;--------------&quot;</span>,e.Num)</span><br><span class="line">e.Num++</span><br><span class="line">time.Sleep(<span class="number">500</span> * time.Millisecond)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="params">(e *edr2)</span></span>TaskFunc(args ...<span class="keyword">interface</span>&#123;&#125;)&#123;</span><br><span class="line">fmt.Println(<span class="string">&quot;+++++++++++++++++&quot;</span>,e.Num)</span><br><span class="line">e.Num++</span><br><span class="line">time.Sleep(<span class="number">50</span> * time.Millisecond)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>后续这个库应该会用在edr项目中，根据edr的需求会再迭代</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1 id=&quot;kd-schedule&quot;&gt;&lt;a href=&quot;#kd-schedule&quot; class=&quot;headerlink&quot; title=&quot;kd-schedule&quot;&gt;&lt;/a&gt;kd-schedule&lt;/h1&gt;&lt;ul&gt;
&lt;li&gt;限制并发，使程序可控&lt;/li&gt;
&lt;li&gt;错峰处理，使程序</summary>
      
    
    
    
    <category term="Go" scheme="https://sbcoder.cn/categories/Go/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
    <category term="Go" scheme="https://sbcoder.cn/tags/Go/"/>
    
  </entry>
  
  <entry>
    <title>I/O 多路复用技术-epoll</title>
    <link href="https://sbcoder.cn/2021/12/14/Linux-IO-epoll.html"/>
    <id>https://sbcoder.cn/2021/12/14/Linux-IO-epoll.html</id>
    <published>2021-12-14T07:41:30.000Z</published>
    <updated>2021-12-16T08:06:12.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Socket"><a href="#Socket" class="headerlink" title="Socket"></a>Socket</h2><p>Linux一切皆文件的概念，都可以用“打开open –&gt; 读写write&#x2F;read –&gt; 关闭close”模式来操作。Socket就是该模式的一个实现，socket即是一种特殊的文件，一些socket函数就是对其进行的操作（读&#x2F;写IO、打开、关闭），这些函数我们在后面进行介绍。</p><p>想要客户端和服务端在网络间通信则必须使用<code>Socket</code>，支持跨主机通信</p><p>在建立两端通信时，需要将客户端和服务端都创建一个<code>Socket</code>，像一条线通过<code>Socket</code>连接起两端主机，<code>Socket</code>创建时可以指定使用的网络协议，通常情况下是使用<code>TCP</code> 和<code>UDP</code>，而相对来说<code>TCP</code>的场景偏多一些</p><p>如何创建两端通信呢？首先，服务端调用 <code>socket()</code>函数，创建网络协议IPV4，传输协议为<code>TCP</code> 的<code>Socket</code>，接着调用 <code>bind()</code>函数给这个<code>Socket</code>绑定IP和端口，接着会调用 <code>listen()</code> 函数监听连接接入，通过 <code>accept()</code>函数等待连接连入，如无客户端连接则阻塞，客户端则在创建好 <code>Socket</code> 后调用 <code>connect()</code> 函数发起连接，指定服务端的IP及端口，然后通过<code>TCP</code>的三次握手后连接建立完成</p><p>这个连接过程中，监听和连接的<code>Socket</code> 实际上是两个<code>Socket</code></p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/16/T9V5Uf.png" alt="T9V5Uf.png" title="">                </div>                <div class="image-caption">T9V5Uf.png</div>            </figure><p>通过上图可以发现，<code>Socket</code>本质上与文件传输很接近，而Linux一切皆文件的概念，<code>Socket</code>本质上也是文件，而上面这种<code>Socket</code>通信，是最简单的一对一通信，当服务端未处理完一个客户端的网络I&#x2F;O时则会阻塞，而这个时候其他客户端是无法连接的，只能等待</p><h2 id="多进程模型"><a href="#多进程模型" class="headerlink" title="多进程模型"></a>多进程模型</h2><p>基于上述的<code>Socket</code>阻塞传输I&#x2F;O，衍生出了多进程模型，即为每个连接进来的客户端都分配一个进程去处理，阻塞也只阻塞当前进程，服务器主进程通过<code>accept()</code>监听客户端连接，当接收到连接后，调用系统<code>fork()</code>函数创建子进程，将父进程的一切内容复制到子进程中，这种复制更像是一种指针，通过子进程来继续与客户端通信，待子进程处理完后再返回给父进程，通过不同的返回值，子进程为 <code>0</code>。</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/16/T9eyXd.png" alt="T9eyXd.png" title="">                </div>                <div class="image-caption">T9eyXd.png</div>            </figure><p>这种做法很容易出现垃圾无法回收的问题，子进程无法销毁，因此父进程可以调用<code>wait()</code>和<code>waitpid()</code>来回收子进程</p><p>这种多进程模型的缺点在于，不断地fork子进程会造成大量的进程间上下文切换，而且进程并不足够<code>轻量</code>，每次创建进程则也需要创建对应的 堆栈.寄存器等一系列资源</p><h2 id="多线程模型"><a href="#多线程模型" class="headerlink" title="多线程模型"></a>多线程模型</h2><p>通过上面的多进程模型理念可以看出，不够<code>轻量</code>会导致更多的负载，那么后续又衍生出了多线程模型的概念，既然进程不满足那么就从多线程去下手</p><p>通过<code>线程池</code>的概念，连接连接进来时，将已连接的<code>Socket</code>塞到<code>Socket</code>等待队列中，另一边从线程池不断地取出已连接的<code>Socket</code>，然后创建线程交给线程去处理</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/16/T9Ju7D.png" alt="T9Ju7D.png" title="">                </div>                <div class="image-caption">T9Ju7D.png</div>            </figure><p>结合之前的文章，实际应用中，每个创建的线程创建后都需要加锁，避免资源竞争问题</p><p>而这种多线程的做法很大程度上提高了一些效率，也减少了上下文切换的资源消耗问题，但是当数量很大的请求过来时，维护一个超大数量的线程池，或者说给线程池加上限，这并不是一个很好的做法，而维护也更麻烦，调度可能就会宕机，调度宕机也就面临着不可预测的问题。</p><h2 id="I-O多路复用"><a href="#I-O多路复用" class="headerlink" title="I&#x2F;O多路复用"></a>I&#x2F;O多路复用</h2><p>多路复用的概念则是从源头出发，这种一对一的方式显然不是最好的，那么就衍生出了 <code>一个进程/线程 对应多个Socket的技术</code></p><p>一个进程同时只能处理一个<code>Socket</code>，但是如果将这个任务时间控制到毫秒微妙级时，将多个<code>Socket</code>都指向同一个进程则是多路复用，他与CPU的并发模型很接近，也被称为<code>时分多路复用</code></p><p>I&#x2F;O 复用其实复用的不是 I&#x2F;O 连接，而是复用线程，让一个 thread of control 能够处理多个连接（I&#x2F;O 事件）</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/16/T9YOs0.png" alt="T9YOs0.png" title="">                </div>                <div class="image-caption">T9YOs0.png</div>            </figure><h3 id="select"><a href="#select" class="headerlink" title="select"></a>select</h3><p>将已连接的<code>Socket</code>放到一个<code>文件描述集合(类指针)</code>中，调用<code>select</code>函数将集合拷贝到内核中，内核遍历其中的<code>Socket</code>是否有事件产生，然后将其标记为<code>可读</code>,<code>可写</code>标识，将改过的集合送回用户态，然后用户态则继续遍历找到<code>可读</code>,<code>可写</code>的<code>Socket</code>对其处理</p><p><code>select</code>使用<code>bitsmap</code>标识<code>文件描述集合</code>，所支持的描述符个数有限制，在Linux中的<code>FD_SETSIZE</code>限制，默认最大值是<code>1024</code>，因此只能监听<code>0~1023</code>个<code>文件描述符</code></p><h3 id="poll"><a href="#poll" class="headerlink" title="poll"></a>poll</h3><p>poll与select很接近，只是不采用bitsmap存储，改用了链表，解除了限制</p><p>但由于结构未变，因此poll与select都有遍历两次循环的问题，且都需要复制两次集合的操作</p><h3 id="epoll"><a href="#epoll" class="headerlink" title="epoll"></a>epoll</h3><p><code>epoll</code>的诞生就是为了解决<code>select/poll</code>留下的问题，且目前<code>epoll</code>的应用场景也很多</p><p>关于存储文件描述符，<code>epoll</code>使用红黑树来跟踪进程所有待检测的文件描述符，将需要监控的 <code>Socket</code> 使用 <code>epoll_ctl()</code> 函数将其加入至内核中的红黑树中，这样检查 <code>Socket</code> 是否有事件发生则只需要传入一个待检测的 <code>Socket</code> 即可，不需要整个集合复制，减少了多次数据拷贝的问题</p><p><code>epoll</code> 使用事件驱动，内核中维护一个链表来记录就绪事件，当 <code>Socket</code> 发生了事件时，内核会将其加入这个链表中，用户调用 <code>epoll_wait()</code> 时，只返回链表（事件发生的个数）即可，不需要整个集合返回</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/16/T9aLhF.png" alt="T9aLhF.png" title="">                </div>                <div class="image-caption">T9aLhF.png</div>            </figure><p><strong>水平触发</strong></p><p>实则上面的 select&#x2F;poll&#x2F;epoll 都支持水平触发，当<code>Socket</code>有可读事件发生时，服务端<code>不断</code>地苏醒，直到<code>read</code>函数执行完才停止</p><p><strong>边缘触发</strong></p><p>epoll独有的边缘触发，当 <code>Socket</code> 有可读事件发生时，服务端从 <code>epoll_wait</code> 中苏醒，并执行<code>read</code>读取数据，由于他只苏醒一次的概念，因此我们在读取时要一次性将数据读完</p><p>边缘触发是循环从<code>文件描述符</code>读写数据，那么如果<code>文件描述符</code>是阻塞的，没有数据可读写时，进程会阻塞在读写函数那里，程序就没办法继续往下执行。所以，边缘触发模式一般和非阻塞 I&#x2F;O 搭配使用，程序会一直执行 I&#x2F;O 操作，直到系统调用(如 read 和 write)返回错误，错误类型为 EAGAIN 或 EWOULDBLOCK</p><h3 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h3><p>多路复用 API 返回的事件并不一定可读写的，因此使用多路复用时最好配合 <code>非阻塞 I/O</code>一起使用，应对特殊情况</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Socket&quot;&gt;&lt;a href=&quot;#Socket&quot; class=&quot;headerlink&quot; title=&quot;Socket&quot;&gt;&lt;/a&gt;Socket&lt;/h2&gt;&lt;p&gt;Linux一切皆文件的概念，都可以用“打开open –&amp;gt; 读写write&amp;#x2F;read –&amp;gt</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>一文搞懂Linux I/O流</title>
    <link href="https://sbcoder.cn/2021/12/13/One-Linux-IO.html"/>
    <id>https://sbcoder.cn/2021/12/13/One-Linux-IO.html</id>
    <published>2021-12-13T03:29:48.000Z</published>
    <updated>2021-12-14T07:40:16.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Linux中的I-O操作"><a href="#Linux中的I-O操作" class="headerlink" title="Linux中的I&#x2F;O操作"></a>Linux中的I&#x2F;O操作</h2><h3 id="缓冲与非缓冲-I-O"><a href="#缓冲与非缓冲-I-O" class="headerlink" title="缓冲与非缓冲 I&#x2F;O"></a>缓冲与非缓冲 I&#x2F;O</h3><ul><li><p>缓冲 I&#x2F;O，利用的是标准库的缓存实现文件的加速访问，而标准库再通过系统调用访问文件。</p></li><li><p>非缓冲 I&#x2F;O，直接通过系统调用访问文件，不经过标准库缓存。</p></li></ul><p>程序在读写操作时系统并不会立刻返回数据或者处理数据，系统会监听操作并存储在缓冲区，例如<code>C</code>中的 <code>Scanf</code> 操作，只有在用户敲下了回车时才能真正将输入的字符写入，而输入的过程中可能有删除有追加，他们都是存储在缓冲区的</p><p>而非缓冲则是使程序直接访问文件系统，直接读取文件内容</p><h3 id="直接与非直接I-O"><a href="#直接与非直接I-O" class="headerlink" title="直接与非直接I&#x2F;O"></a>直接与非直接I&#x2F;O</h3><p>「是否利用操作系统的缓存」，可以把文件 I&#x2F;O 分为直接 I&#x2F;O 与非直接 I&#x2F;O</p><p>在操作文件时 可以使用参数<code>O_DIRECT</code>来指定是否需要直接I&#x2F;O，如果有此参数则说明不需要走操作系统缓存IO</p><p>他与缓冲I&#x2F;O不同在于，一个是操作系统缓存，一个是标准库缓存</p><p>例如在Go语言中，利用Go的StringBuffer，可以先将待写入的文件存入系统缓存中，待到调用 <code>write</code> 时才真正的写入到文件中</p><h3 id="阻塞I-O与异步I-O"><a href="#阻塞I-O与异步I-O" class="headerlink" title="阻塞I&#x2F;O与异步I&#x2F;O"></a>阻塞I&#x2F;O与异步I&#x2F;O</h3><p>用户在发起I&#x2F;O请求时，内核态会阻塞该线程，直到内核态准备好数据将数据移到程序的缓冲区阻塞才会解除</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/14/ojr1Fe.png" alt="ojr1Fe.png" title="">                </div>                <div class="image-caption">ojr1Fe.png</div>            </figure><p>而非阻塞I&#x2F;O是在请求后立即返回，如果没有得到结果则反复请求的过程</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/14/ojsFnP.png" alt="ojsFnP.png" title="">                </div>                <div class="image-caption">ojsFnP.png</div>            </figure><p>如果设置了 <code>O_NONBLOCK</code> 标志，那么就表示使用的是非阻塞 I&#x2F;O 的 方式访问，而不做任何设置的话，默认是阻塞 I&#x2F;O。</p><p>这种I&#x2F;O轮询的方式会拖慢整个线程的速度，因此I&#x2F;O多路复用就出现了</p><p>而I&#x2F;O多路复用也是基于非阻塞I&#x2F;O的衍生，实际上IO多路复用也是从内核态阻塞线程变更到内核态阻塞，当数据准备好后再通知线程，这样做的好处是可以将CPU的利用率达到更高</p><p>而实际上上面所说的阻塞 非阻塞 基于非阻塞的I&#x2F;O多路复用实际上<code>本质都是同步I/O</code></p><p>而异步I&#x2F;O则是在内核态阻塞后立即返回，当数据处理好后再通知线程</p><h2 id="文件"><a href="#文件" class="headerlink" title="文件"></a>文件</h2><h3 id="DMA"><a href="#DMA" class="headerlink" title="DMA"></a>DMA</h3><p>在<code>DMA</code>技术没有应用时，I&#x2F;O的过程是这样的</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/14/ovkTdH.png" alt="ovkTdH.png" title="">                </div>                <div class="image-caption">ovkTdH.png</div>            </figure><p>当接收到程序发送的 I&#x2F;O 请求时，CPU会直接阻塞住，处理数据，等待I&#x2F;O处理完成后才能继续执行任务</p><p>DMA则是在这之中起到了一个中间价的作用，当CPU接收到请求时，会把任务扔给DMA就去做别的事去了，DMA将处理请求给磁盘，磁盘将缓冲区数据拷贝到内核缓冲区，当DMA读取到了足够的数据会给CPU发送中断信号，CPU接收到信号后将内核缓冲区数据返回给用户态，返回数据</p><h3 id="文件传输"><a href="#文件传输" class="headerlink" title="文件传输"></a>文件传输</h3><h4 id="socket传输"><a href="#socket传输" class="headerlink" title="socket传输"></a>socket传输</h4><p>Socket是一种可以远程可以本地传输的套接字，可以理解为一个接口，他的应用场景非常多，可以连接应用程序，可以连接网络层，websocket也正是借鉴了socket的特性开发出的一种协议</p><p>实际应用中，我们也是使用socket作为文件传输工具，也可以说，很多I&#x2F;O操作也都是使用了Socket来操作的，而我们文件传输则需要socket来作为连接网卡的接口来使用</p><h4 id="mmap"><a href="#mmap" class="headerlink" title="mmap"></a>mmap</h4><p>文件拷贝时，相当于 先 <code>read</code> 再 <code>write</code></p><p>应用发起<code>read</code>操作时，应用调用 <code>mmap()</code> 可以将内核缓冲区的数据映射到用户缓冲区里面</p><p>当应用调用 <code>mmap()</code>时，DMA会将磁盘的数据拷贝到内核缓冲区，然后将应用进程及内核共享此内容，然后调用<code>write</code>，操作系统将内核缓冲区的内容拷贝到Socket缓冲区，最后把Socket缓冲区的内容拷贝到网卡缓冲区，整个过程都是由DMA操作的</p><h4 id="sendfile（零拷贝）"><a href="#sendfile（零拷贝）" class="headerlink" title="sendfile（零拷贝）"></a>sendfile（零拷贝）</h4><p>在 Linux 内核版本 2.1 中，提供了一个专⻔发送文件的系统调用函数 <code>sendfile()</code> ，函数形式如下</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;sys/socket.h&gt;</span></span></span><br><span class="line"><span class="type">ssize_t</span> <span class="title function_">sendfile</span><span class="params">(<span class="type">int</span> out_fd, <span class="type">int</span> in_fd, <span class="type">off_t</span> *offset, <span class="type">size_t</span> count)</span>;</span><br></pre></td></tr></table></figure><p>它的前两个参数分别是目的端和源端的文件描述符，后面两个参数是源端的偏移量和复制数据的⻓度，返回值是实际复制数据的⻓度，通过<code>sendfile</code>调用来发送数据，则可以替代 read + write 的操作，这样就只调用一次文件拷贝，减少了上下文开销且该方法类似<code>mmap</code>可以直接跳过用户态将内核态数据复制到 <code>socket缓冲区</code></p><p>而网卡如果支持<code>SG-DMA</code>技术的话则可以在此基础上更近一步，跳过<code>socket缓冲区</code>直接将数据发送到网卡缓冲区</p><p>通过以下命令查看是否支持</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ethtool -k eth0 | grep scatter-gather</span><br></pre></td></tr></table></figure><p>在 Linux 2.4之后的版本，通过调用<code>sendfile()</code>来实现复制，如果网卡支持<code>SG-DMA</code>则复制文件则会产生如下操作</p><p>第一步，通过 DMA 将磁盘上的数据拷⻉到内核缓冲区里;</p><p>第二步，缓冲区描述符和数据⻓度传到 socket 缓冲区，这样网卡的 SG-DMA 控制器就可以直接将内 核缓存中的数据拷⻉到网卡的缓冲区里，此过程不需要将数据从操作系统内核缓冲区拷⻉到 socket 缓冲区中，这样就减少了一次数据拷⻉;</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/14/ovu7GQ.png" alt="ovu7GQ.png" title="">                </div>                <div class="image-caption">ovu7GQ.png</div>            </figure><p>这就是所谓的零拷⻉(Zero-copy)技术，因为我们没有在内存层面去拷⻉数据，也就是说全程没有通过 CPU 来搬运数据，所有的数据都是通过 DMA 来进行传输的，总体来看，零拷⻉技术可以把文件传输的性能提高至少一倍以上</p><p>类似零拷贝技术的应用场景有很多，例如 ：</p><p>kafka内部使用的<code>transferTo()</code>实际上就是调用 <code>sendfile</code></p><p>nginx通过配置可以选择是否开启<code>sendfile</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">http &#123; </span><br><span class="line">...</span><br><span class="line">sendfile on </span><br><span class="line">...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="大文件传输"><a href="#大文件传输" class="headerlink" title="大文件传输"></a>大文件传输</h4><p>大文件传输很少使用同步传输，由于文件的不可确定性，小文件更适合使用同步传输，大文件由于占用时间过长，如果一直等待的情况下，会让CPU一直阻塞，因此大文件通常使用 <code>异步 I/O + 直接 I/O</code>来替代零拷贝技术</p><p>nginx中则可以使用 如下配置</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">location /sbcoder.cn/ &#123;</span><br><span class="line">    sendfile on;</span><br><span class="line">    aio on;</span><br><span class="line">    directio 1024m;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Linux中的I-O操作&quot;&gt;&lt;a href=&quot;#Linux中的I-O操作&quot; class=&quot;headerlink&quot; title=&quot;Linux中的I&amp;#x2F;O操作&quot;&gt;&lt;/a&gt;Linux中的I&amp;#x2F;O操作&lt;/h2&gt;&lt;h3 id=&quot;缓冲与非缓冲-I-O&quot;&gt;&lt;a </summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>多线程中的资源竞争</title>
    <link href="https://sbcoder.cn/2021/12/06/Process-Thread-Competition.html"/>
    <id>https://sbcoder.cn/2021/12/06/Process-Thread-Competition.html</id>
    <published>2021-12-06T05:54:50.000Z</published>
    <updated>2021-12-07T02:37:22.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="资源竞争问题"><a href="#资源竞争问题" class="headerlink" title="资源竞争问题"></a>资源竞争问题</h2><p>当我们有两个线程同时操作同一块儿内存空间时，就容易出现资源竞争问题，这种问题目前有各种各样的出现情况，但在分布式系统中，或者说多线程任务中都是需要处理的</p><p>多线程是线程阻塞通过调度器去协调处理的，那么按理说即使是多线程实际上也都是串行操作，为什么也会出现资源竞争呢？</p><p>如下图</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/06/osnXcQ.png" alt="osnXcQ.png" title="">                </div>                <div class="image-caption">osnXcQ.png</div>            </figure><p>当进入线程操作时，会先把变量存的值存入寄存器，待到处理完后在重新放回i的所属内存空间，那么当在放回内存时就有可能覆盖掉上一个线程操作的值，也就出现了资源竞争</p><h2 id="解决策略"><a href="#解决策略" class="headerlink" title="解决策略"></a>解决策略</h2><h3 id="互斥"><a href="#互斥" class="headerlink" title="互斥"></a>互斥</h3><p>由于多线程执行操作共享变量的这段代码可能会导致竞争状态，因此我们将此段代码称为临界区(critical section)，它是访问共享资源的代码片段，一定不能给多线程同时执行。我们希望这段代码是互斥(mutualexclusion)的，也就说保证一个线程在临界区执行时，其他线程应该 被阻止进入临界区，说白了，就是这段代码执行过程中，最多只能出现一个线程。</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s4.ax1x.com/2021/12/06/osKHSS.png" alt="osKHSS.png" title="">                </div>                <div class="image-caption">osKHSS.png</div>            </figure><p>这种行为也被称为 <code>互斥</code>，通过阻塞完成</p><h3 id="同步"><a href="#同步" class="headerlink" title="同步"></a>同步</h3><p>另外还有一种Go语言中常用的操作是 <code>同步</code>，当任务一和任务二同时执行时，任务二的某处任务需要等到等到任务一执行完得到的数据才能继续执行任务二，相当于Go中的信道阻塞<code>select</code>，只有取到数据才执行否则就一直阻塞</p><h3 id="原子操作与锁"><a href="#原子操作与锁" class="headerlink" title="原子操作与锁"></a>原子操作与锁</h3><p>原子操作，类似于事务，原子操作就是要么全部执行，要么都不执行，不能出现执行到一半的中间状态</p><p>锁的概念与进程资源锁一样，进程中通过信号判断是否可以执行，而在线程中，可以通过代码来处理</p><p>声明一个变量存储 0 1 为占用状态，为 0 时进入等待队列，使用while循环等待，直到为1时才可执行，这只是一种最简单的锁</p><h3 id="信号量"><a href="#信号量" class="headerlink" title="信号量"></a>信号量</h3><p>信号量则是一个类似线程池的概念，通过信号量控制线程数，当一个方法被多个线程调用时，每个线程进入方法时就增加信号量的值，直到一个负荷后阻塞后来的线程进入等待队列，当信号量发生变更时再决定是否要让新的线程进入</p><p>而信号量同样可以适用于更丰富的场景，当程序需要同时执行两块儿代码段时，那就需要占两个锁，而进入第一个锁时，另外的程序占用了第二块儿程序，就无法出现同时占两个锁的情况，也有可能造成同时的阻塞，通过信号量则可以处理此类问题，将程序1加入信号量，程序2也加入信号量，当信号量为2时可以执行两个程序，如果线程1占用了一个锁，那么线程2看到自己没有抢到锁且信号量为1则直接进入等待队列，线程1则继续拿第二个锁，程序执行完时释放加回信号量即可</p><h3 id="读写问题"><a href="#读写问题" class="headerlink" title="读写问题"></a>读写问题</h3><p>「读-读」允许:同一时刻，允许多个读者同时读<br>「读-写」互斥:没有写者时读者才能读，没有读者时写者才能写<br>「写-写」互斥:没有其他写者时，写者才能写</p><p>通过信号量来处理读写问题，所有的操作都存储于队列，当写操作开始时，所有其他任务都终止。即当写操作的信号量为0时才可以进行读操作，读操作信号量不为0时写操作不允许执行，所有任务以队列形式进入，因此，此为公平的读写操作</p><h2 id="锁的安全性"><a href="#锁的安全性" class="headerlink" title="锁的安全性"></a>锁的安全性</h2><h3 id="deadlock"><a href="#deadlock" class="headerlink" title="deadlock"></a>deadlock</h3><p>死锁，一个生产环境上最为可怕的错误之一，他的形成原因大概可以被解释为，程序1和程序2都在等待对方结束才可执行，结果造成了无限期的等待，程序就此卡死，典型的死锁场景</p><p>死锁一般长出现于并发线程场景，满足如下条件时会发生</p><ul><li><code>互斥条件</code>，互相等待对方结束后才可继续执行，一次两个或多个线程同时阻塞</li><li><code>持有并等待条件</code>，持有资源一后需要拿到资源二的时候发生，不释放资源一（参照哲学家就餐的问题，可以按照规定顺序拿资源解决，按场景使用信号量解决）</li><li><code>不可剥夺条件</code>，当线程A持有资源时，必须等到线程A结束时线程B才可获取</li><li><code>环路等待条件</code>，两个线程获取的资源形成环形链，死循环造成死锁</li></ul><p>在Go语言中可以使用pprof来跟踪堆栈获取死锁行为的信息</p><h3 id="死锁解决策略"><a href="#死锁解决策略" class="headerlink" title="死锁解决策略"></a>死锁解决策略</h3><p>所有的资源全部按顺序获取，例如强制线程来的时候先拿A资源再拿B资源，当A信号量不足时线程阻塞等待，直到 A，B资源同时被上一个线程拿到后再释放信号量</p><p>这么做的目的是为了资源的合理分配，而这种情况也会导致资源的缓慢阻塞问题，要最大化的利用则可以根据场景去制定更好的合理化资源分配方案</p><h3 id="自旋锁还是互斥锁"><a href="#自旋锁还是互斥锁" class="headerlink" title="自旋锁还是互斥锁"></a>自旋锁还是互斥锁</h3><p>简单来说，互斥锁是通过内核态由CPU调度处理的锁，当程序没有拿到锁的时候会直接释放CPU，进入睡眠等待，也就是上下文切换，等到拿到锁的时候再唤醒</p><p>自旋锁是发生于用户态的锁，由用户程序控制，通俗地讲使用<code>while</code>去轮询获取锁，也算是阻塞等待了，这种操作在Go语言中还挺常见的（所以我总是认为Go的设计理念很大部分都是基于用户态的），CPU提供了<code>PAUSE</code>函数去等待获取锁，相对于<code>while</code>他可以有效减少耗电量，自旋锁可以通过CPU去加锁，CPU提供了<code>CAS</code>函数来加锁，也可以用户自定义锁的方式来做</p><h3 id="是否有必要读优先或者写优先"><a href="#是否有必要读优先或者写优先" class="headerlink" title="是否有必要读优先或者写优先"></a>是否有必要读优先或者写优先</h3><p>字面意思，读优先是，不管什么情况下，读写锁，只要有读操作的线程加入，那么写就要向后排，直到所有的读操作结束写操作才能结束，而写优先则反之</p><p>这种情况可以有效地解决一些并发场景，但一昧的单条优先行为，可能会导致 读或者写长期阻塞（<code>饥饿</code>），这并不是开发者愿意看到的，所以使用这种读写优先锁，还是要谨慎</p><h3 id="悲观锁和乐观锁"><a href="#悲观锁和乐观锁" class="headerlink" title="悲观锁和乐观锁"></a>悲观锁和乐观锁</h3><p>首先，为了安全性稳定性，我们上述的所有操作都属于悲观锁</p><p>乐观锁是什么呢？它的工作方式是，先修改完共享资源，再验证这段时间内 有没有发生冲突，如果没有其他线程在修改资源，那么操作完成，如果发现有其他线程已经修改过这个资源，就放弃本次操作，释放寄存器。</p><p>反之悲观锁是只要占用上就不能继续操作</p><p>但某些场景下，为了效率，有的人也推荐使用乐观锁</p><p>例如在线文档，如果使用悲观锁，那么有人进入文档操作时，剩下的人都得等待，直到编写完成后才能查看或写入，使用乐观锁则可以通过数据判断修改内容，达成在线多人文档的需求</p><p>我们常用的<code>Git</code>和<code>Svn</code>等常见的版本控制工具也都是借鉴了这种想法思路</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;资源竞争问题&quot;&gt;&lt;a href=&quot;#资源竞争问题&quot; class=&quot;headerlink&quot; title=&quot;资源竞争问题&quot;&gt;&lt;/a&gt;资源竞争问题&lt;/h2&gt;&lt;p&gt;当我们有两个线程同时操作同一块儿内存空间时，就容易出现资源竞争问题，这种问题目前有各种各样的出现情况，但在分</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>进程与线程,概念及优化空间</title>
    <link href="https://sbcoder.cn/2021/12/01/Process-Thread-Optimization.html"/>
    <id>https://sbcoder.cn/2021/12/01/Process-Thread-Optimization.html</id>
    <published>2021-12-01T02:36:57.000Z</published>
    <updated>2021-12-03T09:18:26.000Z</updated>
    
    <content type="html"><![CDATA[<p>本文以Go语言为基础</p><h2 id="进程"><a href="#进程" class="headerlink" title="进程"></a>进程</h2><h3 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h3><p>将编译好的的二进制程序，在系统中执行起来的程序会被CPU装载到内存中，CPU会按照程序的指令去顺序执行程序，这个执行中的程序被称之为进程，多个程序同时执行则被称为多进程</p><p>单核CPU在执行任务过程中不能同时执行多余的任务，但是我们在实际场景中往往可以看到一台电脑有非常多的进程在运行，这就引出了进程的中断，当程序在读写硬盘这种慢IO操作时，当前进程会发出中断指令，使得CPU去执行下一个进程，防止了阻塞等待的问题，而CPU的执行效率是非常快的，所以更多时候即使他是串行执行程序，但也可以完美接收并发任务</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/01/o8RNHH.png" alt="o8RNHH.png" title="">                </div>                <div class="image-caption">o8RNHH.png</div>            </figure><p>值得注意的是，并发和并行并非一样的东西，并发是代表一个CPU核心同时处理多个任务的情况，而并行是多个CPU核心处理多个任务</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/01/o8RSBQ.png" alt="o8RSBQ.png" title="">                </div>                <div class="image-caption">o8RSBQ.png</div>            </figure><p>当进程中有大量硬盘IO操作时，将会出现大量的进程阻塞行为，而这种情况可能会占用大量的物理内存，在虚拟内存中，则会将这种阻塞的进程物理内存地址转移至硬盘地址，直至阻塞结束后再替换回物理内存中</p><p>而这种进程的执行过程也可以分为 创建、终止、阻塞、唤醒 的过程</p><h2 id="线程"><a href="#线程" class="headerlink" title="线程"></a>线程</h2><h3 id="基本概念-1"><a href="#基本概念-1" class="headerlink" title="基本概念"></a>基本概念</h3><p>一个进程可以有一个或多个线程</p><p>个人认为 ~ 线程是进程的抽象化，当一个进程只有一个线程时，那么这个线程就是进程</p><p>线程与进程，进程容纳了所有的资源，内存文件及各种单位，线程则只有寄存器和栈，线程与进程相同，同样有 阻塞和唤醒。</p><p>线程只有寄存器和栈的特性，以至于创建一个线程比创建进程更方便快捷，占用资源更少，当然前提是这些线程之间的共享资源大部分相同</p><p>进程占用资源，线程执行过程，线程都是依托于进程的，线程之间可以共享进程的资源</p><h3 id="三种形式"><a href="#三种形式" class="headerlink" title="三种形式"></a>三种形式</h3><ul><li>用户线程 （User Thread）</li><li>内核线程 （Kennel Thread）</li><li>轻量线程 （LightWeight Thread）</li></ul><p>首先要明确一个事实，他们并不是同一个维度的，多个用户线程对应多个内核线程，也就是他们是多对多的关系（协程则相当于一个内核线程对应了多个用户线程）</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/01/oG86l6.png" alt="oG86l6.png" title="">                </div>                <div class="image-caption">oG86l6.png</div>            </figure><p>通常我们常说的线程大部分指的是内核线程 ~</p><p>用户线程是由用户发起的调用，操作系统无法干预，当用户线程执行过程中，操作系统无法查看当前线程的情况也无法由操作系统关闭，即任务管理器也没用（协程则可以通过 pprof 之类的debug工具去测试）</p><p>用户线程相当于用户自发开启的线程，不通过系统内核，也可以认为启动用户线程的速度要比内核线程要快的多，也因为如此，即使是不支持线程的系统，也能由用户自发开启的线程来开启用户线程无需兼容内核</p><p>内核线程则是通过操作系统调用的，可以通过操作系统去管理该线程，相比于用户线程，内核线程的资源分配更加合理，且用户线程可能会因为阻塞导致多个线程同时阻塞，而内核线程的调度则由操作系统直接完成，无需考虑这一问题，但相比于用户线程，显然内核线程要更重量级一些</p><p>轻量线程有多重解释，它相当于内核线程与用户线程的对应和结合，相当于用户线程与内核线程的桥梁或者中间层，与用户线程也是，多对多的关系，兼容三种模式 1:1 N:1 N:N</p><p>1:1 一个用户线程 对应一个轻量线程 对应一个内核线程<br>N:1 多个用户线程对应一个轻量线程 对应一个内核线程<br>N:N 混合模式，前面两种方式的结合，多个用户线程对应多个轻量线程，由轻量线程找到内核线程一一对应</p><h2 id="调度"><a href="#调度" class="headerlink" title="调度"></a>调度</h2><h3 id="调度模型"><a href="#调度模型" class="headerlink" title="调度模型"></a>调度模型</h3><p>进程调度，当出现IO请求的时候，调度会将当前执行的进程切换到另一个进程，并保留上下文，以便于稍后切换回来时能够继续执行之前的进程</p><p>进程调度，当出现长时间占用CPU的进程时，造成系统吞吐量降低，调度会权衡任务完成数量</p><p>如果一个进程本身计算不复杂，而占用时间长时，需要考虑是否是IO的调用导致的，频繁的IO请求会增加CPU的进程切换，也会加大程序的执行时长</p><p>调度对于鼠标键盘等需要实时响应的程序会优先考虑</p><p>进程如果处于就绪状态，调度会尽快让进程继续执行</p><p>进程之间会通过内核的时间分片去模拟出并发场景，当单核CPU出现三个进程时，如果都没有阻塞，则调度会通过时间分片的方式先完成简单的程序然后再完成复杂程序，ABC三个进程同时存在时，按照进程顺序， A B C，内核会分配一个固定时间分片，例如 5ns，A执行5ns后执行B，B执行5ns后执行C，假设进程B执行完成时，则调度会继续A C之间的循环，B完成后执行C，C执行5ns后执行A，然后循环执行A C</p><p>如上操作会出现一个问题就是内核会频繁的切换进程，我们知道上下文也是消耗资源的，那么内核会做一个递增时间分片的操作，例如一开始是5ns，后续可能就递增为 10ns 15ns，以便于尽早完成一个进程减少进程上下文</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/03/oaUUtx.png" alt="oaUUtx.png" title="">                </div>                <div class="image-caption">oaUUtx.png</div>            </figure><h3 id="通信"><a href="#通信" class="headerlink" title="通信"></a>通信</h3><p><strong>管道</strong><br>在Linux中我们常用的通信管道，<code>|</code>，如下命令中 <code>ps -ef |grep sbcoder</code> ，里面的符号位 <code>|</code> 就是一个管道，他代表将前一个进程中的数据带到下一个进程中</p><p>这种没有命名的管道被称之为 匿名管道，匿名管道将在进程结束后释放，有匿名则也有有名字的管道 命名管道 ，Linux中通过关键字 <code>mkfifo</code> 创建命名管道 <code>mkfifo sbcoderChannel</code>，通过命令可以将数据传输至管道中，<code>echo &quot;sbcoder&quot; &gt; sbcoderChannel</code>，接着命令就卡住了，这与Go语言中的信道很类似，有阻塞的作用通过阻塞我们可以做很多事情，有入则有出，可以通过命令取出数据 <code>cat &lt; sbcoderChannel</code> 获取刚才echo进去的数据</p><p>管道实际上是内核中的缓存，而读取管道数据则是在一个进程中fork出一个子进程去读取，而如果由一个进程同事负责读写则会非常混乱，所以如果需要双向通信则需要fork两个子进程，而创建子进程也会徒增负荷，也要尽可能避免此类操作</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/03/oa1uHf.png" alt="oa1uHf.png" title="">                </div>                <div class="image-caption">oa1uHf.png</div>            </figure><p><strong>消息队列</strong><br>消息队列是保存在内核中的消息链表，由于消息队列的特性，会出现通信不及时和大小限制问题，更适合小数据的场景</p><p><strong>共享内存</strong><br>进程A与进程B都使用虚拟内存（只保存物理地址），则可以实现同一个数据块儿被两个进程同时使用</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/03/oa38IO.png" alt="oa38IO.png" title="">                </div>                <div class="image-caption">oa38IO.png</div>            </figure><p>当A和B同时操作一块儿内存时，则也会出现问题，很容易造成数据冲突，就出现了<code>lock</code>的概念，也被称为 <code>信号量</code>，A操作时将信号量数值更改，B同时操作时发现数值已经被更改则说明资源被占用，进程阻塞，A在操作完成后会将信号量数值再改回去，B此时即可继续执行</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/12/03/oa89YD.png" alt="oa89YD.png" title="">                </div>                <div class="image-caption">oa89YD.png</div>            </figure><p><strong>信号Signal</strong></p><p>信号，也就是Signal，通过进程中的各种指令做通信，例如：程序接收到快捷键 <code>ctrl + c</code> 则会终止程序</p><p>Go语言中的Signal同理~</p><p><strong>socket</strong></p><p>不同主机之间的socket通信，为了方便不同主机之间的进程通信，衍生出的通信方式，他可以借助 TCP以及UDP以及本地进程等方式通信，其中TCP和UDP更适用于远程主机通信，而本地通信可以借助本地进程通信（字节流，数据报）</p><h2 id="思考"><a href="#思考" class="headerlink" title="思考"></a>思考</h2><ul><li>高并发场景是否应该频繁读取硬盘信息呢</li></ul><p>个人感觉可以通过一个大文本读取至内存，然后并发处理的过程中将会很少产生阻塞行为，但也属于物理内存充足的情况下（空间换时间）</p><ul><li>如何更好的利用进程特性处理高并发任务</li></ul><p>我们了解并发实际也是自上至下的串行执行程序，那么也要适当地减少并发任务的复杂度和频繁的IO操作，但合理运用内存很重要，如果能计算出什么时间内物理内存的占用情况则更合理一些</p><ul><li>单内核多进程调度场景，如何设计更适合的程序结构</li></ul><p>个人认为，应该尽可能减少进程数量，在用户态之间搞定，类似Go的GMP调度，如果进程数量实在无法减少可以尝试将某些轻量级程序减负，让重量级的程序保持，多应用消息队列的方式进行通信（过多使用消息队列也是负担），需要综合考量异步的优缺点</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;本文以Go语言为基础&lt;/p&gt;
&lt;h2 id=&quot;进程&quot;&gt;&lt;a href=&quot;#进程&quot; class=&quot;headerlink&quot; title=&quot;进程&quot;&gt;&lt;/a&gt;进程&lt;/h2&gt;&lt;h3 id=&quot;基本概念&quot;&gt;&lt;a href=&quot;#基本概念&quot; class=&quot;headerlink&quot; title=</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>物理内存与虚拟内存与Swap内存</title>
    <link href="https://sbcoder.cn/2021/11/30/Memory-Optimization.html"/>
    <id>https://sbcoder.cn/2021/11/30/Memory-Optimization.html</id>
    <published>2021-11-30T03:48:38.000Z</published>
    <updated>2021-11-30T06:15:06.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="区别"><a href="#区别" class="headerlink" title="区别"></a>区别</h2><h3 id="物理内存"><a href="#物理内存" class="headerlink" title="物理内存"></a>物理内存</h3><p>物理内存是真实的内存空间，通过物理内存地址，标记存储的数据，物理内存的实际大小也与内存条有关，由内核直接调用使用</p><h3 id="虚拟内存"><a href="#虚拟内存" class="headerlink" title="虚拟内存"></a>虚拟内存</h3><p>虚拟内存是物理内存的映射关系，为了防止程序开辟不同的物理内存空间，或者多处占用，则由操作系统去调度，使得进程在调用使用内存时需要通过虚拟内存的映射找到对应的物理内存地址，最终才能使用存储数据</p><p>如下图所示</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/30/olRoWT.png" alt="olRoWT.png" title="">                </div>                <div class="image-caption">olRoWT.png</div>            </figure><h3 id="Swap内存空间"><a href="#Swap内存空间" class="headerlink" title="Swap内存空间"></a>Swap内存空间</h3><p>Swap内存空间，顾名思义就是交换内存的空间，它的空间是硬盘空间，他是一个很有意思的东西，我们真实的内存空间存储时也是分一段一段去存储的，由于无法连续，那么可能也就无法让性能最大化</p><p>例如下图</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/30/olWiOH.png" alt="olWiOH.png" title="">                </div>                <div class="image-caption">olWiOH.png</div>            </figure><p>游戏，浏览器及音乐各占不同的内存空间，当浏览器进程退出时，操作系统会回收内存空间，但由于它是一段一段存储的，导致后来的程序想要占用200M的内存空间则无法实现，最多只能使用128M。</p><p>而交换空间则应运而生，程序在发生浏览器退出时，会将后面的音乐占用内存放到交换空间中，而后清空游戏后面的内存，再将音乐内存直接放到游戏内存后面，而后面的下一个程序则可以直接占用内存200m</p><p>所以交换空间配置适量的大小也很重要，太大没意义，太小则可能无法满足释放内存的需求，而由于交换空间是硬盘空间，速度显然不是很友好，因此相当大的程序释放（放入）时也许会造成程序卡顿。</p><p>而这种分段的片段，也可以称之为内存分段</p><p>由于内存分段的数量过于庞大，他需要每次程序释放时同时释放内存碎片，为了更好地释放内存，物理内存存储的也是映射关系，也称之为 内存分页，相当于一个索引，一个内存分页存储着不同内存分段的物理地址，而程序只需要通过内存分页即可找到真实的内存数据，由于现实场景中，进程数量的激增，一层分页也无法满足所有，需要每个进程都保存一份分页不太现实，就出现了多级分页，只存储顶级分页及常用的二级分页</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/30/olj5DI.png" alt="olj5DI.png" title="">                </div>                <div class="image-caption">olj5DI.png</div>            </figure><p>总结来说 Swap是硬盘空间，速度较差，它存储的进程数据一般是交换空间数据或者不活跃的进程数据</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>为了在多进程环境下，使得进程之间的内存地址不受影响，相互隔离，于是操作系统就为每个进程独立分 配一套虚拟地址空间，每个程序只关心自己的虚拟地址就可以，实际上大家的虚拟地址都是一样的，但分 布到物理地址内存是不一样的。作为程序，也不用关心物理地址的事情。</p><p>每个进程都有自己的虚拟(内存)空间，而物理内存只有一个，所以当启用了大量的进程，物理内存必然会很紧 张，于是操作系统会通过内存交换技术，把不常使用的内存暂时存放到硬盘(换出)，在需要的时候再装 载回物理内存(换入)。</p><h2 id="划分空间"><a href="#划分空间" class="headerlink" title="划分空间"></a>划分空间</h2><h3 id="C语言中的空间划分"><a href="#C语言中的空间划分" class="headerlink" title="C语言中的空间划分"></a>C语言中的空间划分</h3><p>C语言有着各式各样的内存清理问题，这也是各种C语言BUG的大头</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/30/o1pdmj.png" alt="o1pdmj.png" title="">                </div>                <div class="image-caption">o1pdmj.png</div>            </figure><p>C语言中，动态分配的内存（malloc，mmap）则是动态分配堆和文件的内存 </p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>小林Coding（图解系统）</li></ul><p>近期写一写感谢大佬的电子图书笔记，小白受益良多</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;区别&quot;&gt;&lt;a href=&quot;#区别&quot; class=&quot;headerlink&quot; title=&quot;区别&quot;&gt;&lt;/a&gt;区别&lt;/h2&gt;&lt;h3 id=&quot;物理内存&quot;&gt;&lt;a href=&quot;#物理内存&quot; class=&quot;headerlink&quot; title=&quot;物理内存&quot;&gt;&lt;/a&gt;物理内存&lt;/h</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>利用CPU的特性开发更高效的代码</title>
    <link href="https://sbcoder.cn/2021/11/29/CPU-Cache-Optimization.html"/>
    <id>https://sbcoder.cn/2021/11/29/CPU-Cache-Optimization.html</id>
    <published>2021-11-29T08:31:34.000Z</published>
    <updated>2021-11-30T01:35:30.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="CPU-Cache是什么"><a href="#CPU-Cache是什么" class="headerlink" title="CPU Cache是什么"></a>CPU Cache是什么</h2><p>CPU Cache是在内存的基础上，可以被CPU直接读取的缓存，分为 L1,L2,L3 三层缓存级别，他的读取速度，是内存的100倍以上，我们都知道基于内存的数据库Redis，仅仅是使用了内存存储就很快了，CPU Cache则更快，利用好CPU Cache则可以让你编写的程序更快。</p><p>相比较各类IO操作，CPU Cache则是最底层的，分级一般为 L1 Cache &gt; L2 Cache &gt; L3 Cache &gt; MEM &gt; SSD &gt; HDD，按照现在市场上面的定价，相对应的价格也是梯形下降</p><p>相对于CPU Cache昂贵的价格，带来的收益自然也要更高，可以通过如下命令查看所在机器的CPU Cache分别是多少，从而更有利于优化代码</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">获取L1 数据缓存大小</span></span><br><span class="line">cat /sys/devices/system/cpu/cpu0/cache/index0/size</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">获取L1 指令缓存大小</span></span><br><span class="line">cat /sys/devices/system/cpu/cpu0/cache/index1/size</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">获取L2 Cache 大小</span></span><br><span class="line">cat /sys/devices/system/cpu/cpu0/cache/index2/size</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">获取L3 Cache 大小</span></span><br><span class="line">cat /sys/devices/system/cpu/cpu0/cache/index3/size</span><br></pre></td></tr></table></figure><p>一般来说 L3 的容量 &gt; L2 &gt; L1数据 &#x3D; L1指令</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/29/oMLjgI.png" alt="oMLjgI.png" title="">                </div>                <div class="image-caption">oMLjgI.png</div>            </figure><p>越靠近 CPU 核心的缓存其访问速度越快，CPU 访问 L1 Cache 只需要 2<del>4 个时钟周期，访问 L2 Cache 大约 10</del>20 个时钟周期，访问 L3 Cache 大约 20<del>60 个时钟周期，而访问内存速度大概在 200</del>300 个 时钟周期之间。</p><p>时钟周期是CPU主频的倒数，例如 2GHZ主频的CPU，一个时钟周期是 0.5ns</p><h2 id="CPU-Cache-Line"><a href="#CPU-Cache-Line" class="headerlink" title="CPU Cache Line"></a>CPU Cache Line</h2><p>CPU Cache Line 是每次CPU载入缓存的大小，CPU在读取缓存信息时并非是一次一字节读取而是每次读一个固定字节长度的数据</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size</span><br></pre></td></tr></table></figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/29/oMOIRs.png" alt="oMOIRs.png" title="">                </div>                <div class="image-caption">oMOIRs.png</div>            </figure><p>由于他每次是读一块儿数据，那么我们在编写代码时则可以避免多次读取内存，可以将数据内容压缩到64位以内，避免重复读</p><p>当我们在使用数组时，例如一个 数据 A 长度 65，则会缓存前64位数组内容，例如从下标0读到63，则不会重复读取内容，那么如果读0 然后 读 64呢？</p><p>答案是会重复读内存，他会自动缓存从0开始的一共长度64的数据，那么下标64已经超出这个长度则会重复读内存</p><p>那么如果读 0 然后读 2呢，还会重复读内存吗？</p><p>答案也是肯定的，<em>如果跳着读他会重复缓存，必须是一个连续的数值才可以利用上这个长度</em></p><figure class="highlight golang"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">p : = [<span class="number">3</span>][<span class="number">3</span>]<span class="type">int</span>&#123;&#123;<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>&#125;, &#123;<span class="number">4</span> ,<span class="number">5</span>, <span class="number">6</span>&#125;, &#123;<span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>&#125;&#125;</span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i &lt; <span class="number">3</span>; i++ &#123;</span><br><span class="line"><span class="keyword">for</span> j := <span class="number">0</span>; j &lt; <span class="number">3</span>; i++ &#123;</span><br><span class="line">fmt.Println(<span class="string">&quot;echo : &quot;</span> ,p[i][j])</span><br><span class="line"><span class="comment">// fmt.Println(&quot;echo : &quot; ,p[j][i])</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上述<code>Go</code>代码中 <code>fmt.Println(&quot;echo : &quot; ,p[i][j]) </code>是在内存中读取连续的数值，而 <code>fmt.Println(&quot;echo : &quot; ,p[j][i])</code> 则并非是在读连续数据，他会不断地请求内存，从而会发现前者的效率更高一些</p><p>总结 ： 抛开一切因素，读取数据时按照存储顺序来读一定要比任意读效率要高，如果有条件控制数据长度那么可以结合CPU Cache Line 的长度来做一些优化</p><h2 id="CPU分支预测"><a href="#CPU分支预测" class="headerlink" title="CPU分支预测"></a>CPU分支预测</h2><p>CPU本身是有一个分支预测功能，它相当于一个CPU自带的优化器，当我们在代码中使用if判断的时候，CPU会自行预测他的结果并缓存，那么CPU预测的结果就一定是准确的么，当然不是~</p><p>既然CPU的分支预测可以在不知道结果的情况下缓存他认为正确的数据，那么我们在编写代码时则可以适当地让CPU的分支预测更准确，那么也就避免了继续从内存读取数据，避免了多余的操作</p><p>代码实现该如何做呢，当一个if语句大多数时间都是 <code>真</code> 的情况下，那么CPU的分支预测将在后续预测中更容易缓存 <code>真</code> 的数据，也可以说，我们的代码尽量让数据保持在一个分支中，可以避免重复读取操作</p><p>除了这种CPU自动的分支预测，C语言也提供了一个方法可以告诉CPU大概的结果，从而使CPU更多的缓存某个分支的数据</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> likely(x) __builtin_expect(!!(x),1)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> unlikely(x) __builtin_expect(!!(x),0)</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (likely(a == <span class="number">1</span>))</span><br><span class="line">&#123;</span><br><span class="line"><span class="comment">/* code */</span></span><br><span class="line">&#125;<span class="keyword">else</span>&#123;</span><br><span class="line"><span class="comment">/* code */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="数据类型和线程绑定"><a href="#数据类型和线程绑定" class="headerlink" title="数据类型和线程绑定"></a>数据类型和线程绑定</h2><p>一般情况下，<code>long</code> 类型 要占用更多的空间，所以很多人在使用时更愿意使用 <code>int</code>，但是在CPU Cache line 中确并不如此，如果一些相同的数据经常要一起使用，我们尽量需要把数据长度控制在特定长度之内或者将数据按照指定顺序来存储更好。</p><p>数据类型会影响什么，真的是占用内存越小越好吗？</p><p>并非如此，现在的服务器更多的是多核CPU，单核CPU则不需要特别注意，多核CPU在处理数据的时候，L1，L2 Cache是独立存在于各个CPU核心的，只有L3 Cache是共享的，既如此，那么L1 和L2的Cache是如何共享信息保持数据一致性？</p><p>如果一个进程在不同核心 来回切换，各个核心的缓存命中率就会受到影响，当有多个同时执行「计算密集型」的线程，为了防止因为切换到不同的核心，而导致缓存命中率下降的问 题，我们可以把线程绑定在某一个 CPU 核心上</p><p>在 Linux 上提供了 sched_setaffinity 方法，来实现将线程绑定到某个 CPU 核心这一功能，从某些程度上来说，亦可以保证数据的一致性问题</p><p>多核多线程之间的数据一致性如何保证？现在市面上大多数的CPU核心是通过 <code>MESI</code> 协议来保持数据一致性的，是<code>Modified Exclusive Shared Invalidated</code>的缩写，即是： 已修改 独占 已共享 已失效</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/30/oleDCd.png" alt="oleDCd.png" title="">                </div>                <div class="image-caption">oleDCd.png</div>            </figure><p>如上，当两个线程都在操作时，A和B都是从内存取出一块儿数据来操作（CPU Cache Line），很多情况下，如果未能保证数据的连续性，A线程就容易拿到B的数据，B也会拿到A的数据，如果A线程操作变量内容时，那么B也需要同时修改才能保证数据的一致性</p><p>那么数据的’锁‘该如何保证呢，则是 <code>MESI</code>协议来保证的。</p><p>线程A操作变量发生变化时，线程A不会广播写入到内存，而是将数据标识为 <code>已修改</code>，而其他线程则是将数据标记为 <code>已失效</code>，当线程读取数据发现标识为已失效时才会重复读取数据更新数据，否则频繁的刷新数据则失去了CPU Cache的意义</p><p>当线程A将已修改的数据写入到内存后，其他线程也更新完数据，那么，将会把数据标记为 已共享</p><p>当线程A创建一个数据，其他线程缓存并不存在该数据时则该数据为 独占</p><p>如上，当出现越来越多的数据在不断地变化，多个线程操作同一块儿缓存，即使有<code>MESI</code>协议的调度，也不免多了很多操作，所以有些人就想到了用占位更大的字符类型让一个变量占用更多的字节数，从而达到保证线程永远拿到这一块儿数据的时候不会有其他线程的共享数据，而实际上，在多核系统中，也提供了宏定义 <code>__cacheline_aligned_in_smp</code> 来保证数据的长度与CPU Cache Line 保持一致</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://z3.ax1x.com/2021/11/30/olnX9J.png" alt="olnX9J.png" title="">                </div>                <div class="image-caption">olnX9J.png</div>            </figure><p>如上，A和B通过宏定义 <code>__cacheline_aligned_in_smp</code> 定义后，字节数会各自占用一块儿，则避免了数据频繁共享的问题</p><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li>小林Coding（图解系统）</li></ul><p>近期写一写感谢大佬的电子图书笔记，小白受益良多</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;CPU-Cache是什么&quot;&gt;&lt;a href=&quot;#CPU-Cache是什么&quot; class=&quot;headerlink&quot; title=&quot;CPU Cache是什么&quot;&gt;&lt;/a&gt;CPU Cache是什么&lt;/h2&gt;&lt;p&gt;CPU Cache是在内存的基础上，可以被CPU直接读取的缓</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="优化" scheme="https://sbcoder.cn/tags/%E4%BC%98%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>frp+Nginx内网穿透远程桌面</title>
    <link href="https://sbcoder.cn/2020/07/27/frp-nginx.html"/>
    <id>https://sbcoder.cn/2020/07/27/frp-nginx.html</id>
    <published>2020-07-27T08:41:31.000Z</published>
    <updated>2020-07-27T08:51:36.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说明"><a href="#说明" class="headerlink" title="说明"></a>说明</h2><p>基于 <a href="https://github.com/fatedier/frp">fatedier&#x2F;frp</a> 的内网穿透服务<br>参考文档 <a href="https://github.com/fatedier/frp/blob/master/README_zh.md">frp中文文档</a><br>参考文档 <a href="https://sspai.com/post/52523">使用frp进行内网穿透</a></p><h2 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h2><p>直接下载 <a href="https://github.com/fatedier/frp/releases">Releases · fatedier&#x2F;frp</a><br>找到对应版本下载即可，我这里服务端选用的是 <code>frp_0.33.0_linux_386</code></p><p>国内机器速度慢可以使用我的个人镜像地址</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://api.0161.org/resources/frp_0.33.0_linux_386.tar.gz</span><br></pre></td></tr></table></figure><p>修改配置文件 <code>frps.ini</code> 文件，建议增加Token验证 关于服务端配置可以参照官方给出的完全版配置文件及注释查看 <code>frps_full.ini</code> 文件</p><p>配置示例</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[common]</span><br><span class="line">bind_port = 7000</span><br><span class="line">token = 123456</span><br><span class="line">dashboard_port = 7500</span><br><span class="line">dashboard_user = admin</span><br><span class="line">dashboard_pwd = 123456</span><br><span class="line">vhost_http_port = 10088</span><br><span class="line">vhost_https_port = 10443</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup ./frps -c ./frps.ini &amp;</span><br></pre></td></tr></table></figure><p>查看后台进程 </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jobs</span><br></pre></td></tr></table></figure><p>删除进程示例</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ps -ef | grep frps | grep -v grep</span><br><span class="line">kill &lt;进程id&gt;</span><br></pre></td></tr></table></figure><p>根据上述配置好的端口 <code>7500</code> 使用 IP+端口 访问frp面板 输入面板用户名+密码<br>该面板无实际性作用，仅用来做探针以及查看当前服务的状态，如未配置dashboard则无法使用dashboard</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/ai3FHK.png" alt="1.png" title="">                </div>                <div class="image-caption">1.png</div>            </figure><h2 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h2><p>下载 客户端 可以直接在github下载或者使用我的</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://api.0161.org/resources/frp_0.33.0_windows_amd64.zip</span><br></pre></td></tr></table></figure><p>解压后修改 <code>frpc.ini</code></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">[common]</span><br><span class="line">server_addr = &lt;你的服务器IP地址&gt;</span><br><span class="line">server_port = 7000</span><br><span class="line">token = 123456</span><br><span class="line">[rdp]</span><br><span class="line">type = tcp</span><br><span class="line">local_ip = 127.0.0.1           </span><br><span class="line">local_port = 3389</span><br><span class="line">remote_port = 7001</span><br><span class="line">[web]</span><br><span class="line">type = http</span><br><span class="line">local_port = 80</span><br><span class="line">custom_domains = &lt;你的远程解析域名 例如: xxx.0161.org&gt;</span><br></pre></td></tr></table></figure><p>上述使用Windows开启3389后可以访问远程桌面，Linux同理，只需要修改为 <code>SSH</code> 即可</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/ai2Nut.png" alt="2.png" title="">                </div>                <div class="image-caption">2.png</div>            </figure><p>值得注意的是 custom_domains 这个参数需要配合 vhost_http_port 这个参数使用，由于跟Nginx冲突所以上述端口我开启的是 10088<br>可以使用域名解析的方式 架设游戏服务器 或者网络云盘 群晖 你懂得网站等</p><h2 id="Nginx反向代理"><a href="#Nginx反向代理" class="headerlink" title="Nginx反向代理"></a>Nginx反向代理</h2><p>使用上述配置必须要使用 域名+端口 的形式才能访问，如果要用正式环境则不美观，且我们希望它与Nginx共存，因此，可以通过Nginx反向代理的形式去解析<br>配置Nginx配置文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">    listen       80;</span><br><span class="line">    server_name xxx.0161.org;</span><br><span class="line"></span><br><span class="line">    location / &#123;</span><br><span class="line">        proxy_pass  http://127.0.0.1:10088;</span><br><span class="line">        proxy_set_header Host $host;</span><br><span class="line">        proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line">        proxy_set_header REMOTE-HOST $remote_addr;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>流程图解</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/aiy8OK.png" alt="3.png" title="">                </div>                <div class="image-caption">3.png</div>            </figure><p>至此，可以直接访问 xxx.0161.org 无需携带端口号</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;说明&quot;&gt;&lt;a href=&quot;#说明&quot; class=&quot;headerlink&quot; title=&quot;说明&quot;&gt;&lt;/a&gt;说明&lt;/h2&gt;&lt;p&gt;基于 &lt;a href=&quot;https://github.com/fatedier/frp&quot;&gt;fatedier&amp;#x2F;frp&lt;/a&gt; 的内网</summary>
      
    
    
    
    <category term="折腾" scheme="https://sbcoder.cn/categories/%E6%8A%98%E8%85%BE/"/>
    
    
    <category term="运维" scheme="https://sbcoder.cn/tags/%E8%BF%90%E7%BB%B4/"/>
    
    <category term="内网穿透" scheme="https://sbcoder.cn/tags/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/"/>
    
    <category term="frp" scheme="https://sbcoder.cn/tags/frp/"/>
    
  </entry>
  
  <entry>
    <title>简单制作网易云音乐解析接口</title>
    <link href="https://sbcoder.cn/2020/07/27/neteasy-music.html"/>
    <id>https://sbcoder.cn/2020/07/27/neteasy-music.html</id>
    <published>2020-07-27T02:44:29.000Z</published>
    <updated>2020-07-27T06:33:58.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="官方接口"><a href="#官方接口" class="headerlink" title="官方接口"></a>官方接口</h2><p>网易云是有一个官方的音乐解析接口的，只是隐藏的比较深（其实也还好），可以选择使用官方的解析接口也可以使用我的，可能官方的有时效性</p><p>Step1. 找到一张无版权歌曲<br>点击生成外链播放器</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/aPDuNR.png" alt="aPDuNR.png" title="">                </div>                <div class="image-caption">aPDuNR.png</div>            </figure><p>Step2. 选择flash播放器<br>开启F12 审查元素 选择flash播放器</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/aPDnE9.png" alt="aPDnE9.png" title="">                </div>                <div class="image-caption">aPDnE9.png</div>            </figure><p>Step3. 搜索接口<br>直接在F12 搜索 song 找到如下接口</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/aPDZB4.png" alt="aPDZB4.png" title="">                </div>                <div class="image-caption">aPDZB4.png</div>            </figure><p>Step. 复制接口地址<br>302直接跳转，我们可以直接获取到直链地址</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/27/aPDeHJ.png" alt="aPDeHJ.png" title="">                </div>                <div class="image-caption">aPDeHJ.png</div>            </figure><p>找到官方接口</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://music.163.com/song/media/outer/url?id=&lt;歌曲ID&gt;</span><br></pre></td></tr></table></figure><h2 id="根据官方内容自制接口"><a href="#根据官方内容自制接口" class="headerlink" title="根据官方内容自制接口"></a>根据官方内容自制接口</h2><figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?php</span></span><br><span class="line"><span class="variable">$params</span> = <span class="variable">$_REQUEST</span>;</span><br><span class="line"><span class="variable">$returnData</span> = [];</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;src&#x27;</span>] = <span class="string">&#x27;error 500&#x27;</span>;</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;code&#x27;</span>] = <span class="number">0</span>;</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;msg&#x27;</span>] = <span class="string">&#x27;无状态&#x27;</span>;</span><br><span class="line"><span class="keyword">if</span> (!<span class="keyword">isset</span>(<span class="variable">$params</span>[<span class="string">&#x27;url&#x27;</span>]) || <span class="keyword">empty</span>(<span class="variable">$params</span>[<span class="string">&#x27;url&#x27;</span>])) &#123;</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;msg&#x27;</span>] = <span class="string">&#x27;5001 URL或者ID参数不存在&#x27;</span>;</span><br><span class="line">    <span class="keyword">echo</span> <span class="title function_ invoke__">json_encode</span>(<span class="variable">$returnData</span>,JSON_UNESCAPED_SLASHES);</span><br><span class="line">    <span class="keyword">exit</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable">$url</span>     = <span class="variable">$params</span>[<span class="string">&#x27;url&#x27;</span>];</span><br><span class="line"><span class="variable">$pattern</span> = <span class="string">&#x27;/(\d&#123;5,20&#125;)/i&#x27;</span>;</span><br><span class="line"><span class="title function_ invoke__">preg_match</span>(<span class="variable">$pattern</span>, <span class="variable">$url</span>, <span class="variable">$matches</span>);</span><br><span class="line"><span class="keyword">if</span> (!<span class="variable">$matches</span>) &#123;</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;msg&#x27;</span>] = <span class="string">&#x27;5002 URL或者ID格式有误&#x27;</span>;</span><br><span class="line">    <span class="keyword">echo</span> <span class="title function_ invoke__">json_encode</span>(<span class="variable">$returnData</span>,JSON_UNESCAPED_SLASHES);</span><br><span class="line">    <span class="keyword">exit</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable">$getParameterUrl</span> = <span class="string">&#x27;https://music.163.com/song/media/outer/url?id=&#x27;</span> . <span class="variable">$matches</span>[<span class="number">0</span>];</span><br><span class="line"><span class="title function_ invoke__">var_dump</span>(<span class="variable">$getParameterUrl</span>);<span class="keyword">exit</span>();</span><br><span class="line"><span class="variable">$headers</span> = <span class="title function_ invoke__">get_headers</span>(<span class="variable">$getParameterUrl</span>, <span class="literal">TRUE</span>);</span><br><span class="line"><span class="comment">//输出跳转到的网址</span></span><br><span class="line"><span class="keyword">if</span> (<span class="variable">$headers</span>[<span class="string">&#x27;Location&#x27;</span>]) &#123;</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;msg&#x27;</span>] = <span class="string">&#x27;成功&#x27;</span>;</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;src&#x27;</span>] = <span class="variable">$headers</span>[<span class="string">&#x27;Location&#x27;</span>];</span><br><span class="line"><span class="variable">$returnData</span>[<span class="string">&#x27;code&#x27;</span>] = <span class="number">1</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">echo</span> <span class="title function_ invoke__">json_encode</span>(<span class="variable">$returnData</span>,JSON_UNESCAPED_SLASHES);</span><br><span class="line"></span><br><span class="line"><span class="keyword">exit</span>();</span><br></pre></td></tr></table></figure><p>二次封装之后可以使用<br>注意：网易云的这个接口无法使用国外IP访问，如IP不符可能会返回404</p><p><strong>可以使用我的API接口获取最新版解析</strong></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;官方接口&quot;&gt;&lt;a href=&quot;#官方接口&quot; class=&quot;headerlink&quot; title=&quot;官方接口&quot;&gt;&lt;/a&gt;官方接口&lt;/h2&gt;&lt;p&gt;网易云是有一个官方的音乐解析接口的，只是隐藏的比较深（其实也还好），可以选择使用官方的解析接口也可以使用我的，可能官方的有时</summary>
      
    
    
    
    <category term="折腾" scheme="https://sbcoder.cn/categories/%E6%8A%98%E8%85%BE/"/>
    
    
    <category term="音乐" scheme="https://sbcoder.cn/tags/%E9%9F%B3%E4%B9%90/"/>
    
  </entry>
  
  <entry>
    <title>使用Rancher快速部署k8s集群</title>
    <link href="https://sbcoder.cn/2020/07/24/rancher-install.html"/>
    <id>https://sbcoder.cn/2020/07/24/rancher-install.html</id>
    <published>2020-07-24T03:32:57.000Z</published>
    <updated>2020-07-24T03:34:48.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="安装Rancher"><a href="#安装Rancher" class="headerlink" title="安装Rancher"></a>安装Rancher</h2><p><strong>注意</strong>：最低配置为 2H4G1M  本教程使用 2H8G5M Ubuntu18.04<br>卸载旧版Docker</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get remove docker docker-engine docker.io containerd runc</span><br></pre></td></tr></table></figure><p>脚本安装Docker</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun</span><br></pre></td></tr></table></figure><p>更换阿里云源<br>登录 <a href="https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors">https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors</a></p><p>找到 加速地址，或者使用我的</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">sudo mkdir -p /etc/docker</span><br><span class="line">sudo tee /etc/docker/daemon.json &lt;&lt;-&#x27;EOF&#x27;</span><br><span class="line">&#123;</span><br><span class="line">  &quot;registry-mirrors&quot;: [&quot;https://p4sew3ge.mirror.aliyuncs.com&quot;]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl restart docker</span><br></pre></td></tr></table></figure><p>安装Rancher</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo docker run -d --restart=unless-stopped -v /home/rancher:/var/lib/rancher/ -p 80:80 -p 443:443 rancher/rancher:stable</span><br></pre></td></tr></table></figure><p>打开 https:&#x2F;&#x2F;&lt;你的IP&gt;<br>忽略掉证书提示，继续进入</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXXLLt.png" alt="1.png" title="">                </div>                <div class="image-caption">1.png</div>            </figure><h2 id="添加集群"><a href="#添加集群" class="headerlink" title="添加集群"></a>添加集群</h2><p>Step1.设置语言</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXjlO1.png" alt="2.png" title="">                </div>                <div class="image-caption">2.png</div>            </figure><p>Step2.选择右上角添加集群，选择自定义</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXjctS.png" alt="3.png" title="">                </div>                <div class="image-caption">3.png</div>            </figure><p>Step3.设置好集群名字后直接点击下一步</p><p>Step4.配置节点<br>按照需要配置，我这里选择全部</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXvRUK.png" alt="4.png" title="">                </div>                <div class="image-caption">4.png</div>            </figure><p>Step5.配置公网IP<br>云主机需要配置</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXxexJ.png" alt="5.png" title="">                </div>                <div class="image-caption">5.png</div>            </figure><p>Step6.复制命令执行</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXxwZt.png" alt="6.png" title="">                </div>                <div class="image-caption">6.png</div>            </figure><p>执行后会启动一个容器</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXxhd0.png" alt="7.png" title="">                </div>                <div class="image-caption">7.png</div>            </figure><p>Step7.集群部署节点完成<br>准备中…</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXzPQH.png" alt="8.png" title="">                </div>                <div class="image-caption">8.png</div>            </figure><p>完成部署</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UXznfS.png" alt="9.png" title="">                </div>                <div class="image-caption">9.png</div>            </figure><h2 id="增加节点"><a href="#增加节点" class="headerlink" title="增加节点"></a>增加节点</h2><p>选择主机 - 编辑集群</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/UjC13T.png" alt="11.png" title="">                </div>                <div class="image-caption">11.png</div>            </figure><p>拉到最下面，与上面添加节点方式一样，修改为子节点的ip，然后在子节点运行该命令<br>等待添加完成</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/24/Uj9r0s.png" alt="10.png" title="">                </div>                <div class="image-caption">10.png</div>            </figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;安装Rancher&quot;&gt;&lt;a href=&quot;#安装Rancher&quot; class=&quot;headerlink&quot; title=&quot;安装Rancher&quot;&gt;&lt;/a&gt;安装Rancher&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：最低配置为 2H4G1M  本教程使用 2H</summary>
      
    
    
    
    <category term="架构" scheme="https://sbcoder.cn/categories/%E6%9E%B6%E6%9E%84/"/>
    
    
    <category term="运维" scheme="https://sbcoder.cn/tags/%E8%BF%90%E7%BB%B4/"/>
    
    <category term="Docker" scheme="https://sbcoder.cn/tags/Docker/"/>
    
  </entry>
  
  <entry>
    <title>Ubuntu18.04部署Kubernetes(k8s)集群可视化界面Dashboard</title>
    <link href="https://sbcoder.cn/2020/07/23/Kubernetes-Ubuntu.html"/>
    <id>https://sbcoder.cn/2020/07/23/Kubernetes-Ubuntu.html</id>
    <published>2020-07-23T01:12:57.000Z</published>
    <updated>2020-07-23T06:03:38.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="k8s概念"><a href="#k8s概念" class="headerlink" title="k8s概念"></a>k8s概念</h2><h3 id="架构"><a href="#架构" class="headerlink" title="架构"></a>架构</h3><blockquote><p>Kubernetes是一个完备的分布式系统支撑平台。Kubernetes具有完备的集群管理能力，包括多层次的安全防护和准入机制&#x2F;多租户应用支撑能力、透明的服务注册和服务发现机制、内建智能负载均衡器、强大的故障发现和自我修复功能、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制，以及多粒度的资源配额管理能力。同时kubernetes提供了完善的管理工具，这些工具覆盖了包括开发、测试部署、运维监控在内的各个环节；因此kubernetes是一个全新的基于容器技术的分布式架构解决方案，并且是一个一站式的完备的分布式系统开发和支撑平台</p></blockquote><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/20/U4kh5j.png" alt="Kubernetes简易.png" title="">                </div>                <div class="image-caption">Kubernetes简易.png</div>            </figure><h3 id="Kubernetes-Service"><a href="#Kubernetes-Service" class="headerlink" title="Kubernetes Service"></a>Kubernetes Service</h3><blockquote><p><code>Service</code>的服务进程目前都基于<code>Socker</code>通信方式对外提供服务，比如redis、memcache、MySQL、Web Server，或者是实现了某个具体业务的一个特定的TCP Server进程。虽然一个<code>Service</code>通常由多个相关的服务进程来提供服务，每个服务进程都有一个独立的Endpoint(IP+Port)访问点，但Kubernetes 能够让我们通过<code>Service</code>虚拟<code>Cluster IP+Service Port</code>连接到指定的<code>Service上</code>。有了<code>Kubernetes</code>内建的透明负载均衡和故障恢复机制，不管后端有多少服务进程，也不管某个服务进程是否会由于发生故障而重新部署到其他机器，都不会影响到我们对服务的正常调用。更重要的是这个<code>Service</code>本身一旦创建就不再变化，这意味着<code>Kubernetes</code>集群中，我们再也不用为了服务的IP地址变来变去的问题而头疼。</p></blockquote><p><code>service</code>可以通过访问点去访问不同的子节点下面的<code>Pod</code>上，类似一个<code>Proxy</code>的概念，个人理解为他本身类似集群，通过<code>service</code>分发<br>与<code>swarm</code>集群中的<code>service</code>类似，可以保持容器启动数量，由于权限相关问题，用户手动命令要大于service控制的权限级别，因此如果在使用<code>service</code>控制<code>Pod</code>时，有可能导致报错，不推荐使用</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/20/U4AzTg.png" alt="Kubernetes Service.png" title="">                </div>                <div class="image-caption">Kubernetes Service.png</div>            </figure><h3 id="Kubernetes-Pod"><a href="#Kubernetes-Pod" class="headerlink" title="Kubernetes Pod"></a>Kubernetes Pod</h3><blockquote><p>Pod运行在一个我们称之为节点Node的环境中，可以是私有云也可以是公有云的虚拟机或者物理机，通常在一个节点上运行几百个Pod;其次，每个Pod里运行着一个特殊的被称之为Pause的容器，其他容器则为业务容器，这些业务容器共享Pause容器的网络栈和Volume挂载卷，因此他们之间的通讯和数据交换更为高效。在设计时我们可以充分利用这一特征将一组密切相关的服务进程放入同一个Pod中。<br>并不是每个Pod和它里面运行的容器都能映射到一个Service 上，只有那些提供服务(无论是对内还是对外)的一组Pod才会被映射成一个服务。</p></blockquote><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/21/UIKJMQ.png" alt="Kubernetes Pod.png" title="">                </div>                <div class="image-caption">Kubernetes Pod.png</div>            </figure><h3 id="Pod-Container"><a href="#Pod-Container" class="headerlink" title="Pod &amp; Container"></a>Pod &amp; Container</h3><ul><li><p>容器（Container）是一种高度隔离的封装程序</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/21/UIDylQ.png" alt="容器1.png" title="">                </div>                <div class="image-caption">容器1.png</div>            </figure><p>非所有的应用都适合选择容器，开发者可以根据自己应用的特点和需求选择最适合的计算单元。例如，你的应用是高性能、互信的，且处于同一个管理区域，那么用线程或者进程就可以满足；但如果你的应用是多租户的，并且和其他应用运行在同一个空间，那么你就需要考虑如何将这些应用安全地隔离开，使得数据不会被泄露或性能受到影响。那么这时，容器也许就是一个不错的选择了。<br>容器便于管理，因为现在市场上有着完全完善的生态以及<code>Docker</code>的支持度愈发增加，越来越多的公司（个人）选择<code>Docker</code>，我个人也更倾向于<code>Docker</code>，有了<code>Docker</code>就可以非常完美的管理<code>Images</code>以及<code>Container</code></p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/21/UIrVtf.png" alt="容器2.png" title="">                </div>                <div class="image-caption">容器2.png</div>            </figure><p>容器是只占用很少的空间的，真正占用空间大的是<code>Images</code>，也可以说 <code>Container</code> 依赖 <code>Images</code></p></li><li><p>Pod，一种增强型容器<br>Pod是一种组合的多容器运行单元，也是Kubernetes里的一个基础单元。你可以把它看作是一种容器的扩展或者增强型的容器。Pod里面包括一个主容器和数个辅助容器，它们共同完成一个特定的功能。把多个进程（容器也是一种隔离的进程）打包在一个Name Space里的时候，就构成了一个Pod。Pod里面不同进程的应用包装仍然是独立的（每个容器都会有自己的镜像）。<br>Pod的意义在于，它可以既保持主容器和辅助容器的的密切关系，又保持主容器的独立性。由于主容器和辅助容器的生命周期相同，可以同时被创建和销毁，因此把它们放在一个Pod中，可以使他们的交互更加高效。</p></li></ul><h3 id="参考文档"><a href="#参考文档" class="headerlink" title="参考文档"></a>参考文档</h3><p><a href="https://www.sohu.com/a/382769383_115128">Aholiab - 云原生的基石，一文读懂容器、Docker、Pod到底是什么！ </a><br><a href="https://k.i4t.com/">abcdocker编写k8s中文文档</a><br><a href="https://k8sops.cn/ubuntu_kubeadm/">Ubuntu18.04使用kubeadm部署v1.18 HA集群</a></p><h2 id="部署k8s"><a href="#部署k8s" class="headerlink" title="部署k8s"></a>部署k8s</h2><h3 id="机器选择"><a href="#机器选择" class="headerlink" title="机器选择"></a>机器选择</h3><p>这里我只做学习用途，因此开通的是阿里的按量计费机器以及低配置机器</p><ul><li>master01 2H8G  阿里云 Ubuntu18.04</li><li>node01 2H8G  阿里云 Ubuntu18.04</li></ul><h3 id="部署环境"><a href="#部署环境" class="headerlink" title="部署环境"></a>部署环境</h3><p><strong>Ubuntu修改仓库镜像</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">sudo cat &gt; /etc/apt/sources.list &lt;&lt; EOF</span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse</span><br><span class="line"></span><br><span class="line">deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse</span><br><span class="line">deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><p><strong>关闭防火墙</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo ufw disable</span><br></pre></td></tr></table></figure><p><strong>时间同步</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get install chrony -y &amp;&amp; sudo systemctl start chrony &amp;&amp; sudo systemctl enable chrony</span><br><span class="line"></span><br><span class="line">#查看chrony连接的公网服务器</span><br><span class="line">cat /etc/chrony/chrony.conf </span><br><span class="line">pool ntp.ubuntu.com        iburst maxsources 4</span><br><span class="line">pool 0.ubuntu.pool.ntp.org iburst maxsources 1</span><br><span class="line">pool 1.ubuntu.pool.ntp.org iburst maxsources 1</span><br><span class="line">pool 2.ubuntu.pool.ntp.org iburst maxsources 2</span><br></pre></td></tr></table></figure><p><strong>禁用swap</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo swapoff -a</span><br></pre></td></tr></table></figure><p>上述命令可以临时禁用掉swap，如果想要永久禁止，需要编辑 <code>/etc/fstab</code> 文件,将swap那一行注释掉，如果没有则不管</p><p><strong>禁用SELinux</strong><br>如果安装了则需要禁止掉，如果没有安装则可以跳过此步骤</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">sudo setenforce 0           #临时关闭</span><br><span class="line">sudo vi /etc/selinux/config #永久关闭</span><br><span class="line">SELINUX=permissive </span><br></pre></td></tr></table></figure><p><strong>修改内核</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">sudo  cat &gt; /etc/sysctl.d/k8s.conf &lt;&lt; EOF</span><br><span class="line">net.bridge.bridge-nf-call-ip6tables = 1</span><br><span class="line">net.bridge.bridge-nf-call-iptables = 1</span><br><span class="line">net.ipv4.ip_forward = 1                     #开启ipv4转发，允许内置路由</span><br><span class="line">EOF</span><br><span class="line">sudo sysctl --system</span><br></pre></td></tr></table></figure><p><strong>修改时区</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime</span><br><span class="line">sudo bash -c &quot;echo &#x27;Asia/Shanghai&#x27; &gt; /etc/timezone&quot;</span><br></pre></td></tr></table></figure><p><strong>安装Docker</strong><br>Step 1: 安装必要的一些系统工具</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get update</span><br><span class="line">sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common</span><br></pre></td></tr></table></figure><p>Step 2: 安装GPG证书</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -</span><br></pre></td></tr></table></figure><p>Step 3: 写入软件源信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo add-apt-repository &quot;deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable&quot;</span><br></pre></td></tr></table></figure><p>Step 4: 查找Docker-CE的版本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-cache madison docker-ce</span><br></pre></td></tr></table></figure><p>Step 5: 安装指定版本的Docker-CE,docker-ce&#x3D;<a href="%E5%A6%82%E6%9E%9C%E5%AE%89%E8%A3%85%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%E5%88%99%E6%97%A0%E9%9C%80%E5%B8%A6%E7%89%88%E6%9C%AC%E5%8F%B7">VERSION</a></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo apt-get -y install docker-ce</span><br></pre></td></tr></table></figure><p>Setp 6: 安装完成后Docker默认就已经启动和加入开机自启了，这点我们不需要再做了，不过可以检查一下</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo systemctl status docker</span><br><span class="line">sudo systemctl is-enabled docker</span><br></pre></td></tr></table></figure><p>Setp 7:  配置Docker镜像加速以及指定cgroup驱动为systemd</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">sudo mkdir -p /etc/docker</span><br><span class="line">sudo tee /etc/docker/daemon.json &lt;&lt;-&#x27;EOF&#x27;</span><br><span class="line">&#123;</span><br><span class="line">  &quot;exec-opts&quot;: [&quot;native.cgroupdriver=systemd&quot;],</span><br><span class="line">  &quot;registry-mirrors&quot;: [&quot;https://81z69sad.mirror.aliyuncs.com&quot;]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl restart docker</span><br></pre></td></tr></table></figure><p>Setp 8:  配置完成后使用 docker info 可以看到修改的配置信息</p><p><strong>配置主机名</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">cat &gt;&gt; /etc/hosts &lt;&lt; EOF</span><br><span class="line">172.26.147.37  master01</span><br><span class="line">172.26.147.36  node01</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure><p><strong>安装Kubeadm Kubelet Kubectl</strong><br>Step 1: 安装必要的程序包</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get update &amp;&amp; apt-get install -y apt-transport-https</span><br></pre></td></tr></table></figure><p>Step 2: 导入Kubernetes官方包签名密钥</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - </span><br></pre></td></tr></table></figure><p>Step 3: 添加Kubernetes仓库</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cat &gt; /etc/apt/sources.list.d/kubernetes.list &lt;&lt; EOF</span><br><span class="line">deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main</span><br><span class="line">EOF </span><br></pre></td></tr></table></figure><p>Step 4: 更新仓库 </p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get update</span><br></pre></td></tr></table></figure><p>Step 5: 查找kubeadm kubelet kubectl版本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">apt-cache madison kubeadm | grep 1.18</span><br><span class="line">apt-cache madison kubelet | grep 1.18</span><br><span class="line">apt-cache madison kubectl | grep 1.18</span><br></pre></td></tr></table></figure><p>目前1.18发布了1.18.0-00 1.18.1-00 1.18.2-00 三个版本</p><p>Step 6: 指定版本安装kubelet kubeadm kubectl(如果安装最新版本则无需带版本号)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get install kubeadm kubelet kubectl -y</span><br></pre></td></tr></table></figure><h3 id="Master节点部署"><a href="#Master节点部署" class="headerlink" title="Master节点部署"></a>Master节点部署</h3><p><strong>根据需要修改的参数更换以下内容</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">kubeadm init \</span><br><span class="line">--image-repository registry.aliyuncs.com/google_containers \</span><br><span class="line">--kubernetes-version v1.18.0 \</span><br><span class="line">--control-plane-endpoint master01 \</span><br><span class="line">--pod-network-cidr=10.244.0.0/16 \</span><br><span class="line">--service-cidr=10.96.0.0/12 \</span><br><span class="line">--apiserver-advertise-address=0.0.0.0 \</span><br><span class="line">--ignore-preflight-errors=Swap \</span><br><span class="line">--token-ttl 30m</span><br></pre></td></tr></table></figure><p><strong>参数说明</strong></p><ul><li>image-repository：初始化过程中会去docker仓库拉去镜像，默认指定的为docker hub(国内访问网速不堪)，所以在此使用–image-repository参数指定阿里云镜像。</li><li>kubernetes-version：指定正在使用的 Kubernetes 程序组件的版本号，需要与 kubelet kubeadm kubectl 的版本号一致。</li><li>control-plane-endpoint: 指定控制平面的固定访问端点，可以是IP地址或DNS名称，会被用于集群管理员及集群组件的kubeconfig配置文件API Server的访问地址；单控制平面部署时可以不使用该选项(如果是单个Master部署则不需要使用该选项，因为等会我们要再加入其它两个Master节点到控制平面，所以这里加上此参数)。</li><li>pod-network-cidr：Pod 网络的地址范围，其值为 CIDR 格式的网络地址，使用 flannel 网络插件时，其默认地址为 10.244.0.0&#x2F;16。</li><li>service-cidr：Service 的网络地址范围，其值为 CIDR 格式的网络地址，默认地址为 10.96.0.0&#x2F;12。</li><li>apiserver-advertise-address：API Server 通告给其它组件的IP地址，一般为 Master 节点的IP地址，0.0.0.0 标识节点上所有可用的地址。<br>ignore-preflight-errors：忽略哪些运行时的错误信息，其值为 Swap 时，表示忽略因 swap 未关闭而导致的错误。</li><li>token-ttl：token令牌自动删除时间，默认为24小时，指定为 0 表示永不过期，指定单位可以使 秒s 分m 时h，在node加入Kubernetes集群时需要指定token。<br><strong>初始化过程</strong><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHburQ.png" alt="01.png" title="">                </div>                <div class="image-caption">01.png</div>            </figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHb15q.png" alt="02.png" title="">                </div>                <div class="image-caption">02.png</div>            </figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHbNMF.png" alt="03.png" title="">                </div>                <div class="image-caption">03.png</div>            </figure><strong>初始化完成</strong><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">#您的Kubernetes控制平面初始化成功!</span><br><span class="line">Your Kubernetes control-plane has initialized successfully!</span><br><span class="line"></span><br><span class="line">#要开始使用您的集群，您需要作为一个普通用户运行以下程序:</span><br><span class="line">To start using your cluster, you need to run the following as a regular user:</span><br><span class="line">  mkdir -p $HOME/.kube</span><br><span class="line">  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config</span><br><span class="line">  sudo chown $(id -u):$(id -g) $HOME/.kube/config</span><br><span class="line"></span><br><span class="line">#你需要部署一个网络插件到集群中才能够使Kubernetes网络运转起来</span><br><span class="line">You should now deploy a pod network to the cluster.</span><br><span class="line">Run &quot;kubectl apply -f [podnetwork].yaml&quot; with one of the options listed at:</span><br><span class="line">  https://kubernetes.io/docs/concepts/cluster-administration/addons/</span><br><span class="line"></span><br><span class="line">#如果要添加其它控制平面到集群中使用以下命令</span><br><span class="line">You can now join any number of control-plane nodes by copying certificate authorities</span><br><span class="line">and service account keys on each node and then running the following as root:</span><br><span class="line">  kubeadm join k8s-devops.io:6443 --token 8r7sjk.9a31rmcjot9650fe \</span><br><span class="line">    --discovery-token-ca-cert-hash sha256: \</span><br><span class="line">    --control-plane</span><br><span class="line"></span><br><span class="line">#如果要添加数据平面节点到集群中使用以下命令</span><br><span class="line">Then you can join any number of worker nodes by running the following on each as root:</span><br><span class="line">kubeadm join k8s-devops.io:6443 --token 8r7sjk.9a31rmcjot9650fe \</span><br><span class="line">    --discovery-token-ca-cert-hash sha256:</span><br></pre></td></tr></table></figure></li></ul><p><strong>创建用户</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">root@master01:~# useradd -m -s /bin/bash k8s  # 创建用户</span><br><span class="line">root@master01:~# passwd k8s  # 设置密码</span><br><span class="line">Enter new UNIX password:</span><br><span class="line">Retype new UNIX password:</span><br><span class="line">passwd: password updated successfully</span><br></pre></td></tr></table></figure><p>为普通用户提权</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">root@master01:~# echo &#x27;k8s ALL=(ALL:ALL) NOPASSWD:ALL&#x27; &gt;&gt; /etc/sudoers.d/k8s</span><br></pre></td></tr></table></figure><p>创建权限</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">root@master01:~# su k8s  # 切换用户</span><br><span class="line">k8s@master01:/root$    </span><br><span class="line">k8s@master01:/root$ cd /  # 切换目录</span><br><span class="line">k8s@master01:/$ mkdir -p $HOME/.kube                                     #在当前用户家目录下创建.kube目录</span><br><span class="line">k8s@master01:/$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config  #复制config命令配置文件到当前用户.kube目录下</span><br><span class="line">k8s@master01:/$ sudo chown $(id -u):$(id -g) $HOME/.kube/config           #修改config文件权限</span><br></pre></td></tr></table></figure><p><strong>部署网络插件</strong><br>Step 1: 可以直接在线部署(如果网络下载不了的情况下,也可以先试用浏览器下载后上传到服务器上)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">k8s@master01:/$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml</span><br></pre></td></tr></table></figure><p>Step 2: 如果上述方法还是不行，则可以尝试使用我的</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f https://api.0161.org/resources/kube-flannel.yml</span><br></pre></td></tr></table></figure><p>Step 3: 上传完后修改文件的属性信息(如上述1,2步骤已完成则直接跳过)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">k8s@master01:/$ sudo chown -Rf k8s.k8s kube-flannel.yml</span><br></pre></td></tr></table></figure><p>Step 4: 然后指定文件部署网络插件(如上述1,2步骤已完成则直接跳过)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">k8s@master01:/$ kubectl apply -f kube-flannel.yml</span><br><span class="line">podsecuritypolicy.policy/psp.flannel.unprivileged created</span><br><span class="line">clusterrole.rbac.authorization.k8s.io/flannel created</span><br><span class="line">clusterrolebinding.rbac.authorization.k8s.io/flannel created</span><br><span class="line">serviceaccount/flannel created</span><br><span class="line">configmap/kube-flannel-cfg created</span><br><span class="line">daemonset.apps/kube-flannel-ds-amd64 created</span><br><span class="line">daemonset.apps/kube-flannel-ds-arm64 created</span><br><span class="line">daemonset.apps/kube-flannel-ds-arm created</span><br><span class="line">daemonset.apps/kube-flannel-ds-ppc64le created</span><br><span class="line">daemonset.apps/kube-flannel-ds-s390x created</span><br></pre></td></tr></table></figure><p>Step 5: 查看网络插件是否部署完成(下面有一个叫kube-flannel-ds-amd64的Pod)<br>如果发现你的 flannel Pod 处于 ImagePullBackOff 状态，那么就是 flannel 镜像未拉取成功，而正常的则为 Running状态</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">k8s@master01:/$ kubectl get pods -n kube-system | grep flannel</span><br><span class="line">kube-flannel-ds-amd64-hx9cr        1/1     Running   0          2m3s</span><br></pre></td></tr></table></figure><p>Step 6: 查看目前k8s节点信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">k8s@master01:/$ kubectl get nodes</span><br><span class="line">NAME       STATUS   ROLES    AGE   VERSION</span><br><span class="line">master01   Ready    master   65m   v1.18.6</span><br></pre></td></tr></table></figure><h3 id="子节点加入到集群"><a href="#子节点加入到集群" class="headerlink" title="子节点加入到集群"></a>子节点加入到集群</h3><p>master节点查看join参数</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm token create --print-join-command</span><br></pre></td></tr></table></figure><p>子节点运行</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubeadm join master01:6443 --token 8z8ot9.ylyj39j1po0hgyun     --discovery-token-ca-cert-hash sha256:e0bb3c41**********************************813c84472f65c</span><br></pre></td></tr></table></figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHb0aR.png" alt="04.png" title="">                </div>                <div class="image-caption">04.png</div>            </figure><h2 id="安装Dashboard"><a href="#安装Dashboard" class="headerlink" title="安装Dashboard"></a>安装Dashboard</h2><h3 id="官方文档方式启动-不建议"><a href="#官方文档方式启动-不建议" class="headerlink" title="官方文档方式启动(不建议)"></a>官方文档方式启动(不建议)</h3><p>与端口+ip只能选择一种使用！！！</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml</span><br></pre></td></tr></table></figure><p>如遇到无法访问或者网络连接问题可以使用我的备份文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl apply -f https://api.0161.org/resources/recommended.yaml</span><br></pre></td></tr></table></figure><p>代理方式启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl proxy</span><br></pre></td></tr></table></figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHbhdA.png" alt="05.png" title="">                </div>                <div class="image-caption">05.png</div>            </figure><h3 id="端口-IP启动-推荐"><a href="#端口-IP启动-推荐" class="headerlink" title="端口+IP启动(推荐)"></a>端口+IP启动(推荐)</h3><p><strong>环境部署</strong><br>下载文件</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://k8s-1252147235.cos.ap-chengdu.myqcloud.com/dashboard/dashboard.yaml</span><br></pre></td></tr></table></figure><p>拉取镜像</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kubernetes-dashboard-amd64:v1.10.1</span><br></pre></td></tr></table></figure><p>创建服务</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo kubectl apply -f dashboard.yaml</span><br></pre></td></tr></table></figure><p>浏览器输入 <code>https://IP:30001</code> 打开 （可以使用Safari或者火狐，Chrome无法访问）</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHb7z8.png" alt="06.png" title="">                </div>                <div class="image-caption">06.png</div>            </figure><p><strong>绑定用户</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo kubectl create serviceaccount dashboard-admin -n kube-system</span><br><span class="line">kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard</span><br></pre></td></tr></table></figure><p><strong>获取Token</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl describe secrets -n kube-system $(kubectl -n kube-system get secret | awk &#x27;/dashboard-admin/&#123;print $1&#125;&#x27;)</span><br></pre></td></tr></table></figure><p>按Token启动</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/22/UHqnW6.png" alt="07.png" title="">                </div>                <div class="image-caption">07.png</div>            </figure><h3 id="赋予用户权限"><a href="#赋予用户权限" class="headerlink" title="赋予用户权限"></a>赋予用户权限</h3><p><strong>单命名空间权限文件及绑定</strong><br>创建 role.yaml</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">kind: Role</span><br><span class="line">apiVersion: rbac.authorization.k8s.io/v1</span><br><span class="line">metadata:</span><br><span class="line">  namespace: kube-system</span><br><span class="line">  name: role-dashboard-admin</span><br><span class="line">rules:</span><br><span class="line">- apiGroups: [&quot;&quot;]</span><br><span class="line">  resources: [&quot;pods&quot;,&quot;services&quot;]</span><br><span class="line">  verbs: [&quot;get&quot;, &quot;watch&quot;, &quot;list&quot;]</span><br><span class="line">- apiGroups: [&quot;extensions&quot;, &quot;apps&quot;]</span><br><span class="line">  resources: [&quot;deployments&quot;]</span><br><span class="line">  verbs: [&quot;get&quot;, &quot;list&quot;, &quot;watch&quot;, &quot;create&quot;, &quot;update&quot;, &quot;patch&quot;, &quot;delete&quot;]</span><br></pre></td></tr></table></figure><p>创建 role-bind.yaml</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">kind: RoleBinding</span><br><span class="line">apiVersion: rbac.authorization.k8s.io/v1</span><br><span class="line">metadata:</span><br><span class="line">  name: role-bind-dashboard-admin</span><br><span class="line">  namespace: kube-system</span><br><span class="line">subjects:</span><br><span class="line">- kind: ServiceAccount</span><br><span class="line">  name: dashboard-admin</span><br><span class="line">  namespace: kube-system</span><br><span class="line">roleRef:</span><br><span class="line">  kind: Role</span><br><span class="line">  name: role-dashboard-admin</span><br><span class="line">  apiGroup: rbac.authorization.k8s.io</span><br></pre></td></tr></table></figure><p><strong>集群权限配置及绑定</strong><br>创建 cluster-role.yaml</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">kind: ClusterRole</span><br><span class="line">apiVersion: rbac.authorization.k8s.io/v1</span><br><span class="line">metadata:</span><br><span class="line"> name: cluster-role-dashboard-admin</span><br><span class="line">rules:</span><br><span class="line">- apiGroups: [&quot;&quot;]</span><br><span class="line">  resources: [&quot;pods&quot;]</span><br><span class="line">  verbs: [&quot;get&quot;, &quot;watch&quot;, &quot;list&quot;]</span><br></pre></td></tr></table></figure><p>创建 cluster-role-bind.yaml</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">kind: ClusterRoleBinding</span><br><span class="line">apiVersion: rbac.authorization.k8s.io/v1</span><br><span class="line">metadata:</span><br><span class="line"> name: cluster-role-bind-dashboard-admin</span><br><span class="line">subjects:</span><br><span class="line">- kind: ServiceAccount</span><br><span class="line"> name: dashboard-admin</span><br><span class="line"> apiGroup: rbac.authorization.k8s.io</span><br><span class="line">roleRef:</span><br><span class="line"> kind: ClusterRole</span><br><span class="line"> name: cluster-role-dashboard-admin</span><br><span class="line"> apiGroup: rbac.authorization.k8s.io</span><br></pre></td></tr></table></figure><p>执行命令</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">kubectl create -f role.yaml</span><br><span class="line">kubectl create -f role-bind.yaml</span><br><span class="line">kubectl create -f cluster-role.yaml</span><br><span class="line">kubectl create -f cluster-role-bind.yaml</span><br></pre></td></tr></table></figure><p>完成权限配置，可根据自身情况增加配置！</p><h2 id="常用k8s命令"><a href="#常用k8s命令" class="headerlink" title="常用k8s命令"></a>常用k8s命令</h2><ul><li>查看pod列表<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">kubectl get pods --all-namespaces   # 查看所有</span><br><span class="line">sudo kubectl get pod -n kube-system # 查看指定命名空间</span><br></pre></td></tr></table></figure></li><li>查看service列表<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get service --all-namespaces   # 查看所有</span><br></pre></td></tr></table></figure></li><li>删除指定命名空间下的service<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete service serviceName --namespace=namespaceName</span><br></pre></td></tr></table></figure></li><li>删除指定命名空间下的pod<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete pod podName --namespace=namespaceName</span><br></pre></td></tr></table></figure></li><li>查看所有deployment<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl get deployment -A</span><br></pre></td></tr></table></figure></li><li>删除指定deployment<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kubectl delete deployment podName</span><br></pre></td></tr></table></figure></li><li>查看指定命名空间端口<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo kubectl get pod,svc -n kube-system</span><br></pre></td></tr></table></figure></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;k8s概念&quot;&gt;&lt;a href=&quot;#k8s概念&quot; class=&quot;headerlink&quot; title=&quot;k8s概念&quot;&gt;&lt;/a&gt;k8s概念&lt;/h2&gt;&lt;h3 id=&quot;架构&quot;&gt;&lt;a href=&quot;#架构&quot; class=&quot;headerlink&quot; title=&quot;架构&quot;&gt;&lt;/a&gt;架</summary>
      
    
    
    
    <category term="架构" scheme="https://sbcoder.cn/categories/%E6%9E%B6%E6%9E%84/"/>
    
    
    <category term="架构" scheme="https://sbcoder.cn/tags/%E6%9E%B6%E6%9E%84/"/>
    
    <category term="Docker" scheme="https://sbcoder.cn/tags/Docker/"/>
    
  </entry>
  
  <entry>
    <title>Redis持久化及数据备份</title>
    <link href="https://sbcoder.cn/2020/06/10/Redis-Backup.html"/>
    <id>https://sbcoder.cn/2020/06/10/Redis-Backup.html</id>
    <published>2020-06-10T08:14:42.000Z</published>
    <updated>2020-07-23T07:15:16.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Redis持久化"><a href="#Redis持久化" class="headerlink" title="Redis持久化"></a>Redis持久化</h2><p>Redis作为内存数据库，数据的安全性一定要得到确切的保障，很多情况下，Redis是作为存储数据库来用的，如果遇到断电，关机等突发情况，则容易丢失关键数据，对此，Redis的持久化就显得尤为关键，甚至某些情况下，需要定时去做备份</p><h3 id="RDB"><a href="#RDB" class="headerlink" title="RDB"></a>RDB</h3><p>可以在每隔一段时间执行一次备份操作，性能比AOF方式更好，RDB是紧凑型文件，但是最多可以执行到5分钟左右，如果再低可能会影响性能<br>RDB相当于 备份数据</p><ul><li>恢复数据快</li><li>性能更好</li><li>可以分时间节点备份文件 </li><li>容易丢失数据</li></ul><h3 id="AOF"><a href="#AOF" class="headerlink" title="AOF"></a>AOF</h3><p>可以按秒级存储数据，由于长期存储，如果发生崩溃事件，它可能只会丢失几秒的数据，相比较来说，可能更安全<br>AOF相当于 备份执行语句</p><ul><li>数据安全性更高</li><li>存储时不占用资源</li><li>可自定 fsync 策略</li><li>恢复速度慢</li></ul><h2 id="Docker安装"><a href="#Docker安装" class="headerlink" title="Docker安装"></a>Docker安装</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker pull redis:latest</span><br><span class="line">docker run -itd --name redis01 -p 6379:6379 redis</span><br></pre></td></tr></table></figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/07/09/UeweFP.png" alt="1.png" title="">                </div>                <div class="image-caption">1.png</div>            </figure><p>未完！！！</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Redis持久化&quot;&gt;&lt;a href=&quot;#Redis持久化&quot; class=&quot;headerlink&quot; title=&quot;Redis持久化&quot;&gt;&lt;/a&gt;Redis持久化&lt;/h2&gt;&lt;p&gt;Redis作为内存数据库，数据的安全性一定要得到确切的保障，很多情况下，Redis是作为存储</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="数据库" scheme="https://sbcoder.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    <category term="Redis" scheme="https://sbcoder.cn/tags/Redis/"/>
    
  </entry>
  
  <entry>
    <title>MySQL主从同步 读写分离 集群部署</title>
    <link href="https://sbcoder.cn/2020/06/10/MySQL-Cluster-MySQLProxy.html"/>
    <id>https://sbcoder.cn/2020/06/10/MySQL-Cluster-MySQLProxy.html</id>
    <published>2020-06-10T06:25:42.000Z</published>
    <updated>2020-06-10T06:28:18.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h2><p>可以使用之前写的<code>Canal</code>阿里巴巴增量订阅更新做简单的主从备份，由于Canal只读取 <code>binary log</code> 日志做增量更新</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/05/trt36S.png" alt="canal工作流程图.png" title="">                </div>                <div class="image-caption">canal工作流程图.png</div>            </figure><p>通过canal可以做简单的按更新备份也可以通过canal做数据更新，根据更新的内容去更新数据库中其他的字段值<br>也可以通过canal客户端发送消息给 <code>ElasticSearch</code> 等服务，适合多样化复杂的MySQL主从操作<br>通过伪造<code>slave</code>的方式请求<code>binary log</code>消息</p><p>阿里巴巴也为我们提供了更好的基于Canal的分布式数据库同步系统 <code>otter</code></p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/05/trNja9.jpg" alt="otter工作原理.jpg" title="">                </div>                <div class="image-caption">otter工作原理.jpg</div>            </figure><p>本文所用Docker目的是一台机器搞定集群功能，实际生产环境中不建议使用Docker</p><h2 id="参考项目："><a href="#参考项目：" class="headerlink" title="参考项目："></a>参考项目：</h2><p><a href="https://github.com/alibaba/otter">alibaba&#x2F;otter - 阿里巴巴分布式数据库同步系统(解决中美异地机房)</a><br><a href="https://github.com/alibaba/canal">alibaba&#x2F;canal - 阿里巴巴 MySQL binlog 增量订阅&amp;消费组件</a></p><h2 id="通过MySQL配置主从备份"><a href="#通过MySQL配置主从备份" class="headerlink" title="通过MySQL配置主从备份"></a>通过MySQL配置主从备份</h2><p>主从备份，通过配置MySQL做主从备份</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/05/trNQE9.jpg" alt="主从备份流程图.jpg" title="">                </div>                <div class="image-caption">主从备份流程图.jpg</div>            </figure><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li>主从数据库版本保持一致</li><li>需要单独的两台服务器（单台机器可使用Docker，没有测试过）</li><li>需要网络相连，保证主从服务器通信</li><li>表结构不使用外键，使用外键容易造成同步失败</li><li>主键使用无意义自增字段</li><li>同步数据库所用的账号拥有一定的权限，也可以使用root</li></ul><h3 id="安装MySQL"><a href="#安装MySQL" class="headerlink" title="安装MySQL"></a>安装MySQL</h3><p>参照之前的文章 <a href="https://sbcoder.cn/2020/05/17/Docker_PHP_fpm.html#MySQL-Docker%E5%90%AF%E5%8A%A8">MySQL Docker启动</a><br>启动两个不同的 MySQL 映射不同的端口</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker run --restart=always --name mysql5.7-1 -p 3307:3306 -v /Users/XXX/Downloads/Docker/mysql5.7-1:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci</span><br><span class="line"></span><br><span class="line">docker run --restart=always --name mysql5.7 -p 3306:3306 -v /Users/XXX/Downloads/Docker/mysql5.7:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci</span><br></pre></td></tr></table></figure><p>进入容器内部 安装vim 或者映射 使用参数 <code>-v</code>  映射位置 <code>/etc/mysql/my.cnf</code> 配置文件亦可</p><p>安装 vim 方式 编辑 my.cnf</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apt-get install</span><br><span class="line">apt-get install vim</span><br></pre></td></tr></table></figure><p>挂载 本地文件 内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"># Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.</span><br><span class="line">#</span><br><span class="line"># This program is free software; you can redistribute it and/or modify</span><br><span class="line"># it under the terms of the GNU General Public License, version 2.0,</span><br><span class="line"># as published by the Free Software Foundation.</span><br><span class="line">#</span><br><span class="line"># This program is also distributed with certain software (including</span><br><span class="line"># but not limited to OpenSSL) that is licensed under separate terms,</span><br><span class="line"># as designated in a particular file or component or in included license</span><br><span class="line"># documentation.  The authors of MySQL hereby grant you an additional</span><br><span class="line"># permission to link the program and your derivative works with the</span><br><span class="line"># separately licensed software that they have included with MySQL.</span><br><span class="line">#</span><br><span class="line"># This program is distributed in the hope that it will be useful,</span><br><span class="line"># but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span class="line"># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span class="line"># GNU General Public License, version 2.0, for more details.</span><br><span class="line">#</span><br><span class="line"># You should have received a copy of the GNU General Public License</span><br><span class="line"># along with this program; if not, write to the Free Software</span><br><span class="line"># Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA</span><br><span class="line"></span><br><span class="line">!includedir /etc/mysql/conf.d/</span><br><span class="line">!includedir /etc/mysql/mysql.conf.d/</span><br></pre></td></tr></table></figure><h3 id="配置主从备份"><a href="#配置主从备份" class="headerlink" title="配置主从备份"></a>配置主从备份</h3><p><em>主节点 使用root 用户 配置</em></p><p>修改配置文件 &#x2F;etc&#x2F;mysql&#x2F;my.cnf</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line">log-bin=mysql-bin</span><br><span class="line">server-id=1</span><br></pre></td></tr></table></figure><p>执行命令</p><p><strong>input</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">GRANT REPLICATION SLAVE ON *.* to &#x27;root&#x27;@&#x27;%&#x27; identified by &#x27;123456&#x27;;</span><br><span class="line">FLUSH PRIVILEGES;</span><br><span class="line">SHOW MASTER STATUS;</span><br></pre></td></tr></table></figure><p><strong>output</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |</span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br><span class="line">| mysql-bin.000001 |      589 |              |                  |                   |</span><br><span class="line">+------------------+----------+--------------+------------------+-------------------+</span><br></pre></td></tr></table></figure><p><em>从节点 使用root 用户 配置</em><br>修改配置文件 &#x2F;etc&#x2F;mysql&#x2F;my.cnf</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[mysqld]</span><br><span class="line">log-bin=mysql-bin</span><br><span class="line">server-id=2</span><br></pre></td></tr></table></figure><p>执行命令</p><p><strong>input</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">change master to master_host=&#x27;172.17.0.2&#x27;,master_user=&#x27;root&#x27;,master_password=&#x27;123456&#x27;,master_log_file=&#x27;mysql-bin.000001&#x27;,master_log_pos=589;</span><br><span class="line">start slave;</span><br><span class="line">show slave status\G;</span><br></pre></td></tr></table></figure><p><strong>output</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line">*************************** 1. row ***************************</span><br><span class="line">               Slave_IO_State: Waiting for master to send event</span><br><span class="line">                  Master_Host: 172.17.0.2</span><br><span class="line">                  Master_User: root</span><br><span class="line">                  Master_Port: 3306</span><br><span class="line">                Connect_Retry: 60</span><br><span class="line">              Master_Log_File: mysql-bin.000001</span><br><span class="line">          Read_Master_Log_Pos: 589</span><br><span class="line">               Relay_Log_File: f919535d2d58-relay-bin.000002</span><br><span class="line">                Relay_Log_Pos: 320</span><br><span class="line">        Relay_Master_Log_File: mysql-bin.000001</span><br><span class="line">             Slave_IO_Running: Yes</span><br><span class="line">            Slave_SQL_Running: Yes</span><br><span class="line">              Replicate_Do_DB:</span><br><span class="line">          Replicate_Ignore_DB:</span><br><span class="line">           Replicate_Do_Table:</span><br><span class="line">       Replicate_Ignore_Table:</span><br><span class="line">      Replicate_Wild_Do_Table:</span><br><span class="line">  Replicate_Wild_Ignore_Table:</span><br><span class="line">                   Last_Errno: 0</span><br><span class="line">                   Last_Error:</span><br><span class="line">                 Skip_Counter: 0</span><br><span class="line">          Exec_Master_Log_Pos: 589</span><br><span class="line">              Relay_Log_Space: 534</span><br><span class="line">              Until_Condition: None</span><br><span class="line">              Until_Log_File:</span><br><span class="line">                Until_Log_Pos: 0</span><br><span class="line">           Master_SSL_Allowed: No</span><br><span class="line">           Master_SSL_CA_File:</span><br><span class="line">           Master_SSL_CA_Path:</span><br><span class="line">              Master_SSL_Cert:</span><br><span class="line">            Master_SSL_Cipher:</span><br><span class="line">               Master_SSL_Key:</span><br><span class="line">        Seconds_Behind_Master: 0</span><br><span class="line">Master_SSL_Verify_Server_Cert: No</span><br><span class="line">                Last_IO_Errno: 0</span><br><span class="line">                Last_IO_Error:</span><br><span class="line">               Last_SQL_Errno: 0</span><br><span class="line">               Last_SQL_Error:</span><br><span class="line">  Replicate_Ignore_Server_Ids:</span><br><span class="line">             Master_Server_Id: 1</span><br><span class="line">                  Master_UUID: 380e925e-a645-11ea-a304-0242ac110004</span><br><span class="line">             Master_Info_File: /var/lib/mysql/master.info</span><br><span class="line">                    SQL_Delay: 0</span><br><span class="line">          SQL_Remaining_Delay: NULL</span><br><span class="line">      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates</span><br><span class="line">           Master_Retry_Count: 86400</span><br><span class="line">                  Master_Bind:</span><br><span class="line">      Last_IO_Error_Timestamp:</span><br><span class="line">     Last_SQL_Error_Timestamp:</span><br><span class="line">               Master_SSL_Crl:</span><br><span class="line">               Master_SSL_Crlpath:</span><br><span class="line">           Retrieved_Gtid_Set:</span><br><span class="line">            Executed_Gtid_Set:</span><br><span class="line">                Auto_Position: 0</span><br><span class="line">         Replicate_Rewrite_DB:</span><br><span class="line">                 Channel_Name:</span><br><span class="line">           Master_TLS_Version:</span><br><span class="line">1 row in set (0.00 sec)</span><br></pre></td></tr></table></figure><p>测试 创建一个 test数据库 </p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/10/toQoRg.png" alt="主从数据库同步.png" title="">                </div>                <div class="image-caption">主从数据库同步.png</div>            </figure><h3 id="监控状态"><a href="#监控状态" class="headerlink" title="监控状态"></a>监控状态</h3><p>可以使用crontab 配合钉钉通知 使用 curl命令通知 主从同步是否成功</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">!/bin/bash</span></span><br><span class="line">array=($(mysql -uroot -p -e &quot;show slave status\G&quot; | grep &quot;Running&quot; | awk &#x27;&#123;print $2&#125;&#x27;))</span><br><span class="line">if [ &quot;$&#123;array[0]&#125;&quot; == &quot;Yes&quot; ] || [ &quot;$&#123;array[1]&#125;&quot; == &quot;Yes&quot; ]</span><br><span class="line">    then</span><br><span class="line">        echo &quot;Slave is OK&quot;</span><br><span class="line">    else</span><br><span class="line">        echo &quot;Slave is error&quot;</span><br><span class="line">fi</span><br></pre></td></tr></table></figure><h2 id="读写分离"><a href="#读写分离" class="headerlink" title="读写分离"></a>读写分离</h2><p>master数据库处理写操作，slave数据库处理读操作。利用上面配置的主从数据库，使master数据库的变更实时更新到slave节点上，支持事务，但可能会因为某些原因有阻塞现象发生，不可避免的可能会出现数据同步慢的情况</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/10/to1KhT.png" alt="读写分离.png" title="">                </div>                <div class="image-caption">读写分离.png</div>            </figure><p>使用 MySQLProxy 做读写分离</p><blockquote><p>MySQLProxy实际上是在客户端请求与MySQLServer之间建立了一个连接池。所有客户端请求都是发向MySQLProxy，然后经由MySQLProxy进行相应的分析，判断出是读操作还是写操作，分发至对应的MySQLServer上。对于多节点Slave集群，也可以起做到负载均衡的效果。</p></blockquote><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/10/to1Q9U.png" alt="MySQLProxy.png" title="">                </div>                <div class="image-caption">MySQLProxy.png</div>            </figure><p>为何要使用MySQLProxy？其实可以不使用，但为了减少代码量，减少开发成本，可以通过运维的手段去做分发处理。<br>常见的开发框架实际上很多是支持读写分离操作不同数据库的，而代理服务器做的则是将这些框架封装好的东西通过代理分发的方式，分别给不同的数据库发送请求，主库只修改，从库只读</p><p><strong>缺点</strong></p><ul><li>目前MySQLProxy仍然是 alpha（内测） 版</li><li>通过lua脚本做的读写分离，MySQL官方并不建议使用</li></ul><h3 id="配置MySQLProxy读写分离"><a href="#配置MySQLProxy读写分离" class="headerlink" title="配置MySQLProxy读写分离"></a>配置MySQLProxy读写分离</h3><p>假定 上述两台服务器 分别为 master slave 那么我们现在需要第三台服务器 proxy<br>proxy需要做中转代理，将接收到的数据库请求分别指向 master 和 slave</p><p>下载 MySQLProxy<br>下载地址：<a href="https://downloads.mysql.com/archives/proxy/">MySQL Product Archives</a></p><p>由于我的环境为MAC新版，对 MySQLProxy 的支持度并不好，因此并不在本机使用可以参照下面引用的文章参考配置</p><h2 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h2><ul><li><a href="https://blog.csdn.net/bvcxz10328/article/details/76030278">Mysql 主从备份完整版</a></li><li><a href="https://www.jianshu.com/p/1eed312e83bf">MySQL主从备份配置</a></li><li><a href="https://segmentfault.com/a/1190000003716617">MySQL读写分离介绍及搭建</a></li><li><a href="https://www.jianshu.com/p/cadf337274c1">MySQL Proxy</a></li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;简介&quot;&gt;&lt;a href=&quot;#简介&quot; class=&quot;headerlink&quot; title=&quot;简介&quot;&gt;&lt;/a&gt;简介&lt;/h2&gt;&lt;p&gt;可以使用之前写的&lt;code&gt;Canal&lt;/code&gt;阿里巴巴增量订阅更新做简单的主从备份，由于Canal只读取 &lt;code&gt;binary l</summary>
      
    
    
    
    <category term="优化" scheme="https://sbcoder.cn/categories/%E4%BC%98%E5%8C%96/"/>
    
    
    <category term="MySQL" scheme="https://sbcoder.cn/tags/MySQL/"/>
    
    <category term="运维" scheme="https://sbcoder.cn/tags/%E8%BF%90%E7%BB%B4/"/>
    
  </entry>
  
  <entry>
    <title>MAC环境记录</title>
    <link href="https://sbcoder.cn/2020/06/06/myMacOptionPHP.html"/>
    <id>https://sbcoder.cn/2020/06/06/myMacOptionPHP.html</id>
    <published>2020-06-06T06:36:36.000Z</published>
    <updated>2020-07-27T09:08:30.000Z</updated>
    
    <content type="html"><![CDATA[<div class="hbe hbe-container" id="hexo-blog-encrypt" data-wpm="Oh, this is an invalid password. Check and try again, please." data-whm="OOPS, these decrypted content may changed, but you can still have a look.">  <script id="hbeData" type="hbeData" data-hmacdigest="4aece097af00dd980b4a4d15b3e5d64d998341cbeeef4bd228f76da047e17699">8ad9776b9e3adf3c3a869363e1dea3820779a6263c38edd5817c839a47dbb23eb9ed78024d5c6f4eee84fa1923141e181f76112bff4d53d6f179dcb782d5ca9384d3fd21cde6f66a3fe292d3042d115b1d3142850034f76f96d51454f9dd62a1f136b526386cb4b3057b46b8f73a9ffc802b13169689204c5ae8bc66a39ee1021e2c3b6c7186d020fa0d868971c327ee886f799aa521aa421080719c0c778eae0e51ed3b8c1e33306a842f9070932b02e8f2c0470792a28428f88e8ac8a3616a8731dd0a142ffe2cf39a9b787430ef5d675b69644959d739c5dbb114dd9bc0242acc7c011e242981132ffafe8e79744c26b20c72901e1fe088819e838306706653fa12df823217f9871f61a1ffd0a535fe67f7d4575ccbf432ecfc0d0490bc95f9c5cc37b5f56423e0e7fdde087466a13542e3a5b9bbb1a70e32b0967aa9ed60df008060d611bfceb3c4a4bec82846d12d2a2bcd780b4e6597b164769d35ab4cb866e188ef20758a14b29e38487711a84a5ccef95408d36d10090b7d3061b3464f3cf32a8c04d4e49f02e44c395e1b912cfd0c899fbcd45b03f1b95ad4f3975d2968528cb997774f51a62b473603e65d67d7b9719765b206bc77f360a2e396e533c043c9c64506fdb88334710d4b6c15aa1bd85d3ef27b962284be68f34e11675ab5d7f942679a292f56e15eef630f4604a89accdbf3bf11db53bd20e5cb6fe82766473cba465c25d1fe96e72531d0cfaae7820563ac5a79e64341870cf775baea73164e5582edb768aec7f83ad8e877f1cbb98f35fde4a3f984b030c18b21283d6ae30142d86034a2980672c5e40dbc1bf65ee60956e181f183bf384f69be7922a9197b72fae609f582f161cc860d50ba4b5c3c7054ac560841eb479e77698b12d73b595861b1192089ab92554bca94dc2abcdc26242dce16fa8354f6a3157d395d29ac69d13b5912e3199a79f1a5c14fbe8e005fb78d6b16147a949dd30442bc96307d9adf2f8132e4e00d15fc920924383353b3de98b31b825795b5e7e24f1fc541860c40c2cc95565f77ae8354c1b1ae3c2783a34a1b0337bc81894191e4daf8860d938b5bb07474607808c79a713d048471298d76206164bcae1c2605b88424bf6890772470b48cf85314fdb84a491abe506c1b8febd45ed5d5dbb102a6c6a919b4ed23ad1dc025058e765592cfde8899c44f9c6011c7b02d5064f4f56084969cea46f73054058ec64aaaa273a449943264f574c92fe804e6409a9b2c1ec411aa372d1cf3590f6c13083763b5499ba37009c9507c4867c46ac3b6bd1f3a1b12f01812640db88cc558cdd2da28982e817ec04b624167d93f8fd16d2f60f3a86c22736c6399796a6801733fd0a8929ea57d1e453c66b46799eae0fd608b194b5b79bf79fb2b326d47e2bcaace36587cb2d6b7c06b574f90dfe478c8e0e1f5e3f8867ad8bb11d5c593e586dc2b12b089aa94d7f84b08956feea3a9d702e32965ded93b21cea55d279470229c54e25e9a305d9bf0d2b933b3706be6511b18f81b577b2c342cf5aace53c22772edf0cc187e2cdee45b30b33aad3332dd4942f6c09ae63017b6ef4175adac4439b5241eb11418233c908297c5bee844dff254d6d7d3c6caafb6e778e4c706249b99e086</script>  <div class="hbe hbe-content">    <div class="hbe hbe-input hbe-input-default">      <input class="hbe hbe-input-field hbe-input-field-default" type="password" id="hbePass">      <label class="hbe hbe-input-label hbe-input-label-default" for="hbePass">        <span class="hbe hbe-input-label-content hbe-input-label-content-default">Hey, password is required here.</span>      </label>    </div>  </div></div><script data-pjax src="/lib/hbe.js"></script><link href="/css/hbe.style.css" rel="stylesheet" type="text/css">]]></content>
    
    
    <summary type="html">Here&#39;s something encrypted, password is required to continue reading.</summary>
    
    
    
    <category term="note" scheme="https://sbcoder.cn/categories/note/"/>
    
    
    <category term="笔记" scheme="https://sbcoder.cn/tags/%E7%AC%94%E8%AE%B0/"/>
    
  </entry>
  
  <entry>
    <title>ElasticSearch &amp; ELK日志分析 从零开始搭建到使用</title>
    <link href="https://sbcoder.cn/2020/05/27/ELK_Stack.html"/>
    <id>https://sbcoder.cn/2020/05/27/ELK_Stack.html</id>
    <published>2020-05-27T12:34:16.000Z</published>
    <updated>2020-06-04T08:31:50.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><h3 id="介绍"><a href="#介绍" class="headerlink" title="介绍"></a>介绍</h3><p>基于Lucene的搜索服务器，它提供了一个分布式多用户能力的全文搜索引擎，基于RESTful web接口。<br>更适用于集群部署，适合各类 分词，全文搜索，通过建立索引（分片，按节点分片）来实现更快的搜索<br>Elasticsearch是与Logstash的数据收集和日志解析引擎以及Kibana的分析和可视化平台一起开发的。这三个产品被设计成一个集成解决方案，称为“Elastic Stack”（以前称为“ELK stack”）。<br>本文只做单节点运行</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/03/tU7KfS.png" alt="ELK.png" title="">                </div>                <div class="image-caption">ELK.png</div>            </figure><h3 id="官方介绍"><a href="#官方介绍" class="headerlink" title="官方介绍"></a>官方介绍</h3><blockquote><p>Elasticsearch 是一个分布式、RESTful 风格的搜索和数据分析引擎，能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心，它集中存储您的数据，帮助您发现意料之中以及意料之外的情况。</p></blockquote><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li>单点服务器维持稳定可能需要常驻内存 4G 以上</li><li>单点ELK维持稳定可能需要CPU 4核心 以上</li></ul><h3 id="参考文章"><a href="#参考文章" class="headerlink" title="参考文章"></a>参考文章</h3><ul><li><a href="https://www.cnblogs.com/fbtop/p/11005469.html">Docker安装部署ELK教程 (Elasticsearch+Kibana+Logstash+Filebeat)</a></li><li><a href="https://zhang.ge/5135.html">零门槛！基于Docker快速部署ES集群</a></li></ul><h2 id="下载集群所需镜像-zookeeper-kafka"><a href="#下载集群所需镜像-zookeeper-kafka" class="headerlink" title="下载集群所需镜像 zookeeper kafka"></a>下载集群所需镜像 zookeeper kafka</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">docker pull zookeeper</span><br><span class="line">docker pull wurstmeister/kafka</span><br></pre></td></tr></table></figure><h2 id="单节点无内网IP使用"><a href="#单节点无内网IP使用" class="headerlink" title="单节点无内网IP使用"></a>单节点无内网IP使用</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker network create elkwork</span><br></pre></td></tr></table></figure><p>创建内部网络后在每次 docker run 的时候 增加参数 <code>--net elkwork</code></p><h2 id="elastic相关"><a href="#elastic相关" class="headerlink" title="elastic相关"></a>elastic相关</h2><ul><li><p>旧版本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker pull docker.elastic.co/elasticsearch/elasticsearch:5.6.8</span><br><span class="line">docker pull docker.elastic.co/kibana/kibana:5.6.8</span><br><span class="line">docker pull docker.elastic.co/logstash/logstash:5.6.8</span><br></pre></td></tr></table></figure></li><li><p>新版本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">docker pull docker.elastic.co/elasticsearch/elasticsearch:7.7.0</span><br><span class="line">docker pull docker.elastic.co/kibana/kibana:7.7.0</span><br><span class="line">docker pull docker.elastic.co/logstash/logstash:7.7.0</span><br><span class="line">docker pull store/elastic/filebeat:7.7.0</span><br></pre></td></tr></table></figure></li></ul><h2 id="启动elasticsearch-自行替换版本"><a href="#启动elasticsearch-自行替换版本" class="headerlink" title="启动elasticsearch 自行替换版本"></a>启动elasticsearch 自行替换版本</h2><p><code>&quot;discovery.type=single-node&quot;</code> 单节点</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e &quot;discovery.type=single-node&quot; docker.elastic.co/elasticsearch/elasticsearch:5.6.8</span><br></pre></td></tr></table></figure><p>默认用户名默认密码 <br>elasticchangeme     </p><p>测试是否已经连通<code>-u elastic:changeme</code> 验权</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -u elastic:changeme localhost:9200</span><br></pre></td></tr></table></figure><p>浏览器端口访问测试</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/05/27/tAsJj1.png" alt="elasticsearch.png" title="">                </div>                <div class="image-caption">elasticsearch.png</div>            </figure><h2 id="elasticsearch-各类语法"><a href="#elasticsearch-各类语法" class="headerlink" title="elasticsearch 各类语法"></a>elasticsearch 各类语法</h2><h3 id="基本"><a href="#基本" class="headerlink" title="基本"></a>基本</h3><p>浏览器访问<br><code>http://xxx.xx.xxx.xx:9200/_cat/indices?v</code>  查看当前节点的所有 Index<br><code>http://xxx.xx.xxx.xx:9200/_mapping?pretty=true</code>  列出每个 Index 所包含的 Type</p><p>验权机制增加参数  <code>-u elastic:changeme</code> 验权</p><p>命令行访问<br><code>curl -u elastic:changeme -X PUT &#39;localhost:9200/weather&#39;</code> 可以直接向 Elastic 服务器发出 PUT 请求<br><code>curl -u elastic:changeme -X DELETE &#39;localhost:9200/weather&#39;</code>  发出 DELETE 请求，删除这个 Index</p><h3 id="插入数据"><a href="#插入数据" class="headerlink" title="插入数据"></a>插入数据</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">curl -X POST &#x27;localhost:9200/account/person&#x27; -d &#x27;</span><br><span class="line">&#123;</span><br><span class="line">  &quot;user&quot;: &quot;李四&quot;,</span><br><span class="line">  &quot;title&quot;: &quot;工程师&quot;,</span><br><span class="line">  &quot;desc&quot;: &quot;系统管理&quot;</span><br><span class="line">&#125;&#x27;</span><br></pre></td></tr></table></figure><h3 id="读取数据"><a href="#读取数据" class="headerlink" title="读取数据"></a>读取数据</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl &#x27;localhost:9200/account/person/1?pretty=true&#x27;</span><br></pre></td></tr></table></figure><p>示例</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;_index&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;accounts&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;_type&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;person&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;_id&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;1&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;_version&quot;</span> <span class="punctuation">:</span> <span class="number">1</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;found&quot;</span> <span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;_source&quot;</span> <span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;user&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;张三&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;title&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;工程师&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;desc&quot;</span> <span class="punctuation">:</span> <span class="string">&quot;数据库管理&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h3 id="删除记录"><a href="#删除记录" class="headerlink" title="删除记录"></a>删除记录</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -X DELETE &#x27;localhost:9200/accounts/person/1&#x27;</span><br></pre></td></tr></table></figure><h3 id="更新记录"><a href="#更新记录" class="headerlink" title="更新记录"></a>更新记录</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">curl -X PUT &#x27;localhost:9200/accounts/person/1&#x27; -d &#x27;</span><br><span class="line">&#123;</span><br><span class="line">    &quot;user&quot; : &quot;张三&quot;,</span><br><span class="line">    &quot;title&quot; : &quot;工程师&quot;,</span><br><span class="line">    &quot;desc&quot; : &quot;数据库管理，软件开发&quot;</span><br><span class="line">&#125;&#x27; </span><br></pre></td></tr></table></figure><h3 id="返回所有记录"><a href="#返回所有记录" class="headerlink" title="返回所有记录"></a>返回所有记录</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl &#x27;localhost:9200/accounts/person/_search&#x27;</span><br></pre></td></tr></table></figure><ul><li>索引 ：<code>/Index/Type/_search</code></li><li>total：返回记录数，本例是2条。</li><li>max_score：最高的匹配程度，本例是1.0。</li><li>hits：返回的记录组成的数组。</li></ul><h3 id="查询记录"><a href="#查询记录" class="headerlink" title="查询记录"></a>查询记录</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">curl &#x27;localhost:9200/accounts/person/_search&#x27;  -d &#x27;</span><br><span class="line">&#123;</span><br><span class="line">  &quot;query&quot; : &#123; &quot;match&quot; : &#123; &quot;desc&quot; : &quot;软件 系统&quot; &#125;&#125;,</span><br><span class="line">  &quot;from&quot;: 1</span><br><span class="line">  &quot;size&quot;: 1</span><br><span class="line">&#125;&#x27;</span><br></pre></td></tr></table></figure><ul><li>size 返回数量</li><li>from 开始位置</li><li>OR搜索，当前搜索的示例是 <code>软件</code>或<code>系统</code></li><li>AND搜索示例<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;query&quot;: &#123;</span><br><span class="line">    &quot;bool&quot;: &#123;</span><br><span class="line">      &quot;must&quot;: [</span><br><span class="line">        &#123; &quot;match&quot;: &#123; &quot;desc&quot;: &quot;软件&quot; &#125; &#125;,</span><br><span class="line">        &#123; &quot;match&quot;: &#123; &quot;desc&quot;: &quot;系统&quot; &#125; &#125;</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="参考文章-1"><a href="#参考文章-1" class="headerlink" title="参考文章"></a>参考文章</h3><ul><li><a href="http://www.ruanyifeng.com/blog/2017/08/elasticsearch.html">全文搜索引擎 Elasticsearch 入门教程</a></li></ul><h2 id="启动kibana-自行替换版本"><a href="#启动kibana-自行替换版本" class="headerlink" title="启动kibana 自行替换版本"></a>启动kibana 自行替换版本</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name kibana -p 8001:5601 docker.elastic.co/kibana/kibana:5.6.8</span><br></pre></td></tr></table></figure><p>kibana 容器内部修改配置ip</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Vi ./config/kibana.yml</span><br></pre></td></tr></table></figure><p>重启容器使配置生效</p><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/05/27/tAsApj.png" alt="kibana.png" title="">                </div>                <div class="image-caption">kibana.png</div>            </figure><h2 id="配置-logstash"><a href="#配置-logstash" class="headerlink" title="配置 logstash"></a>配置 logstash</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">mkdir /home/tjy/docker/logstash/</span><br><span class="line">mkdir /home/tjy/docker/logstash/conf.d/</span><br><span class="line">vi /home/tjy/docker/logstash/logstash.yml</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">path.config: /usr/share/logstash/conf.d/*.conf</span><br><span class="line">path.logs: /var/log/logstash</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /home/tjy/docker/logstash/conf.d/test.conf</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">input &#123;</span><br><span class="line">    beats &#123;</span><br><span class="line">    port =&gt; 5044</span><br><span class="line">    codec =&gt; &quot;json&quot;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">output &#123;</span><br><span class="line">  elasticsearch &#123; </span><br><span class="line">hosts =&gt; [&quot;xxx.xx.xxx.xx:9200&quot;]</span><br><span class="line">user =&gt; elastic </span><br><span class="line">    password =&gt; changeme </span><br><span class="line">&#125;</span><br><span class="line">  stdout &#123; codec =&gt; rubydebug &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="启动logstash并挂载"><a href="#启动logstash并挂载" class="headerlink" title="启动logstash并挂载"></a>启动logstash并挂载</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it -d -p 8011:5044 -p 9600:9600 --name logstash -v /home/tjy/docker/logstash/logstash.yml:/usr/share/logstash/config/logstash.yml -v /home/tjy/docker/logstash/conf.d/:/usr/share/logstash/conf.d/ docker.elastic.co/logstash/logstash:5.6.8</span><br></pre></td></tr></table></figure><h2 id="配置-filebeat"><a href="#配置-filebeat" class="headerlink" title="配置 filebeat"></a>配置 filebeat</h2><p>下载 通用配置文件</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">mkdir /Users/XXX/Downloads/Docker/filebeat/</span><br><span class="line">cd /Users/XXX/Downloads/Docker/filebeat</span><br><span class="line">wget https://raw.githubusercontent.com/elastic/beats/7.1/deploy/docker/filebeat.docker.yml</span><br><span class="line">vi filebeat.docker.yml</span><br></pre></td></tr></table></figure><p>配置监听 Nginx log</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">filebeat.config:</span><br><span class="line">  modules:</span><br><span class="line">    path: $&#123;path.config&#125;/modules.d/*.yml</span><br><span class="line">    reload.enabled: false</span><br><span class="line"></span><br><span class="line">filebeat.autodiscover:</span><br><span class="line">  providers:</span><br><span class="line">    - type: docker</span><br><span class="line">      hints.enabled: true</span><br><span class="line"></span><br><span class="line">processors:</span><br><span class="line">- add_cloud_metadata: ~</span><br><span class="line"></span><br><span class="line">filebeat.inputs:</span><br><span class="line">- type: log</span><br><span class="line">  enabled: true</span><br><span class="line">  paths:</span><br><span class="line">  - /var/log/nginx/*.log</span><br><span class="line"></span><br><span class="line">output.logstash:</span><br><span class="line">  hosts: [&#x27;logstash:5044&#x27;]</span><br></pre></td></tr></table></figure><h2 id="filebeat-配合-logstash-挂载并启动"><a href="#filebeat-配合-logstash-挂载并启动" class="headerlink" title="filebeat 配合 logstash 挂载并启动"></a>filebeat 配合 logstash 挂载并启动</h2><p>以下映射的路径为我自己电脑的路径，需要自行修改！</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name filebeat --user=root -d --net elkwork -v /usr/local/var/log/nginx/:/var/log/nginx/ -v /Users/XXX/Downloads/Docker/filebeat/filebeat.docker.yml:/usr/share/filebeat/filebeat.yml -v /var/run/docker.sock:/var/run/docker.sock store/elastic/filebeat:7.7.0</span><br></pre></td></tr></table></figure><figure class="image-bubble">                <div class="img-lightbox">                    <div class="overlay"></div>                    <img src="https://s1.ax1x.com/2020/06/03/tUHz8O.png" alt="success.png" title="">                </div>                <div class="image-caption">success.png</div>            </figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;引言&quot;&gt;&lt;a href=&quot;#引言&quot; class=&quot;headerlink&quot; title=&quot;引言&quot;&gt;&lt;/a&gt;引言&lt;/h2&gt;&lt;h3 id=&quot;介绍&quot;&gt;&lt;a href=&quot;#介绍&quot; class=&quot;headerlink&quot; title=&quot;介绍&quot;&gt;&lt;/a&gt;介绍&lt;/h3&gt;&lt;p&gt;基于L</summary>
      
    
    
    
    <category term="架构" scheme="https://sbcoder.cn/categories/%E6%9E%B6%E6%9E%84/"/>
    
    
    <category term="ElasticSearch" scheme="https://sbcoder.cn/tags/ElasticSearch/"/>
    
    <category term="kibana" scheme="https://sbcoder.cn/tags/kibana/"/>
    
    <category term="Logstash" scheme="https://sbcoder.cn/tags/Logstash/"/>
    
  </entry>
  
  <entry>
    <title>Docker 安装 PHP-fpm</title>
    <link href="https://sbcoder.cn/2020/05/17/Docker_PHP_fpm.html"/>
    <id>https://sbcoder.cn/2020/05/17/Docker_PHP_fpm.html</id>
    <published>2020-05-17T04:54:47.000Z</published>
    <updated>2020-06-05T09:10:42.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="创建-uploads-ini"><a href="#创建-uploads-ini" class="headerlink" title="创建 uploads.ini"></a>创建 uploads.ini</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">file_uploads = On</span><br><span class="line">memory_limit = 64 M</span><br><span class="line">upload_max_filesize = 20M</span><br><span class="line">post_max_size = 20M</span><br><span class="line">max_execution_time = 600</span><br></pre></td></tr></table></figure><h2 id="创建-Dockerfile"><a href="#创建-Dockerfile" class="headerlink" title="创建 Dockerfile"></a>创建 Dockerfile</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">FROM php:7.3-fpm</span><br><span class="line"></span><br><span class="line">RUN apt-get update</span><br><span class="line">RUN apt-get install -y libwebp-dev libjpeg-dev libpng-dev libfreetype6-dev</span><br><span class="line"></span><br><span class="line">EXPOSE 9000</span><br><span class="line"></span><br><span class="line">#上传配置成20M</span><br><span class="line">COPY uploads.ini /usr/local/etc/php/conf.d</span><br><span class="line"></span><br><span class="line">RUN docker-php-ext-install mysqli</span><br><span class="line">RUN docker-php-ext-install pdo</span><br><span class="line">RUN docker-php-ext-install pdo_mysql</span><br><span class="line">RUN pecl install redis-4.2.0 &amp;&amp; docker-php-ext-enable redis</span><br><span class="line">RUN docker-php-ext-install bcmath</span><br><span class="line">RUN docker-php-ext-configure gd  --with-webp-dir=/usr/include/webp --with-png-dir=/usr/include --with-jpeg-dir=/usr/include --with-freetype-dir=/usr/include/freetype2</span><br><span class="line">RUN docker-php-ext-install gd</span><br></pre></td></tr></table></figure><h2 id="Docker-build"><a href="#Docker-build" class="headerlink" title="Docker build"></a>Docker build</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build -t ai0by/php-fpm73:v1 .</span><br></pre></td></tr></table></figure><h2 id="运行容器"><a href="#运行容器" class="headerlink" title="运行容器"></a>运行容器</h2><p>挂载物理机内容到 容器内部 可以修改下方的 <code>/var/www/html/workspace</code> 为你的项目地址</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -v /var/www/html/workspace:/var/www/html/workspace  -p 9002:9000 -d php73:0.1</span><br></pre></td></tr></table></figure><h2 id="Nginx配置"><a href="#Nginx配置" class="headerlink" title="Nginx配置"></a>Nginx配置</h2><p>修改 <code>fastcgi_pass</code> 后面的 值为 <code>127.0.0.1:9002</code></p><p>LNMP用户 修改 <code>/usr/local/nginx/conf/enable-php-pathinfo.conf</code></p><p>将 <code>fastcgi_pass  unix:/tmp/php-cgi.sock;</code> 修改为 <code>fastcgi_pass  127.0.0.1:9002;</code></p><p>其他环境与此类似，直接改即可</p><h2 id="MySQL-Docker启动"><a href="#MySQL-Docker启动" class="headerlink" title="MySQL Docker启动"></a>MySQL Docker启动</h2><p>自行修改 挂载路径 以及 密码</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --restart=always --name mysql5.7 -p 3306:3306 -v /Users/XXX/Downloads/Docker/mysql5.7:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci</span><br></pre></td></tr></table></figure><p>Nginx 个人不习惯扔Docker中，因此暂时不管</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;创建-uploads-ini&quot;&gt;&lt;a href=&quot;#创建-uploads-ini&quot; class=&quot;headerlink&quot; title=&quot;创建 uploads.ini&quot;&gt;&lt;/a&gt;创建 uploads.ini&lt;/h2&gt;&lt;figure class=&quot;highlight </summary>
      
    
    
    
    <category term="PHP" scheme="https://sbcoder.cn/categories/PHP/"/>
    
    
    <category term="fpm" scheme="https://sbcoder.cn/tags/fpm/"/>
    
    <category term="nginx" scheme="https://sbcoder.cn/tags/nginx/"/>
    
  </entry>
  
</feed>
