Sunday, December 27, 2015

集群负载均衡技术概述

集群负载均衡技术(Load Balancing)是目前互联网后端服务的关键技术,是互联网系统演化到现在这样巨大规模的基础。
客观地说,负载均衡是一个门槛相当不低的领域,已有技术主要包括硬件方案和软件方案。简单说,硬件方案性能好,但是昂贵;软件方案性能差,但是成本相对可控。
硬件方案代表为F5、Ctrix、A10、Redware 等 LB 厂商的产品,每年市场营收额高达百亿。
开源的软件实现方案也有不少,知名的包括 HAProxy、Nginx、LVS 等。
在实际大规模高性能的场景下,往往很难靠单一方案实现可靠的负载均衡服务。
很多 LB 厂家现在已经不再使用“负载均衡设备”这个术语了,改叫做应用分发(ADC、ADN)设备(甚至直接叫做 4-7 层交换机),但在这些设备中的最为基础和关键的技术仍然是对海量流量进行处理的负载均衡技术。
实际上,从客户端是否能感知或参与负载均衡的过程来区分,可以首先将负载均衡技术大概分为两大类:客户端可感知的负载均衡和客户端透明的负载均衡。当然,两类技术又可以进一步地结合起来使用。

客户端可感知负载均衡

顾名思义,客户端主动参与负载均衡过程,可以感知负载均衡存在。
典型的例子是一些客户端应用,需要动态获知服务地址。从这个意义上看,不少 P2P 应用都属于该范畴。
基本的过程可以为,客户端先向某个控制(Control)服务器发起请求,获取业务(Service)服务器地址(域名或者 IP 地址)的列表。获取列表成功后,本地按照某种均衡策略向这些业务服务器发出请求。
这样做的好处显而易见,可以降低对服务器端进行负载均衡的要求,甚至服务端可以不需要再进行负载均衡,简单资源池即可。
技术难点主要在于客户端和服务端之间的信息同步。比如业务服务器池调整后信息怎么及时更新到客户端;某些负载均衡策略需要获取实时服务器的状态信息,等等。
具体实现上,往往需要客户端和服务端进行一些配合。针对某些特定的业务场景,可以进行一些调整和优化,例如 Yahoo 就在某些互联网业务中使用了这种模式。
桌面时代的客户端往往受控性差,情况比较复杂,这种模式实现难度较大。
现在移动互联网发展起来后,客户端 APP 的可控性大大提高,比较看好这种模式的应用前景。

客户端透明负载均衡

客户端透明负载均衡实际上又包括很多层面的技术,这里都统归为一类。不同实现可能放在不同地方(运营商或者服务商等),但原理都是一致的,核心都是借用了“Overlay”的思想(计算机行业的所有问题,基本都可以通过引入新的层来实现)。
下面从客户端发出请求后的完成流程来看,可以在哪些步骤实现负载均衡。

DNS 层

首先,客户端会向某个业务服务器的域名发起请求,要先解析这个域名为具体的 IP 地址。
域名解析这块能做的事情很多,但大致上要么是运营商本地应答,要么运营商扔给服务商的域名服务器。
如果是前者(一般情况下)的话,运营商会通过本地 cache 进行查询,无命中则扔给上层域名服务或者服务商。
域名解析的过程直接决定了进行 LB 的效果。这里就有问题了,由于域名是由运营商进行维护答复的,一旦发生变化,服务商怎么去快速地调整呢,传统域名更新的方式可达数分钟甚至数小时的时延。
一种思路是跟运营商去谈,所有相关请求都服务商自己来处理或者怎么能合作进行快速更新;一种是将请求想办法绕开运营商,隧道给自己(又是一种 Overlay),腾讯的 HttpDNS 就是这个思路,域名解析不走传统 DNS 协议,而是通过 HTTP 请求来实现。
总结下,基于 DNS 的 LB 方式是比较简单直接,容易实现的,但是存在问题也不少,主要有多级 DNS 结构不可控,容易分布不均匀,和难以及时刷新等等。

IP 层

