美文网首页
架构的高可用高性能keepalived和varnish

架构的高可用高性能keepalived和varnish

作者: N33_LvQing | 来源:发表于2019-02-12 21:55 被阅读0次

    1、简述HA cluster原理
    2、keepalived实现主从、主主架构
    3、简述http协议缓存原理及常用首部讲解
    4、简述回源原理和CDN常见多级缓存
    5、varnish实现缓存对象及反代后端主机

    1、简述HA cluster原理

    高可用集群(High Availability Cluster)简单的理解就是多个节点作为一个整体向用户提供一组网络资源。如果某个节点失效,它的备用节点将在几秒钟的时间内接管它的职责。用户将完全感受不到这个过程,因此,对于用户而言,集群永远不会停机。高可用集群软件的主要作用就是实现故障检查和业务切换的自动化。只有两个节点的高可用集群又称为双机热备,即使用两台服务器互相备份。

    2、keepalived实现主从、主主架构

    首先需要同步时间,时间不同步的话就很可能会出错
    然后下载keepalived安装包,默认在base的yum里面
    安装完后我们编辑配置文件/etc/keepalived.conf

    ! Configuration File for keepalived
    
    global_defs {
       notification_email {
            root@localhost  #接收信息的邮件地址
       }
       notification_email_from keepalive@localhost   #邮件来自于谁,可以不存在
       smtp_server 127.0.0.1 #邮件服务器可以是自己;
       smtp_connect_timeout 30 #邮件服务器链接超时时长
       router_id rt1  #router标识一个组内不同的router
       vrrp_mcast_group4 224.0.0.1  #组播地址
    }
    
    vrrp_instance VI_1 {  #组名VI_1
        state MASTER 
        interface ens33   
        virtual_router_id 51   #整个虚拟组的id,同组配置须保持一致
        priority 100
        advert_int 1 #一秒检查一次
        authentication {
            auth_type PASS #simple认证
            auth_pass 12345678  #最大支持8位
        }
        virtual_ipaddress {
            #<IPADDR>/<MASK> brd <IPADDR> dev <STRING> scope <SCOPE>
            192.168.31.240/24 dev ens33 label ens33:0
        }
    }                    
    

    然后将配置文件传给另一台主机
    scp keepalived.conf root@192.168.31.201:/etc/keepalived/
    在这一台主机里我们只需要简单的修改几项
    router_id rt2
    state BACKUP
    ppriority 95 #低一点

    配置到这里就结束了,很简单。接下来我们就可以开始测试了
    先在backup机上开启keepalive进程



    可以看到已经拿到地址了
    现在我们在master上开启进程


    image.png
    发现被更高的优先级抢走了
    然后我们可以抓包查看他们互相通告的信息
    image.png

    双主模式

    但如果这样配置的话就只有一台在工作,另一台一直是备用的,我们可以在主机上分别配置两个虚拟路由器,假如A,B两台主机我们想要让他们同时工作起来,可以让A为第一个虚拟路由器的master,则B就是第二个虚拟路由器的master然后我们就有了两个VIP,但是有了两个VIP其他主机怎么与我们通信实现负载均衡呢,这个时候我们就需要一个新的调度器,但我们配置keepalive本来就是为了增强调度器的冗余安全性,如果引入了新的节点岂不是本末倒置。
    这时我们可以使用DNS服务,DNS本来就是主从互备不存在单点性且只需要我们在一个域名里添加两条A记录就可以达到轮询负载均衡的目的。
    编辑配置文件增加一个虚拟路由器配置:

    #RT1上添加一段
    vrrp_instance VI_2 {
        state BACKUP
        interface ens33 
        virtual_router_id 52
        priority 96
        advert_int 1
        authentication {
            auth_type PASS
            auth_pass 98765432
        }
        virtual_ipaddress {
            192.168.31.241/24 dev ens33 label ens33:1                                           
        }
    
    #RT2上添加一段
    vrrp_instance VI_1 {
        state MASTER 
        interface ens33 
        virtual_router_id 52
        priority 100 
        advert_int 1
        authentication {
            auth_type PASS
            auth_pass 98765432
        }
        virtual_ipaddress {
            192.168.31.241/24 dev ens33 label ens33:1                                           
        }
    }
    

    然后我们抓包看


    image.png

    每一台主机都分别获取到了一个IP地址如果我们down了其中一台主机,则ip地址会跑到另一台上,测试一下看看


    image.png
    则简单的实验就完成了
    我们可以定义发生变化时执行指定的脚本
    通知脚本的使用方式:
    示例通知脚本:
    #!/bin/bash
    #
    contact='root@localhost'
    
    notify() {
            local mailsubject="$(hostname) to be $1, vip floating"
            local mailbody="$(date +'%F %T'): vrrp transition, $(hostname) changed to be $1"
            echo "$mailbody" | mail -s "$mailsubject" $contact
    }
    case $1 in
            master)
                notify master
                ;;
            backup)
                notify backup
                ;;
            fault)
                notify fault
                ;;
            *)
                            echo "Usage: $(basename $0) {master|backup|fault}"
                exit 1
                ;;
    esac        
    #脚本的调用方法,写在虚拟路由器中
    notify_master "/etc/keepalived/notify.sh master"
    notify_backup "/etc/keepalived/notify.sh backup"
    notify_fault "/etc/keepalived/notify.sh fault"  
    

    3、简述http协议缓存原理及常用首部讲解

    (1)强制缓存机制(过期时间机制)

    基本原理:
    客户端第一次请求服务端时,服务端把缓存规则信息添加到header中,客户端通过这些信息判断是否能缓存。若能强制缓存,则header中会有两个字段来标记缓存失效的时间(expires或cache-control)。在客户端第一次请求并添加缓存后,以后每次客户端的请求响应数据都是缓存服务器提供的,不会再是服务端。缓存服务器根据cache-control字段来判断是否使用、是否更新、何时更新缓存。

    • expires,缓存过期时间
    • cache-control有下面几个参数:
    • public,允许客户端和代理使用缓存,即客户端请求的资源可以被任何缓存区所缓存
    • private,允许客户端使用缓存,即对于某个用户的响应信息不能被共享缓存区所缓存
    • max-age,缓存最大失效时长(单位为秒)
    • no-cache,关闭强制缓存,需要使用对比缓存
    • no-store,所有内容都不缓存

    (2)对比缓存机制(条件式缓存机制):

    基本原理:

    • a)缓存命中的情况:客户端向缓存服务器请求获取缓存header标识,客户端获取标识后,向后端服务器发送header标识规则,若未失效便通知客户端使用缓存服务器缓存的数据(状态码304)。
    • b)缓存未命中的情况:客户端向缓存服务器请求获取缓存header标识,客户端获取标识后,向后端服务器发送header标识规则,若失效便通知客户端不使用缓存服务器缓存的数据(状态码200),并更新缓存。
      对比缓存标识:
      last-modified/if-modfied-since:资源最后的修改时间戳
      etag/if-none-match:资源校验码

    4、简述回源原理和CDN常见多级缓存

    回源是指浏览器在发送请求报文时,响应该请求报文的是源站点的服务器,而不是各节点上的缓存服务器,那么这个过程相对于通过各节点上的缓存服务器来响应的话就称作为回源。回源的请求或流量太多的话,有可能会让源站点的服务器承载着过大的访问压力,进而影响服务的正常访问。
    CDN(Content Delivery Network)内容分发网络,其思路是尽可能避开网络上的瓶颈,通过在网络边缘部署边缘服务器,依靠CDN中心平台的负载均衡、内容分发及调度等功能,使用户就近获取所需的内容,降低网络拥堵,提高用户访问响应速度和命中率。所以基本上CDN就是广泛采用各种缓存服务器,使得用户的请求直接由这些缓存服务器响应,加快了响应速度;只有在用户请求的资源在缓存服务器上没有找到或者请求访问的资源在源站点服务器上已经修改过的情况下,缓存服务器才会去访问源站点服务器以获取最新的资源。简单的来说就是在多个地方设置缓存服务器,使当地的用户可直接访问当地的缓存服务器而不必频繁的去访问源站,减少根服务器的压力。


    image.png

    CDN节点的缓存机制也是遵循http协议,因此也会受到Cache-Control等字段的影响。如果缓存的时间太短就会频繁的向根源服务器发起请求,增加源站点的负担,如果缓存时间太长又有可能涉及到更新的问题,这就需要设计者根据实际情况去设计。

    5、varnish实现缓存对象及反代后端主机

    缓存原理

    Varnish 与一般服务器软件类似,分为 master 进程和 child 进程。Master 进程读入存储配置文件,调用合适的存储类型,然后创建 / 读入相应大小的缓存文件,接着 master 初始化管理该存储空间的结构体,然后 fork 并监控 child 进程。Child 进程在主线程的初始化的过程中,将前面打开的存储文件整个 mmap 到内存中,此时创建并初始化空闲结构体,挂到存储管理结构体,以待分配。Child 进程分配若干线程进行工作,主要包括一些管理线程和很多 worker 线程。
    接着,开始真正的工作,varnish 的某个负责接收新 HTTP 连接线程开始等待用户,如果有新的 HTTP 连接过来,它总负责接收,然后唤醒某个等待中的线程,并把具体的处理过程交给它。Worker 线程读入 HTTP 请求的 URI,查找已有的 object,如果命中则直接返回并回复用户。如果没有命中,则需要将所请求的内容,从后端服务器中取过来,存到缓存中,然后再回复。

    分配缓存的过程是这样的:它根据所读到 object 的大小,创建相应大小的缓存文件。为了读写方便,程序会把每个 object 的大小变为最接近其大小的内存页面倍数。然后从现有的空闲存储结构体中查找,找到最合适的大小的空闲存储块,分配给它。如果空闲块没有用完,就把多余的内存另外组成一个空闲存储块,挂到管理结构体上。如果缓存已满,就根据 LRU 机制,把最旧的 object 释放掉。

    释放缓存的过程是这样的:有一个超时线程,检测缓存中所有 object 的生存期,如果超初设定的 TTL(Time To Live)没有被访问,就删除之,并且释放相应的结构体及存储内存。注意释放时会检查该存储内存块前面或后面的空闲内存块,如果前面或后面的空闲内存和该释放内存是连续的,就将它们合并成更大一块内存。

    整个文件缓存的管理,没有考虑文件与内存的关系,实际上是将所有的 object 都考虑是在内存中,如果系统内存不足,系统会自动将其换到 swap 空间,而不需要 varnish 程序去控制。

    varnish的程序环境:
    /etc/varnish/varnish.params: 配置varnish服务进程的工作特性,例如监听
    的地址和端口,缓存机制;
    /etc/varnish/default.vcl:配置各Child/Cache线程的缓存策略;
    主程序:
        /usr/sbin/varnishd
    CLI interface:
        /usr/bin/varnishadm
    VCL配置文件重载程序:
        /usr/sbin/varnish_reload_vcl
    
    varnish的缓存存储机制( Storage Types):
      -s [name=]type[,options]  
        · malloc[,size]
            内存存储,[,size]用于定义空间大小;重启后所有缓存项失效;
        · file[,path[,size[,granularity]]]
            磁盘文件存储,黑盒;重启后所有缓存项失效;
        · persistent,path,size
            文件存储,黑盒;重启后所有缓存项有效;实验;
    

    通过yum安装完varnish后,首先我们来看看varnish.params配置文件

    # Varnish environment configuration description. This was derived from
    # the old style sysconfig/defaults settings
    
    # Set this to 1 to make systemd reload try to switch VCL without restart.
    RELOAD_VCL=1
    
    # Main configuration file. You probably want to change it.
    VARNISH_VCL_CONF=/etc/varnish/default.vcl  #指定默认的vcl文件
    
    # Default address and port to bind to. Blank address means all IPv4
    # and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted
    # quad, or an IPv6 address in brackets.
    # VARNISH_LISTEN_ADDRESS=192.168.1.5
    VARNISH_LISTEN_PORT=80 #指定监听的端口
    
    # Admin interface listen address and port
    VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 #管理地址
    VARNISH_ADMIN_LISTEN_PORT=6082
    
    # Shared secret file for admin interface
    VARNISH_SECRET_FILE=/etc/varnish/secret #口令文件
    
    # Backend storage specification, see Storage Types in the varnishd(5)
    # man page for details.
    VARNISH_STORAGE="file,/var/varnish/cache,256M" #这个是我们主要改的,存储的位置,方法形式
    
    # User and group for the varnishd worker processes
    VARNISH_USER=varnish
    VARNISH_GROUP=varnish
    
    # Other options, see the man page varnishd(1)
    #DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"    
    
    varnish程序的选项:
                程序选项:/etc/varnish/varnish.params文件
                    -a address[:port][,address[:port][...],默认为6081端口; 
                    -T address[:port],默认为6082端口;
                    -s [name=]type[,options],定义缓存存储机制;
                    -u user
                    -g group
                    -f config:VCL配置文件;
                    -F:运行于前台;
    

    然后我们使用varnishadm来登陆接口
    varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082
    登陆进来使用help查看可用的命令

        
                配置文件相关:
                    vcl.list 
                    vcl.load:装载,加载并编译;
                    vcl.use:激活;
                    vcl.discard:删除;
                    vcl.show [-v] <configname>:查看指定的配置文件的详细信息;
                    
                运行时参数:
                    param.show -l:显示列表;
                    param.show <PARAM>
                    param.set <PARAM> <VALUE>
                    
                缓存存储:
                    storage.list
                    
                后端服务器:
                    backend.list 
    

    下面我们来介绍下VCL配置文件,里面的功能是通过一种语言实现的。VCL有多个状态引擎,状态之间存在相关性,但状态引擎彼此间互相隔离;每个状态引擎可使用return(x)指明关联至哪个下一级引擎;每个状态引擎对应于vcl文件中的一个配置段,即为subroutine。


    image.png
    vcl_recv的默认配置:
                
                    sub vcl_recv {
                        if (req.method == "PRI") {
                            /* We do not support SPDY or HTTP/2.0 */
                            return (synth(405));
                        }
                        if (req.method != "GET" &&
                        req.method != "HEAD" &&
                        req.method != "PUT" &&
                        req.method != "POST" &&
                        req.method != "TRACE" &&
                        req.method != "OPTIONS" &&
                        req.method != "DELETE") {
                            /* Non-RFC2616 or CONNECT which is weird. */
                            return (pipe);
                        }
    
                        if (req.method != "GET" && req.method != "HEAD") {
                            /* We only deal with GET and HEAD by default */
                            return (pass);
                        }
                        if (req.http.Authorization || req.http.Cookie) {
                            /* Not cacheable by default */
                            return (pass);
                        }
                            return (hash);
                        }
                    }
    

    里面还有许许多多的变量

    变量类型:
                内建变量:
                    req.*:request,表示由客户端发来的请求报文相关;
                        req.http.*
                            req.http.User-Agent, req.http.Referer, ...
                    bereq.*:由varnish发往BE主机的httpd请求相关;
                        bereq.http.*
                    beresp.*:由BE主机响应给varnish的响应报文相关;
                        beresp.http.*
                    resp.*:由varnish响应给client相关;
                    obj.*:存储在缓存空间中的缓存对象的属性;只读;
                    
                    常用变量:
                        bereq.*, req.*:
                            bereq.http.HEADERS
                            bereq.request:请求方法;
                            bereq.url:请求的url;
                            bereq.proto:请求的协议版本;
                            bereq.backend:指明要调用的后端主机;
                            
                            req.http.Cookie:客户端的请求报文中Cookie首部的值; 
                            req.http.User-Agent ~ "chrome"
                            
                            
                        beresp.*, resp.*:
                            beresp.http.HEADERS
                            beresp.status:响应的状态码;
                            reresp.proto:协议版本;
                            beresp.backend.name:BE主机的主机名;
                            beresp.ttl:BE主机响应的内容的余下的可缓存时长;
                            
                        obj.*
                            obj.hits:此对象从缓存中命中的次数;
                            obj.ttl:对象的ttl值
                            
                        server.*
                            server.ip
                            server.hostname
                        client.*
                            client.ip                   
                    
                用户自定义:
                    set 
                    unset 
    

    默认的VCL文件

    vcl 4.0;
    
    # Default backend definition. Set this to point to your content server.
    backend default {
        .host = "192.168.31.201";
        .port = "80";
    }
    
    sub vcl_recv {
        # Happens before we check if we have this in cache already.
        #
        # Typically you clean up the request here, removing cookies you don't need,
        # rewriting the request, etc.
    }
    
    sub vcl_backend_response {
        # Happens after we have read the response headers from the backend.
        #
        # Here you clean the response headers, removing silly Set-Cookie headers
        # and other mistakes your backend does.
    }
    
    sub vcl_deliver {
        # Happens when we have all the pieces we need, and are about to send the
        # response to the client.
        #
        # You can do acc
    

    然后我们再在varnish主机上配置nginx来进行反代
    测试实验结果

    [root@node1 ~]# curl -I  http://192.168.31.201:/index.html
    HTTP/1.1 200 OK
    Server: nginx/1.12.2
    Date: Tue, 12 Feb 2019 12:59:11 GMT
    Content-Type: text/html
    Content-Length: 22
    Connection: keep-alive
    Last-Modified: Thu, 03 Jan 2019 14:07:05 GMT
    ETag: "5c2e1709-16"
    X-Varnish: 32770 3
    Age: 10
    Via: 1.1 varnish-v4
    

    配置手动清除缓存

    backend default {
        .host = "192.168.31.203";
        .port = "80";
    }
    
    sub vcl_recv {
        # Happens before we check if we have this in cache already.
        #
        # Typically you clean up the request here, removing cookies you don't need,
        # rewriting the request, etc.
         if (req.method == "PURGE") {
            return (purge);   //清除缓存
    }
    
    sub vcl_purge {
            return(synth(200,"success"));
    }
    
    vcl.load test1 /etc/varnish/default.vcl
    200        
    VCL compiled.
    vcl.use test1
    200        
    VCL 'test1' now active
    

    清除缓存的结果

    [root@node1 ~]# curl -I -X PURGE http://192.168.31.201    
    HTTP/1.1 200 success
    Server: nginx/1.12.2
    Date: Tue, 12 Feb 2019 13:49:13 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 240
    Connection: keep-alive
    X-Varnish: 56
    Retry-After: 5
    

    相关文章

      网友评论

          本文标题:架构的高可用高性能keepalived和varnish

          本文链接:https://www.haomeiwen.com/subject/ynumsqtx.html