新东方的负载均衡架构探索和实践

2020-05-25 00:00:00 数据库 配置 容器 负载均衡 边界

文由4月12日晚姜江,新东方运维工程师所做的技术分享整理而成。
姜江,一名伪SRE。十余年IT运维从业经历,早年在金融行业从事linux,AIX,Oracle的运维支持,现在专注于运维自动化、容器和cloud native相关技术的研究和落地。目前就职于新东方,负责新东方容器云平台的探索和实践。


大家好!话说加入Rancher官方微信群也有三年多了,每天在群里看着大家讨论技术问题给我很多启发 。 我今天也来和大家分享一下我在rancher上的一些实践,希望能为各位的实践提供一些参考。

为了避免大家歧义,下面说的Rancher指的Rancher 1.6 上的cattle引擎。

摘要

Rancher是一个对用户很友好的产品,吸引了大批的用户和粉丝。在实际落地过程中,大家可能已经注意到Rancher组件之间的耦合存在单点。那么如何部署才能提高Rancher的可用性和可扩展性呢?Rancher在官方文档中给出了一些指导方案,用户可以根据自己的需要选择合适的方案落地。我今天和大家分享的是新东方在Rancher全组件负载均衡架构的实践,供大家在探索自己的高可用方案时做个参考。

1. Rancher的部署架构演变

Rancher 1.6是一套小巧而实用的容器管理平台,我个人认为Rancher的定位应该是容器编排引擎的后台支撑系统, 或者说是编排引擎的系统,因此Rancher1.6的架构并不是分布式架构,而是传统的C/S架构。 无数的client(agent)连接到一个中心的Server ,中心的Server连接一个数据库做持久化。这种架构就必然会涉及一个老话题,如何增强C/S之间的高可用性、可扩展性和解耦问题。我今天和大家聊内容是:Rancher 1.6 全组件负载均衡设计。

一般Rancher的简单部署方案是这样的:



一个server,一些节点 ,一个mysql数据库。从这张图上就可以发现Rancher在部署上的一些问题:

  1. SPOF问题,Server的单点,数据库的单点等。
  2. 扩展性问题,单server能带动的client数量有限。
  3. 强耦合问题,server 写死数据库地址,client写死server地址等等。

总结下来就是下面这个图



下面就对这个架构进行优化,我们的目标是达到Server/Client 和数据库三个组件的自由扩展,如何做到呢? Rancher官方文档中已经给了答案,只需要在C/S 中间增加一层负载均衡方案,在数据库一侧增加高可用方案即可。

总体架构就演变为这样:



我们看到,Server一侧使用Rancher Server HA方案,将server扩展为多个。

中间增加一层负载均衡,这个负载均衡常见的私有云方案有LVS+Nginx或者F5, 在公有云中可以使用阿里云的SLB或者AWSELB等等。Rancher的数据量并不算太大,可以简单的使用Mysql的主从方案。

优化到这步已经可以满足日常工作需要了,这里大家会注意到mysql主从还是会影响server的可靠性。 一旦出现主库问题,Mysql切换的时候server肯定就down了, 切换也需要一定的时间,启动后还需要重启server等等。如果希望更进一步提高server的可靠性,或者希望数据库切换对Rancher Server透明,那就需要使用更的数据库高可用方案。

我们的DBA推荐使用Maxscale中间件+Galera 集群的方案, Galera为多主库的分布式数据方案,发生写入操作后Galera会同步数据到其他数据库中,直到同步都完成后返回完成写入操作。MaxScale是数据库中间件,它通过解析mysql协议判断读写操作,可以将读写操作分离。一旦数据库发生故障整个数据库集群的切换对外界是无感知的。

这个方案的部署图是这样的:



每个组件都介绍一下, 负载均衡采用互联网常用的LVS-DR+Nginx方案。数据库采用Galera集群做多主库的数据库复制,通过Maxscale中间件来做高可用和读写分离。

这就是我们现在终的架构, 这个架构的好处有几点:

  1. 可靠性大大增加, 所有组件都可以扩展,server, client,数据库和负载均衡本身。
  2. 每个组件的扩展并不影响其他组件,所有组件的扩展都可以在线进行。
  3. 配置解耦,通过域名映射的方式,server连接数据库的域名映射为maxsacle中间件的ip, client连接server的域名映射为负载均衡的Vip。
  4. 故障切换透明,对其他组件无感知。数据库故障,server故障都可以在线解决,解决后重新加入集群。

