王明芬 ,陈锐旺
(1. 福建师范大学协和学院信息技术系,福建福州 350117;2. 福州迅腾网络技术有限公司,福建福州 350004)
基于传统的Web 系统架构模式,即采用单体架构或面向服务的架构(SOA)存在诸多不足. 比如资源扩容难,运维难度大,平台即使只是改动一个小功能,也需要将整个应用重新发布, 容易由于系统升级而造成线上业务停顿. 随着在线用户数量以及数据规模的增长,传统Web 系统架构的开发、测试、部署、维护愈发困难,已经不能满足当前需要[1]. 目前Docker 的细粒度微服务已逐渐成为Web 架构设计主流,将网站的系统功能划分为多个独立的服务,大大提高了系统资源的灵活度. 文章针对传统Web 结构资源难编排、不能快速扩容等不足,结合微服务和容器化技术,设计基于Docker 容器化技术的Web 架构,通过资源调度和系统容器的弹性伸缩提升网站平台的高可用性和可扩展性.
Docker 是一种开源的软件容器平台,开发人员可将其应用程序和依赖项打包到可移植镜像中,这对于应用程序的部署和扩展都很方便. 通过Docker 打包的应用程序与业务功能匹配的微服务部署到云平台,可以选择一键式部署方法. 它的横向扩展和持续集成的功能大大提高部署和运营效率. 微服务和Docker 容器的组合可以解决构建大量系统应用程序时的困难、系统模块的可重用性低以及操作和维护困难等问题[2-3]. 使用Docker 技术可以轻松隔离和划分设备资源,同时由于Docker 本身的超轻量级特性,可以高密度地部署设备. 多设备有利于实现高可用性和高弹性的应用,从而最大限度地利用和调度资源.
Kubernetes 是一个强大的开源分布式架构,主要用于容器应用的编排,可以实现自动化调度、资源分发. 由于容器快速启动的特性,可以在业务高峰时快速启动成百上千个容器来负载应用,如果物理机资源不足可以使用join命令将新机器加入集群. 同时Kubernetes 的智能负载均衡器让业务在更新或是回滚上线时实现无停机,可以有效提高资源利用率和应用服务质量,有着出色的用户体验. 云原生时代Kubernetes 已成为IT 自动化的基石[4-5].
Docker 容器在底层的Kubernetes 集群中运行,集群中的数据保存在Etcd 中. 系统架构可以集群化部署Etcd,从而实现数据存储的高可用. 为了应对人员流量的突然增加和主机的突然中断,Kubernetes 集群进行高可用性和负载平衡的设计.
Kubernetes 由Master 节点和多个Node 节点组成.Master 主要负责节点的管理和资源的调度,Node 是工作负载节点,作为分布式部署节点与Master 通信[6]. 基于Docker 的Web架构设计如图1 所示,系统集群由3 台机器组成,分别为Master 管理节点、Node1 工作节点和Node2 工作节点.
Master 管理节点的核心组件如下.
Etcd:开发的分布式键值存储模块,可用于服务发现,共享配置和一致性保障.
API Server:提供集群管理的REST API接口,包括身份验证和授权,操作资源以及其他模块之间的数据交互和通信. 在架构中只有API Server 能访问Etcd.
Scheduler:负责将Pod 分配和调度到集群中的节点上. 它在API Server 中查询并侦听尚未分配给节点的Pod,然后根据调度策略将节点分配给这些Pod .
Controller Manager:控制器模块就是集群的大脑,它通过API Server 监控整个集群的工作状态,并确保工作状态达到预期.
Node 工作节点的核心组件如下.
kubelet:接收并执行Master 发出的管理Pod 和Pod 容器的指令. 每个kubelet 进程节点的信息在API Server 上注册,并定期向Master节点报告该节点的资源使用情况.
kube-proxy: 监 听API Server 中 服 务 和pod 节点的变化,并通过IP 表配置服务的负载均衡.
Pod: 工作节点中的每个Pod 对应一个用于支撑线上教育平台业务运行的微服务.
如图1 所示,Node1 中的Pod 运行的是Web Server 服 务,Node2 是MySQL 服 务, 两个Pod 通过节点中的kube-proxy 进行通信支撑整个业务的正常运行,每个Pod 都有自己的IP 地址,但管理人员和用户并不需要关注这些Pod 的IP,因为当管理节点监控到某个Pod的健康状况不佳时就会清除并重启这个Pod,所以Pod 的IP 地址都是不固定的,底层都是Docker 引擎.
图1 容器化的Web 系统架构设计
微服务架构的核心是将大型单体应用程序拆分为很多小的相互关联的微服务,每个微服务后面有多个镜像在支撑业务. 这些特性为后期微服务的拓展提供了基础,用户可以方便地在原有业务基础上进行功能模块的拓展. 文章设计的线上教育平台的数据库和Web 应用服务器就是两个微服务.
容器技术为微服务理念提供了一种匹配的实现机制,这能够解决当前传统Web 平台的问题. 轻量级且可以实现虚拟化运行环境的Docker 容器为微服务提供了理想的载体[7]. 轻量级的Docker容器是微服务的最佳运行环境,微服务应用在容器环境下运行时才能有效提升运维效率.
用3 台机器来搭建容器集群平台,其中一台为Master 节点,另两台为Node 节点. 选定操作系统,设置初始的集群IP 地址和外部IP地址,物理机具体配置如表1 所示.
系统为所有节点角色分配及文件添加全域名解析,安装与配置容器集群化的流程如图2所示.
表1 实验硬件环境
图2 容器集群化流程
配置成功后查看集群状态都是Ready, 同时显示生存时长和版本号.
首先部署Web 服务器,创建Web Server的 Pod 资源, Node1 部署为Web 服务器. 其次部署Web Server 的服务功能,主要涉及到IP地址和类型、通信协议、API 版本、命名空间、端口号、服务功能等配置,完成后网络信息如图3 所示.
部署MySQL 服务器,创建MySQL 的Pod资 源,Node2 部 署 为MySQL 服 务 器. 部 署MySQL 的服务功能,主要涉及到的网络服务功能等配置与Web 服务器类似,完成后网络信息如图4 所示.
修改配置文件中数据库的IP 地址参数,使得数据库应用与集群关联,如图5 所示.
图3 Web Server 网络信息
图4 MySQL 网络信息
图5 实验数据库配置
Web 系统架构中采用Docker 作为微服务的载体,由于在具体的应用中可能需要分割出大量的微服务,因此要调用Kubernetes 自带的插件式调度器. 它通过默认算法分配和调度具体的Pod 来运行微服务程序,每次调度一个Pod 容器,通过初选以及优选策略来决定待调度容器的最优Node 节点[8]. 文章采用资源负载均衡调度法,如图6 所示.
所有待调度容器组成待调度Pod 队列,所有可选的Node 节点组成Node 队列,调度器循环执行,每次取出待调度Pod 队列的队首元素进行调度. 首先进行预选策略,遍历所有Node节点或者部分节点,根据待调度容器的CPU内存等资源需求来筛选Node 节点,去除掉不符合最基本资源需求的节点. 接着采用资源利用最均衡优先级函数来打分,根据分数高低选择最优的Node 节点. 最后将待调度容器绑定到目标最优节点,启动容器即完成单个容器的调度过程[9-10].
该调度策略是从系统资源利用平衡度的出发,为了避免出现CPU、内存消耗不均衡的情况. 该调度策略的打分标准公式如下:
其中a为CPU 的申请率CPUFraction,b为内存资源的申请率memoryFraction,两者均表示为请求数与资源的比值. 当CPUFraction与memoryFraction 的值相等时,分值score 最高.
图6 资源负载均衡调度法
Web 系统的流量并发既具有周期规律又具有不可控的突发因素,实际应用中的不确定性需要集群具有伸缩性. 综合资源CPU 利用率,Kubernetes 提供实现Pod 水平自动伸缩功能的HPA 策略(Horizontal Pod Autoscaler)来支持集群的弹性伸缩. 传统的HPA 策略V1 版本资源伸缩时只关注CPU 的利用率,但是一般的网站不仅对CPU 资源需求高,而且对内存资源的需求也比较高. 文章通过资源监控采集到CPU 和内存的利用率,采用求二者均值的方式来调度资源.
图7 HPA 弹性伸缩策略
如图7所示,Kubelet 启动容器组的容器时,HPA 通过集群内的资源监控系统来获取集群中资源的使用状态. 系统将CPU、内存以及用户自定义的最大使用率等参数进行权值调和,根据指标参数来制定一个阈值,一旦超出阈值,HPA 就会自动计算伸缩尺度,决定增加或者缩减Pod 副本.
计算每次扩容或者缩容的Pod 的数量采用Ceil 函数:Ceil(( 目前使用率 / 自定义最大使用率) * Pod 数量). 该函数返回大于或者等于表达式的最小整数. 且为了系统的稳定,规定每次扩容Pod 数量不会超过当前Pod 数量的2 倍.
在集群中和外网机器上都是使用WebServer的地址访问网页,如图8 所示.
图8 访问Web 网站
基于微服务和容器的Web 系统架构可以保持高可用性和健壮性. 当网站的Pod 出现故障或者网站更新上线时,都无需中断当前业务的运行,系统会自动调度资源,用户体验是无感的.
高可用功能测试时,首先关闭运行MySQL数 据 库Pod 的Node 节 点[root@k8s-node2 config]# shut down now. 此时数据库已断开,如果没有采用Kubernetes 的Docker 集群调度,则用网站停止运行,网页提示连接数据库失败,如图9 所示.
图9 网站业务中断
Kubernetes 集群管理检测到Node2 的数据库Pod 失效,立即启用资源负载均衡调度法最后选择在Node1 创建MySQL 的Pod 用于支撑业务运行,恢复速度取决于集群服务器性能,在生产环境中通常是几秒之内,Pod 申请创建并成功运行. 再次测试网站业务,显示业务正常,如图10 所示.
业务在Kubernetes 集群的其中一个工作节点上运行,当工作节点意外宕机之后,Node节点的Kubelet 还能访问到另一个主节点的API Server 等组件进行运行、自动重调度、自动重启、自动复制,当支撑业务运行Pod 所在节点出现问题时,管理节点会检测到并在几秒内在健康节点启动新的Pod 支撑业务的运行.
图10 业务恢复正常
3.2.1 HPA 设置
部署弹性伸缩测试集群,如图11 所示. 设定最小Pod 实例值为1,最大值10. 用于计算所需的Pod 副本数量的指标列表metrics 包含有CPU 指标、内存指标、Pods 和特定指标Object. 其中核心指标resource,包含CPU 和内存两种, CPU 和内存的目标利用率都是设置为50%.
图11 HPA 指标设置
为了避免系统弹性伸缩过于动荡,HPA控制策略中有一个包容的概念,可以允许一定范围内指标不稳定,文章设置包容系数为0.1. 如果设定系统资源超过50% 触发扩容,那么只有当使用率大于55% 时发生扩容或者小于45% 触发缩容.
3.2.2 伸缩性测试结果
在测试前查看相关资源Pod 的副本数量,刚开始数量是2,如图12 所示.
图12 初始Pod 副本
创建一个模拟压力测试访问Web 网址http://192.168.127.126:30003/index.html. 利 用 率超出了目标使用率50% 且大于系统设置的包容系数10%,将触发扩容.
扩容后副本数量已经从原来的2 变成了6,如图13 所示.
图13 伸缩后Pod 副本
系统关闭压力测试后并等待一段时间,容器资源会自动缩回原来的规模.
传统的Web 平台有升级缓慢、架构臃肿、不能快速迭代、访问量大、易崩溃等问题. 通过Docker 打包微服务应用以及依赖包,将它们封装成一个可移植的容器,构建在集群中.集群通过负载均衡算法灵活调度和分配资源. 这个架构实现的形式多样化,不仅可以在物理机集群和私有云上运行,也可以托管到公有云中运行.
通过容器编排引擎Kubernetes 一键部署应用以及后期业务的运维,实现系统资源利用效率的提升,并且可以有效地共享物理资源. 相比传统在线教育平台运维部署模式,容器技术有助于在Web 平台业务开发实现高可用性、应用迭代敏捷和部署环境的一致性.