HAProxy负载均衡实战

一、前言

本次实验的目的:
(1) LNMP动静分离部署wordpress,动静都要能实现负载均衡,要注意会话的问题;
(2) 在haproxy和后端主机之间添加varnish进行缓存;
(3) haproxy的设定要求:
(a) stats page,要求仅能通过本地访问使用管理接口;
(b) 动静分离;
(c) 压缩合适的内容类型;

4)最后添加一tomcat服务器,实现动静分离处理jsp动态请求。(补充)

部署拓扑图

二、LNMP环境搭建

1、配置nginx-dynamic

#安装nginx和php-fpm服务
[root@dynamic ~]# yum install -y epel-release
[root@dynamic ~]# yum install -y nginx php-fpm php-mysql php-mbstring php-mcrypt

#创建nginx web根目录
[root@dynamic ~]# mkdir -pv /data/nginx/html

#下载wordpress到指定目录并解压
[root@dynamic html]# cd /data/nginx/html/
[root@dynamic html]# wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
[root@dynamic html]# tar xf wordpress-4.9.4-zh_CN.tar.gz

#创建php动态测试页面
[root@dynamic html]# vim test.php
<html>
 <head>
  <title>PHP 测试</title>
 </head>
 <body>
 <?php echo '<p>Hello World</p>'; ?>
 </body>
</html>

#创建web根目录的默认html和php页面
[root@dynamic html]# vim index.html
<h1>This is dynamic</h1>
[root@dynamic html]# vim index.php
<h1>Dynamic</h1>
<?php
        phpinfo();
?>

#编辑配置/etc/php-fpm.d/www.conf文件
[root@dynamic html]# vim /etc/php-fpm.d/www.conf
listen = 0.0.0.0:9000
user = apache
group = apache
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
ping.path = /ping
ping.response = pong
pm.status_path = /status
slowlog = /var/log/php-fpm/www-slow.log
php_admin_value[error_log] = /var/log/php-fpm/www-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/session

#创建php-fpm的session目录
[root@dynamic html]# mkdir /var/lib/php/session
[root@dynamic html]# chown apache /var/lib/php/session/

#编辑创建nginx的配置文件
#注意在/etc/nginx/nginx.conf文件中注释下述两个默认配置
#        listen       80 default_server;
#        listen       [::]:80 default_server;
[root@dynamic html]# vim /etc/nginx/conf.d/dynamic.conf 
server {
        listen 80;
        server_name www.ilinux.io;
        root /data/nginx/html;
        index index.html index.php;
        location ~* \.php$ {
                fastcgi_pass 192.168.0.83:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME /data/nginx/html/$fastcgi_script_name;
        }
        location ~* ^/(ping|status)$ {
                fastcgi_pass 192.168.0.83:9000;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;

        }


#启动nginx和php-fpm服务并调整firewalld和selinux状态
[root@dynamic html]# systemctl start php-fpm
[root@dynamic html]# systemctl start nginx 
[root@dynamic html]# systemctl stop firewalld
[root@dynamic html]# systemctl disable firewalld
[root@dynamic html]# setenforce 0

2、配置nginx-static

#安装nginx服务和mariadb-server
[root@static ~]# yum install -y epel-release mariadb-server

#配置创建wordpress数据库
[root@static ~]# systemctl start mariadb
[root@static ~]# mysql
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 5.5.56-MariaDB MariaDB Server

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> create database wordpress;
Query OK, 1 row affected (0.00 sec)

MariaDB [(none)]> grant all on wordrpess.* to 'wpuser'@'192.168.0.%' identified by "magedu";
Query OK, 0 rows affected (0.00 sec)

#创建nginx web根目录
[root@static ~]# mkdir -pv /data/nginx/htm

#下载wordpress到指定目录并解压
[root@static html]# cd /data/nginx/html/
[root@static html]# wget https://cn.wordpress.org/wordpress-4.9.4-zh_CN.tar.gz
[root@static html]# tar xf wordpress-4.9.4-zh_CN.tar.gz 

#创建txt文本和复制相关的图片内容到web根目录下作为静态内容
[root@dynamic html]# cp /usr/share/backgrounds/*.{png,jpg} .
[root@static html]# vim poem.txt
 Quiet Night
I saw the moonlight before my couch,
And wondered if it were not the frost on the ground.
I raised my head and looked out on the mountain moon,
I bowed my head and thought of my far-off home.
by S. Obata

#配置创建web根目录的默认html和php页面
[root@static html]# vim index.html
<h1>This is static</h1>
[root@static html]# vim index.php
<h1>Static</h1>
<?php
        phpinfo();
?>

#编辑创建nginx的配置文件
[root@static html]# vim /etc/nginx/conf.d/static.conf
server {
        listen 80;
        server_name www.ilinux.io;
        root /data/nginx/html;
        index index.html index.php;
        location ~* \.php$ {
                fastcgi_pass 192.168.0.83:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME /data/nginx/html/$fastcgi_script_name;
        }
        location ~* ^/(ping|status)$ {
                fastcgi_pass 192.168.0.83:9000;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;

        }
}

#启动nginx服务并检查firewalld和selinux的状态
[root@static html]# systemctl stop firewalld
[root@static html]# systemctl disable firewalld
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@static html]# setenforce 0
[root@static html]# systemctl start nginx

