一、集群基础

1、系统的扩展方式
  • scale up向上扩展:提高单台服务器的性能

  • scale out向外扩展:多台服务器联合起来满足同一个需要

2、集群类型
  • LB :load balancing,负载均衡集群,通过横向扩展提高系统性能

    • 前端 : 负载均衡器,调度器

    • 后端 : 上游服务器(upstream server),后端服务器,“真”服务器(real server)

    • 传输层 : ipvs(lvs)

    • 应用层 : nginx(upstream,proxy)

    • 实现方式

    • 架构的基本表现方式

      SPOF : Single point of failure(单点故障)
  • HA : High Avalilability,高可用集群,提供冗余主机提升系统可用性

    • 前端:Active,活动服务器

    • 后端:passive,备用服务器

    • 架构的基本表现方式

      avalilability = 平均无故障时间/(平均无故障时间+平均修复时间)
      
      值的取值范围:0-1之间,99%,99.9%, 99.99%,99.999% 
      5个9表示: 一年有5分钟不在线的时间
  • HP : High Performance,高可用集群
    组合多台主机解决一个问题, 每个主机只负责其中一部分运算

  • DS : Distributed System,分布式系统

    • Hadoop的YARN框架

    • batch : MapReduce(批处理计算)

    • in-memory : spark

    • stream : storm

    • HDFS(hadoop)

    • mogileFS

    • ClusterFS

    • Ceph(已经收录到linux内核)

    • 分布式存储

    • 分布式计算

二、集群实现方式

1、集群的实现
  • 基于实现方式划分:

    • Lvs(Linux virtual Server)

    • HAproxy

    • Nginx

    • ats (apache traffic server)

    • perlbal

    • F5(BIG-IP)

    • Citrix Netscaler

    • A10(A10)

    • Arry

    • redware

    • 硬件实现:

    • 软件实现

  • 基于工作的协议层次划分

    • HAproxy(mode http)

    • Nginx

    • ats

    • perlbal

    • lvs

    • HAproxy(mode tcp)

    • 传输层

    • 应用层

2、HA集群的实现
  • Keepalived

    • 通过模拟Vrrp协议来实现地址漂移

  • AIS系统

    • heartbeat(Centos 6之前系统可能使用)

    • Cman+rgmanager(RHCS : Redhat Cluster Suite)

    • Corosync+pacemaker+crmsh

三、HA Cluster

HA Nginx Porxy Service需要的关键资源
  • 公网IP

  • Nginx Service(两台server的时间要严格同步)

  • 相同的配置文件

AIS可用性委员组,规定高可用集群栈
  • 1、Messaging Layer(Infrastructure Layer),消息层(心跳层)

    • 互相传递心跳信息(集群事务信息的传递,由监听的套接字服务来实现),向上提供一堆的API接口,在这周提供高可用的能力

  • 2、CRM(Cluster Resource manager)集群资源管理层

    • 专门负责高可用集群的资源管理,如:选取主节点

    • 其中CRM包含了LRM(Local Resource Manager),执行资源配置

  • 3、RA(Resource Agent),资源代理层

    • 管理机制的实现(如:start,stop,restart,status,monitor)

四、高可用集群面临的问题

1、集群的分裂(partion)

被称之为集群的分区(partion)也被称之为脑裂(brain-split))为了避免出现分裂,事先做好决策,在每个主机上都有一票,票数多的将获取主节点。如果一个服务器性能好,可以有2票。

2、多节点使用同一个共享存储

在集群发生分裂的情况下, 可能会引发多节点同时对一个块级别的共享存储写一个文件,这样会导致文件系统损坏

  • 解决方法

    • 干掉对方服务器的电源(如通过电源交换机将主机的电源断掉)

五、VRRP概述

VRRP协议

