负载均衡比较 | dpdk 和 lvs 对比 | Nginx 反向代理负载均衡实验

参考资料

Using nginx as HTTP load balancer

Maglev: A Fast and Reliable Software Network Load Balancer, Google Inc. UCLA SpaceX

MGW——美团点评高性能四层负载均衡 - 美团技术团队 (meituan.com)

Open-sourcing Katran, a scalable network load balancer - Engineering at Meta (fb.com)

NAPI polling in kernel threads [LWN.net]


负载均衡概述

        负载均衡是基于横向扩展(Scale out)的,保证高并发系统架构高可用的优化方法。常用的负载均衡方案有四层(传输层,IP+port)和七层(应用层,如http 的请求路径 url)。在域名解析上,也可以用DNS 做负载均衡(不过 DNS生效慢且存在多级缓存,不能保证集群中机器down掉后快速调整高可用)。路由器(三层交换机)也可以做负载均衡(三层,IP)。

        四层方案是基于篡改目标ip地址的技术,一个重点就是需要对头部信息进行解包,修改和分发,这个工作本来是路由器进行的,如果要把负载均衡放到服务机上,本身对服务机性能要求不是很高,因为就算所有的数据包都要先聚合到负载均衡宿主上,他也只需要篡改部分数据然后转发出去。四层方案有使用外部硬件的如 F5公司提供的F5硬件。对于 IP 数据包来说,在kernel 中进行路由分发是一个高效的软件方案,Linux 下有基于 netfilter 实现的开源软件方案 Linux virtual server (后来并入内核)提供内核态根据规则过滤包的四层负载均衡,能够达到 F5硬件的60%性能。四层方案基于 IP +端口号进行负载均衡,性能指标较好,灵活性不高。

        对于应用层协议,如 http,同一主机可以有不同域名,不同的请求对应不同的目录结构。可以使用应用层软件方案实现七层负载均衡。如本文使用的俄罗斯开源软件 Nginx。要求单机性能高,因为每个连接需要两个连接,也需要软件性能高(Nginx 本身是高性能的,能处理c10k,理想能处理c100k)。目前Nginx 已被 F5 收购。

        常用的网络应用架构设计,一般采用上游 DNS 指派分区服务器集群,然后服务器集群采用LVS + Nginx 的负载均衡方案。

       实际基于普通的 LVS的方案有一些缺点,之前在OS课里写网卡驱动的时候,已经通过论文明白了网卡Receiving livelock 存在的原因(我之前的讲解这方面知识的博客文章),实际在目前的高并发需求下,服务器启用linux 的NAPI 驱动的 polling 来缓解大量的网卡中断基本是必须的。同时 LVS 本身是基于 netfilter 的,他本身还是有context switch(netfilter v.s. dpdk),开销包括页表切换,Cache miss,流水线冲刷,对于C10M 问题开销不可忽略,在2018 Meltdown+Spectre 引发的地址隔离技术引入Linux后,这部分开销影响越来越大。目前,很多企业(如Google 的Maglev(论文提到可以用,不知道是不是用 dpdk)、Facebook 的Katran、京东(京东的负载均衡器名字太多了)、美团的MGW、爱奇艺的DPVS)都使用Intel 提供的DPDK套件进行 kernel baypass,直接全部在用户态进行。

       本文简单的学习一下怎么使用 Nginx 搭建一个七层反向代理实现的负载均衡器。至于四层的 LVS 和基于 DPDK 的方案这里就只点到上面的理论知识为止,有时间具体分析一下 DPDK 的 kernel bypass 再做一篇笔记。


反向代理介绍

一般集群的服务器分为有公网和内网的,也可以全暴露到公网。代理是用一个隧道让所有流量都传到代理服务器上,反向代理把一个端口的所有请求分出来传到localhost的其他端口去。如服务器上apache监听8080,然后ftp监听20、21,但是用户都能用80来访问服务器,80是被nginx监听的,然后根据域名来转发到localhost其他端口。

反向代理既支持不同服务,又支持同一服务。

而负载均衡是指同一个服务请求派发到不同的机器上去,他可以通过反向代理实现。在本实验,只根据单一的ip地址(因为没有备案的域名)。

