Manticore Search 集群

Manticore Search 是一个高度分布式的系统,提供了创建高可用和可扩展的搜索数据库所需的所有组件。这包括:

  • 用于分片的分布式表
  • 用于高可用性的镜像
  • 用于可扩展性的负载均衡
  • 用于数据安全性的复制

在设置集群时,Manticore Search 提供了很大的灵活性。没有限制,因此您可以根据自己的需求设计集群。只需了解上述提到的工具,并使用它们来实现您的目标。

添加新节点

要将新节点添加到集群,只需启动 Manticore 的另一个实例,并确保其他节点可以访问它。使用分布式表将新节点连接到集群的其余部分,并通过复制确保数据安全性。

添加带有远程代理的分布式表

要了解如何使用远程代理添加分布式表,首先需要对分布式表有基本的了解。在本文中,我们将重点介绍如何使用分布式表作为创建Manticore实例集群的基础。

以下是如何在4台服务器上拆分数据的示例,每台服务器都提供一个分片:

  1. table mydist {
  2. type = distributed
  3. agent = box1:9312:shard1
  4. agent = box2:9312:shard2
  5. agent = box3:9312:shard3
  6. agent = box4:9312:shard4
  7. }

在发生服务器故障的情况下,分布式表仍然可以工作,但是来自失败分片的结果将丢失。

现在我们已经添加了镜像,每个分片在两台服务器上都能找到。默认情况下,主服务器(具有分布式表的searchd实例)将随机选择其中一个镜像。

用于选择镜像的模式可以使用 ha_strategy 设置进行设置。除了默认的随机模式之外,还有 ha_strategy = roundrobin。

基于延迟加权概率的更高级的策略包括 noerrors 和 nodeads。这些不仅会排除存在问题的镜像,还会监视响应时间并进行平衡。如果某个镜像响应较慢(例如,由于正在运行某些操作),它将接收较少的请求。当镜像恢复并提供更好的响应时间时,它将接收更多的请求。

  1. table mydist {
  2. type = distributed
  3. agent = box1:9312|box5:9312:shard1
  4. agent = box2:9312:|box6:9312:shard2
  5. agent = box3:9312:|box7:9312:shard3
  6. agent = box4:9312:|box8:9312:shard4
  7. }

镜像

代理镜像可以在处理搜索查询时互换使用。托管镜像代理的 Manticore 实例(或实例)在其中定义了镜像代理的分布表,跟踪镜像状态(存活或死亡)和响应时间,并根据此信息执行自动故障转移和负载平衡。

代理镜像

  1. agent = node1|node2|node3:9312:shard2

上面的示例声明了 node1:9312、node2:9312 和 node3:9312 都有一个名为 shard2 的表,并且可以作为可互换的镜像使用。如果其中任何服务器宕机,查询将在剩余的两台服务器之间分发。当服务器恢复在线时,主服务器将检测到它并开始将查询路由到所有三个节点。

镜像还可以包括一个单独的表列表,如下所示:

  1. agent = node1:9312:node1shard2|node2:9312:node2shard2

这与前面的示例类似,但在查询不同的服务器时将使用不同的表名称。例如,在查询 node1:9312 时将使用 node1shard2,在查询 node2:9312 时将使用 node2shard。

默认情况下,所有查询都会路由到最佳镜像。最佳镜像是根据最近的统计信息选择的,由 ha_period_karma 配置指令控制。主服务器为每个代理存储度量(总查询计数、错误计数、响应时间等),并按时间跨度对这些度量进行分组。 karma 是时间跨度的长度。然后根据最后两个这样的时间跨度动态确定最佳的代理镜像。可以使用 ha_strategy 指令配置用于选择镜像的特定算法。

karma 周期为秒,默认为 60 秒。主服务器为每个代理存储多达 15 个 karma 跨度的统计信息,用于仪表板目的(请参阅 SHOW AGENT STATUS 语句)。然而,这些中仅使用最后两个跨度用于 HA/LB 逻辑。

当没有查询时,主服务器每隔 ha_ping_interval 毫秒发送一条常规 ping 命令,以收集统计信息并检查远程主机是否仍然存活。ha_ping_interval 默认为 1000 毫秒。将其设置为 0 将禁用 ping,统计信息将仅基于实际查询累积。

