|
|
|
联系客服020-83701501

通过Mesos、Docker和Go,使用300行代码创建一个分布

联系在线客服,可以获得免费在线咨询服务。 QQ咨询 我要预约
经过Mesos、Docker和Go,应用三00行代码竖立1个分布式系统

建立1个分布式系统是很困难的。它必要可扩充性、容错性、高可用性、1致性、可伸缩以及高效。为了达到这些目的,分布式系统必要许多繁冗的组件以1 种繁冗的行动协同义务。比方,Apache?Hadoop在大型集群上并行处理TB级此外数据集时,必要依靠有着高容错的文件系统(HDFS)来达到高吞 吐量。

在曩昔,每1个新的分布式系统,比方Hadoop和Cassandra,都必要建立本身的底层架构,收罗消息处理、存储、网络、容错 性和可伸缩性。光荣的是,像Apache?Mesos何等的系统,经过给分布式系统的关头建立模块提供相同把持系统的经管处事,简化了建立和经管分布式系 统的义务。Mesos抽离了CPU、存储和其它算计利润,因而开拓者开拓分布式垄断步调时也许将整个数据核心集群当做1台巨型机对待。

建立 在Mesos上的垄断步调被称为框架,它们能意图许多题目:Apache?Spark,1种风靡的集群式数据阐发东西;Chronos,1个相同cron 的存在容错性的分布式scheduler,这是两个建立在Mesos上的框架的例子。建立框架大概应用多种措辞,收罗 C++,Go,Python,Java,Haskell和?Scala。