虚拟路由冗余协议(virtual router redundancy protocol,简称VRRP),是由IETF提出的解决局域网中配置静态网关出现单点失效现象的路由协议,1998年已推出正式的RFC2338协议标准,VRRP广泛应用在边缘网络中,它的设计目标是支持特定情况下IP数据流量失败转移不会引起混乱,允许主机使用单路由器,以及及时在实际第一跳路由器使用失败的情形下仍能够维护路由器间的连通性。

VRRP术语
  • 虚拟路由器

    • 由一个Master路由器和多个Backup路由器组成,主机将虚拟路由器当作默认网关

  • VRID

    • 虚拟路由器的标识,有相同VRID的一组路由器构成一个虚拟路由器

  • Master路由器

    • 虚拟路由器中承担报文转发任务的路由器,即主节点(仅能有一个)

  • Backup路由器

    • Master路由器出现故障时,能够代替Master路由器工作的路由器,即备用节点(可以有多个)

  • 虚拟IP地址(VIP)

    • 虚拟路由器的IP地址,已改为虚拟路由器可以拥有一个或多个IP地址

  • IP地址拥有者

    • 接口IP地址与虚拟IP地址相同的路由器被称之为IP地址拥有者

  • 虚拟MAC地址(VMAC)

    • 一个虚拟路由器拥有一个虚拟MAC地址,虚拟路由器回应ARP请求使用的是虚拟MAC地址

  • 优先级

    • VRRP根据优先级来确定虚拟路由器中每台路由器的地位

  • 非抢占方式

    • 若Backup路由器工作在非抢占模式下,则只要Master路由器没有故障,Backup路由器即使随后被配置了更高的优先级也不会成为Master路由器

  • 抢占方式

    • 如果backup路由器工作在抢占方式下, 当它收到VRRP报文后,会将自己的优先级与通告报文中的优先级进行比较,如果自己的优先级比当前的Master优先级高,就会主动抢占成为Master路由器,否则,将保持Backup状态

VRRP工作过程
  • 1、虚拟路由器中的路由器根据优先级选举出Master,Master通过发送ARP报文,将自己的虚拟MAC地址发送给其它设备和主机

  • 2、Master路由器周期性发送VRRP报文,以公布其配置信息(优先级等)和工作状态

  • 3、如果Master路由器出现故障, 虚拟路由器的backup路由器根据优先级重新选举新的Master

  • 4、虚拟路由器状态切换时,新的Master路由器只是简单地发送一个携带虚拟路由器的MAC地址和IP地下信息的ARP报文,这样就可以更新与它连接的主机或设备中的ARP相关信息,网络中的主机感知不到Master的切换

  • 5、backup路由器优先级高于master路由器时,由backup路由的工作方式(抢占或非抢占方式)决定是否重新选举Master

  • VRRP优先级的取值范围为0-255(数值越大优先级越高),可配置的范围为1到254,优先级0为系统保留给路由器放弃master位置时使用,255则是系统保留给IP地址拥有者使用,当路由器为IP地址拥有者时,其优先级始终为255,当虚拟路由器拥有虚拟IP地址时,只要其工作正常,则为Master路由器

路由通告的工作原理
  • Master路由器周期发送VRRP报文,在虚拟路由器中公布其配置信息(优先级)和工作状态,backup路由器通过接收vrrp报文情况来判断master是否工作正常

  • master路由器主动放弃master地位时,发送优先级为0的VRRP报文,致使backup路由器切换为master路由器,这个切换时间为skew time, 计算方式为:(256-backup路由器的优先级/256,单位为秒)

  • 当master路由器发送网络故障不能发送VRRP报文的时,backup路由器不能立即知道其工作状态,backup路由器等待一段时间后,如果还没有收到VRRP报文, 会认为master工作不正常, 而把自己升级为master路由器,周期发送VRRP报文,如果此时多个backup路由器竞争master路由的位置,将通过优先级选举master路由器,backup路由器默认等待的时间为master_down_interval,取值为:(3*VRRP报文的发送时间间隔+skew time,单位为秒)

  • 在性能不稳定的网络中, backup路由器可能因为网络堵塞而在master_down_interval期间没有收到master路由的报文,而主动抢占master位置, 如果此时master报文又到达了, 就会出现虚拟路由器的成员频繁的进行master抢占现象,为了缓解这种情况发生,特制定了延迟等待定时器,它可以使得backup路由器在等待了master_down_interval后,再等待延迟等待时间,如果在此期间仍然没有收到VRRP报文,则此backup路由器才会切换为master路由器,对外发送VRRP报文

VRRP实现的工作
  • 路由选举

  • 路由状态通知

  • 为了提高安全性,VRRP还软件娃娃了认证功能

VRRP认证方式
  • 无认证

  • 简单字符认证,通常用于局域网

  • MD5认证,跨越互联网

VRRP高可用工作模型
  • 主备备份

    • 主备备份方式表示业务仅由Master路由器承担,当Master路由器出现故障时,才会由选举出来的Backup路由器接替它的工作,如下图:


  • 主主备份

    • 在路由器的一个接口上可以创建多个虚拟路由器,使得该路由器可以在一个虚拟路由器中作为Master路由器,同时在其它的虚拟路由器中作为Bacup路由器,主主备份模式可以实现负载分担方式,是指多台路由器同时承担业务,因此负载分担方式需要两个或两个以上的虚拟路由器,每个虚拟路由器都包括一个Master路由器和若干个Backup路由器。各虚拟路由器的Master路由器可以不相同,如下图:
      0?wx_fmt=gif&tp=webp&wxfrom=5&wx_lazy=1

Keepalived

一、keepalived功能

keepalived程序是vrrp协议在linux主机上以守护进程方式的实现,能够根据配置文件生成IPVS规则 ,并对各real server的健康做检测,以及Loadbalance主机和backup主机之间failover的实现,keepalived在Centos6.4+收录到了发行版光盘中。

二、keepalived核心组件

640?wx_fmt=png&tp=webp&wxfrom=5&wx_lazy=

  • 核心组件

    • TCP

    • HTTP

    • SSL

    • MISC

    • Watchdog : 高可用监视器(监控服务本身,可实现重启的)

    • Checkers : 健康状态检测器,可实现如下协议

    • SMTP : 支持发送邮件通知机制

    • System Call : 通过系统调用做出管理操作

    • VRRP stack : VRRP栈的实现,实现VRRP协议调用

    • NetLink Reflectior : VRRP借助于netlink监控网络,实现网络功能配置

    • Ipvs wrapper : ipvs控制

  • IO复用器

  • 内存管理

  • 控制面板(配件文件分析器,以实现应用配置文件)

三、Keepalive的工作原理:

  • 1、主节点主动向备用节点发送存活通知消息(只是3层判断)

  • 2、发送存活通知消息机制:

    • 广播(broadcast)

    • 组播(multicast)

    • 单播(unicast)

  • 3、设定各服务器的优先级,优先级判断方法

    • 手动设定

    • 根据IP地址数值大小,大的优先级高

    • 随机的挑选

  • 4、需要监控服务器的存活状态,如果服务故障需要重启服务,如重启服务无效,就需要降低主节点的优先级

  • 5、各节点需要安装keepalive服务,并且都加入到同一个集群中,并且每个节点都监听在某个套接字止,不断向外传递心跳信息

  • 6、多个节点配置域共享密钥,防止有人恶意加入集群

  • 7、集群自行决定来启动服务,不能够也不应该手动启动(建立策略来决定哪个节点启动服务)

  • 8、将多个资源绑定在一起,一同调用或配置

  • 9、模拟VRRP协议,实现地址飘移,keepalived仅能飘移IP地址

  • 10、不能转移服务,内置了一个模块,能直接向内核的ipvs添加规则,创建一人LVS(keepalved天生高可用lvs)

  • 11、内置的提供了一个接口,可以通过编写脚本,来检测服务的状态,根据返回的状态,如果发生了故障,就主动降低服务器的优先级(vrrp_script,track_script)

