当前位置: 首页 > 工具软件 > Apache Helix > 使用案例 >

集群管理和分布式任务 Apache helix 抽象模型

钮博裕
2023-12-01

apache helix是一个通用的集群管理框架,既能做分布式task,也能做分布式存储,还可以做服务发现,分布式锁等,大大简化了你系统的设计,分布式系统开发过程中,一些通用的部分,它全部给你抽象实现,基于zookeeper。

那么既然是通用,那么必须要高度抽象,只有理解了抽象出来的几个概念,我们才能更好地读懂它的实现和设计原理,ok废话不多说了,撸一把。

假如我们要设计分布式task系统,那么对于一个task,有两个基本的属性,一个是位置,一个是状态。同样对于分布式存储,一个partition或者region也有位置和状态,同时,这种有位置和状态属性的东西,可以统一抽象成资源,资源分布式化,因此需要有一种平衡的理想状态。

Ideal State

"TASK_NAME" : {
  "LOCATION" : "STATE"
}

如果你希望在N1上启动myTask,那么理想状态也可以描述成这样:

{
  "id" : "MyTask",
  "mapFields" : {
    "myTask" : {
      "N1" : "ONLINE",
    }
  }
}

Partition

分区,分区概念一般在消息系统上比较常见,比如kafka,每个topic有多个partition;对于分布式task来讲,如果一个task单机单进程搞不定,那么可以映射成子任务,这种子任务,你可以理解成storm作业的spout,bolt task,那么这种东西,统一抽象成partition,代表最小的资源颗粒。

"myTask_0", "myTask_1", "myTask_2" 运行在N1, N2 和 N3 上,那么理想状态描述成下面这样,其实这里helix的理想状态就相当于storm里的每个topology的assignment,即任务分配细节。

{
  "id" : "myTask",
  "simpleFields" : {
    "NUM_PARTITIONS" : "3",
  }
 "mapFields" : {
    "myTask_0" : {
      "N1" : "ONLINE",
    },
    "myTask_1" : {
      "N2" : "ONLINE",
    },
    "myTask_2" : {
      "N3" : "ONLINE",
    }
  }
}

Replica

Partitioning是说将任务或者数据分成更细粒度地分片,然后通常为了可用性,每个分片还有多个副本。这种例子到处都是,hdfs的文件由很多block组成,每个block又有三个或者多个副本;storm作业每个task都有并发度,当然jstorm的并发度是不是task副本的概念,要看grouping的方;elasticsearch的索引文件,同样有多个副本。

helix 统一将这种分片的副本或者备份,称之为replica,了解hdfs的同学,很容易理解这种概念。那么这种情况下,资源的assignment就是这样子。

{
  "id" : "myIndex",
  "simpleFields" : {
    "NUM_PARTITIONS" : "3",
    "REPLICAS" : "2",
  },
 "mapFields" : {
    "myIndex_0" : {
      "N1" : "ONLINE",
      "N2" : "ONLINE"
    },
    "myIndex_1" : {
      "N2" : "ONLINE",
      "N3" : "ONLINE"
    },
    "myIndex_2" : {
      "N3" : "ONLINE",
      "N1" : "ONLINE"
    }
  }
}

State

状态,这种例子也很多,比如zookeeper,每个节点分为leader和follow;kafka的partition也区分master,slave;hdfs在做block recovery的时候,也要持有副本的datanode选举出master和slave,即解决一致性的问题,副本之间通常要选出来一个master负责接收请求,再同步给其它slave。

比如我用helix组织mysql实例做一个mysql集群,一个数据库做主备,那么assignment(idea state)是这样子:

{
  "id" : "myDB",
  "simpleFields" : {
    "NUM_PARTITIONS" : "1",
    "REPLICAS" : "2",
  },
  "mapFields" : {
    "myDB" : {
      "N1" : "MASTER",
      "N2" : "SLAVE",
    }
  }
}

State Machine and Transitions