拿到 IP 之后,客户端可以发起请求到对应的 IP 地址,之后就等着接收到源地址为该 IP 的响应数据包。很自然的,可以在 LB 上替换掉这个地址,发给后端的真实服务池。这也是目前大量三层负载均衡器的基本原理。
实践中,前面挡一层 DNS 均衡,后面进行三层负载均衡,已经可以支持很大规模的场景了。
典型的,LVS 是这一类的软件方案,但具体实现上,LVS 支持三种模式:NAT(Network Address Translation)、DR(Direct Routing)、TUN(IP Tunneling)。NAT 就是把 LB 做 NAT 网关;DR 和 TUN 是想办法把流量转发给后端服务器,让后面服务器自己处理,形成三角路由。
首先,负载均衡器上会带有一个 VIP(用户看到的服务地址)和 DIP(用于探测后端服务的存活),后端真实服务器上会有 RIP。
NAT 模式下,请求和响应流量都经过负载均衡器,性能会差一些。
通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。
DR 模式下通过改写请求报文的目的 MAC 地址为某个真实服务器的 MAC(ARP 请求肯定不能自动响应了),将请求发送到真实服务器。而真实服务器将响应直接返回给客户。该模式扩展型号,但要求 LB 与真实服务器可以二层连通。这种模式因为性能好,用的很多。
TUN 是解决 DR 无法跨网络的问题,不是拿 MAC 做转发,而是封装完整包做 IP 转发,比 DR 处理要复杂。
此外,肯定要保证 Session 一致性,可以根据 IP 头和 TCP 头记录之前决策,保证流调度到同一台机器。实践中,支持十几台到数十台后端服务器比较合适。

应用层

用户访问资源需要通过 URI,一个 IP 地址上可能支持数个 URI,在三层均衡的同时,可以根据这些 URI 来制定具体的分发策略,比如访问 Front_IP:80/app1 的流量可能会被分配到 Back_IP1:80/app1;而到 Front_IP:80/app2 的流量被分配到Back_IP1:80/app2 等等。
这种应用层均衡,特点当然是最灵活,可以多级划分,但因为要看应用层的信息,计算复杂性大一些,对均衡器要求也比较高,很少有能做高性能的。

Saturday, October 31, 2015

OpenStack Summit 2015 Tokyo 有感

本次峰会是 10.27 ~ 10.30,四天在东京的品川站附近召开,6000 多人参会,几百个主会 speak 和各个项目的 design summit。
因为要做一个有关容器和网络的 speak,所以,虽经波折,最终还是按时参加了峰会。业余玩社区确实挑战比较大。
整体感受是,时间很紧,内容很多,身体压力很大。虽然只挑了最核心最热门的话题去听,也是从早到晚急匆匆地从一个会场赶到另一个(好几个 building)。一天下来,疲劳的很。

社区,不只是技术

开源项目的成功,除了技术外,往往还有很多很重要的因素。
比如怎么运营社区,怎么跟商业公司合作,怎么处理各个团队的关系……
毫无疑问,OpenStack 到今天能这么火,在各个方面做得都是非常优秀的。
本届大会,基本上越大的主题演讲 topic 都越浅显一些,但是人满为患;design summit 则集中到具体项目进行设计的讨论,反而人气没那么旺。
参加的人员,技术人员仍然是主体,但是非技术人员也不少见。
云,其实本质上不是个技术的事情。呵呵呵~

容器和网络是热点

OpenStack 社区对容器还是很积极的一个主动拥抱态度,各个项目都在考虑虚拟化对象是容器的新场景。
实际上,无论是 Docker 系列,K8s、Mesos,都有一些相对完整的 solution,无需 IaaS 的支持,自己就可以玩得很好。
但 OpenStack 社区还是希望底下用自己,所以努力提供新的 API 来支持这些 solution。
两边的定位有 overlap,肯定会冲突。底层平台必须要主动考虑上层 workload,考虑应用特性。这个是生产关系决定的。
网络话题这次被广泛关注,大会报告中有好几个都在谈网络(包括 SDN 和 NFV)。这次来参会的公司也有不少是网络公司,不过技术上新的东西不多。
比较搞笑的是,这次峰会的超级用户奖颁给了 NTT(sponser 了现场的网络接入),然而 wifi 接入体验比较一般(本来多好的宣传机会!)。
两个值得关注的项目,kuryr 还有 ovs 自己搞的 ovn 等开始亮相社区,都挺有意思,定位思路很清晰,不像 Magnum,做起来的问题不大。
围绕 neutron,问题不少,但是老框架在这里,能周旋的余地很少。怎么能跟别的项目更好的集成,怎么提供更好的性能,都是很现实的问题。
强调下,云计算的技术基础是计算虚拟化,然而成功能否,根本取决于网络。
到现在还没意识到这点的,基本可以歇了。
比较遗憾的是,有一些传统网络厂商,没能很好的抓住云计算这波机会。亡羊补牢,为时未晚,还可以考虑抓紧时间布局物联网。