Keepalived高可用集群配置前提
  • 各节点时间要同步,一般使用网络时间服务器

  • 确保iptables及selinux服务关闭

  • 各节点之间可通过主机名互相通信,节点的名称设定与hosts文件中解析的主机名都要保持一致(AIS架构必须项)

    • uname -n 获得主机名,与解析的主机名要相同

  • 各节点基于密钥认证的方式通过ssh互信通信

keepalived的程序环境
  • 主配置文件

    • /etc/keepalived/keepalived.service

  • 生成hash指纹的工具

    • /etc/bin/genhash

      [root@Centos7 ~]# genhash -s 172.16.36.70 -p 80 -u index.html
      MD5SUM = 7833123aaf6b782a8997b80affda274f

四、keepalived配置详解

/etc/keepalived/keepalived.conf
  • Global configuration : 全局配置

      global_defs {
          ...
      }
  • VRRP Configuration : 配置VRRP实例

      vrrp_instance NAME {
          ...
    
      }
  • LVS Configuration : IPVS的相关配置

      virtual_server IP PORT {
          ...
          real_server IP PORT {
              ...
          }
      }
Global指令
  • notification_email {} : 邮件通知的对象,收件人邮箱

  • notification_email_from : 发件人邮箱

  • smtp_server : 邮件发送服务器IP地址

  • smtp_connect_timeout : 连接邮件服务器的超时时长

  • router-id HOSTNAME : 物理节点的标识符,建议使用主机名

  • vrrp_mcast_grou4 224.0.0.18 : vrrp的多播地址,IPV4,默认为224.0.0.18

  • vrrp_mcast_group6 ff02::12 : vrrp的多播地址, IPV6

  • vrrp_script NAME { } : 定义脚本,可以在vrrp_instance中使用track_script引用

    • script COMMAND : script是固定字段,后面为脚本的内容,有空格需要使用引号包括起来

    • interval # : 间隔多长时间进行状态查看,以秒为单位

    • weight [+|-] # : 如果脚本的返回状态是失败的,将优先级减去相应的数值

  • nopreempt : 定义为非抢占模式

  • preempt_delay TIME : 定义为延迟抢占模式

VRRP_instance指令
  • state MASTER | BACKUP : 在当前VRRP实例中(虚拟路由器组)此节点的初始实例

  • Interface IFACE_NAME : vrrp用于绑定VIP的接口,各节点网卡接口名称需保持一致

  • virtual_route_id # : 虚拟路由器的ID(VRID),可用值为0-255,默认为51

  • priority # : 当前路由器节点的优先级,可用范围为0-255

  • advert_in # : 通告时间间隔,单位是秒种,默认是1秒

  • authentication { } : 定义认证的特殊引用段

    • auth type PASS : 指定集群密钥方式

    • auth_pass 1234 : 字符密钥吸有前8个有效

  • virtual_ipaddress { } : 定义集群中主机的特殊引用

    • \

      /brd \Dev\scope \label \
  • notify_master <string> | <quoted-string> : 当前节点转为主节点触发的脚本

  • notify_backup <string> | <quoted-string> : 当前节点转为备用节点触发的脚本

  • notify_fault <string> | <quoted-string> : 当前节点出现故障时触发的脚本

  • notify <string> | <quoted-string> : 一般情况下, 只使用上面三个, 或者只使用下面一个

  • track_script { VRRP_SCRIPT_NAME } : 使用此引用,可以调用vrrp_script定义的脚本并执行

  • track_script { IFACE_NAME } : 调用vrrp_script内置方法,可以判断主机的网络接口是否正常,如果不正常将自动降低其权重,转为backup模式