状态机和状态转换,这个基本上是failover的东西,即容灾,资源做好了ideastate那么helix就会想办法达成这种状态,类似storm里的assignment,mkAssignment之后,就要调度分配槽位,执行task。helix在一个集群中有一个controller的角色,它相当于storm里的nimbus,或者hbase里的hbasemaster,负责状态转换等,目的就是为了让集群,让你的资源达到这种ideastate。

问题是controller怎么知道应该怎么做?这就需要有一个状态机,第一次接触状态机是在yarn里,后来jstorm中nimbus也有一个状态机,那么状态转换关系提前定制好,controller自然就能计算出,下一步应该怎么走,因此,helix需要用户提前定义好状态机

MasterSlave ,最简单的状态机模型示例:

OFFLINE  | SLAVE  |  MASTER
         _____________________________
        |          |        |         |
OFFLINE |   N/A    | SLAVE  | SLAVE   |
        |__________|________|_________|
        |          |        |         |
SLAVE   |  OFFLINE |   N/A  | MASTER  |
        |__________|________|_________|
        |          |        |         |
MASTER  | SLAVE    | SLAVE  |   N/A   |
        |__________|________|_________|

Helix 支持灵活的状态机配置,一种资源配一个状态机,因此在同一个集群中,其实可以有多种资源,多个状态机,你想在一个集群中管理一个数据库,同时再管理一个索引存储系统,也是可以的:

Current State

CurrentState 用于表示一个节点,即分布式系统的一个node的当前状态,比如storm里的supervisor的心跳信息,里面包括机器名,槽位名,运行的拓扑,taskid等信息,下面的例子是说node1这个节点持有的资源 ,以及资源的状态。

{
  "id":"MyResource"
  ,"simpleFields":{
    ,"SESSION_ID":"13d0e34675e0002"
    ,"INSTANCE_NAME":"node1"
    ,"STATE_MODEL_DEF":"MasterSlave"
  }
  ,"mapFields":{
    "MyResource_0":{
      "CURRENT_STATE":"SLAVE"
    }
    ,"MyResource_1":{
      "CURRENT_STATE":"MASTER"
    }
    ,"MyResource_2":{
      "CURRENT_STATE":"MASTER"
    }
  }
}

集群的每个节点都有自己的currentstate,节点,在helix里称为participants。

External View

helix把集群客户端称为spectators,相当于storm里的nimbusclient,比如storm用户想看到我的作业分配情况,其实获取assignment就行了,ExternalView其实跟ideastate结构类似,只不过数据结构更加简单,专门暴露给客户端的数据结构,叫做ExternalView

{
  "id":"MyResource",
  "mapFields":{
    "MyResource_0":{
      "N1":"SLAVE",
      "N2":"MASTER",
      "N3":"OFFLINE"
    },
    "MyResource_1":{
      "N1":"MASTER",
      "N2":"SLAVE",
      "N3":"ERROR"
    },
    "MyResource_2":{
      "N1":"MASTER",
      "N2":"SLAVE",
      "N3":"SLAVE"
    }
  }
}

Rebalancer

rebalance也比较容易理解,集群资源分布不均,或者task分布不均,可能导致热点问题;存储里面比较容易理解,分布式计算的rebalance 有时候可能指作业task的重新调度,helix在节点从起,stop,软件硬件错误,集群新增节点,配置变更,或者idea state发生变化的时候,helix controller模块会触发rebalance


rebalance算法简单说做三个事情:

  • 比较当前状态currentstate和ideastate,
  • 走状态机流程,计算应该怎样transition
  • 通告节点执行transition
rebalance的目标是达到 'IdealState = CurrentState = ExternalView'的状态

Dynamic IdealState

动态idealstate其实就是支持动态调整资源的状态,这很重要,helix可以感知集群变化,然后动态调整idealstate,同时触发rebalance

helix支持三种方式实现动态调整idealstate

  • FULL_AUTO:全自动,根据约束条件,helix自动调整
  • SEMI_AUTO: 半自动,这种情况下需要用户提供一个期望的idealstate信息,helix会超这个状态rebalance
  • CUSTOMIZED: 完全用户定制,这种方式,相当于jstorm里的指定supervisor调度


 类似资料: