拓扑结构介绍

        在实际的生产使用过程中,一个基本的能够应对日均百万PV的网络,一般会具有以下几种结构。

%E5%9F%BA%E6%9C%AC%E7%9A%84%E7%BD%91%E7%

这其中每种结构担负了不同的角色。

  • 代理服务器,负责进行请求调度,实现了负载均衡。

  • KeepAlived配置代理服务器实现了高可用。

  • 缓存服务器,实现了资源的缓存,提高了请求的命中率,加快了访问速度。

  • 动静分离,减轻后端服务器压力,提高资源访问速度。

  • 数据库主从复制,读写分离,降低了数据库的压力

  • 运维监控系统,实时监控系统运行状态。

  • 自动化运维控制系统,批量管理大量服务器。

  • 版本控制系统,在应用的迭代过程中有着至关重要的作用。

实验结构介绍

        下面,我们来模拟实现一个简单的网络集群结构。下面是这个结构的网络拓扑图。

%E5%AE%9E%E9%AA%8C%E7%BD%91%E7%BB%9C%E6%

实验环境介绍

序号 担任角色 主机名 地址 功能描述
A 互联网客户端 windows 172.18.2.22 充当互联网用户进行网络访问
B 代理服务器 haproxy VIP 172.18.3.77;DIP 192.168.22.77 对网络请求进行调度,实现均衡负载
C 缓存服务器 varnish 1 192.168.22.33 针对网络请求进行缓存,同时对后端服务器进行动静分离,并提供均衡负载
D 缓存服务器 varnish 2 192.168.22.44 针对网络请求进行缓存,同时对后端服务器进行动静分离,并提供均衡负载
E 静态web服务器 staticweb1 192.168.22.100 提供静态的网络服务,例如html,js,css之类
F 静态web服务器 staticweb2 192.168.22.101 提供静态的网络服务,例如html,js,css之类
G 动态web服务器 dynamicweb1 192.168.22.200 提供动态的网络服务,例如PHP,jsp等
H 动态web服务器 dynamicweb2 192.168.22.201 提供动态的网络服务,例如PHP,jsp等
I 数据库服务器 database 192.168.22.128 提供数据库服务,供应用程序进行读写操作

实验过程中,首先关闭SELinux和防火墙策略

一、配置HAproxy

        在主机A上安装HAProxy,并对其进行配置。

global    log         127.0.0.1 local2    chroot      /var/lib/haproxy    pidfile     /var/run/haproxy.pid    maxconn     4000    user        haproxy    group       haproxy    daemon    # turn on stats unix socket    stats socket /var/lib/haproxy/statsdefaults    mode                    http    log                     global    option                  httplog    option                  dontlognull    option http-server-close    option forwardfor       except 127.0.0.0/8    option                  redispatch    retries                 3    timeout http-request    10s    timeout queue           1m    timeout connect         10s    timeout client          1m    timeout server          1m    timeout http-keep-alive 10s    timeout check           10s    maxconn                 3000    # 指定对外提供网络服务的端口frontend web 172.18.3.77:80        bind 172.18.3.77:9099    stats enable        stats uri /hastats    stats hide-version    stats refresh 2s    use_backend varnish_srvs    # 指定后端的Varnish缓存服务器# 使用的端口是varnish的默认端口,这一点需要在varnish服务器中进行配置backend varnish_srvs     balance	uri    hash-type	consistent    server  varnish1 192.168.22.33:6081 weight 1 check    server  varnish2 192.168.22.44:6081 weight 1 check

        将HAProxy配置好以后,重启一下服务。然后在浏览器中输入 http://172.18.3.77:9099/hastats,就可以查看到HAProxy的调度管理界面。 

此时,如果Varnish服务器已经配置成功了的话,就会显示出如下界面。

HAProxy%E7%9B%91%E6%8E%A7.png

二、配置Varnish缓存服务器

        此时,在配置好HAProxy服务器之后,就可以对varnish缓存服务器进行配置了。主要修改的文件为下面两个。Varnish1 与Varnish2的配置文件一致,将IP修改为自己对应的IP就可以了。

  • /etc/varnish/default.vcl,varnish 的默认配置文件

  • /etc/varnish/varnish.params,varnish 的一些默认参数。