顺便提一下,这个架构中的数据库部分还可以进一步优化为:



MaxScale前增加一层LVS四层负载均衡(设备可复用c/s之间的负载均衡),那么这个方案就可以说是全模块无死角的负载均衡架构了。 但是我们实际实施的时候并没有采用这样的方案,考虑到 Rancher Server 和 Client断开一段时间后并不会影响主机上的容器运行。

这段时间完全可以做一些维护, 采用 Galera和Maxscale后已经大大的减少了数据库切换时间,并且实测MaxScale的稳定性很好,感觉没有必要再投入更多资源在MaxScale上。更何况加入更多的组件会使得整个系统的复杂度上升,这实际上增加了维护成本并且扩展了故障域,可靠性有可能不升反降。因此这个方案也只是停留在纸面上了。

那么说到这里大家对整体架构就有了初步认识,下面说说实现。

篇幅和时间原因,我这里只是点一下配置的要点,具体的实践过程可以关注我的工作笔记 http://jiangjiang.space

2. Rancher各个组件负载均衡的配置

2.1 LVS-DR + Nginx

LVS-DR设置:
LVS1 : 配置keepalived,配置虚拟ip,配置到Nginx1和Nginx2的四层转发
LVS2 : 配置keepalived,配置虚拟ip,配置到Nginx1和Nginx2的四层转发
Nginx1 :配置nginx 到 rancher server 8080 上的七层转发
Nginx2 :配置nginx 到 rancher server 8080 上的七层转发

A. 安装keepalived 和 ipvsadmin
LVS从2.6内核开始就已经是内核的一部分了,因此只需要安装ipvsadmin和keepalived,通过yum安装或者源码安装都可以,步骤略过。

B. 配置keepalived.conf
vi /etc/keepalived/conf/rancher.conf



C. Nginx节点配置
Nginx节点配置分为两部分:
1.虚拟IP(VIP)设置到回环设备上(lo),当接收到lvs发来的包后本机网卡才会处理这些包。

2.设置Nginx的Websocket转发到rancher server的8080端口上。

VIP配置在lo上的配置:




下面设置Nginx的Websocket转发到Rancher server的8080端口上。 安装nginx过程略过,在conf.d中增加虚拟主机配置。 vi /usr/local/nginx/conf/conf.d/rancher.conf



配置好后,直接访问 http://VIP:80 应该就可以看到Rancher控制台界面了。如果没有则是配置错误,继续调整。

参考文档: cnblogs.com/liwei0526vi rancher.com/docs/rancheconfiguration

2.2 galera 和 Maxscale

以下步骤摘自新东方DBA傅少峰的文档。 mariadb.com/downloads 下载并安装mariadb 10.2

安装如下rpm包
MariaDB-client-10.2.11-1.el7.centos.x86_64
MariaDB-devel-10.2.11-1.el7.centos.x86_64
MariaDB-server-10.2.11-1.el7.centos.x86_64
MariaDB-common-10.2.11-1.el7.centos.x86_64
MariaDB-compat-10.2.11-1.el7.centos.x86_64
galera-25.3.22-1.rhel7.el7.centos.x86_64.rpm
jemalloc-3.6.0-1.el7.x86_64.rpm
jemalloc-devel-3.6.0-1.el7.x86_64.rpm
maxscale-2.1.16-1.centos.7.x86_64.rpm
maxscale-devel-2.1.16-1.centos.7.x86_64.rpm
maxscale可以复用其中一个数据库节点或者单独部署到一个机器。

mysql配置注意的地方,其他参数省略。



galera配置



执行:



建立cattle数据库和用户(连接任何一个galera实例执行):



创建maxscale监控用户(连接任何一个galera实例执行):



数据库准备完毕,下面是配置MaxScale。

MaxScale配置
配置文件: /etc/maxscale.cnf




启动 maxscale



参考资料: jianshu.com/p/772e17c10 rancher.com/docs/ranche linux.cn/article-5767-1

2.3 server 、client 和 数据库的连接和设置

