vlambda博客
学习文章列表

一个基于Docker的负载均衡实例


一个基于Docker的负载均衡实例




前言

近年来,云计算的概念席卷了整个 IT 圈。抛开忽悠概念的因素,云计算的发展和应用极大地改变了 IT 产业的研发、运营和管理作为云计算最重要的核心技术之一,虚拟化技术的发展促成了这一巨大的变革,而容器技术作为最具有代表性的虚拟化技术革新,目前已经得到了业界的广泛关注,其中以 Docker 最具有代表性,最为火爆,鹅厂目前很多应用也或多或少使用到了 docker。本文目地主要是给大家简单安利一下目前最火的容器产品 Docker 及其所涉及的相关技术,并通过一个实际例子演示一下容器技术的典型应用场景。



1
简单扯扯容器



虚拟化技术的核心在于资源划分、隔离和管理。围绕着这个核心,在不同层次上发展出了多种虚拟化技术,如以虚拟机为代表的硬件级虚拟化(Hardware Virtualization)技术以及以容器(Container)为代表的操作系统级虚拟化(Operating System Level Virtualization)技术


容器并不是一个全新的技术体系,下图是从 Wikipedia 摘录的容器实现全家福,可以看到此项技术可以追溯到 1982 年,并且覆盖了多种操作系统。近年来,随着 Docker 的快速崛起,容器技术再次吸引了 IT 业界的广泛关注。


一个基于Docker的负载均衡实例


为什么要用"再"?这就需要聊聊容器的特点以及跟虚拟机的区别和联系。


随着技术的发展,IT 基础设施的能力越来越大,原来需要多个硬件单元完成的任务现在仅用一个硬件单元的一部分就能够完成了,那么为了资源的合理分配,将资源集合划分为更细粒度的资源单元,就是虚拟化技术的意义。


下图是虚拟机和容器技术的对比示意图。


左图中,在宿主机操作系统(Host OS)之上,通过 Hypervisor 将资源划分为资源单元,每个单元有自己的操作系统(Guest OS)、工具和库,在其上运行各自的 app 互不干扰,每个资源单元就是一个虚拟机;右图中在宿主机操作系统之上,通过容器管理器(Container Manager)将一部分资源隔离出来形成资源单元,每个资源单元没有自己的操作系统,有自己的工具和库,在这之上运行自己的 app,这里每个资源单元就是一个容器。


一个基于Docker的负载均衡实例


通过上图的分析可以看到,虚拟机和容器技术在隔离的层次上并不相同,虚拟机有从操作系统开始的完整的基础设施,而容器仅在工具、库这个层次及以上形成了自己的特有区域。这个特点决定了两者的属性,容器是比虚拟机更轻量的资源单元。轻量,意味着快速启停、迁移、分发等优良的性质,并且在资源总量一样的情况下,能够支持的容器单元数量将数倍于虚拟机。



下面扯点题外话,人类善于通过逻辑思维的手段从不同的事物中抽取出本质并加以推广。举个例子,运输业是一个很古老的行业,运输业的发展推动了人类的进步,当人类的运输需求变得越来越复杂,遇到了下面的问题,如何用标准的交通工具运输各种各样需求不同的物品?


一个基于Docker的负载均衡实例


为了解决这个问题,人们发明了集装箱,它将运输品所需满足的条件(光照、冷藏、密封等)限制在集装箱之内,对外而言它只是一个提供标准运输接口的单元,这样的单元可以通过各种使用标准运输接口的交通工具运输。



看到这里大家应该不难理解,通过类比,IT 攻城狮们再次发现虚拟化技术所蕴含的巨大潜力,虚拟化可以充当集装箱的角色,将 app 运行所需满足的条件(依赖、工具、库等)限制在资源单元之内,对外提供标准的接口,并且能够装载于各类服务器基础设施。并且在比较了各类虚拟化技术后,容器轻量的特点让它更适宜与成为集装箱。在重新审视了容器技术的巨大价值之后,各方势力纷纷开始占山头立门户,在这个过程中诸多新的容器技术相继发布,其中就以取名为码头工人的 Docker 最具代表性。