3、配置varnish

#安装varnish服务
[root@static ~]# yum install -y epel-release
[root@static ~]# yum install -y varnish

#配置varnish的监听信息和系统参数
[root@static ~]# vim /etc/varnish/varnish.params
RELOAD_VCL=1
VARNISH_VCL_CONF=/etc/varnish/default.vcl
VARNISH_LISTEN_PORT=6081
VARNISH_ADMIN_LISTEN_ADDRESS=192.168.0.87
VARNISH_ADMIN_LISTEN_PORT=6082
VARNISH_SECRET_FILE=/etc/varnish/secret
VARNISH_STORAGE="file,/data/cache/varnish_storage.bin,1G"
VARNISH_USER=varnish
VARNISH_GROUP=varnish

#创建缓存目录
[root@static ~]# mkdir -pv /data/cache
[root@static ~]# chown varnish /data/cache


#编辑配置varnish的vcl
[root@static ~]# vim /etc/varnish/default.vcl
import directors;
probe static_healthcheck {
    .url = "/index.html";
    .window = 5;
    .threshold = 4;
    .interval =2s;
    .timeout = 1s;
}

backend static {
    .host = "192.168.0.84";
    .port = "80";
    .probe = static_healthcheck;
}


sub vcl_init {
    new BE = directors.round_robin();
    BE.add_backend(static);
}

acl purgers {
    "127.0.0.1";
    "192.168.0.0/24";
}

sub vcl_recv {
    if (req.method == "GET" && req.http.cookie) {  
        return(hash);
    }
    if (req.method == "PURGE") {   
        if (client.ip ~ purgers) {
          return(purge);
        }
    }
    if (req.http.X-Forward-For) {   
        set req.http.X-Forward-For = req.http.X-Forward-For + "," + client.ip;
    } else {
        set req.http.X-Forward-For = client.ip;
    }
        set req.backend_hint = BE.backend();  
        return(hash);
}

sub vcl_backend_response {  
    if (bereq.url ~ "\.(jpg|jpeg|gif|png)$") {
        set beresp.ttl = 1d;
    }
    if (bereq.url ~ "\.(html|css|js|txt)$") {
        set beresp.ttl = 12h;
    }
    if (beresp.http.Set-Cookie) {   
    set beresp.grace = 30m;
        return(deliver);
    }
}

sub vcl_deliver {  
    if (obj.hits > 0) {     
        set resp.http.X-Cache = "HIT from " + server.ip;
    } else {
        set resp.http.X-Cache = "MISS";
    }
}


#启动varnish服务并调整firewalld和selinux状态
[root@static ~]# systemctl start varnish
[root@static ~]# systemctl stop firewalld
[root@static ~]# systemctl disable firewalld
[root@static ~]# setenforce 0

二、HAProxy的搭建和配置

配置完后端的LNMP环境后,接着我们来配置HAproxy。

#安装haproxy服务
[root@haproxy ~]# yum install -y haproxy

#配置HAProxy记录日志到本地
[root@haproxy ~]# vim /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
local2.*                                                /var/log/haproxy.log
[root@haproxy ~]# vim /etc/sysconfig/rsyslog
SYSLOGD_OPTIONS="-r"
[root@haproxy ~]# systemctl restart rsyslog

#编辑配置haproxy的配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend  main *:80
    acl url_static       path_end       -i .jpg .gif .png .css .js .txt
    acl url_dynamic     path_end        -i .php
    compression algo gzip  #设置压缩算法为gzip
    compression type text/html text/plain image/x-png image/x-citrix-jpeg  #设置压缩的内容类型为相关静态内容
    use_backend static          if url_static
    use_backend dynamic     if url_dynamic
    default_backend             websrvs

backend websrvs
        balance roundrobin
        server web1 192.168.0.83:80 check  
        server web2 192.168.0.87:6081 check  

backend static  #添加varnish为静态服务,由varnish将代理处理静态请求
        balance roundrobin
        server srvs1 192.168.0.87:6081 check

backend dynamic
        balance roundrobin
        server dyn1 192.168.0.83:80 check

