blob: 4373c16feffca0c17dfef3bbdf1e57f2f03552e8 [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pegasus | Usage Scenario</title>
<link rel="stylesheet" href="/zh/assets/css/app.css">
<link rel="shortcut icon" href="/zh/assets/images/favicon.ico">
<link rel="stylesheet" href="/zh/assets/css/utilities.min.css">
<link rel="stylesheet" href="/zh/assets/css/docsearch.v3.css">
<script src="/assets/js/jquery.min.js"></script>
<script src="/assets/js/all.min.js"></script>
<script src="/assets/js/docsearch.v3.js"></script>
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>Usage Scenario | Pegasus</title>
<meta name="generator" content="Jekyll v4.3.3" />
<meta property="og:title" content="Usage Scenario" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="从 1.8.1 版本开始,Pegasus 支持了 Usage Scenario 功能。" />
<meta property="og:description" content="从 1.8.1 版本开始,Pegasus 支持了 Usage Scenario 功能。" />
<meta property="og:site_name" content="Pegasus" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2024-04-22T06:39:52+00:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Usage Scenario" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","dateModified":"2024-04-22T06:39:52+00:00","datePublished":"2024-04-22T06:39:52+00:00","description":"从 1.8.1 版本开始,Pegasus 支持了 Usage Scenario 功能。","headline":"Usage Scenario","mainEntityOfPage":{"@type":"WebPage","@id":"/administration/usage-scenario"},"url":"/administration/usage-scenario"}</script>
<!-- End Jekyll SEO tag -->
</head>
<body>
<div class="dashboard is-full-height">
<!-- left panel -->
<div class="dashboard-panel is-medium is-hidden-mobile pl-0">
<div class="dashboard-panel-header has-text-centered">
<a href="/zh/">
<img src="/assets/images/pegasus-logo-inv.png" style="width: 80%;">
</a>
</div>
<div class="dashboard-panel-main is-scrollable pl-6">
<aside class="menu">
<p class="menu-label">Pegasus 产品文档</p>
<ul class="menu-list">
<li>
<a href="/zh/docs/downloads"
class="">
下载
</a>
</li>
</ul>
<p class="menu-label">编译构建</p>
<ul class="menu-list">
<li>
<a href="/zh/docs/build/compile-by-docker"
class="">
使用 Docker 完成编译(推荐)
</a>
</li>
<li>
<a href="/zh/docs/build/compile-from-source"
class="">
从源码编译
</a>
</li>
</ul>
<p class="menu-label">客户端库</p>
<ul class="menu-list">
<li>
<a href="/zh/clients/java-client"
class="">
Java 客户端
</a>
</li>
<li>
<a href="/zh/clients/cpp-client"
class="">
C++ 客户端
</a>
</li>
<li>
<a href="https://github.com/apache/incubator-pegasus/tree/master/go-client"
class="">
Golang 客户端
</a>
</li>
<li>
<a href="/zh/clients/python-client"
class="">
Python 客户端
</a>
</li>
<li>
<a href="/zh/clients/node-client"
class="">
NodeJS 客户端
</a>
</li>
<li>
<a href="/zh/clients/scala-client"
class="">
Scala 客户端
</a>
</li>
</ul>
<p class="menu-label">生态工具</p>
<ul class="menu-list">
<li>
<a href="/zh/docs/tools/shell"
class="">
Pegasus Shell 工具
</a>
</li>
<li>
<a href="https://github.com/pegasus-kv/admin-cli"
class="">
集群管理命令行
</a>
</li>
<li>
<a href="https://github.com/pegasus-kv/pegic"
class="">
数据访问命令行
</a>
</li>
</ul>
<p class="menu-label">用户接口</p>
<ul class="menu-list">
<li>
<a href="/zh/api/ttl"
class="">
TTL
</a>
</li>
<li>
<a href="/zh/api/single-atomic"
class="">
单行原子操作
</a>
</li>
<li>
<a href="/zh/api/redis"
class="">
Redis 适配
</a>
</li>
<li>
<a href="/zh/api/geo"
class="">
GEO 支持
</a>
</li>
<li>
<a href="/zh/api/http"
class="">
HTTP 接口
</a>
</li>
</ul>
<p class="menu-label">高效运维</p>
<ul class="menu-list">
<li>
<a href="/zh/administration/deployment"
class="">
集群部署
</a>
</li>
<li>
<a href="/zh/administration/config"
class="">
配置说明
</a>
</li>
<li>
<a href="/zh/administration/rebalance"
class="">
负载均衡
</a>
</li>
<li>
<a href="/zh/administration/monitoring"
class="">
可视化监控
</a>
</li>
<li>
<a href="/zh/administration/rolling-update"
class="">
集群重启和升级
</a>
</li>
<li>
<a href="/zh/administration/scale-in-out"
class="">
集群扩容缩容
</a>
</li>
<li>
<a href="/zh/administration/resource-management"
class="">
资源管理
</a>
</li>
<li>
<a href="/zh/administration/cold-backup"
class="">
冷备份
</a>
</li>
<li>
<a href="/zh/administration/meta-recovery"
class="">
元数据恢复
</a>
</li>
<li>
<a href="/zh/administration/replica-recovery"
class="">
Replica 数据恢复
</a>
</li>
<li>
<a href="/zh/administration/zk-migration"
class="">
Zookeeper 迁移
</a>
</li>
<li>
<a href="/zh/administration/table-migration"
class="">
Table 迁移
</a>
</li>
<li>
<a href="/zh/administration/table-soft-delete"
class="">
Table 软删除
</a>
</li>
<li>
<a href="/zh/administration/table-env"
class="">
Table 环境变量
</a>
</li>
<li>
<a href="/zh/administration/remote-commands"
class="">
远程命令
</a>
</li>
<li>
<a href="/zh/administration/partition-split"
class="">
Partition-Split
</a>
</li>
<li>
<a href="/zh/administration/duplication"
class="">
跨机房同步
</a>
</li>
<li>
<a href="/zh/administration/compression"
class="">
数据压缩
</a>
</li>
<li>
<a href="/zh/administration/throttling"
class="">
流量控制
</a>
</li>
<li>
<a href="/zh/administration/experiences"
class="">
运维经验
</a>
</li>
<li>
<a href="/zh/administration/manual-compact"
class="">
Manual Compact 功能
</a>
</li>
<li>
<a href="/zh/administration/usage-scenario"
class="is-active">
Usage Scenario 功能
</a>
</li>
<li>
<a href="/zh/administration/bad-disk"
class="">
坏盘检修
</a>
</li>
<li>
<a href="/zh/administration/whitelist"
class="">
Replica Server 白名单
</a>
</li>
<li>
<a href="/zh/administration/backup-request"
class="">
Backup Request
</a>
</li>
<li>
<a href="/zh/administration/hotspot-detection"
class="">
热点检测
</a>
</li>
</ul>
</aside>
</div>
</div>
<!-- main section -->
<div class="dashboard-main is-scrollable">
<nav class="navbar is-hidden-desktop">
<div class="navbar-brand">
<a href="/zh/" class="navbar-item">
<!-- Pegasus Icon -->
<img src="/assets/images/pegasus-square.png">
</a>
<div class="navbar-item">
<!--A simple language switch button that only supports zh and en.-->
<!--IF its language is zh, then switches to en.-->
<!--If you don't want a url to be relativized, you can add a space explicitly into the href to
prevents a url from being relativized by polyglot.-->
<a class="button is-light is-outlined is-inverted" href=" /administration/usage-scenario"><strong>En</strong></a>
</div>
<a role="button" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navMenu">
<!-- Appears in mobile mode only -->
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div class="navbar-menu" id="navMenu">
<div class="navbar-end">
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
Pegasus 产品文档
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/docs/downloads"
class="navbar-item ">
下载
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
编译构建
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/docs/build/compile-by-docker"
class="navbar-item ">
使用 Docker 完成编译(推荐)
</a>
<a href="/zh/docs/build/compile-from-source"
class="navbar-item ">
从源码编译
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
客户端库
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/clients/java-client"
class="navbar-item ">
Java 客户端
</a>
<a href="/zh/clients/cpp-client"
class="navbar-item ">
C++ 客户端
</a>
<a href="https://github.com/apache/incubator-pegasus/tree/master/go-client"
class="navbar-item ">
Golang 客户端
</a>
<a href="/zh/clients/python-client"
class="navbar-item ">
Python 客户端
</a>
<a href="/zh/clients/node-client"
class="navbar-item ">
NodeJS 客户端
</a>
<a href="/zh/clients/scala-client"
class="navbar-item ">
Scala 客户端
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
生态工具
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/docs/tools/shell"
class="navbar-item ">
Pegasus Shell 工具
</a>
<a href="https://github.com/pegasus-kv/admin-cli"
class="navbar-item ">
集群管理命令行
</a>
<a href="https://github.com/pegasus-kv/pegic"
class="navbar-item ">
数据访问命令行
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
用户接口
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/api/ttl"
class="navbar-item ">
TTL
</a>
<a href="/zh/api/single-atomic"
class="navbar-item ">
单行原子操作
</a>
<a href="/zh/api/redis"
class="navbar-item ">
Redis 适配
</a>
<a href="/zh/api/geo"
class="navbar-item ">
GEO 支持
</a>
<a href="/zh/api/http"
class="navbar-item ">
HTTP 接口
</a>
</div>
</div>
<!--dropdown-->
<div class="navbar-item has-dropdown is-hoverable">
<a href=""
class="navbar-link ">
<span>
高效运维
</span>
</a>
<div class="navbar-dropdown">
<a href="/zh/administration/deployment"
class="navbar-item ">
集群部署
</a>
<a href="/zh/administration/config"
class="navbar-item ">
配置说明
</a>
<a href="/zh/administration/rebalance"
class="navbar-item ">
负载均衡
</a>
<a href="/zh/administration/monitoring"
class="navbar-item ">
可视化监控
</a>
<a href="/zh/administration/rolling-update"
class="navbar-item ">
集群重启和升级
</a>
<a href="/zh/administration/scale-in-out"
class="navbar-item ">
集群扩容缩容
</a>
<a href="/zh/administration/resource-management"
class="navbar-item ">
资源管理
</a>
<a href="/zh/administration/cold-backup"
class="navbar-item ">
冷备份
</a>
<a href="/zh/administration/meta-recovery"
class="navbar-item ">
元数据恢复
</a>
<a href="/zh/administration/replica-recovery"
class="navbar-item ">
Replica 数据恢复
</a>
<a href="/zh/administration/zk-migration"
class="navbar-item ">
Zookeeper 迁移
</a>
<a href="/zh/administration/table-migration"
class="navbar-item ">
Table 迁移
</a>
<a href="/zh/administration/table-soft-delete"
class="navbar-item ">
Table 软删除
</a>
<a href="/zh/administration/table-env"
class="navbar-item ">
Table 环境变量
</a>
<a href="/zh/administration/remote-commands"
class="navbar-item ">
远程命令
</a>
<a href="/zh/administration/partition-split"
class="navbar-item ">
Partition-Split
</a>
<a href="/zh/administration/duplication"
class="navbar-item ">
跨机房同步
</a>
<a href="/zh/administration/compression"
class="navbar-item ">
数据压缩
</a>
<a href="/zh/administration/throttling"
class="navbar-item ">
流量控制
</a>
<a href="/zh/administration/experiences"
class="navbar-item ">
运维经验
</a>
<a href="/zh/administration/manual-compact"
class="navbar-item ">
Manual Compact 功能
</a>
<a href="/zh/administration/usage-scenario"
class="navbar-item is-active">
Usage Scenario 功能
</a>
<a href="/zh/administration/bad-disk"
class="navbar-item ">
坏盘检修
</a>
<a href="/zh/administration/whitelist"
class="navbar-item ">
Replica Server 白名单
</a>
<a href="/zh/administration/backup-request"
class="navbar-item ">
Backup Request
</a>
<a href="/zh/administration/hotspot-detection"
class="navbar-item ">
热点检测
</a>
</div>
</div>
</div>
</div>
</nav>
<nav class="navbar is-hidden-mobile">
<div class="navbar-start w-full">
<div class="navbar-item pl-0 w-full">
<!--TODO(wutao): Given the limitation of docsearch that couldn't handle multiple input,
I make searchbox only shown in desktop. Fix this issue when docsearch.js v3 released.
Related issue: https://github.com/algolia/docsearch/issues/230-->
<div id="docsearch"></div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<!--A simple language switch button that only supports zh and en.-->
<!--IF its language is zh, then switches to en.-->
<!--If you don't want a url to be relativized, you can add a space explicitly into the href to
prevents a url from being relativized by polyglot.-->
<a class="button is-light is-outlined is-inverted" href=" /administration/usage-scenario"><strong>En</strong></a>
</div>
</div>
</nav>
<section class="hero is-info lg:mr-3">
<div class="hero-body">
<p class="title is-size-2 is-centered">Usage Scenario 功能</p>
</div>
</section>
<section class="section" style="padding-top: 2rem;">
<div class="content">
<blockquote>
<p>从 1.8.1 版本开始,Pegasus 支持了 Usage Scenario 功能。</p>
</blockquote>
<h1 id="原理">原理</h1>
<p>Usage Scenario 功能,是指对 Pegasus 表指定 <em>使用场景</em>。针对不同的场景,通过优化底层 RocksDB 的配置,以获得更好的读写性能。</p>
<p>RocksDB 采用了 LSM tree 存储架构,其中的 <a href="https://github.com/facebook/rocksdb/wiki/Compaction">Compaction</a> 会较大地影响读写性能,Pegasus 采用了 Classic Leveled 算法,他的 Compaction 原理参考 <a href="https://github.com/facebook/rocksdb/wiki/Leveled-Compaction">Leveled-Compaction</a></p>
<p>RocksDB 是一个可配置性很强的引擎,各种 flush 操作和 compaction 操作都可以通过配置调节,并且有部分配置是可以运行时修改的。这里给出几个比较关键的配置:</p>
<blockquote>
<p>(配置说明源自 RocksDB 源码)</p>
<ul>
<li>write_buffer_size: Amount of data to build up in memory before converting to a sorted on-disk file.</li>
<li>level0_file_num_compaction_trigger: Number of files to trigger level-0 compaction. A value &lt;0 means that level-0 compaction will not be triggered by number of files at all.</li>
<li>level0_slowdown_writes_trigger:Soft limit on number of level-0 files. We start slowing down writes at this point. A value &lt;0 means that no writing slow down will be triggered by number of files in level-0.</li>
<li>level0_stop_writes_trigger: Maximum number of level-0 files. We stop writes at this point.</li>
<li>max_bytes_for_level_base: Control maximum total data size for a level. max_bytes_for_level_base is the max total for level-1.</li>
<li>max_bytes_for_level_multiplier: Maximum number of bytes for level L can be calculated as (max_bytes_for_level_base) * (max_bytes_for_level_multiplier ^ (L-1)).</li>
</ul>
</blockquote>
<p>Pegasus 在提供读写服务时,需要考虑这些因素:</p>
<ul>
<li>写操作越快,memtable 就会更快写满,就会更快地 flush memtable 产生 level-0 上新的 sstable 文件</li>
<li>随着 level-0 上 sstable 文件的累积,就会触发 compaction 操作,并从低层向高层逐层蔓延</li>
<li>Compaction 操作越多,耗费的 CPU 和磁盘 IO 负载越高,从而影响读写操作的性能</li>
<li>如果 level-0 到 level-1 的 compaction 操作速度低于数据写入的速度,level-0 的文件数就会累积得越多,最终达到 <code class="language-plaintext highlighter-rouge">level0_slowdown_writes_trigger</code> 阈值,使写操作的延迟陡增,甚至进一步达到 <code class="language-plaintext highlighter-rouge">level0_stop_writes_trigger</code> 阈值,使写操作失败,影响系统的稳定性和服务的可用性</li>
<li>高吞吐且低延迟的读写需求很难同时得到满足,二者需要权衡。
<ul>
<li>Compaction 操作进行得越快,level-0 累积得文件数越少,读操作需要读取的文件个数就越少,读性能就越高</li>
<li>但是 compaction 越快,带来的写放大就越大,CPU 和磁盘 IO 负载就越高,也会影响读写性能</li>
</ul>
</li>
</ul>
<p>所幸的是,RocksDB 针对这个问题也给出了一些解决方案,例如在 <a href="https://github.com/facebook/rocksdb/wiki/RocksDB-FAQ">RocksDB-FAQ</a> 中给出的方案:</p>
<blockquote>
<p>Q: What’s the fastest way to load data into RocksDB?</p>
<p>A: A fast way to direct insert data to the DB:</p>
<ol>
<li>using single writer thread and insert in sorted order</li>
<li>batch hundreds of keys into one write batch</li>
<li>use vector memtable</li>
<li>make sure options.max_background_flushes is at least 4</li>
<li>before inserting the data, disable automatic compaction, set options.level0_file_num_compaction_trigger, options.level0_slowdown_writes_trigger and options.level0_stop_writes_trigger to very large value. After inserting all the data, issue a manual compaction.</li>
</ol>
<p>3-5 will be automatically done if you call Options::PrepareForBulkLoad() to your option</p>
</blockquote>
<p>Pegasus 的解决方案是,针对不同应用场景,设置不同的 RocksDB 参数,调节 RocksDB 的行为,以提供更好的读写性能。具体来说:</p>
<ul>
<li>通过 <a href="table-env">Table 环境变量</a> 设置 <code class="language-plaintext highlighter-rouge">rocksdb.usage_scenario</code> 来指定对应的应用场景</li>
<li>各表的 replica 在检测到该环境变量发生变化时,就会根据业务场景修改 RocksDB 的配置参数。
<blockquote>
<p>具体设置了哪些参数,可参考 <a href="https://github.com/apache/incubator-pegasus/blob/master/src/server/pegasus_server_impl.cpp">src/server/pegasus_server_impl.cpp</a> 中的 <code class="language-plaintext highlighter-rouge">set_usage_scenario()</code> 方法。</p>
</blockquote>
</li>
</ul>
<h1 id="支持场景">支持场景</h1>
<p>目前 Pegasus 支持三种场景:</p>
<ul>
<li>normal:正常场景,读写兼顾。这也是表的默认场景,该场景不会对写进行特别的优化,适合大部分读写均衡的应用</li>
<li>prefer_write:写多读少的场景。主要是增大 <code class="language-plaintext highlighter-rouge">write_buffer_size</code><code class="language-plaintext highlighter-rouge">level0_file_num_compaction_trigger</code> 以降低 memtable 的 flush 操作和 level-0 到 level-1 的 compaction 操作的速度</li>
<li>bulk_load:批量导入数据的场景(注意这不是 <a href="https://pegasus.apache.org/zh/2020/02/18/bulk-load-design.html">bulk-load</a>)。使用上面 RocksDB-FAQ 中提到的优化,禁用 compaction 操作。此时,所有新写入的数据都会堆积在 level-0 层,对读不友好。因此,<code class="language-plaintext highlighter-rouge">bulk_load</code> 场景通常与 <a href="manual-compact">Manual Compact 功能</a> 结合使用,在数据导入完成后,进行一次 Manual Compact,以快速进行垃圾回收、全局排序来提升读性能,然后恢复为 normal 模式。典型的批量数据导入流程:
<ul>
<li>设置表的 <code class="language-plaintext highlighter-rouge">rocksdb.usage_scenario</code> 模式为 <code class="language-plaintext highlighter-rouge">bulk_load</code></li>
<li>导入数据:在 <code class="language-plaintext highlighter-rouge">bulk_load</code> 场景下数据写入 TPS 会更高,流量更稳定</li>
<li>执行 Manual Compact:该过程会消耗大量的 CPU 和磁盘 IO 资源,可能对集群读写性能有影响</li>
<li>恢复表的 <code class="language-plaintext highlighter-rouge">rocksdb.usage_scenario</code> 模式为 <code class="language-plaintext highlighter-rouge">normal</code></li>
</ul>
</li>
</ul>
<h1 id="如何使用">如何使用</h1>
<h2 id="通过-shell-工具设置">通过 shell 工具设置</h2>
<p>通过 shell 工具的 <a href="/zh/docs/tools/shell/#set_app_envs">set_app_envs</a> 命令来设置,例如设置 temp 表为 bulk_load 模式:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; use temp
&gt;&gt;&gt; set_app_envs rocksdb.usage_scenario bulk_load
</code></pre></div></div>
<blockquote>
<p>Table 的环境变量不会立即生效,大约需要等几十秒(取决于配置项 <code class="language-plaintext highlighter-rouge">[replication]config_sync_interval_ms</code>)后才能在所有 replica 上生效。</p>
</blockquote>
<h2 id="通过辅助脚本设置">通过辅助脚本设置</h2>
<p>Pegasus 提供了一个辅助脚本 <a href="https://github.com/apache/incubator-pegasus/blob/master/scripts/pegasus_set_usage_scenario.sh">scripts/pegasus_set_usage_scenario.sh</a> 来方便地设置环境变量,用法:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ ./scripts/pegasus_set_usage_scenario.sh
This tool is for set usage scenario of specified table(app).
USAGE: ./scripts/pegasus_set_usage_scenario.sh &lt;cluster-meta-list&gt; &lt;app-name&gt; &lt;normal|prefer_write|bulk_load&gt;
</code></pre></div></div>
<p>该脚本会调用 shell 工具中设置 Table 环境变量的命令,然后检测是否在所有 replica 上都已经生效,只有所有 replica 上都生效了才算执行完成。</p>
</div>
</section>
<footer class="footer">
<div class="container">
<div class="content is-small has-text-centered">
<div style="margin-bottom: 20px;">
<a href="http://incubator.apache.org">
<img src="/assets/images/egg-logo.png"
width="15%"
alt="Apache Incubator"/>
</a>
</div>
Copyright &copy; 2023 <a href="http://www.apache.org">The Apache Software Foundation</a>.
Licensed under the <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache License, Version
2.0</a>.
<br><br>
Apache Pegasus is an effort undergoing incubation at The Apache Software Foundation (ASF),
sponsored by the Apache Incubator. Incubation is required of all newly accepted projects
until a further review indicates that the infrastructure, communications, and decision making process
have stabilized in a manner consistent with other successful ASF projects. While incubation status is
not necessarily a reflection of the completeness or stability of the code, it does indicate that the
project has yet to be fully endorsed by the ASF.
<br><br>
Apache Pegasus, Pegasus, Apache, the Apache feather logo, and the Apache Pegasus project logo are either
registered trademarks or trademarks of The Apache Software Foundation in the United States and other
countries.
</div>
</div>
</footer>
</div>
<!-- right panel -->
<div class="dashboard-panel is-small is-scrollable is-hidden-mobile">
<p class="menu-label">
<span class="icon">
<i class="fa fa-bars" aria-hidden="true"></i>
</span>
本页导航
</p>
<ul class="menu-list">
<li><a href="#原理">原理</a></li>
<li><a href="#支持场景">支持场景</a></li>
<li><a href="#如何使用">如何使用</a>
<ul>
<li><a href="#通过-shell-工具设置">通过 shell 工具设置</a></li>
<li><a href="#通过辅助脚本设置">通过辅助脚本设置</a></li>
</ul>
</li>
</ul>
</div>
</div>
<script src="/assets/js/app.js" type="text/javascript"></script>
<script>
docsearch({
container: '#docsearch',
appId: 'QRN30RBW0S',
indexName: 'pegasus-apache',
apiKey: 'd3a3252fa344359766707a106c4ed88f',
debug: true
});
</script>
</body>
</html>