示例:

  1. # 在总共 4 台服务器上进行分表
  2. # 仅在 2 个分片上进行,但每个分片有 2 个故障转移镜像
  3. # node1、node2 承载 shard1 作为本地
  4. # node3、node4 承载 shard2 作为本地
  5. # 在 node1、node2 上的配置
  6. agent = node3:9312|node4:9312:shard2
  7. # 在 node3、node4 上的配置
  8. agent = node1:9312|node2:9312:shard1

负载均衡

对于使用镜像的任何分布式表,默认情况下会启用负载均衡。默认情况下,查询在镜像之间随机分发。您可以通过使用 ha_strategy 更改此行为。

ha_strategy

  1. ha_strategy = {random|nodeads|noerrors|roundrobin}

用于负载均衡的镜像选择策略是可选的,默认设置为随机。

这个指令控制主服务器在配置的镜像代理节点之间执行负载均衡的方式,或者换句话说,选择分布式表中特定代理镜像的方式。实现了以下策略:

简单的随机均衡

默认的均衡模式是简单的线性随机分布在镜像之间。这意味着给每个镜像分配相等的选择概率。这类似于循环轮询(RR),但不会强加严格的选择顺序。

自适应随机均衡

默认的简单随机策略不考虑镜像的状态、错误率,更重要的是实际响应延迟。为了解决异构集群和代理节点负载的临时波动,有一组基于实际查询延迟的均衡策略,根据主服务器观察到的实际查询延迟动态调整概率。

基于延迟加权概率的自适应策略工作原理如下:

  1. 延迟统计信息在 ha_period_karma 秒的块中累积。
  2. 每个 karma 周期重新计算一次基于延迟加权的概率。
  3. “死或活” 标志在每个请求时进行一次调整,包括 ping 请求。

最初,概率是相等的。在每个步骤中,它们被上一个 karma 期间观察到的延迟的倒数缩放,然后重新标准化。例如,如果在主服务器启动后的第一个 60 秒内,4 个镜像的延迟分别为 10 毫秒、5 毫秒、30 毫秒和 3 毫秒,第一次调整步骤将如下进行:

  1. 初始百分比:0.25, 0.25, 0.25, 0.25。
  2. 观察到的延迟:10 毫秒,5 毫秒,30 毫秒,3 毫秒。
  3. 延迟的倒数:0.1, 0.2, 0.0333, 0.333。
  4. 缩放百分比:0.025, 0.05, 0.008333, 0.0833。
  5. 重新标准化百分比:0.15, 0.30, 0.05, 0.50。

这意味着在下一个 karma 期间,第一个镜像有 15% 的机会被选择,第二个镜像有 30% 的机会,第三个镜像(30 毫秒最慢)只有 5% 的机会,第四个镜像(3 毫秒最快)有 50% 的机会。之后,第二个调整步骤会再次更新这些概率,依此类推。

这个思想是一旦观察到的延迟稳定下来,延迟加权的概率也会稳定下来。所有这些调整迭代的目的是在平均延迟在所有镜像上大致相等的点上收敛。

nodeads

延迟加权的概率,但已经标记为死亡的镜像被排除在选择之外。”死亡” 镜像被定义为在连续的多个严重错误(例如网络故障、没有响应等)中导致的镜像。

ha_strategy = nodeads

noerrors

延迟加权的概率,但在选择时排除错误/成功比率较差的镜像。

ha_strategy = noerrors

轮训

简单的轮询选择,即选择列表中的第一个镜像,然后选择第二个,然后选择第三个,依此类推,一旦到达列表中的最后一个镜像,就重复这个过程。与随机化策略不同,RR强制执行严格的查询顺序(1、2、3、…、N-1、N、1、2、3、…等),并确保不会将两个连续的查询发送到同一个镜像。

Instance-wide options

ha_period_karma

ha_period_karma = 2m

ha_period_karma 定义了代理镜像统计窗口的大小,单位为秒(或时间后缀)。可选,默认值为60。

对于带有代理镜像的分布式表,服务器跟踪多个不同的每个镜像计数器。然后这些计数器用于故障转移和平衡。(服务器根据计数器选择最佳的镜像使用。)计数器在 ha_period_karma 秒的块中累积。