listen stats
        bind *:8080
        stats enable
        stats uri /admin?stats
        acl url_stats src 192.168.0.0/24  #配置ACL匹配本地网段
        stats admin if url_stats  #只允许匹配ACL的本地网段访问stats的管理页面



#启动haproxy服务
[root@haproxy ~]# systemctl start haproxy
[root@haproxy ~]# systemctl stop firewalld
[root@haproxy ~]# setenforce 0
[root@haproxy ~]# systemctl disable firewalld
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
Removed symlink /etc/systemd/system/basic.target.wants/firewalld.service.

三、测试

  • 1)LNMP动静分离部署wordpress,动静都要能实现负载均衡,要注意会话的问题。
    此时访问以.php的结尾的内容会被haproxy负载到dynamic服务器上处理,而访问.jpg,.png和.txt等静态内容则被负载到static服务器上进行处理。


    访问wordpress页面1

    访问wordpress页面2

由上图所示访问wordpres页面的动态和静态内容已被分开处理,静态内容代理到varnish上进行处理,而动态内容则代理到dynamic服务器进行处理。

此时访问http://192.168.0.81 默认会轮询到后端两个服务器上,如下所示:

[root@client ~]# for i in {1..10} ; do curl http://192.168.0.81 ; done
<h1>This is dynamic</h1>
<h1>This is static</h1>
<h1>This is dynamic</h1>
<h1>This is static</h1>
<h1>This is dynamic</h1>
<h1>This is static</h1>
<h1>This is dynamic</h1>
<h1>This is static</h1>
<h1>This is dynamic</h1>
<h1>This is static</h1>

但有些时候需要确保我们用户每次访问的都是同一个服务器,此时我们就需要配置会话保持。haproxy自身提供了会话保持机制,我们可以在haproxy配置里添加基于cookie来做的会话保持,从而实现用户每次访问的都是同一个服务器,如下所示:

backend websrvs
        balance roundrobin
        cookie WEBSRV insert nocache indirect
        server web1 192.168.0.83:80 check cookie web1
        server web2 192.168.0.87:6081 check cookie web2

重启haproxy后,用户通过web访问都会被调度到同一个后端服务器。


基于cookie的haproxy会话保持

其原理在于,haproxy会把客户端第一次的请求由哪个后端服务器处理,使用cookie告知给客户端。然后客户端之后的发送的请求都会带有此后端服务器的cookie,然后haproxy通过读取这个cookie的信息来判断连接请求该调度给哪个后端服务器。

  • 2)在haproxy和后端主机之间添加varnish进行缓存
    从此前的截图上,我们已经能看到,相关的静态内容已经被varnish缓存所“HIT”中了,这说明我们缓存已经生效了。


    静态内容缓存状态
  • 3)压缩合适的内容类型和设置stats page仅能通过本地访问使用管理接口。
    因为我们在haproxy的配置中设置了对相关静态内容进行压缩,所以访问相关静态内容时,如果响应报文带有相关的压缩字段,说明压缩已经成功,如:


    相关内容已压缩成功

此时访问stats页面,因为访问主机是本地网络,所以能够下图红框中的管理操作。如果不是指定的本地网段,则只能查看相关的stats状态,而无法进行管理操作。


stats页面

四、动静分离jsp动态内容(补充)

部署拓扑图

在dynamic服务上部署一个tomcat服务,haproxy上将jsp相关动态内容负载均衡到dynamic服务器的nginx服务监控的Ip和端口上,然后通过本机的nginx服务将jsp动态内容调度到tomcat上进行处理。

1、在dynamic服务器上安装tomcat

#事先下载相应的jdk源码包放置在/usr/local/src目录下,用于编译安装
#编译安装jdk服务
[root@dynamic ~]# cd /usr/local/src/
[root@dynamic src]# tar xf jdk-10.0.1_linux-x64_bin.tar.gz 
[root@dynamic src]# ln -sv /usr/local/src/jdk-10.0.1 /usr/local/jdk
‘/usr/local/jdk’ -> ‘/usr/local/src/jdk-10.0.1’
[root@dynamic src]# vim /etc/profile.d/jdk.sh
export JAVA_HOME=/usr/local/jdk
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
[root@dynamic src]# source /etc/profile.d/jdk.sh
[root@dynamic src]# java -version
java version "10.0.1" 2018-04-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.1+10)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.1+10, mixed mode)

#yum安装tomcat服务
[root@dynamic src]# yum install -y tomcat tomcat-webapps tomcat-admin-webapps tomcat-docs-webapp tomcat-lib

