基于docker的haproxy的反向代理

haproxy介绍

haproxy的工作模型如下图,对于应用服务器而言,haproxy为应用服务器的流量入口,外部流量流经haproxy,haproxy跟需要可以提供L4(IP+PORT,报文解析到传输层tcp、udp)或者L7(解析流量报文到http协议)的流量分发,分发到不同的应用服务器(负载均衡)
基于docker的haproxy的反向代理
图片来源互联网

四层和七层负载均衡的区别

所谓的四层就是ISO参考模型中的第四层。四层负载均衡也称为四层交换机,它主要是通过分析IP层及TCP/UDP层的流量实现的基于IP加端口的负载均衡。常见的基于四层的负载均衡器有LVS、F5等。
以常见的TCP应用为例,负载均衡器在接收到第一个来自客户端的SYN请求时,会通过设定的负载均衡算法选择一个最佳的后端服务器,同时将报文中目标IP地址修改为后端服务器IP,然后直接转发给该后端服务器,这样一个负载均衡请求就完成了。从这个过程来看,一个TCP连接是客户端和服务器直接建立的,而负载均衡器只不过完成了一个类似路由器的转发动作。在某些负载均衡策略中,为保证后端服务器返回的报文可以正确传递给负载均衡器,在转发报文的同时可能还会对报文原来的源地址进行修改。整个过程下图所示。
基于docker的haproxy的反向代理

同理,七层负载均衡器也称为七层交换机,位于OSI的最高层,即应用层,此时负载均衡器支持多种应用协议,常见的有HTTP、FTP、SMTP等。七层负载均衡器可以根据报文内容,再配合负载均衡算法来选择后端服务器,因此也称为“内容交换器”。比如,对于Web服务器的负载均衡,七层负载均衡器不但可以根据“IP+端口”的方式进行负载分流,还可以根据网站的URL、访问域名、浏览器类别、语言等决定负载均衡的策略。例如,有两台Web服务器分别对应中英文两个网站,两个域名分别是A、B,要实现访问A域名时进入中文网站,访问B域名时进入英文网站,这在四层负载均衡器中几乎是无法实现的,而七层负载均衡可以根据客户端访问域名的不同选择对应的网页进行负载均衡处理。常见的七层负载均衡器有HAproxy、Nginx等。

这里仍以常见的TCP应用为例,由于负载均衡器要获取到报文的内容,因此只能先代替后端服务器和客户端建立连接,接着,才能收到客户端发送过来的报文内容,然后再根据该报文中特定字段加上负载均衡器中设置的负载均衡算法来决定最终选择的内部服务器。纵观整个过程,七层负载均衡器在这种情况下类似于一个代理服务器。整个过程如下图所示。

基于docker的haproxy的反向代理

对比四层负载均衡和七层负载均衡运行的整个过程,可以看出,在七层负载均衡模式下,负载均衡器与客户端及后端的服务器会分别建立一次TCP连接,而在四层负载均衡模式下,仅建立一次TCP连接。由此可知,七层负载均衡对负载均衡设备的要求更高,而七层负载均衡的处理能力也必然低于四层模式的负载均衡。

HAProxy的核心能力和关键特性

HAProxy的核心功能

  • 负载均衡:L4和L7两种模式,支持RR/静态RR/LC/IP Hash/URI Hash/URL_PARAM Hash/HTTP_HEADER Hash等丰富的负载均衡算法
  • 健康检查:支持TCP和HTTP两种健康检查模式
  • 会话保持:对于未实现会话共享的应用集群,可通过Insert Cookie/Rewrite Cookie/Prefix Cookie,以及上述的多种Hash方式实现会话保持
  • SSL:HAProxy可以解析HTTPS协议,并能够将请求解密为HTTP后向后端传输
  • HTTP请求重写与重定向
  • 监控与统计:HAProxy提供了基于Web的统计信息页面,展现健康状态和流量数据。基于此功能,使用者可以开发监控程序来监控HAProxy的状态

HAProxy的关键特性

  • 采用单线程、事件驱动、非阻塞模型,减少上下文切换的消耗,能在1ms内处理数百个请求。并且每个会话只占用数KB的内存。
  • 大量精细的性能优化,如O(1)复杂度的事件检查器、延迟更新技术、Single-buffereing、Zero-copy forwarding等等,这些技术使得HAProxy在中等负载下只占用极低的CPU资源。
  • HAProxy大量利用操作系统本身的功能特性,使得其在处理请求时能发挥极高的性能,通常情况下,HAProxy自身只占用15%的处理时间,剩余的85%都是在系统内核层完成的。
  • HAProxy作者在8年前(2009)年使用1.4版本进行了一次测试,单个HAProxy进程的处理能力突破了10万请求/秒,并轻松占满了10Gbps的网络带宽。

haproxy L7负载均衡示例

docker版本和centos版本

[root@master ~]# cat /etc/redhat-release 
CentOS Linux release 7.5.1804 (Core) 
[root@master ~]# docker -v               
Docker version 18.06.1-ce, build e68fc7a
[root@master ~]# 