数据库准备好了,下面就可以启动server了。启动过程非常简单,只需要修改rancher server的启动参数如下:



逐条解释一下:



Server启动后就可以增加client了,登陆Rancher管理控制台,选择infrastructure->Hosts->Add Host



这样一个完整的负载均衡的Rancher就搭建完成了。

3 应用交付和负载均衡

现在说后一个话题,应用交付和负载均衡。 所谓应用交付说的是如何将Rancher上的一个应用公布到公网上给用户使用。为了能在前方接住大量的用户请求,一般都会统一搭建站点级别的入口负载均衡。示意图如下:



如图所示,用户请求从公网进来后,通过各路ISP接入设备到达站点边缘,连接通过各种防御设备到达入口负载均衡(LVS+Keepalived+Nginx),再由入口负载均衡统一代理到内部源站点上,这就是常见的应用交付过程。

在Rancher上的应用对接入口负载均衡一般采用Traefik, Traefik是一个容器化7层代理软件,性能接近Nginx。 之前群里也有多位大拿分享过Traefik的应用, 我这里就不重复介绍了,大家可以参考爱医康架构师张新峰的分享:《关于高可用负载均衡的探索》

我下面要讲的是 traefik与 LVS+Nginx负载均衡的对接和我对traefik的一些实践。

利用traefik交付应用的整个过程我总结为下图:



  1. 用户在浏览器中输入myxdf.com,通过DNS查询到这个域名对应的公网ip地址。
  2. 这个公网ip地址指向我们站点的入口负载均衡(LVS+Nginx),入口负载均衡收到请求后根据域名的设置,将请求转发给Rancher 上的Traefik节点,我称这些节点为Ranhcer edge。
  3. traefik收到请求后,根据traefik.frontend.rule将请求转给打了标记的容器(或者rancher lb)

根据这个流程我们需要做以下几个配置。

3.1 定义边界(rancher edge host)

什么是边界? 边界就是Rancher cluster中对外转发的中转站,边界是特殊的一个Rancher host,边界上只跑treafik,其他什么容器都不跑,边界好也不要接入任何存储(比如Rancher nfs),边界需要做严格的安全加固。 当然也可以不将边界放在专门的host上,可以将边界混合到整个Rancher 集群中,这样的好处是节省计算资源,两种模式都可以。

下面介绍如何将host定义为专门的边界节点:在Ranhcer 控制台上, 打开 infrastructure ,点击Hosts中。找到作为边界的host点击Edit:



在Labels中增加label,增加这个label后traefik就会自动运行在这台host上。



在 Required Container Label 中随便增加一个lable不用给值, 我这里写的cn.xdf.edge


这个lable加入后,这个节点上就不会被调度任何其他容器了。这样一个边界节点就制作好了。

3.2 启动traefik 到 边界节点

在社区商店中找到这个可爱的小交警,启动traefik。



配置说明如下:



好了启动traefik后,容器已经在edge Host 上启动了!



登陆管理界面看看:



3.3 在traefik上发布应用服务

假设现在要把mydockerapp04.myxdf.com这个域名的应用发布出去。 首先将mydockerapp04.myxdf.com这个域名匹配到对应的Rancher stack上面去。



这个就是我们的mydockerapp04应用, 它是一些tomcat容器和一个内部lb组成的。



按照traefik的文档,只需要将label打到容器上即可,这里我的做法是增加了一个内部的lb,直接将label打在lb上。这里必须的label是:



label加入后应用就发布到traefik中了。

3.4 从站点入口负载均衡转发到Traefik

在站点入口负载均衡上做转发配置,转发到treafik边界节点。 负载均衡上所有源站都是通过80端口转发,通过设置不通的server_name来区分转发目的地。将server_name设置为*.myxdf.com 。意思是所有 myxdf.com的二级域名全部转发给traefik,这样做是为了跳过在入口负载均衡上配置明细转发规则(比如mydockerapp01转发到哪里这样的一条一条的规则),所有明细的转发规则全部交给traefik来管理。

这样做有很大的优势,我们之前也看到了traefik设置转发规则非常简单,只需要在容器或者ranhcer lb上打label即可。如果需要修改或者删除规则,也只需要修改或删除对应的label即可,管理灵活又免去了每次都要手动到入口负载均衡上刷新配置的麻烦。