Nginx 是一个俄罗斯开源高性能 HTTP 和反向代理 web服务器,同时支持邮件服务等,支持模块化,其最新版本在 windows 下使用异步IO IOCP,在Linux下使用 epoll(也支持 select 和poll)(epoll 的笔记:EPOLL 原理分析线索)从而实现高性能并发。


Nginx 反向代理负载均衡配置

以下操作环境为 Ubuntu18.04

安装 Docker

单机实践的时候,可以使用 docker 来完成集群的模拟。Docker 的主要原理其在操作系统学虚拟化和沙箱的时候基本都明白了,虚拟机是模拟整个 OS 通过硬件虚拟化运行在 host 上,而沙盒或者 docker 这种容器系统只是虚拟了一个让进程运行的环境出来,减少浪费,主要的 kernel 还是用 host 的运行,本质上是利用了 linux 的 namespace 技术(docker 只支持 linux 系统,win 上运行 linux container 的方法就是,先做一个 vm,再基于他跑多个 docker containers)。

由于 docker 的安装涉及东西比较多,如果要使用 apt 包管理器安装,需要配置 https源、安装新的源GPG key。这是因为 docker 的软件包没有同步到 ubuntu 上游,非 ubuntu 官方仓库中的的源都不会和 os 自带源列表一起提供。如果能用简单的方法把事情做好就用简单的。Docker 提供了脚本安装,只需要运行:

curl -fsSL https://get.docker.com | bash -s docker –-mirror Aliyun

安装结束后,可以运行 docker version查看安装信息。

安装 Nginx

由于 well-known port 必须要 root 才能使用,首先切换用户,然后再安装 nginx。理论上,nginx 也可通过 docker 运行。为简单,这里直接在 host 上运行。

然后运行 service nginx start 可以启动 nginx。

对于 service 这个东西,其实是这样的,在 linux 中,linux 由于常作为服务器应用使用,所以操作系统应当提供一些基础设施用来实现服务的管理。在 linux 下,后台运行并且不与控制终端绑定(从而键盘的 soft interrupt 等将不会引流)的进程成为 daemon 守护神,于是一般和这个有关的名称后缀都有一个 d。

一般程序安装的时候,因为 everything is a file,所以软件的安装本质就是一堆 cp 或者 mv 而已。Nginx 会往 /etc/init.d 目录去放一个 nginx 同名脚本,脚本中编写了 start、restart、update 等 shell 函数,如果要用于自启动, start 和 stop 函数是必须提供的。Service 的功能就是完成这个脚本的寻找,支持传参数去执行,屏蔽细节。

至于 init ,学 os 的时候直到自举成功之后第一个进程就是 init(之前写的笔记:Linux 守护进程),现在一般 init 都是 system V风格的。在 login 成功之后,就会去执行程序把 /etc/rdX.d 里面的全部东西完成开机启动。rc 一共有7个运行级别,分别对应着不同的运行方式和os状态(比如停机、重启)。然后其目录下面的所有东西则是一些软连接:

负责启动的程序会根据这些软连接的名字来进行一个脚本的启动。比如这里 K01nginx 是意思就是说 stop,S01nginx 就是 start,01 则是顺序,一般没有顺序要求的化直接就是 01 了。

而 systemctl则是用来管理这些的一个命令(用户程序),他绑定的是 system V init(对应的即上面说的 rc 系统)。如果想要开机自启我们需要去 rcX.d 里面添加修改软连接。当然我们也可以手动添加软连接和直接运行 init.d 里面的内容。Service 是简单的执行服务的(run a System V init script),他只能去 init.d 里面去执行命令,不用自己执行脚本,但是不能管理开机启动,这是因为开机启动的东西由init 进程会执行的的系统服务进程决定(即这些 K、S 软连接由谁启动),早期一般用chkconfig 进行这个管理,后来 Ubuntu(本质是 debian)引入了update-rc.d 命令,也移除了 chkconfig。systemctl 还能更多功能,因为他是用来管理整个 systemd 的,而systemd 是系统自居后 init 进程启动后要运行的服务(用来初始化 os,运行哪些 rc.d 什么的)。

当所有事情解决后,可以在浏览器看到 Nginx 自带的 web server 已经运行成功了:

Nginx目前默认是启动为一个 http web 服务器。之后把他改成做反向代理。然后服务器用 node.js 运行。

配置服务器

首先安装好 nodejs 的 docker 镜像。通过 docker pull 命令安装即可

随后创建目录用于创建 docker服务器镜像。

准备好 Dockerfile:

和nodejs 的服务器代码: 

其中,Four 这个单词如法炮制修改。

通过 docker 命令创建 4 个 docker 镜像。

docker image build -t 名字 .

其中 -t 后是 docker 镜像的名字。点是当前有 dockerfile 的目录。

然后我们运行 4个镜像,通过 -d 后台运行,-p 绑定容器内端口号和外部端口号。

docker run -d -p 8971:2321 docker1

之后如法炮制4 个:

从而可以进行访问:

配置 nginx 为反向代理模式

nginx 配置和实际运行,我们知道 nginx 是 master – worker 的多进程单线程模型。其中 master 负责接受信号(比如更新 conf 时用到的 nginx -s reload),如果不是异步IO(如 windows 的 IOCP)则监听连接(LT epoll,ET 可能丢失连接请求,尤其是平滑重启的时候),和发信号(用 kill)给worker processes(pid 是存到某个文件里面的)。

Worker process 做的是通过 epoll(connect d 用 Edge trigger) 等待 mater 的通知事件,醒来之后进行一些操作,比如添加一个新的 connection,或者自杀更新配置等。

修改 /etc/nginx/nginx.conf 为下面的配置:

# 全局命令,用于配置 nginx 和 os 的联动参数,比如 pid 文件、日志、进程数

events {
  # events 配置 nginx 的运行属性的,比如最大连接数、事件驱动模型(epoll\poll\select)
}
http 
{
  upstream mysvr {
    server 127.0.0.1:8971 weight=1;
    server 127.0.0.1:8972 weight=1;
    server 127.0.0.1:8973 weight=1;
    server 127.0.0.1:8974 weight=1;
  }

  # 这个会放进 worker 的 polling 列表里
  server
  {
    # 监听端口
    listen 80;
    # 监听地址
    server_name 120.55.168.49;

    # 这个是事件就绪后起来读入请求然后做一次路由,如反向代理、 cgi 或者其他的参数请求
    location = /favicon.ico{
      log_not_found off;
    }
    location = /
    {
      proxy_pass http://mysvr;
    }
  }
}

其中要设置 favicon 是因为每次访问,浏览器都会进行两次 request:

所以我们要禁止浏览器请求 favicon 导致 nginx 访问服务器确定无返回(由 nodejs 的http 服务器框架处理的)。之后就能看到 round-robin 的负载均衡了(虽然配置里用了 weight ,但是我什么也没有配置)

 再请求:

 再请求:

 

宕机(down 机)测试

多机负载均衡同时能够增加稳定性,尝试下线一个docker 容器:

 随后再请求访问 nginx 服务器 80端口:

 

 

可以看到虽然三号机宕了,但是服务整体运行正常。

我们去看一下 nginx 的错误日志(/var/log/nginx):

可以理解 nginx 负载均衡时的行为,每次浏览器来一个HTTP1.1请求(默认长连接)的时候,由于配置upstream 的时候没有配置长连接,nginx 会转为短链接去负载均衡的上有服务器,如果发现宕机了,就把他标记为 failed,然后好一会都不连接他。我们重新启动 docker 容器,可以发现 nginx 又恢复了对 server 3 的路由:

Ip_hash 策略

有时候需要绑定(比如方便缓存有效性什么的)客服。注意的是 nginx 此时不会自动剔除宕的机,不过总是可以方便通过插件或者其他参数设置保证可用性

 随后分别在服务机和客户机进行访问(一个用浏览器一个用 wget):

其他策略

Nginx 还支持 least_conn 通过连接数公平,这是基于代理本身如果维护的连接耗时较长,nginx 可以记录已建立但未完成连接的次数,对于长连接服务、耗时较长的服务很有用。Nginx 还可以通过第三方模块思想其他策略的负载均衡。常用的比如 fair  和 url_hash 这里不述.

注释:这个后半部分写成实验报告一样的东西是因为这个是本学期分布式系统课程的作业。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值