技术周期趋向成熟

基本上,新的项目 focus 的 scope 都圈得比较小。
很多人开始关注实际的部署和运维方面的一些问题(再次强调下我的观点,云环境中,ops 将变得比 dev 更重要!)。
这很正常,最多的 80% 的需求也是最基本的,剩下 20% 不好做,不是通用需求,但往往是差异化和体现技术实力的点。
很多人会松了口气,趋向成熟,意味着再也不用跟着后面折腾太多升级了。
成熟后怎么能再健康的发展下去,是每一个成功社区都会碰到的问题,现在已经有点由盛转衰的意味,虽然不明显。

国内力量不可小觑

market place,国内公司(特别创业公司)见到不少。除了传统方案和硬件厂商,就是日本本地企业和国内企业,甚至国内企业感觉比日本企业还多一些。
而且来的人好多,一下子就是好几十号人,庞大的队伍!
做应用的企业没见到……,不过有一些很有特色的小企业,比如 cumulix 啊、puppet、solinea 啊,哈哈哈~
这次本地报告也不少,竟然还出现了用日语讲报告的情况。
各种基于 OpenStack 的方案,各种特点。
乐观看,大家都尽量兼容 OpenStack,又努力做出自己的特色;悲观看,差异化和成长空间可能有限。

日本的文化和生活

日本是一个很有意思的地方,学习了东方和西方的文化,糅合在一起,难免有不少纠结的地方。
也许是意识到这种文化的缺位,对于传下来的和服啊、武士道啊、艺伎表演啊,就都十分重视。
但日本文化上其实是封闭的,现在年青一代很少愿意去接触外面的世界。整个日本社会就像是一个精密的大机器,每个人按照职责努力的工作。七八点上班,十一二点下班,很少有跳槽,很少有变化,压力太大,森严的规矩,老龄化……日本的年轻人,不容易!
生活成本低、贫富差距不大,这些西方社会普遍的特色,也造成了日本现在已经进入了高度稳定甚至停滞期。

Monday, October 19, 2015

云计算的第二个十年 -- IT 行业的新变化

如果从概念的提出(2006 年由 IBM、Google 联合提出)算起,云计算即将步入第二个十年。
在第一个十年里,云计算从被质疑到成为新一代 IT 标准,从单纯技术上的概念到影响到整个业务模式。
虽然到目前为止,还有很多不成熟的地方值得探索,但云计算在第一个十年里已经正式确立了它的地位,已经被广泛接受并实践。
在云时代的下一个十年里,IT 行业又会发生哪些变化呢?

ops 将变得比 dev 更重要

在过去,无论是企业还是个人市场,新产品的研发能力是最核心的,运营团队一贯被视为“第二梯队”。
造成这种局面的原因很复杂,根子上是基础设施的缺乏。大量的重复性、非标准化、非核心的研发任务,造成 dev 在整个生产链中的核心地位,造成运营团队话语权的缺失。
在云时代,随着基础设施服务的成熟和标准化,新产品研发的效率和复杂度将大大下降。反而是产品上线后,怎么应对不同时间、不同场景的需求变得更为重要。运营能力将直接决定云的质量。
所以,即使是研发团队,也一定要具备一定的运维能力。devops 的紧密结合,才能具备在云时代的快速应变能力。

PaaS 将变得比 IaaS 更重要