在开始新的块后,主服务器可能仍然使用从前一个块累积的值,直到新块被填充到一半为止。因此,先前的任何历史记录在最多 1.5 倍 ha_period_karma 秒后停止影响镜像选择。

尽管最多使用 2 个块进行镜像选择,但实际上最多存储了最后 15 个块,供仪表化目的使用。可以使用 SHOW AGENT STATUS 语句查看它们。

ha_ping_interval

ha_ping_interval = 3s

ha_ping_interval 指令定义了发送到代理镜像的ping之间的间隔,单位为毫秒(或带有时间后缀)。此选项是可选的,默认值为1000。

对于带有代理镜像的分布式表,服务器在空闲时期间向所有镜像发送ping命令,以跟踪它们的当前状态(它们是否存活,网络往返时间等)。ping之间的间隔由 ha_ping_interval 设置确定。

如果要禁用ping,请将 ha_ping_interval 设置为0。

设置副本

使用 Manticore,写入事务(如 INSERT、REPLACE、DELETE、TRUNCATE、UPDATE、COMMIT)可以在当前节点完全应用事务之前被复制到其他集群节点。目前,在 Linux 和 macOS 上支持 percolate 和 rt 表的复制。但是,Manticore Search 的 Windows 包不提供复制支持。

Manticore 的复制由 Galera 库提供支持,并拥有一些令人印象深刻的特性:

  • 真正的多主:随时随地在任何节点进行读写。
  • 几乎同步的复制:没有从节点滞后,节点崩溃后没有数据丢失。
  • 热备份:故障转移期间无需停机(因为没有故障转移)。
  • 紧密耦合:所有节点持有相同的状态,不允许节点之间的数据分歧。
  • 自动节点配置:无需手动备份数据库并在新节点上还原。
  • 易于使用和部署。
  • 检测和自动驱逐不可靠的节点。
  • 基于认证的复制。

要在 Manticore Search 中设置复制:

  1. 必须在配置文件的 “searchd” 部分中设置 data_dir 选项。不支持在普通模式下进行复制。
  2. 必须指定一个包含其他节点可以访问的 IP 地址的 listen 指令,或者包含一个带有可访问 IP 地址的 node_address
  3. 可选地,您可以在每个集群节点上设置 server_id 的唯一值。如果没有设置值,节点将尝试使用 MAC 地址或随机数生成 server_id
  4. 如果没有设置复制的 listen 指令,Manticore 将在默认协议监听端口之后的 200 个端口范围内使用前两个空闲端口。要手动设置复制端口,必须定义 listen 指令(类型为复制)的端口范围,并且地址/端口范围对在同一服务器上的不同节点之间不能相交。作为经验法则,端口范围应该为每个集群指定至少两个端口。

复制集群

复制集群是在其中复制写事务的一组节点。复制是基于每个表进行设置的,这意味着一个表只能属于一个集群。集群可以拥有的表的数量没有限制。对属于该集群的任何 percolate 或实时表的任何 INSERT、REPLACE、DELETE、TRUNCATE 事务都会被复制到该集群中的所有其他节点。复制是多主的,因此对任何节点或多个节点的同时写入都可以正常工作。

要创建一个集群,通常可以使用 create cluster 命令,如 CREATE CLUSTER <cluster name>,要加入一个集群,可以使用 join cluster 命令,如 JOIN CLUSTER <cluster name> at 'host:port'。然而,在一些罕见的情况下,您可能希望微调 CREATE/JOIN CLUSTER 的行为。可用的选项有:

  • name: 此选项指定集群的名称。它应该在系统中的所有集群中是唯一的。

    注意:在 JOIN 命令的最大可允许的主机名长度为 253 个字符。如果超过此限制,searchd 将生成一个错误。

  • path: path 选项指定写集缓存复制和来自其他节点的入站表的数据目录。该值应该在系统中的所有集群中是唯一的,并且应该被指定为相对于 data_dir 目录的路径。默认情况下,它设置为 data_dir 的值。

  • nodes: nodes 选项是集群中所有节点的地址:端口对列表,用逗号分隔。此列表应该使用节点的 API 接口获得,并且可以包括当前节点的地址。它用于将节点加入集群,并在重新启动后重新加入。

  • options: options 选项允许您直接将其他选项传递给 Galera 复制插件,如 Galera 文档中所述。

插入语句