其中/etc/varnish/default.vcl的配置内容,如下。

# new 4.0 format.vcl 4.0;#引入负载均衡模块  import directors;#静态检测probe static_probe{     #指定检测URL    .url="/";    #探测超时时长    .timeout=2s;    #探测次数    .window=5;    #探测次数成功多少次才算健康    .threshold=2;    #Varnish启动探测后端主机2次健康后加入主机    .initial=2;    #探测间隔时长    .interval=2s;    #期望状态响应码    .expected_response=200; }   #动态监测 probe dynamic_probe {   .url="/index.php";   .timeout=2s;   .window=5;   .threshold=2;   .initial=2;   .interval=2s;   .expected_response=200; }      #指定后端服务器,并对后端服务器进行动态监测 backend staticweb1 {    .host = "192.168.22.100";    .port = "80";    .probe = static_probe;}backend staticweb2 {    .host = "192.168.22.101";    .port = "80";    .probe = static_probe;}backend dynamicweb1 {    .host = "192.168.22.200";    .port = "80";    .probe =dynamic_probe;}backend dynamicweb2 {    .host = "192.168.22.201";    .port = "80";    .probe =dynamic_probe;}# 定义负载均衡的调度算法sub vcl_init {    new staticcluster=directors.round_robin();    staticcluster.add_backend(staticweb1);    staticcluster.add_backend(staticweb2);    new dynamiccluster=directors.round_robin();    dynamiccluster.add_backend(dynamicweb1);    dynamiccluster.add_backend(dynamicweb2);}#定义清理缓存的规则acl purgers {    "127.0.0.0"/8;     "192.168.0.0"/16;}# 启用缓存清理sub vcl_purge{    return(synth(200,"Purged"));}# 定义pipe函数sub vcl_pipe{    return(pipe);}# 定义miss函数sub vcl_miss{    return(fetch);}# 定义hash函数sub vcl_hash{    hash_data(req.url);    if(req.http.host){        hash_data(req.http.host);    }else{        hash_data(server.ip);    }    if(req.http.Accept-Encoding~"gzip"){        hash_data("gzip");    }elseif(req.http.Accept-Encoding~"deflate"){        hash_data("deflate");    }}# 对接收到的请求进行配置处理sub vcl_recv {    # 不符合请求的清理操作被拒绝掉    if (req.method == "PURGE") {           if (!client.ip ~ purgers) {                return(synth(405,"Purging not allowed for " + client.ip));           }        return(purge);     }        #让后端服务器能够看到真实的请求地址    if (req.restarts == 0) {        if (req.http.X-Fowarded-For) {            set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "," + client.ip;        } else {            set req.http.X-Forwarded-For = client.ip;        }     }           # 设置动静分离    set req.http.X-Forward-For=client.ip;    if(req.url~"(?i)\.(php|asp|aspx|jsp|do|cshtml)($|\?)"){        set  req.backend_hint = dynamiccluster.backend();    }    # 只缓存下列方法中指定的方法    if (req.method != "GET" &&       req.method != "HEAD" &&       req.method != "PUT" &&       req.method != "POST" &&       req.method != "TRACE" &&       req.method != "OPTIONS" &&       req.method != "DELETE") {           return (pipe);    }        #如果请求不是GET或者HEAD,不缓存    if (req.method != "GET" && req.method != "HEAD") {         return (pass);    }    #如果请求包含Authorization授权或Cookie认证,不缓存    if (req.http.Authorization || req.http.Cookie) {        return (pass);    }    if(req.http.Accept-Encoding){            if(req.url~"\.(bmp|png|gif|jpg|jpeg|ico|gz|tgz|bz2|tbz|zip|rar|mp3|mp4|ogg|swf|flv)$"){                unset   req.http.Accept-Encoding;            }elseif(req.http.Accept-Encoding~"gzip"){               set  req.http.Accept-Encoding="gzip";            }elseif(req.http.Accept-Encoding~"deflate"){                set req.http.Accept-Encoding="deflate";            }else{                unset   req.http.Accept-Encoding;            }     }     return (hash);}# 对响应的请求进行处理sub vcl_backend_response {    # 这里我们不做配置}# 记录缓存的命中状态sub vcl_deliver {    if(obj.hits>0){        set resp.http.X-Cache="HITfrom"+req.http.host;        set resp.http.X-Cache-Hits=obj.hits;    }else{        set resp.http.X-Cache="MISSfrom"+req.http.host;    }    unset   resp.http.X-Powered-By;    unset   resp.http.Server;    unset   resp.http.Via;    unset   resp.http.X-Varnish;    unset   resp.http.Age;}

        对varnish的参数文件进行修改。这样便于让代理服务器知道应该将请求调度给谁。

