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 cardinalityfor 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, ALLmessage = 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 个实例。