在使用复制集群时,所有修改集群表内容的写语句,如 INSERT、REPLACE、DELETE、TRUNCATE、UPDATE,必须使用 cluster_name:index_name 表达式,而不是表名。这确保更改被传播到集群中的所有副本。如果未使用正确的表达式,将触发错误。

在 HTTP 接口中,必须在所有写入语句到集群表的表名后设置 cluster 属性。未设置 cluster 属性将导致错误。

集群中表的自动 ID 应该在 server_id 正确配置的情况下有效。

PHP

  1. $index->addDocuments([
  2. 1, ['title' => 'iphone case', 'price' => 19.85]
  3. ]);
  4. $index->deleteDocument(1);

读取语句

读取语句,如 SELECT、CALL PQ、DESCRIBE,可以使用未附加集群名称的常规表名,也可以使用 cluster_name:index_name 格式。如果使用后者,将忽略 cluster_name 组件。

在使用 HTTP 端点 json/search 时,如果需要,可以指定 cluster 属性,但也可以省略。

JSON

  1. curl -sX POST http://localhost:9308/search -d '
  2. {
  3. "cluster":"posts",
  4. "index":"weekly_index",
  5. "query":{"match":{"title":"keyword"}}
  6. }'

集群参数

可以使用 SET 语句调整复制插件选项。

可以在 Galera 文档的参数中找到可用选项的列表。

JSON

  1. curl -sX POST http://localhost:9308/cli -d "
  2. SET CLUSTER click_query GLOBAL 'pc.bootstrap' = 1
  3. "

具有分歧节点的集群

复制节点可能出现分歧,导致所有节点都被标记为非主节点的状态。这可能是由于节点之间的网络分裂、集群崩溃,或者如果复制插件在确定主要组件时遇到异常引起的。在这种情况下,有必要选择一个节点并将其晋升为主要组件的角色。

要确定需要晋升的节点,应该比较所有节点上的 last_committed 集群状态变量值。如果所有服务器当前正在运行,就无需重新启动集群。相反,可以使用 SET 语句简单地将 last_committed 值最高的节点晋升为主要组件(如示例所示)。

其他节点将随后重新连接到主要组件,并根据该节点重新同步其数据。

JSON

  1. curl -sX POST http://localhost:9308/cli -d "
  2. SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1
  3. "

复制和集群

要使用复制,您需要在配置文件中为 SphinxAPI 协议定义一个侦听端口和一个复制地址的侦听端口范围。还要指定 data_dir 文件夹以接收传入的表。

  1. searchd {
  2. listen = 9312
  3. listen = 192.168.1.101:9360-9370:replication
  4. data_dir = /var/lib/manticore/
  5. ...
  6. }

复制表格,您必须在具有要复制的本地表格的服务器上创建一个集群。

  1. $params = [
  2. 'cluster' => 'posts'
  3. ]
  4. ];
  5. $response = $client->cluster()->create($params);

将这些本地表格添加到集群中。

  1. $params = [
  2. 'cluster' => 'posts',
  3. 'body' => [
  4. 'operation' => 'add',
  5. 'index' => 'pq_title'
  6. ]
  7. ];
  8. $response = $client->cluster()->alter($params);
  9. $params = [
  10. 'cluster' => 'posts',
  11. 'body' => [
  12. 'operation' => 'add',
  13. 'index' => 'pq_clicks'
  14. ]
  15. ];
  16. $response = $client->cluster()->alter($params);

所有希望接收集群表格副本的其他节点应按以下方式加入集群:

  1. $params = [
  2. 'cluster' => 'posts',
  3. 'body' => [
  4. '192.168.1.101:9312'
  5. ]
  6. ];
  7. $response = $client->cluster->join($params);

在运行查询时,请在表名前加上集群名称 “posts:”,或者在 HTTP 请求对象中使用 cluster 属性。

  1. $index->addDocuments([
  2. 3, ['title' => 'test me']
  3. ]);

现在,对集群中的表进行的所有修改查询都会被复制到集群中的所有节点。

复制集群

要创建一个复制集群,至少必须设置其名称。