Nginx配置如下:



3.5 在DNS上设置域名指向站点入口负载均衡

在DNS上添加域名指向, 这里就没有办法偷懒了,需要把所有明细域名都写上。



如果你不是公网应用,也可以使用dnsmasq或者bind 甚至 AD域的DNS 等在内网建立DNS指向,DNS指向的IP为内网LVS的vip。

Rancher里面也有修改DNS的APP,比如aliyun DNS、Gandi.net 等等。这些APP有的是自动添加DNS记录的,有的是根据label添加,大家有兴趣可以继续研究下。

至此, 整个转发过程就完成了。 用户已经可以通过外网访问这个应用了。
通过浏览器:打开 mydockerapp04.myxdf.com



当然这个域名其实并不存在,是我瞎掰的,只为了方便大家理解这个过程。那么今天的分享也就结束了,下面是提问时间。

Q&A

Q1:数据库、负载均衡、Rancher是跑在裸机还是虚拟机上?

A1:数据库,负载均衡,Rancher都是虚机, 我们站点的入口负载均衡是物理机,大家share。

Q1补充:里面的问题是不是全部跑在docker容器里面啊?

A1补充:全部在虚拟机上。

Q2:请问容器数据持久化使用的什么啊?

A2:本机volume 和Rancher nfs ,另外glusterfs 读存储是Rancher nfs ,写存储是glusterfs。

Q3:除了卷挂载方式还有其他持久化方法吗?

A3:牛小南总那里做了一套Rancher 的ceph你可以尝试一下。目前我也没找到更好的挂载卷方式。

Q4:咱们现在的集群规模有多少台主机?traefik和dns都是自动配置的吗?服务的网络模式是managed,有host模式吗?对于cpu型容器,内存型和网络传输型容器有分类管理吗?

A4:其实目前主机并不多,不到20台, 按照Rancher官方文档估计一个server应该能带动50个节点。 traefik和dns可以自动配置,需要对应你自己的环境做一些脚本。网路是rancher vxlan,内存型有,网络传输类的还没有,后期考虑。

Q5:proxysql与maxscale哪个好,MySQL数据卷是容器吗?

A5:mysql是虚机跑的,proxysql也是一个中间件,功能差不多,我们没有应用所以不好对比。

Q6:边界、数据库、LB、Rancher总共大致用了多少台主机?

A6:这里其实是给大家做的一个demo 边界两台,数据库三台,lb四台, Rancher两台。我们具体的环境就不太方便透露啦。

Q7:请问是否有将spring boot 微服务应用到Rancher上?具体是如何实践的?

A7:spring boot目前Rancher社区商店里还没有,我也在考虑是否做一个。如果你有了解也可以定制一个贡献给社区。

Q8:Rancher上的应用都是无状态的么?有状态的话,存储用的什么?性能如何?

A8:rancher适合做无状态应用。有状态的我近在搞es,直接用的本机硬盘。我们本机硬盘有ssd加速所以还好,而且es这类应用,本来就是分布式,一个两个节点出问题是有的补救的。 其他有状态应用就要小心了,我也一直在观察cattle对这些应用的调度。一般可以通过打host label 来限定实例所在主机等方式。但是总体来说有状态应用还是要小心又小心。

Q9:请问 traefik 一个域名根据项目path选择转发不同的web应用该如何配置?

A9:在traefik的文档里是有的,我没有记错的话是 traefik_path。还是具体查一下文档。

Q10:请问,如何将应用发布到集群中,可以讲个大概思路么?包括灰度,红绿。

A10:灰度和蓝绿都可以借助traefik。启动多个stack通过切换label来做。简单一些的可以考虑用service的升级功能,升级后替换镜像。

Q11:gkusterfs是直接挂Rancher client主机上么?

A11:早期glusterfs 有Rancher对应的app后来去掉了。现在我的做法就比较土了,就是直接映射子目录上去。我也没找到更好的办法,期待群里有大牛能分享下这部分。

Q12:我们都知道Java项目启动比较费时,从容器启动成功到Java项目启动成功还是有一定时间的,项目启动成功后有时候还需要一个预热的过程,否则请求打上来很容易超时。请问如何实现Java项目完全正常前不会加入到Traefik负载后端造成502?

