设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客

Docker:分布式系统的软件工程革命(上)

2014-8-1 14:13| 发布者: joejoe0332| 查看: 7585| 评论: 0|原作者: 王益|来自: github

摘要: 为了使用Docker,需要了解不少工具及其设计思路;而这些工具的文档分布在不同的网站。为了方便大家学习,本文以开发一个极简的搜索引擎为例,展示Docker带来的革新。本文以技术教程为主线,穿插了一些关于Hadoop和Me ...


分布式系统的部署

  最简单的使用Docker的部署方案是:启动一个集装箱,在其中运行一个searchengine进程和一个indexer进程。这和上文中介绍的在Mac主机上运行的方式是一样的,但这不符合分布式系统的一般部署原则。


  通常,为了提高处理速度、提升吞吐量和系统容错能力,每个程序都会启动为多个进程,运行在不同的机器上。比如,indexer程序的每个进程处理一部分数据(比如一个cralwer进程的输出)。这样的并行处理提升建立索引的效率。这种情况下,每个进程及其处理的数据被称为一个shard。(shard应该怎么翻译?我不知道)。


  类似地,searchengine进程也会启动为多个进程,每个进程的内存空间里都装着同样地索引结构,所以都能提供同样地服务,从而提升吞吐量。如果这些进程运行在不同的机器上,那么哪怕某些机器挂了,还有活着的进程能不间断地提供搜索服务。这样的每个进程被称为一个replication。


  其实每个indexer shard也可以是一组多个进程,其中每个进程是隶属本shard的一个replication。从而同时提升indexer的处理速度和容错能力。


  这么多进程应该启动在哪些机器上呢?要靠人来决定,可就忙不过来咯;得靠机群管理系统。Google Borg就是这样一套系统。


  可是在很多年的时间里,外界都不知道Borg。有一些项目试图模仿Google的计算架构,比如Hadoop意图模仿MapReduce。Google MapReduce是一个构建在Borg之上的并行计算框架。但是Hadoop的开发者没有开发类似Borg的系统,而是让Hadoop(计算框架)兼任资源管理和调度的功能,导致系统复杂,代码乱作一团。


  实际上,在Hadoop开始的若干年里,甚至没有像Google MapReduce那样让每个job有一个master进程来管理;而是让机群上所有job里的所有进程都向一个叫Job Tracker的进程汇报心跳(heartbeat),以至于一个Hadoop机群不能太大,否则Job Tracker会处理不过来。而且Job Tracker作为性能和稳定性的双重瓶颈,一旦累坏了,整个机群上所有job就都挂了。Hadoop的开发者直到2011年左右才意识到这一点,并发布了一篇文章,开始计划开发“下一代Hadoop”,现在被称为YARN的系统。


  YARN的功能和Google Borg有类似之处,但是真正引发外界对Google Borg关注的,是加州大学伯克利分校和Twitter的合作项目Mesos。这是一个试图复制Borg的尝试。当Mesos在Twitter运行起来的时候,很多从Google加入Twitter的工程师都很兴奋——终于重新能“高效工作”了!这里的故事,可以参见这篇Wired文章。Mesos系统设计思路描述在这篇论文里。其第一作者Ben Hindman曾经在Google实习,后来在Twitter任职。


  实际上,即便Mesos也没有能很相似地模仿Google Borg。至少在程序的发布和部署上。Mesos没有和Google Borg等效的打包和执行包的功能。而这个功能能为外界所访问,正是靠了本文着重介绍的Docker。Docker和Google Borg一样,使用Google工程师为Linux内核贡献的cgroups功能来实现集装箱机制。


  借助Docker,Google终于于本月(2014年7月)开源了Borg——但是是用Go语言重写的Borg,称为Kubernetes——Google Borg是用C++开发的。感谢开源社区不懈的推动!


