<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://czasg.github.io/docusaurus/blog</id>
    <title>Czasg Blog</title>
    <updated>2023-10-09T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://czasg.github.io/docusaurus/blog"/>
    <subtitle>Czasg Blog</subtitle>
    <icon>https://czasg.github.io/docusaurus/img/dd.ico</icon>
    <entry>
        <title type="html"><![CDATA[常见锁机制]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/10/09/常见锁机制</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/10/09/常见锁机制"/>
        <updated>2023-10-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[常见锁机制有：]]></summary>
        <content type="html"><![CDATA[<p>常见锁机制有：</p><ul><li>互斥锁（Mutex）</li><li>读写锁（Read-Write Lock）</li><li>自旋锁（Spin Lock）</li><li>屏障（Barrier）</li><li>原子操作（Atomic Operations）</li><li>分布式锁（Distributed Lock）</li></ul><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="互斥锁">互斥锁<a href="#互斥锁" class="hash-link" aria-label="Direct link to 互斥锁" title="Direct link to 互斥锁">​</a></h3><p>互斥锁是最常见的锁机制之一。它允许只有一个线程或进程可以访问共享资源，其他线程或进程必须等待锁的释放才能访问。
互斥锁提供了最基本的线程同步机制，但如果不慎使用不当，可能会导致死锁问题。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="读写锁">读写锁<a href="#读写锁" class="hash-link" aria-label="Direct link to 读写锁" title="Direct link to 读写锁">​</a></h3><p>读写锁允许多个线程同时读取共享资源，但只有一个线程能够写入。这提高了读取操作的并发性能，但写入操作仍然是互斥的。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="自旋锁">自旋锁<a href="#自旋锁" class="hash-link" aria-label="Direct link to 自旋锁" title="Direct link to 自旋锁">​</a></h3><p>自旋锁（Spin Lock）是一种锁机制，它在尝试获取锁时不会阻塞线程，而是会一直尝试获取锁，如果锁已经被其他线程占用，它会一直忙等（自旋），直到锁变为可用状态。自旋锁的原理可以简单理解为以下几点：</p><ol><li><p><strong>无阻塞等待</strong>：自旋锁不会将线程挂起或阻塞，线程会一直尝试获取锁。因此，它适用于短期内锁被占用的情况，以减少线程切换的开销。</p></li><li><p><strong>忙等待</strong>：自旋锁会让线程忙等，也就是不停地检查锁是否可用。这会消耗CPU资源，因此不适用于长时间的等待。</p></li><li><p><strong>原子操作</strong>：为了确保线程在竞争锁时不会产生竞态条件，自旋锁通常使用原子操作来更新锁的状态。原子操作能够保证在多线程环境下的原子性。</p></li><li><p><strong>公平性</strong>：自旋锁通常是非公平的，它不考虑等待时间，只要锁可用就立即获取，不考虑其他线程是否在等待。</p></li></ol><p>使用场景：自旋锁在多核CPU上的性能较好，因为它可以减少线程切换的开销。但在单核CPU上使用自旋锁可能会导致性能下降，因为它会占用CPU时间。</p><p>自旋锁的适用场景通常是短期内锁的争用较小的情况，例如在多线程环境下对一些共享资源进行读写操作，或者在初始化阶段的互斥访问。在长时间的等待或大量线程争用的情况下，自旋锁可能不是最佳选择，因为它会浪费大量的CPU时间。</p><p>需要谨慎使用自旋锁，确保它在特定的场景中能够提供性能优势，同时避免忙等待时间过长导致的性能问题。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="屏障">屏障<a href="#屏障" class="hash-link" aria-label="Direct link to 屏障" title="Direct link to 屏障">​</a></h3><p>屏障（Barrier）是一种同步机制，用于协调多个线程的执行，确保它们在特定点上等待彼此完成，然后再一起继续执行。理解屏障的原理可以分为以下几个关键概念：</p><ol><li><p><strong>同步点</strong>：屏障通常在代码中的某个特定位置设置，这个位置被称为同步点。在同步点之前的线程会等待，直到所有线程都到达同步点才会继续执行。同步点可以用来确保多个线程在某个特定的执行阶段或时间点上进行同步。</p></li><li><p><strong>等待和唤醒</strong>：线程在达到屏障之前会等待，一旦所有线程都到达屏障，屏障会唤醒这些线程，使它们可以继续执行。屏障的等待和唤醒通常是由一个计数器来管理的，每个线程到达屏障时会将计数器减一，直到计数器减为零时，所有线程都被唤醒。</p></li><li><p><strong>线程协调</strong>：屏障用于协调多个线程的执行，确保它们在某个关键点上进行同步。这对于某些并发算法和多线程编程场景非常有用，例如并行计算、多阶段任务的协同工作等。</p></li><li><p><strong>阻塞和解除阻塞</strong>：在达到屏障之前，线程会被阻塞，无法继续执行。一旦所有线程都到达屏障，屏障将被解除，所有线程都可以继续执行。</p></li><li><p><strong>使用场景</strong>：屏障通常用于多线程协作的场景，例如在并行计算中，多个线程分别执行不同的计算任务，然后在某个阶段需要合并它们的计算结果，这时可以使用屏障等待所有线程完成各自的计算任务，然后再继续下一阶段的操作。</p></li></ol><p>总之，屏障是一种同步机制，它用于协调多个线程在某个同步点上的等待和继续执行，以确保线程之间的协同工作和同步。屏障的原理包括等待、唤醒、计数器管理等机制，它在多线程编程和并发算法中发挥着重要作用。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="原子操作">原子操作<a href="#原子操作" class="hash-link" aria-label="Direct link to 原子操作" title="Direct link to 原子操作">​</a></h3><p>原子操作是一种不需要显式锁的同步机制，它通过硬件支持的原子操作指令来确保对共享资源的原子访问。</p><p>CAS（Compare-And-Swap）是一种并发编程中常用的原子操作机制，用于实现多线程或多进程环境下的原子操作。
CAS操作是一种乐观锁（optimistic locking）的方式，其基本思想是：</p><ol><li>首先，读取共享变量的当前值。 </li><li>然后，与预期的旧值进行比较。</li><li>如果当前值等于预期的旧值，就将新值写入共享变量；否则，认为操作失败，不进行写入。 </li><li>最后，无论是否写入成功，都会返回操作之前的当前值。</li></ol><p>CAS操作的关键在于，它在操作共享变量时，不使用传统的加锁机制，而是通过比较当前值和预期的旧值，
来确定是否可以进行更新操作。这使得CAS操作可以在多线程环境下确保原子性，而无需显式锁定共享资源。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="分布式锁">分布式锁<a href="#分布式锁" class="hash-link" aria-label="Direct link to 分布式锁" title="Direct link to 分布式锁">​</a></h3><p>分布式锁用于多个计算节点之间的同步，以确保在分布式系统中的共享资源或临界区的互斥访问。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[kong和nginx区别]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/09/01/kong和nginx区别</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/09/01/kong和nginx区别"/>
        <updated>2023-09-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Kong 和 Nginx 是两种用于构建和管理 Web 服务和 API 网关的不同软件，它们在设计和用途上有一些区别：]]></summary>
        <content type="html"><![CDATA[<p>Kong 和 Nginx 是两种用于构建和管理 Web 服务和 API 网关的不同软件，它们在设计和用途上有一些区别：</p><ol><li><p><strong>用途</strong>：</p><ul><li><p><strong>Nginx</strong> 是一个高性能的反向代理服务器和 Web 服务器。它最初设计用于提供 Web 服务和处理 HTTP 请求，但后来也扩展到处理 TCP 和 UDP 请求。Nginx 被广泛用于提供 Web 内容和负载均衡，以及用作反向代理来处理客户端请求并将它们转发到后端服务器。</p></li><li><p><strong>Kong</strong> 是一个开源的 API 网关和微服务管理平台。它专注于管理和保护 API，包括认证、授权、访问控制、流量控制、监控等功能。Kong 提供了一个强大的插件系统，允许用户根据需要自定义和扩展其功能，以满足不同的 API 管理需求。</p></li></ul></li><li><p><strong>功能</strong>：</p><ul><li><p><strong>Nginx</strong> 主要用于处理网络请求、反向代理、负载均衡、静态文件服务和 Web 服务器功能。它可以用来提供 HTTP 和 HTTPS 服务，以及 TCP 和 UDP 代理功能。</p></li><li><p><strong>Kong</strong> 主要用于 API 管理和微服务架构。它提供了丰富的 API 管理功能，包括路由、认证、授权、限流、监控和日志记录等。Kong 还具备可扩展的插件系统，以支持各种自定义功能。</p></li></ul></li><li><p><strong>插件系统</strong>：</p><ul><li><p><strong>Nginx</strong> 有一些可用的模块和插件，但插件生态相对较小，而且定制性有限。</p></li><li><p><strong>Kong</strong> 的强大之处在于其插件系统。Kong 具有丰富的官方和社区插件，你可以使用这些插件来扩展 Kong 的功能，以满足特定的 API 管理需求。这使得 Kong 成为一个灵活的、可定制的 API 管理平台。</p></li></ul></li><li><p><strong>配置和管理</strong>：</p><ul><li><p><strong>Nginx</strong> 的配置通常以文本文件的形式进行，需要手动编辑配置文件。虽然有一些工具可以帮助简化配置，但仍然需要一定的系统管理技能。</p></li><li><p><strong>Kong</strong> 提供了一个基于 REST API 的管理界面，使得配置和管理更加简单和可视化。此外，Kong 也可以通过命令行工具进行配置管理。</p></li></ul></li></ol><p>一般来说：</p><ul><li>如果你需要构建一个 API 管理平台或者需要更高级的 API 管理功能，Kong 可能更适合你。</li><li>如果你只需要一个反向代理服务器和 Web 服务器，那么 Nginx 可能是更常见的选择。</li></ul><p>在某些情况下，也可以将它们结合使用，例如使用 Kong 作为 API 网关，同时使用 Nginx 来处理静态文件和负载均衡。</p><p>以下是一些配置上的区别和示例，展示了 Kong 和 Nginx 在用途和功能上的不同：</p><p><strong>1. Kong 配置示例：</strong></p><p>假设你想在 Kong 上创建一个 API，对请求进行认证，并应用速率限制。以下是一个 Kong 的配置示例：</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># Kong 配置文件示例（YAML 格式）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">admin_listen</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">8001</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">proxy_listen</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">8000</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">services</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> my</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">api</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">url</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain">//my</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">backend</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">service</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">routes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> my</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">api</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">route</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">paths</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> /api</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">plugins</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">auth</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> rate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">limit</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">config</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">minute</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">100</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在这个示例中，我们定义了一个名为 <code>my-api</code> 的服务，然后定义了一个路由，将请求路径 <code>/api</code> 与该服务关联。我们还启用了两个插件，一个是 <code>key-auth</code>，用于认证请求，另一个是 <code>rate-limit</code>，用于限制每分钟的请求数。</p><p><strong>2. Nginx 配置示例：</strong></p><p>假设你想使用 Nginx 来反向代理到后端服务器，并配置 HTTPS 支持。以下是一个 Nginx 的配置示例：</p><div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain"># Nginx 配置文件示例</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    listen 443 ssl;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server_name example.com;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    ssl_certificate /etc/nginx/ssl/example.com.crt;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    ssl_certificate_key /etc/nginx/ssl/example.com.key;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    location / {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_pass http://backend-server;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_set_header Host $host;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_set_header X-Real-IP $remote_addr;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">upstream backend-server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server 127.0.0.1:8080;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在这个示例中，我们配置了一个 Nginx 服务器来监听 HTTPS 请求，并将它们反向代理到后端服务器（<code>backend-server</code>）。我们还配置了 SSL 证书以启用安全连接。这是一个简单的反向代理配置，Nginx 还支持更多功能，如负载均衡、缓存等。</p><p><strong>区别和总结：</strong></p><ul><li><p>Kong 专注于 API 管理，提供了高级的 API 管理功能，例如路由、认证、限流等。配置通常以 YAML 或 JSON 格式进行。</p></li><li><p>Nginx 是一个通用的反向代理服务器和 Web 服务器，可以用于处理 HTTP 请求、负载均衡、反向代理等。配置通常以 Nginx 的专有配置语言进行。</p></li><li><p>Kong 提供了一个可视化的管理界面，可以通过 REST API 进行配置管理。</p></li><li><p>Nginx 提供了更广泛的用途，包括静态文件服务、负载均衡等，但在配置上可能需要更多的手动设置。</p></li></ul><p>因此，Kong 更适用于 API 管理，而 Nginx 更适用于通用的反向代理和 Web 服务器需求。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
    </entry>
    <entry>
        <title type="html"><![CDATA[linux常见目录说明]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/07/27/linux常见目录说明</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/07/27/linux常见目录说明"/>
        <updated>2023-07-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在 Linux 系统中，有一些特定的目录在整个操作系统中起着非常重要的作用。]]></summary>
        <content type="html"><![CDATA[<p>在 Linux 系统中，有一些特定的目录在整个操作系统中起着非常重要的作用。
这些目录是按照约定和设计用途来组织的，每个目录都有其特定的功能和用途。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="dev">/dev<a href="#dev" class="hash-link" aria-label="Direct link to /dev" title="Direct link to /dev">​</a></h2><ul><li><code>/dev</code> 是设备目录，用于存放设备文件，用于与硬件设备进行交互。</li><li>在 Linux 中，一切设备都被抽象成文件，这些设备文件位于 <code>/dev</code> 目录下。</li><li>例如：<ul><li><code>/dev/sda</code>: 硬盘设备的第一个分区。</li><li><code>/dev/ttyUSB0</code>: USB 串口设备。</li><li><code>/dev/null</code>: 特殊设备文件，用于丢弃数据，类似于黑洞。</li></ul></li><li>通过读写这些设备文件，用户和应用程序可以与硬件设备进行交互和通信。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="proc">/proc<a href="#proc" class="hash-link" aria-label="Direct link to /proc" title="Direct link to /proc">​</a></h2><ul><li><code>/proc</code> 是虚拟文件系统，提供了对内核和进程信息的访问接口。</li><li>它不是真正的文件系统，而是运行时内核状态的映射，允许用户和进程通过文件访问内核的信息。</li><li>例如：<ul><li><code>/proc/cpuinfo</code>: 包含了 CPU 的信息，比如型号、频率等。</li><li><code>/proc/meminfo</code>: 提供了系统内存的信息。</li><li><code>/proc/PID/status</code>: 对应特定进程的状态信息。</li></ul></li><li>使用 <code>/proc</code> 目录，用户可以动态地监视和配置内核参数，以及查看系统和进程的各种信息。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="bin">/bin<a href="#bin" class="hash-link" aria-label="Direct link to /bin" title="Direct link to /bin">​</a></h2><ul><li><code>/bin</code> 是二进制目录，包含了最基本的用户级别的命令和可执行文件。</li><li>这些文件通常是系统启动过程中所需的基本工具和命令，不依赖于其他目录或文件系统。</li><li>由于 <code>/bin</code> 目录在系统启动时就被挂载，所以即使出现文件系统问题，基本的系统工具也能够正常使用。</li><li>例如：<ul><li><code>/bin/ls</code>: 列出目录内容。</li><li><code>/bin/cat</code>: 查看文件内容。</li><li><code>/bin/cp</code>: 复制文件或目录。</li><li><code>/bin/mkdir</code>: 创建目录。</li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="etc">/etc<a href="#etc" class="hash-link" aria-label="Direct link to /etc" title="Direct link to /etc">​</a></h2><ul><li><code>/etc</code> 是配置文件目录，包含了系统和应用程序的配置文件。</li><li>这些配置文件用于设置各种系统参数、网络配置、服务的启动脚本等。</li><li>例如：<ul><li><code>/etc/passwd</code>: 包含用户账户信息。</li><li><code>/etc/hosts</code>: 存放主机名与 IP 地址的映射。</li><li><code>/etc/fstab</code>: 挂载文件系统的配置文件。</li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="home">/home<a href="#home" class="hash-link" aria-label="Direct link to /home" title="Direct link to /home">​</a></h2><ul><li><code>/home</code> 是用户主目录的父目录，每个用户在系统上都有一个对应的子目录，用于存放个人文件和配置。</li><li>用户主目录通常被表示为 <code>/home/username</code>，其中 <code>username</code> 是用户的登录名。</li><li>例如：<ul><li><code>/home/john</code>: 用户 John 的主目录。</li><li><code>/home/mary</code>: 用户 Mary 的主目录。</li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="usr">/usr<a href="#usr" class="hash-link" aria-label="Direct link to /usr" title="Direct link to /usr">​</a></h2><ul><li><code>/usr</code> 是 Unix 软件资源目录，包含了大部分用户安装的软件和应用程序。</li><li>它类似于 <code>/</code> 根目录，但主要用于存放不是系统启动所必需的文件。</li><li>例如：<ul><li><code>/usr/bin</code>: 存放用户安装的应用程序可执行文件。</li><li><code>/usr/lib</code>: 存放共享库文件。</li><li><code>/usr/share</code>: 存放共享数据文件，比如帮助文档、图标等。</li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="var">/var<a href="#var" class="hash-link" aria-label="Direct link to /var" title="Direct link to /var">​</a></h2><ul><li><code>/var</code> 是变量目录，包含经常变化的文件，如日志文件、邮件、数据库等。</li><li>它通常包含一些在运行时需要改变大小的文件，以及某些服务的运行时状态。</li><li>例如：<ul><li><code>/var/log</code>: 存放系统和应用程序的日志文件。</li><li><code>/var/spool</code>: 存放邮件和打印队列等临时文件。</li><li><code>/var/www</code>: 存放 web 服务器的网站数据。</li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="tmp">/tmp<a href="#tmp" class="hash-link" aria-label="Direct link to /tmp" title="Direct link to /tmp">​</a></h2><ul><li><code>/tmp</code> 是临时目录，用于存放临时文件和临时数据。</li><li>这些文件在系统重启时通常会被清除。</li><li>由于它是共享目录，因此所有用户都可以在 <code>/tmp</code> 目录下创建和访问临时文件。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="sbin">/sbin<a href="#sbin" class="hash-link" aria-label="Direct link to /sbin" title="Direct link to /sbin">​</a></h2><ul><li><code>/sbin</code> 是系统管理员命令目录，包含一些系统管理和维护的命令。</li><li>这些命令通常用于系统的管理任务，只有管理员才有权限执行这些命令。</li><li>例如：<ul><li><code>/sbin/reboot</code>: 重启系统。</li><li><code>/sbin/ifconfig</code>: 配置网络接口。</li></ul></li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="boot">/boot<a href="#boot" class="hash-link" aria-label="Direct link to /boot" title="Direct link to /boot">​</a></h2><ul><li><code>/boot</code> 是启动目录，包含了系统启动所需的文件，如内核文件和启动加载器配置。</li><li>当系统启动时，系统加载程序 (boot loader) 会从这个目录中找到内核并加载。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="lib">/lib<a href="#lib" class="hash-link" aria-label="Direct link to /lib" title="Direct link to /lib">​</a></h2><ul><li><code>/lib</code> 用于存放共享库文件。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="root">/root<a href="#root" class="hash-link" aria-label="Direct link to /root" title="Direct link to /root">​</a></h2><ul><li><code>/root</code> 是超级用户（root）的主目录，也称为 root 主目录。</li><li>超级用户是系统中拥有最高权限的用户，它的主目录位于 <code>/root</code>。</li><li>不同于一般用户的主目录（在 <code>/home</code> 目录下），root 主目录的权限只有 root 用户才能访问。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="opt">/opt<a href="#opt" class="hash-link" aria-label="Direct link to /opt" title="Direct link to /opt">​</a></h2><ul><li><code>/opt</code> 是可选目录，用于存放第三方软件包或额外安装的软件。</li><li>当某些软件包不遵循标准的文件系统层次结构时，可以选择将它们安装在 <code>/opt</code> 目录下，以保持整洁性。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="etcopt">/etc/opt<a href="#etcopt" class="hash-link" aria-label="Direct link to /etc/opt" title="Direct link to /etc/opt">​</a></h2><ul><li><code>/etc/opt</code> 是 <code>/opt</code> 目录的配置文件目录，用于存放与 <code>/opt</code> 目录中安装软件相关的配置文件。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="srv">/srv<a href="#srv" class="hash-link" aria-label="Direct link to /srv" title="Direct link to /srv">​</a></h2><ul><li><code>/srv</code> 是服务数据目录，用于存放系统服务（如 Web 服务器、FTP 服务器等）的数据文件。</li><li>例如，网站的文档根目录和用户上传的文件通常可以放在 <code>/srv</code> 目录下。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="mnt">/mnt<a href="#mnt" class="hash-link" aria-label="Direct link to /mnt" title="Direct link to /mnt">​</a></h2><ul><li><code>/mnt</code> 是挂载目录，用于手动挂载临时文件系统或其他设备。</li><li>当需要将外部存储设备（如 USB 驱动器、CD-ROM 等）连接到系统时，可以使用 <code>/mnt</code> 进行挂载。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="media">/media<a href="#media" class="hash-link" aria-label="Direct link to /media" title="Direct link to /media">​</a></h2><ul><li><code>/media</code> 是媒体挂载目录，用于自动挂载可移动媒体设备，如 USB 驱动器和光盘。</li><li>当插入可移动媒体设备时，系统通常会自动将其挂载到 <code>/media</code> 目录下的适当子目录中。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="run">/run<a href="#run" class="hash-link" aria-label="Direct link to /run" title="Direct link to /run">​</a></h2><ul><li><code>/run</code> 是临时运行时数据目录，用于存放系统启动后产生的临时运行时文件。</li><li>这个目录中的数据通常在系统重启时会被清理，不同于 <code>/var</code> 目录中的持久性数据。</li></ul><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>这些目录是 Linux 系统中重要的一部分，每个目录都有其特定的用途和作用。
同时，它们的设计也体现了 Linux 系统的灵活性和一致性，使得 Linux 成为一种强大且易于管理的操作系统。</p></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="linux" term="linux"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[后端技术框架与架构的探索实践]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/06/09/后端技术框架探索与实践</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/06/09/后端技术框架探索与实践"/>
        <updated>2023-06-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在现代 Web 开发中，技术框架与架构之间是相辅相成的关系，它们在后端开发中都扮演着至关重要的角色。]]></summary>
        <content type="html"><![CDATA[<p>在现代 Web 开发中，技术框架与架构之间是相辅相成的关系，它们在后端开发中都扮演着至关重要的角色。
因此，学习框架在开发过程中的作用，了解架构的演进，是每位后端开发者都应该具备的重要知识。</p><p>通过本文，你可以学习并了解以下内容：</p><ul><li>后端技术框架的重要性和作用</li><li>后端技术架构的发展趋势</li><li>常见后端技术框架</li><li>技术框架选择与评估</li><li>后端技术框架实践</li></ul><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="后端技术框架的重要性和作用">后端技术框架的重要性和作用<a href="#后端技术框架的重要性和作用" class="hash-link" aria-label="Direct link to 后端技术框架的重要性和作用" title="Direct link to 后端技术框架的重要性和作用">​</a></h3><p>后端技术框架提供了一个结构化的框架，帮助开发人员构建高效、可靠和可扩展的后端应用程序。
这些框架简化了开发过程，提高了效率，促进了代码的组织和可维护性。</p><p>在后端技术框架中，最常见的核心模块之一是对 HTTP 请求处理的封装。一次完整的 HTTP 请求过程包括：</p><ol><li><strong>接收请求</strong>：框架通过网络监听和接收传入的 HTTP 请求。</li><li><strong>请求报文解析</strong>：框架负责解析请求报文，提取出请求的方法、URL、请求头和请求体等信息。</li><li><strong>业务逻辑处理</strong>：框架将请求路由到相应的处理程序或控制器，执行具体的业务逻辑，可能涉及数据库操作、外部服务调用等。</li><li><strong>响应报文构建</strong>：在业务处理完成后，框架根据处理结果构建响应报文，包括设置响应状态码、响应头和响应体等内容。</li><li><strong>发送响应</strong>：框架将构建好的响应报文发送回客户端，完成一次完整的请求-响应周期。</li></ol><div class="tabs-container tabList__CuJ"><ul role="tablist" aria-orientation="horizontal" class="tabs"><li role="tab" tabindex="0" aria-selected="true" class="tabs__item tabItem_LNqP tabs__item--active">请求报文示例</li><li role="tab" tabindex="-1" aria-selected="false" class="tabs__item tabItem_LNqP">响应报文示例</li></ul><div class="margin-top--md"><div role="tabpanel" class="tabItem_Ymn6"><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">GET / HTTP/1.1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Content-Type: text/html</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Content-Length: 8</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Connection: keep-alive</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Accept-Encoding: gzip, deflate, br</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Accept-Language: zh-CN,zh;q=0.9,en;q=0.8</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">req body</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div><div role="tabpanel" class="tabItem_Ymn6" hidden=""><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">HTTP/1.1 200 OK</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Content-Type: text/html</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Content-Length: 9</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Connection: keep-alive</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Content-Encoding: gzip</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Date: Fri, 23 Jun 2023 14:00:49 GMT</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">resp body</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div></div><p>除了对 HTTP 请求的支持之外，技术框架还可以提供对开发流程的规范约束和最佳实践。
框架能够简化技术人员对底层细节的处理，并提供开发过程中所需的工具、库和组件，以加速应用程序的开发。</p><p>我们可以总结出现代后端技术框架在web开发过程中发挥的作用：</p><ul><li>加速开发，提高效率</li><li>抽象底层细节</li><li>标准化架构设计和模式</li><li>丰富的工具/组件库</li></ul><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="后端技术架构的发展趋势">后端技术架构的发展趋势<a href="#后端技术架构的发展趋势" class="hash-link" aria-label="Direct link to 后端技术架构的发展趋势" title="Direct link to 后端技术架构的发展趋势">​</a></h3><p>随着业务复杂度以及开发团队规模的不断扩大，后端技术架构呈现以下发展趋势：</p><ul><li>单体架构</li><li>分布式架构</li><li>微服务架构</li><li>云原生架构</li><li>无服务器架构</li></ul><p>让我们分别了解下每一个阶段架构的特点，以更好地理解它们的优势和适用场景。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="单体架构">单体架构<a href="#单体架构" class="hash-link" aria-label="Direct link to 单体架构" title="Direct link to 单体架构">​</a></h4><p>单体架构是传统的应用架构模式，它将整个应用作为一个单一的、完整的系统进行开发和部署，具有简单、易于开发和测试的优点。</p><p>但随着业务的增长，可能面临扩展和维护的挑战。包括：</p><ul><li><strong>单点风险</strong>：一旦应用服务异常，则可能导致整个服务异常</li><li><strong>可扩展性有限</strong>：单体架构在应对大规模和高并发的需求时存在单机瓶颈限制，难以实现水平扩展</li></ul><p><img loading="lazy" alt="单体架构" src="/docusaurus/assets/images/single-dfb3b58c159c689fc79fc1567b506c9e.png" width="1111" height="294" class="img_ev3q"></p><p>为了解决以上问题，业界衍生出了分布式架构和多服务部署的方式。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="分布式架构">分布式架构<a href="#分布式架构" class="hash-link" aria-label="Direct link to 分布式架构" title="Direct link to 分布式架构">​</a></h4><p>分布式架构将应用程序拆分为多个独立的模块，每个模块可以部署在不同的服务器或计算节点上。
通过分布式架构，可以实现系统的横向扩展和高可用性，并提供更好的性能和容错能力。</p><p>在分布式架构中，我们往往容易混淆它和多服务部署之间的关系。</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>如何理解分布式与多服务部署之间的关系</div><div class="admonitionContent_S0QG"><p>分布式架构是一种系统架构的设计模式，它通过将系统拆分为多个组件并分布在不同节点上来提高可扩展性和性能。</p><p>多服务部署，则是分布式架构中的一种实践方式，
它通过将应用拆分为多个微服务并在多个节点上进行部署来提高系统的可靠性和容错性。</p></div></div><p>分布式架构虽然解决了单点故障与瓶颈问题，但随着业务的增长，可能面临系统复杂度提升的挑战。主要包括：</p><ul><li><strong>系统复杂性增加</strong>：分布式架构中的各个组件和服务之间需要进行协同和管理，系统的复杂性增加。</li><li><strong>异常定位困难</strong>：分布式架构往往涉及多个组件和服务之间的协同工作。一旦出现异常，跨服务的工作模式可能会给问题定位增加难度。</li></ul><p><img loading="lazy" alt="分布式架构" src="/docusaurus/assets/images/distributed-7a82e85ee8a9a652071f7853e01fa249.png" width="1034" height="345" class="img_ev3q"></p><p>因此，如何按照一定的业务边界划分系统功能模块，提高模块的可复用性和可维护性就显得很关键了。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="微服务架构">微服务架构<a href="#微服务架构" class="hash-link" aria-label="Direct link to 微服务架构" title="Direct link to 微服务架构">​</a></h4><p>当我们有了按业务拆分应用模块的想法时，做出来的产品就具有了微服务的雏形了。</p><p>其实在微服务成为潮流之前，还有一个很热门的阶段，就是我们常说的面向服务的架构（Service-Oriented Architecture，简称SOA）。
因为它们都具有<strong>拆</strong>的思想，所以很多同学都往往容易混淆。</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>如何理解微服务架构与SOA架构之间的关系</div><div class="admonitionContent_S0QG"><p>面向服务的架构（Service-Oriented Architecture，简称SOA）是一种以服务为中心的架构模式，
它将应用程序划分为一系列独立的、可重用的服务组件。
这些服务通过标准化的接口和协议进行通信，实现松耦合和可组合的系统构建。</p><p>其中，有一个著名的实践方式就是企业服务总线架构（Enterprise Service Bus，简称ESB）。</p><p><img loading="lazy" alt="ESB" src="/docusaurus/assets/images/esb-c62c21a97872f699b5bd463a9d7fd882.png" width="1003" height="418" class="img_ev3q"></p><p>ESB采用中心化的总线架构，将服务治理能力集成到中心的ESB中。在这种架构中，总线模块将变得及其臃肿，这也是一个弊端吧。</p><p>在SOA架构中，服务之间不够绝对的独立，因为它们总是通过ESB进行绑定。</p><p>对比微服务的话，可以把微服务简单理解为"去掉ESB的SOA"。
或者是另一种<strong>更加独立的"拆法"</strong>。</p></div></div><p>微服务架构是一种基于分布式架构的设计模式，它将应用程序拆分为一组小型、独立的服务。
每个服务都可以<strong>独立开发、部署和扩展</strong>。其中，不同程序之间通过轻量级通信机制（SDK）进行互相协作。
微服务架构具有<strong>高度可扩展性、灵活性和自治性</strong>的特点。</p><p><img loading="lazy" alt="微服务架构" src="/docusaurus/assets/images/micro-1b8aa286425b3ef5fbbe296cab258974.png" width="1483" height="581" class="img_ev3q"></p><p>当然，微服务拆多了也是一场运维灾难。实际拆分场景应该<strong>综合考虑业务（程序）的独立性、复用性和整体架构复杂度</strong>。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="云原生架构">云原生架构<a href="#云原生架构" class="hash-link" aria-label="Direct link to 云原生架构" title="Direct link to 云原生架构">​</a></h4><p>随着容器化技术的兴起，云原生架构得到了广泛应用。</p><p>云原生架构是为云环境设计和构建的应用架构，利用云服务提供的<strong>弹性、可扩展和自动化特性</strong>。
它强调<strong>容器化部署、动态编排和自动化管理</strong>，以适应云环境的要求。</p><p>当前应用市场基本就是 K8S 全家桶了。</p><p><img loading="lazy" alt="云原生架构" src="/docusaurus/assets/images/k8s-b9b6153142a30c31d2f710f1fd0a1bc9.png" width="1424" height="506" class="img_ev3q"></p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="无服务器架构">无服务器架构<a href="#无服务器架构" class="hash-link" aria-label="Direct link to 无服务器架构" title="Direct link to 无服务器架构">​</a></h4><p>无服务器架构（Serverless Architecture）是一种以<strong>事件驱动</strong>和<strong>函数计算</strong>为核心的架构模式。
在无服务器架构中，开发人员可以编写独立的函数，由云平台自动管理函数的部署和资源分配，无需关心底层的服务器和基础设施。</p><p><img loading="lazy" alt="无服务器架构" src="/docusaurus/assets/images/aws-9b581d9de890a7e81dec5f539eb8bbb0.png" width="1132" height="423" class="img_ev3q"></p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="常见后端技术框架">常见后端技术框架<a href="#常见后端技术框架" class="hash-link" aria-label="Direct link to 常见后端技术框架" title="Direct link to 常见后端技术框架">​</a></h3><p>后端技术框架的生态圈是非常丰富的。此处仅列举部分有代表性的框架：</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="极简主义">极简主义<a href="#极简主义" class="hash-link" aria-label="Direct link to 极简主义" title="Direct link to 极简主义">​</a></h4><p>所谓极简主义，就是框架本身没有任何限制，它仅仅提供最基础的Web开发能力。开发人员可以自由实现项目架构与内容组织。</p><p>Flask 就是典型的极简主义框架。它是一个轻量级且易用的框架，适合作为入门框架。</p><p>但这并不意味着 Flask 就没有任何深度了。要想深入学习和进阶一个框架，也是一件不容易的事。
如果你不了解 Flask 的蓝图、钩子、线程本地数据等机制，那你可能还需要再研究研究。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="全能战士">全能战士<a href="#全能战士" class="hash-link" aria-label="Direct link to 全能战士" title="Direct link to 全能战士">​</a></h4><p>能被称作"全能战士"的框架，一定都是市场占有度非常高的。而 Django 就是典型的"全能战士"框架。</p><p>相比于极简主义，Django 在设计上更加全面，它提供了更多的内置功能和约定，旨在为开发人员提供最大的开发效率和生产力。
它包含了诸多功能，例如对象关系映射（ORM）、认证和授权系统、管理界面、表单处理、缓存机制等等。
这些内置功能使得 Django 成为一个完整而强大的框架，适用于大型和复杂的Web应用程序的开发。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="微服务框架">微服务框架<a href="#微服务框架" class="hash-link" aria-label="Direct link to 微服务框架" title="Direct link to 微服务框架">​</a></h4><p>看名字就知道是老潮流了。此处我们以 B 站开源的 Kratos 为例简单介绍下。</p><p>Kratos 是一款开源的微服务框架，由 Bilibili 开发并开源。
它是基于 Go 语言构建的，旨在帮助开发人员更轻松地构建高性能、可扩展的微服务应用程序。</p><p>相比于我们的"全能战士"，微服务框架还提供了微服务治理的能力。
包括我们常说的服务注册与发现、负载均衡、熔断器等，这些可以帮助开发人员更好地管理和监控微服务应用。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="技术框架选择与评估">技术框架选择与评估<a href="#技术框架选择与评估" class="hash-link" aria-label="Direct link to 技术框架选择与评估" title="Direct link to 技术框架选择与评估">​</a></h3><p>那么有这么多技术框架，我们如何选择和评估最合适的技术框架呢？</p><p>通常情况下，<strong>减少变量是最佳选择</strong>。</p><p>比如你身处在一个团队中，那么使用团队中已有的技术框架是最佳选择。</p><p>因为引入新的技术不仅有一定的学习成本，在某些时候甚至会引入风险。因为"前沿"技术并不一定是"稳定"的。</p><p>如果确实需要重新选择技术框架，应优先从业务角度出发进行评估和选择。</p><ul><li>对于重点交付的项目，可以考虑Java Spring全家桶，它在国内具有广泛的应用。</li><li>对于高性能云端项目，可以考虑使用Go语言，它在性能和内存占用方面具有优势。</li><li>对于一次性交付的工具、爬虫等，可以考虑使用Python实现快速交付。</li></ul><p>当然，这仅仅只是其中的部分选择。对于具有成熟脚手架的团队来说，可以按照团队的技术栈灵活选择。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="后端技术框架实践">后端技术框架实践<a href="#后端技术框架实践" class="hash-link" aria-label="Direct link to 后端技术框架实践" title="Direct link to 后端技术框架实践">​</a></h3><p>这里主要介绍一下作者的开源项目 Pywss。</p><p>Pywss（发音 /piːwaɪz/，类似 p~whys）是一个轻量级的 Python Web 框架，它基于 Python3.6+ 特性构建。</p><p>与 Flask、Django 等主流框架不同的是，Pywss 的底层并没有实现 WSGI 接口协议。
其编程风格也更类似于 Gin、Iris 等框架，因此对于熟悉这些框架的开发者来说，Pywss 是一个非常值得探索的项目。</p><p>其关键特性有：</p><ul><li>简单：拒绝海量参数，减少心智负担。了解上下文 pywss.Context 即刻启程。</li><li>快速：纯手撸 socket，拒绝中间商赚取性能差价。(实在有性能追求的同学，不妨再探索下其他语言~Go~)</li><li>优雅：ctx.next 真的太优雅了。如果你也和我一样喜欢，那我觉得这件事情，泰裤辣！！</li><li>标准化：集成了部分 OpenAPI（Swagger）能力，方便开发者快速生成 API 文档并进行调试。</li><li>支持WebSocket：开箱即用的 WebSocket 能力。</li><li>接口测试：开箱即用的 API 测试模块，不启动服务也能测试接口功能辣！</li></ul><p>在线文档 <a href="https://czasg.github.io/pywss/" target="_blank" rel="noopener noreferrer">https://czasg.github.io/pywss/</a></p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="后端" term="后端"/>
        <category label="分享" term="分享"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[OSI七层模式]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/04/12/OSI七层模式</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/04/12/OSI七层模式"/>
        <updated>2023-04-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[OSI（Open Systems Interconnection）是一个用于理解和描述计算机网络通信协议的参考模型。]]></summary>
        <content type="html"><![CDATA[<p>OSI（Open Systems Interconnection）是一个用于理解和描述计算机网络通信协议的参考模型。
它将计算机网络通信过程划分为七个不同的层次，每个层次负责特定的功能，各层之间通过接口进行交互。</p><ol><li><p><strong>应用层（Application Layer）</strong>：</p><ul><li><p>应用层是用户与网络通信的接口，负责为应用程序提供网络服务。
它包括各种应用协议，例如HTTP、FTP、SMTP等。在这一层上，数据被封装成应用层数据包。</p></li><li><p>举例：当您使用Web浏览器访问一个网站时，浏览器会使用HTTP协议发送请求，该请求是在应用层上创建的数据包。</p></li></ul></li><li><p><strong>表示层（Presentation Layer）</strong>：</p><ul><li>表示层负责数据的格式转换和加密解密等操作，确保不同系统之间能够正确地解释数据。在TCP/IP协议族中，表示层的功能很少被使用，因为大多数应用程序在应用层处理了数据格式的问题。</li></ul></li><li><p><strong>会话层（Session Layer）</strong>：</p><ul><li>会话层负责建立、管理和终止会话连接，确保通信双方之间的通信顺序和数据完整性。在TCP/IP协议族中，会话层的功能也很少被使用，因为这些任务通常由应用层处理。</li></ul></li><li><p><strong>传输层（Transport Layer）</strong>：</p><ul><li><p>传输层提供端到端的数据传输服务。最常用的协议是TCP（Transmission Control Protocol）和UDP（User Datagram Protocol）。</p></li><li><p>举例：当您在Web浏览器中访问一个网站时，浏览器会使用TCP协议建立一个与服务器的连接，确保数据的可靠传输。而在视频会议或实时游戏等场景中，可能会使用UDP协议，因为它具有较低的延迟，但可靠性较差。</p></li></ul></li><li><p><strong>网络层（Network Layer）</strong>：</p><ul><li><p>网络层负责数据包的路由和转发，以及IP地址的分配。最常用的协议是IP（Internet Protocol）。</p></li><li><p>举例：在互联网上，当您的计算机发送一个数据包到目标服务器时，数据包会在网络层被路由器转发，根据目标IP地址找到正确的路径。</p></li></ul></li><li><p><strong>数据链路层（Data Link Layer）</strong>：</p><ul><li><p>数据链路层负责将数据包封装成数据帧，处理物理地址（MAC地址）和错误检测等。最常用的协议是以太网（Ethernet）。</p></li><li><p>举例：在局域网中，当您的计算机发送一个数据帧到另一台计算机时，数据帧会在数据链路层添加源MAC地址和目标MAC地址，然后通过交换机或直接连接到目标计算机的设备传输。</p></li></ul></li><li><p><strong>物理层（Physical Layer）</strong>：</p><ul><li><p>物理层负责数据的物理传输，包括电缆、网卡、光纤等物理设备和接口。</p></li><li><p>举例：当数据帧在计算机之间通过网线传输时，物理层将数据转换为电信号，并通过网卡的物理接口发送到传输媒介上。</p></li></ul></li></ol><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="计算机" term="计算机"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[defer坑点收录]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/03/21/defer三规三返</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/03/21/defer三规三返"/>
        <updated>2023-03-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Go defer 史诗级坑点整理！]]></summary>
        <content type="html"><![CDATA[<p>Go defer 史诗级坑点整理！</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="入参是确定的">入参是确定的<a href="#入参是确定的" class="hash-link" aria-label="Direct link to 入参是确定的" title="Direct link to 入参是确定的">​</a></h3><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">demo</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    i </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">defer</span><span class="token plain"> fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">i</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// 输出1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    i</span><span class="token operator" style="color:rgb(212, 212, 212)">++</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> i</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>入参在 defer 出现时刻已经确定，因为执行 <code>defer fmt.Println(i)</code> 时已经生成临时变量拷贝了一份参数。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="后近先处">后近先处<a href="#后近先处" class="hash-link" aria-label="Direct link to 后近先处" title="Direct link to 后近先处">​</a></h3><p>这个通常没有问题，即后面定义的 defer 会先执行，很好理解。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="可操作具名参数返回">可操作具名参数返回<a href="#可操作具名参数返回" class="hash-link" aria-label="Direct link to 可操作具名参数返回" title="Direct link to 可操作具名参数返回">​</a></h3><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">demo</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">result </span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    i </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">defer</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        result</span><span class="token operator" style="color:rgb(212, 212, 212)">++</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// demo函数返回值为2</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> i</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>此处函数 return 实际可以拆解为两步，即：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">result </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> i</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>故 defer 会修改此处实际返回值。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="不可操作非具名返回">不可操作非具名返回<a href="#不可操作非具名返回" class="hash-link" aria-label="Direct link to 不可操作非具名返回" title="Direct link to 不可操作非具名返回">​</a></h3><p>同样的函数我们作下适当的调整</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">demo</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    i </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">defer</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        i</span><span class="token operator" style="color:rgb(212, 212, 212)">++</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">// demo函数返回值为1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> i</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在执行 return 的时候，已经生成临时变量存储返回值，故延迟函数 defer 无法对返回值做出修改。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[管理者如何评价待转正员工]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/03/12/管理者如何评价待转正员工</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/03/12/管理者如何评价待转正员工"/>
        <updated>2023-03-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[管理者如何评价待转正员工]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="管理者如何评价待转正员工">管理者如何评价待转正员工<a href="#管理者如何评价待转正员工" class="hash-link" aria-label="Direct link to 管理者如何评价待转正员工" title="Direct link to 管理者如何评价待转正员工">​</a></h2><p>作为一个管理者，我们通常从以下几个方面考虑或评价一名员工：</p><ul><li>工作表现</li><li>团队合作能力</li><li>个人素养</li></ul><p>对于快要转正的员工，应该针对以上几个方面进行评价，并给出相应的建议。</p><p>首先是<strong>工作表现</strong>。我会考虑员工在工作中的表现，包括完成任务的效率、工作质量、创新能力等。
如果员工在这些方面表现良好，我会积极推荐他转正，并给出具体的工作建议，帮助他进一步提升工作表现。</p><p>其次是<strong>团队合作能力</strong>。一个好的员工应该具备良好的团队合作能力，能够与其他团队成员有效地沟通和协作。
如果员工在这方面表现良好，我会鼓励他在团队中继续发挥作用，并给出一些团队合作方面的建议。</p><p>最后是<strong>个人素养</strong>。一个好的员工应该具备高度的职业素养，包括诚实、守时、自律等。
如果员工在这方面表现良好，我会积极推荐他转正，并给出一些个人素养方面的建议，帮助他进一步提升自己。</p><p>综上所述，作为一个管理者，需要从多个方面综合评估员工，并给出积极的评价和建议，帮助他们更好地成长和发展。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="职场" term="职场"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[python写入csv乱码问题]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/03/09/python写入csv乱码问题</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/03/09/python写入csv乱码问题"/>
        <updated>2023-03-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[正常的写入代码如下，但实际打开结果会是乱码！]]></summary>
        <content type="html"><![CDATA[<p>正常的写入代码如下，但实际打开结果会是乱码！</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> csv</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">open</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"file.csv"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"w"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> encoding</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"utf-8"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> newline</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">""</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    csv_w </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> csv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">write</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    csv_w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">writerow</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">"中文乱码"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>通过排查，发现改变编码方式可以解决这个问题。即把<code>utf-8</code>变更为<code>utf-8-sig</code>编码。</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> csv</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">open</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"file.csv"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"w"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> encoding</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"utf-8-sig"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> newline</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">""</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    csv_w </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> csv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">write</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    csv_w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">writerow</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">"中文正常展示"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>原因分析：</p><p>uft-8-sig 中的 sig 表示 signature，也就是带有签名的 utf-8。</p><p>Excel 在读取 csv 文件的时候是通过读取文件头上的 BOM 来识别编码。如果文件头没有 BOM 信息，则默认按照 Unicode 编码读取。</p><p>当我们使用 utf-8 编码来生成 csv 文件的时候，由于并没有生成 BOM 信息，Excel 就会自动按照 Unicode 编码读取，从而导致了乱码问题。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[jwt学习]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/03/08/jwt学习</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/03/08/jwt学习"/>
        <updated>2023-03-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[JWT 全称 JSON Web Token，是一种允许携带非敏感信息的认证机制。常用于服务之间的认证校验。]]></summary>
        <content type="html"><![CDATA[<p>JWT 全称 JSON Web Token，是一种允许携带非敏感信息的认证机制。常用于服务之间的认证校验。</p><p>JWT 结构组成包括三个部分：</p><ul><li>Header：一般用于指定token类型，包括<code>alg</code>和<code>typ</code>两个字段</li><li>Payload：数据载体，一般需要包含<code>exp</code>表示过期时间</li><li>Signature：摘要，是前面两个部分的摘要运算</li></ul><p>组成形式为 Header计算Base64 . Payload计算Base64 . 前两部分哈希运算</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">https://github.com/czasg/pywss/blob/master/pywss/middleware/jwt.py</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> json</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> base64</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> hashlib</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">class</span><span class="token plain"> </span><span class="token class-name" style="color:rgb(78, 201, 176)">JWT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">__init__</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">str</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> expire</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3600</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">secret </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> secret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">expire </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> expire</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">header </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> base64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">b64encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">json</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">dumps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token string" style="color:rgb(206, 145, 120)">"alg"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"HS256"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token string" style="color:rgb(206, 145, 120)">"typ"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"JWT"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> ensure_ascii</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">False</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">encrypt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">**</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        kwargs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">exp</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">+</span><span class="token plain"> self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">expire</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        payload </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> base64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">b64encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">json</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">dumps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">kwargs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> ensure_ascii</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">False</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> hashlib</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">header</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">secret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        signature </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">hexdigest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token string-interpolation string" style="color:rgb(206, 145, 120)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string-interpolation interpolation">self</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string-interpolation interpolation">header</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string-interpolation interpolation">decode</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string-interpolation string" style="color:rgb(206, 145, 120)">.</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string-interpolation interpolation">payload</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string-interpolation interpolation">decode</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string-interpolation string" style="color:rgb(206, 145, 120)">.</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string-interpolation interpolation">signature</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string-interpolation string" style="color:rgb(206, 145, 120)">"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">decrypt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> token</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">str</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">dict</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token plain"> token</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">startswith</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Bearer"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            token </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> token</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">replace</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Bearer"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">""</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">strip</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        tokens </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> token</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">split</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"."</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">len</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">tokens</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token keyword" style="color:rgb(86, 156, 214)">raise</span><span class="token plain"> Exception</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid JWT Token"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        header</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> payload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> signature </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> tokens  </span><span class="token comment" style="color:rgb(106, 153, 85)"># type: str</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> hashlib</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">header</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">update</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">self</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">secret</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token plain"> sha256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">hexdigest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> signature</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            </span><span class="token keyword" style="color:rgb(86, 156, 214)">raise</span><span class="token plain"> Exception</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Invalid JWT Token, Signature Except"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">loads</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">base64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">b64decode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">payload</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="后端" term="后端"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[正则学习总结]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/03/02/正则学习总结</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/03/02/正则学习总结"/>
        <updated>2023-03-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文作者: Czasg]]></summary>
        <content type="html"><![CDATA[<div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">()为了提取匹配字符串，(.*)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[]定义匹配的字符范围，[a-zA-Z0-9]   --- 只能取这里面的一个</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">{}定义匹配的长度，{0-9}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(0-9)匹配'0-9'本身</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[0-9]*匹配数字，若在里面加入了^表示取非，如([^\d].*)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[0-9]{0,9}表示长度为0-9的数字字符串</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">*可以表示为{0,}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+可以表示为{1,}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">?可以表示为{0,1}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">在正则中，你要匹配多种，需要使用到[]，比如：([\s\S]*)，你这样才能匹配带任何数据</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">而这句话，我们可以加入 flags=re.S 表示 . 可以去到任何数据</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">而且 [匹配-—] 只能匹配到这里面的某一个字，无法具体匹配其字串</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">此时我们可以使用 (?:匹配|-|—)这样就可以了</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;=(href=)) 表示匹配以(href=)开发的字符串，并且存储到分组中</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?=(href=)) 表示匹配以(href=)结尾的字符串，并且存储到分组中</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;=(?:href=)) 表示匹配以(href=)开发的字符串，但不存储到分组中</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?=(?:href=)) 表示匹配以(href=)结尾的字符串，但不存储到分组中</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?:)  (czaissg|czaisorz) 就是 (czais(?:sg|orz))  </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">可以简化表达式</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?=) (czaissg(?=1|2)) 可以匹配'czaissg1' / 'czaissg2'，但不能匹配'czaissg3'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">匹配结尾的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;=) ((?&lt;=1|2)czaissg) 可以匹配'1czaissg' / '2czaissg'，但不能匹配'3czaissg'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">匹配开头的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?!) (czaissg(?!1|2))，对于众多的'czaissgx'，不匹配以1,2结尾的，其他都匹配</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">不匹配结尾字段的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;!) ((?!1|2)czaissg) 对于众多的'xczaissg'，不匹配以1,2开头的，其他都匹配</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">U币匹配开头字段的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">其他说法：</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?:exp) 匹配exp,不捕获匹配的文本</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?=exp) 匹配exp前面的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;=exp) 匹配exp后面的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?!exp) 匹配后面跟的不是exp的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;!exp) 匹配前面不是exp的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">对于()的内容，获取的方法，我们通常使用group来获取</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">但实际上我们还可以使用'\\1'或者r'\1'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?:)  (czaissg|czaisorz) 就是 (czais(?:sg|orz))  </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">可以简化表达式</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?=) (czaissg(?=1|2)) 可以匹配'czaissg1' / 'czaissg2'，但不能匹配'czaissg3'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">匹配结尾的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;=) ((?&lt;=1|2)czaissg) 可以匹配'1czaissg' / '2czaissg'，但不能匹配'3czaissg'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">匹配开头的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?!) (czaissg(?!1|2))，对于众多的'czaissgx'，不匹配以1,2结尾的，其他都匹配</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">不匹配结尾字段的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;!) ((?!1|2)czaissg) 对于众多的'xczaissg'，不匹配以1,2开头的，其他都匹配</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">U币匹配开头字段的意思</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">其他说法：</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?:exp) 匹配exp,不捕获匹配的文本</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?=exp) 匹配exp前面的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;=exp) 匹配exp后面的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?!exp) 匹配后面跟的不是exp的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">(?&lt;!exp) 匹配前面不是exp的位置</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">对于()的内容，获取的方法，我们通常使用group来获取</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">但实际上我们还可以使用'\\1'或者r'\1'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">a = re.search('(?P&lt;test1&gt;.*?)_(?P&lt;test2&gt;.*?-)', s).groupdict()  # 能够得到匹配的字典咯</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="正则" term="正则"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[爬虫进阶-隐藏selenium特征]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/02/27/爬虫进阶-隐藏selenium特征</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/02/27/爬虫进阶-隐藏selenium特征"/>
        <updated>2023-02-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[这是一场反爬与反反爬技术人员之间的斗争~]]></summary>
        <content type="html"><![CDATA[<p>这是一场反爬与反反爬技术人员之间的斗争~</p><p>爬虫服务能够在网络上不知疲倦的获取信息，所以一般会带有某些易于常人的特征</p><p>反爬则基于这些特征进行拦截，而反反爬有两个思路：<br>
<!-- -->1、消除爬虫特征，使得自己像正常人一样。比如降低爬取频率就是一个不错的方案~<br>
<!-- -->2、破解反爬技术，即使被识别仍然可以获取   </p><p>在反反爬的技术领域，有这么一类偏方，就是自动化。<br>
<!-- -->它完全模拟常人操作，从而达到"一力破万法"的效果。</p><p>但随着反爬技术的进一步完善，自动化工具也逐渐的被识别并拦截，随之而来的就是一波反反爬技术的升级~</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="cdp">CDP<a href="#cdp" class="hash-link" aria-label="Direct link to CDP" title="Direct link to CDP">​</a></h2><p>CDP 全称为 <a href="https://chromedevtools.github.io/devtools-protocol/" target="_blank" rel="noopener noreferrer">Chrome Devtools-Protocol</a></p><p>通过执行 CDP 命令，可以在网页加载前运行一段代码，进而改变甚至屏蔽部分浏览器的指纹特征。</p><p>由于浏览器特征种类过多，所以可以直接使用现成的工具，直接屏蔽大部分特征。参考：
<a href="https://github.com/berstend/puppeteer-extra/blob/stealth-js/stealth.min.js" target="_blank" rel="noopener noreferrer">stealth.min.js</a></p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> webdriver</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">options </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> Options</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">service </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> Service</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">by </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> By</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">chrome_options </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> Options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 无头模式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># chrome_options.add_argument("--headless")</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 添加请求头</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">chrome_options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token string" style="color:rgb(206, 145, 120)">'user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">s </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> Service</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">r"chromedriver.exe路径"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">service</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> options</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">chrome_options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 利用stealth.min.js隐藏浏览器指纹特征</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># stealth.min.js下载地址：https://github.com/berstend/puppeteer-extra/tree/stealth-js</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">open</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'./stealth.min.js'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> f</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">execute_cdp_cmd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Page.addScriptToEvaluateOnNewDocument"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token string" style="color:rgb(206, 145, 120)">"source"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> f</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">read</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">url</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">'URL'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># driver.get(url='https://bot.sannysoft.com/')</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 保存图片</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">save_screenshot</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'result.png'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">200</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="undetected_chromedriver">undetected_chromedriver<a href="#undetected_chromedriver" class="hash-link" aria-label="Direct link to undetected_chromedriver" title="Direct link to undetected_chromedriver">​</a></h2><p>这是一个防止浏览器指纹特征被识别的依赖库，可以自动下载驱动配置再运行</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">安装依赖</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">pip install undetected</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain">chromedriver</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">undetected-chromedriver用例参考</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">options </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> Options</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">service </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> Service</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> time</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> undetected_chromedriver </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> uc</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">chrome_options </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> Options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># chrome_options.add_argument("--headless")</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">s </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> Service</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">r"chromedriver.exe"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> uc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">service</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> options</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">chrome_options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">url</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">'URL'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># driver.get(url='https://bot.sannysoft.com/')</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">save_screenshot</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'result.png'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">sleep</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">100</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="操作已开启的浏览器">操作已开启的浏览器<a href="#操作已开启的浏览器" class="hash-link" aria-label="Direct link to 操作已开启的浏览器" title="Direct link to 操作已开启的浏览器">​</a></h2><p>操作的原理是先单独开启一个浏览器，并开启远程调试能力，如：</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">import subprocess</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 1、打开浏览器</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 指定端口号为：1234</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 配置用户数据路径：--user-data-dir</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">cmd = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe --remote-debugging-port=1234 --user-data-dir="C:\\selenum\\user_data"'</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">subprocess.run(cmd)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>然后调整代码，远程加入调试：</p><div class="codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">import time</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">from selenium import webdriver</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">from selenium.webdriver.chrome.options import Options</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">from selenium.webdriver.chrome.service import Service</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 操作上面已经打开的浏览器，进行百度搜索</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">chrome_options = Options()</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 指定已经打开浏览器的地址及端口号</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:1234")</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 注意：chrome版本与chromedirver驱动要保持一致</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 下载地址：http://chromedriver.storage.googleapis.com/index.html</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">s = Service(r"chromedriver.exe")</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver = webdriver.Chrome(service=s, options=chrome_options)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"># 打开目标网站</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver.get(url="URL")</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">time.sleep(200)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="爬虫" term="爬虫"/>
        <category label="selenium" term="selenium"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[结构化思考与沟通]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/02/05/结构化思考与沟通</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/02/05/结构化思考与沟通"/>
        <updated>2023-02-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[语言的本质是对思维的表达，只有把某个事务的脉络理清了，才能想清楚，讲清楚。]]></summary>
        <content type="html"><![CDATA[<p>语言的本质是对思维的表达，只有把某个事务的脉络理清了，才能想清楚，讲清楚。</p><p>整理下结构化思考中捋清事务脉络的方式。</p><p>说话时，适当减慢语速。不要让思维跟不上表达。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="自我介绍">自我介绍<a href="#自我介绍" class="hash-link" aria-label="Direct link to 自我介绍" title="Direct link to 自我介绍">​</a></h2><ul><li>给自己绑定少量标签</li><li>我为什么来这里  </li><li>我能带来什么价值  </li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="祝辞">祝辞<a href="#祝辞" class="hash-link" aria-label="Direct link to 祝辞" title="Direct link to 祝辞">​</a></h2><ul><li>自我简介</li><li>感谢</li><li>回顾</li><li>愿景</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="谈话">谈话<a href="#谈话" class="hash-link" aria-label="Direct link to 谈话" title="Direct link to 谈话">​</a></h2><ul><li>表扬</li><li>批评</li><li>表扬</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="复盘">复盘<a href="#复盘" class="hash-link" aria-label="Direct link to 复盘" title="Direct link to 复盘">​</a></h2><ul><li>回顾目标</li><li>结果对比</li><li>亮点介绍</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="排错">排错<a href="#排错" class="hash-link" aria-label="Direct link to 排错" title="Direct link to 排错">​</a></h2><ul><li>找到问题</li><li>分析原因</li><li>解决方案</li><li>达成结果</li></ul><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="职场" term="职场"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[selenium学习总结]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2023/01/04/selenium学习总结</id>
        <link href="https://czasg.github.io/docusaurus/blog/2023/01/04/selenium学习总结"/>
        <updated>2023-01-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文作者: Czasg]]></summary>
        <content type="html"><![CDATA[<div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> webdriver  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 提供WebDriver的实现</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">keys </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> Keys  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 提供键盘按键的支持</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">options </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">ChromeOptions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">add_experimental_option</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'excludeSwitches'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">'enable-automation'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 设置为开发者模式，避免被识别</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'--headless'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 无界面操作。效率应该高一些</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">add_argument</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"--proxy-server=http://39.97.240.222:5739"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 使用代理</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">add_cookie</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 添加cookie</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"http://www.python.org"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">elem </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"q"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">elem</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">clear</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">elem</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">seWebDrivernd_keys</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"pycon"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">elem</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">send_keys</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">Keys</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">RETURN</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 在input中输入回车键</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 仅关闭一个标签页。quit将关闭整个浏览器。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">element </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_xpath</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"//select[@name='name']"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 找到下拉框</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">all_options </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_elements_by_tag_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"option"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 找到此元素中的option</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> option </span><span class="token keyword" style="color:rgb(86, 156, 214)">in</span><span class="token plain"> all_options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Value is: %s"</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token plain"> option</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_attribute</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"value"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取value属性值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    option</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">拖放工具</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> ActionChains  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 专门用于拖放的</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">element </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"source"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">target </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"target"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">action_chains </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> ActionChains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">action_chains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">drag_and_drop</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> target</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">perform</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">switch_to_window</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"windowName"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 支持不同窗口之间的移动</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">forward</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">back</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 访问历史记录</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_cookies</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取昂前页面的Cookie</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">xpath查找元素</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">by </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> By  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于查找元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">By</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">XPATH</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"//button[text()="</span><span class="token plain">something</span><span class="token string" style="color:rgb(206, 145, 120)">"]"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># find_element 方法用于查找单个元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_elements</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">By</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">XPATH</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'//button'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># find_elements 用于查找多个元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 这二者是等价的把</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'loginForm'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 第一个该 匹配 元素 会被匹配并返回</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> webdriver</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">common</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">by </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> By</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">support</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">ui </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> WebDriverWait  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于创建等待对象</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">support </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> expected_conditions </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> EC  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 提供了一组预定义的条件供WebDriverWait使用</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Chrome</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"http://somedomain/url_that_delays_loading"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 显式等待 - 等待满足一定条件之后再进一步执行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">try</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    element </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> WebDriverWait</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">10</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">until</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        EC</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">presence_of_element_located</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">By</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">ID</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"myDynamicElement"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">finally</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">quit</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 隐式等待 - 去等待一定的时间后去查找元素。 默认等待时间是0秒，一旦设置该值，隐式等待是设置该WebDriver的实例的生命周期</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">implicitly_wait</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">10</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)"># seconds</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> webdriver</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_cookie</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_cookies</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_screenshot_as_base64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 以base64编码的字符串获取当前窗口的屏幕快照</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_screenshot_as_file</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">filename</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将当前窗口的屏幕快照保存到PNG图像文件中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_screenshot_as_png</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 以二进制数据获取当前窗口的屏幕截图</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">save_screenshot</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">filename</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将当前窗口的屏幕快照保存到PNG图像文件中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_window_position</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">windowHandle </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">'current'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取当前窗口的x，y位置</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_window_rect</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取窗口的x，y坐标以及当前窗口的高度和宽度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_window_size</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">windowHandle </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">'current'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取当前窗口的宽度和高度。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">add_cookie</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将cookie添加到当前会话</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">delete_all_cookies</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 删除会话范围内的所有cookie</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">delete_cookie</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'name'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 删除具有给定名称的单个cookie</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">back</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">forward</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 关闭当前窗口</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">create_web_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">element_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 使用指定的element_id创建一个Web元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">execute</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># ?</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">execute_async_script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 在当前窗口/框架中异步执行JavaScript</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">execute_script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">script</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> args</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 在当前窗口/框架中同步执行JavaScript  # arguments[0] arguments[1] 这些是起传递参数的作用</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_elements</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_class_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_xpath</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">maximize_window</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 最大化</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">minimize_window</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># “最小化”操作</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">refresh</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 刷新当前页面</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">set_window_position</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">x，y，windowHandle </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">'current'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 设置当前窗口的x，y位置</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">set_window_rect</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">x </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token plain">，y </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token plain">，width </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token plain">，height </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 设置窗口的x，y坐标以及当前窗口的高度和宽度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">set_window_size</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">width，height，windowHandle </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">'current'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 设置当前窗口的宽度和高度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">name  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 返回此实例的基础浏览器的名称。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">title  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 返回当前页面的标题</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">remote</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webelement</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">WebElement  </span><span class="token comment" style="color:rgb(106, 153, 85)"># DOM元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_attribute</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取元素的给定属性或属性。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get_property</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 获取元素的给定属性</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">is_displayed</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 元素是否对用户可见</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">is_enabled</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 是否启用元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">is_selected</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 是否选择元素。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">screenshot</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将当前元素的屏幕快照保存到PNG图像文件中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">send_keys</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 模拟输入到元素中</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">submit</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 提交表格</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">clear</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 清除文本</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 单击元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">screenshot_as_base64</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># base64编码字符串的形式获取当前元素的屏幕快照</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">screenshot_as_png</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 以二进制数据获取当前元素的屏幕截图</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_class_name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 该元素的子元素中查找元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 该元素的子元素中查找元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_xpath</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 该元素的子元素中查找元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token builtin" style="color:rgb(86, 156, 214)">id</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">tag_name</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">text</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> ActionChains</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 移动到元素 menu 然后点击 hidden_submenu 按钮</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">menu </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_css_selector</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">".nav"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">hidden_submenu </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_css_selector</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">".nav #submenu1"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">ActionChains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">move_to_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">menu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">hidden_submenu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">perform</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 与上面你是等价的</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">menu </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_css_selector</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">".nav"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">hidden_submenu </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">find_element_by_css_selector</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">".nav #submenu1"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">actions </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> ActionChains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">driver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">actions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">move_to_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">menu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">actions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">hidden_submenu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">actions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">perform</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 这句话是执行的意思</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">on_element</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 点击某个元素。点完就松开了</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">click_and_hold</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">on_element</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 左键点击某个元素并且不松手</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">context_click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">on_element</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 右键点击某个元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">double_click</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">on_element</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 双击某个元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">drag_and_drop</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> target</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 按住源元素上的鼠标左键, 然后移动到目标元素并释放鼠标按钮</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">drag_and_drop_by_offset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">source</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> xoffset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> yoffset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 按住源元素上的鼠标左键，然后移动到目标偏移量并释放鼠标按钮。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">key_down</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> element</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 只发送一个按键，不释放它。比如使用 Control, Alt and Shift 的时候</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">key_up</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">value</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> element</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token boolean">None</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 释放修改键</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">move_by_offset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">xoffset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> yoffset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将鼠标移动到当前鼠标位置的偏移量。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">move_to_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">to_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将鼠标移动到元素的中间。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">move_to_element_with_offset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">to_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> xoffset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> yoffset</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将鼠标移动指定元素的偏移量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">pause</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 暂停所有输入达指定的持续时间（以秒为单位）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">perform</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 执行所有存储的操作</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">release</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">on_element </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token boolean">None</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 释放元素上按住的鼠标键</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">reset_actions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 清除已存储在远端的操作。</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">send_keys</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> keys_to_send </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将键发送到当前的焦点元素</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">send_keys_to_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">element，</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> keys_to_send </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 将键发送到元素</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">from</span><span class="token plain"> selenium</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">webdriver</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">support </span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> expected_conditions </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> EC  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 提供了一组预定义的条件供WebDriverWait使用</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">alert_is_present</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 希望有警报出现</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">element_located_selection_state_to_be</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">locator</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">is_selected</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望找到一个元素并检查指定的选择状态是否处于该状态. is_selected的元组是布尔值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">element_located_to_be_selected</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 选择对要定位的元素的期望。定位符是（按路径）的元组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">element_selection_state_to_be</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于检查是否选择了给定元素的期望。元素是WebElement对象is_selected是布尔值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">element_to_be_clickable</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于检查元素的期望是可见的并且已启用，因此您可以单击它</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">element_to_be_selected</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 选择检查选择的期望</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">frame_to_be_available_and_switch_to_it</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于检查给定帧是否可切换到的期望。如果该框架可用，它将给定的驱动程序切换到指定的框架</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">invisibility_of_element_located</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于检查元素在DOM上不可见或不存在的期望. 用于查找元素的定位器</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">new_window_is_opened</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望将打开一个新窗口并增加窗口句柄的数量</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">number_of_windows_to_be</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望窗口数为一定值</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">presence_of_all_elements_located</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查网页上是否存在至少一个元素。定位器用于查找元素，找到后返回</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">presence_of_element_located</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查页面的DOM上是否存在元素。这并不一定意味着该元素是可见的。定位器-用于查找元素，找到后返回</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">staleness_of</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 等待直到元素不再附加到DOM。element是要等待的元素。如果该元素仍附加在DOM上，则返回False，否则返回true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">text_to_be_present_in_element</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于检查指定元素中是否存在给定文本的期望。文字定位器</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">text_to_be_present_in_element_value</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 用于检查给定文本是否存在于元素的定位器中的期望</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">title_contains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 当前URL是否包含区分大小写的子字符串</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">url_changes</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">url</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查当前URL. url是期望的url，如果不相同，则不能完全匹配，否则返回True，否则返回false. 改变了就行</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">url_contains</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">url_to_be</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查当前URL。url是预期的url，必须完全匹配，如果标题匹配，则返回True，否则返回false。这个就是要完全变为这样</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">visibility_of</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查已知在页面DOM上存在的元素是否可见</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">visibility_of_any_elements_located</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查网页上是否存在至少一个元素。定位器用于查找元素，找到后返回WebElement列表</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">visibility_of_element_located</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 期望检查元素是否存在于页面的DOM上并且可见。可见性意味着不仅显示元素，而且其高度和宽度都大于0</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="selenium" term="selenium"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[tidb主键自增异常排查]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/12/08/tidb主键自增异常排查</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/12/08/tidb主键自增异常排查"/>
        <updated>2022-12-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在一次线上运维过程中，发现最新的数据，排在了前几天之后。]]></summary>
        <content type="html"><![CDATA[<p>在一次线上运维过程中，发现最新的数据，排在了前几天之后。</p><p>因为列表是按主键排序的，所以显示是没有问题的。</p><p>问题就在于，为什么最新的数据，主键会小于前几天的数据。</p><p>之后，我们通过阅读官方文档，发现这似乎并不是一个异常。</p><p>::: info
TiDB 的自增 ID (AUTO_INCREMENT) 只保证自增且唯一，并不保证连续分配。<br>
<!-- -->TiDB 目前采用批量分配的方式，所以如果在多台 TiDB 上同时插入数据，分配的自增 ID 会不连续。<br>
<!-- -->当多个线程并发往不同的 tidb-server 插入数据的时候，有可能会出现后插入的数据自增 ID 小的情况。
此外，TiDB允许给整型类型的字段指定 AUTO_INCREMENT，且一个表只允许一个属性为 AUTO_INCREMENT 的字段。
:::</p><p>文档参考：</p><ul><li><a href="https://docs.pingcap.com/zh/tidb/v4.0/auto-increment" target="_blank" rel="noopener noreferrer">https://docs.pingcap.com/zh/tidb/v4.0/auto-increment</a>  </li><li><a href="https://docs.pingcap.com/zh/tidb/v4.0/mysql-compatibility" target="_blank" rel="noopener noreferrer">https://docs.pingcap.com/zh/tidb/v4.0/mysql-compatibility</a></li></ul><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[python打包说明]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/12/02/python打包说明</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/12/02/python打包说明"/>
        <updated>2022-12-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[通用流程]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="通用流程">通用流程<a href="#通用流程" class="hash-link" aria-label="Direct link to 通用流程" title="Direct link to 通用流程">​</a></h2><ul><li>检测</li></ul><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">python setup.py check</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>构建</li></ul><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">python setup.py sdist</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><ul><li>上传</li></ul><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">pip </span><span class="token function" style="color:rgb(220, 220, 170)">install</span><span class="token plain"> twine</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">twine upload dist/__packages__-__version__.tar.gz</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="文件管理">文件管理<a href="#文件管理" class="hash-link" aria-label="Direct link to 文件管理" title="Direct link to 文件管理">​</a></h2><p>在正常构建过程中，打包程序可能会索引到一些测试、缓存文件，比如：</p><ul><li><strong>pycache</strong></li><li>*.pyc</li><li>*_test.py</li></ul><p>此时，我们可以通过引入<code>MANIFEST.in</code>文件，来对构建过程中的文件进行简单管理。相关指令有：</p><table><thead><tr><th>指令</th><th>说明</th></tr></thead><tbody><tr><td>include file-pattern ...</td><td>添加指定文件，非根目录文件需要指定路径</td></tr><tr><td>exclude file-pattern ...</td><td>排除指定文件，非根目录文件需要指定路径</td></tr><tr><td>recursive-include dir-pattern file-pattern ...</td><td>递归添加指定目录下的指定文件</td></tr><tr><td>recursive-exclude dir-pattern file-pattern ...</td><td>递归排除指定目录下的指定文件</td></tr><tr><td>global-include file-or-dir-pattern ...</td><td>全局添加指定目录或者文件</td></tr><tr><td>global-exclude file-or-dir-pattern ...</td><td>全局排除指定目录或者文件</td></tr><tr><td>graft dir-pattern</td><td>添加指定目录下所有文件</td></tr><tr><td>prune dir-pattern</td><td>排除指定目录下所有文件</td></tr></tbody></table><p>文件或者目录，可以提供精确名字，也可以提供正则匹配。如：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">MANIFEST.in</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">include LICENSE</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">include MANIFEST.in</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">include requirements.txt</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">exclude README.md</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">global-exclude __pycache__</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">global-exclude *.py[cod]</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">global-exclude *_test.py</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">global-exclude test_*.py</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">prune test</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">prune demo</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[前端元素自动铺满换行]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/11/30/前端元素自动铺满换行</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/11/30/前端元素自动铺满换行"/>
        <updated>2022-11-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[主要有三种方式：]]></summary>
        <content type="html"><![CDATA[<p>主要有三种方式：</p><ul><li>inline-block</li><li>flex + flex-wrap</li><li>grid</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="inline-block">inline-block<a href="#inline-block" class="hash-link" aria-label="Direct link to inline-block" title="Direct link to inline-block">​</a></h2><p>在子元素中增加<code>inline-block</code>属性</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token selector class" style="color:rgb(215, 186, 125)">.block</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">display</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> inline-block</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="flex">flex<a href="#flex" class="hash-link" aria-label="Direct link to flex" title="Direct link to flex">​</a></h2><p>在父元素中使用，此时不能设置高度。</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token selector class" style="color:rgb(215, 186, 125)">.block</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">display</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> flex</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">flex-wrap</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> wrap</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>因为<code>flex-wrap</code>属性指定<code>flex</code>元素单行显示还是多行显示，设置了高度将会平铺。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="grid">grid<a href="#grid" class="hash-link" aria-label="Direct link to grid" title="Direct link to grid">​</a></h2><p>在父元素中使用，此时不根据大小平铺，而是强制平铺</p><div class="language-css codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-css codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token selector class" style="color:rgb(215, 186, 125)">.block</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">display</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> grid</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token property">grid-template-columns</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token unit">fr</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token unit">fr</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token unit">fr</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">/*横向排布时，宽度均分为三等分*/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="前端" term="前端"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Go实现非跳转的http请求]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/11/17/Go实现非跳转http请求</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/11/17/Go实现非跳转http请求"/>
        <updated>2022-11-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Go http 发起请求时，一旦存在302等跳转请求的场景，会默认帮你跳转过去。]]></summary>
        <content type="html"><![CDATA[<p>Go http 发起请求时，一旦存在302等跳转请求的场景，会默认帮你跳转过去。</p><p>比如你只是想简单的 Head 请求，但当对方响应 302 时，实际最后获取到的就是 Location 的结果。</p><p>实际我们可以通过自定义 http client 实现非跳转请求：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">var</span><span class="token plain"> client </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Client</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    CheckRedirect</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">req </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Request</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> via </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Request</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">error</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">ErrUseLastResponse</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次关于文件IO的争执]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/11/11/记一次文件IO异常</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/11/11/记一次文件IO异常"/>
        <updated>2022-11-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[背景是有个需求需要下载文件并计算此文件的MD5。]]></summary>
        <content type="html"><![CDATA[<p>背景是有个需求需要下载文件并计算此文件的MD5。</p><p>然后同事开发的（Go）程序是先创建一个文件，然后写入下载数据。再没有关闭文件的前提下，重新又开启了一个新的文件流来计算MD5。</p><p>由此引发了一些争执...</p><p>为此我据理力争：</p><p>文件IO在<code>write</code>的过程，是不保证落盘的，即有一部分数据会暂存在内存中。<br>
<!-- -->在这种情况下，重新创建一个只读的文件流，可能读不到在内存中的数据...</p><p>但是同事用实际证明了，这段代码再实际计算过程，并没有任何问题...</p><p>我自己也无法复现...</p><p>之后用<code>Python</code>测试了下，发现确实读不到，但<code>Go</code>就是可以读取到...</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">open</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"tmpfile"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"w"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> encoding</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">"utf</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token number" style="color:rgb(181, 206, 168)">8</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    w</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">write</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hello world"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">with</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">open</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"tmpfile"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"r"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> encoding</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"utf-8"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> r</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">assert</span><span class="token plain"> r</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">read</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">==</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"hello world"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>最后总结：   </p><p>Go 文件句柄调用 Write 时是直接调用的系统接口，故可以读取到未落盘。</p><p>Python 则是自己实现了缓存机制。在 Go 中也有 bufio 库可以实现类似的机制</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="职场" term="职场"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Iaas & Paas & Saas]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/11/08/IaasPaasSaas</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/11/08/IaasPaasSaas"/>
        <updated>2022-11-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Iaas: Infrastructure as a Service 基础设施即服务]]></summary>
        <content type="html"><![CDATA[<p><strong>Iaas</strong>: Infrastructure as a Service 基础设施即服务</p><p><strong>Paas</strong>: Platform as a service 平台即服务</p><p><strong>Saas</strong>: Software as a service 软件即服务</p><p>以个人搭建服务为例：</p><p>当我们开发好一个服务，需要进行部署时，我们可以直接购买物理机进行部署，但这样我们就需要直接面对物理机的维护，还有网络维护等问题。<br>
<!-- -->为了避免这些繁琐的问题，我们更简单的方法是直接去云服务厂商租一台云服务器，然后将我们的程序部署在此服务器上。<br>
<!-- -->该云服务器为我们提供了计算、存储、网络等硬件基础能力，这种租硬件设备的服务就是Iaas。</p><p>所以如果你有过购买过服务器的精力经历，那其实你就已经购买过Iaas服务了~</p><p>如果我们开发的服务，涉及类似支付等三方能力时，我们几乎不可能自己写一套支付交易系统，更多的是对接微信、支付宝等三方支付接口。<br>
<!-- -->这类服务就是Paas，平台即服务。</p><p>以上服务都是自己开发的，市面上还有很多服务是通过提供软件服务，如果购物系统、物流系统、采购系统等，这些就是Saas服务了。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="未定义" term="未定义"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[SQL随录]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/10/17/SQL随录</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/10/17/SQL随录"/>
        <updated>2022-10-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[需求说明：在众多函数中，找到与目标表相关的函数。]]></summary>
        <content type="html"><![CDATA[<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    proname </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    pg_proc </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    prosrc </span><span class="token operator" style="color:rgb(212, 212, 212)">LIKE</span><span class="token string" style="color:rgb(206, 145, 120)">'%table_name%'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>需求说明：在众多函数中，找到与目标表相关的函数。</p><p>实现说明：</p><ul><li>pg_proc：pg存储函数的表</li><li>prosrc：是函数源码，通过模糊匹配查询所有源码中，与目标表有关的函数</li><li>proname：函数名</li></ul><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="sql" term="sql"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[SQL随录]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/10/14/SQL随录</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/10/14/SQL随录"/>
        <updated>2022-10-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[需求说明：table.key是一个JSONB字段，存储数据为：[{"rule": ["hash=hashstring;"]}]，现需要解析此数据，]]></summary>
        <content type="html"><![CDATA[<div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    SUBSTRING</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'rule'</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">-</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> :: </span><span class="token keyword" style="color:rgb(86, 156, 214)">TEXT</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'=*([0-9a-zA-Z]*);'</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">hash</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>需求说明：<code>table.key</code>是一个<code>JSONB</code>字段，存储数据为：<code>[{"rule": ["hash=hashstring;"]}]</code>，现需要解析此数据，
并截取出此数据结构中的哈希数据。</p><p>参考：<a href="http://postgres.cn/docs/12/functions-json.html" target="_blank" rel="noopener noreferrer">9.15. JSON 函数和操作符</a><br>
<!-- -->参考：<a href="http://postgres.cn/docs/12/functions-string.html" target="_blank" rel="noopener noreferrer">9.4. 字符串函数和操作符</a>     </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="sql" term="sql"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[如何理解引擎]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/10/07/如何理解引擎</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/10/07/如何理解引擎"/>
        <updated>2022-10-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在软件开发过程中，经常遇到各种高级词汇，比如病毒查杀引擎、云引擎等等。]]></summary>
        <content type="html"><![CDATA[<p>在软件开发过程中，经常遇到各种高级词汇，比如病毒查杀引擎、云引擎等等。   </p><p>我个人理解，引擎更多用于定义一种经过高度抽象的业务执行逻辑。   </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="未定义" term="未定义"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次SQLAlchemy连接异常问题]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/08/21/记一次SQLAlchemy连接异常问题</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/08/21/记一次SQLAlchemy连接异常问题"/>
        <updated>2022-08-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[排查与定位]]></summary>
        <content type="html"><![CDATA[<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">服务错误日志</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">mysql.connector.errors.OperationalError: 2055: Lost connection to MySQL server</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="排查与定位">排查与定位<a href="#排查与定位" class="hash-link" aria-label="Direct link to 排查与定位" title="Direct link to 排查与定位">​</a></h2><p>从连接信息可以快速看出，是数据库连接丢失了，我们首先做了简单的服务重启，并重试请求，期间同步观察数据库状态，确保数据库服务持续可用。</p><p>神奇的是，这是一个必现的错误。</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">服务错误日志</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">File "/usr/local/lib/python3.6/site-packages/mysql/connector/network.py", line 140, in send_plain </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    self.sock.sendall(packet) </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">BrokenPipeError: [Errno 32] Broken pipe </span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>继续排查日志，我们看到是在推送数据的过程，连接损坏了。由于是必现，所以网络不稳定基本可以排除。<br>
<!-- -->我们怀疑这可能是数据库侧的主动行为，即触发了某些机制，导致数据库强制关闭了连接。</p><p>我们拿到了待执行的SQL，直接在Navicat上进行复现，发现了新的错误信息：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">navicat错误日志</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">Got a packet bigger than 'max_allowed_packet' bytes</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这明显就是单次请求大小超过了数据库的限制，所以导致连接被强制关闭。但是被<code>SQLAlchemy</code>封装了一层，导致错误信息有部分偏差。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="修复">修复<a href="#修复" class="hash-link" aria-label="Direct link to 修复" title="Direct link to 修复">​</a></h2><p>通过查询得知当前数据库单次请求体积不能查超过4M</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">show</span><span class="token plain"> variables </span><span class="token operator" style="color:rgb(212, 212, 212)">like</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'max_allowed_packet'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><table><thead><tr><th>name</th><th>value</th></tr></thead><tbody><tr><td>max_allowed_packet</td><td>4194304</td></tr></tbody></table><p>调大即可，这里我调到了64M，满足当前业务述求。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">修复SQL</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">set</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">global</span><span class="token plain"> max_allowed_packet </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">67108864</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[如何从零开始设计一个后端框架]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/07/18/如何从零开始设计一个后端框架</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/07/18/如何从零开始设计一个后端框架"/>
        <updated>2022-07-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[web探秘]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="web探秘">web探秘<a href="#web探秘" class="hash-link" aria-label="Direct link to web探秘" title="Direct link to web探秘">​</a></h2><p>我们常说的web服务，通常是指的HTTP WEB服务。</p><p>在不了解web服务之前，我一直很好奇一件事情。<br>
<!-- -->我在浏览器里输入一个地址，他会返回一些内容给我。
我一直困惑于他实现的原理是什么？我是不是也可以自己搭建一个这样的服务？以前梦想就是想自己搭建一个web服务。</p><p>如果你学过python，那你一定用过requests库，我们用它来发起一次HTTP请求</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> requests  </span><span class="token comment" style="color:rgb(106, 153, 85)"># pip install requests</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">resp </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> requests</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">get</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"http://www.baidu.com"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">resp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这是一段非常简单的代码，但不知道你们有没有想过，它最底层是怎么实现的，为什么这么简单的几行代码，就可以发起一次HTTP请求。</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> socket</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">sock </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> socket</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">socket</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">sock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">connect</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"www.baidu.com"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">80</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 建立TCP连接</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">sock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">sendall</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"GET / HTTP/1.1\r\n\r\n"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain">  </span><span class="token comment" style="color:rgb(106, 153, 85)"># 自己构造请求，发送给服务端</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">sock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">recv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1024</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token number" style="color:rgb(181, 206, 168)">1024</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">decode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>HTTP请求报文</p><ul><li>请求行</li><li>请求头</li><li>请求体</li></ul><p>HTTP响应报文</p><ul><li>响应行</li><li>响应头</li><li>响应体</li></ul><p>抛开所有的业务，所有的实现，我们来看一下HTTP的请求，或者说web服务的本质，其实就是我给你一段文本，你给我一段文本。</p><p>框架使用多了，特别是一些集成度很高的框架，可能会使我们失去一些基础的能力、判断力。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="如何实现一个web服务">如何实现一个web服务<a href="#如何实现一个web服务" class="hash-link" aria-label="Direct link to 如何实现一个web服务" title="Direct link to 如何实现一个web服务">​</a></h2><p>我们先来看看flask框架如何实现一个web服务</p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> flask</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">app </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> flask</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Flask</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">__name__</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">route</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"/hello"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> methods</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token string" style="color:rgb(206, 145, 120)">"GET"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">lambda</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"hello world"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">app</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>通过route注册一个路由，然后绑定一个匿名函数，最后启动服务。</p><p>这是我们能看到的框架，那么框架帮我们做了什么事情呢？<br>
<!-- -->首先，第一件事肯定是帮我们解析HTTP请求报文，然后你觉得他们会做什么事情。<br>
<!-- -->他会去匹配路由，然后执行对应的处理函数。  </p><p>接着，我们来看下如何基于socket实现方式。<br>
<!-- -->基于socket，我们可以非常轻松的实现一个简陋的web服务，这个服务接收任何请求，然后响应<code>hello world</code></p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> socket</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">sock </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> socket</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">socket</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">sock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">bind</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"localhost"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">8080</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">sock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">listen</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">while</span><span class="token plain"> </span><span class="token boolean">True</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> addr </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> sock</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">accept</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">recv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1024</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token number" style="color:rgb(181, 206, 168)">1024</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">decode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">sendall</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"HTTP/1.1 200 ok\r\nContent-Length: 11\r\n\r\nhello world"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">encode</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">close</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="如何实现一个web框架">如何实现一个web框架<a href="#如何实现一个web框架" class="hash-link" aria-label="Direct link to 如何实现一个web框架" title="Direct link to 如何实现一个web框架">​</a></h2><p>框架的目的，是为了减少重复性工作。那么我们实现这个框架的目的，就是为了不在自己解析HTTP请求和构造HTTP响应。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[如何设计一个结构化日志]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/07/17/结构化日志</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/07/17/结构化日志"/>
        <updated>2022-07-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[结构化日志，即日志遵循一定的结构。程序输出内容不再是自由格式，而是类似JSON格式的文本。]]></summary>
        <content type="html"><![CDATA[<p>结构化日志，即日志遵循一定的结构。程序输出内容不再是自由格式，而是类似JSON格式的文本。</p><p>结构化日志的最大好处就是简化日志解析，便于日志分类、聚合。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="定义标准">定义标准<a href="#定义标准" class="hash-link" aria-label="Direct link to 定义标准" title="Direct link to 定义标准">​</a></h2><p>在开始编程前，需要先设计好项目的整体架构。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="日志基础信息">日志基础信息<a href="#日志基础信息" class="hash-link" aria-label="Direct link to 日志基础信息" title="Direct link to 日志基础信息">​</a></h3><p>首先，日志格式我们选择JSON格式。<br>
<!-- -->此外，还需要附带基础日志信息，这里我们选择时间和日志级别。  </p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> json</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> datetime</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">log</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">msg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">print</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">json</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">dumps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token builtin" style="color:rgb(86, 156, 214)">dict</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        time</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string-interpolation string" style="color:rgb(206, 145, 120)">f"</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token string-interpolation interpolation">datetime</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string-interpolation interpolation">datetime</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token string-interpolation interpolation">now</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token string-interpolation interpolation punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token string-interpolation string" style="color:rgb(206, 145, 120)">"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        level</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"info"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        msg</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">msg</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">log</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hello world"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这样，一个简单的结构化日志雏形就已经出现了。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="项目结构">项目结构<a href="#项目结构" class="hash-link" aria-label="Direct link to 项目结构" title="Direct link to 项目结构">​</a></h3><ul><li>Logger: 日志实体<ul><li>Level: 日志级别</li><li>Format: 日志格式</li><li>Hook: 日志钩子</li></ul></li><li>Entry: 数据实体<ul><li>Data: 数据</li></ul></li></ul><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[云服务初识]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/07/12/云服务初识</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/07/12/云服务初识"/>
        <updated>2022-07-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Serverless：从使用角度看不见服务器，无需创建、管理对应的服务。]]></summary>
        <content type="html"><![CDATA[<p>Serverless：从使用角度看不见服务器，无需创建、管理对应的服务。</p><p>ServiceMesh：服务网格
是致力于解决服务间通讯的基础设施层。负责现代云原生应用程序的复杂服务拓扑来可靠的传递请求。
本质是一组轻量级的网络代理。和服务应用部署在一起但是对程序透明。
特点：
1、应用程序间通讯的中间层
2、轻量级的网络代理
3、应用程序无感知
4、解耦应用程序的监控、追踪与服务发现</p><p>微服务框架-服务治理技术演进：<br>
<!-- -->第一阶段：服务治理能力抽象到统一的SDK实现<br>
<!-- -->优点：</p><ul><li>代码重复少</li><li>治理逻辑代码与业务代码隔离
缺点：</li><li>SDK语言绑定</li><li>代码侵入  </li><li>基于SDK有学习成本 </li></ul><p>第二阶段：服务治理能力归一到服务网格<br>
<!-- -->优点：</p><ul><li>独立进程，用户业务非侵入</li><li>语言无关</li><li>既有服务无需改造直接使用
缺点：</li><li>服务治理代理的性能和资源开销</li></ul><p>微服务：
1、实现上，把一个大系统，按照业务功能分解为多个职责相对单一的小系统。并利用简单的方法使多个系统之间相互协作，组成一个大系统。<br>
<!-- -->2、本质上，把相同领域或者因相同原因而变化的功能聚合到一起，把不同业务领域或因不同原因而变化的功能拆离开，并使用轻量化机制（HTTP RESTful API）实现通信。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="未定义" term="未定义"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[casbin学习]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/07/10/casbin学习</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/07/10/casbin学习"/>
        <updated>2022-07-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[摘要在此处]]></summary>
        <content type="html"><![CDATA[<p>摘要在此处</p><p>正文在此处</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="未定义" term="未定义"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[权限设计整理]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/07/09/权限设计整理</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/07/09/权限设计整理"/>
        <updated>2022-07-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[<!--]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="acl">ACL<a href="#acl" class="hash-link" aria-label="Direct link to ACL" title="Direct link to ACL">​</a></h2><p>ACL 是 Access Control List 的缩写，表示<strong>访问控制列表</strong>。</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">ACL配置表</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">资源列表</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">核心资产页面</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">用户</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 员工A</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 无权限</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">用户</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 员工B</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 查询权限</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">用户</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 员工C</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 增话、删除、修改、查询权限</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>ACL 的设计思想主要是围绕<strong>资源</strong>来设计的权限管理</p><p>从维护角度来看，每新增一名用户时，需要赋予初始化权限，会比较繁琐。但针对员工的权限修改，会显得比较容易。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="rbac">RBAC<a href="#rbac" class="hash-link" aria-label="Direct link to RBAC" title="Direct link to RBAC">​</a></h2><p>RBAC 是 Role Base Access Control 的缩写，表示<strong>基于角色的访问控制</strong>，</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">RBAC</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">用户表</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">用户</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> A</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">角色</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">研发</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">用户</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> B</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">角色</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">测试</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">---</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">角色表</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">角色</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 研发</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">修复BGU</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">角色</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 测试</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">创建BUG</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">---</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">权限表</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 创建BUG</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">资源表</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">资源</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> BUG单</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">创建、修改</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 修复BGU</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">资源表</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> 资源</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> BUG单</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">权限</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">修改、完成</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>RBAC 的思想，来源于现实世界中的企业结构，不同的角色设计有不同的权限，而不用的主体将拥有一个至多个角色。</p><p>从维护角度来看，在相对静态的情况下，是比较容易维护的。相对静态的意思就是说，每个角色拥有的权限是相对固定的。<br>
<!-- -->比如一名刚入职的员工，他的角色可能就是未转正员工，此时该名员工所拥有的权限将是非常小的一部分。
但是由于某些特殊情况，这名员工又需要申请更高权限时，就会比较难处理。因为不能直接修改角色的权限，这样会破坏这名角色的原生属性。<br>
<!-- -->在这种场景下，一般只能创建新的角色并赋予此名员工，这样就会降低系统的可维护性。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="未定义" term="未定义"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[redis 分布式锁]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/06/21/redis分布式锁</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/06/21/redis分布式锁"/>
        <updated>2022-06-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[<!--]]></summary>
        <content type="html"><![CDATA[<p>并发场景下的<strong>锁机制</strong>，其实就是用来保护不同线程对<strong>共享资源</strong>的访问，这样可以确保程序按预设的逻辑执行。
<strong>分布式锁</strong>也是一样的原理，它是用于分布式系统并发场景下访问共享资源的一种锁机制。   </p><p>一把合格的分布式锁，应该至少具备以下特征：</p><ul><li>互斥性：任意时刻，只有一个客户端持有。</li><li>超时机制：持有锁并超时时，可以自动释放，避免死锁。</li><li>安全性：在未超时场景下，锁只能被持有者释放。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="单节点分分布式锁">单节点分分布式锁<a href="#单节点分分布式锁" class="hash-link" aria-label="Direct link to 单节点分分布式锁" title="Direct link to 单节点分分布式锁">​</a></h2><p>SET 是 redis 关键字指令，属于原子操作，其作用是给指定 key 赋值 value。并且支持 NX 和 PX 参数：</p><ul><li>NX：<code>if not exists</code> 缩写，当 key 不存在时才允许赋值成功。</li><li>PX：表示过期时间。</li></ul><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">核心语句</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">SET key uniqueValue NX PX </span><span class="token number" style="color:rgb(181, 206, 168)">1000</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>具体的场景如下：<br>
<!-- -->1、用户一：创建随机值，使用 set 赋值，赋值成功，持有分布式锁。<br>
<!-- -->2、用户二：创建随机值，使用 set 赋值，赋值失败。<br>
<!-- -->3、用户一：执行任务超过1秒，自动释放锁。<br>
<!-- -->4、用户二：创建随机值，使用 set 赋值，赋值成功，持有分布式锁。<br>
<!-- -->5、用户一：任务结束，获取锁，对比当前锁是否属于自己，不属于则忽略。    </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="多节点分布式锁">多节点分布式锁<a href="#多节点分布式锁" class="hash-link" aria-label="Direct link to 多节点分布式锁" title="Direct link to 多节点分布式锁">​</a></h2><p>单节点 redis 可以基于 <code>SET key uniqueValue NX PX 1000</code> 实现分布式锁，但存在宕机的风险。<br>
<!-- -->所以 redis 作者提出了 redlock 算法，用于支持多节点下的分布式锁。</p><p>其算法步骤（以5个节点为例）：<br>
<!-- -->1、获取当前时间戳 和 UUID值。<br>
<!-- -->2、基于过期时间选择毫秒级的网络连接和响应时间。<br>
<!-- -->3、客户端逐一去申请锁，申请方式和单节点一样，当从 <code>N/2 + 1</code> 个节点都获取到锁，且使用时间小于当前锁失效时间，才算获取成功。<br>
<!-- -->4、真正的执行时间，时过期时间-获取锁的时间-时钟偏移时间。<br>
<!-- -->5、释放锁时需要每一个节点都尝试释放锁。   </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="redis" term="redis"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[PEP8 规范]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/06/20/pep8规范</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/06/20/pep8规范"/>
        <updated>2022-06-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[PEP 是 Python Enhancement Proposal 的缩写，表示Python 增强提案。]]></summary>
        <content type="html"><![CDATA[<p>PEP 是 <code>Python Enhancement Proposal</code> 的缩写，表示<strong>Python 增强提案</strong>。</p><p>PEP8 则表示其中第8条提案，这是针对编码规范的提案。其中包括：<strong>命名规范、编排规范、注释规范、代码规范</strong>等。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[基于docker搭建gitlan-runner]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/06/17/基于docker搭建gitlan-runner</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/06/17/基于docker搭建gitlan-runner"/>
        <updated>2022-06-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[gitlab-runner实际运行时，会远程获取我们的代码仓，然后执行配置的.gitlab-ci.yaml文件，这个文件和jenkinsfile一个性质，里面定义了 CICD 的检测流程。]]></summary>
        <content type="html"><![CDATA[<p><code>gitlab-runner</code>实际运行时，会远程获取我们的代码仓，然后执行配置的<code>.gitlab-ci.yaml</code>文件，这个文件和<code>jenkinsfile</code>一个性质，里面定义了 CICD 的检测流程。</p><p>换句话说，<code>gitlab-runner</code>和我们的代码仓是完全解耦的。是可以部署在其他服务器上，并且可以部署多个的。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1创建-volume">1、创建 volume<a href="#1创建-volume" class="hash-link" aria-label="Direct link to 1、创建 volume" title="Direct link to 1、创建 volume">​</a></h2><p>首先需要为 <code>gitlab-runner</code> 创建一个公共配置存在路径，目的是为了共享配置。</p><p>可以是具体的文件路径，也可以使用 <code>docker volume create</code> 创建一个公共挂载，后续其他的 runner 都挂载此目录，即可实现共享配置。   </p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">docker</span><span class="token plain"> volume create gitlab-runner-config</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2注册-runner">2、注册 runner<a href="#2注册-runner" class="hash-link" aria-label="Direct link to 2、注册 runner" title="Direct link to 2、注册 runner">​</a></h2><p>首先需要获取 gitlab 基础信息。<br>
<img loading="lazy" src="/docusaurus/assets/images/register-runner-b4f53c0f79480a169c48045f8e9d04fe.png" width="1200" height="643" class="img_ev3q"></p><p>然后注册 runner   </p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">docker</span><span class="token plain"> run --rm -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner register </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --non-interactive </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --url </span><span class="token string" style="color:rgb(206, 145, 120)">"Gitlab 的 URL 复制过来"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --registration-token </span><span class="token string" style="color:rgb(206, 145, 120)">"Gitlab 的 Token 复制过来"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --executor </span><span class="token string" style="color:rgb(206, 145, 120)">"docker"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --docker-image </span><span class="token string" style="color:rgb(206, 145, 120)">"要运行的镜像，eg: python:3.6.8"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --description </span><span class="token string" style="color:rgb(206, 145, 120)">"docker-runner-test"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --tag-list </span><span class="token string" style="color:rgb(206, 145, 120)">"docker,test"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --run-untagged</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"true"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --locked</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"false"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --access-level</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"not_protected"</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  --docker-pull-policy</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token string" style="color:rgb(206, 145, 120)">"if-not-present"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>注册完成后，在 gitlab 界面会出现你注册的 runner 信息。没有可以刷新看看，实在没有，应该是注册失败了。<br>
<img loading="lazy" src="/docusaurus/assets/images/register-runner-2-e878524955915d3ddf5e39c86ddb0e29.png" width="876" height="246" class="img_ev3q">   </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3启动-runner">3、启动 runner<a href="#3启动-runner" class="hash-link" aria-label="Direct link to 3、启动 runner" title="Direct link to 3、启动 runner">​</a></h2><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">help帮助指令1</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">docker</span><span class="token plain"> run -it --name gitlab-runner --rm </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v /var/run/docker.sock:/var/run/docker.sock </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v gitlab-runner-config:/etc/gitlab-runner </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    gitlab/gitlab-runner:latest </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">help</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">help帮助指令2</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">docker</span><span class="token plain"> run -it --name gitlab-runner --rm </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v /var/run/docker.sock:/var/run/docker.sock </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v gitlab-runner-config:/etc/gitlab-runner </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    gitlab/gitlab-runner:latest </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">help</span><span class="token plain"> unregister</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">list 列表查看runner</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">docker</span><span class="token plain"> run -it --name gitlab-runner --rm </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v /var/run/docker.sock:/var/run/docker.sock </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v gitlab-runner-config:/etc/gitlab-runner </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    gitlab/gitlab-runner:latest list</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">unregister 删除runner</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">docker</span><span class="token plain"> run -it --name gitlab-runner --rm </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v /var/run/docker.sock:/var/run/docker.sock </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    -v gitlab-runner-config:/etc/gitlab-runner </span><span class="token punctuation" style="color:rgb(212, 212, 212)">\</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    gitlab/gitlab-runner:latest unregister -t</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">GIRLAB_TOKEN</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="其他" term="其他"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[如何理解 OKR & KPI]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/06/09/如何理解OKRKPI</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/06/09/如何理解OKRKPI"/>
        <updated>2022-06-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[什么是 KPI]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="什么是-kpi">什么是 KPI<a href="#什么是-kpi" class="hash-link" aria-label="Direct link to 什么是 KPI" title="Direct link to 什么是 KPI">​</a></h2><p>KPI 指 <code>Key Performance Indicator</code>，即<strong>关键绩效指标</strong>。</p><p>对于公司来讲，他可以将公司的目标从上至下地分解，然后通过相关的关键绩效指标来衡量实际的执行效果。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="kpi-存在的问题">KPI 存在的问题<a href="#kpi-存在的问题" class="hash-link" aria-label="Direct link to KPI 存在的问题" title="Direct link to KPI 存在的问题">​</a></h2><p>经过大量实践证明，KPI 只适合<strong>标准化的、目标稳定的工作。</strong></p><p>比如某标准的工业流水线中，KPI 可以制定流水线中转化效率、转化比率等，这些都是可以定量的。<br>
<!-- -->但是对于<strong>创新类</strong>技术来说，它存在比较大的不确定性。这种类型就不适合用 KPI 来衡量了。</p><p>其次，<strong>KPI 会给团队带来不良风气</strong>，比如：<br>
<!-- -->1、追求低指标：如果制定指标过高，完不成，那就是搬起石头砸自己的脚，所以大家会更倾向于制定低指标。<br>
<!-- -->2、追求短视：一些需要长期投入的事情会被人嫌弃，大家更加关注短期获益的KPI。<br>
<!-- -->3、工作和考核本末倒置：在制定和把控严格的KPI管理上，投入了大量的时间和精力。等真正到了具体执行上，却敷衍了事。这类现象比比皆是。   </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="什么-okr">什么 OKR<a href="#什么-okr" class="hash-link" aria-label="Direct link to 什么 OKR" title="Direct link to 什么 OKR">​</a></h2><p>OKR 是 <code>Objectives and Key Results</code>，即<strong>目标与关键成果</strong>。</p><p>它的实施步骤是：<br>
<!-- -->1、首先制定<strong>业务目标 Objectives</strong>。比如：提升某系统稳定性。<br>
<!-- -->2、然后为每个目标设定关键结果 Key Results。比如：为了实现 提升系统稳定性 这个目标，计划引入数据库主备机制、异地多活方案等。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="okr-和-kpi-之间的区别与联系">OKR 和 KPI 之间的区别与联系<a href="#okr-和-kpi-之间的区别与联系" class="hash-link" aria-label="Direct link to OKR 和 KPI 之间的区别与联系" title="Direct link to OKR 和 KPI 之间的区别与联系">​</a></h2><p>我们会发现 OKR 和 KPI 很像，整体看下来甚至都没有什么区别。因为 <strong>OKR 中的一个 KR，似乎就是一个 KPI 指标</strong>。</p><p>其实区别很简单，KPI 中的关键词是 Indicators，而 OKR 中的关键词是 Objectives。<br>
<!-- -->换句话说，KPI 关注的是<strong>数据指标</strong>，OKR 关注的是<strong>业务目标</strong>。  </p><p>为了更好的理解，可以举个简单的例子，以某场比赛为例：<br>
<!-- -->如果从 KPI 的角度看，我们则更关注拿到几分、赢了几场等。<br>
<!-- -->如果从 OKR 的角度看，我们更关注夺冠、进四强、保级等。   </p><p>关键区别点就是指标和目标这两个词，虽然只是简单的两个词，却反映了两种截然不同的思维方式。</p><p>当我们使用 KPI 规划法时，更关注数据指标，第一思维就是：我要做什么事。在这种思维下我们更关注当下已有的工作。<br>
<!-- -->当我们使用 OKR 规划法时，更关注业务目标，第一思维就是：我要做成什么事。在这种思维下我们全局定位方向，再指定KR。</p><p>除此之外，OKR 和 KPI 也有很强的内在联系。<br>
<!-- -->OKR 的 KR 就有两种表现形式，一种就是 KPI，一种就是里程碑。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="基础技能" term="基础技能"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[PostgreSQL vs MySQL]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/06/07/pgvsmysql</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/06/07/pgvsmysql"/>
        <updated>2022-06-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[<!--]]></summary>
        <content type="html"><![CDATA[<p>MySQL 是业界主流的关系型数据库，目前被 Oracle 收购，并提供包括免费、付费等多种社区版本。<br>
<!-- -->PostgreSQL 则是一个开源的数据库。有句比较经典的话你可能听过，那就是："PostgreSQL 能与 Oracle 媲美，并且没有那么昂贵的价格和傲慢的客服。"    </p><p>两类数据库各有高低，本文主要学习总结下二者之间的特点，以及各自的优势。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="pg相较于mysql优势">PG相较于MySQL优势<a href="#pg相较于mysql优势" class="hash-link" aria-label="Direct link to PG相较于MySQL优势" title="Direct link to PG相较于MySQL优势">​</a></h2><p>首先 PG 完全开源，相较于 MySQL 来说，拥有更迅速的功能迭代。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="更丰富的数据类型">更丰富的数据类型<a href="#更丰富的数据类型" class="hash-link" aria-label="Direct link to 更丰富的数据类型" title="Direct link to 更丰富的数据类型">​</a></h3><p>除了常规的数据类型外，PG 的数据类型更加丰富，且完善了部分 MySQL 数据类型的一些槽点。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="支持jsonjsonb类型">支持json、jsonb类型<a href="#支持jsonjsonb类型" class="hash-link" aria-label="Direct link to 支持json、jsonb类型" title="Direct link to 支持json、jsonb类型">​</a></h4><p>随着json格式的流行，越来越多的数据存储和传输，采用json格式。     </p><p>但存储这类半结构化数据，对于关系型数据库来说并不友好。往往只能先将json数据序列化为成字符串，然后存储字符串。<br>
<!-- -->这也是 MongoDB 等非关系型数据库逐渐流行的原因之一。       </p><p>PG 支持 json、jsonb 两类数据类型：   </p><ul><li>json：存储文本数据，每次读取都会对其进行json解析。不支持索引。  </li><li>jsonb：存储二进制数据，相对于json类型来说，避免了重复解析，并且支持索引。  </li></ul><p>所以当数据库字段设计时，仅仅有部分字段数据类型是半结构化的，数据库选型时 PG 将是非常优秀的选择。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="text无长度限制支持全文索引">text无长度限制，支持全文索引<a href="#text无长度限制支持全文索引" class="hash-link" aria-label="Direct link to text无长度限制，支持全文索引" title="Direct link to text无长度限制，支持全文索引">​</a></h4><p>一般关系型数据库的字符串有长度限制，大小在8k左右，PG 则没有限制。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="字符编码支持更友好">字符编码支持更友好<a href="#字符编码支持更友好" class="hash-link" aria-label="Direct link to 字符编码支持更友好" title="Direct link to 字符编码支持更友好">​</a></h4><p>对于 emoji 的存储，MySQL 需要 utf8mb4 编码才能正确显示，在 PG 种遇不到。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="更丰富的索引类型">更丰富的索引类型<a href="#更丰富的索引类型" class="hash-link" aria-label="Direct link to 更丰富的索引类型" title="Direct link to 更丰富的索引类型">​</a></h3><p>MySQL 的索引类型取决于底层引擎选型，像 MyISAM、InnoDB 等支持B+树索引类型。<br>
<!-- -->PG 则支持B+数索引、哈希索引、Gist索引等。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="更丰富的集群支持">更丰富的集群支持<a href="#更丰富的集群支持" class="hash-link" aria-label="Direct link to 更丰富的集群支持" title="Direct link to 更丰富的集群支持">​</a></h3><p>MySQL 的集群高可用依赖于主从复制（replication），其底层基于 binlog 实现，并且是异步的。<br>
<!-- -->这种同步方案很难实现同步复制，更适合异地复制的场景。当主从节点处理能力不一致时，特别是主节点能力弱于从节点时，可能会存在较大的麻烦。</p><p>PG 的主备复制属于物理复制，相较于binlog的逻辑复制，数据的一致性更加可靠，复制性能更高，对主机的影响也更小。<br>
<!-- -->PG 集群有较多的插件：   </p><ul><li>slony 支持字段级的同步集群。  </li><li>standby 支持WAL文件级或流式的读写分离集群。     </li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="mysql相较于pg优势">MySQL相较于PG优势<a href="#mysql相较于pg优势" class="hash-link" aria-label="Direct link to MySQL相较于PG优势" title="Direct link to MySQL相较于PG优势">​</a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="业界主流">业界主流<a href="#业界主流" class="hash-link" aria-label="Direct link to 业界主流" title="Direct link to 业界主流">​</a></h3><p>主流就意味着你能找到更多的用户经验、解决方案、文档等。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="线程模式比进程模式更占据优势">线程模式比进程模式更占据优势<a href="#线程模式比进程模式更占据优势" class="hash-link" aria-label="Direct link to 线程模式比进程模式更占据优势" title="Direct link to 线程模式比进程模式更占据优势">​</a></h3><p>MySQL 使用了线程，而 PG 使用的是进程。</p><p>进程之间的调度开销要比线程大很多。也是因为这个原因，PG 默认最大连接数只有 100，对于数据库来说，这是非常小的连接数了。<br>
<!-- -->因此，PG 更需要类似 pgbounder 的连接池代理服务来确保数据库稳定。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="存储引擎插件化">存储引擎插件化<a href="#存储引擎插件化" class="hash-link" aria-label="Direct link to 存储引擎插件化" title="Direct link to 存储引擎插件化">​</a></h3><p>MySQL 的存储引擎插件化机制，是的它的应用场景更加广泛，比如 InnoDB 适合事务场景，MyISAM 则更适合静态数据的查询场景。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="索引组织表">索引组织表<a href="#索引组织表" class="hash-link" aria-label="Direct link to 索引组织表" title="Direct link to 索引组织表">​</a></h3><p>以 InnoDB 为例，B+树索引中，主键索引树中叶子节点存储的就是物理数据，普通节点物理索引存储的是主键的索引。</p><p>PG 的索引记录的均是物理位置，需要二次查询。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Go Http模块坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/06/05/golanghttp模块</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/06/05/golanghttp模块"/>
        <updated>2022-06-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[记录原生库 net/http 中可能遇到的坑点。]]></summary>
        <content type="html"><![CDATA[<p>记录原生库 <code>net/http</code> 中可能遇到的坑点。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="默认-httpclient-未配置超时">默认 HttpClient 未配置超时<a href="#默认-httpclient-未配置超时" class="hash-link" aria-label="Direct link to 默认 HttpClient 未配置超时" title="Direct link to 默认 HttpClient 未配置超时">​</a></h2><p>默认的 <code>http.DefaultClient</code> 不包含请求超时时间。在某些场景会造成程序异常阻塞。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">增加超时时间</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">client </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Client</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Timeout</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">60</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Second</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="go" term="go"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang高IO场景下的坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/05/31/golang高IO场景下的坑点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/05/31/golang高IO场景下的坑点"/>
        <updated>2022-05-31T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[计算机程序场景可分为计算密集型和IO密集型。计算密集型，即CPU占用较高的程序，一般类似AI算法等。IO密集型则包括磁盘IO和网络IO等。]]></summary>
        <content type="html"><![CDATA[<p>计算机程序场景可分为计算密集型和IO密集型。计算密集型，即CPU占用较高的程序，一般类似AI算法等。IO密集型则包括磁盘IO和网络IO等。<br>
<!-- -->Go 的协程，天然支持并发场景，对于计算密集型和IO密集型都比较友好。但是高磁盘IO场景会有点问题，使用不当还可能造成坑点。</p><p>网络IO属于<strong>事件驱动</strong>型，可以通过注册回调实现异步化。<br>
<!-- -->磁盘IO的 read/write 都是同步IO，是阻塞事件，需要同步等待。</p><p>所以，磁盘IO会造成Go的线程阻塞，而Go基于GMP模型，当M阻塞的时候，会重新创建新的M来执行G任务。<br>
<!-- -->所以当类似任务足够多时，会造成Go的M暴涨，超过1w以后，会被杀掉。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="go" term="go"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[go mod理解]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/04/07/gomod理解</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/04/07/gomod理解"/>
        <updated>2022-04-07T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[如果你搭建过早期 Go 项目，应该会比较熟悉 GOPATH。]]></summary>
        <content type="html"><![CDATA[<p>如果你搭建过早期 Go 项目，应该会比较熟悉 GOPATH。<br>
<!-- -->在以前，项目依赖三方包时，我们需要通过<code>go get</code>将三方依赖库下载到 GOPATH。这就涉及到一个版本维护的问题。  </p><p>为了解决这个问题，引入了<code>go mod</code>。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="go-mod">go mod<a href="#go-mod" class="hash-link" aria-label="Direct link to go mod" title="Direct link to go mod">​</a></h2><p><code>go mod</code> 是一个包依赖管理工具。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="git没法拉代码">git没法拉代码<a href="#git没法拉代码" class="hash-link" aria-label="Direct link to git没法拉代码" title="Direct link to git没法拉代码">​</a></h2><p>go mod vendor拉取代码报错：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">""</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">The project you were looking for could not be found</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这种属于git未配置好导致的，可以再根目录下创建：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">.git-credentials</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">https://user:pwd@gitee.com</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">https://user:pwd@github.com</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="go" term="go"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[tcmalloc理解]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/04/05/tcmalloc理解</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/04/05/tcmalloc理解"/>
        <updated>2022-04-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[tcmalloc（Thread-Caching Malloc）是一个内存分配器，用于管理堆内存。]]></summary>
        <content type="html"><![CDATA[<p>tcmalloc（Thread-Caching Malloc）是一个内存分配器，用于管理堆内存。<br>
<!-- -->主要影响的是malloc和free，用于降低频繁分配、释放内存场景所造成的性能损耗，可以有效的控制内存碎片。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="ptmalloc--tcmalloc">ptmalloc &amp; tcmalloc<a href="#ptmalloc--tcmalloc" class="hash-link" aria-label="Direct link to ptmalloc &amp; tcmalloc" title="Direct link to ptmalloc &amp; tcmalloc">​</a></h2><p>在tcmalloc之前，还有一个ptmalloc，tcmalloc号称要比它快。<br>
<!-- -->一次malloc和free操作，ptmalloc需要300ns，而tcmalloc只需要50ns。   </p><p>tcmalloc将内存请求分为了两类：大对象请求和小对象请求。（大于32K的属于大对象）<br>
<!-- -->它会为每个线程分配本地缓存，小对象请求可以直接从本地缓存获取，所以对于小对象的分配基本不存在锁竞争。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="计算机基础" term="计算机基础"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[redis指标小结]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/04/02/redis指标小结</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/04/02/redis指标小结"/>
        <updated>2022-04-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文学习总结下 redis 常用的观测指标，包括：性能指标、内存指标等。]]></summary>
        <content type="html"><![CDATA[<p>本文学习总结下 redis 常用的观测指标，包括：性能指标、内存指标等。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="性能指标">性能指标<a href="#性能指标" class="hash-link" aria-label="Direct link to 性能指标" title="Direct link to 性能指标">​</a></h2><p>redis 作为高性能缓存服务，其性能指标是一个很重要的观测点。</p><table><thead><tr><th>名称</th><th>说明</th></tr></thead><tbody><tr><td>latency</td><td>平均响应时间。该数据无法从 info 中获取，需要使用 redis-cli 加指定参数。eg：<code>redis-cli --latency</code></td></tr><tr><td>instantaneous_ops_per_sec</td><td>每秒处理的命令总数，可以在 info stats 中获取。</td></tr><tr><td>hit rate</td><td>缓存命中率。该值无法直接获取，需要通过计算：<code>keyspace_hits /（keyspace_hits + keyspace_misses）</code></td></tr></tbody></table><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="内存指标">内存指标<a href="#内存指标" class="hash-link" aria-label="Direct link to 内存指标" title="Direct link to 内存指标">​</a></h2><p>redis 作为常见内存数据库，其内存指标也是一个很重要的观测点。</p><table><thead><tr><th>名称</th><th>说明</th></tr></thead><tbody><tr><td>used_memory</td><td>内存使用量，可以在 info memory 中获取。</td></tr><tr><td>mem_fragmentation_ratio</td><td>操作系统分配的内存和 redis 请求的内存的比率。计算方式为：<code>mem_fragmentation_ratio = used_memory_rss / used_memory</code>。该指标可以用于观测 redis 服务器的内存碎片率。该值大于1，表示存在内存碎片，比如1.5，则表示50%是内存碎片。若该值小于1，则表示redis内存分配超出了物理内存，操作系统正在进行内存交换。</td></tr></tbody></table><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="redis" term="redis"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次 redis 查询 异常]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/04/01/记一次redis查询异常</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/04/01/记一次redis查询异常"/>
        <updated>2022-04-01T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[今天遇到一个诡异的事情，有一个基于 redis 提供高性能查询的服务，在非高峰期时居然大量报错。]]></summary>
        <content type="html"><![CDATA[<p>今天遇到一个诡异的事情，有一个基于 redis 提供高性能查询的服务，在非高峰期时居然大量报错。<br>
<!-- -->为什么说诡异呢，因为报错内容为：<code>redis: connection pool timeout</code>。而这个服务的查询场景及其简单，只有 <code>get</code> 和 <code>mget</code> 两种，报这个错就意味着 redis 查询性能不足？<br>
<!-- -->本文记录一下排查问题的过程。<br>
<img loading="lazy" src="/docusaurus/assets/images/1.1-4bc31816ef539655bfe098ea5f783376.png" width="1273" height="341" class="img_ev3q"></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="第一轮分析定位">第一轮分析定位<a href="#第一轮分析定位" class="hash-link" aria-label="Direct link to 第一轮分析定位" title="Direct link to 第一轮分析定位">​</a></h2><p><code>redis: connection pool timeout</code> 是连接池超时，这种问题发生的场景一般是由于某个操作过于耗时，导致 redis 阻塞，从而导致其他查询报错。<br>
<!-- -->所以第一步就是去线上查看慢日志 <code>SLOWLOG</code>，我们慢日志阈值为 1s，而连接超时配置为 4s。如果是因为慢操作导致超时，那应该是会被记录下来的。<br>
<!-- -->但实际没有，因为我们业务场景只有简单的 <code>get</code> 和 小量的 <code>mget</code>。所以要从其他角度进行分析。</p><p>这个服务当时的并发压力在几千QPS左右，redis 不应该存在抗不住的问题。翻了下报错时间点的上下文日志，确实发现了一些问题：<br>
<img loading="lazy" src="/docusaurus/assets/images/1.2-de83c2983f5b33486ca20d81f846071f.png" width="568" height="200" class="img_ev3q"><br>
<!-- -->箭头时间段，即在42分到44分之间，刚好就是 redis 查询报错的时间段。<br>
<!-- -->说明就是42分的同步行为，影响到了 redis 的查询性能。   </p><p>通过排查发现，这个服务有点特殊，是以 daemon 的形式部署在 k8s 上，且单 pod 独占节点。pod 内又包含 redis 和 postgres 等多个服务。<br>
<!-- -->进一步排查了解到，因为资源有限，所以没加资源配额，避免服务部署不上去。因此，存在某时刻的<strong>资源倾斜</strong>导致其余服务不可用。</p><p>这类问题其实在物理机上经常发生，没想到这次换了种形式发生在了 k8s 上面。<br>
<!-- -->解决方法也比较简单：<br>
<!-- -->1、增加机器资源，建议 4c 升级 8c。<br>
<!-- -->2、增加资源配额。 </p><p>由于预算不足，暂时只能采用第二种方案，即加上资源配额。<br>
<!-- -->但是资源实在有限，无法具体精确到每一个容器，故暂时仅对 redis 加上资源配额：  </p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">resources</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">requests</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">cpu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'1'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="第二轮分析定位">第二轮分析定位<a href="#第二轮分析定位" class="hash-link" aria-label="Direct link to 第二轮分析定位" title="Direct link to 第二轮分析定位">​</a></h2><p>通过几天的观察，发现并没有实际的效果。redis 仍然出现了查询超时的场景。而且还是在更新高峰期时间段发生的。<br>
<!-- -->但是我们已经给 redis 单独申请了 1c 的计算资源，不应该出现类似问题。</p><p>我们仔细排查了容器监控，发现各个容器都没有出现明显的高负载场景。情况有点诡异，从内部看不出什么情况，所以我们看了下当前节点的监控：<br>
<img loading="lazy" src="/docusaurus/assets/images/1.5-c0bd63ecb09746f45f46bf689728f8d2.png" width="939" height="288" class="img_ev3q"><br>
<!-- -->果然，cpu 利用率没有满，但是 Load 负载已经满了。甚至超了很多。<br>
<!-- -->基本可以石锤是 pg 在高更新场景影响 redis 调度。暂时只能增加 limits 资源限制了。</p><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>load average - 平均负载</div><div class="admonitionContent_S0QG"><p><code>load average</code> 是指单位时间内，系统处于 <strong>可运行状态</strong> 和 <strong>不可终端状态</strong> 的平均进程数，它和 cpu 使用率没有直接关系。</p><p>其中，可运行状态指正在使用 cpu 或者 正在等待 cpu 的进程，即处于 R 状态的进程。<br>
<!-- -->不可中断状态的进程，是指正处于内核态关键流程中的进程，并且这些进程是不可打断的。比如最常见的就是等待硬件设备的IO响应。    </p><p>所以，1m load average 的意思就是指 1min 内正在使用 cpu 的线程 + 正在等待 cpu 的线程 + 正在等待IO的线程。同理 5m 和 15 m 也是如此计算。</p><p>对于计算密集型任务，cpu 使用率升高时，平均负载基本也会升高。<br>
<!-- -->对于IO密集型任务，cpu 使用率可能不会很高，但由于等待IO的线程会增加，所以平均负载也会增加。         </p></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="第三轮分析定位">第三轮分析定位<a href="#第三轮分析定位" class="hash-link" aria-label="Direct link to 第三轮分析定位" title="Direct link to 第三轮分析定位">​</a></h2><p>突然想起官网的一句话：对于 redis 来说，cpu 往往不会是性能瓶颈，内存大小和网络带宽才可能是 redis 的瓶颈。</p><p>之前的分析应该是被带偏了。对于高更新场景，数据库会占用大量的磁盘IO，这一块可能会造成影响？</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="redis" term="redis"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang 选项模式]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/28/golang选项模式</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/28/golang选项模式"/>
        <updated>2022-03-28T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在 golang 开发过程中，可能会遇到这么一种问题：参数过多，当希望将参数配置成可选的模式。]]></summary>
        <content type="html"><![CDATA[<p>在 golang 开发过程中，可能会遇到这么一种问题：参数过多，当希望将参数配置成可选的模式。    </p><p>在其他语言中有不同的解决方法，比如 python 就支持默认参数，可以很好的处理这个问题。<br>
<!-- -->在 golang 中也有一种选项模式，可以比较友好的处理这类问题。   </p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="选项模式">选项模式<a href="#选项模式" class="hash-link" aria-label="Direct link to 选项模式" title="Direct link to 选项模式">​</a></h4><p>选项模式的主要流程是：初始化一个默认参数，然后提供可变参数，这些参数可以针对性的修改此默认参数，最终得到目标参数。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">type</span><span class="token plain"> MyFuncOption </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">options </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">MyFuncOptions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">WithOptionStr1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">str1 </span><span class="token builtin" style="color:rgb(86, 156, 214)">string</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> MyFuncOption </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">options </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">MyFuncOptions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">optionStr1 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> str1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">WithOptionInt1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">int1 </span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> MyFuncOption </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">options </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">MyFuncOptions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">optionInt1 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> int1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">WithOptionStr2AndInt2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">str2 </span><span class="token builtin" style="color:rgb(86, 156, 214)">string</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> int2 </span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> MyFuncOption </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">options </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">MyFuncOptions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">optionStr2 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> str2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">optionInt2 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> int2</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">NewIns</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">options </span><span class="token operator" style="color:rgb(212, 212, 212)">...</span><span class="token plain">MyFuncOption</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    defaultOptions </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> Options</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> </span><span class="token boolean">_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> f </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">range</span><span class="token plain"> options </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token function" style="color:rgb(220, 220, 170)">f</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">defaultOptions</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="常见方法">常见方法<a href="#常见方法" class="hash-link" aria-label="Direct link to 常见方法" title="Direct link to 常见方法">​</a></h4><p>这类参数的选择起始比较自由，一般选项模式适用于参数量较多的场景，当参数较少时，不妨直接匹配选项</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">type</span><span class="token plain"> Opt </span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    OptEnv Opt </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;&lt;</span><span class="token plain"> </span><span class="token boolean">iota</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    OptDefault</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    OptSilent </span><span class="token comment" style="color:rgb(106, 153, 85)">// ignore err and iterate over all fields.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">NewIns</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">opts </span><span class="token operator" style="color:rgb(212, 212, 212)">...</span><span class="token plain">Opt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">var</span><span class="token plain"> opt Opt </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> </span><span class="token boolean">_</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> o </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">range</span><span class="token plain"> opts </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        opt </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> opt </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> o</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang 的 CSP&GMP 模型]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/27/golang-GMP模型</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/27/golang-GMP模型"/>
        <updated>2022-03-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[CSP]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="csp">CSP<a href="#csp" class="hash-link" aria-label="Direct link to CSP" title="Direct link to CSP">​</a></h2><p>CSP（communicating sequential processes），是 golang 推崇的一种并发模式，其中有一句比较经典的话是：<br>
<strong>不要以共享内存的方式来通信，相反，应该以通信的方式来共享内存。</strong></p><p>在常见的多线程共享内存的模式中，当涉及到多线程操作共享数据时，一般需要通过加锁来保证数据和线程安全。<br>
<!-- -->go 则引入了 chan 信道，可以用于多 goroutine 之间的通信。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="gmp">GMP<a href="#gmp" class="hash-link" aria-label="Direct link to GMP" title="Direct link to GMP">​</a></h2><p>golang 执行多任务时，会创建多个线程，然后有调度器会将任务单元分配给线程执行，这种方式是一种典型的生产者消费者模式。</p><ul><li>G：goroutine，此处指协程。它相当于操作系统的进程控制块，包含：寄存器、线程上下文、函数执行指令等。     </li><li>M：machine，此处指实际的内核线程，用于执行 G。    </li><li>P：processor，此处指调度器，是 M 所需要的上下文环境，内部维护有一个本地队列。当 P 中有任务时，会创建或者唤醒 M 去处理任务。   </li><li>本地队列：P 维护一个本地队列来存放 G，新创建的 G 会优先存放在 P 的本地队列，当本地队列满后，会放入到全局队列。    </li><li>全局队列：M 执行时会先从本地队列获取 G，本地没有则去全局队列获取，如果全局队列也没有，则尝试去其他 P 的本地队列去偷取一些任务。   </li><li>M0：程序启动后第一个线程，负责启动起一个 G0 并执行初始化操作，包含初始化本地队列、全局队列等，启动 G0 之后 M0 就和普通 M 一样了。</li><li>G0：每创建一个 M，都会创建一个 G0，这里的 G0 仅用于负责调度其他的 G。比如当 M 从 G1 切换至 G2，首先应该切到 G0，然后由 G0 干掉 G1，再把 G2 加载进来。</li></ul><p><img loading="lazy" src="/docusaurus/assets/images/gmp-b4344ddfef7df6cef196627cd459e710.png" width="837" height="759" class="img_ev3q"><br>
<!-- -->1、go 创建 G。<br>
<!-- -->2、将 G 保存在本地队列，若本地队列满了，则保存到全局队列。<br>
<!-- -->3、P 与 M 绑定，M 执行本地队列任务 G，若本地队列任务执行完成，则从全局队列获取任务，若全局队列也没有，则从其他 P 的本地队列中偷取一半任务来执行。<br>
<!-- -->4、若 M 执行期间发生系统阻塞，此时 M 与 P 解绑，P 将申请创建新的 M 或者唤醒休眠的 M 重新绑定与执行。<br>
<!-- -->5、当 M 恢复时，会尝试获取一个空闲的 P，如果没有 P 空闲，M 则进入休眠，G 会放入到全局队列。  </p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="go-初始化流程">go 初始化流程<a href="#go-初始化流程" class="hash-link" aria-label="Direct link to go 初始化流程" title="Direct link to go 初始化流程">​</a></h4><p>1、创建 M0<br>
<!-- -->2、创建 G0<br>
<!-- -->3、绑定 M0 与 G0<br>
<!-- -->4、执行初始化操作<br>
<!-- -->5、M0 投入使用，尝试与空闲 P 绑定   </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="114-基于信号的抢占式调度">1.14 基于信号的抢占式调度<a href="#114-基于信号的抢占式调度" class="hash-link" aria-label="Direct link to 1.14 基于信号的抢占式调度" title="Direct link to 1.14 基于信号的抢占式调度">​</a></h2><p>当有大量 G 任务，为了让每个任务都有时间运行，<code>runtime.main</code> 会创建一个额外的 M 来运行 <code>sysmon</code> 函数，来实现监控与抢占。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    runtime</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">GOMAXPROCS</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">go</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"pass"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在 1.14 之前上面这段代码将不会输出任何结果，因为 main 会占用全部的计算资源。   </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次pg迁移k8s的坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/25/记一次pg迁移k8s的坑点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/25/记一次pg迁移k8s的坑点"/>
        <updated>2022-03-25T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[坑点：字符集不兼容]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="坑点字符集不兼容">坑点：字符集不兼容<a href="#坑点字符集不兼容" class="hash-link" aria-label="Direct link to 坑点：字符集不兼容" title="Direct link to 坑点：字符集不兼容">​</a></h2><p>有台物理机部署了 postgres 数据库，现在要把这个数据库迁移至 k8s。</p><p>第一次迁移，我们首先关闭了数据库，把文件直接挪到了 k8s 上，配上对应的 pg 镜像。<br>
<!-- -->测试时，服务正常运行了，但是没有办法提供数据服务，甚至连数据库也连接不上。</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">连接报错</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">zh_CN.UTF-8:initdb: error: locale “zh_CN.UTF-8“ requires unsupported encoding "en_CN.UTF-8"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>我们没有深究，就感觉可能是数据库文件不兼容，不能直接暴力迁移文件。</p><p>第二次迁移，我们使用 pg_dumps 和 pg_restore 工具进行迁移。数据量有点大，等待迁移完成后，我们再次进行了测试。</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">连接报错</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">zh_CN.UTF-8:initdb: error: locale “zh_CN.UTF-8“ requires unsupported encoding "en_CN.UTF-8"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>仍然报字符集不兼容的问题。这着实有点让人费解。</p><p>咨询了运维大佬后，给的建议是安装下依赖，即：</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">yum </span><span class="token function" style="color:rgb(220, 220, 170)">install</span><span class="token plain"> -y langpacks-zh_CN</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这种方式需要在编译镜像时安装，影响比较小。</p><p>后面又查询到一种方式，在编译镜像时，使用 <code>localedef</code> 指定编码并设置环境变量为 LANG 为 zh_CN.utf8：</p><div class="language-dockerfile codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-dockerfile codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">FROM postgres</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">RUN localedef -i zh_CN -c -f UTF-8 -A /usr/share/locale/locale.alias zh_CN.UTF-8</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">ENV LANG zh_CN.utf8</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>但是用了这种方法，日志似乎会变成中文😂😂😂</p><p><img loading="lazy" src="https://serverfault.com/questions/1074738/docker-postgresql-change-database-encoding-to-utf-8/1074756" alt="参考文档" class="img_ev3q"></p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[make和new之间的区别]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/24/make和new之间的区别</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/24/make和new之间的区别"/>
        <updated>2022-03-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[make 和 new 都是用来创建对象和初始化内存的。在实际使用场景中还是有一些不同的。]]></summary>
        <content type="html"><![CDATA[<p>make 和 new 都是用来创建对象和初始化内存的。在实际使用场景中还是有一些不同的。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="new">new<a href="#new" class="hash-link" aria-label="Direct link to new" title="Direct link to new">​</a></h4><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">new 源码注释</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)">// The new built-in function allocates memory. The first argument is a type,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// not a value, and the value returned is a pointer to a newly</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// allocated zero value of that type.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">new</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">Type</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">Type</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在源码注释中我们可以看出 new 的功能：<strong>输入一个类型，不能是值，返回一个指向该类型零值的指针。</strong></p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="make">make<a href="#make" class="hash-link" aria-label="Direct link to make" title="Direct link to make">​</a></h4><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">make 源码注释</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)">// The make built-in function allocates and initializes an object of type</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// slice, map, or chan (only). Like new, the first argument is a type, not a</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// value. Unlike new, make's return type is the same as the type of its</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// argument, not a pointer to it. The specification of the result depends on</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// the type:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  Slice: The size specifies the length. The capacity of the slice is</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  equal to its length. A second integer argument may be provided to</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  specify a different capacity; it must be no smaller than the</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  length. For example, make([]int, 0, 10) allocates an underlying array</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  of size 10 and returns a slice of length 0 and capacity 10 that is</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  backed by this underlying array.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  Map: An empty map is allocated with enough space to hold the</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  specified number of elements. The size may be omitted, in which case</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  a small starting size is allocated.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  Channel: The channel's buffer is initialized with the specified</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  buffer capacity. If zero, or the size is omitted, the channel is</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">//  unbuffered.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">make</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">t Type</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> size </span><span class="token operator" style="color:rgb(212, 212, 212)">...</span><span class="token plain">IntegerType</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> Type</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在源码注释中我们可以看出 make 的功能：<strong>输入一个类型（必须是slice、map、chan），返回一个按指定条件初始化后的类型对象。</strong></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="主要区别">主要区别<a href="#主要区别" class="hash-link" aria-label="Direct link to 主要区别" title="Direct link to 主要区别">​</a></h2><p>其实感觉没什么太大关系，都是内置的初始化函数，new 返回指针，make 只能用于特定类型。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang测试梳理]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/23/golang测试梳理</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/23/golang测试梳理"/>
        <updated>2022-03-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[单元测试 flag]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="单元测试-flag">单元测试 flag<a href="#单元测试-flag" class="hash-link" aria-label="Direct link to 单元测试 flag" title="Direct link to 单元测试 flag">​</a></h2><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-bench-regexp">-bench regexp<a href="#-bench-regexp" class="hash-link" aria-label="Direct link to -bench regexp" title="Direct link to -bench regexp">​</a></h4><p>执行基准测试，后面可以接正则表达式，如果需要执行全部的基准测试，可以使用 <code>-bench=.</code></p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">Benchmark</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">b </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">testing</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">B</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    b</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">ResetTimer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> i </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> i </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> b</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">N</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> i</span><span class="token operator" style="color:rgb(212, 212, 212)">++</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-benchtime-t">-benchtime t<a href="#-benchtime-t" class="hash-link" aria-label="Direct link to -benchtime t" title="Direct link to -benchtime t">​</a></h4><p>基准测试的持续时间，默认是 1s，可以使用 <code>-benchtime=1h30s</code></p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-count-n">-count n<a href="#-count-n" class="hash-link" aria-label="Direct link to -count n" title="Direct link to -count n">​</a></h4><p>基准测试的执行次数，默认仅执行一次。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-cover">-cover<a href="#-cover" class="hash-link" aria-label="Direct link to -cover" title="Direct link to -cover">​</a></h4><p>用于分析并输出单元测试覆盖率。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-covermode-setcountatomic">-covermode set,count,atomic<a href="#-covermode-setcountatomic" class="hash-link" aria-label="Direct link to -covermode set,count,atomic" title="Direct link to -covermode set,count,atomic">​</a></h4><p>单元测试的覆盖率分析模式。默认分析模式是 set，当使用 -race 时，则分析模式变为 atomic。</p><p>set：哪一行代码被执行了。<br>
<!-- -->count：哪行代码被执行了，且被执行了多少次。<br>
<!-- -->atomic：类似 count，但是会多线程并发检测，存在并发冲突时会报错。  </p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-cpu">-cpu<a href="#-cpu" class="hash-link" aria-label="Direct link to -cpu" title="Direct link to -cpu">​</a></h4><p>指定 GOMAXPROCS</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-failfast">-failfast<a href="#-failfast" class="hash-link" aria-label="Direct link to -failfast" title="Direct link to -failfast">​</a></h4><p>当测试失败时立即退出当前测试，而不是继续执行剩下的测试。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-timeout">-timeout<a href="#-timeout" class="hash-link" aria-label="Direct link to -timeout" title="Direct link to -timeout">​</a></h4><p>单个单元测试执行的最长时间，默认是 10 分钟</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-benchmem">-benchmem<a href="#-benchmem" class="hash-link" aria-label="Direct link to -benchmem" title="Direct link to -benchmem">​</a></h4><p>输出基准测试过程中内存的分配与统计。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-coverprofile-coverout">-coverprofile cover.out<a href="#-coverprofile-coverout" class="hash-link" aria-label="Direct link to -coverprofile cover.out" title="Direct link to -coverprofile cover.out">​</a></h4><p>测试过程覆盖率情况</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">可视化单元测试覆盖率</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">go tool cover -html</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">cover.out</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-cpuprofile-cpuout">-cpuprofile cpu.out<a href="#-cpuprofile-cpuout" class="hash-link" aria-label="Direct link to -cpuprofile cpu.out" title="Direct link to -cpuprofile cpu.out">​</a></h4><p>测试过程 cpu 调度情况</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="-memprofile">-memprofile<a href="#-memprofile" class="hash-link" aria-label="Direct link to -memprofile" title="Direct link to -memprofile">​</a></h4><p>测试过程内存使用情况</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次关于 httpClient 的坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/22/记一次关于httpClient的坑点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/22/记一次关于httpClient的坑点"/>
        <updated>2022-03-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[坑点：DefaultClient 无超时]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="坑点defaultclient-无超时">坑点：DefaultClient 无超时<a href="#坑点defaultclient-无超时" class="hash-link" aria-label="Direct link to 坑点：DefaultClient 无超时" title="Direct link to 坑点：DefaultClient 无超时">​</a></h2><p>go 默认的 httpClient 不包含超时时间，不像其他语言可能会有默认的超时时间。<br>
<!-- -->一般尽量少用默认的 http.DefaultClient，未每一个请求加上默认超时时间。</p><div class="language-golang codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">配置超时时间</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-golang codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">client := &amp;http.Client{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Timeout: time.Second * 10,</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="坑点defaultclient-长连接受限">坑点：DefaultClient 长连接受限<a href="#坑点defaultclient-长连接受限" class="hash-link" aria-label="Direct link to 坑点：DefaultClient 长连接受限" title="Direct link to 坑点：DefaultClient 长连接受限">​</a></h2><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">var</span><span class="token plain"> DefaultTransport RoundTripper </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">Transport</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Proxy</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ProxyFromEnvironment</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    DialContext</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">net</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Dialer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        Timeout</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain">   </span><span class="token number" style="color:rgb(181, 206, 168)">30</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Second</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        KeepAlive</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">30</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Second</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">DialContext</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    ForceAttemptHTTP2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain">     </span><span class="token boolean">true</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    MaxIdleConns</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain">          </span><span class="token number" style="color:rgb(181, 206, 168)">100</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    IdleConnTimeout</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain">       </span><span class="token number" style="color:rgb(181, 206, 168)">90</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Second</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    TLSHandshakeTimeout</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain">   </span><span class="token number" style="color:rgb(181, 206, 168)">10</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Second</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    ExpectContinueTimeout</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Second</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// DefaultMaxIdleConnsPerHost is the default value of Transport's</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)">// MaxIdleConnsPerHost.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> DefaultMaxIdleConnsPerHost </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="defaultmaxidleconnsperhost">DefaultMaxIdleConnsPerHost<a href="#defaultmaxidleconnsperhost" class="hash-link" aria-label="Direct link to DefaultMaxIdleConnsPerHost" title="Direct link to DefaultMaxIdleConnsPerHost">​</a></h4><p>DefaultMaxIdleConnsPerHost 表示客户端对每个主机服务保留的最大空闲连接数。  </p><p>在这里可以看到，http.DefaultClient 配置有 DefaultMaxIdleConnsPerHost，值为 2。<br>
<!-- -->表示客户端对每个主机服务保留的最大空闲连接数为 2，所以当我们有较多长连接场景时，http.DefaultClient 可能会干掉其他长连接，仅保留两个。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="keepalive">KeepAlive<a href="#keepalive" class="hash-link" aria-label="Direct link to KeepAlive" title="Direct link to KeepAlive">​</a></h4><p>KeepAlive 表示长连接存活时间。  </p><p>此处默认为 30s，在某些压力测试场景下可能会导致 socket 连接被耗尽。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">配置存活时间 24h 案例</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">client </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Client</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Transport</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">http</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Transport</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        DialContext</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">net</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Dialer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            KeepAlive</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> time</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Hour </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">24</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">DialContext</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[数据库单表十亿量级的优化之路]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/03/18/数据库单表十亿量级的优化之路</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/03/18/数据库单表十亿量级的优化之路"/>
        <updated>2022-03-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[在常规数据库中，单表数据量到达百万时，查询方面就可能出现性能问题。而当单表数据量达到千万量级时，不仅查询，连索引维护也可能出现问题。]]></summary>
        <content type="html"><![CDATA[<p>在常规数据库中，单表数据量到达百万时，查询方面就可能出现性能问题。而当单表数据量达到千万量级时，不仅查询，连索引维护也可能出现问题。<br>
<!-- -->此次我们的主角是"单表量级十亿"，本文章主要记录在优化期间的一些思路与实现。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="背景介绍">背景介绍<a href="#背景介绍" class="hash-link" aria-label="Direct link to 背景介绍" title="Direct link to 背景介绍">​</a></h2><ul><li><strong>数据库</strong>：postgres  </li><li><strong>数据库配置</strong>：4c8g + ssd</li><li><strong>表名</strong>：czasg（已脱敏）</li><li><strong>表量级</strong>：10亿  </li><li><strong>表字段</strong>：（已脱敏）<ul><li><strong>key</strong>：主键，类型 text</li><li><strong>value</strong>： 类型 text</li></ul></li><li><strong>业务需求</strong>：每天会有一批数据源，400w 左右，需求就是写入这批数据，并输出实际新增和更新的数据。</li></ul><p>当前线上处理方式比较常规，主要包括下面两个步骤：</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1创建临时表写入数据">1、创建临时表，写入数据<a href="#1创建临时表写入数据" class="hash-link" aria-label="Direct link to 1、创建临时表，写入数据" title="Direct link to 1、创建临时表，写入数据">​</a></h4><p>创建临时表，存储业务待处理数据，总量在 400w 上下。（数据插入过程略）</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TEMPORARY</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> tmp_czasg </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain">  </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">COMMIT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">DROP</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>创建临时表，用于存储最终更新数据。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TEMPORARY</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> tmp_czasg_update </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain">      </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    old_value  </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">COMMIT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">DROP</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2join-计算结果集">2、join 计算结果集<a href="#2join-计算结果集" class="hash-link" aria-label="Direct link to 2、join 计算结果集" title="Direct link to 2、join 计算结果集">​</a></h4><p>以 key 为连接条件 join 原表，再过滤出 value 不同或者原表 value 为空的数据.</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> tmp_czasg_update </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> newkv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> newkv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> tmp_czasg </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> newkv </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">LEFT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">JOIN</span><span class="token plain"> czasg </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> kv </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> newkv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> newkv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">OR</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">IS</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3将结果集更新至表-czasg">3、将结果集更新至表 <code>czasg</code><a href="#3将结果集更新至表-czasg" class="hash-link" aria-label="Direct link to 3将结果集更新至表-czasg" title="Direct link to 3将结果集更新至表-czasg">​</a></h4><p><code>tmp_czasg_update</code> 中 old_value 为空的表示新增数据，我们将它插入到原表中。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> czasg </span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> tmp_czasg_update </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> old_value </span><span class="token operator" style="color:rgb(212, 212, 212)">IS</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>tmp_czasg_update</code> 中 old_value 非空的表示更新数据，我们将它更新到原表中。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">UPDATE</span><span class="token plain"> czasg </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> kv </span><span class="token keyword" style="color:rgb(86, 156, 214)">SET</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> newkv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">value</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> tmp_czasg_update </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> old_value </span><span class="token operator" style="color:rgb(212, 212, 212)">IS</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> newkv </span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> newkv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token keyword" style="color:rgb(86, 156, 214)">key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>至此业务结束。根据当前线上情况，执行完一次需要 N（N &gt;= 2）小时。</p><p>优化需求：由于该业务会长时间阻塞，影响其他关联业务，<strong>希望减少此阶段的执行时间。</strong></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="优化之路痛点分析">优化之路：痛点分析<a href="#优化之路痛点分析" class="hash-link" aria-label="Direct link to 优化之路：痛点分析" title="Direct link to 优化之路：痛点分析">​</a></h2><p>看完上面的背景介绍后，我们应该已经初步了解业务流程了，整理如下图：<br>
<img loading="lazy" src="/docusaurus/assets/images/data-update-88b60cabf7dd6d40a060adc7a5de11ee.png" width="731" height="550" class="img_ev3q"></p><p>可以看出，主要涉及到的操作就是对数据表更新并生成版本更新包。</p><p>现在我们来拆解其中的流程，大致分析下耗时的原因：</p><p>1、创建临时表<br>
<!-- -->2、数据写入临时表<br>
<!-- -->3、<strong>关联计算最终待作业的数据</strong><br>
<!-- -->4、<strong>插入新数据</strong><br>
<!-- -->5、更新旧数据<br>
<!-- -->6、导出结果集   </p><p>在上述流程中，主要耗时点就是步骤 3 和 4。<br>
<!-- -->步骤 3 耗时是因为数据量过大，关联过程无法全程在内存中操作，需要借用磁盘来完成中间计算。<br>
<!-- -->步骤 4 耗时是因为存在索引，对这个量级的索引进行增删操作都会非常耗时。     </p><p>首先，针对量级过大的问题，解决方案比较统一，那就是进行水平拆分，尽可能减小表的大小。<br>
<!-- -->其次，针对索引导致的插入/删除耗时，解决方案也比较简单，就是插入/删除前，先 <code>DROP INDEX</code>，执行完操作后，再 <code>CREATE INDEX</code>。<br>
<!-- -->在这里我们之所以不这样做，是因为重建一张 10亿 量级表的索引，不见得比当前方案快多少。     </p><p>有了大致思路，我们再来想想具体的落地方案。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="优化之路表分区">优化之路：表分区<a href="#优化之路表分区" class="hash-link" aria-label="Direct link to 优化之路：表分区" title="Direct link to 优化之路：表分区">​</a></h2><p>针对第一个问题，我们计划选择水平拆分这张大表。<br>
<!-- -->拆分时要考虑到单表的大小，最好能控制在百万级。<br>
<!-- -->所以我们可以选择将这张 10亿 大表拆分成 256 张小表，这样平均到每张表的大小就是 400w 左右了。</p><p>一般拆分的方式就是创建多张物理表，然后将数据按照某种规则均匀的插入到这些表中，从而减小单表的大小。<br>
<!-- -->但我们业务场景并没有特别复杂，在这里我们选择了<strong>表分区</strong>。</p><p>自然而然，<code>key</code> 字段也就成了我们首选的分区条件。<br>
<!-- -->由于该字段是随机字串，没有规律，只能采用哈希的方式散射到各个分区。<br>
<!-- -->然后我在分区内创建 <code>key_btree_index_key</code> 索引，此时每个分区的索引大小就可以控制在较小的范围内了。  </p><p>到这里，初步优化方案已经形成。但考虑到随机字串生成的索引，无论在空间还是性能上都有所欠缺，
所以本着一步优化到位的想法，我们决定重新设计字段索引：<br>
<!-- -->1、新增一个字段 <code>key_crc32</code>，用于存储 <code>key</code> 值计算出的哈希数，此数位于 <code>1 ~ 2^32</code> 之间。<br>
<!-- -->2、将分区条件设定为 <code>key_crc32</code><br>
<!-- -->3、创建分区索引 <code>key_crc32_btree_index_key</code>     </p><p>至此，我们的表分区方案初步落地。索引这一块属于过度设计，因为引入了新字段，所以是否属于正向优化，有待考量。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>表继承</div><div class="admonitionContent_S0QG"><p>在 postgres 中，继承可以快速的<strong>关联、区分</strong>多张表，让数据维护更加高效。  </p><p>使用继承时，至少需要有一张源表，然后通过指定源表来创建继承表。<br>
<!-- -->对于继承表来说，此时的继承表将<strong>拥有源表的全部列</strong>，并且可以自定义额外的列属性。<br>
<!-- -->对于源表来说，此时的源表将可以检索<strong>自身以及继承表的全部数据</strong>。   </p><p>在这里我们举一个例子，假设你有一张表 <code>cities</code>，里面存放了国内外所有的城市。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> cities </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    name      </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain">   </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 城市名</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    altitude  </span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token plain">     </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 城市海拔高度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>可是每个国家只有一个首都城市，现在有业务需求要快速筛分首都城市。<br>
<!-- -->为了实现这个需求，我们可能需要给这张表加一个字段，或者重新创建一张首都城市的表，这些都是不错的实现方案。<br>
<!-- -->现在，让我们用继承来实现这个需求：</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> capitals </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    country  </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token plain">     </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 所属国</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">cities</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在这里我们创建继承表 <code>capitals</code>，继承自 <code>cities</code>。这时我们可以这样存储数据：<br>
<!-- -->1、将首都城市存放至 <code>capitals</code>，并指定所属国。<br>
<!-- -->2、将其余城市存放至 <code>cities</code>。   </p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">查询所有城市中，海拔高于500的城市</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> cities </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> altitude </span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">500</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">查询非首都城市中，海拔高于500的城市</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> ONLY cities </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> altitude </span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">500</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 通过 ONLY 限制仅查 cities 表</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">查询所有首都城市中，海拔高于500的城市</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> capitals </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> altitude </span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">500</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div></div></div><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>表分区</div><div class="admonitionContent_S0QG"><p>在 postgres 中，表分区是将一张大表，划分成一些小的物理上的片。这样划分的好处有很多：  </p><ul><li>某些场景下读写性能提升。<strong>减小单表数据量、索引大小</strong>。      </li><li>某些场景下，<strong>批量操作</strong>性能将得到极大提升。     </li><li>可以按实际需求，将价值低的数据块迁移至便宜且较慢的存储介质上。   </li></ul><p>创建表分区的方式有两种：<br>
<!-- -->第一种，初始化时通过 <code>PARTITION BY</code> 声明该表为分区表，且需要指定分区键，然后就可以创建分区了。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">声明分区表</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> measurement </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    city_id    </span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">not</span><span class="token plain"> </span><span class="token boolean">null</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    logdate    </span><span class="token keyword" style="color:rgb(86, 156, 214)">date</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">not</span><span class="token plain"> </span><span class="token boolean">null</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    peaktemp   </span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    unitsales  </span><span class="token keyword" style="color:rgb(86, 156, 214)">int</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">PARTITION</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">BY</span><span class="token plain"> RANGE </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">logdate</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 分区支持范围划分、列表划分、哈希划分</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">创建分区</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> measurement_y2006m02 </span><span class="token keyword" style="color:rgb(86, 156, 214)">PARTITION</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">OF</span><span class="token plain"> measurement</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">FOR</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'2006-02-01'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TO</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'2006-03-01'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> measurement_y2006m03 </span><span class="token keyword" style="color:rgb(86, 156, 214)">PARTITION</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">OF</span><span class="token plain"> measurement</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">FOR</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'2006-03-01'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TO</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'2006-04-01'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>创建分区之后，你对 <code>measurement</code> 的操作都会被重定向到某个分区，比如：<br>
<!-- -->1、插入一条数据到 <code>measurement</code> 中，当这条数据被<strong>映射到 <code>measurement_y2006m02</code> 时</strong>，
这条数据将被<strong>重定向</strong>到 <code>measurement_y2006m02</code> 分区。<br>
<!-- -->2、读取一条数据，当这条数据被映射到 <code>measurement_y2006m02</code> 时，查询也会重定向。</p><p>第二种，通过继承实现表分区。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">创建继承表</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> measurement_y2006m02 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">measurement</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>为了实现类似分区表的能力，我们引入触发器：</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">创建触发器与函数</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">OR</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">REPLACE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FUNCTION</span><span class="token plain"> measurement_insert_trigger</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">RETURNS</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TRIGGER</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> $$</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">BEGIN</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> measurement_y2008m01 </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">RETURN</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">END</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$$</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">LANGUAGE</span><span class="token plain"> plpgsql</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TRIGGER</span><span class="token plain"> insert_measurement_trigger</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    BEFORE </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> measurement</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">FOR EACH ROW</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXECUTE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FUNCTION</span><span class="token plain"> measurement_insert_trigger</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>我们可以看到通过继承与触发器的方式，我们可以间接实现分区表的能力，他相比于声明式分区表，优势就是限制会宽松一些，
比如我们可以为每一个分区创建不同的字段的不同索引，但代价就是更复杂维护逻辑。</p></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="优化之路继承式分区表填坑">优化之路：继承式分区表填坑<a href="#优化之路继承式分区表填坑" class="hash-link" aria-label="Direct link to 优化之路：继承式分区表填坑" title="Direct link to 优化之路：继承式分区表填坑">​</a></h2><p>按照预期方案实现后，我拷贝了一份正式环境数据执行测试，结果令人震惊，耗时 3小时 😱😱😱<br>
<!-- -->就离了个大谱，妥妥的反向优化。 😭😭😭  </p><p>理论和实际差距过大，不得不让我开始反思到底是哪里出现了异常。<br>
<!-- -->通过日志发现在关联计算、插入新数据、更新数据这些流程都非常耗时。<br>
<!-- -->但是我们已经设计了分区，减小了每张表的数量和索引大小。所以理论上操作不可能会更耗时。  </p><p>通过进一步打断点输出日志，我发现了继承式分区表的触发器，在执行操作时性能非常拉跨。</p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">初始化表分区</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_0 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">CHECK</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">origin_id </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">cloud_search_kvs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_0_0 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">CHECK</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">858993459</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">origin_0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_0_1 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">CHECK</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">858993459</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1717986918</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">origin_0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_0_2 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">CHECK</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1717986918</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2576980377</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">origin_0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_0_3 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">CHECK</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">2576980377</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3435973836</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">origin_0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_0_4 </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">CHECK</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">3435973836</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">4294967295</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> INHERITS </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">origin_0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">初始化触发器</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">OR</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">REPLACE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FUNCTION</span><span class="token plain"> origin_0_insert_trigger</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">RETURNS</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TRIGGER</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> $$</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">BEGIN</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">858993459</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">THEN</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> origin_0_0 </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> ELSIF </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">858993459</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1717986918</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">THEN</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> origin_0_1 </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> ELSIF </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">1717986918</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2576980377</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">THEN</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> origin_0_2 </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> ELSIF </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">2576980377</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3435973836</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">THEN</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> origin_0_3 </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> ELSIF </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">3435973836</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">4294967295</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">THEN</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> origin_0_4 </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">NEW</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">END</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">RETURN</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">END</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">$$ </span><span class="token keyword" style="color:rgb(86, 156, 214)">LANGUAGE</span><span class="token plain"> plpgsql</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>触发器的原理就是通过查询条件，将数据重定向到指定分区。<br>
<!-- -->上面的初始化语句都是简化后的，实际上有 256 个判断条件，而且触发器每次似乎只能执行单条语句，这也导致了整体性能急剧下降。<br>
<!-- -->我们方案设计上没有太大的问题，但是执行方式有问题，触发器的重定向不适合这种场景，所以我只能尝试自己维护。</p><p>重新优化思路，获取每个分区的数据，直接和目标分区作关联运算，绕开触发器。  </p><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TEMPORARY</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> temp_diff_</span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    k </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    v </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    k_crc32 </span><span class="token keyword" style="color:rgb(86, 156, 214)">bigint</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    old_v </span><span class="token keyword" style="color:rgb(86, 156, 214)">text</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">COMMIT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">DROP</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">WITH</span><span class="token plain"> temp_diff_w </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> temp_add </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;=</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> temp_diff_</span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d </span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">origin_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> temp_diff_w </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> tadd </span><span class="token keyword" style="color:rgb(86, 156, 214)">LEFT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">JOIN</span><span class="token plain"> origin </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> kv </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> tadd</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v </span><span class="token operator" style="color:rgb(212, 212, 212)">OR</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v </span><span class="token operator" style="color:rgb(212, 212, 212)">IS</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> temp_diff </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> temp_diff</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">UPDATE</span><span class="token plain"> origin </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> o </span><span class="token keyword" style="color:rgb(86, 156, 214)">SET</span><span class="token plain"> v </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">row</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> temp_diff_</span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> old_v </span><span class="token operator" style="color:rgb(212, 212, 212)">IS</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">row</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> o</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">row</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k_crc32 </span><span class="token operator" style="color:rgb(212, 212, 212)">AND</span><span class="token plain"> o</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">row</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">DROP</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INDEX</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_btree_index_key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> origin </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> k_crc32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> origin_id</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> k_crc32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> origin_id </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> temp_diff_</span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> old_v </span><span class="token operator" style="color:rgb(212, 212, 212)">IS</span><span class="token plain"> </span><span class="token boolean">NULL</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">CREATE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INDEX</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">NOT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> origin_btree_index_key </span><span class="token keyword" style="color:rgb(86, 156, 214)">ON</span><span class="token plain"> origin </span><span class="token keyword" style="color:rgb(86, 156, 214)">USING</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">btree</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">k_crc32</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">DROP</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> temp_diff_</span><span class="token operator" style="color:rgb(212, 212, 212)">%</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">d</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>以上是部分执行语句（已脱敏），可以看出，第一步就取出了分区数据，然后执行关联运算获取最终结果集，再将结果集数据写入源表即可。  </p><p>再次测试，执行一次大概在 半小时 左右，完美 🤠🤠🤠</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[数据库是否适合容器化部署]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/02/22/数据库是否适合容器化部署</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/02/22/数据库是否适合容器化部署"/>
        <updated>2022-02-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[随着 Kubernetes 的流行，越来越来的应用被打包成镜像，作为容器部署在 k8s 上。]]></summary>
        <content type="html"><![CDATA[<p>随着 Kubernetes 的流行，越来越来的应用被打包成镜像，作为容器部署在 k8s 上。</p><p>在 k8s 中，pod 是最小的部署单位，内部可以包含多个容器镜像，每一个 pod 都具有有限的生命周期。<br>
<!-- -->对于无状态服务来说，特别适合在 k8s 上运行，因为无状态服务，是具有弹性的，可以更好的应对 pod 扩缩容、重启等特性。<br>
<!-- -->相反，对于有状态服务（类似数据库等），则存在一定的瓶颈限制。</p><p>先来看下 k8s 如何部署有状态服务，然后讨论下其优缺点。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="daemonset--statefulset">DaemonSet &amp; StatefulSet<a href="#daemonset--statefulset" class="hash-link" aria-label="Direct link to DaemonSet &amp; StatefulSet" title="Direct link to DaemonSet &amp; StatefulSet">​</a></h2><p><strong>DaemonSet</strong> 是 k8s 的控制器资源对象之一，其特点是：   </p><blockquote><p>1、确保每个节点仅启动一个 pod 副本，当有新节点加入集群时，自动为其增加一个 pod。</p></blockquote><p>比较典型的是日志收集服务，比如：我们需要确保每个节点上起一个 <code>logstash</code>，以便回收节点上的服务日志。  </p><p>数据库服务可以在类似场景下使用，比如给某个节点打上标签，确保某个数据库在对应节点上以 DaemonSet 类型启动，这样就可以确保该节点仅有一个 pod 副本。
最后通过 <code>nodeport</code> 的方式对外提供服务。
此时我们的数据库就拥有了稳定的节点 ip 和本地存储。  </p><p>但是这种方式，和直接在物理机上部署的方式差别不大，主要是复用了 k8s 的管理能力。</p><br><p><strong>StatefulSet</strong> 是 k8s 专为有状态服务设计的资源类型，它拥有：  </p><blockquote><p>1、稳定的网络标识：当服务重启，pod 绑定的 ip 不会变化，但是手动删除或者重建副本时，会重新分配 ip。
创建 headless service 时可以通过 <code>${serviceName-number}.${service}.${namespace}</code> 访问指定 pod。<br>
<!-- -->2、稳定的持久存储：基于 pvc 实现，每个 pod 会绑定专有的 pvc 存储。<br>
<!-- -->3、有序的扩缩容：会安装顺序从 0 逐一启动或者重建，此时类似滚动更新的扩容策略不在适用。      </p></blockquote><p>当我们的数据库服务部署 k8s 上时，可以选择 StatefulSet 资源类型。<br>
<!-- -->它的基本能力，足够支持一个有状态服务的正常运转。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="性能瓶颈">性能瓶颈<a href="#性能瓶颈" class="hash-link" aria-label="Direct link to 性能瓶颈" title="Direct link to 性能瓶颈">​</a></h2><p>数据库主要是和存储打交道，其性能瓶颈通常在磁盘IO。<br>
<!-- -->那么快速的磁盘IO，将有助于提升数据库的性能和吞吐量。<br>
<!-- -->比如：分别部署在 HDD 和 SSD 上的两个数据库，在相同其他条件下，SSD 上的数据库肯定拥有更高的性能。 </p><p>当我们的数据库部署在 k8s 上时，可以通过挂载卷 volume（nfs、ceph）持久化数据，但是这样就不可避免的引入了网络IO，在本身的瓶颈上又补一刀。<br>
<!-- -->所以当我们使用 k8s 部署数据库时，可能需要重点考虑下性能问题。</p><p>除了 nfs、ceph 之外，还有 hostpath 这类本地存储，可以忽略网络影响。
但是这需要我们的副本绑定到固定的节点上，此时就走的类似 DaemonSet 的部署路线了。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次 golang 升级导致的 goland 不可用]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/02/17/golang升级导致goland不可用</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/02/17/golang升级导致goland不可用"/>
        <updated>2022-02-17T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[go1.14.1 升级至 go1.17.7，导致 goland 打开后显示无法找到 GOROOT。]]></summary>
        <content type="html"><![CDATA[<p>go1.14.1 升级至 go1.17.7，导致 goland 打开后显示无法找到 GOROOT。</p><p>错误显示：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">The selected directory is not a valid home for Go SDK</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>通过 go env 查看后发现相关配置无问题，环境变量也无问题。</p><p>最后找的解决方案：<br>
<strong>1、</strong>go version 查看自己当前版本<br>
<strong>2、</strong>编辑 {GOROOT}/src/runtime/internal/sys/zversion.go 文件，写入以下变量</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">const</span><span class="token plain"> TheVersion </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">`go1.17.4`</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><strong>3、</strong>重启 goland，然后点击 setroot 即可。  </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
        <category label="bug" term="bug"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Jmeter及性能测试]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/02/02/jmeter及性能测试</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/02/02/jmeter及性能测试"/>
        <updated>2022-02-02T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[记录 jmeter 工具的使用，以及在性能测试过程中学习到的一些知识点。]]></summary>
        <content type="html"><![CDATA[<p>记录 jmeter 工具的使用，以及在性能测试过程中学习到的一些知识点。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="性能指标">性能指标<a href="#性能指标" class="hash-link" aria-label="Direct link to 性能指标" title="Direct link to 性能指标">​</a></h2><ul><li>TPS（Transactions Per Second）：每秒事务数，吞吐率</li><li>QPS（Queries Per Second）：每秒查询数</li><li>RT（Response Time）：响应时间，服务延迟</li></ul><p>性能问题，归根结底还是资源问题。常见的瓶颈点：<br>
<!-- -->1、网络IO<br>
<!-- -->2、存储IO<br>
<!-- -->3、CPU、内存<br>
<!-- -->4、应用  </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="jmeter-结果解读">jmeter 结果解读<a href="#jmeter-结果解读" class="hash-link" aria-label="Direct link to jmeter 结果解读" title="Direct link to jmeter 结果解读">​</a></h2><p>并发线程、响应时间、TPS之间的关联：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">TPS = (1s/响应时间) * 并发线程</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_S0QG"><p>假设有4个线程，每个线程每秒发起4个请求并响应，此时并发是16而非4</p></div></div><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">1个线程</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary +   5922 in 00:00:30 =  197.4/s Avg:     4 Min:     0 Max:    26 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary =  35463 in 00:03:05 =  192.0/s Avg:     5 Min:     0 Max:   147 Err:     0 (0.00%)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary +   5922 in 00:00:30 =  197.5/s Avg:     4 Min:     0 Max:    24 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary =  41385 in 00:03:35 =  192.8/s Avg:     5 Min:     0 Max:   147 Err:     0 (0.00%)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary +   5808 in 00:00:30 =  193.6/s Avg:     5 Min:     0 Max:    25 Err:     0 (0.00%) Active: 1 Started: 1 Finished: 0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary =  47193 in 00:04:05 =  192.9/s Avg:     5 Min:     0 Max:   147 Err:     0 (0.00%)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>(1000ms/5ms)*1=200TPS</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">10个线程</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary +  11742 in 00:00:30 =  391.3/s Avg:    25 Min:     0 Max:   335 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary =  55761 in 00:02:24 =  386.6/s Avg:    25 Min:     0 Max:   346 Err:     0 (0.00%)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary +  11924 in 00:00:30 =  397.5/s Avg:    25 Min:     0 Max:    80 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary =  67685 in 00:02:54 =  388.5/s Avg:    25 Min:     0 Max:   346 Err:     0 (0.00%)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary +  11884 in 00:00:30 =  396.2/s Avg:    25 Min:     0 Max:   240 Err:     0 (0.00%) Active: 10 Started: 10 Finished: 0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">summary =  79569 in 00:03:24 =  389.6/s Avg:    25 Min:     0 Max:   346 Err:     0 (0.00%)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>(1000ms/25ms)*10=400TPS</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="分布式压力测试">分布式压力测试<a href="#分布式压力测试" class="hash-link" aria-label="Direct link to 分布式压力测试" title="Direct link to 分布式压力测试">​</a></h2><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">启动指令</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">/jemeter/bin/jmeter -n -t ./script.jmx -r -l ./script.jtl -e -o ./script</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">分布式 jmeter 启动指令</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">/jmeter/bin/jmeter -n -t tmpl.jmx -R </span><span class="token number" style="color:rgb(181, 206, 168)">1.1</span><span class="token plain">.1.1:8000,1.1.1.2:8000</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="性能测试" term="性能测试"/>
        <category label="jmeter" term="jmeter"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[常见 sql 批量操作]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/01/20/常用sql操作</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/01/20/常用sql操作"/>
        <updated>2022-01-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[整理下 sql 常见的批量操作写法。]]></summary>
        <content type="html"><![CDATA[<p>整理下 sql 常见的批量操作写法。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="插入">插入<a href="#插入" class="hash-link" aria-label="Direct link to 插入" title="Direct link to 插入">​</a></h2><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">批量插入</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> my_table </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">VALUES</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">'k'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'v'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 插入单条</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> my_table </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> same_table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 相同结构表之间的批量插入</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">INSERT</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">INTO</span><span class="token plain"> my_table </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> v</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> v </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> other_table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 不同结构表之间的批量插入</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="更新">更新<a href="#更新" class="hash-link" aria-label="Direct link to 更新" title="Direct link to 更新">​</a></h2><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">批量更新</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">UPDATE</span><span class="token plain"> my_table </span><span class="token keyword" style="color:rgb(86, 156, 214)">SET</span><span class="token plain"> v </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'new_v'</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> k </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'new_k'</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 更新一次</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">UPDATE</span><span class="token plain"> my_table </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> o </span><span class="token keyword" style="color:rgb(86, 156, 214)">SET</span><span class="token plain"> v </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> new_table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">v </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token keyword" style="color:rgb(86, 156, 214)">SELECT</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> other_table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">as</span><span class="token plain"> new_table </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> o</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> new_table</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> </span><span class="token comment" style="color:rgb(106, 153, 85)">-- 批量更新</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="删除">删除<a href="#删除" class="hash-link" aria-label="Direct link to 删除" title="Direct link to 删除">​</a></h2><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">批量删除</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">DELETE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">FROM</span><span class="token plain"> new_table </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> kv </span><span class="token keyword" style="color:rgb(86, 156, 214)">USING</span><span class="token plain"> other_table </span><span class="token keyword" style="color:rgb(86, 156, 214)">AS</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">row</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">WHERE</span><span class="token plain"> kv</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">row</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">k</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-sql codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">联级删除 CASCADE</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-sql codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">DROP</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">TABLE</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">IF</span><span class="token plain"> </span><span class="token keyword" style="color:rgb(86, 156, 214)">EXISTS</span><span class="token plain"> my_table </span><span class="token keyword" style="color:rgb(86, 156, 214)">CASCADE</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="数据库" term="数据库"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[nginx 配置说明]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2022/01/12/nginx配置说明</id>
        <link href="https://czasg.github.io/docusaurus/blog/2022/01/12/nginx配置说明"/>
        <updated>2022-01-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[记录一下 nginx 常见配置说明和部署模板（docker、k8s）。]]></summary>
        <content type="html"><![CDATA[<p>记录一下 nginx 常见配置说明和部署模板（docker、k8s）。</p><p>nginx 是一个高性能的 web 服务器，同时也能提供负载均衡和反向代理服务。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="nginx-常用指令">nginx 常用指令<a href="#nginx-常用指令" class="hash-link" aria-label="Direct link to nginx 常用指令" title="Direct link to nginx 常用指令">​</a></h2><ul><li>-c：用于指定一个配置文件</li><li>-t：用于测试配置是否可用</li><li>-s：用于发送信号，包括：stop, quit, reopen, reload。eg：<code>nginx -s reload</code></li></ul><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">指定并测试配置文件是否正确</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">nginx -t -c ./nginx.conf</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="nginx-核心模块">nginx 核心模块<a href="#nginx-核心模块" class="hash-link" aria-label="Direct link to nginx 核心模块" title="Direct link to nginx 核心模块">​</a></h2><p>nginx 的核心模块主要有三个：</p><ul><li>主模块：管理 nginx 基本功能的模块</li><li>事件模块：管理 nginx 处理连接请求的模块</li><li>HTTP 模块：管理 nginx 处理 http 请求的模块</li></ul><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="主模块">主模块<a href="#主模块" class="hash-link" aria-label="Direct link to 主模块" title="Direct link to 主模块">​</a></h3><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">user  nginx;  # 用户</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">pid  /var/run/nginx.pid;  # 进程ID</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">worker_processes  auto;  # 工作进程，可以指定具体数字</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">error_log  /var/log/nginx/error.log notice;  # 指定日志和错误级别，包含：debug、info、notice、warn、error、crit</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">worker_cpu_affinity  none;  # 用于绑定 worker 进程与 cpu</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="事件模块">事件模块<a href="#事件模块" class="hash-link" aria-label="Direct link to 事件模块" title="Direct link to 事件模块">​</a></h3><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">events {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    worker_connections  1024;  # 每个工作进程最大链接数。乘以 worker_processes 就是该 nginx 服务的最大连接数</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="http-模块">HTTP 模块<a href="#http-模块" class="hash-link" aria-label="Direct link to HTTP 模块" title="Direct link to HTTP 模块">​</a></h3><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="location-路由匹配规则及顺序">location 路由匹配规则及顺序<a href="#location-路由匹配规则及顺序" class="hash-link" aria-label="Direct link to location 路由匹配规则及顺序" title="Direct link to location 路由匹配规则及顺序">​</a></h4><ul><li><code>=</code>: 精确匹配</li><li><code>^~</code>: 优先前缀匹配</li><li><code>~</code>: 正则匹配，区分大小写</li><li><code>~*</code>: 正则匹配，不区分大小写</li><li><code>!~</code>: 正则匹配，区分大小写</li><li><code>!~*</code>: 正则匹配，不区分大小写</li><li><code>/route</code>: 普通前缀匹配</li><li><code>/</code>: 通用匹配</li></ul><blockquote><p>精确匹配 &gt; 优先前缀匹配 &gt; 正则匹配 &gt; 普通前缀匹配 &gt; 通用匹配</p></blockquote><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">http {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        # 优先匹配依次往下</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location = /route { return 200; }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location ^~ /route { return 201; }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location ~ ^/route { return 202; }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /route { return 203; }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location / { return 204; }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="upstream-负载均衡策略">upstream 负载均衡策略<a href="#upstream-负载均衡策略" class="hash-link" aria-label="Direct link to upstream 负载均衡策略" title="Direct link to upstream 负载均衡策略">​</a></h4><ul><li>轮询：在每个服务之间轮询请求</li><li>weight：按指定权重比例在服务之间请求，默认 weight 为 1</li><li>ip_hash：按照请求 IP 计算 Hash，保证每次请求都访问同一个服务</li><li>fair：按照后端的响应时间来分配（三方插件实现）</li></ul><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">http {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    # 负载均衡</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    upstream serverName {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        # ip_hash;  # 指定 ip_hash 负载均衡策略</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        server 10.251.10.10:8080 weight=2;  # 指定权重比例</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        server 10.251.10.10:8081 down;  # down 表示服务下线</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        server 10.251.10.10:8082;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        server 10.251.10.10:8083 backup;  # backup 表示备用，当其他机器 down 或者压力比较大时，流量会走到此服务</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        # fair;  # 指定 fair 负载均衡策略</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        listen  80;  # 监听端口</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        server_name  _;  # 不启用域名检测</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location / {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            proxy_pass  http://serverName;  # 指定 upstream 名字即可</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="http-客户端与服务端参数配置">http 客户端与服务端参数配置<a href="#http-客户端与服务端参数配置" class="hash-link" aria-label="Direct link to http 客户端与服务端参数配置" title="Direct link to http 客户端与服务端参数配置">​</a></h4><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">http {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        client_body_timeout  60s;  # 定义读取客户端请求体的超时</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        client_body_buffer_size  8k;  # 设置读取客户端请求体的缓冲区大小（超过则存储到临时文件中）</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        client_header_timeout  60s;  # 定义读取客户端请求头的超时</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        client_header_buffer_size  1k;  # 设置读取客户端请求头的缓冲区大小</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        client_max_body_size  0;  # 数据最大传输限制</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_request_buffering  off;  # 默认开启，作用是缓冲请求。关闭后请求会立即转发到后端服务</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_buffering  off;  # 对代理服务器的响应内容缓冲</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_buffer_size  4k;  # 从代理服务器获取部分响应后进行缓冲</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_buffers  8 4k;  # 从被代理的后端服务器取得的响应内容，会缓冲到这里</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_connect_timeout  60s;  # 与后端服务建立连接的超时时间</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_send_timeout  60s;  # 向后端传输请求的超时时间</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_read_timeout  60s;  # 从后端读取响应的超时时间</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_set_header  Host $proxy_host;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        proxy_set_header  Host $proxy_host;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location / {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            proxy_set_header  Auth "auth-key";</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            proxy_pass  http://serverName;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">http {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /index {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            index  index.html;  # 首页，即未指定后续路径时，匹配首页</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /try_files {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            root  /static</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            try_files  $uri index.html;  # 依次尝试。/try_files/file -&gt; /try_files/static/file</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /alias/ {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            alias  /a/new/route/;  # 请求路径 /alias/files 等效于 /a/new/route/files，会替换掉匹配路由</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /root {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            root  /a/new/route/;  # 请求路径 /root/files 等效于 /a/new/route/root/files，会保留匹配路由</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            # proxy_pass  http://serverName/;  # /root/index.html -&gt; http://serverName/index.html</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            # proxy_pass  http://serverName;  # /root/index.html -&gt; http://serverName/root/index.html</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /rewrite {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            rewrite  ^/rewrite/permanent/(.*) http://serverName/$1 permanent;  # 301 永久重定向</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            rewrite  ^/rewrite/redirect/(.*) http://serverName/$1 redirect;  # 302 临时重定向</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            rewrite  ^/rewrite/last/(.*) http://serverName/$1 last;  # 实现重定向</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            rewrite  ^/rewrite/break/(.*) http://serverName/$1 break;  # 实现重定向</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="mirror">mirror<a href="#mirror" class="hash-link" aria-label="Direct link to mirror" title="Direct link to mirror">​</a></h4><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">http {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    server {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /mirror {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            mirror  /internal;  # mirror 实现流量拷贝</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            proxy_pass  http://serverName;</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        location /internal {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            internal;  # 表示仅被内部请求发现</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            proxy_pass  http://serverName;  # 指定 upstream 名字即可</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="nginx" term="nginx"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang内存管理]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/27/golang内存管理</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/27/golang内存管理"/>
        <updated>2021-12-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[golang 的 GC 一直是大家诟病最多的话题之一。下面是 golang 不同版本之中有一些重要改进：]]></summary>
        <content type="html"><![CDATA[<p>golang 的 GC 一直是大家诟病最多的话题之一。下面是 golang 不同版本之中有一些重要改进：  </p><ul><li>v1.1 STW</li><li>v1.3 Mark STW，Sweep 并行</li><li>v1.5 三色标记法</li><li>v1.8 hybrid write barrier</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="三色标记法">三色标记法<a href="#三色标记法" class="hash-link" aria-label="Direct link to 三色标记法" title="Direct link to 三色标记法">​</a></h2><p>三色标记法，就是将对象按状态分为三类，并分为赋予三种颜色：<br>
<!-- -->1、<strong>白色对象</strong>（可能死亡）：未被回收器访问到的对象。所有对象在起始阶段均为白色，在回收结束后白色对象被回收。<br>
<!-- -->2、<strong>灰色对象</strong>（中间态）：已被回收器访问到的对象。但可能存在指向其他对象的引用。<br>
<!-- -->3、<strong>黑色对象</strong>（确定存活）：已被回收器访问到的对象，且不存在指向其他对象的引用。    </p><p>除此之外，在 v1.8 版本重还引入<strong>写屏障</strong>的概念：在 GC 执行期间，新创建的对象会被默认赋予灰色对象，以便垃圾回收的正常执行。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="标记起始阶段">标记起始阶段<a href="#标记起始阶段" class="hash-link" aria-label="Direct link to 标记起始阶段" title="Direct link to 标记起始阶段">​</a></h4><p>1、STW<br>
<!-- -->2、确定 GC ROOT，并将其置为灰色<br>
<!-- -->3、引入写屏障  </p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="标记阶段">标记阶段<a href="#标记阶段" class="hash-link" aria-label="Direct link to 标记阶段" title="Direct link to 标记阶段">​</a></h4><p>1、标记与业务并行</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="标记终止阶段">标记终止阶段<a href="#标记终止阶段" class="hash-link" aria-label="Direct link to 标记终止阶段" title="Direct link to 标记终止阶段">​</a></h4><p>1、STW<br>
<!-- -->2、移除写屏障</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="清除阶段">清除阶段<a href="#清除阶段" class="hash-link" aria-label="Direct link to 清除阶段" title="Direct link to 清除阶段">​</a></h4><p>1、回收白色对象</p><p>三色标记法，大大减少了 GC 的 STW 时间，使得标记阶段与业务并行。<br>
<!-- -->引入写屏障，使得程序在 GC 期间会有额外的性能消耗。  </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>逃逸分析</div><div class="admonitionContent_S0QG"><p>用来在编译阶段确认对象的内存是分配到堆中还是分配到栈中。</p></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="调优避免在gc期间引入耗时操作">调优：避免在GC期间引入耗时操作<a href="#调优避免在gc期间引入耗时操作" class="hash-link" aria-label="Direct link to 调优：避免在GC期间引入耗时操作" title="Direct link to 调优：避免在GC期间引入耗时操作">​</a></h2><p>背景：希望收集线上 GC 日志，以便用于后续分析。<br>
<!-- -->实现：开启 GODEBUG=gctrace=1，并将输出流指向某文件。<br>
<!-- -->导致：监控显示，线上业务必定间隔性抖动。<br>
<!-- -->原因：GC 日志输出属于 STW 期间，原本 STW 基于内存完成，但现在强行引入磁盘 IO，导致堆程序造成性能影响。   </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="未定义" term="未定义"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[python内存管理]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/26/python内存管理</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/26/python内存管理"/>
        <updated>2021-12-26T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[python 在开发过程中，不需要像 C/C++ 那样需要手动申请并回收内存。]]></summary>
        <content type="html"><![CDATA[<p>python 在开发过程中，不需要像 C/C++ 那样需要手动申请并回收内存。<br>
<!-- -->这得益于高级语言的内存管理机制。所有的 python 对象和数据结构都存储在私有堆中，由内存管理器进行管理。   </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="垃圾回收">垃圾回收<a href="#垃圾回收" class="hash-link" aria-label="Direct link to 垃圾回收" title="Direct link to 垃圾回收">​</a></h2><p>python 的垃圾回收主要有三种机制：<strong>引用计数</strong>、<strong>标记清除</strong>、<strong>分代回收</strong>   </p><p>首先通过"引用计数"，来保持追踪内存中的对象，以便创建和回收。<br>
<!-- -->然后通过"标记-清除"解决对象之间可能产生的循环引用问题。<br>
<!-- -->最后通过"分代回收"，以空间换时间的方法提高垃圾回收效率。   </p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="引用计数">引用计数<a href="#引用计数" class="hash-link" aria-label="Direct link to 引用计数" title="Direct link to 引用计数">​</a></h4><p>首先是 引用计数，这是最简单的一种回收机制：<br>
<!-- -->为每一个对象维护一个引用计数，有变量或者容器结构引用时，该对象的引用计数加一，反之减一。<br>
<!-- -->当对象的引用计数值为 0 时，则可以进行回收。</p><p>但是引用计数有一个致命的缺陷，就是循环引用，在这种场景下对象间的引用计数无法清零，会造成资源泄露。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="标记清除">标记清除<a href="#标记清除" class="hash-link" aria-label="Direct link to 标记清除" title="Direct link to 标记清除">​</a></h4><p>标记清除算法分为标记阶段和清除阶段：<br>
<!-- -->标记阶段：从根对象开始遍历，将可以访问到的对象标记为可达对象。<br>
<!-- -->清除阶段：将不可达对象清除。</p><p>虽然 标记-清除 可以很好的解决引用计数中循环依赖造成的资源泄露问题，但是标记清除它本身是一个很笨重的行为，
需要STW（stop the world）且遍历全部对象。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="分代回收">分代回收<a href="#分代回收" class="hash-link" aria-label="Direct link to 分代回收" title="Direct link to 分代回收">​</a></h4><p>分代回收基于一个统计理论，即存活越久的对象，被清除的可能性就越小。所以为了提高性能，引入了分代回收算法。<br>
<!-- -->将对象分为三代：0、1、2代，活过一次 gc，则分配到下一代。</p><p>默认阈值为：700、10、10<br>
<!-- -->700：表示新创建对象减去从新对象中回收的对象的值，大于 700 则进行一次 0 代回收。<br>
<!-- -->10：10 次 0 代回收触发一次 1 代回收。<br>
<!-- -->10：10 次 1 代回收触发一次 2 代回收。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[RAID 独立磁盘冗余阵列]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/24/raid初识</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/24/raid初识"/>
        <updated>2021-12-24T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[独立磁盘冗余阵列 RAID（redundant array of independent disks）技术]]></summary>
        <content type="html"><![CDATA[<p>独立磁盘冗余阵列 RAID（redundant array of independent disks）技术<br>
<!-- -->是将多块磁盘通过某种协议管理起来，使其共同对外提供服务，从而提升性能。</p><p>常见 RAID 有五种：RAID 0、RAID 1、RAID 10、RAID 5、RAID 6。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="raid-0">RAID 0<a href="#raid-0" class="hash-link" aria-label="Direct link to RAID 0" title="Direct link to RAID 0">​</a></h2><p>RAID 0 是将一个文件的数据分成 N 片，同时向 N 个磁盘写入，这样单个文件就可以存储在 N 个磁盘上。<br>
<!-- -->理论上通过 RAID 0，单文件容量可以提升 N 倍，读写速度也可以提升 N 倍。<br>
<!-- -->但是 RAID 0 可能提升文件损坏的风险，因为任何一个磁盘损坏，都将导致数据不完整。<br>
<img loading="lazy" src="/docusaurus/assets/images/raid-0-a5168c5847ccc32c497a3889f13dca23.png" width="531" height="413" class="img_ev3q"></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="raid-1">RAID 1<a href="#raid-1" class="hash-link" aria-label="Direct link to RAID 1" title="Direct link to RAID 1">​</a></h2><p>RAID 1 是同时往两块磁盘上写数据，其中一块用户数据备份。这样只要不是磁盘全部损坏，那么文件数据就不会丢失，文件的可用性大大提升。<br>
<!-- -->但是可用的存储空间就降低一半了。而且由于多写了一份数据，写入性能也变相的降低了。<br>
<img loading="lazy" src="/docusaurus/assets/images/raid-1-c505b2458f60664dc52a52d9e8c94cee.png" width="323" height="389" class="img_ev3q"></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="raid-10">RAID 10<a href="#raid-10" class="hash-link" aria-label="Direct link to RAID 10" title="Direct link to RAID 10">​</a></h2><p>RAID 10 是结合了 RAID 1 和 RAID 0，将多块硬盘进行两两分组。文件数据被分成了 N 份，每个组写入一份，并且每个分组的数据都有一份备份。<br>
<!-- -->这样不仅提升了文件存储的容量和性能，也提高了文件的可用性。<br>
<!-- -->但不可避免的和 RAID 1 一样，磁盘整体存储利用只有 50% 了。<br>
<img loading="lazy" src="/docusaurus/assets/images/raid-10-32305ed150f7861e3b5b1b67d601ee9b.png" width="531" height="413" class="img_ev3q"></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="raid-5">RAID 5<a href="#raid-5" class="hash-link" aria-label="Direct link to RAID 5" title="Direct link to RAID 5">​</a></h2><p>RAID 5 针对 RAID 1 和 RAID 10 中磁盘浪费的情况进行了优化。<br>
<!-- -->将数据分成 N - 1 份，再利用这 N - 1 份数据进行位运算，计算一片校验数据，然后将这 N 片数据写入 N 个磁盘中。<br>
<!-- -->这样任何一个磁盘损坏，都可以利用校验数据进行恢复，磁盘利用率也提高到 (N-1)/N  </p><p>虽然 RAID 5 可以解决一块磁盘损坏后修复的场景，但是两块磁盘损坏，就仍然会出现数据丢失的情况。   </p><p>实践过程中，使用最多的还是 RAID 5.</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="raid-6">RAID 6<a href="#raid-6" class="hash-link" aria-label="Direct link to RAID 6" title="Direct link to RAID 6">​</a></h2><p>针对 RAID 5 中可能出现的两块磁盘损坏的场景，引入了两种位运算计算和存储数据，这样即使两块磁盘损坏，仍然是可以得到修复的。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="计算机基础" term="计算机基础"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[初步了解 k8s 资源配额]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/23/k8s资源配额</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/23/k8s资源配额"/>
        <updated>2021-12-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[<!--]]></summary>
        <content type="html"><![CDATA[<p>用一台服务器同时跑多个任务时，最常发生的事故就是资源抢占问题。比如端口、cpu、内存、存储等都可能会发生冲突。<br>
<!-- -->而 k8s 作为容器编排工具，则提供了资源配额来避免这类问题。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="资源配额-resourcequota">资源配额 ResourceQuota<a href="#资源配额-resourcequota" class="hash-link" aria-label="Direct link to 资源配额 ResourceQuota" title="Direct link to 资源配额 ResourceQuota">​</a></h2><p>资源配额用于声明命名空间中所有 pod 的最终资源情况，一旦命名空间中启用了 ResourceQuota，则部署 pod 时必须设定请求值（request）和约束值（limit），否则配额系统将拒绝 pod 的创建。<br>
<!-- -->资源配额在 k8s 集群中默认是支持的，当一个命名空间中存在一个 ResourceQuota 对象时，该命名空间的资源配额就是开启的。   </p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">资源配额：ResourceQuota.yaml</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ResourceQuota</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> demo</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">hard</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">requests.cpu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"1"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">requests.memory</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 1Gi</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">limits.cpu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"2"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">limits.memory</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> 2Gi</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>此配置表示： </p><ul><li>每个容器必须有 memory、cpu 的请求和限制。</li><li>所有容器的 memory 请求总和不能超过 1 GiB。</li><li>所有容器的 memory 限制总和不能超过 2 GiB。</li><li>所有容器的 cpu 请求总和不能超过 1 cpu。</li><li>所有容器的 cpu 限制总和不能超过 2 cpu。</li></ul><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">部署示例：pod.yaml</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">apiVersion</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> v1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">kind</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Pod</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">metadata</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> demo</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">spec</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">containers</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> nginx</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">image</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> nginx</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">resources</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">limits</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">cpu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"200m"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">memory</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"400Mi"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token key atrule">requests</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">cpu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"100m"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">memory</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"200Mi"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="requestslimits">requests/limits<a href="#requestslimits" class="hash-link" aria-label="Direct link to requests/limits" title="Direct link to requests/limits">​</a></h2><p>requests 表示请求值，而 limits 则表示约束值。<br>
<!-- -->一般情况下 requests 是小于 limits 的，这里涉及到服务质量等级概念：</p><table><thead><tr><th>服务质量等级</th><th>说明</th></tr></thead><tbody><tr><td>Guaranteed（完全可靠的）</td><td>pod 中全部容器配置了资源配额，且 requests == limits，或者只设置了 limits，此时默认 requests 等于 limits。</td></tr><tr><td>Burstable（弹性波动、较可靠的）</td><td>pod 中部分容器配置了 requests 和 limits。</td></tr><tr><td>BestEffort（尽力而为、不太可靠的）</td><td>pod 中容器未配置 requests 和 limits。</td></tr></tbody></table><p>当我们配置了 requests 请求值，那么部署时，目标节点需要拥有多余该请求值的空闲资源，才可以部署此服务。如果没有符合条件的节点，那么该服务将无法部署。<br>
<!-- -->当我们未配置 limits 约束值时，limits 默认就是当前节点的资源上限。   </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="常使用的配额类型">常使用的配额类型<a href="#常使用的配额类型" class="hash-link" aria-label="Direct link to 常使用的配额类型" title="Direct link to 常使用的配额类型">​</a></h2><p>资源配额的种类有很多，最常使用的配额主要有三类：</p><ul><li>cpu：中央处理器</li><li>memory：内存</li><li>ephemeral-storage：存储</li></ul><p>大部分资源类型都可以通过标准的模板进行配额设置，如：  </p><ul><li><code>count/&lt;resource&gt;.&lt;group&gt;</code>：用于非核心 core 组的资源</li><li><code>count/&lt;resource&gt;</code>：用于核心组的资源</li></ul><table><thead><tr><th>配额</th><th>说明</th></tr></thead><tbody><tr><td>count/pods</td><td>在该命名空间中允许存在的非终止状态的 pod 总数上限。</td></tr><tr><td>count/services</td><td>在该命名空间中允许存在的 service 总数上限。</td></tr><tr><td>count/configmaps</td><td>在该命名空间中允许存在的 configmaps 总数上限。</td></tr></tbody></table><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="k8s" term="k8s"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[记一次 golang cmd 模块导致的进程泄漏]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/22/golang-cmd模块导致的进程泄漏</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/22/golang-cmd模块导致的进程泄漏"/>
        <updated>2021-12-22T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[一个稳定跑了一年多的项目，近期突然被运维告知存在进程泄漏，带着懵逼的心情开始了排查...]]></summary>
        <content type="html"><![CDATA[<p>一个稳定跑了一年多的项目，近期突然被运维告知存在进程泄漏，带着懵逼的心情开始了排查...</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="僵尸进程拖垮服务器">僵尸进程拖垮服务器<a href="#僵尸进程拖垮服务器" class="hash-link" aria-label="Direct link to 僵尸进程拖垮服务器" title="Direct link to 僵尸进程拖垮服务器">​</a></h2><p>首先来看下运维提供的截图（屏蔽了部分敏感信息）：<br>
<strong>1、大面积僵尸进程（进程状态 Z）</strong><br>
<img loading="lazy" src="/docusaurus/assets/images/进程泄漏1-60d5187b97e7e7c887961f0423beda8c.png" width="666" height="769" class="img_ev3q">  </p><p><strong>2、统计进程数近30w</strong><br>
<img loading="lazy" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAecAAAAnCAYAAAA1koBUAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAABWxSURBVHhe7d0HuC9HWcfx2HsXe0HFhl1QkUCAKGoURbErir23oCg2ECtWxMcusQuxYg3YFRUVE4EUUEBNcksINx0Q+/H9XM6EeSbv/939n3suOefeefb5Pv/dmd39787Ozm/ed8qec9uLX7pzWDhxw407z3v+C3aeffkVO8+6/PKdK6967s4VwVXdbxbmV/hllz1z59JdrC9xzZFjd+DalWHb0p9j0/k27WM9i7v99+ixnSNHj+8cu+6FO0ePXXeSY7u/R4+/4lfYdbHP9S86sXPixpvSZzCZTCaT08/t4nzhhQ/fue955+2ce5/77Nz73HMPFBdccMHOEy+++KQgn+TZL6eJcfvt1/vftt6EeS3XHjnaQez67U1h29KfY9P5Nu1TCPLub88YZptwn/ztwnuuvubanSuvfM7OJU956s4TLrpo59GPeUz6jCaTyWSyHfSW7j7g/PM3i/M97nHPnXPOOefg8YbBfYPzEz4++ITd3369/+3j32lLzt2St9uST96S99mS99+S9+h4z2G7R9y7B47J/rfxXsHdu9/3Dt43QXjDuWH9nrt8SIftewQftLve4j84uFtw1+CtgzcNsvw0mUwmB5BemHG7OFPw7IA7lTcJMlFuNNFdSybAFZkAV2QCXJEJcEUmgBUfsAsRbettOyMT5EqkieQ2ENRtOG9LVAJGVApUJN51FwL+LsE7B9LiA4P2f30lIOPNO94skD9VHl83eM0gy8OTyWSygl6Ycbs4M7HvcMADgscHPx0opMf408lrB/cJMlFuNNFdspjbdibAFZkAV2QCXJEJcEUmwBWZADd6sW400W2C7LciE+CKXnjXkAlwRSbOFffbkrdYwRsHrxVkebrnQcHPBN8fsPazfc5UVGbeIHjVLmwJlR+VoVfpws5k3OerD2F3Nq6JR+o1urCDimv0PqpIv/5u2AGnF2bU4vy9wf8GChBWxxh/OniH4EMD7s5MkHua+K4lE+AKgquC0JOFNTIBrsgEuCIT4IpRhEeBHmnivJZMgCsyAa7IBLgiE+CKTIArRiGuUIipYGZ5HA8MfjmwWM/2kWffLZBXPiXYRswOIgrK3wyuDS4LvOvZfhkXBM8MVH6y+DONTwyeH6iQZPEZHxX8bPBXwS8E9w6y/fYKb9GzA2VvFn+QcO/PC64Ofms37IDTCzNqcX5s4GGM4aeTrwh+PxiFOGMU3yUyAa7oreI1jOK7RCbAFZkAV2QC3Iv1KNqZAFdkAlyRCXBFJsAVmQBXZAJckYlwBe8Ct3eWz0GsbgwycWZdXh9wu39L8GfBuM9h4+HBfwU8ct6vbSywTwpuCAhEFn+moc/FDwWv14VV8ERcHvx18LjgGcG/B4yGbP+9IE/fFHxMF3ZQeZ1AHvvJ4KrdsANOL8yoxfl7giuHMLxtoEDxsIjpNwcKuxavoPzW4AuCsXB6q8Ax3xQoeFq4c31W8GuBwigT45Hejd1+23q/3eiFdw2ZAFdkAlyRCXBFJsAVvSgvQaQzAa7IBLgiE+CKUXyXGMV3iUyAK5rorkV7NzYJtPZvhd2Hd2EKY4Xf1wW3Bp8ZXBr8bqDduz8+g9dJ2n1s4B2U7n08a945vyv48kD7ex9/KjgXAf6GQDt/H+7dflrwL4F38eOCbdyNjjkWZB39Hhy413sFxEh/ghangiSMle66vjbw7rV4z9WxXxQQuBbuXNLRdSqPdDxscUt43q73MYH0cA19PGuYJ0Dl7POCbwvas/V8WM0PCVzDqwXtOJ4T7+qFgXMr45qbX1NK/yy5xFVmfq4Lg/fW8Y8OvDP9+Ze4S3Bd4Nqz+BHpp1wcw98y0KzTPEu8IQ8Lvj3gISKs4zF7Rdo+awg7oPTCjL2Js4zzkkCh8ZzAC3dRIO6rg/8MuFauCbiiFFTiFEbcDP8U/E3gHJ8eiFOIXRL4P+6ZTIxHvABnkzhz9RPd7LenhY2W8RKtLXkto/gu0UR3LaP4LpEJcMUovkuM4rtEE2dplbm4M3GWL/4+IMzirggsXHQ/FfTHZ/xOwGL6h+BvA+9Ys3QUen8QvDAg9t7dnwjGc+wF7yxLn+Xm3bfumYhzf97to8HNwVMClXC96sfzbML7m4nzdwea3v4icD8vC74yaPGPCogUD6C0PBI8MhD3nYH0+eNA+irPCKY4rtCXBv8YjOm4hIqV+39q8Je76/2x8rZze0YvCP45kD7E942C3whcj+fUu7XfJnCPmgR+LxBv36yPA9H2vz/ahX1GcEvAqnZdymflRH9cxbbiLH3dx+gh+ZrAtbtuzaX2+dfAc/CMvzTo9z8VXMNZJc5q5ZYfCdS81NLePlAgeTm4w+2no4ttL4htHWA8XBnQ9pMCL2xfU/riIBPijCbCa8kEuCIT4IpRfJfIBLiC6G5DE+dNjOI8WsZLZAJcMYrvEqP4LpEJcEUmwBWj+C7RxBmsOVax597yeibOjT8JHhFoO1P5ZV2saXMmvlzlCvK2TZSss6wsLOe2PyumrW9CQd86cbF2G7YVvNYV9No52zEEmIj0lhkXo0p5296GTJyl6f8FLEHbHx1YeObaPoTY8lW7265VpUD+shAs4UT5PwIWpW2Vl9uClj7Ek1CvsTQ9474y5hn09+3ds6gANLe1srI/t+vyHHs3vmfQ5x/NAxZ5v4U1WOwqLe+3u+3+3I8yuO2j0khw2/YS24oz76qKovR23R8WCH9iID2tq0z+W9CuQ77Vz6KdYxM6CI75EdKzf0/OOnEmdB78O3ZhMB75f4LeXa02pAZpXa1Pz+8Wx7XhhehdYFzhmRBnjOK7RCbAFQrGBvHttzNkwG3IBLgiE+CKXnhHYe5p8ZkAV2QCXDGK7xKj+C6RCXBFJsAVmQBX9OKMLwsURi2vj+JMBLlEFdTETiFILFg5a9setU0Tlrb9uQErrRVe2t8Uhj8QeIf6YzdBIIgLq9OxDWL59YF3xaIQVKkAS4j134vpfoszD57Cv/V2J17HA67rtg/DgLU4iirrzcLVLs1cM49f6zxEPFinbX9ueeLmubawTXhWXLR/Hji3DnCs7+aC9i6oVCgzxmMbnxq8KBjb2D8i0CfHdUvL/w649ft9iKKFF7OFfWSgzJYP+323YVtxtv+JwLvzfYF7VkngxZD+RFR8q1xtg8qW/NDnR+ns3PJj2++sE2edM2T4MaPKOCxlnRlamIKidWbhwvnh3XUolOzfanf4nGAU4U1kAlzRC+8aRst4iUyAKzIBrsgEuKIX501McV5PL7xrGMVZgcv92/L6KM7cfNyUmn4smn9eHBAFbts1Vg5B4DJu2ywwLtnmQmaZaG/WecjCrb1kkbsubtlPC/r8qEmq5TMLoSaiRNP+3ol+/De3/NO77W3IxNn/Sxt9YGyzVhXQ3MptH22z0rEJY0NbJGFwH64Xno18IZ5B8au761DmqQh4b1tYhkoAS1lFhhdQufPbAYFo12DCHOWetBuPb7i3UZyVr4wZrmpts8pK26697aPtmmCrfLUwSD/7nsqwvW3FGZ73DwZ0QIVThYGQuk75io5od8+OrfA+SaM+P3q/pLdKaNtPswePR3/sAaUXZuxdnLUdjS4x7QcWidTC1KBbe/QfBdqjWpwOGgqOPgOq6WdCnNEL7xoyAa4YxXeJUXyX6DPWGnrhXUMvwmvIBLgiE+CKTIArMgGuGMV3iUyAKzIBrhjFGX372yjORFIl6dcDbbcEznv2hYHCbM1EJ38YEN627R0mQtmxrBmerrEdd1sIv17Y3t0svrHf4izPWnTasi19CVNzYYM4PzcYKyDKMJakDqp9eIPAOq5ta6rTBMc67/cbcX08FX27Nxc/i64XZ0Jftfe6J23G/Vhngusa2raObu5B2tiWHp51bwA1uLAtBL0P36bH/F7EmThyzxs2yKPh+qVr8wTRF8Pr+mO2uaYldDwe0/GA0gszanHeNJRKbdwydujwAnC5KHAUKNqgvPx6kIonkBZd/WVeGat3c+P+QSbEGaP4LpEJcEUmwBWZAFdkAlxBcHklxt+ePqwX3jVkAlyRCXBFJsAVmQBXZAJckQlwRSbAFaMwo++5zcWn4BrbnLlAVVy5PVlPa0S5oaCzsK5YKRaWsjjP7E8DbbKsFW3R/mub82/CnAjedRbpQ4NfDPRJ6fdRQGeV/TVk4kzsuJ5VYIiAij9x7tucVUB0PhrFmcjqeMd4+JJAeaVi49rFs5otPx40F3hLxwqW898FLGdp/GOBxX03cfZcLSpi4/GEW4eoiwOLkTB61btvgm1hiQrjibQId3+8BhbX7PlrX3Zf7dw/H0gfguXaWPSns0MYVDAtKonyu4UXqMU3LaEDLd/sxZLehEqtRQVJr3vlbrbfAaAXZtTibPIRlq3M29+UDOTBZ0NE9C6UMbgSPASdx/r4zw68RHpGeqHGbvNqOBJ0DToEbIOXYxu4XbYhO0cFN9w2qFFug9rpNiikt0FBtA3ZOSrkhW3I0qBC3tuG7BlWZPckHeRzQ3O0S1q4K1v+95xVXlk6CkHDfFrcGrSVcm17P9s75n/F8VCZpEIvYW5WhbVK6HiOveC+iJh3m+XOLdwsusbnB8S7D1tLJs5wb98RcJtq09ckQLhavGFJLE7Poz8OxEIFQnrovKbyIN3F6RugOY5YiO/TcQmVIG3XykBlIUOEsLdr0DHPECedaMdjiRWrnXDqMMvYsd0mgWJ9eq76IRBe4q9iLf216etsJS0cg9YzHa6f2PNeGEVDxDcN88vYizhrRpHPaIZt/9l3SAQvhkqjfON+3U8ff6pok39yID3a8z2A9MKMWpxZmzIZd3RWyztdSMBMjEcyAa7oC841ZAJckZ2jYhTfJTKBqcgEuMLLuw1NdNeSnaMiE+CKLA0qMgGuyJ5hRXZP0kEe18HIe8WF3XeIPFVUiPte03cG7j0LPxU2ibNOqd4968oEy35MvKEjK1HJ4s5W9iLO23A68s0hohdm1OJ8Z8ElOApxRibAFX3BuYZRfJfIzlGRCXBFJjAVmQBXZGJSMYrvEtk5KjIBrsjSoCIT4IrsGVZk9yQdsjy/X7CaWU9Z3GFGPxbttGPvZU1vBIPFrjlNBzdp3++zF1SczsR0PBX0MdKjfewdPtkXemHGwRRnaDvNBLknE+CKsfBcIhPgiuwcFQp8ojuKwBg+xXkdWRpU9Om9huwZVmT3NLZ97jeGMepvkMUdZrSNagYYO2SxpLVraqeshiZtC0/hmZiOp4Je0IYmHWDX8GGmF2YcXHHWFpIJck8mwBVZAVqRCXBFdo6KJrpryQSmIhPgiuyeNkFoMgGucEx2rsYYnwlwRZYGFZkAV2TPsKIJco/wLL9PJpOzml6YcXDFGYY5ZKLcyAS4Yiw8l+iFYg3ZOSoyAa7IBKYiE+CKTEwqMgGuyM5RkQlwRZYGFZkAV2TPsGK8H/+Z5fPJZHLW0wszDrY4Q2+/TJiRCXBFVoBWZAJckZ2jIhPgilFclsgEuGIUkyUyAa7IzlGRCXBFlgYVmQBXZM+wYrwfaZDl8clkctbTCzNycTbjjt6k2nhMLNB/Q1W7jjjd4Y1LM1ONXt2GJYgnmoZUGN6gE4dCrT+voQLOa6KA8RvR5so1fad4sxG19iUubuNkpzhvRybAFaOYLDGK7xLZOSoyAa7I0qBiFN8lsmdY0d+L/+vz+mQymXT0wow7irNCxBzYJkcwFs4Af+PP2jzaBsCbiN8AeNPi+eKLRScBBVj7yopxlAa8G5JAGB3bJgQw/s+vqffaGE8Tmhi4r+eleD0z9TxtQycI9TcGJk+f4ryOTIArejFZQybAFdk5KjIBrsjSoGIU3yWyZ1jR38vp7gg2mUwONb0w447iTARYvO2rNgbUE1kzvNhuhZr9bJvHt01NJ84XRayLa19NaYPOfVO1WdisYTPpGOBv2xAJg9GbGPuIhqXN9sOCtxigTqj1GjSLVJvQfw19wbmGTIArsnNU9MK7hl5Y1pAJcEUvJmvIBLgiO0dFJsAVWRpUjOK7RPYMK9p9uHd5eDKZTDbQCzPWtTmbFm6cZhOE1Axi/ddPegi7ZdOcu21WmCxOoWa+3jZDkmkJ29dFuLwt/pvg98edrbDMiEAvUgRXRaZnFOSeJiZr6YV3Ddk5KkbxXaIX3jVkAlyRCXBFu4fseU0mk0lHL8xYFmdfarH45NgYZ5o8AjrOsW1uWFPfcYmzrIlCi/MFKmFc30TfnNT9sQ1fdPGJsfbFKh8CMPOR9m8f5zYNof/uP0852Tu9uI0iuYlMgCuyc1T0QpqJbxPlxhi/RCbAFZkAV0xX9mQyWUkvzKjFWTuzWXfaV6V6FD4mc2/fP+0xx62J47Uhm8+071BGbH8lMKOPr4X08wo3CK6PYvTz8HJ/s96fEPxS4MMFlk3iPjn8jGK3RHaOyWQyOQT0wnzTzbcU4qxt+PmBuXq1p/Zx0CHLYnaeMa5hYncduzZ9zcWk8jqG9Za1SeF1MiPg/b4mc/eFHt8CdW3t/+csPpPJZDI55PTifOKGGzeIM0tXZ62n7W5nsGBNRK+jUhbf4L7OrGtwi7OQ28fSiTmXdf+R88bjA4uhWLZ9UN13U83DPe47mUwmk8khgrXc9PjmW25LxJmVbNJ3i09F+uSj3tss1XYiE6Br7/VJyRYG+wjTS9vctD6zZnlYIJ4F7ZOR5s32lRlu7WcE2uZ8apKb3EKAjZ3W8cu+jvWlGcsjdtdvCUbrejKZTCaTQ8jVV18TAn3r7QJ9R3EmknpFc2kbs6zTlrZj3yVtJ/Jxb99NHSdA11bM8iW6XNB4VNA6xhBTLmvxflUC2kQkdwuMn3Z8/78+kN3Of2FwPOAK92F0lYQWN5lMJpPJIeX660+cdGdvFme0nq/9GF7bLV5PWvu07R4dc7inDaMy8ccYb/gVUW/jqBuOy/53/B/Hz+FTk8lkMjmDOHb8ugXLeTKZTCaTySuVI0eOnrSetTdPcZ5MJpPJ5ADAaj5xw00n255vve0lU5wnk8lkMrmzaVp89Njxk0I9xXkymUwmkzsZOsxiZjnnQ6l6dOi6a6AntekLx/jJZLI3dGz0Xuk8qYNlts9kMjlr4NLW7tx6bNfibOjSicDHKe61G3YYMUWo8dpZ3BLnBQ8ZwvYDvdN9ratKVxUiY7p9Q1vP9Wyf04Wvht0lOAjTYuqdb8y9a8ri9wNfReunme0xd/z9g7sH+zVftvsxZNCwwioPmJO8/51MJmck17/oFZ3BlsXZ95evCRSOSzOB7RcPCoyp3iQKCslHBmYXU6Bm+4xcEjx9CFuLj21cMYTtBwp548Af14X1GDOuUmS899HAt7WJQ7bvfsKSe2ygUnZpsEmwXpk8OLC0MfH7iXR+UuD75Z71GG+cvg+4mGPe70ODcZ+9oKJxfvCy4IG7YT3y/5OD+wWmyL04GPeZTCZnDE2LX85Ld/4fHHS0L8j8bREAAAAASUVORK5CYII=" width="487" height="39" class="img_ev3q">  </p><p>并且僵尸进程持续增长，最终拖垮服务器。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>僵尸进程</div><div class="admonitionContent_S0QG"><p>一个进程的退出，需要被它的父进程或者相关联的进程接收，否则会一直阻塞，成为僵尸进程。</p><p>常见的僵尸进程产生场景有：<br>
<!-- -->1、父进程还在执行，子进程退出了，此时子进程的退出没有被父进程接收到，导致当前进程成为僵尸进程。<br>
<!-- -->2、子进程还在执行，父进程退出了，此时子进程的退出无法被其他进程接收，导致成为孤儿进程，也是僵尸进程的一种。     </p><p>僵尸进程状态为：Z<br>
<!-- -->以 <code>&lt;defunct&gt;</code> 标记指明    </p></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="代码分析">代码分析<a href="#代码分析" class="hash-link" aria-label="Direct link to 代码分析" title="Direct link to 代码分析">​</a></h2><div class="language-golang codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">调用 cmd 模块</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-golang codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">ctxTimeout, cancel := context.WithDeadline(ctx, cfg.ExpiredAt)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">defer cancel()</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">cmd := exec.CommandContext(ctxTimeout, "/third_party/aria2c", args...)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在上述代码能够看到，调用 <code>cmd</code> 时传入了 <code>ctxTimeout</code>，并且函数栈退出时调用了 <code>cancel</code>。<br>
<!-- -->看到这里，我们可以大致确认，<code>cmd</code> 最终肯定是可以退出的。但是就是这么一段简单的代码，仍然发生了进程泄漏。</p><p>我们需要注意的是，cmd 是 golang 的基础包，其启动方式有两种，如下：</p><div class="language-golang codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">cmd 启动方法</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-golang codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    cmd.Start()</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    cmd.Wait()</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">{</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    cmd.Run()  // 等价于 start + wait</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>继续往下排查：</p><div class="language-golang codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-golang codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">ctxTimeout, cancel := context.WithDeadline(ctx, cfg.ExpiredAt)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">defer cancel()</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">cmd := exec.CommandContext(ctxTimeout, "/third_party/aria2c", args...)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">path, err := consumeOutput(cmd, ctxTimeout, cfg)</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">if err != nil {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    retrun err</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p><code>consumeOutput</code> 函数中涉及到一些日志输出的读取与分析，这里就不具体展示了，但这个函数的<strong>最后一行调用了</strong> <code>cmd.Wait()</code>。<br>
<!-- -->看到这里，问题的起因就大致有点眉目了。</p><p>我们来看下 <code>cmd.Wait()</code> 的文档，最后一行写着：</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">Wait releases any resources associated with the Cmd.</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>所以可以初步判定，就是因为该函数调用过程中出现异常，没有执行 <code>cmd.Wait()</code> 函数就直接退出，导致 cmd 相关的子进程资源没有及时释放，从而造成线上大量僵尸进程。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="解决方法">解决方法<a href="#解决方法" class="hash-link" aria-label="Direct link to 解决方法" title="Direct link to 解决方法">​</a></h2><p>老项目，怎么简单怎来。<br>
<!-- -->这个问题说到底，还是 <code>cmd</code> 模块的使用方法不正确导致的，项目能稳定运行一年多，也只能归结于运气好...</p><p>直接在 <code>consumeOutput</code> 函数调用后主动加上 <code>cmd.Wait()</code> 就行了，虽然不优雅，但能解决问题。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
        <category label="bug" term="bug"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[cpu 调度]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/21/cpu调度</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/21/cpu调度"/>
        <updated>2021-12-21T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[<!--]]></summary>
        <content type="html"><![CDATA[<p>说到 cpu 调度，我们第一时间想到的可能是时间片、分时调度等关键词。
要说更具体的内容，可能就比较模糊了，因为涉及到了操作系统的底层知识，平常工作中接触的比较少。</p><p>这篇文章也仅仅做个简单的了解。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="基础概念">基础概念<a href="#基础概念" class="hash-link" aria-label="Direct link to 基础概念" title="Direct link to 基础概念">​</a></h2><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="cpu上下文切换"><strong>cpu：上下文切换</strong><a href="#cpu上下文切换" class="hash-link" aria-label="Direct link to cpu上下文切换" title="Direct link to cpu上下文切换">​</a></h4><p>每一个进程启动，都需要有一个执行指令入口，即使该进程被暂停调度，也会有一个即将被执行的指令入口。
对于这些即将被执行的指令，我们将他们的地址信息保存在 cpu 的寄存器中。<br>
<!-- -->此时，这些寄存器中的信息，就是我们常说的 cpu 上下文。</p><p>所以简单点理解就是，将当前任务的上下文保存，并将下一个执行任务的上下文加载到寄存器中的过程，称之为 cpu 的上下文切换。
当然，实际过程更为复杂。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>用户级和系统级的上下文</div><div class="admonitionContent_S0QG"><p>我们常说的上下文更多的是用户级别的，他和系统级上下文保存内容有所不同：  </p><ul><li>用户级上下文：程序运行时堆栈信息、数据块、代码块等。  </li><li>系统级上下文：进程标识信息、控制信息等。</li></ul></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="cpu上下文保存的方式"><strong>cpu：上下文保存的方式</strong><a href="#cpu上下文保存的方式" class="hash-link" aria-label="Direct link to cpu上下文保存的方式" title="Direct link to cpu上下文保存的方式">​</a></h4><p>操作系统给进程分配资源时，会分配一个内核空间，这部分空间只能够由内核代码访问。<br>
<!-- -->执行上下文切换时，会将上下文信息保存在内核空间中，等待下次调度时，再重新加载到 cpu 中。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="cpu上下文切换的方式"><strong>cpu：上下文切换的方式</strong><a href="#cpu上下文切换的方式" class="hash-link" aria-label="Direct link to cpu上下文切换的方式" title="Direct link to cpu上下文切换的方式">​</a></h4><p>执行上下文切换，需要由 cpu 来执行。但由于当前 cpu 已经被进程占用了，所以需要一种策略，来获取 cpu 的执行权限。获取的方式主要有两种：</p><p>1、协作式策略<br>
<!-- -->由进程主动让出 cpu</p><p>2、抢占式策略<br>
<!-- -->依赖硬件的定时中断机制，操作系统初始化时向硬件注册中断回调，以便当硬件发生中断时，硬件会将 cpu 的处理权交还给操作系统。<br>
<!-- -->这样，操作系统就可以通过中断回调的方式来获取 cpu 的调度权。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="最简单的调度fifo">最简单的调度：FIFO<a href="#最简单的调度fifo" class="hash-link" aria-label="Direct link to 最简单的调度：FIFO" title="Direct link to 最简单的调度：FIFO">​</a></h2><p>说到最简单的调度策略，那肯定是先进先出（FIFO）策略了。<br>
<!-- -->FIFO 的意思就是先来的任务先处理，等当前任务执行完成后，再执行下一个任务。</p><p>他的优点就是简单明了，缺点也很明显，就是正在执行中的任务会阻塞后面的任务。<br>
<!-- -->特别当有多个任务时：</p><ul><li>执行时间较长的任务可能会阻塞执行时间较短的任务</li><li>优先级低的任务可能会阻塞优先级高的任务</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="最短任务优先sjf">最短任务优先：SJF<a href="#最短任务优先sjf" class="hash-link" aria-label="Direct link to 最短任务优先：SJF" title="Direct link to 最短任务优先：SJF">​</a></h2><p>SJF 全称 Short Job First，就是执行时间短的任务优先执行。</p><p>他相较于 FIFO 来说，弥补了一部分调度策略的缺陷。<br>
<!-- -->当一批任务到来时，可以优先处理执行时间较短的任务。<br>
<!-- -->但是当执行时间较长的任务正在被处理，此时再投放执行时间较短的任务，这些短任务仍然会被阻塞。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="最短时间优先完成stcf">最短时间优先完成：STCF<a href="#最短时间优先完成stcf" class="hash-link" aria-label="Direct link to 最短时间优先完成：STCF" title="Direct link to 最短时间优先完成：STCF">​</a></h2><p>STCF 全称 Shortest Time-to-Completion First，就是当运行时间较短的任务达到时，会中断当前任务，转而执行这批短时间任务。<br>
<!-- -->很显然，这是 SJF 的一种优化。</p><p>在这里我们其实可以看到，不管是 FIFO、SJF 还是 STCF，这些调度策略的本质都是先执行一个任务，再执行下一个任务。    </p><p>当完成一个短任务所需要的时间也很长时，这个时候，对于每一个任务，调度执行的时间将不可避免的被延长。   </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="基于时间片的轮询">基于时间片的轮询<a href="#基于时间片的轮询" class="hash-link" aria-label="Direct link to 基于时间片的轮询" title="Direct link to 基于时间片的轮询">​</a></h2><p>既然，这种完成一个任务再完成下一个任务的调度策略这么不友好，那么我们就让这些任务一起执行。</p><p>原理也比较简单：<br>
<!-- -->1、给每个任务分配一个时间片，时间片表示该任务被 cpu 调度执行的时间。<br>
<!-- -->2、当时间片的调度时间结束后，cpu 会中断该任务，切换到下一个任务。<br>
<!-- -->3、通过 round robin 轮询的策略，对每一个任务执行调度。    </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="多级反馈队列mlfq">多级反馈队列：MLFQ<a href="#多级反馈队列mlfq" class="hash-link" aria-label="Direct link to 多级反馈队列：MLFQ" title="Direct link to 多级反馈队列：MLFQ">​</a></h2><p>MLFQ 全称 Multi-Level Feedback Queue</p><p>该策略综合考虑了优先级和轮询的特点，此时调度策略类似：<br>
<!-- -->1、任务优先级高的任务先执行<br>
<!-- -->2、优先级相同的任务轮询调度执行  </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="linux完全公平调度cfs">linux完全公平调度：CFS<a href="#linux完全公平调度cfs" class="hash-link" aria-label="Direct link to linux完全公平调度：CFS" title="Direct link to linux完全公平调度：CFS">​</a></h2><p>CFS 全称 Completely Fair Scheduler</p><p>CFS 希望将 cpu 公平的平均分到每个任务。为了实现平均能力， CFS 引入了计数的概念。
每个任务都维护有一个 <code>vruntime</code> 的值，用来表示调度执行的时间，每次调度执行后，该值都会加上此次调度时间的值。
每一次调度，操作系统会选择 <code>vruntime</code> 值最小的优先调度。</p><p>在 CFS 种，调度执行时间片不是固定的，linux 提供了可配参数 <code>sched_latency</code>，调度时间片就是：<code>time_slice = sched_latency / n</code>，
这里的 n 就是任务数，即任务数越多，时间片越小。</p><p>除此之外，linux 也提供了权重来标记任务的优先级，优先级高的任务将分配有更多的执行时间片。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>权重机制</div><div class="admonitionContent_S0QG"><p>linux 提供了权重机制，用于标记任务的优先级。<br>
<!-- -->优先级高的任务，将被分配更多的执行时间片。<br>
<!-- -->在权重机制下，也不再是取 <code>vruntime</code> 值最小的优先调度了，会有新的算法引入权重值。</p></div></div><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>CFS 存储结构：红黑树</div><div class="admonitionContent_S0QG"><p>在文中已经说明，CFS 调度时会选择 <code>vruntime</code> 最小的值，此时为了性能，采用的是红黑树来存储 <code>vruntime</code> 数据。<br>
<!-- -->红黑树在插入和删除时，操作复杂度为 log(n)<br>
<!-- -->而有序链表的操作复杂度为 O(n)</p></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="计算机基础" term="计算机基础"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[字符编码]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/15/字符编码</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/15/字符编码"/>
        <updated>2021-12-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[字符串是使用的最多的数据类型之一。]]></summary>
        <content type="html"><![CDATA[<p>字符串是使用的最多的数据类型之一。<br>
<!-- -->如果说在使用过程中会遇到什么问题，那可以说，大部分都是编码方面的问题了。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="ascii-编码">ascii 编码<a href="#ascii-编码" class="hash-link" aria-label="Direct link to ascii 编码" title="Direct link to ascii 编码">​</a></h2><blockquote><p>字符编码的本质，是数字到字符串的映射</p></blockquote><p>最早的编码是 ascii 编码，它是一个包含 128 个字符的字符集，可以编码字母和特殊字符。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>比特与字节</div><div class="admonitionContent_S0QG"><p>由于计算机底层只能够处理数字，如果要处理类似文本图片等数据，就需要先将这些数据转化为数字才能够继续处理。<br>
<!-- -->最早计算机在设计时采用 8 个比特（bit）作为一个字节（byte），所以一个字节能表示的最大数字就是 255，二进制表示 <code>1111 1111</code></p><p>如果需要表示更大的数，就需要更多的字节</p></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="unicode-编码">unicode 编码<a href="#unicode-编码" class="hash-link" aria-label="Direct link to unicode 编码" title="Direct link to unicode 编码">​</a></h2><p>随着计算机的发展，单一的 ascii 编码已经无法满足多元的文化需求。<br>
<!-- -->计算机需要支持更多的编码集，例如：中国制定有 gb2312，其他国家也有类似的编码集。</p><p>虽然每个国家都实现了特定的编码，但是当一个文本中混合了多个国家的语言时，就不可避免的出现局部乱码。</p><p>为了解决这个问题，业界决定使用统一的 unicode 编码。<br>
<!-- -->即将所有国家的编码收录到一个字符集中。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="utf-8-编码">utf-8 编码<a href="#utf-8-编码" class="hash-link" aria-label="Direct link to utf-8 编码" title="Direct link to utf-8 编码">​</a></h2><p>虽然 unicode 可以解决乱码问题，但并不优雅。因为它存在一个这样的问题：<br>
<!-- -->中英混合时，一个中文可能需要占据两个字节，这个时候为了正确编码，原本只需要占据一个字节的英文，不得不占据两个字节。<br>
<!-- -->从而造成了资源浪费。</p><p>为了解决这个缺陷，基于 unicode 编码又推出了可变长编码 utf-8</p><p>即 utf-8 会根据实际类型选择最佳的字节占位，从而节省空间。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="计算机通用编码方式">计算机通用编码方式<a href="#计算机通用编码方式" class="hash-link" aria-label="Direct link to 计算机通用编码方式" title="Direct link to 计算机通用编码方式">​</a></h2><p>搞清楚了 ascii、unicode、utf-8 编码，我们梳理下计算机通用的编码方式：<br>
<!-- -->1、在计算机内存中，统一使用 unicode 编码<br>
<!-- -->2、当需要保存到硬盘或者传输的时候，转化为 utf-8 编码   </p><p>以我们的 txt 文本为例：<br>
<!-- -->1、打开文本：数据以 unicode 编码，以便展示内容。<br>
<!-- -->2、保存文本：数据以 utf-8 编码，以便节约空间。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>常用字符 ascii 码</div><div class="admonitionContent_S0QG"><p>0-9：48 ~ 57<br>
<!-- -->A-Z：65 ~ 90<br>
<!-- -->a-z：97 ~ 122    </p></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="计算机基础" term="计算机基础"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[gRPC 负载均衡]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/13/gRPC负载均衡</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/13/gRPC负载均衡"/>
        <updated>2021-12-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文主要介绍在 k8s 环境下 gRPC 服务在实现负载均衡时遇到的问题和解决思路。]]></summary>
        <content type="html"><![CDATA[<p>本文主要介绍在 k8s 环境下 gRPC 服务在实现负载均衡时遇到的问题和解决思路。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="概述">概述<a href="#概述" class="hash-link" aria-label="Direct link to 概述" title="Direct link to 概述">​</a></h2><p>我们的 gRPC 应用最初使用 <code>DaemonSet</code> 类型的资源对象部署在 k8s 上。通过标签配置，使得单台 Node 节点仅部署一个 pod 应用。
而 gRPC 应用则通过 <code>NodePort Service</code> 的方式对外暴露服务。</p><p>在这种场景下直接对外暴露固定 IP 提供服务，业务流量全部打到单台宿主机上，所以也不存在负载均衡的说法。</p><p>随着业务压力逐渐增大，单点提供的能力已逐渐达到极限，我们采用水平拓展的方式，部署了多台单节点服务。也算暂时抗住了压力。但随后的暴露的问题，也让我们被迫选择了重构。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>为什么选择重构</div><div class="admonitionContent_S0QG"><p>业务持续拓展，引入多节点的问题也逐渐暴露出来，当前服务架构下，多节点之间的数据一致性完全不能保证，人工运维简直不要太恶心，无奈只能重构。这里我们不针对此展开。  </p></div></div><p>服务改造升级完毕后，完全兼容历史 gRPC 接口，在 k8s 的配置上也有部分改动，以前的 <code>DaemontSet</code> 资源变更为 <code>Deployment</code> 资源，而 <code>NodePort Service</code> 资源则变更为 <code>ClusterIP Service</code> 资源。<br>
<!-- -->项目正式进入到了提测阶段。</p><p>功能上基本没有太大的问题，毕竟引用了相同的 gRPC 接口文件。</p><p>问题主要出现在了负载均衡上，在多副本的场景下，发生了严重的流量倾斜，具体表现就是某个副本的压力非常高，而其他副本的压力很小，进而导致服务整体异常。</p><div class="theme-admonition theme-admonition-tip alert alert--success admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>简单分析</div><div class="admonitionContent_S0QG"><p>gRPC 是基于 HTTP2.0 实现的长连接，且默认没有超时，这种长连接能够大量减少 TCP 连接管理所带来的开销，但也破坏了标准的连接级的负载均衡。因为连接已经建立且不断开，所以也无法再进一步负载均衡了。  </p><p>那么再回到上述场景，显然就是客户端与某个具体的服务建立了长连接，而连接又不会断开，从而导致了持续的流量倾斜问题。</p></div></div><p>选择有效的 gRPC 负载均衡方案，是解决我们当前问题的核心。</p><p>具体解决的方法有多种，我们主要将其分为：  </p><ul><li>用户侧的负载均衡</li><li>服务侧的负载均衡</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="grpc-负载均衡---用户侧">gRPC 负载均衡 - 用户侧<a href="#grpc-负载均衡---用户侧" class="hash-link" aria-label="Direct link to gRPC 负载均衡 - 用户侧" title="Direct link to gRPC 负载均衡 - 用户侧">​</a></h2><p>用户侧的 gRPC 负载均衡，是通过 DNS，使用户解析出全部的 gRPC 服务地址，然后用户自己实现负载策略。
最简单的策略就是与每个服务建立 gRPC 连接，然后轮询访问，实现 rr 负载。</p><p><img loading="lazy" src="/docusaurus/assets/images/client-load-balancer-1a9f6252b1ac5acc0894bbbcf73094f8.png" width="563" height="316" class="img_ev3q"></p><p>该方案实施起来比较容易，但对于用户侧有一定的要求。如：</p><ul><li>安全方面，要考虑用户的可靠性。</li><li>更新策略，解析 DNS 虽有现成的方案，但是常规方案一般无法探知到后续新创建的服务，所以需要设计更新策略。</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="grpc-负载均衡---服务侧">gRPC 负载均衡 - 服务侧<a href="#grpc-负载均衡---服务侧" class="hash-link" aria-label="Direct link to gRPC 负载均衡 - 服务侧" title="Direct link to gRPC 负载均衡 - 服务侧">​</a></h2><p>服务侧的 gRPC 负载均衡，需要引入一个负载均衡代理，我们称之为 <code>Load Balancer</code>，
用户向 LB 发起 RPC 请求，然后由该 LB 将 RPC 分配到一个可用的后端服务器上，
由该服务器提供 gRPC 服务，并将负载情况报告给 LB，进一步补全 LB 的负载信息。
<img loading="lazy" src="/docusaurus/assets/images/server-load-balancer-6f95677aa715fccbc4fff53fb1fb59ea.png" width="574" height="351" class="img_ev3q"></p><p>在该方案中，负载均衡由 LB 统一管理，有一定的实施难度。<br>
<!-- -->除非能找到高 star 的开源项目，不然开发与运维就是一笔不小的投入。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="方案选择">方案选择<a href="#方案选择" class="hash-link" aria-label="Direct link to 方案选择" title="Direct link to 方案选择">​</a></h2><p>考虑到实施难度，我们选择了用户侧的负载均衡方式。</p><p><strong>首先要解决 DNS 的解析与负载</strong>，这一块，官方已经封装了 gRPC SDK，用户可以通过简单升级 SDK 即可实现该功能。</p><p><strong>其次就是服务发现这一块了</strong>。解决的方案也有两种：<br>
<!-- -->1、服务端实现：MaxConnectionAge。定期断开连接，从而触发客户端重解析。<br>
<!-- -->2、客户端实现：KubeResolver。客户端接入 k8s api 从而实现服务发现。   </p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>MaxConnectionAge</div><div class="admonitionContent_S0QG"><p>MaxConnectionAge 是 gRPC 服务端的参数，用于指定长连接最大保持时间。<br>
<!-- -->配置该参数会使得长连接变成“短”连接，故性能会有一定的降低。</p><p>该方案的原理是，通过定期释放连接，使得客户端重新解析 DNS 获取最新的服务地址。</p></div></div><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>KubeResolver</div><div class="admonitionContent_S0QG"><p>该方案的原理是通过监听 k8s 的 api 资源状态，实时获取 gRPC 服务资源信息，从而实现检测更新。</p></div></div><p>综合考虑后，最终选择了 MaxConnectionAge 方案，因为此方案仅仅通过适配参数就可以完成预期功能，虽然略显僵硬，但实际上效果还不错。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="grpc" term="grpc"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[gRPC 原理及使用]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/12/gRPC原理</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/12/gRPC原理"/>
        <updated>2021-12-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[<!--]]></summary>
        <content type="html"><![CDATA[<p>gRPC 是一个高性能、跨平台的开源 RPC 框架。</p><p>由 Google 开源，支持多种编程语言。它使用 Protocol Buffers 作为接口定义语言，可以生成客户端和服务端的代码，
使得跨语言、跨平台的服务调用变得更加简单和高效。</p><p>gRPC 是一个<strong>基于HTTP2、支持<code>protocol buffers</code>序列化机制、支持多语言的、高性能的、面向服务端和移动端</strong>的高级RPC框架。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="在-go-中使用-grpc">在 Go 中使用 gRPC<a href="#在-go-中使用-grpc" class="hash-link" aria-label="Direct link to 在 Go 中使用 gRPC" title="Direct link to 在 Go 中使用 gRPC">​</a></h2><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1安装-grpc-库">1、安装 gRPC 库<a href="#1安装-grpc-库" class="hash-link" aria-label="Direct link to 1、安装 gRPC 库" title="Direct link to 1、安装 gRPC 库">​</a></h3><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">go get -u google.golang.org/grpc</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2定义-protobuf-文件">2、定义 protobuf 文件<a href="#2定义-protobuf-文件" class="hash-link" aria-label="Direct link to 2、定义 protobuf 文件" title="Direct link to 2、定义 protobuf 文件">​</a></h3><p>gRPC 使用 protobuf 来定义服务和消息的格式，因此需要先定义protobuf文件。
可以使用 protobuf3 语法，定义服务的方法和请求/响应消息的结构。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">syntax </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"proto3"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">package greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">service</span><span class="token plain"> Greeter </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  rpc SayHello </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">HelloRequest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> returns </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">HelloReply</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">message HelloRequest </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  string name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">message HelloReply </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  string message </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3生成代码">3、生成代码<a href="#3生成代码" class="hash-link" aria-label="Direct link to 3、生成代码" title="Direct link to 3、生成代码">​</a></h3><p>基于上述 protobuf 文件生成Go代码，可以使用 protoc 和 protoc-gen-go 插件来生成。</p><p>安装protoc和protoc-gen-go：</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token comment" style="color:rgb(106, 153, 85)"># 安装protoc</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">brew </span><span class="token function" style="color:rgb(220, 220, 170)">install</span><span class="token plain"> protobuf</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token comment" style="color:rgb(106, 153, 85)"># 安装protoc-gen-go</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">go get -u github.com/golang/protobuf/protoc-gen-go</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>生成Go代码：</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">protoc --go_out</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">plugins</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">grpc:. *.proto</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="4启动服务">4、启动服务<a href="#4启动服务" class="hash-link" aria-label="Direct link to 4、启动服务" title="Direct link to 4、启动服务">​</a></h3><p>实现定义的服务接口，实现具体的服务逻辑。</p><p>例如，实现SayHello方法：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">type</span><span class="token plain"> server </span><span class="token keyword" style="color:rgb(86, 156, 214)">struct</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">s </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">server</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">SayHello</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">ctx context</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Context</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> req </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">HelloRequest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain">greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">HelloReply</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">error</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    message </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Sprintf</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Hello, %s!"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> req</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">HelloReply</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain">Message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token boolean">nil</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>接着使用gRPC库提供的方法，启动服务并监听端口。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">s </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> grpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">NewServer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">RegisterGreeterServer</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">server</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> s</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Serve</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">lis</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> </span><span class="token boolean">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    log</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Fatalf</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"failed to serve: %v"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="5客户端调用">5、客户端调用<a href="#5客户端调用" class="hash-link" aria-label="Direct link to 5、客户端调用" title="Direct link to 5、客户端调用">​</a></h3><p>使用gRPC提供的客户端代码，调用定义的服务。</p><p>例如，调用SayHello方法：</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">conn</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> grpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Dial</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"localhost:50051"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> grpc</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">WithInsecure</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> </span><span class="token boolean">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    log</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Fatalf</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"did not connect: %v"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">defer</span><span class="token plain"> conn</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Close</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">c </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">NewGreeterClient</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">conn</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">resp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> c</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">SayHello</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">context</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Background</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">&amp;</span><span class="token plain">greeter</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">HelloRequest</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain">Name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"world"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">if</span><span class="token plain"> err </span><span class="token operator" style="color:rgb(212, 212, 212)">!=</span><span class="token plain"> </span><span class="token boolean">nil</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    log</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Fatalf</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"could not greet: %v"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> err</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">log</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Printf</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"Greeting: %s"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> resp</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token plain">Message</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="protocol-buffers">Protocol Buffers<a href="#protocol-buffers" class="hash-link" aria-label="Direct link to Protocol Buffers" title="Direct link to Protocol Buffers">​</a></h2><p>Protocol Buffers (protobuf) 是一种高效、灵活、跨平台的序列化机制。<br>
<!-- -->它能够将结构化数据序列化成紧凑的二进制格式，以便在不同应用程序之间进行数据交换和存储。</p><p>其设计原理主要有：</p><ul><li>二进制编码：protobuf 使用二进制编码，而不是文本编码，可以大大减小序列化后数据的大小。相比于 JSON 或 XML 等文本格式，protobuf 可以将数据压缩至原来的 1/3 到 1/10。</li><li>代码生成：protobuf 可以根据定义在 .proto 文件中的消息结构，自动生成对应的编解码代码，从而提高编解码的效率。生成的代码通常是直接使用底层的二进制序列化和反序列化函数，而不需要额外的解析或转换。</li><li>紧凑的消息格式：protobuf 的消息格式非常紧凑，消息中的每个字段都有一个固定的编码方式，编码后的数据长度非常短。同时，protobuf 中的消息格式是二进制的，每个字段的类型和长度都是固定的，所以在解码时，可以直接从二进制数据中读取每个字段的值，而不需要进行类型检查和解析。</li><li>可扩展的消息格式：protobuf 支持向后和向前兼容的消息格式，并支持在不破坏现有消息的前提下，向现有消息添加新的字段或删除旧的字段。这使得应用程序可以逐步升级其消息格式，而无需重写和重新编译现有的代码。</li></ul><p>这些设计原则使得 protobuf 具有非常快的编解码速度和高效的数据压缩率，因为它们充分利用了底层的二进制编码和紧凑的消息格式。
相比于 JSON 或 XML 等文本格式，protobuf 在序列化和反序列化时的效率通常要高出数倍甚至数十倍，</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="proto-file">proto file<a href="#proto-file" class="hash-link" aria-label="Direct link to proto file" title="Direct link to proto file">​</a></h2><p>接下来主要介绍下一个完整 proto 文件的组成：</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1语法指令">1、语法指令<a href="#1语法指令" class="hash-link" aria-label="Direct link to 1、语法指令" title="Direct link to 1、语法指令">​</a></h3><p>使用 syntax 关键字指定 protobuf 使用的语法版本，目前最新版本为 proto3。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">syntax </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"proto3"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2package">2、package<a href="#2package" class="hash-link" aria-label="Direct link to 2、package" title="Direct link to 2、package">​</a></h3><p>使用 package 关键字指定 protobuf 文件所属的包名。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">package example</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3message">3、message<a href="#3message" class="hash-link" aria-label="Direct link to 3、message" title="Direct link to 3、message">​</a></h3><p>使用 message 关键字定义一个消息类型，包含一组字段定义，每个字段由类型和字段名称组成。
1字段名称和字段类型之间用等号 = 分隔，字段编号和字段名称之间用空格分隔，每个字段定义结束后需要以分号 ; 结尾。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">message Person </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  string name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  int32 age </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  repeated string email </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>其中，string、int32 等为 protobuf 内置类型，还可以自定义类型。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="4字段规则">4、字段规则<a href="#4字段规则" class="hash-link" aria-label="Direct link to 4、字段规则" title="Direct link to 4、字段规则">​</a></h3><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="optional-规则">optional 规则<a href="#optional-规则" class="hash-link" aria-label="Direct link to optional 规则" title="Direct link to optional 规则">​</a></h4><p>使用可选规则的字段可以有零个或一个值。如果不设置该字段，它将不会在序列化后的数据中出现。
如果你的应用程序接收到一个缺少可选字段的消息，它可以使用默认值来代替缺失的数据。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">message OptionalExample </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  optional int32 </span><span class="token function" style="color:rgb(220, 220, 170)">id</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="required-规则">required 规则<a href="#required-规则" class="hash-link" aria-label="Direct link to required 规则" title="Direct link to required 规则">​</a></h4><p>使用必选规则的字段必须设置一个值，否则序列化时将报错。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">message RequiredExample </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  required string name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="repeated-规则">repeated 规则<a href="#repeated-规则" class="hash-link" aria-label="Direct link to repeated 规则" title="Direct link to repeated 规则">​</a></h4><p>使用重复规则的字段可以有零个或多个值，序列化后会生成一个列表。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">message RepeatedExample </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  repeated string tags </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="5字段类型">5、字段类型<a href="#5字段类型" class="hash-link" aria-label="Direct link to 5、字段类型" title="Direct link to 5、字段类型">​</a></h3><p>protobuf 内置类型包括：double、float、int32、int64、uint32、uint64、sint32、sint64、fixed32、fixed64、sfixed32、sfixed64、bool、string、bytes。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">message Example </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  double price </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  int32 quantity </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  string name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  bytes image </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="6字段编号">6、字段编号<a href="#6字段编号" class="hash-link" aria-label="Direct link to 6、字段编号" title="Direct link to 6、字段编号">​</a></h3><p>每个字段必须有一个唯一的编号，编号用于在消息中标识每个字段。编号必须是一个正整数。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">message Person </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  string name </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  int32 age </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  repeated string email </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>在上面的例子中，name 字段的编号是1，age 字段的编号是2，email 字段的编号是3。</p><p>字段编号的作用是在消息编码和解码时，用于标识每个字段的位置和类型。<br>
<!-- -->在消息编码时，每个字段都被分配一个唯一的标识号，用于在序列化后的二进制数据中标识该字段。<br>
<!-- -->在消息解码时，根据这些编号可以将二进制数据转换为消息对象，以及从消息对象中提取相应的字段数据。</p><p>在.proto文件中，字段编号的分配必须遵循以下规则：</p><p>同一个消息类型中，每个字段的编号必须唯一，不能重复。<br>
<!-- -->字段编号必须是一个正整数，且必须按照从小到大的顺序分配。<br>
<!-- -->字段编号不能超过2^29-1，因为其它位已经被用于类型和标记。<br>
<!-- -->需要注意的是，一旦定义了字段编号，就应该避免在.proto文件中对它进行修改，否则可能会导致已经编码的消息与代码不匹配，从而出现严重的错误。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="gRPC" term="gRPC"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[关于副业的一些思考]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/10/关于副业的一些思考</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/10/关于副业的一些思考"/>
        <updated>2021-12-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[所谓副业，本质上就是打多份工...]]></summary>
        <content type="html"><![CDATA[<p>所谓副业，本质上就是打多份工...</p><p>一定要和打工区别开来的话，可能就是我们如今所说的副业，更多的带上了对人生规划的一些思考。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="知道想做什么">知道想做什么<a href="#知道想做什么" class="hash-link" aria-label="Direct link to 知道想做什么" title="Direct link to 知道想做什么">​</a></h2><p>知道自己想做什么，永远是第一步。</p><p>我们常常听到别人高谈自己的"规划"，其实"规划"并不神秘。<br>
<!-- -->你可以把他理解为一些简单的想法，或者说是对未来的一些想法，他们可以是想做的事，也可以是想去的地方...   </p><p>但事实是很多人不知道想做什么。<br>
<!-- -->我们的第一份工作，往往和我们第一学历专业挂钩。<br>
<!-- -->而大学毕业后，毕业生真正知道自己应该干什么的，其实寥寥无几。甚至可能工作两三年后才突然醒悟应该转投其他行业。</p><p>比如我本人是工程管理学专业，但我毕业后就投入到了互联网行业，因为我知道我不喜欢进工厂，相反我很喜欢计算机编程。<br>
<!-- -->而我的大部分同学，毕业两三年后也陆陆续续的转行...</p><p>所以，我觉得很重要的一点，就是要想清楚自己现阶段到底需要做什么。<br>
<!-- -->你需要去尝试做一个决定，这也许这不是一个长期的决定，但是它应该是现阶段你能够稳定投入精力的一个决定。</p><p>这个时候，也不需要考虑什么主业副业，能做好一件就已经很了不起了。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="为什么需要副业">为什么需要副业<a href="#为什么需要副业" class="hash-link" aria-label="Direct link to 为什么需要副业" title="Direct link to 为什么需要副业">​</a></h2><p>那为什么现在又有这么多人选择副业呢？</p><p>以我自己的情况来说，毫无疑问，是典型的属于需要依靠打工来维持生计的群体。个人睡后收入纯靠银行利息，工作的本质是为了混口饭吃。<br>
<!-- -->当然我没有副业，因为互联网并不算特别轻松，我个人时间也并不是很充裕，很难花时间去打第二份工。
况且互联网收入相对来说是可以的。   </p><p>然而，这一切在我买房之后就改变了...<br>
<!-- -->试想，当你的一半甚至一大半收入，全部用于还贷了，还得还三十年，一股有形的压力瞬间压得人喘不过气来。  </p><p>所以并不是我很闲，闲的要去找一份副业来充实自己，而是我很需要第二份收入来充实自己...<br>
<!-- -->现在社会大环境又不好，工资过万，你可以打败全国一半以上的打工群体，但在一二线城市的房价物价面前，就是个屁。</p><p>所以，我想到的能坚持发展副业的人群：<br>
<strong>1、</strong>入不敷出。<br>
<strong>2、</strong>闲不下来。<br>
<strong>3、</strong>个人爱好。    </p><p>大部分人应该是属于第一类吧... 但整体来看，我觉得时间和精力才是最终落地执行的决定因素。<br>
<!-- -->因为过于透支自己的生命换来的财富，将是一笔无法偿还的高利贷。  </p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="认知自己的工作阶段">认知自己的工作阶段<a href="#认知自己的工作阶段" class="hash-link" aria-label="Direct link to 认知自己的工作阶段" title="Direct link to 认知自己的工作阶段">​</a></h2><p>当你有发展副业的想法时，我还是建议先梳理下你自己当前的工作情况，对于一份稳定的工作，应该大致朝着这个阶段方向发展：  </p><ul><li><strong>积累阶段</strong></li></ul><p>一般指一些刚入行的同学，在这个阶段他们需要去积累一些工作经验。</p><p>处于这个阶段时，会有一些比较明显的特点。<br>
<!-- -->比如你的简历上面，可能需要编造大量技能和项目经验，以便通过 HR 的筛选。
一旦面试被人追着问细节时，就会暴露。</p><ul><li><strong>瓶颈阶段</strong></li></ul><p>一般指在某个领域有足够的经验。</p><p>处于这个阶段，你可能不在需要投递简历就能很轻松的找到一份工作。
如果工作不开心，你也很自信可以很快找到另一份工作，虽然找的不一定更好，但不用担心失业问题。</p><ul><li><strong>溢出阶段</strong></li></ul><p>一般指在某个领域有足够经验，在公司也处于中高层。</p><p>你可以很轻松的获取工作之外的报酬，比如公司分红等。</p><p>不是所有的工作都符合这三个阶段，但也可以大致比照着看看自己应该处于什么阶段，对于处于第一阶段的同学，我建议还是先投入精力处理好自己的工作，在考虑发展其他副业。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="关于副业的思考---给自己">关于副业的思考 - 给自己<a href="#关于副业的思考---给自己" class="hash-link" aria-label="Direct link to 关于副业的思考 - 给自己" title="Direct link to 关于副业的思考 - 给自己">​</a></h2><blockquote><p>不能盲目跟风！</p></blockquote><p>不管这句话适不适用于所有领域，但它一直都是我长期以来坚信的。虽然我很眼热能发展副业的同学们，但比起盲目发展副业，我觉得我应该先认清自己的情况。</p><p>首先有很多发展副业的人都是事业编制，他们相对来说个人时间比较充裕。<br>
<!-- -->而互联网，是一个新兴技术频繁更替的行业，也是加班严重的行业之一，我时常也感觉自己个人时间不是很充裕。</p><p>其次，有部分牛人达到了工作的 <strong>瓶颈阶段</strong> 甚至是 <strong>溢出阶段</strong>，他们有能力、有资源去执行副业计划。<br>
<!-- -->而我，菜鸟一个，短时间内是很难雄起了...</p><p>这样一看，我是完全不适合发展副业的了...</p><p>基于这种背景，给自己一些建议：<br>
<!-- -->1、<strong>多整理并总结自己的笔记。</strong><br>
<!-- -->2、<strong>整理文档时，优化下自己的文笔，不要乱糟糟了事，而应该尝试给别人讲述清楚。</strong>      </p><p>说到底，短期还是只能提升软实力了。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="个人" term="个人"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Github 搭建 Docusaurus 站点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/12/03/Github搭建Docusaurus站点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/12/03/Github搭建Docusaurus站点"/>
        <updated>2021-12-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[本文章记录基于 Docusaurus 搭建静态站点，并通过 Github-Actions 实现自动部署。]]></summary>
        <content type="html"><![CDATA[<p>本文章记录基于 Docusaurus 搭建静态站点，并通过 Github-Actions 实现自动部署。</p><p>再整个自动化部署的过程中，最核心的步骤就是初始化并配置公钥、密钥、workflow.yml。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="1新建-github-仓库">1、新建 Github 仓库<a href="#1新建-github-仓库" class="hash-link" aria-label="Direct link to 1、新建 Github 仓库" title="Direct link to 1、新建 Github 仓库">​</a></h2><p>首先，登录<a href="https://github.com/new" target="_blank" rel="noopener noreferrer">Github仓库创建页面</a>，我们创建一个全新的空白仓库，项目名命名为 <code>testDocusaurus</code>。</p><p>然后通过 <code>git</code> 将仓库拉取到本地，至此，我们拥有了一个全新的空白仓库 <code>testDocusaurus</code>。  </p><p><img loading="lazy" src="/docusaurus/assets/images/gitindex-c952d0d7107b2ebfbd532628604eee58.png" width="1966" height="445" class="img_ev3q"></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="2初始化-docusaurus-项目">2、初始化 Docusaurus 项目<a href="#2初始化-docusaurus-项目" class="hash-link" aria-label="Direct link to 2、初始化 Docusaurus 项目" title="Direct link to 2、初始化 Docusaurus 项目">​</a></h2><blockquote><p><a href="https://docusaurus.io/zh-CN/docs/installation" target="_blank" rel="noopener noreferrer">Docusaurus项目初始化细节请参考官方文档</a></p></blockquote><p>进入到仓库 <code>testDocusaurus</code> 所在的空白目录，并在此目录打开终端界面。</p><p>为了更好的完成接下来的步骤，你可能需要预先安装<strong>nodejs</strong>。在此，假设你已经准备完毕。<br>
<!-- -->那我们接下来通过以下指令初始化一个 <code>Docusaurus</code> 项目。</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token operator" style="color:rgb(212, 212, 212)">&gt;&gt;</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> npx create-docusaurus@latest website classic</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Successfully created </span><span class="token string" style="color:rgb(206, 145, 120)">"website"</span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Inside that directory, you can run several commands:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">npm</span><span class="token plain"> start</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Starts the development server.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">npm</span><span class="token plain"> run build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Bundles your website into static files </span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> production.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">npm</span><span class="token plain"> run serve</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Serves the built website locally.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">npm</span><span class="token plain"> deploy</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    Publishes the website to GitHub pages.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">We recommend that you begin by typing:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">cd</span><span class="token plain"> website</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token function" style="color:rgb(220, 220, 170)">npm</span><span class="token plain"> start</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">Happy building awesome websites</span><span class="token operator" style="color:rgb(212, 212, 212)">!</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>该指令运行完后，会输出一些简单的运行指令，而且我们应该可以看到一个 <code>website</code> 的目录，我们先将里面的内容剪贴出来，放到我们空白仓库目录下面。</p><p>此时，我们按照提示，运行 <code>npm start</code> 指令，我们就可以运行此项目。</p><p>通常启动端口为3000，则默认路径为：http://localhost:3000/  </p><p><img loading="lazy" src="/docusaurus/assets/images/websiteindex-6029690b1e9d474cabb01a20b2fbb77f.png" width="2099" height="542" class="img_ev3q"></p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="3搭建-github-actions">3、搭建 Github Actions<a href="#3搭建-github-actions" class="hash-link" aria-label="Direct link to 3、搭建 Github Actions" title="Direct link to 3、搭建 Github Actions">​</a></h2><blockquote><p>Github Actions部署细节参考<a href="https://docusaurus.io/zh-CN/docs/deployment#deploying-to-github-pages" target="_blank" rel="noopener noreferrer">官方文档</a></p></blockquote><p>接入 <code>Github Actions</code> 需要创建一对新的 <strong>SSH Key</strong>，并将公钥和密钥均配置到 Github，我们来具体看下操作。</p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="创建公钥密钥对">创建公钥密钥对<a href="#创建公钥密钥对" class="hash-link" aria-label="Direct link to 创建公钥密钥对" title="Direct link to 创建公钥密钥对">​</a></h3><p>首先通过<code>ssh-keygen</code>指令创建公钥密钥对，通过改指令，我们可以获取到公钥（id_rsa.pub）和私钥（id_rsa）</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token operator" style="color:rgb(212, 212, 212)">&gt;&gt;</span><span class="token operator" style="color:rgb(212, 212, 212)">&gt;</span><span class="token plain"> ssh-keygen -t rsa -C </span><span class="token string" style="color:rgb(206, 145, 120)">"email"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">The key's randomart image is:</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+---</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">RSA </span><span class="token number" style="color:rgb(181, 206, 168)">3072</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">----+</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> .</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">oo*</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">o</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">o.      </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> o+.</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">o</span><span class="token operator" style="color:rgb(212, 212, 212)">==</span><span class="token plain">.o       </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain">  .O.O</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">+o        </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain">  </span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain">o@.oo       </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain"> o +.+S+</span><span class="token punctuation" style="color:rgb(212, 212, 212)">..</span><span class="token plain">     </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain">  </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain"> + </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain"> E.o      </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain">   o </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain"> </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain">         </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain">  </span><span class="token builtin class-name" style="color:rgb(78, 201, 176)">.</span><span class="token plain">              </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain">                 </span><span class="token operator" style="color:rgb(212, 212, 212)">|</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">+----</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain">SHA256</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain">-----+</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="配置公钥密钥">配置公钥密钥<a href="#配置公钥密钥" class="hash-link" aria-label="Direct link to 配置公钥密钥" title="Direct link to 配置公钥密钥">​</a></h3><p>我们打开仓库的 <code>deploy keys</code>，选择新增，其中，title 命名为 <code>GH_PAGES_DEPLOY</code>，
内容则是公钥 <code>id_rsa.pub</code> 中的内容，记住选中 <code>Allow write access</code> 框，表示赋予部署写权限。
<img loading="lazy" src="/docusaurus/assets/images/deploykey-bb9a209de52bea9c40a3707c687d4bec.png" width="2160" height="1262" class="img_ev3q"></p><p>此时部署公钥已经完成，接着我们再将私钥也配置上。打开同级配置下的 Secret，选择新增仓库密钥，
同样，Name 命名为 <code>GH_PAGES_DEPLOY</code>，内容则是密钥 <code>id_rsa</code> 中的内容。
<img loading="lazy" src="/docusaurus/assets/images/deploykey1-58ac42d864933e6d750c826f89dba6ff.png" width="2160" height="1262" class="img_ev3q"></p><h3 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="workflow配置">workflow配置<a href="#workflow配置" class="hash-link" aria-label="Direct link to workflow配置" title="Direct link to workflow配置">​</a></h3><p>最后，我们创建 <code>Github Actions</code>，将模板复制进去，则整个流水线就已经配置好了。模板参考如下：</p><div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Node.js CI</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">push</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">branches</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> main </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">pull_request</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">branches</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token plain"> main </span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token key atrule">jobs</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">checks</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/setup</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">node@v1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">node-version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'18.x'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Test Build</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          if [ -e yarn.lock ]; then</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            yarn install --frozen-lockfile</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          elif [ -e package-lock.json ]; then</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            npm ci</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          else</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            npm i</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          fi</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          npm run build</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">  </span><span class="token key atrule">gh-release</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">runs-on</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> ubuntu</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">latest</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token key atrule">steps</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/checkout@v1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> actions/setup</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">node@v1</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">node-version</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'18.x'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">uses</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> webfactory/ssh</span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain">agent@v0.5.0</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">with</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">ssh-private-key</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> $</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"> secrets.GH_PAGES_DEPLOY </span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">      </span><span class="token punctuation" style="color:rgb(212, 212, 212)">-</span><span class="token plain"> </span><span class="token key atrule">name</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> Release to GitHub Pages</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">env</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">USE_SSH</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token boolean important">true</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">          </span><span class="token key atrule">GIT_USER</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> czasg</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token key atrule">run</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">|</span><span class="token scalar string" style="color:rgb(206, 145, 120)"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          git config --global user.email "your email"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          git config --global user.name "you name"</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          if [ -e yarn.lock ]; then</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            yarn install --frozen-lockfile</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          elif [ -e package-lock.json ]; then</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            npm ci</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          else</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">            npm i</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          fi</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token scalar string" style="color:rgb(206, 145, 120)">          npm run deploy</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>复制模板时，对应的 git 配置记得修改下，如下：</p><div class="language-shell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-shell codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> config --global user.email </span><span class="token string" style="color:rgb(206, 145, 120)">"注册公钥使用到的邮箱"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token function" style="color:rgb(220, 220, 170)">git</span><span class="token plain"> config --global user.name </span><span class="token string" style="color:rgb(206, 145, 120)">"github用户名"</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="4更新仓库尝试自动部署">4、更新仓库，尝试自动部署<a href="#4更新仓库尝试自动部署" class="hash-link" aria-label="Direct link to 4、更新仓库，尝试自动部署" title="Direct link to 4、更新仓库，尝试自动部署">​</a></h2><p>确保 Github Pages 已经初始化好，那么我们往仓库推送修改时，就可以触发自动部署了。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="docusaurus" term="docusaurus"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[关于协程的一些理解]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/11/27/关于协程的一些理解</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/11/27/关于协程的一些理解"/>
        <updated>2021-11-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[以下场景均以单核 cpu 为例。]]></summary>
        <content type="html"><![CDATA[<p>以下场景均以单核 cpu 为例。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="并发">并发<a href="#并发" class="hash-link" aria-label="Direct link to 并发" title="Direct link to 并发">​</a></h4><p>逻辑上同时处理任务的能力。</p><p>cpu 在短时间内来回执行多个任务，使得这些任务看上去是同一时间进行的。<br>
<!-- -->这种宏观意义上是同时执行，微观上仍然是顺序执行的，我们称之为并发。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="并行">并行<a href="#并行" class="hash-link" aria-label="Direct link to 并行" title="Direct link to 并行">​</a></h4><p>物理上同一时刻处理不同任务。</p><p>当系统存在多核 cpu，使得任务可以同一时刻执行，称之为并行。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="进程">进程<a href="#进程" class="hash-link" aria-label="Direct link to 进程" title="Direct link to 进程">​</a></h4><p>进程是计算机资源分配的基本单位。  </p><p>因为 cpu 在多任务之间切换时，如果不正确保存上一个任务的上下文状态，那么下次执行时就会丢失这个任务的执行信息。<br>
<!-- -->进程就是用来定义任务及其资源边界。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="线程">线程<a href="#线程" class="hash-link" aria-label="Direct link to 线程" title="Direct link to 线程">​</a></h4><p>线程是 cpu 调度的基本单位。</p><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="协程">协程<a href="#协程" class="hash-link" aria-label="Direct link to 协程" title="Direct link to 协程">​</a></h4><p>协程是用户态的轻量级线程。</p><p>协程拥有以下特点：<br>
<!-- -->1、调度由用户控制。即在用户态而非内核态完成协程间的调度。
2、更轻量。创建一个协程仅需要很小的空间。<br>
<!-- -->3、协程拥有自己的寄存器上下文和栈空间。   </p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍</p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="计算机基础" term="计算机基础"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang interface 坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/11/20/golang-interface坑点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/11/20/golang-interface坑点"/>
        <updated>2021-11-20T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[坑点：interface == nil]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="坑点interface--nil">坑点：interface == nil<a href="#坑点interface--nil" class="hash-link" aria-label="Direct link to 坑点：interface == nil" title="Direct link to 坑点：interface == nil">​</a></h2><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">var</span><span class="token plain"> v </span><span class="token keyword" style="color:rgb(86, 156, 214)">interface</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">v </span><span class="token operator" style="color:rgb(212, 212, 212)">==</span><span class="token plain"> </span><span class="token boolean">nil</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">v </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token boolean">nil</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">v </span><span class="token operator" style="color:rgb(212, 212, 212)">==</span><span class="token plain"> </span><span class="token boolean">nil</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这是一段简单的代码，我们来看下它的输出结果：  </p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">true</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">false</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这是一个坑点，在 code 过程中，我们常常认为 interface 被赋值了一个空值 nil，再做判断时，可以直接和 nil 做对比。<br>
<!-- -->显然这是错误的，这样会得到与我们预期不符的结果。 </p><p>这是因为 interface 并不是一个指针类型，而是一个特殊的结构体，内部包含了两类数据结构：<strong>类型</strong> 和 <strong>值</strong>。<br>
<!-- -->所以在上面的判断中，需要类型和值都为 nil 的是否才会判断正确。<br>
<!-- -->一旦对 interface 赋予了某个类型或者值，即便是空值，当再次进行判断时，也会出现令人困惑的场景。   </p><p>针对这种场景，一般正确的方式是调用 reflect 反射包进行判断。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang 切片坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/11/19/golang切片坑点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/11/19/golang切片坑点"/>
        <updated>2021-11-19T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[切片是 golang 中的一种特殊结构，由指向数组首位的指针、长度、容量组成。]]></summary>
        <content type="html"><![CDATA[<p>切片是 golang 中的一种特殊结构，由指向数组首位的指针、长度、容量组成。</p><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="坑点切片之间可以相互影响">坑点：切片之间可以相互影响<a href="#坑点切片之间可以相互影响" class="hash-link" aria-label="Direct link to 坑点：切片之间可以相互影响" title="Direct link to 坑点：切片之间可以相互影响">​</a></h2><p>切片底层使用了数组结构，再没有触发扩容机制前，多切片之间是可能相互影响的。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">package</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"fmt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    base </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token builtin" style="color:rgb(86, 156, 214)">int</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">3</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">4</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">5</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    base01 </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> base</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    base02 </span><span class="token operator" style="color:rgb(212, 212, 212)">:=</span><span class="token plain"> base</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token number" style="color:rgb(181, 206, 168)">2</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">base01</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> base02</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    base01</span><span class="token punctuation" style="color:rgb(212, 212, 212)">[</span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">]</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">11</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">base01</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> base02</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>此时修改 base01 的值，会直接影响 base02 的值。  </p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">输出结果</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">[11]</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">[11 2]</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这是因为他们此时公用的底层数组。</p><div class="theme-admonition theme-admonition-note alert alert--secondary admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>扩容机制</div><div class="admonitionContent_S0QG"><div class="language-goalng codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">src/runtime/slice.go</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-goalng codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">func growslice(et *_type, old slice, cap int) slice {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    newcap := old.cap</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    doublecap := newcap + newcap</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    if cap &gt; doublecap {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        newcap = cap</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    } else {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        if old.len &lt; 1024 {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            newcap = doublecap</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        } else {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            // Check 0 &lt; newcap to detect overflow</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            // and prevent an infinite loop.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            for 0 &lt; newcap &amp;&amp; newcap &lt; cap {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">                newcap += newcap / 4</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            // Set newcap to the requested cap when</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            // the newcap calculation overflowed.</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            if newcap &lt;= 0 {</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">                newcap = cap</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">            }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    }</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    ...</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>看源码可以看到，当切片长度小于 1024 时，扩容时直接 double，当切片长度大于 1024 后，每次扩容为之前的 1/4。</p></div></div><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[golang 关于继承的坑点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/11/18/golang继承的坑点</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/11/18/golang继承的坑点"/>
        <updated>2021-11-18T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[准确来说，golang 没有继承，而是组合。]]></summary>
        <content type="html"><![CDATA[<p>准确来说，golang 没有继承，而是组合。</p><div class="language-go codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-go codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">package</span><span class="token plain"> main</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">import</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">"fmt"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">type</span><span class="token plain"> People </span><span class="token keyword" style="color:rgb(86, 156, 214)">struct</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">p People</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">Hello</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"hello"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    p</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">CallName</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">p People</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">CallName</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"my name is people"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">type</span><span class="token plain"> Man </span><span class="token keyword" style="color:rgb(86, 156, 214)">struct</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    People</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">m Man</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">CallName</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    fmt</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Println</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token string" style="color:rgb(206, 145, 120)">"my name is man"</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token keyword" style="color:rgb(86, 156, 214)">func</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">main</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"> </span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">Man</span><span class="token punctuation" style="color:rgb(212, 212, 212)">{</span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">.</span><span class="token function" style="color:rgb(220, 220, 170)">Hello</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain"></span><span class="token punctuation" style="color:rgb(212, 212, 212)">}</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>该代码最终输出的都是结构体 <code>People</code> 定义的方法:</p><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">输出结果</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token plain">hello</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">my name is people</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><p>这是因为 <code>p.CallName()</code> 方法只会调用自己或者组合过来的方法。<br>
<!-- -->通过这种匿名组合的方式，被组合的类型 <code>People</code> 所包含的方法，虽然升级成了外部类型 <code>Teacher</code> 这个组合类型的方法，但接受调用的时候并没有发生变化。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="golang" term="golang"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[python 生成器与迭代器理解]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/11/04/python生成器与迭代器理解</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/11/04/python生成器与迭代器理解"/>
        <updated>2021-11-04T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[生成器]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="生成器">生成器<a href="#生成器" class="hash-link" aria-label="Direct link to 生成器" title="Direct link to 生成器">​</a></h2><p>生成器是 python 中的一种特殊对象，它可以运行时返回计算值，而不用一次将所有逻辑执行完。<br>
<!-- -->生成器定义的方式有两种：  </p><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">列表生成式中 [] 改 ()</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token plain">x </span><span class="token operator" style="color:rgb(212, 212, 212)">*</span><span class="token plain"> x </span><span class="token keyword" style="color:rgb(86, 156, 214)">for</span><span class="token plain"> x </span><span class="token keyword" style="color:rgb(86, 156, 214)">in</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">range</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token number" style="color:rgb(181, 206, 168)">10</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockTitle_Ktv7">在函数中嵌入 yield</div><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token keyword" style="color:rgb(86, 156, 214)">def</span><span class="token plain"> </span><span class="token function" style="color:rgb(220, 220, 170)">fib</span><span class="token punctuation" style="color:rgb(212, 212, 212)">(</span><span class="token builtin" style="color:rgb(86, 156, 214)">max</span><span class="token punctuation" style="color:rgb(212, 212, 212)">)</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    n</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> a</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> b </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">0</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">while</span><span class="token plain"> n </span><span class="token operator" style="color:rgb(212, 212, 212)">&lt;</span><span class="token plain"> </span><span class="token builtin" style="color:rgb(86, 156, 214)">max</span><span class="token punctuation" style="color:rgb(212, 212, 212)">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        </span><span class="token keyword" style="color:rgb(86, 156, 214)">yield</span><span class="token plain"> b</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        a</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> b </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> b</span><span class="token punctuation" style="color:rgb(212, 212, 212)">,</span><span class="token plain"> a </span><span class="token operator" style="color:rgb(212, 212, 212)">+</span><span class="token plain"> b</span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">        n </span><span class="token operator" style="color:rgb(212, 212, 212)">=</span><span class="token plain"> n </span><span class="token operator" style="color:rgb(212, 212, 212)">+</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1</span><span class="token plain"></span><br></span><span class="token-line" style="color:#9CDCFE"><span class="token plain">    </span><span class="token keyword" style="color:rgb(86, 156, 214)">return</span><span class="token plain"> </span><span class="token string" style="color:rgb(206, 145, 120)">'done'</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="迭代器">迭代器<a href="#迭代器" class="hash-link" aria-label="Direct link to 迭代器" title="Direct link to 迭代器">​</a></h2><p>在 python 中，我们将所有可以直接用于 for 循环的对象，统称为<strong>可迭代对象</strong>：<code>Iterable</code></p><p>而生成器是一种特殊的对象，不仅可以直接作用于 for 循环，还可以被 next 函数不断调用返回下一个值，直至最后抛出 StopIteration 错误，
表示已获取到最后一个值。<br>
<!-- -->所以，我们将可以被 next 函数调用并不断返回值的对象称之为 <strong>迭代器</strong>：<code>Iterator</code></p><p><code>Iterator</code> 和常见的 list、map 概念不同：<code>Iterator</code> 表示的是数据流，而他们则表示一个数据集合。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[python 基础数据类型中隐藏的知识点]]></title>
        <id>https://czasg.github.io/docusaurus/blog/2021/11/03/python基础数据类型</id>
        <link href="https://czasg.github.io/docusaurus/blog/2021/11/03/python基础数据类型"/>
        <updated>2021-11-03T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[整数]]></summary>
        <content type="html"><![CDATA[<h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="整数">整数<a href="#整数" class="hash-link" aria-label="Direct link to 整数" title="Direct link to 整数">​</a></h2><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="为了更好的区分位数python-支持以下划线分割整数">为了更好的区分位数，python 支持以下划线分割整数。<a href="#为了更好的区分位数python-支持以下划线分割整数" class="hash-link" aria-label="Direct link to 为了更好的区分位数，python 支持以下划线分割整数。" title="Direct link to 为了更好的区分位数，python 支持以下划线分割整数。">​</a></h4><div class="language-python codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#9CDCFE;--prism-background-color:#1E1E1E"><div class="codeBlockContent_biex"><pre tabindex="0" class="prism-code language-python codeBlock_bY9V thin-scrollbar"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#9CDCFE"><span class="token number" style="color:rgb(181, 206, 168)">1_000_000_000</span><span class="token plain"> </span><span class="token operator" style="color:rgb(212, 212, 212)">==</span><span class="token plain"> </span><span class="token number" style="color:rgb(181, 206, 168)">1000000000</span><br></span></code></pre><div class="buttonGroup__atx"><button type="button" aria-label="Copy code to clipboard" title="Copy" class="clean-btn"><span class="copyButtonIcons_eSgA" aria-hidden="true"><svg class="copyButtonIcon_y97N" viewBox="0 0 24 24"><path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"></path></svg><svg class="copyButtonSuccessIcon_LjdS" viewBox="0 0 24 24"><path d="M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z"></path></svg></span></button></div></div></div><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="字符串">字符串<a href="#字符串" class="hash-link" aria-label="Direct link to 字符串" title="Direct link to 字符串">​</a></h2><h4 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="格式化字符">格式化字符<a href="#格式化字符" class="hash-link" aria-label="Direct link to 格式化字符" title="Direct link to 格式化字符">​</a></h4><ul><li><code>%d</code> 表示输出十进制。</li><li><code>%.2d</code> 表示输出最低两位有效数字</li><li><code>%2d</code> 表示宽度为 2，以右对齐方式输出，左边不足则补空格</li><li><code>%02d</code> 表示宽度为 2，不足补 0</li><li><code>%06.2d</code> 表示宽度为 6，保留最低两位有效数字，以右对齐方式输出，左边不足补 0</li></ul><h2 class="anchor anchorWithHideOnScrollNavbar_WYt5" id="变量">变量<a href="#变量" class="hash-link" aria-label="Direct link to 变量" title="Direct link to 变量">​</a></h2><blockquote><p>变量，指值可以变的量。在数学中，变量以非数字的符号来表达，一般用拉丁字母。变量的用处在于能抽象化描述。</p></blockquote><p>在弱类型语言中，变量本身的类型是不固定的，可以指向任意对象。<br>
<!-- -->在强类型语言中，申明变量时必须要指定变量类型。</p><br><div class="theme-admonition theme-admonition-info alert alert--info admonition_LlT9"><div class="admonitionHeading_tbUL"><span class="admonitionIcon_kALy"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg></span>👇👇👇</div><div class="admonitionContent_S0QG"><p><strong>本文作者:</strong> Czasg<br>
<strong>版权声明:</strong> 转载请注明出处哦~👮‍    </p></div></div>]]></content>
        <author>
            <name>Czasg</name>
            <uri>https://github.com/czasg</uri>
        </author>
        <category label="python" term="python"/>
    </entry>
</feed>