A12:这个之前在群里有类似的讨论,也可以这样:先启动应用,label先不打,或者打到一个静态应用上显示个sorry页面之类的。 等应用完全ok了再打上去,可以配合api搞个自动化。

Q13:请问四层负载与七层负载有什么区别?

A13:简单的说,4层就是常说的tcp层面负载均衡,比如socket之类的;7层就是http等。我刚刚给出的参考文档里面有详细说明,先了解下。

Q14:请问有没有实现根据请求负载的压力自动扩缩容?

A14:目前正在搞,大家也知道现在2.0出来了,本来自动扩缩容,日志和监控都要细化的。我们项目可能1.6 、2.0都会用,后面再考虑吧。

Q15:用的cattle环境还是k8s?考虑点是什么?

A15:cattle。cattle很小巧,简约,学习成本低。因此全世界范围内有不少粉丝。cattle做无状态应用做的很ok。因此我们先搞cattle。后面也会引入k8s。

Q16:rancher中使用webhook是否可实现自动扩容?

A16:可以的,甚至可以通过zabbix做的trigger来调用webhook。网上这方面介绍挺多的。

Q17:你觉得Rancher目前哪些部分还需要完善?

A17:说说cattle。我之前还在想,是否应该给cattle加入有状态支持,现在想想cattle本来的优势就是架构简单,所以还是继续保持吧。 就做好无状态也很好。

再说说Rancher,我觉得Rancher应该在1.6中去掉 mesos。swarm/k8s等七七八八的支持,以后1.6系列改名为cattle就专心搞无状态,比如之前有嘉宾分享就用cattle做ipfs,或者就用cattle做负载均衡等等。 这样cattle其实有自己很好的定位。Rancher则踏踏实实的去做k8s的后台支持和管理,品牌定义清晰、集中资源。

Q18 :可以通过内存或cpu监控来自动做容器的扩缩容吗?有没有什么组件可以实现?

A18:可以,webhook就ok。我之前就打算用zabbix的trigger来做,你也可以直接在你的应用里面调用Rancher api 或者webhook。这部分还没有继续深入研究,等有成果再和大家分享。

Q19:Rancher在2.0中只支持了k8s吧,cattle是不是就不支持了?

A19:我也是看群里大家讨论,cattle在2.0 beta彻底去掉了。官方继续支持一年,随后我估计就是社区支持的状态了。

Q20:文中提到“每个组件都介绍一下, 负载均衡采用互联网常用的LVS-DR+Nginx方案。数据库采用Galera集群做多主库的数据库复制,通过Maxscale中间件来做高可用和读写分离。”

请问为什么必须使用lvs+nginx,我个人感觉nginx完全可以满足需求了啊?lvs+keepalived或者nginx+keepalived就足够了,这里有什么特殊原因吗?

A20:是这样的。一开始我也是一个nginx,后来就想得给nginx做高可用,就增加了keepalived ,这个是没问题的。后来又一想以后机器多了怎么办? 来个负载均衡吧。自然就选择了常用lvs+nginx。 lvs-dr+nginx 你可以看一下我附上的参考文档,里面介绍的很详细。希望能对你有帮助。

Q21: haproxy与nginx优劣是什么?哪个更适合生产环境?Rancher中使用的是haproxy而不是nginx,这说明haproxy更好吗?

A21: nginx目前应用为广泛,其实两者现在功能上在互相追赶,性能上也有很多对比。 这就是看你熟悉哪个了吧。 国内互联网行业大部分都是nginx, 应用广,案例多,所以我们也是nginx。

Rancher里面的haproxy我估计是这样的,因为之前nginx做4层负载均衡差一些,因此大多数厂商都选择haproxy,包括红帽的openshift里也是内嵌haproxy。我觉得还是出于功能考虑。之前群里有大牛讨论 kong traefik这些新性技术现在选择更多了,还是看自己的喜好吧。

Q22:以后Rancher2.0主用k8s,不用cattle了吗?

A22:据说不支持了。

Q23:单个Rancher Server能带多少Agent?

A23:官方文档说 8G jvm的server 一个能带 50个agent。具体我也没有测过,群里我看多有跑host很多的朋友,期待他们以后有机会分享下。

微信号:RancherLabs

相关文章