一个基于Docker的负载均衡实例






2
WOW,Docker来了!它是谁?能干嘛?



Docker 是谁?Docker 是由 dotCloud 公司在 2013 年开源的一款开源容器引擎,后来 Docker 火了干脆公司就改名为 Docker 了……

Docker 是一种基于 Linux 内核隔离技术的容器实现,用 Go 语言编写,其功能特性归纳为:


  • 资源隔离,包括文件系统、进程、网络等;

  • 资源控制;

  • 文件系统,具有写时复制、日志记录、版本管理等;

  • 提供控制 API;

  • 提供镜像分发、重用的生态系统。




Docker 的实现依赖了以下技术:


  • Namespace,利用 Linux 内核提供的 namespace 机制,容器能够建立资源隔离单元,隔离内容包括进程(PID)、网络(Net)、进程交互(IPC)、文件目录(Mnt)、hostname 及用户和用户组等。

  • CGroup,利用 CGroup 机制来处理不同容器之间竞争宿主机系统资源的问题,实现对资源的配额和度量。

  • LXC,在 Docker 发展的过程中,早期使用 LXC 来共享内核,实现容器的快速启停以及减少内存的消耗,在后来的发展中,docker 主键用 libcontainer 替代并扩展了 LXC 的功能。

  • AUFS,Docker 默认使用 AUFS 构建容器的文件系统,提供写时复制(Copy On Write)的特性,这是 Docker 镜像保存、修改及分发的基础。



基于 docker 提供的基础功能和其开源的属性,业界巨头和初创公司纷纷以此为基础开发出各种框架和工具,在分布式特性、网络特性、存储特性以及管理特性等方面对 Docker 进行扩展和补充,鹅厂 IEG 内部使用的 Docker 管理平台以及 TEG 的 Gaia 系统都是很好的例子。


关于 docker 技术原理的文章能够很容易搜索到,本文就不在这里展开了,下面将根据容器的特点介绍几个典型的应用场景,并给大家介绍如何从零开始写一个简单的基于 Docker 的负载均衡器。



根据前述,Docker 作为一种容器,能够快速启停、占用较少的系统资源,同时根据其自身实现技术特点,又具备写时复制、保存分发等特点。所以不难想到以下几种应用场景很适合使用 Docker 实现:


  • 平台即服务(PAAS),沙箱的完美替代品;

  • 自动测试及持续集成,测试妹纸笑开了花;

  • 构建标准化无状态运行环境及快速部署,你知道重装环境有多么烦么;

  • 高可用(HA)和负载均衡(LB)系统,让故障和攻击陷入人民战争的汪洋大海,一会慢慢讲。


夸了那么多,难道 Docker 就没有缺点么?不是的,目前 Docker 正在快速发展过程中,在人们使用的过程中逐渐暴露了 Docker 的很多问题,其中不乏一些很严重的问题:


  • 隔离性问题,docker 依赖 Linux 内核提供的隔离机制,相比虚拟机而言,级别和程度都有不少下降,这也是追求轻量带来的副作用

  • 安全性问题,跟隔离性分不开,目前 Docker 存在诸如 root 权限提升,共享宿主信息等安全漏洞,这阻碍了其推广到企业级应用的脚步

  • 性能问题,由于引入了 AUFS,提供了很好的 COW 特性,但是这也会对 I/O 性能造成一定影响,因此不建议用 docker 负担有状态的任务



    Docker 提供用于镜像分发和重用的生态系统,全球开发者都能够通过这个平台进行交流,但随之而来的就是如何保证镜像的质量、可靠性和安全性,PS.别人做的你敢用?



尽管存在诸多问题,但是这并不妨碍 docker 前进的脚步。业界也在期盼 docker 的快速成长。






3
别光看,动手做吧




感谢您能够看到这里,啰嗦结束之后,我们来动手做一个简单的基于 Docker 的负载均衡器实例。

负载均衡,顾名思义就是对负载进行分流实现均衡的目的。在 web 网站以及 web service 发展的过程中,负载和处理能力的矛盾使得负载均衡成为必须考虑的问题,如下图所示:

一个基于Docker的负载均衡实例


  • 当请求负载在单节点处理能力之下时,没有必要设置负载均衡器,所有的请求都由一台服务器搞定;

  • 当请求达到一定数量,超过了单台服务器处理能力,那么现在就需要添加多台服务器,并且使用负载均衡器(Load Balancer)进行流量分发,保证业务请求平均地分散到各 web 服务器;

  • 业务的流量特点很多变,流量高峰何时到来谁也不知道,如果使用多台 web 服务器在后台值班,这样难免会造成资源的浪费,并且这样也有可能无法应对流量峰值,因此需要一个自动的负载均衡器,它能够实时检测当前到来的业务流量,并且能够控制后端资源池快速完成资源的申请、释放以及路由切换,这样就可以通过实时的流量检测数据完成 web 服务器的动态配置,在后端资源池能力足够的情况下,轻松应对多变的请求量。



为了实现 3 的目标,我们的系统需要以下几大功能模块,如下图所示:


一个基于Docker的负载均衡实例



  • 负载均衡器:负责分发流量请求,并且在节点数目变化时完成路由切换。在本实例中,我选取了开源的 HAProxy 作为负载均衡器的实现,它支持多种流量分发算法,本例采用了简单的轮询(RoundRobin)模式。

  • 负载监控器:负责监控当前负载请求量,并且根据设定阈值决定下一步动作。本例中由 Python 实现,配合 Web 服务器实时上报的当前流量状况决定是否动态申请资源,实现 Scale-Out,具体代码请移步微码:
    https://github.com/kevinjs/docker-demo/blob/master/lb_demo/watch.py

  • 资源控制器:封装 docker 的操作 API,根据监控器的指令完成添加或删除服务节点的具体操作,本例中由 Python 实现,具体代码请移步微码:
    https://github.com/kevinjs/docker-demo/blob/master/lb_demo/control.py

  • Web 服务器:发挥 docker 的特点,将业务所需的 WebServer 功能组件,负载获取上报模块等打包成为镜像并注册于镜像库中,根据控制器的指令启停。


Docker 服务镜像的准备按照以下步骤进行:

一个基于Docker的负载均衡实例

  • 安装 docker 及相关服务组件;

  • Docker pull 拉取空白的实例;

  • 安装所需的基础组件,部署业务代码;

  • 将实例保存为镜像(类比 OOM 中创建了一个类);

  • Docker push 可以将此镜像上传到公共、私有镜像库,完成分发或重用(类比将 4 中创建的类发布,供其他人继承或是实例化对象并使用)。



本例所使用的镜像已经上传至 docker 官方镜像库,可以通过以下 docker 命令下载使用:

docker pull kevinjs/ubuntu:py27tor2






3
运行效果




通过模拟 http 请求访问负载均衡器服务 IP,控制访问量观察后端服务节点的数目和响应情况,最后将数据可视化输出如下图所示,可以看到,随着访问量的上升,监控器准确地反馈了流量的变化,并在短时间内通知后端资源池添加服务节点,从一个服最终增加到 18 个服务节点,在每一时刻都尽量保证每个服务节点都分布到平均的负载压力,并且在负载下降后及时减少服务节点以节省资源。


需要解释一下的是,从图中可以看出每隔一一定时间访问量有突降的情况,这是由于需要在自动添加服务节点后重启负载均衡器 HAProxy 造成的,这里是一个简单的实现,如果换用能够动态加载配置的负载均衡器方案,就能做到流量的平滑过渡。

一个基于Docker的负载均衡实例


下图是总的访问量与平均访问量之间的对比,在总请求量暴涨的情况下,通过快速反馈调节后端 web 服务实例的数量,平均访问量快速收敛,实现负载均衡。


一个基于Docker的负载均衡实例







一个基于Docker的负载均衡实例




往期推荐

一个基于Docker的负载均衡实例
一个基于Docker的负载均衡实例
一个基于Docker的负载均衡实例



一个基于Docker的负载均衡实例
扫码关注我们

多树云服   

专注企业信息化云服务
一个基于Docker的负载均衡实例
都在看
点点点,赞和在看都在这儿!