1.Redis 集群 metainfo.xml
示例
<?xml version="1.0"?>
<metainfo>
<schemaVersion>2.0</schemaVersion>
<services>
<service>
<!-- Redis 集群服务的基本信息 -->
<name>REDIS</name>
<displayName>Redis</displayName>
<comment>
Component Redis Power By JaneTTR . mail: 3832514048@qq.com ,git: https://gitee.com/tt-bigdata/ambari-env
</comment>
<version>7.4.0</version>
<!-- Redis 集群组件定义 -->
<components>
<!-- Redis 主节点组件 -->
<component>
<name>REDIS_MASTER</name>
<displayName>Redis Master</displayName>
<category>MASTER</category>
<cardinality>3+</cardinality> <!-- Redis 集群至少需要 3 个主节点 -->
<versionAdvertised>true</versionAdvertised>
<commandScript>
<script>scripts/redis_master.py</script> <!-- Python 脚本 -->
<scriptType>PYTHON</scriptType>
</commandScript>
</component>
<!-- Redis 从节点组件 -->
<component>
<name>REDIS_SLAVE</name>
<displayName>Redis Slave</displayName>
<category>SLAVE</category>
<cardinality>3+</cardinality> <!-- 从节点可以是 0 或多个 -->
<versionAdvertised>true</versionAdvertised>
<commandScript>
<script>scripts/redis_slave.py</script> <!-- Python 脚本 -->
<scriptType>PYTHON</scriptType>
</commandScript>
</component>
<!-- Redis 客户端组件 -->
<component>
<name>REDIS_CLIENT</name>
<displayName>Redis Client</displayName>
<category>CLIENT</category>
<cardinality>0+</cardinality> <!-- 客户端是可选的,可以部署多个 -->
<versionAdvertised>true</versionAdvertised>
<commandScript>
<script>scripts/redis_client.py</script> <!-- Python 脚本 -->
<scriptType>PYTHON</scriptType>
</commandScript>
<configFiles>
<configFile>
<type>xml</type>
<fileName>redis-site.xml</fileName>
<dictionaryName>redis-site</dictionaryName>
</configFile>
<configFile>
<type>xml</type>
<fileName>redis-env.sh</fileName>
<dictionaryName>redis-env</dictionaryName>
</configFile>
</configFiles>
</component>
</components>
<!-- 操作系统相关 -->
<osSpecifics>
<osSpecific>
<osFamily>any</osFamily> <!-- 支持任何操作系统 -->
<packages>
<package>
<name>redis_${stack_version}</name>
</package>
</packages>
</osSpecific>
</osSpecifics>
<!-- Redis 服务健康检查 -->
<commandScript>
<script>scripts/service_check.py</script> <!-- 健康检查 Python 脚本 -->
<scriptType>PYTHON</scriptType>
<timeout>300</timeout>
</commandScript>
<!-- Redis 服务不依赖其他服务 -->
<!-- 如果有其他依赖项,可以在这里定义 -->
<!-- 配置依赖 -->
<configuration-dependencies>
<config-type>redis-site</config-type>
<config-type>redis-env</config-type>
</configuration-dependencies>
</service>
</services>
</metainfo>
在这个文件中,我们定义了 Redis 集群的三个关键组件: Redis Master、Redis Slave 和 Redis Client。这些组件由 Python 脚本控制,它们的详细定义帮助 Ambari 在集群中进行服务管理。
在 Ambari 的配置和管理中,metainfo.xml
文件是定义服务、组件及其依赖关系的核心。通过对 cardinality
和 category
的精准定义,我们可以确保集群中的组件以预期的方式部署,并符合高可用性要求。
2. cardinality
和 category
的作用 📂
在 metainfo.xml
文件中,category
和 cardinality
是两个核心属性。category
定义了组件的角色,比如 MASTER
、CLIENT
,而 cardinality
则控制组件的实例数量及部署要求。接下来,我们将深入探讨这两个属性。
2.1 cardinality
的作用 🎯
cardinality
属性定义了一个组件在集群中必须部署的 数量要求。它确保集群能够正确部署并符合高可用性等重要系统要求。
2.1.1 定义角度分析
常见的 cardinality
值有以下几种类型:
- 1:表示该组件在集群中只能有 1 个实例,适用于唯一性组件,例如数据库主节点。
- 1+:表示该组件至少需要 1 个实例,但可以有多个实例,适合扩展性服务,如负载均衡器。
- 0+:表示该组件是可选的,可能没有实例或有多个实例,常用于客户端组件,如
Redis Client
。 - 3+:表示该组件至少需要 3 个实例,通常用于高可用性场景,如
Redis Master
,确保集群的健壮性和可扩展性。
例如,在 Redis 集群的 metainfo.xml
文件中,我们为 Redis Master 设置了 cardinality: 3+
,这意味着集群中必须至少部署 3 个 Redis 主节点,确保系统的高可用性和数据安全性。
值的定义 | 描述 | 示例 |
---|---|---|
精确值 | exact: 表示组件的确切数量 | <cardinality>3</cardinality> <cardinality>1</cardinality> |
最小值 | min: 表示组件的最小数量要求 | <cardinality>1-3</cardinality> <cardinality>3+</cardinality> |
最大值 | max: 表示组件的最大数量要求 | <cardinality>1-3</cardinality> <cardinality>3-9</cardinality> |
是否所有 | ALL: 表示组件需要在所有节点上部署 | <cardinality>ALL</cardinality> |
2.1.2 代码实现 🧑💻
cardinality
在代码中的实现由 Java 类 Cardinality
负责,它会根据 metainfo.xml
中的配置对组件的部署进行严格校验。通过判断 cardinality
的不同值类型,我们可以设置最小值 min
、最大值 max
,以及确切的部署数量 exact
。
package org.apache.ambari.server.topology;
/**
* Component cardinality representation.
*/
public class Cardinality {
String cardinality;
int min = 0;
int max = Integer.MAX_VALUE;
int exact = -1;
boolean isAll = false;
// 核心参数-------核心中的核心 请往这里看👀
// 核心参数-------核心中的核心 请往这里看👀
public Cardinality(String cardinality) {
this.cardinality = cardinality;
if (cardinality != null && ! cardinality.isEmpty()) {
if (cardinality.contains("+")) {
min = Integer.parseInt(cardinality.split("\\+")[0]);
} else if (cardinality.contains("-")) {
String[] toks = cardinality.split("-");
min = Integer.parseInt(toks[0]);
max = Integer.parseInt(toks[1]);
} else if (cardinality.equals("ALL")) {
isAll = true;
} else {
exact = Integer.parseInt(cardinality);
}
}
}
// 核心参数-------核心中的核心 请往这里看👀
// 核心参数-------核心中的核心 请往这里看👀
}
在这段代码中,cardinality
的定义被解析为不同的类型,比如 3+
表示最少 3 个实例,1-3
表示部署的实例数在 1 到 3 之间,ALL
表示所有节点都必须部署该组件。
Java 端主要负责将配置文件中的 cardinality
属性加载和校验其合规性,而实际的验证则由 Python 脚本执行。
2.1.3 Python 验证逻辑 🧑💻
在 Python 部分,getComponentLayoutValidations
方法会根据 cardinality
的配置对集群的实际部署进行校验。这个方法位于 StackAdvisor
子类中,例如 BIGTOP320StackAdvisor
。
def getComponentLayoutValidations(self, services, hosts):
# Validating cardinality
for component in componentsList:
if component["StackServiceComponents"]["cardinality"] is not None:
componentName = component["StackServiceComponents"]["component_name"]
componentDisplayName = component["StackServiceComponents"]["display_name"]
componentHosts = []
if component["StackServiceComponents"]["hostnames"] is not None:
componentHosts = [componentHost for componentHost in component["StackServiceComponents"]["hostnames"] if componentHost in hostsSet]
componentHostsCount = len(componentHosts)
cardinality = str(component["StackServiceComponents"]["cardinality"])
# cardinality types: null, 1+, 1-2, 1, ALL
message = None
# 核心参数-------核心中的核心 请往这里看👀
# 核心参数-------核心中的核心 请往这里看👀
if "+" in cardinality:
hostsMin = int(cardinality[:-1])
if componentHostsCount < hostsMin:
message = "At least {0} {1} components should be installed in cluster.".format(hostsMin, componentDisplayName)
elif "-" in cardinality:
nums = cardinality.split("-")
hostsMin = int(nums[0])
hostsMax = int(nums[1])
if componentHostsCount > hostsMax or componentHostsCount < hostsMin:
message = "Between {0} and {1} {2} components should be installed in cluster.".format(hostsMin, hostsMax, componentDisplayName)
elif "ALL" == cardinality:
if componentHostsCount != hostsCount:
message = "{0} component should be installed on all hosts in cluster.".format(componentDisplayName)
else:
if componentHostsCount != int(cardinality):
message = "Exactly {0} {1} components should be installed in cluster.".format(int(cardinality), componentDisplayName)
if message is not None:
items.append({"type": 'host-component', "level": 'ERROR', "message": message, "component-name": componentName})
该方法会检查 cardinality
配置的要求,并根据实际部署的主机数量进行比对,生成错误或成功消息。比如,如果组件 cardinality
设置为 3+
,而实际部署了 2 个实例,系统会返回相应的错误信息。
2.2 从请求到验证的流程详解 🛠️
通过一个实际的 API 请求,我们可以详细分析整个验证流程,看看 Ambari 如何验证 cardinality
的配置。
⬇️⬇️⬇️查看全部内容⬇️⬇️⬇️
查看全部内容,更多详细内容请关注我们的微信公众号:发送"文章"关键字获取
或加入QQ1群,了解版本动向,解答大数据问题。
⬆️⬆️⬆️查看全部内容⬆️⬆️⬆️
当验证逻辑完成后,Ambari 将会返回一个包含验证结果的响应,说明每个组件的部署情况和潜在的错误。
{
"resources": [
{
"items": [
{
"level": "ERROR",
"host": "centos3",
"type": "host-component",
"message": "Host is not used"
},
{
"component-name": "ZOOKEEPER_CLIENT",
"level": "ERROR",
"type": "host-component",
"message": "At least 1 ZooKeeper Client components should be installed in cluster."
}
]
}
]
}
这个响应中显示了 ZooKeeper Client
组件未能满足 1+
的 cardinality
要求,因此系统返回了错误信息。
2.3 结合Redis场景说明
<component>
<name>REDIS_MASTER</name>
<displayName>Redis Master</displayName>
<category>MASTER</category>
<cardinality>3+</cardinality> <!-- 至少需要 3 个主节点 -->
<versionAdvertised>true</versionAdvertised>
<commandScript>
<script>scripts/redis_master.py</script>
<scriptType>PYTHON</scriptType>
</commandScript>
</component>
在上面的例子中,cardinality
被定义为 3+
,表示 Redis 主节点在集群中必须至少有 3 个实例。