如果说 IaaS 是云计算一切服务的基础,那么 PaaS 将变成未来云计算服务的核心。
IaaS 的定位是提供基础架构能力,从整个云计算栈上看,无论是提供裸机、虚机还是容器,这只是对物理计算资源进行单纯的抽象和管理,并不具备任何面向业务属性。而 PaaS 则在基础架构的基础上进一步抽象计算资源为软件业务能力。
如果以盖房子为例子,IaaS 相当于提供了砖头和水泥。而 PaaS 则进一步的整合这些基础材料为墙板、横梁。显然,施工团队更喜欢直接用后者。
同时,由于 PaaS 更贴近应用,也具有更多话语权。
那么,比 PaaS 再上一层的 SaaS 是否更有优势呢?理论上是没错的,但是实际上在下一个十年里,公有 SaaS 成为主流的可能性不大。一方面是大量的企业的应用并不具有太强的通用性,需要定制化开发;另一方面是过度耦合到第三方服务的隐患。
私有 SaaS 会有,但是一定种类不会太多。办公类、娱乐类将成主体。

通用平台将越来越少

由于搭建和运维云成本的进一步降低,云将成为家家户户都可以创建的资源,面向公共服务的通用云平台将进一步集中,成为两三家的业务。
另外一方面,面向通用计算的云平台将很难获利。反而是某些具有特色服务的专有云将大量出现。
这些特色应该至少包括安全性、高性能、跟托管业务紧耦合的一些辅助服务,例如域名、CDN 等等。

Tuesday, September 22, 2015

用 Docker 搭建 Spark 集群

简介

Spark 是 Berkeley 开发的分布式计算的框架,相对于 Hadoop 来说,Spark 可以缓存中间结果到内存而提高某些需要迭代的计算场景的效率,目前收到广泛关注。
熟悉 Hadoop 的同学也不必担心,Spark 很多设计理念和用法都跟 Hadoop 保持一致和相似,并且在使用上完全兼容 HDFS。但是 Spark 的安装并不容易,依赖包括 Java、Scala、HDFS 等。
通过使用 Docker,可以快速的在本地搭建一套 Spark 环境,方便大家开发 Spark 应用,或者扩展到生产环境。
Spark 的设计理念很简单master 节点负责接收要执行的应用和指令worker 节点负责具体处理
除了自带的集群机制,还兼容集成到其他的集群框架,包括 mesos、yarn 等。

安装

其实官方的源码中已经提供了支持 mesos 的 Dockerfile 文件,在 docker\spark-mesos 下面,可以据此生成 Docker 镜像。
这里,我们采用比较热门的 sequenceiq/docker-spark 镜像,这个镜像已经安装了对 Spark 的完整依赖。
无论官方还是 sequenceiq/docker-spark 镜像,都是基于提前打包的二进制文件来制作的,都可以放心使用。
由于镜像比较大(2+ GB),首先下载该镜像到本地。
$ docker pull sequenceiq/spark:1.4.0
下载完毕后,从 https://github.com/yeasy/docker-compose-files/tree/master/spark_cluster 下载编写好的支持 Spark 集群的 docker-compose.yml 文件,并启动它
$ sudo pip install docker-compose==1.4.0
$ docker-compose up
可以看到类似如下的输出:
Creating sparkcompose_master_1...
Creating sparkcompose_slave_1...
Attaching to sparkcompose_master_1, sparkcompose_slave_1
master_1 | /
master_1 | Starting sshd: [  OK  ]
slave_1  | /
slave_1  | Starting sshd: [  OK  ]
master_1 | Starting namenodes on [master]
slave_1  | Starting namenodes on [5d0ea02da185]
master_1 | master: starting namenode, logging to /usr/local/hadoop/logs/hadoop-root-namenode-master.out
slave_1  | 5d0ea02da185: starting namenode, logging to /usr/local/hadoop/logs/hadoop-root-namenode-5d0ea02da185.out
master_1 | localhost: starting datanode, logging to /usr/local/hadoop/logs/hadoop-root-datanode-master.out
slave_1  | localhost: starting datanode, logging to /usr/local/hadoop/logs/hadoop-root-datanode-5d0ea02da185.out
master_1 | Starting secondary namenodes [0.0.0.0]
slave_1  | Starting secondary namenodes [0.0.0.0]
master_1 | 0.0.0.0: starting secondarynamenode, logging to /usr/local/hadoop/logs/hadoop-root-secondarynamenode-master.out
master_1 | starting yarn daemons
master_1 | starting resourcemanager, logging to /usr/local/hadoop/logs/yarn--resourcemanager-master.out
master_1 | localhost: starting nodemanager, logging to /usr/local/hadoop/logs/yarn-root-nodemanager-master.out
master_1 | starting org.apache.spark.deploy.master.Master, logging to /usr/local/spark-1.4.0-bin-hadoop2.6/sbin/../logs/spark--org.apache.spark.deploy.master.Master-1-master.out
slave_1  | 0.0.0.0: starting secondarynamenode, logging to /usr/local/hadoop/logs/hadoop-root-secondarynamenode-5d0ea02da185.out
slave_1  | starting yarn daemons
slave_1  | starting resourcemanager, logging to /usr/local/hadoop/logs/yarn--resourcemanager-5d0ea02da185.out
slave_1  | localhost: starting nodemanager, logging to /usr/local/hadoop/logs/yarn-root-nodemanager-5d0ea02da185.out
slave_1  | starting org.apache.spark.deploy.worker.Worker, logging to /usr/local/spark-1.4.0-bin-hadoop2.6/sbin/../logs/spark--org.apache.spark.deploy.worker.Worker-1-5d0ea02da185.out
docker-compose 服务起来后我们还可以用 scale 命令来动态扩展 Spark 的 worker 节点数例如
$ docker-compose scale worker=2
Creating and starting 2... done
注意,需要先用 pip 安装 docker-compose,1.4.1 版本有 bug,推荐使用 1.4.0 版本。