docker镜像下载

haproxy:1.5.19
tomcat:9.0.12-jre8

docker pull haproxy:1.5.19
docker pull tomcat:9.0.12-jre8

[root@master ~]# docker image ls | grep -E "haproxy|tomcat"
tomcat                                                           9.0.12-jre8         62cd07af12f5        3 days ago          463MB
haproxy                                                          1.5.19              8892b24d066b        2 weeks ago         65.4MB

运行Tomcat

启动两个容器,分别为tomcat01和tomcat02,为了以示区别,启动容器后进入容器将首页内容进行调整

docker run -it --name tomcat01 --restart=always -d tomcat:9.0.12-jre8

docker run -it --name tomcat02 --restart=always -d tomcat:9.0.12-jre8

docker exec -it tomcat01 /bin/bash
cd /usr/local/tomcat/webapps/ROOT
root@70314f5c55b9:/usr/local/tomcat/webapps/ROOT# pwd
/usr/local/tomcat/webapps/ROOT
#将index.jsp修改为I'm tomcat01
root@70314f5c55b9:/usr/local/tomcat/webapps/ROOT# cat index.jsp
I'm tomcat01
root@70314f5c55b9:/usr/local/tomcat/webapps/ROOT# 

#使用同样的方法修改容器tomcat02
docker exec -it tomcat02 /bin/bash

容器运行后,在宿主机上如何访问

#查看容器的ip,分别为172.17.0.2和172.17.0.2
[root@master ~]# docker inspect --format '{{ .NetworkSettings.IPAddress }}' tomcat01
172.17.0.2
[root@master ~]# docker inspect --format '{{ .NetworkSettings.IPAddress }}' tomcat02
172.17.0.3
[root@master ~]# 

[root@master ~]# curl http://172.17.0.2:8080
I'm tomcat01
[root@master ~]# curl http://172.17.0.3:8080
I'm tomcat02

运行haproxy

docker run -d -it --name haproxy -v /root/haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro haproxy:1.5.19

haproxy.cfg

#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
 
#---------------------------------------------------------------------
# Global settings    
#---------------------------------------------------------------------
global    #全局配置文件
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:     #配置日志
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog    #修改syslog配置文件
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog    #定义日志设备
    #
    #    local2.*                       /var/log/haproxy.log
    #
    #log         127.0.0.1 local2        #日志配置,所有的日志都记录本地,通过local2输出
 
    #chroot      /var/lib/haproxy        #改变haproxy的工作目录
    #pidfile     /var/run/haproxy.pid    #指定pid文件的路径
    maxconn     4000                    #最大连接数的设定
    #user        haproxy                 #指定运行服务的用户
    #group       haproxy                 #指定运行服务的用户组
    daemon
 
    # turn on stats unix socket
    #stats socket /var/lib/haproxy/stats
 
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
     
    mode                    http                  #默认使用协议,可以为{http|tcp|health} http:是七层协议 tcp:是四层 health:只返回OK
    log                     global                #全局日志记录
    option                  httplog               #详细记录http日志
    option                  dontlognull           #不记录空日志
    option http-server-close                      #启用http-server-close
    option forwardfor       except 127.0.0.0/8    #来自这些信息的都不forwardfor
    option                  redispatch            #重新分发,ServerID对应的服务器宕机后,强制定向到其他运行正常的服务器
    retries                 3                      #3次连接失败则认为服务不可用
    timeout http-request    10s                    #默认http请求超时时间
    timeout queue           1m                     #默认队列超时时间
    timeout connect         10s                    #默认连接超时时间
    timeout client          1m                     #默认客户端超时时间
    timeout server          1m                     #默认服务器超时时间
    timeout http-keep-alive 10s                    #默认持久连接超时时间
    timeout check           10s                    #默认检查时间间隔
    maxconn                 3000                   #最大连接数
 
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend  main *:80
    #定义ACL规则以如".html"结尾的文件;-i:忽略大小写
    acl url_static       path_beg       -i /static /images /javascript /stylesheets
    acl url_static       path_end       -i .jpg .gif .png .css .js
 
    use_backend static          if url_static    #调用后端服务器并检查ACL规则是否被匹配
    default_backend             app              #客户端访问时默认调用后端服务器地址池
 
#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------
backend static                    #定义后端服务器
    balance     roundrobin        #定义算法;基于权重进行轮询
    server      static 127.0.0.1:4331 check    check #启动对后端server的健康状态检测
 
#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------
backend app
    balance     roundrobin
    server  app1 172.17.0.2:8080 check
    server  app2 172.17.0.3:8080 check

注意:
haproxy的官方镜像的Makefile
https://github.com/docker-library/haproxy/blob/5803ee6e7e1f542bb22dbf83761bbe908d8e66ab/1.5/Dockerfile
并且根据镜像运行容器时启动haproxy使用的是
CMD ["haproxy", "-f", "/usr/local/etc/haproxy/haproxy.cfg"]
并且镜像中并不存在/usr/local/etc/haproxy/haproxy.cfg此文件,所以我们在运行haproxy时,必须要使用-v或者volume挂载配置文件到容器的/usr/local/etc/haproxy/haproxy.cfg