virtual_server指令
  • delay_loop <INT> : 延迟多长时间检测集群服务是否OK

  • lb_algo rr|wrr|lc|wlc|lblc|sh|dh : lvs的调度算法

  • lb_kind NAT|DR|TUN : lvs的类型,如需支持fullnat,需要打补丁

  • persistence_timeout <INT> : 持久时长,0表示不启用

  • nat_mask 255.255.255.0 : IP掩码地址,此处的nat没有写错

  • protocol TCP : lvs调度的协议,默认是udp,如果是udp可以不用添加此指令

  • virtual_host <string> : 对哪个虚拟主机做健康状态检测,可以不定义

  • quorum <INT> : 最少法定票数,判断realserver有几台才是OK的

  • quorum_up : 添加票数

  • quorum_down : 降低票数

  • sorry_server <IPADDR><PORT> : 定义sorry server

  • real_server IP PORT { } :定义一个real_server主机

    • connect_timeout <INT> : 连接超时时长

    • connect_ip : 检测的realserver的IP,一般不需要写,同url中的参数一样

    • connect_port : 检测的realserver的port,一般不需要写,同url中的参数一样

    • bindto <IP ADDR> : 同url中的参数一样

    • bind_port <port> : 使用哪个端口做健康状态检测

    • url { } : 对url做健康检测的特殊引用

    • nb_get_retry <INT> : get请求的重试次数

    • delay_befor_retry <INT> : 两次重试之间的时间间隔,要延迟多长时间,再retry

    • connect_ip <IPADDR> : 默认会按real server的IP做健康状态检测,一般不需要再写,但有的时候可能有一个IP专门做健康状态检测的IP,故要手动添加上去

    • connect_port <PORT> : 连接的端口

    • bindto <IPADDR> : 如果keepalived主机有多个IP,定义用哪个IP完成健康状态检测

    • connect_timeout <INT> : 连接超时时长,默认为5秒,但这个时长比较长, 建议调整至3秒

    • warmup <INT> : 做健康状态检测的延迟, 即keepalived服务起来后,等待多长时间再开始健康状态检测,有时候后端的real server还未启动完成,故需要等待一段时间

    • path <string> : 检测的url路径

    • status_code <INT> : 依赖返回状态码进行检测

    • digest <string> : 依赖页面的hash值进行检测,基于genhash命令完成hash值计算

    • weight <INT> : 权重

    • inhibit_no_failure : 如果检测失败,就把权重设置为0

    • notify_up <string> | <quoted-string> : realserver上线通知,依赖脚本完成

    • notify_down <string> | <quoted-string> : realserver下线通知,依赖脚本完成

    • HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK : 对后端的realserver主机,使用相应的方法做健康状态检测

    • TCP_CHECK { } : 传输层健康状态检测

五、主备模式的可高可用nginx的配置实例