如果您正在创建单个集群或第一个集群,可以省略路径选项。在这种情况下,将使用 data_dir 选项作为集群路径。然而,对于所有后续的集群,必须指定路径并确保该路径可用。还可以设置节点选项以列出集群中的所有节点。

  1. $params = [
  2. 'cluster' => 'posts',
  3. ]
  4. ];
  5. $response = $client->cluster()->create($params);
  6. $params = [
  7. 'cluster' => 'click_query',
  8. 'body' => [
  9. 'path' => '/var/data/click_query/'
  10. ]
  11. ]
  12. ];
  13. $response = $client->cluster()->create($params);
  14. $params = [
  15. 'cluster' => 'click_query',
  16. 'body' => [
  17. 'path' => '/var/data/click_query/',
  18. 'nodes' => 'clicks_mirror1:9312,clicks_mirror2:9312,clicks_mirror3:9312'
  19. ]
  20. ]
  21. ];
  22. $response = $client->cluster()->create($params);

如果在创建集群时未指定节点选项,则加入集群的第一个节点将被保存为节点选项。

加入集群

要加入一个现有的集群,您必须至少指定:

  1. 集群的名称。
  2. 您要加入的集群中另一节点的主机:端口。
  1. $params = [
  2. 'cluster' => 'posts',
  3. 'body' => [
  4. '10.12.1.35:9312'
  5. ]
  6. ];
  7. $response = $client->cluster->join($params);

在大多数情况下,上述操作对于单个复制集群就足够了。然而,如果您要创建多个复制集群,还必须设置路径并确保目录是可用的。

  1. JOIN CLUSTER c2 at '127.0.0.1:10201' 'c2' as path

节点通过从指定节点获取数据并在成功时更新所有其他集群节点上的节点列表来加入集群,这与通过 ALTER CLUSTER … UPDATE nodes 手动完成的方式相同。这个列表用于在重新启动时重新加入节点到集群。

有两个节点列表:

  1. cluster_<name>_nodes_set:用于在重新启动时重新加入节点到集群。它会在所有节点上像 ALTER CLUSTER … UPDATE nodes 一样更新。JOIN CLUSTER 命令会自动执行此更新。集群状态将此列表显示为 cluster_<name>_nodes_set
  2. cluster_<name>_nodes_view:此列表包含所有用于复制的活动节点,无需手动管理。ALTER CLUSTER … UPDATE nodes 实际上会将此节点列表复制到重新启动时重新加入的节点列表中。集群状态将此列表显示为 cluster_<name>_nodes_view

当节点位于不同的网络段或数据中心时,可以显式设置 nodes 选项。这样可以最小化节点之间的流量,并利用网关节点在数据中心之间进行通信。以下代码使用 nodes 选项加入现有的集群。

注意:使用此语法时,cluster_<name>_nodes_set 列表不会自动更新。要进行更新,请使用 ALTER CLUSTER … UPDATE nodes。

  1. $params = [
  2. 'cluster' => 'posts',
  3. 'body' => [
  4. 'nodes' => 'clicks_mirror1:9312;clicks_mirror2:9312;clicks_mirror3:9312'
  5. ]
  6. ];
  7. $response = $client->cluster->join($params);

JOIN CLUSTER 命令是同步执行的,并且在节点从集群中的其他节点接收到所有数据并与它们同步后立即完成。

删除集群

DELETE CLUSTER 语句会删除指定名称的集群。一旦集群被删除,它将从所有节点中移除,但其表保持不变,并变为活动的本地非复制表。

  1. $params = [
  2. 'cluster' => 'click_query',
  3. 'body' => []
  4. ];
  5. $response = $client->cluster()->delete($params);

从集群中新增或者删除表

ALTER CLUSTER <cluster_name> ADD <table_name> 将现有的本地表添加到集群中。接收 ALTER 查询的节点将表发送到集群中的其他节点。集群其他节点上具有相同名称的所有本地表都将替换为新表。

一旦表被复制,就可以在任何节点上执行写入语句,但表名必须以集群名称为前缀,如 INSERT INTO <clusterName>:<table_name>

  1. $params = [
  2. 'cluster' => 'click_query',
  3. 'body' => [
  4. 'operation' => 'add',
  5. 'index' => 'clicks_daily_index'
  6. ]
  7. ];
  8. $response = $client->cluster()->alter($params);

ALTER CLUSTER <cluster_name> DROP <table_name> 可以将一个本地表从集群中移除。这并不会删除节点上的表文件,而只是使其成为一个非活动、非复制的表。