# 6081 是varnish的默认监听端口 ,在HAProxy中需要对这个端口进行监听。VARNISH_LISTEN_ADDRESS=192.168.22.33VARNISH_LISTEN_PORT=6081

        在上面的配置完成之后,在varnishadm控制台界面调用backend.list命令就能够查看,后端服务器的健康状态了。

backend.list200        Backend name                   Refs   Admin      Probestaticweb1(192.168.22.100,,80) 1      probe       Sick 0/5staticweb2(192.168.22.101,,80) 1      probe       Sick 0/5dynamicweb1(192.168.22.200,,80) 1      probe      Sick 0/5dynamicweb2(192.168.22.201,,80) 1      probe      Sick 0/5

        因为我们的后端服务器还没有进行配置,所以四个服务器都是处于宕机状态。

三、在静态服务器上安装HTTPD,并添加一些静态资源

        使用yum来安装Httpd软件包就可以。安装之后,启动服务,确保80端口已经打开。此时再在Varnish服务器上调用backend.list命令就可以查看到已经又两个服务器处于Healthy状态了。

backend.list200        Backend name                   Refs   Admin      Probestaticweb1(192.168.22.100,,80) 1      probe      Healthy 5/5staticweb2(192.168.22.101,,80) 1      probe      Healthy 4/5dynamicweb1(192.168.22.200,,80) 1      probe      Sick 0/5dynamicweb2(192.168.22.201,,80) 1      probe      Sick 0/5

四、安装数据库

        在数据库服务器上,安装数据库服务,同时建立给WordPress应用程序使用的数据库表和用户。

create database wpdb;grant all on wpdb.* to 'wpuser'@'192.168.22.%' identified by "123456";

五、在动态服务器上安装HTTPD,php等相关内容

安装 httpd php php-mysql

# CentOS 6:yum install httpd  php php-mysqlservice httpd start# CentOS 7:yum install httpd  php  php-mysqlsystemctl start httpd.service

        安装wordpress,将wordpress 解压到http默认路径下,并修改WordPress的数据库配置文件。

WordPress%E8%AE%BE%E7%BD%AE.png

修改目录权限

setfacl -R -m u:apache:rwx wordpress

创建varnish健康性检查页面

backend.list200        Backend name                   Refs   Admin      Probestaticweb1(192.168.22.100,,80) 1      probe      Healthy 5/5staticweb2(192.168.22.101,,80) 1      probe      Healthy 5/5dynamicweb1(192.168.22.200,,80) 1      probe      Healthy 5/5dynamicweb2(192.168.22.201,,80) 1      probe      Healthy 5/5

在浏览器地址栏输入 http://172.18.3.77/wordpress/index.php,此时站点访问成功。

WordPress%E5%AE%89%E8%A3%85%E7%95%8C%E9%
%E6%8E%A7%E5%88%B6%E7%95%8C%E9%9D%A2.png

总结

1、架构优点

  • HAProxy为缓存服务器提供了负载均衡,使用了uri调度算法,保证了同样路径的请求能够被调度到同样的主机上,提高了缓存的命中率。

  • HAProxy提供了web管理界面,能够更直观的进行调度管理和管控

  • Varnish的缓存机制,以及动静分离等技术,提高了web服务器的负载能力,从而使系统能够应对高并发量的请求

  • 数据库的主从复制,也是企业实际生产应用中使用较多的生产策略,这样能够实现网络请求的频繁读写,对降低了数据库服务器的压力。

2、尚且不足

  • 用户上传的静态资源如何存储到静态服务器中,文件的分布式存储与数据同步是这个结构需要解决的一个重要问题

  • HAproxy做负载均衡,没有冗余能力,容易出现单点故障,最好配合KeepAlived实现高可用。

  • 如果用户在访问过程中,建立了Session会话,会话行为应该如何保持