【成神之路】Ambari实战-014-代码生命周期-metainfo-cardinality详解

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 MasterRedis SlaveRedis Client。这些组件由 Python 脚本控制,它们的详细定义帮助 Ambari 在集群中进行服务管理。

在 Ambari 的配置和管理中,metainfo.xml 文件是定义服务、组件及其依赖关系的核心。通过对 cardinalitycategory 的精准定义,我们可以确保集群中的组件以预期的方式部署,并符合高可用性要求。


2. cardinalitycategory 的作用 📂

metainfo.xml 文件中,categorycardinality 是两个核心属性。category 定义了组件的角色,比如 MASTERCLIENT,而 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 个实例。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值