blob: ffb1bcdcba65a97871f2cba639c9cfe4543c0aec [file] [log] [blame]
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Pegasus | Scale In Out</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>Scale In Out | Pegasus</title>
<meta name="generator" content="Jekyll v4.3.3" />
<meta property="og:title" content="Scale In Out" />
<meta property="og:locale" content="en_US" />
<meta name="description" content="功能目标" />
<meta property="og:description" content="功能目标" />
<meta property="og:site_name" content="Pegasus" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2024-04-22T13:02:52+00:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="Scale In Out" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","dateModified":"2024-04-22T13:02:52+00:00","datePublished":"2024-04-22T13:02:52+00:00","description":"功能目标","headline":"Scale In Out","mainEntityOfPage":{"@type":"WebPage","@id":"/administration/scale-in-out"},"url":"/administration/scale-in-out"}</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="is-active">
集群扩容缩容
</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="">
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/scale-in-out"><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 is-active">
集群扩容缩容
</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 ">
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/scale-in-out"><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">集群扩容缩容</p>
</div>
</section>
<section class="section" style="padding-top: 2rem;">
<div class="content">
<h1 id="功能目标">功能目标</h1>
<p>当集群存储容量不够或者读写吞吐太大了,需要通过增加节点来扩容;反之,可以通过减少节点来缩容。</p>
<blockquote>
<p>本文所述的扩容缩容是针对 replica server。</p>
</blockquote>
<p>扩容和缩容时,需要考虑这些点:</p>
<ul>
<li>不要停止 Pegasus 服务</li>
<li>尽量不要影响可用性</li>
<li>尽量减少不必要的数据传输</li>
</ul>
<h1 id="扩容流程">扩容流程</h1>
<p>扩容流程比较简单:</p>
<ul>
<li>要扩容多个服务器,就在这些新增服务器上启动 replica server 进程,启动后 replica server 会主动联系 meta server,加入节点列表中。</li>
<li>在 meta level 为 <code class="language-plaintext highlighter-rouge">steady</code> 时,不会进行 <a href="rebalance">负载均衡</a>,因此用 shell 工具的 <code class="language-plaintext highlighter-rouge">nodes -d</code> 命令查看,可以看到新节点的状态为 <code class="language-plaintext highlighter-rouge">ALIVE</code>,但是该节点服务的 replica 个数为 0。</li>
<li>通过 shell 工具的 <code class="language-plaintext highlighter-rouge">set_meta_level lively</code> 启动负载均衡,meta server 会逐渐将部分 replica 迁移到新节点上。</li>
<li>通过 shell 工具的 <code class="language-plaintext highlighter-rouge">nodes -d</code> 命令查看各节点服务 replica 的情况,在达到均衡状态后,通过 <code class="language-plaintext highlighter-rouge">set_meta_level steady</code> 关闭负载均衡,扩容完成。</li>
</ul>
<h1 id="缩容流程">缩容流程</h1>
<p>缩容相对扩容要考虑的点就多些,主要包括:</p>
<ul>
<li>如果同时要下线多个节点,需要一个一个进行,等一个下线完成后再下线另一个,避免影响集群的可用性和数据的完整性。</li>
<li>如果同时要下线多个节点,那么在下线一个节点时,要尽量避免 meta server 在补充副本时将副本分派到即将要下线的其他节点上,否则在下线其他节点时,又要重新补充副本,造成不必要的跨节点数据拷贝。我们提供了 <a href="/zh/administration/rebalance#assign_secondary_black_list">black_list</a> 来支持这个功能。</li>
</ul>
<blockquote>
<p>注意:节点下线后,在 meta server 上的状态会变成 <code class="language-plaintext highlighter-rouge">UNALIVE</code>,可能会造成 <code class="language-plaintext highlighter-rouge">ALIVE</code> 的节点比例低于配置参数 <code class="language-plaintext highlighter-rouge">node_live_percentage_threshold_for_update</code>,此时,meta server 就会自动降级为 <code class="language-plaintext highlighter-rouge">freezed</code> 状态,此时所有的 <code class="language-plaintext highlighter-rouge">reconfiguration</code> 操作(即重新分派副本的操作)都无法进行,缩容流程也将无进继续进行。所以在缩容之前需要计算一下是否会造成这种情况,如果会,就先修改 meta server 的配置,将 <code class="language-plaintext highlighter-rouge">node_live_percentage_threshold_for_update</code> 修改至足够低,以保证在缩容过程中 meta server 不会自动降级为 <code class="language-plaintext highlighter-rouge">freezed</code> 状态。</p>
</blockquote>
<h2 id="推荐的缩容流程">推荐的缩容流程</h2>
<ul>
<li>计算缩容后 <code class="language-plaintext highlighter-rouge">ALIVE</code> 的节点比例,如果低于参数 <code class="language-plaintext highlighter-rouge">node_live_percentage_threshold_for_update</code>,则使用 <a href="/zh/administration/remote-commands">远程命令</a> 修改该参数使其足够小。
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; remote_command -t meta-server meta.live_percentage $percentage
</code></pre></div> </div>
<p>其中 <code class="language-plaintext highlighter-rouge">percentage</code> 为整数,取值范围为 [0, 100]。</p>
</li>
<li>使用 shell 工具的 <code class="language-plaintext highlighter-rouge">set_meta_level</code> 命令将集群设置为 <code class="language-plaintext highlighter-rouge">steady</code> 模式,关闭 <a href="rebalance">负载均衡功能</a>,避免不必要的 replica 迁移。
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; set_meta_level steady
</code></pre></div> </div>
</li>
<li>使用 shell 工具向 meta server 发送 <a href="remote-commands#meta-server">远程命令</a> 来更新 <code class="language-plaintext highlighter-rouge">assign_secondary_black_list</code>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; remote_command -t meta-server meta.lb.assign_secondary_black_list $address_list
</code></pre></div> </div>
<p>其中 <code class="language-plaintext highlighter-rouge">address_list</code> 是要下线节点的 <code class="language-plaintext highlighter-rouge">ip:port</code> 列表,用逗号分隔。</p>
</li>
<li>使用 shell 工具将 <code class="language-plaintext highlighter-rouge">assign_delay_ms</code> 设为 10,使得在节点下线后,立即在其他存活节点上补充副本:
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; remote_command -t meta-server meta.lb.assign_delay_ms 10
</code></pre></div> </div>
</li>
<li>逐个下线 replica server。单个 replica server 下线流程:
<ul>
<li>kill 掉想要下线的 replica server 进程。</li>
<li>使用 shell 工具的 <code class="language-plaintext highlighter-rouge">ls -d</code> 命令查看集群状态,等待所有 partition 都完全恢复健康(所有表的 unhealthy partition 数都为 0)。</li>
<li>清理该节点上的数据,释放磁盘空间。</li>
</ul>
</li>
<li>重启 meta server:
<ul>
<li>重启 meta server 是为了清理已下线节点的记录(即在 shell 工具的 <code class="language-plaintext highlighter-rouge">nodes -d</code> 不再显示已经下线的节点),并重置以上修改过的配置项。</li>
</ul>
</li>
</ul>
<h2 id="脚本">脚本</h2>
<p>以上过程已被脚本 <a href="https://github.com/apache/incubator-pegasus/blob/master/scripts/pegasus_offline_node_list.sh">scripts/pegasus_offline_node_list.sh</a> 实现。</p>
<blockquote>
<p>不过该脚本不能直接使用,因为他依赖 <a href="https://github.com/XiaoMi/minos">minos 部署工具</a>.</p>
</blockquote>
<h1 id="节点迁移">节点迁移</h1>
<p>通过先扩容,再缩容的方式,来实现集群的节点迁移。为了尽量减少不必要的数据传输,建议按照如下步骤:</p>
<ul>
<li>先扩容:将需要扩容的服务器加入到集群中,但是在加入后暂时不进行 <a href="/zh/administration/rebalance#控制集群的负载均衡">负载均衡</a></li>
<li>再缩容:将需要缩容的服务器通过上面的 <a href="#缩容流程">缩容流程</a> 进行下线。</li>
<li>执行 <a href="/zh/administration/rebalance#控制集群的负载均衡">负载均衡</a></li>
</ul>
<h1 id="其他配置">其他配置</h1>
<ul>
<li>迁移限速。可以设置单块磁盘的读写带宽,避免高吞吐带来的性能影响。
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt;&gt;&gt; remote_command -t replica-server nfs.max_send_rate_megabytes_per_disk $rate
&gt;&gt;&gt; remote_command -t replica-server nfs.max_copy_rate_megabytes_per_disk $rate
</code></pre></div> </div>
<p>其中 <code class="language-plaintext highlighter-rouge">rate</code> 的单位为 <code class="language-plaintext highlighter-rouge">MB/s</code></p>
</li>
</ul>
</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="#推荐的缩容流程">推荐的缩容流程</a></li>
<li><a href="#脚本">脚本</a></li>
</ul>
</li>
<li><a href="#节点迁移">节点迁移</a></li>
<li><a href="#其他配置">其他配置</a></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>