集成测试

  基于上一节的介绍,我们能想象,如果每个集装箱只执行一个进程,那么机群管理系统在部署和调度应用时受到的限制最少。反过来想,如果我们在一个集装箱里同时运行一个indexer进程和一个searchengine进程,那么我们实际上引入了一个不必要的约束——indexer进程和searchengine进程一一对应。而且如果机群中有一台机器,可以承担运行一个进程的负载,但是不能承担同时运行两个进程,那么这台机器上就没法部署上述“大”集装箱了。

  

  所以,在Google Borg和Google Kubernetes里,都建议每个集装箱里只执行一个进程。


  基于“打包一次,兼顾测试和发布”的原则,我们可以想象,对于一个应用(或者叫做产品,比如上述的极简搜索引擎),最常见的打包方式是产生一个集装箱镜像,但是每个集装箱里只执行一个程序的一个进程。


  上文中,我们已经用一个Dockerfile把两个程序:indexer和searchengine都装进一个镜像wangkuiyi/hellworld了。接下来,我们尝试在Mac主机上启动两个集装箱,分别执行一个indexer和一个searchengine进程:

docker run -d -p 8080:8080 --name searchengine wangkuiyi/helloworld /searchengine
VBoxManage modifyvm "boot2docker-vm" --natpf1 "tcp-port8080,tcp,,8080,,8080"
docker run -d --name indexer --link searchengine:se wangkuiyi/helloworld /indexer -searchengine=se:8080


  这里,第一行启动了一个集装箱,并且起名叫searchengine,执行的镜像是wangkuiyi/helloworld。-d的意思是在后台执行,类似一个shell命令后面跟上一个&符号的效果。-p 8080:8080的意思是:“这个集装箱里有个程序会监听8080端口(如果看看searchengine的源码,会发现8080是其默认端口),把这个端口映射到主机(boot2docker创建的Linux虚拟机)的8080端口”。


  第二个命令让VirtualBox把Linux虚拟机的8080端口映射为Mac主机的8080端口。这样就可以在Mac主机上启动一个浏览器,通过访问本机的8080端口,来访问集装箱里的searchengine服务。(如果你在Linux主机上开发,就不需要boot2docker虚拟一个Linux主机了,也就不需要这个命令了。)


  上述第三个命令启动了一个名为indexer的集装箱,执行的也是wangkuiyi/helloworld镜像。在这个集装箱里启动了一个indexer进程;这个进程会去连接se:8080这个网络地址,并通过RPC调用,向这个目标地址发送更新的索引数据。se这个IP地址是怎么来的呢?这是--link seachengine:se参数的效果——这个参数使得Docker在启动indexer集装箱之前,修改了其中/etc/hosts文件,在其中增加了一行:

 xxx.xxx.xxx.xxx se


  这里 xxx.xxx.xxx.xxx 指代集装箱searchengine(--link searchengine:se中冒号左边的部分)的虚拟IP地址,se(--link searchengine:se中冒号右边的部分)也就是其域名了。Docker就是通过--link这个参数,让不同集装箱内的多个进程可以互相通信的。


  此时,在本机打开一个浏览器窗口并访问http://localhost:8080/?q=news,可以看到和上图完全一样的结果。


自动部署


  到目前为止,我们都是手动调用docker命令来操作docker的。而得到的效果——在Mac主机上启动极简搜索引擎——和不用Docker是一样的。大家不禁会问,为什么要引入Docker呢?


  其实,实际使用Docker时,我们不会手动敲docker命令,而是会利用fleet或者Kubernetes来部署和启动集装箱。这样只需要写一个非常简明的部署配置文件,就可以在开发机、集成测试机群、预发布机群、和产品环境中完成部署了。这篇文章为了说明Docker的设计思路和使用方法已经很长了,所以关于fleet和Kubernetes的介绍,我准备放在《Docker:分布式系统的软件工程革命(下)》中。

原文链接:Docker:分布式系统的软件工程革命(上)


酷毙

雷人
1

鲜花

鸡蛋

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部