构建一个分布式系统是很困难的。它需要可扩展性、容错性、高可用性、一致性、可伸缩以及高效。为了达到这些目的,分布式系统需要很多复杂的组件以一 种复杂的方式协同工作。例如,Apache Hadoop在大型集群上并行处理TB级别的数据集时,需要依赖有着高容错的文件系统(HDFS)来达到高吞 吐量。
在之前,每一个新的分布式系统,例如Hadoop和Cassandra,都需要构建自己的底层架构,包括消息处理、存储、网络、容错 性和可伸缩性。庆幸的是,像Apache Mesos这样的系统,通过给分布式系统的关键构建模块提供类似操作系统的管理服务,简化了构建和管理分布式系 统的任务。Mesos抽离了CPU、存储和其它计算资源,因此开发者开发分布式应用程序时能够将整个数据中心集群当做一台巨型机对待。
构建 在Mesos上的应用程序被称为框架,它们能解决很多问题:Apache Spark,一种流行的集群式数据分析工具;Chronos,一个类似cron 的具有容错性的分布式scheduler,这是两个构建在Mesos上的框架的例子。构建框架可以使用多种语言,包括 C++,Go,Python,Java,Haskell和 Scala。
在分布式系统用例上,比特币开采就是一个很好的例子。比特币将为生 成 acceptable hash 的挑战转为验证一块事务的可靠性。可能需要几十年,单台笔记本电脑挖一块可能需要花费超过150年。结果是,有许多 的“采矿池”允许采矿者将他们的计算资源联合起来以加快挖矿速度。Mesosphere的一个实习生,Derek,写了一个比特币开采框架 (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会和一个比特币采矿池通信,并给每个worker分配blocks。Worker会努力工作,即开采比特币。
任务实际上被封装 在executor框架中,因此任务运行意味着告诉Mesos master在其中一个slave上面启动一个executor。由于这里使用的是标准命 令执行器(executor),因此可以指定任务是二进制可执行文件、bash脚本或者其他命令。由于Mesos支持Docker,因此在本例中将使用可 执行的Docker镜像。Docker是这样一种技术,它允许你将应用程序和它运行时需要的依赖一起打包。
为了在Mesos中使用Docker镜像,这里需要在Docker registry中注册它们的名称:
1 2 3 4 |
const ( MinerServerDockerImage = "derekchiang/p2pool" MinerDaemonDockerImage = "derekchiang/cpuminer" ) |
然后定义一个常量,指定每个任务所需资源:
1 2 3 4 5 |
const ( MemPerDaemonTask = 128 // mining shouldn't be memory-intensive MemPerServerTask = 256 CPUPerServerTask = 1 // a miner server does not use much CPU ) |
现在定义一个真正的scheduler,对其跟踪,并确保其正确运行需要的状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 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必须实现下面的接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 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 2 3 4 5 6 7 8 9 10 11 |
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挂了的时候会发生。
目前为止,这里仅仅在回调函数中打印了日志信息,因为对于一个像这样的简单框架,大多数回调函数可以空在那里。然而,下一个回调函数就是每一个框架的核心,必须要认真的编写。
ResourceOffers在scheduler 从master那里得到一个offer的时候被调用。每一个offer包含一个集群上可以给框架使用的资源列表。资源通常包括CPU、内存、端口和磁盘。一个框架可以使用它提供的一些资源、所有资源或者一点资源都不给用。
针 对每一个offer,现在期望聚集所有的提供的资源并决定是否需要发布一个新的server任务或者一个新的worker任务。这里可以向每个offer 发送尽可能多的任务以测试最大容量,但是由于开采比特币是依赖CPU的,所以这里每个offer运行一个开采者任务并使用所有可用的CPU资源。
1 2 3 4 5 6 7 8 9 10 11 |
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. } } |
针对每个任务都需要创建一个对应的TaskInfo message ,它包含了运行这个任务需要的信息。
1 2 3 4 5 |
s.tasksLaunched++ taskID = &mesos.TaskID { Value: proto.String("miner-server-" + strconv.Itoa(s.tasksLaunched)), } |
Task IDs由框架决定,并且每个框架必须是唯一的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
containerType := mesos.ContainerInfo_DOCKER task = &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), }, }, Command: &mesos.CommandInfo { 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指定了一些关于任务的重要元数据信息,它允许Mesos节点运行Docker容器,特别会指定name、task ID、container information以及一些需要给容器传递的参数。这里也会指定任务需要的资源。
现在TaskInfo已经被构建好,因此任务可以这样运行:
1 |
driver.LaunchTasks([]*mesos.OfferID{offer.Id}, tasks, &mesos.Filters{RefuseSeconds: proto.Float64(1)}) |
在框架中,需要处理的最后一件事情是当开采者server关闭时会发生什么。这里可以利用StatusUpdate 函数来处理。
在一个任务的生命周期中,针对不同的阶段有不同类型的状态更新。对这个框架来说,想要确保的是如果开采者server由于某种原因失败,系统会Kill所有开采者worker以避免浪费资源。这里是相关的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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上建立一个正常工作的分布式比特币开采框架,它只用了大约300行GO代码。这证明了使用Mesos 框架的API编写分布式系统是多么快速和简单。
【via@John Walter / 由OneAPM工程师翻译】
- 上一篇:用眼睛解读心灵
- 下一篇:NFS打造Web图片服务器
猜你还喜欢
- 07-08八年专业安全团队承接渗透入侵维护服务
- 08-06SQLMAP的注入命令以及使用方法
- 08-03白帽故事汇:网络安全战士从来不是「男生」的专利
- 07-27编辑器漏洞手册
- 07-12web安全之如何全面发现系统后台
- 02-22常见Web源码泄露总结
- 07-25网站后台登陆万能密码
- 07-23破解emlog收费模板“Begin”
- 01-12批量检测SQL注入
- 01-22Apache Solr远程代码执行漏洞(CVE-2017-12629)从利用到入侵检测
- 随机文章
-
- 主机安全:洋葱Webshell检测实践与思考
- 解密无文件攻击的各种姿势及最新检测方法
- thinkphp漏洞集合与复现
- Thinkphp5代码执行学习
- 闲谈Webshell实战应用
- 代码克隆检测技术初探和开源工具地址分享
- 记录几种XSS绕过方式
- 通达OA远程命令执行漏洞分析
- 一次对果聊诈骗的分析:那些你不知道的套路诈骗
- 看我如何制造漏洞绕过安全软件来加入自启动
- 看我如何制造漏洞绕过安全软件来加入自启动
- iOS逆向之人脸识别绕过
- 白盒系列之变量追踪引擎(一)
- 黑灰产的廉价“温床”—跑分平台
- Nuclei:一款快速自定义模板扫描工具
- Django初次尝试编写Web漏洞扫描器挖坑记录
- SRC漏洞挖掘信息收集与挖掘技巧
- php 反序列化 魔术方法
- 挖洞经验 | 雷蛇电子钱包APP漏洞分析
- DEDECMS伪随机漏洞 (二) :Cookie算法与Rootkey随机强度分析
- 热门文章
-
- 八年专业安全团队承接渗透入侵维护服务
- Emlog黑客站模板“Milw0rm”发布
- Stuxnet纪录片-零日 Zero.Days (2016)【中文字幕】
- SQLMAP的注入命令以及使用方法
- 白帽故事汇:网络安全战士从来不是「男生」的专利
- 编辑器漏洞手册
- web安全之如何全面发现系统后台
- 常见Web源码泄露总结
- 渗透测试培训(第五期)
- 深入理解JAVA反序列化漏洞
- cmseasy前台无需登录直接获取敏感数据的SQL注入(有POC证明)
- 网站后台登陆万能密码
- 黑麒麟2016渗透培训系列教程
- 破解emlog收费模板“Begin”
- 那些强悍的PHP一句话后门
- Android平台渗透测试套件zANTI v2.5发布(含详细说明)
- 渗透工具BackTrack与KaliLinux全套视频教程
- Python列为黑客应该学的四种编程语言之一 初学者该怎么学
- CVE-2017-11882漏洞复现和利用
- 恶意程序报告在线查询工具
文章存档
- 2021年3月(4)
- 2020年12月(4)
- 2020年11月(5)
- 2020年10月(8)
- 2020年9月(8)
- 2020年8月(20)
- 2020年7月(47)
- 2020年6月(70)
- 2020年5月(41)
- 2020年4月(21)
- 2020年3月(120)
- 2020年2月(26)
- 2019年12月(12)
- 2019年11月(13)
- 2019年10月(17)
- 2019年9月(15)
- 2019年8月(13)
- 2019年7月(15)
- 2019年6月(15)
- 2019年5月(19)
- 2019年4月(23)
- 2019年3月(19)
- 2019年2月(11)
- 2019年1月(29)
- 2018年12月(24)
- 2018年11月(56)
- 2018年10月(79)
- 2018年9月(20)
- 2018年8月(17)
- 2018年7月(16)
- 2018年6月(7)
- 2018年5月(10)
- 2018年3月(6)
- 2018年2月(2)
- 2018年1月(11)
- 2017年11月(18)
- 2017年10月(6)
- 2017年9月(8)
- 2017年8月(7)
- 2017年7月(7)
- 2017年6月(15)
- 2017年5月(30)
- 2017年4月(7)
- 2017年3月(1)
- 2017年2月(4)
- 2017年1月(1)
- 2016年12月(3)
- 2016年11月(7)
- 2016年10月(6)
- 2016年9月(6)
- 2016年8月(102)
- 2016年7月(24)
- 2013年7月(1)
- 文章标签
-