docker-compose 文件

我们来解析下 docker-compose 文件,核心内容很简单,包括 master 服务和 worker 服务。
master:
  image: sequenceiq/spark:1.4.0
  hostname: master
  ports:
  - "4040:4040"
  - "8042:8042"
  - "7077:7077"
  - "8080:8080"
  - "8088:8088"
  restart: always
  command: bash /usr/local/spark/sbin/start-master.sh && ping localhost > /dev/null

worker:
  image: sequenceiq/spark:1.4.0
  links:
  - master:master
  expose
  - "8081"
  restart: always
  command: bash /usr/local/spark/sbin/start-slave.sh spark://master:7077 && ping localhost >/dev/null

master 服务

首先,master 服务映射了好几组端口到本地,分别功能为: 4040:Spark 运行任务时候提供 web 界面观测任务的具体执行状况,包括执行到哪个阶段、在哪个 executor 上执行; 8042:Hadoop 的节点管理界面; 7077:Spark 主节点的监听端口,用户可以提交应用到这个端口,worker 节点也可以通过这个端口连接到主节点构成集群; 8080:Spark 的监控界面,可以看到所有的 worker、应用整体信息; * 8088:Hadoop 集群的整体监控界面。
master 服务启动后执行了 bash /usr/local/spark/sbin/start-master.sh 命令来配置自己为 master 节点然后通过 ping 来避免容器退出

worker 服务

类似 master 节点,启动后,执行了 /usr/local/spark/sbin/start-slave.sh spark://master:7077 命令来配置自己为 worker 节点,然后通过 ping 来避免容器退出。
注意,启动脚本后面需要提供 spark://master:7077 参数来指定 master 节点地址。
8081 端口提供的 web 界面,可以看到该 worker 节点上任务的具体执行情况。

执行应用

Spark 推荐用 spark-submit 命令来提交执行的命令基本语法为
spark-submit \
  --class your-class-name \
  --master master_url \
  your-jar-file
  app_params