一旦从集群中移除表,它就变成了一个本地表,写入语句必须只使用表名,例如 INSERT INTO <table_name>,不需要集群前缀。

  1. $params = [
  2. 'cluster' => 'posts',
  3. 'body' => [
  4. 'operation' => 'drop',
  5. 'index' => 'weekly_index'
  6. ]
  7. ];
  8. $response = $client->cluster->alter($params);

管理复制节点

ALTER CLUSTER <cluster_name> UPDATE nodes 语句会更新指定集群中每个节点上的节点列表,以包括集群中的所有活动节点。有关节点列表的更多信息,请参见加入集群。

  1. $params = [
  2. 'cluster' => 'posts',
  3. 'body' => [
  4. 'operation' => 'update',
  5. ]
  6. ];
  7. $response = $client->cluster()->alter($params);

例如,当最初建立集群时,用于重新加入集群的节点列表是 10.10.0.1:9312,10.10.1.1:9312。从那时起,其他节点加入了集群,现在活动节点是 10.10.0.1:9312,10.10.1.1:9312,10.15.0.1:9312,10.15.0.3:9312。然而,用于重新加入集群的节点列表尚未更新。

要纠正这个问题,您可以运行 ALTER CLUSTER ... UPDATE nodes 语句,将活动节点的列表复制到用于重新加入集群的节点列表中。之后,用于重新加入集群的节点列表将包括集群中的所有活动节点。

可以使用 Cluster 状态语句查看两个节点列表(cluster_post_nodes_setcluster_post_nodes_view)。

从集群中删除节点

要从复制集中删除节点,请按照以下步骤进行:

  1. 停止节点。
  2. 从已停止的节点的 <data_dir>/manticore.json 文件(通常是 /var/lib/manticore/manticore.json)中删除有关集群的信息。
  3. 在任何其他节点上运行 ALTER CLUSTER cluster_name UPDATE nodes

完成这些步骤后,其他节点将忘记已分离的节点,而分离的节点也将忘记有关集群的信息。此操作不会影响集群中的表或分离节点上的表。

复制集群状态

您可以通过检查节点状态来查看集群状态信息。这可以通过使用节点状态命令来完成,该命令显示有关节点的各种信息,包括集群状态变量。

集群状态变量的输出格式如下:cluster_name_variable_name variable_value。大多数变量在Galera文档状态变量中有描述。除了这些变量之外,Manticore Search还显示:

  • cluster_name - 复制设置中定义的集群名称
  • node_state - 节点的当前状态:closed(关闭),destroyed(已销毁),joining(正在加入),donor(捐赠者),synced(同步)
  • indexes_count - 集群管理的表的数量
  • indexes - 集群管理的表名列表
  • nodes_set - 使用CREATE、JOIN或ALTER UPDATE命令定义的集群中的节点列表
  • nodes_view - 当前节点可以看到的集群中的实际节点列表。
  1. $params = [
  2. 'body' => []
  3. ];
  4. $response = $client->nodes()->status($params);

重启集群

在多主复制集群中,必须在其他节点可以加入并形成集群之前建立一个参考点。这称为集群引导,涉及启动单个节点作为主要组件。可以正常地重启单个节点或在关闭后重新连接。

在完全关闭集群的情况下,应该首先启动最后停止的服务器,并使用—new-cluster命令行选项或通过运行manticore_new_cluster通过systemd。为了确保该服务器能够成为参考点,应更新位于集群路径下的grastate.dat文件,将safe_to_bootstrap选项的值更新为1。必须满足—new-cluster和safe_to_bootstrap=1这两个条件。如果启动了任何其他节点而没有设置这些选项,将发生错误。可以使用—new-cluster-force命令行选项来覆盖此保护并强制从另一台服务器启动集群。或者,您可以运行manticore_new_cluster —force以使用systemd。

在发生严重崩溃或集群中所有服务器发生非正常关闭的情况下,必须识别grastate.dat文件中位于集群路径下的具有最大seqno的最先进的节点,并使用—new-cluster-force命令行键启动它。

集群恢复

如果Manticore搜索守护程序停止,且集群中没有剩余节点来提供请求,就需要进行恢复。由于复制使用的Galera库的多主性质,Manticore复制集群是一个维护其节点和数据一致性以及整个集群状态的单一逻辑实体。这允许在多个节点上同时进行安全写入,并确保集群的完整性。