当容器启动失败,可以使用docker logs查错误信息,进行排错后再启动

docker logs haproxy

最终效果

此处使用的lb算法为roundrobin(轮询),所以每次访问会分摊到tomcat01和tomcat02上。

[root@master ~]# curl http://172.17.0.4
I'm tomcat02
[root@master ~]# curl http://172.17.0.4
I'm tomcat01

haproxy配置文件参数说明

https://blog.csdn.net/tiny_du/article/details/81220660
http://blog.51cto.com/wuhf2015/1659308

L4负载示例

参考下面的博客中的haproxy
https://www.jianshu.com/p/c9f6d55288c0

keepalived

keepalived是什么

Keepalived软件起初是专为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入了可以实现高可用的VRRP功能。因此,Keepalived除了能够管理LVS软件外,还可以作为其他服务(例如:Nginx、Haproxy、MySQL等)的高可用解决方案软件。

Keepalived软件主要是通过VRRP协议实现高可用功能的。VRRP是Virtual Router RedundancyProtocol(虚拟路由器冗余协议)的缩写,VRRP出现的目的就是为了解决静态路由单点故障问题的,它能够保证当个别节点宕机时,整个网络可以不间断地运行。

所以,Keepalived 一方面具有配置管理LVS的功能,同时还具有对LVS下面节点进行健康检查的功能,另一方面也可实现系统网络服务的高可用功能。

keepalived官网http://www.keepalived.org

keepalived服务的三个重要功能

  • 管理LVS负载均衡软件
  • 实现LVS集群节点的健康检查中
  • 作为系统网络服务的高可用性(failover)

VRRP协议

参考
https://blog.csdn.net/xiaolinyouni/article/details/72854784
http://blog.51cto.com/billy98/2064252

keepalived架构

基于docker的haproxy的反向代理
keepalived也是模块化设计,不同模块复杂不同的功能,其组件包括:

  • core:是keepalived的核心,复杂主进程的启动和维护,全局配置文件的加载解析等
  • check:负责healthchecker(健康检查),包括了各种健康检查方式,以及对应的配置的解析包括LVS的配置解析
  • vrrp:VRRPD子进程,VRRPD子进程就是来实现VRRP协议的
  • libipfwc:iptables(ipchains)库,配置LVS会用到
  • libipvs*:配置LVS会用到

由图可知,两个子进程都被系统WatchDog看管,两个子进程各自复杂自己的事,checker子进程复杂检查各自服务器的健康程度,例如HTTP,LVS等等,如果checker子进程检查到MASTER上服务不可用了,就会通知本机上的兄弟VRRP子进程,让他删除通告,并且去掉虚拟IP,转换为BACKUP状态,并且会自动在ipvs内核添加相应的集群调度规则,所以说keepalived与lvs是天生搭配的。

keepalived工作原理

基于docker的haproxy的反向代理

Keepalived的工作原理:
  Keepalived高可用对之间是通过VRRP通信的,因此,我们从 VRRP开始了解起:

  • 1) VRRP,全称 Virtual Router Redundancy Protocol,中文名为虚拟路由冗余协议,VRRP的出现是为了解决静态路由的单点故障。
  • 2) VRRP是通过一种竟选协议机制来将路由任务交给某台 VRRP路由器的。
  • 3) VRRP用 IP多播的方式(默认多播地址(224.0_0.18))实现高可用对之间通信。
  • 4) 工作时主节点发包,备节点接包,当备节点接收不到主节点发的数据包的时候,就启动接管程序接管主节点的开源。备节点可以有多个,通过优先级竞选,但一般 Keepalived系统运维工作中都是一对。
  • 5) VRRP使用了加密协议加密数据,但Keepalived官方目前还是推荐用明文的方式配置认证类型和密码。

介绍完 VRRP,接下来我再介绍一下 Keepalived服务的工作原理:

Keepalived高可用对之间是通过 VRRP进行通信的, VRRP是通过竞选机制来确定主备的,主的优先级高于备,因此,工作时主会优先获得所有的资源,备节点处于等待状态,当主挂了的时候,备节点就会接管主节点的资源,然后顶替主节点对外提供服务。

在 Keepalived服务对之间,只有作为主的服务器会一直发送 VRRP广播包,告诉备它还活着,此时备不会枪占主,当主不可用时,即备监听不到主发送的广播包时,就会启动相关服务接管资源,保证业务的连续性.接管速度最快可以小于1秒。

keepalived配置文件详解

keepalived的配置文件分为三大部分:全局定义模块、VRRPD配置、LVS配置

参考:https://blog.csdn.net/mofiu/article/details/76644012

上一篇:JVM 类加载机制


下一篇:HashMap源码分析