例如,我们可以使用 spark 自带样例中的计算 Pi 的应用。
在 master 节点上执行命令
/urs/local/spark/bin/spark-submit --master spark://master:7077 --class org.apache.spark.examples.SparkPi /usr/local/spark/lib/spark-examples-1.4.0-hadoop2.6.0.jar 1000
最后的参数 1000 表示要计算的迭代次数为 1000 次。
任务运行中,可以用浏览器访问 4040 端口,看到任务被分配到了两个 worker 节点上执行。 
计算过程中也会输出结果,如下:
...
15/09/22 03:07:54 INFO scheduler.TaskSetManager: Finished task 998.0 in stage 0.0 (TID 998) in 201 ms on 172.17.0.49 (998/1000)
15/09/22 03:07:54 INFO scheduler.TaskSetManager: Finished task 999.0 in stage 0.0 (TID 999) in 142 ms on 172.17.0.49 (999/1000)
15/09/22 03:07:54 INFO scheduler.TaskSetManager: Finished task 997.0 in stage 0.0 (TID 997) in 220 ms on 172.17.0.49 (1000/1000)
15/09/22 03:07:54 INFO scheduler.TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool
15/09/22 03:07:54 INFO scheduler.DAGScheduler: ResultStage 0 (reduce at SparkPi.scala:35) finished in 23.149 s
15/09/22 03:07:54 INFO scheduler.DAGScheduler: Job 0 finished: reduce at SparkPi.scala:35, took 23.544018 s
Pi is roughly 3.1417124
15/09/22 03:07:54 INFO handler.ContextHandler: stopped o.s.j.s.ServletContextHandler{/metrics/json,null}
15/09/22 03:07:54 INFO handler.ContextHandler: stopped o.s.j.s.ServletContextHandler{/stages/stage/kill,null}
15/09/22 03:07:54 INFO handler.ContextHandler: stopped o.s.j.s.ServletContextHandler{/api,null}
...

总结

集群系统作为现代 IT 基础架构的重要组成部分,一直是运维部门的“硬骨头”。上线、部署、扩容……规模大了后各方面都可能出问题。而结合 Docker 这样的容器技术,可以很大程度上解耦对周边环境的依赖。如果再配合 mesos 等资源管理系统,可以大大降低人工运维的风险和复杂性。
当然,优秀的系统一定要配合正确的流程。生产环境中如果缺乏一套成熟的 devops 流程,是不可能有高效的生产力的。加班,也就成了常态。
转载请注明。

Tuesday, August 18, 2015

用 consul + consul-template + registrator + nginx 打造真正可动态扩展的服务架构

在互联网应用领域,服务的动态性需求十分常见,这就对服务的自动发现和可动态扩展提出了很高的要求。
Docker 的出现,以及微服务架构的兴起,让众多开源项目开始关注在松耦合的架构前提下,如何基于 Docker 实现一套真正可动态扩展的服务架构。

基本需求

基本的需求包括:
  • 服务启动后要能自动被发现(vs 传统需要手动进行注册);
  • 负载要能动态在可用的服务实例上进行均衡(vs 传统需要静态写入配置);
  • 服务规模要方便进行快速调整(vs 传统需要较长时间的手动调整)。

相关项目

服务发现

服务发现的项目已经有不少,包括之前介绍的 consul,以及 skydnsserf、以及主要关注一致性的强大的 zookeeper 等。
这些项目各有优缺点,功能上大同小异,都是要通过某种机制来获取服务信息,然后通过维护一套(分布式)数据库来存储服务的信息。这也是为什么 etcd 受到大家关注和集成。
在这里,选用 HashiCorp 公司的 consul 作为服务发现的管理端,它的简介可以参考 这里

服务注册

服务注册的手段有很多,当然,从发起方是谁可以分为两大类,主动注册还是被动探测。
主动注册,顾名思义,服务启动后,向指定的服务发现管理端的 API 发送请求,给出自身的相关信息。这样做,对管理端的要求简单了很多,但意味着服务自身要完成注册工作,并且极端情况下,管理端比较难探测出真正存活的服务。
被动探测,则是服务发现管理端通过某种机制来探测存活的服务。这样可以获取真实的服务情况,但如何探测是个很难设计的点,特别当服务类型比较复杂的时候。
以上两种,都对网络连通性要求较高。从短期看,主动注册方式会比较容易实现一些,应用情形更广泛;但长期维护上,被动探测方式应该是更高效的设计。
这里,我们选用 gliderlabs 的 registrator,它可以通过跟本地的 docker 引擎通信,来获取本地启动的容器信息,并且注册到指定的服务发现管理端。

配置更新

服务被调整后,负载均衡器要想动态重新分配负载,就需要通过配置来获取更新。这样的方案也有不少,基本上都是要安装一些本地 agent 来监听服务发现管理端的信息,生成新的配置,并执行更新命令。
HashiCorp 公司 的consul-template,可以通过监听 consul 的注册信息,来完成本地应用的配置更新。

负载均衡