然而,这也带来了一些挑战。让我们使用节点A、B和C的集群来考虑一些场景,看看在一些或所有节点变得不可用时需要做什么。

情况1

当停止节点A时,其他节点会收到“正常关闭”消息。集群大小减小,进行仲裁重新计算。

启动节点A时,它加入集群,并在完全与集群同步之前不会提供任何写事务。如果捐赠节点B或C上的写入集缓存(可以使用Galera集群的gcache.size控制)仍包含节点A错过的所有事务,则节点A将接收到快速增量状态传输(IST),即仅传输错过的事务。如果没有,将发生快照状态传输(SST),涉及传输表文件。

情况2

在节点A和B都停止的情况下,集群大小减小到一个,节点C形成主要组件来处理写事务。

然后可以像往常一样启动节点A和B,它们将在启动后加入集群。节点C作为捐赠者,为节点A和B提供状态传输。

情况3

所有节点像往常一样停止,集群关闭。

现在的问题是如何初始化集群。重要的是,在searchd正常关闭时,节点将最后执行的事务数写入集群目录grastate.dat文件,同时写入标志safe_to_bootstrap。最后停止的节点将具有safe_to_bootstrap: 1和最先进的seqno编号。

重要的是首先启动此节点以形成集群。要引导集群,应在此节点上使用—new-cluster命令行标志启动服务器。在Linux上,您还可以运行manticore_new_cluster,它将通过systemd以—new-cluster模式启动Manticore。

如果另一个节点首先启动并引导了集群,那么最先进的节点将加入该集群,执行完整的SST,并接收包含与之前获得的表文件相比缺少的某些事务的表文件。这就是为什么重要的是首先启动最后关闭的节点,它应该在grastate.dat中具有safe_to_bootstrap: 1的标志。

情况4

由于崩溃或网络故障导致节点A从集群中消失,节点B和C将尝试重新连接到节点A。失败后,它们将从集群中删除节点A。在三个节点中仍有两个运行时,集群保持其仲裁,并继续正常运行。

当重新启动节点A时,它将自动加入集群,如情况1所述。

情况5

节点A和B已经离线。节点C无法独自形成仲裁,因为1个节点少于总节点数(3)。结果,节点C上的集群转移到非主要状态,并拒绝任何写事务,显示错误消息。

与此同时,节点C等待其他节点连接,并尝试连接到它们。如果发生这种情况,网络恢复,节点A和B重新在线,集群将自动重新形成。如果节点A和B只是暂时从节点C断开连接但仍然可以彼此通信,它们将继续正常运行,因为它们仍然形成仲裁。

然而,如果节点A和B都崩溃或由于电源故障而重新启动,则必须使用以下命令在节点C上激活主要组件:

  1. curl -sX POST http://localhost:9308/cli -d "
  2. SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1
  3. "

重要的是在执行此命令之前,必须确认其他节点确实无法访问。否则,可能会发生脑裂情景,形成分开的集群。

情况6

所有节点都已崩溃。在这种情况下,集群目录中的grastate.dat文件尚未更新,不包含有效的seqno序列号。

如果发生这种情况,必须有人找到具有最新数据的节点,并使用—new-cluster-force命令行键在其上启动服务器。所有其他节点将像在情况3中描述的那样正常启动。在Linux上,还可以使用manticore_new_cluster —force命令,它将通过systemd以—new-cluster-force模式启动Manticore。

情况7

脑裂可能导致集群转移到非主要状态。例如,考虑由偶数节点(四个节点)组成的集群,例如位于不同数据中心的两对节点。如果网络故障中断了数据中心之间的连接,脑裂就会发生,因为每组节点恰好持有仲裁的一半。因此,由于Galera复制模型优先考虑数据一致性,并且在没有仲裁的情况下,集群无法接受写事务,因此两个组都停止处理写事务。然而,两个组中的节点都试图重新连接到另一组的节点,以恢复集群。

如果有人想在网络恢复之前恢复集群,则应采取情况5中概述的相同步骤,但仅在一组节点上执行。

执行该语句后,具有在其上运行的节点的组将能够再次处理写事务。

  1. curl -sX POST http://localhost:9308/cli -d "
  2. SET CLUSTER posts GLOBAL 'pc.bootstrap' = 1
  3. "