实验环境:
172.16.36.70
172.16.36.71
######172.16.36.70的配置
~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
~]# ssh-copy-id root@172.16.36.71
~]# vim /etc/hosts
172.16.36.71 Centos7.pc2
~]# ntpdate 172.16.0.1
~]# yum install nginx
~]# mv /usr/share/nginx/html/index.html{,.bak}
~]# vim /usr/share/nginx/html/index.html
172.16.36.70
~]# systemctl start nginx
使用客户端IE测试测试页面,是否正常显示
~]# yum install keepalived
~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
   notification_email {
    root@localhost
   }
   notification_email_from keepalived_admin@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Centos7.pc1 #路由设备在网络中的名称,一般为hostname
}
######使用vrrp_script实现依赖脚本监测文件的存在性,来降低节点的优先级,以此实现主备模式的切换
vrrp_script chk_down {
    script "[ -f /etc/keepalived/down ] && exit 1 || exit 0"
    interval 1
    weight -20
}
######监测web的访问返回结果,判断服务的可用性, 来了解你节点的优先级
vrrp_script chk_nginx {
    script "curl -s 172.16.36.70 | grep 172 &> /dev/null"
    interval 1
    weight -20
}
######监控主机的nginx是否存在,0信号只是做进程探测的
vrrp_script chk_nginx2 {
        script "killall -0 nginx"   
        interval 1
        weigth -20
}
vrrp_instance VI_1 {
    state MASTER
    interface eno16777736
    virtual_router_id 100
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 99999999
    }
    virtual_ipaddress {
    172.16.36.100/16 dev eno16777736 label eno16777736:1
    }
    notify_master "/etc/keepalived/keepalived.sh master"
    notify_bakcup "/etc/keepalived/keepalived.sh backup"
    notify_fault "/etc/keepalived/keepalived.sh fault"
    track_script {
    chk_down
    chk_nginx
    eno16777736    #监控主机的网卡,如果出现故障可自动降低优先级。 此脚本调用不用定义,是vrrp_script内置的

    }
}
~]# vim /etc/keepalived/keepalived.sh
#!/bin/bash
#author :Magedu
#Description : an example of notify script
contact='root@localhost'
notify() {
    mailsubject="$(hostname) to be $1:vip floating"
    mailbody="$(date +'%F %H:%M:%S'): vrrp transition,$(hostname) change to be $1"
    echo $mailbody | mail -s "$mailsubject" $contact
case $1 in
master)
    notify master
    systemctl start nginx.service
    exit 0
    ;;
backup)
    notify backup
    systemctl restart nginx.service
    exit 0
    ;;
fault)
    notify fault
    systemctl stop nginx.service
    exit 0
    ;;
*)
    echo "Usage: $(basename $0) {master|backup|fault}"
    exit
    ;;
esac
######172.16.36.71的配置
172.16.36.71
~]# ssh-keygen -t rsa -P '' -f /root/.ssh/id_rsa
~]# ssh-copy-id root@172.16.36.70
~]# vim /etc/hosts
172.16.36.70 Centos7.pc1
~]# ntpdate 172.16.0.1

~]# yum install nginx
~]# mv /usr/share/nginx/html/index.html{,.bak}
~]# vim /usr/share/nginx/html/index.html
172.16.36.70
~]# systemctl start nginx
使用客户端IE测试测试页面,是否正常显示
~]# yum install keepalived
~]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
   notification_email {
        root@localhost
   }
   notification_email_from keepalived_admin@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Centos7.pc2
}
vrrp_script chk_down {
        script "[ -f /etc/keepalived/down ] && exit 1 || exit 0"
        interval 1
        weight -20
}
vrrp_script chk_nginx {
        script "curl -s http://172.16.36.100 | grep 172 &> /dev/null"
        interval 1
        weight -10
}
vrrp_instance VI_1 {
    state BACKUP
    interface eno16777736
    virtual_router_id 100
    priority 99
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 99999999
    }
    virtual_ipaddress {
        172.16.36.100/16 dev eno16777736 label eno16777736:1
    }
    notify_master "/etc/keepalived/keepalived.sh master"
    notify_bakcup "/etc/keepalived/keepalived.sh backup"
    notify_fault "/etc/keepalived/keepalived.sh fault"
    track_script {
        chk_down
        chk_nginx
    }
}
~]# vim /etc/keepalived/keepalived.sh
#!/bin/bash
#author :Magedu
#Description : an example of notify script
contact='root@localhost'
notify() {
    mailsubject="$(hostname) to be $1:vip floating"
    mailbody="$(date +'%F %H:%M:%S'): vrrp transition,$(hostname) change to be $1"
    echo $mailbody | mail -s "$mailsubject" $contact
case $1 in
master)
    notify master
    systemctl start nginx.service
    exit 0
    ;;
backup)
    notify backup
    systemctl restart nginx.service
    exit 0
    ;;
fault)
    notify fault
    systemctl stop nginx.service
    exit 0
    ;;
*)
    echo "Usage: $(basename $0) {master|backup|fault}"
    exit
    ;;
esac