#配置开启tomcat的管理页面
[root@dynamic src]# vim /etc/tomcat/tomcat-users.xml 
<role rolename="admin-gui"/>
<role rolename="manager-gui"/> 
<user username="admin" password="magedu" roles="admin-gui,manager-gui"/>

#手动添加一个java测试页面
[root@dynamic src]# mkdir -pv /usr/local/tomcat/webapps/javatest/{classes,lib,WEB-INF}
mkdir: created directory ‘/usr/local/tomcat/webapps/javatest’
mkdir: created directory ‘/usr/local/tomcat/webapps/javatest/classes’
mkdir: created directory ‘/usr/local/tomcat/webapps/javatest/lib’
mkdir: created directory ‘/usr/local/tomcat/webapps/javatest/WEB-INF’

[root@dynamic src]# vim /usr/local/tomcat/webapps/javatest/index.jsp
<%@ page language="java" %>
<html>
    <head><title>TomcatA</title></head>
    <body>
        <h1><font color="red">TomcatA.magedu.com</font></h1>
        <table align="centre" border="1">
            <tr>
                <td>Session ID</td>
            <% session.setAttribute("magedu.com","magedu.com"); %>
                <td><%= session.getId() %></td>
            </tr>
            <tr>
                <td>Created on</td>
                <td><%= session.getCreationTime() %></td>
            </tr>
        </table>
    </body>
</html>

#配置编辑tomcat的serve.xml文件
[root@dynamic src]# vim /etc/tomcat/server.xml
      <Host name="192.168.0.83"  appBase="/usr/local/tomcat/webapps/"    #定义javatest访问路径
            unpackWARs="true" autoDeploy="true">


#启动tomcat服务
[root@dynamic src]# systemctl start tomcat

#配置nginx服务将jsp动态内容代理到tomcat监听的端口
[root@dynamic src]# vim /etc/nginx/conf.d/dynamic.conf
server {
        listen 80;
        server_name www.ilinux.io;
        root /data/nginx/html;
        index index.html index.php;
        location ~* \.php$ {
                fastcgi_pass 192.168.0.83:9000;
                fastcgi_index index.php;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME /data/nginx/html/$fastcgi_script_name;
        }
        location ~* ^/(ping|status)$ {
                fastcgi_pass 192.168.0.83:9000;
                include fastcgi_params;
                fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;

        }  
        location ~* /javatest\.* {  #把java动态内容的URI路径代理至tomcat
                proxy_pass http://192.168.0.83:8080;
        }
        location ~* \.(jsp|do)$ {    #将以.jsp和.do的动态内容代理到tomcat进行处理
                proxy_pass http://192.168.0.83:8080;
        }
}

#重载nginx服务
[root@dynamic src]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@dynamic src]# nginx -s reload

2、修改haproxy负载代理jsp动态内容

#修改haproxy配置文件中的fontend配置段的内容
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg 
frontend  main *:80
    acl url_static       path_end       -i .jpg .gif .png .css .js .txt
    acl url_dynamic     path_end        -i .php .jsp .do  #在url_dynamic ACL中添加以.jsp,.do为后缀的动态内容
    acl url_java    path_beg        -i /javatest  #添加tomcat动态内容的路径
    compression algo gzip
    compression type text/css text/html text/plain image/x-png image/x-citrix-jpeg
    use_backend static          if url_static
    use_backend dynamic     if url_dynamic
    use_backend dynamic     if url_java
    default_backend             websrvs

#重启haproxy服务
[root@haproxy ~]# systemctl restart haproxy
能通过haproxy代理访问到tomcat服务

上述截图说明tomcat的jsp动态内容能够被haproxy正常负载调度到tomcat服务器上,而此时相应的静态内容依旧能正常访问。


依旧能正常访问静态内容
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容

  • 互联网架构基础知识 一、网站常见架构 负载层 页面缓存层 web层 数据层 二、运维法则 缓存为王 尽量在前端(缓...
    魏镇坪阅读 4,786评论 0 9
  • 目录: HAProxy是什么 HAProxy的核心能力和关键特性 HAProxy的安装和运行 使用HAProxy搭...
    kelgon阅读 79,754评论 9 159
  • 在大型系统设计中用代理在负载均衡是最常见的一种方式,而相对靠谱的解决方案中Nginx、HAProxy、LVS、F5...
    欢醉阅读 4,567评论 1 5
  • 一.HAProxy介绍 HAProxy: 是法国人Willy Tarreau开发的一个开源软件,是 一款应对客户端...
    楠人帮阅读 1,089评论 0 2
  • 今天在Codecademy学编程过程中,突然意识到一件事情——我苦苦寻找的“用英语的场景”终于出现了。 自从知道学...
    老鹿在跑步阅读 212评论 0 1