负载均衡对性能要求很高,其实并不是软件所擅长的领域,但软件方案胜在成本低、维护方便。包括 lvshaproxy 都是很优秀的设计方案。
这里,我们选用 nginx。nginx 不仅是个强大的 web 代理服务器,同时在负载均衡方面表现也不俗。更关键的,新版本的 nginx 对在线升级支持做到了极致。实时配置更新更是不在话下,可以保证服务的连续性。

实验过程

准备工作

首先,从 这里 下载模板文件。
主要内容如下:
#backend web application, scale this with docker-compose scale web=3
web:
  image: yeasy/simple-web:latest
  environment:
    SERVICE_80_NAME: http
    SERVICE_NAME: web
    SERVICE_TAGS: backend
  ports:
  - "80"

#load balancer will automatically update the config using consul-template
lb:
  image: yeasy/nginx-consul-template:latest
  hostname: lb
  links:
  - consulserver:consul
  ports:
  - "80:80"

consulserver:
  image: gliderlabs/consul-server:latest
  hostname: consulserver
  ports:
  - "8300"
  - "8400"
  - "8500:8500"
  - "53"
  command: -data-dir /tmp/consul -bootstrap -client 0.0.0.0

# listen on local docker sock to register the container with public ports to the consul service
registrator:
  image: gliderlabs/registrator:master
  hostname: registrator
  links:
  - consulserver:consul
  volumes:
  - "/var/run/docker.sock:/tmp/docker.sock"
  command: -internal consul://consul:8500
如果没有安装 docker 和 docker-compose,需要先进行安装,以 ubuntu 系统为例。
$ curl -sSL https://get.docker.com/ | sh
$ sudo pip install docker-compose

执行

docker-compose 模板所在目录,执行
$ sudo docker-compose up
相关镜像即可自动被下载,下载完毕后,容器就启动起来了。
访问 http://localhost 可以看到一个 web 页面,提示实际访问的目标地址。
多次刷新,可以看到目标地址没有变化,这是因为,目前我们只有一个 web 后端服务器。
2015-08-18 03:37:58: 6 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.148>
调整后端为 3 个服务器。
$ sudo docker-compose scale web=3
然后,再次访问 http://localhost,多次刷新,可以看到访问的实际目标地址发生了变化,新启动的 web 服务器被自动注册,并且 nginx 自动对它们进行了负载均衡。
2015-08-18 03:37:58: 6 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.148>
2015-08-18 03:38:17: 5 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.152>
2015-08-18 03:38:20: 5 requests from <LOCAL: 172.17.1.150> to WebServer <172.17.1.153>

Tuesday, August 04, 2015

Consul 简介

概述

Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。
它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群 提供图形界面 跨平台,支持 Linux、Mac、Windows

安装

从 www.consul.io/downloads.html 下载二进制文件到本地即可。
consul 在每个节点上都只需要相同的单一二进制文件,部署十分简单。

基本概念

agent

组成 consul 集群的每个成员上都要运行一个 agent,可以通过 consul agent 命令来启动。agent 可以运行在 server 状态或者 client 状态。自然的,运行在 server 状态的节点被称为 server 节点;运行在 client 状态的节点被称为 client 节点。

client 节点

负责转发所有的 RPC 到 server 节点。本身无状态,且轻量级,因此,可以部署大量的 client 节点。

server 节点

负责组成 cluster 的复杂工作(选举、状态维护、转发请求到 lead),以及 consul 提供的服务(响应 RCP 请求)。考虑到容错和收敛,一般部署 3 ~ 5 个比较合适。
第一个节点:
$ consul agent -data-dir=/tmp/consul -server -bootstrap-expect 1 -bind $IP
其他节点:
$ consul agent -data-dir=/tmp/consul -server -join $IP
通过 $IP:8500/v1/catalog/nodes 可以访问到注册上的节点。

Gossip

基于 Serf 实现的 gossip 协议,负责成员、失败探测、事件广播等。通过 UDP 实现各个节点之间的消息。分为 LAN 上的和 WAN 上的两种情形。

架构

consul architecture

相关项目

registrator

可以监听主机上的容器信息,并把有暴露端口的容器注册到给定的 consul/etcd 等服务上。

consul-template

可以监听 consul 服务的内容变化,并根据变化实时更新应用的配置文件。