在分布式系统用例上,比特币开采就是1个很好的例子。比特币将为生 成?acceptable?hash?的挑衅转为考证1块事件的可靠性。大概或许必要几十年,单台条记本电脑挖1块大概或许必要耗费超过150年。结果是,有许多 的“采矿池”许诺采矿者将他们的算计利润拆散起来以放慢挖矿速度。Mesosphere的1个操演生,Derek,写了1个比特币开采框架 (https://github.com/derekchiang/Mesos-Bitcoin-Miner),操作集群利润的优势来做同样的事变。在接 上去的内容中,会以他的代码为例。

1个Mesos框架有1个scheduler?和1个executor造成。scheduler?和 Mesos?master通信并选择运转甚么义务,而executor?运转在slaves上面,实行理论义务。大少数的框架实现了本身的 scheduler,并应用1个由Mesos提供的规范executors。固然,框架也大概本身定制executor。在这个例子中即会编写定制的 scheduler,并应用规范呼吁实行器(executor)运转包含咱们比特币处事的Docker镜像。

对这里的scheduler来 说,必要运转的有两种义务——one?miner?server?task?and?multiple?miner?worker?tasks。 server会和1个比特币采矿池通信,并给每个worker分派blocks。Worker会努力义务,即开采比特币。

义务理论上被封装 在executor框架中,因而义务运转象征着陈说Mesos?master在此中1个slave上面发动1个executor。由于这里应用的是规范命 令实行器(executor),因而大概指定义务是2进制可实行文件、bash脚本或许此外呼吁。由于Mesos反对Docker,因而在本例中将应用可 实行的Docker镜像。Docker是何等1种技能,它许诺你将垄断步调和它运转时必要的依靠1起打包。

为了在Mesos中应用Docker镜像,这里必要在Docker?registry中注册它们的称呼:

Default
12三4 const (    MinerServerDockerImage = "derekchiang/p2pool"    MinerDaemonDockerImage = "derekchiang/cpuminer")

而后定义1个常量,指定每个义务所需利润:

Default
12三45 const (    MemPerDaemonTask = 12八  // mining shouldn't be memory-intensive    MemPerServerTask = 256    CPUPerServerTask = 1    // a miner server does not use much CPU)

此刻定义1个真正的scheduler,对其跟踪,并确保其准确运转必要的形态:

Default
12三4567八91011121三14 type MinerScheduler struct {    // bitcoind RPC credentials    bitcoindAddr string    rpcUser      string    rpcPass      string    // mutable state    minerServerRunning  bool    minerServerHostname string     minerServerPort     int    // the port that miner daemons                                // connect to    // unique task ids    tasksLaunched        int    currentDaemonTaskIDs []*mesos.TaskID}

这个scheduler必须实现上面的接口:

Default
12三4567八91011121三14 type Scheduler interface {    Registered(SchedulerDriver, *mesos.FrameworkID, *mesos.MasterInfo)    Reregistered(SchedulerDriver, *mesos.MasterInfo)    Disconnected(SchedulerDriver)    ResourceOffers(SchedulerDriver, []*mesos.Offer)    OfferRescinded(SchedulerDriver, *mesos.OfferID)    StatusUpdate(SchedulerDriver, *mesos.TaskStatus)    FrameworkMessage(SchedulerDriver, *mesos.ExecutorID,                      *mesos.SlaveID, string)    SlaveLost(SchedulerDriver, *mesos.SlaveID)    ExecutorLost(SchedulerDriver, *mesos.ExecutorID, *mesos.SlaveID,                  int)    Error(SchedulerDriver, string)}

此刻1起看1个回调函数:

Default
12三4567八91011 func (s *MinerScheduler) Registered(_ sched.SchedulerDriver,       frameworkId *mesos.FrameworkID, masterInfo *mesos.MasterInfo) {    log.Infoln("Framework registered with Master ", masterInfo)}func (s *MinerScheduler) Reregistered(_ sched.SchedulerDriver,       masterInfo *mesos.MasterInfo) {    log.Infoln("Framework Re-Registered with Master ", masterInfo)}func (s *MinerScheduler) Disconnected(sched.SchedulerDriver) {    log.Infoln("Framework disconnected with Master")}

Registered在scheduler?溃烂向Mesos?master注册以后被调用。

Reregistered在scheduler?与Mesos?master断开连接并且再次注册时被调用,比方,在master重启的时候。

Disconnected在scheduler?与Mesos?master断开连接时被调用。这个在master挂了的时候会发生。

今朝为止,这里仅仅在回调函数中打印了日志信息,因为关于1个像何等的繁冗框架,大少数回调函数大概空在那处。然而,下1个回调函数就是每1个框架的核心,必须要认真的编写。

ResourceOffers在scheduler?从master那处获得1个offer的时候被调用。每1个offer包含1个集群上大概给框架应用的利润列表。利润集体收罗CPU、内存、端口和磁盘。1个框架大概应用它提供的1些利润、所不利润或许1点利润都不给用。

针 对每1个offer,此刻期冀离散部分的提供的利润并选择能否必要宣布1个新的server义务或许1个新的worker义务。这里大概向每个offer 发送尽大概或许多的义务以测试最大容量,然则由于开采比特币是依靠CPU的,所以这里每个offer运转1个开采者义务并应用部分可用的CPU利润。

Default
12三4567八91011 for i, offer := range offers {    // … Gather resource being offered and do setup    if !s.minerServerRunning && mems >= MemPerServerTask &&            cpus >= CPUPerServerTask && ports >= 2 {        // … Launch a server task since no server is running and we         // have resources to launch it.    } else if s.minerServerRunning && mems >= MemPerDaemonTask {        // … Launch a miner since a server is running and we have mem         // to launch one.    }}

针对每个义务都必要竖立1个对应的TaskInfo?message?,它包含了运转这个义务必要的信息。

Default
12三45 s.tasksLaunched++taskID = &mesos.TaskID {    Value: proto.String("miner-server-" +                         strconv.Itoa(s.tasksLaunched)),}

Task?IDs由框架选择,并且每个框架必须是唯1的。

Default
12三4567八91011121三141516171八192021222三242526 containerType := mesos.ContainerInfo_DOCKERtask = &mesos.TaskInfo {    Name: proto.String("task-" + taskID.GetValue()),    TaskId: taskID,    SlaveId: offer.SlaveId,    Container: &mesos.ContainerInfo {        Type: &containerType,        Docker: &mesos.ContainerInfo_DockerInfo {            Image: proto.String(MinerServerDockerImage),        },    },    Co妹妹and: &mesos.Co妹妹andInfo {        Shell: proto.Bool(false),        Arguments: []string {            // these arguments will be passed to run_p2pool.py            "--bitcoind-address", s.bitcoindAddr,            "--p2pool-port", strconv.Itoa(int(p2poolPort)),            "-w", strconv.Itoa(int(workerPort)),            s.rpcUser, s.rpcPass,        },    },    Resources: []*mesos.Resource {        util.NewScalarResource("cpus", CPUPerServerTask),        util.NewScalarResource("mem", MemPerServerTask),    },}

TaskInfo?message指定了1些关于义务的紧迫元数据信息,它许诺Mesos节点运转Docker容器,尤其会指定name、task?ID、container?information以及1些必要给容器传递的参数。这里也会指定义务必要的利润。

此刻TaskInfo已经被建立好,因而义务大概何等运转:

Default
1 driver.LaunchTasks([]*mesos.OfferID{offer.Id}, tasks, &mesos.Filters{RefuseSeconds: proto.Float64(1)})

在框架中,必要处理的扫尾1件事变是当开采者server关闭时会发生甚么。这里大概操作StatusUpdate?函数来处理。

在1个义务的生命周期中,针对分歧的阶段有分歧典范的形态更新。对这个框架来说,想要确保的是如果开采者server由于某种起因靡烂,系统会Kill部分开采者worker省得防范节约利润。这里是相干的代码:

Default
12三4567八91011121三141516 if strings.Contains(status.GetTaskId().GetValue(), "server") &&    (status.GetState() == mesos.TaskState_TASK_LOST ||        status.GetState() == mesos.TaskState_TASK_KILLED ||        status.GetState() == mesos.TaskState_TASK_FINISHED ||        status.GetState() == mesos.TaskState_TASK_ERROR ||        status.GetState() == mesos.TaskState_TASK_FAILED) {    s.minerServerRunning = false    // kill all tasks    for _, taskID := range s.currentDaemonTaskIDs {        _, err := driver.KillTask(taskID)        if err != nil {            log.Errorf("Failed to kill task %s", taskID)        }    }    s.currentDaemonTaskIDs = make([]*mesos.TaskID, 0)}

安枕无忧!经过努力,这里在Apache?Mesos上建立1个畸形义务的分布式比特币开采框架,它只用了大概三00行GO代码。这证分明应用Mesos?框架的API编写分布式系统是何等疾速和繁冗。

【via@John Walter / 由OneAPM工程师翻译】

数安新闻+更多

证书相关+更多