使用HAProxy Keepalived实现主备及负载均衡

HAProxy提供高可用性负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。根据官方数据,其最高极限支持10G的并发。

HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。其支持从4层至7层的网络交换,即覆盖所有的TCP协议。就是说,Haproxy甚至还支持Mysql的负载均衡。如果说在功能上,能以proxy反向代理方式实现WEB均衡负载,这样的产品有很多。包括Nginx,ApacheProxy,lighttpd,Cheroke等。但要明确一点的,Haproxy并不是Http服务器。以上提到所有带反向代理均衡负载的产品,都清一色是WEB服务器。简单说,就是他们能自个儿提供静态(html,jpg,gif..)或动态(php,cgi..)文件的传输以及处理。而Haproxy仅仅,而且专门是一款的用于均衡负载的应用代理。其自身并不能提供http服务。开始Haproxy主备高可用测试

未分类

测试系统:

  • CentOS6.7/Ubuntu15.04

IP信息:

  • 主Haproxy:192.168.15.132

  • 备Haproxy:192.168.15.133

  • VIP:192.168.15.135(www.test.com/img.test.com)

  • Real1:192.168.15.128

  • Real2:192.168.15.130

  • Real3:192.168.15.140

主LB与备LB均配置

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf         #开启数据包转发

echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf   #允许监听非本地地址

sysctl -p

安装haproxy

cd /usr/local/src

CentOS系统:

yum install wget gcc gcc-c++ autoconf automake make

Ubuntu系统:

sudo apt-get install build-essential  libtool

wget http://pkgs.fedoraproject.org/repo/pkgs/haproxy/haproxy-1.4.24.tar.gz/86422620faa9759907563d5e0524b98c/haproxy-1.4.24.tar.gz

tar -xvzf haproxy-1.4.24.tar.gz

cd haproxy-1.4.24

make TARGET=linux2628 && make install  

#kernel版本大于2.6.28的,使用"TARGET=linux2628",否则使用"TARGET=linux26"。

添加haproxy用户:

useradd -d /var/lib/haproxy -s /bin/false haproxy

创建配置文件

mkdir -p /etc/haproxy 

cp -r  /usr/local/src/haproxy-1.4.24/examples/errorfiles  /etc/haproxy/errorfiles

cp /usr/src/haproxy-1.4.24/examples/haproxy.cfg /etc/haproxy  #拷贝示例文件

cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak      #备份示例文件

负载均衡①:

vi /etc/haproxy/haproxy.cfg
global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 5000
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon
defaults
        log     global
        mode    http          #所处理的类别 (#7层 http;4层tcp  )
        option  httplog
        option  httpclose
        option  dontlognull   #不记录健康检查的日志信息
        option  forwardfor    #后端服务器需要获得客户端真实ip时配置的参数,可以从Http Header中获得客户端ip
        option  redispatch    #serverId对应的服务器挂掉后,强制定向到其他健康的服务器
        retries 3
        maxconn 4000
        contimeout      8000
        clitimeout      80000
        srvtimeout      80000
listen Web_LB  
      bind *:80
      mode http   #7层:http;4层:tcp
      cookie Web_LB  insert
      balance roundrobin
      option httpclose
      option forwardfor
      #option httpchk GET /index.html #心跳检测的文件
      server Real1 192.168.15.128:80 cookie Real1 check inter 1500 rise 3 fall 3 weight 1
      server Real2 192.168.15.130:80 cookie Real2 check inter 1500 rise 3 fall 3 weight 1
      server Real3 192.168.15.140:80 cookie Real3 check inter 1500 rise 3 fall 3 weight 1
      #服务器定义,"cookie Real1"表示serverid为Real1,"check inter 1500"是检测心跳频率,"rise 3"是3次正确认为服务器可用,"fall 3"是3次失败认为服务器不可用,weight代表权重
      srvtimeout 30000 
listen stats  192.168.15.135:9999
    mode http
    stats enable
    stats refresh 5s
    stats hide-version
    stats realm Haproxy Statistics #监控页面提示信息
    stats uri /haproxy-status
    stats auth test:123456
    acl allow src 192.168.15.0/16
    stats admin if TRUE  #手动启用/禁用后端服务器(haproxy-1.4.9以后版本)
    errorfile 403 /etc/haproxy/errorfiles/403.http
    errorfile 500 /etc/haproxy/errorfiles/500.http
    errorfile 502 /etc/haproxy/errorfiles/502.http
    errorfile 503 /etc/haproxy/errorfiles/503.http
    errorfile 504 /etc/haproxy/errorfiles/504.http

负载均衡②:

vi /etc/haproxy/haproxy.cfg
global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 5000
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon
defaults
        log     global
        mode    http 
        option  httplog
        option  httpclose
        option  dontlognull  
        option  forwardfor   
        option  redispatch   
        retries 3
        maxconn 4000
        contimeout      8000
        clitimeout      80000
        srvtimeout      80000
listen stats  192.168.15.135:9999
    mode http
    stats enable
    stats refresh 5s
    stats hide-version
    stats realm Haproxy Statistics 
    stats uri  /haproxy-status
    stats auth test:123456
    acl allow src 192.168.15.0/16
    stats admin if TRUE
frontend www
    bind *:80
    acl web hdr_reg(host) -i ^(www.test.com|test.com)$
    #acl后面是规则名称。如果请求的域名满足正则表达式中的2个域名返回true(-i是忽略大小写),则分发请求至webserver的作用域。
    acl img hdr(host) -i img.test.com
    #如果访问img.test.com就分发到imgserver这个作用域。
    use_backend webserver if web
    use_backend imgserver if img
    default_backend webserver

backend webserver
    mode http
    balance roundrobin               #默认的负载均衡方式
    #balance source                  #类似Nginx的ip_hash,balance source 保存session值
    #balance leastconn               #最小连接
    cookie  SERVERID insert indirect
    option  httpchk /index.php   
    server Real1 192.168.15.128:80 cookie Real1 check inter 1500 rise 3 fall 3 weight 1
    server Real2 192.168.15.130:80 cookie Real2 check inter 1500 rise 3 fall 3 weight 1
    server Real3 192.168.15.140:80 cookie Real3 check inter 1500 rise 3 fall 3 weight 1
    #服务器定义,"cookie Real1"表示serverid为Real1,"check inter 1500"是检测心跳频率,"rise 3"是3次正确认为服务器可用,"fall 3"是3次失败认为服务器不可用,weight代表权重

backend imgserver
    mode http
    balance  roundrobin  
    option  httpchk /index.php
    server Real1 192.168.15.128:80 check inter 1500 rise 3 fall 3 weight 1
    server Real2 192.168.15.130:80 check inter 1500 rise 3 fall 3 weight 1
    server Real3 192.168.15.140:80 check inter 1500 rise 3 fall 3 weight 1

    errorfile 403 /etc/haproxy/errorfiles/403.http
    errorfile 500 /etc/haproxy/errorfiles/500.http
    errorfile 502 /etc/haproxy/errorfiles/502.http
    errorfile 503 /etc/haproxy/errorfiles/503.http
    errorfile 504 /etc/haproxy/errorfiles/504.http

动静分离:

global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 5000
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon
defaults
        log     global
        mode    http 
        option  httplog
        option  httpclose
        option  dontlognull  
        option  forwardfor   
        option  redispatch   
        retries 3
        maxconn 4000
        contimeout      8000
        clitimeout      80000
        srvtimeout      80000
listen stats  192.168.15.135:9999
    mode http
    stats enable
    stats refresh 5s
    stats hide-version
    stats realm Haproxy Statistics 
    stats uri  /haproxy-status
    stats auth test:123456
    acl allow src 192.168.15.0/16
    stats admin if TRUE
frontend  main *:80       #前端代理
    acl url_static     path_beg   -i  /static /images /javascript /stylesheets
    acl url_static     path_end   -i  .jpg .gif .png .css .js
    acl url_dynamic    path_end   -i  .php
    use_backend static_servers    if url_static
    default_backend           dynamic_servers 
backend static_servers   #后端的静态请求响应
    balance     roundrobin
    server      static 192.168.15.128:80 inter 3000 rise 2 fall 3 check maxconn 5000
backend dynamic_servers  #后端的动态请求响应
    balance     roundrobin
    server  dynamic1 192.168.15.130:80 inter 3000 rise 2 fall 3 check maxconn 5000
    server  dynamic2 192.168.15.140:80 inter 3000 rise 2 fall 3 check maxconn 5000

    errorfile 403 /etc/haproxy/errorfiles/403.http
    errorfile 500 /etc/haproxy/errorfiles/500.http
    errorfile 502 /etc/haproxy/errorfiles/502.http
    errorfile 503 /etc/haproxy/errorfiles/503.http
    errorfile 504 /etc/haproxy/errorfiles/504.http

启动haproxy

cp /usr/local/src/haproxy-1.4.24/examples/haproxy.init  /etc/rc.d/init.d/haproxy

chmod +x  /etc/rc.d/init.d/haproxy

chkconfig haproxy on

cp /usr/local/src/haproxy-1.4.24/haproxy /usr/sbin/haproxy

/etc/init.d/haproxy start

设置HAProxy日志

“/etc/rsyslog.d”目录下创建haproxy日志配置文件

local0.=info -/var/log/haproxy.log         #haproxy.log保存http日志

local0.notice -/var/log/haproxy-status.log #haproxy-status.log记录haproxy状态变更

vi /etc/rsyslog.d/haproxy.conf

$ModLoad imudp       #imudp是模块名,支持UDP协议
$UDPServerRun 514   #允许514端口接收使用UDP和TCP协议转发过来的日志,rsyslog在默认情况下在514端口监听UDP
$template Haproxy,"%msg%n"
local0.=info -/var/log/haproxy.log;Haproxy
local0.notice -/var/log/haproxy-status.log;Haproxy
### keep logs in localhost ##
local0.* ~

vim /etc/sysconfig/rsyslog

SYSLOGD_OPTIONS="-c 2 -r -m 0"
#各参数作用:
#-c 指定运行兼容模式。
#-r 接收远程日志
#-x 在接收客户端消息时,禁用DNS查找。需和-r参数配合使用。
#-m 标记时间戳。单位是分钟,为0时,表示禁用该功能。

重启rsyslog服务

service rsyslog restart

日志轮转配置

vim /etc/logrotate.d/haproxy

/var/log/haproxy.log {
    missingok
    notifempty
    sharedscripts
    rotate 5
    daily
    compress
    postrotate
        reload rsyslog >/dev/null 2>&1 ||truep;true
    endscript
}

创建定时任务:

59 23 * * * root /usr/sbin/logrotate -f /etc/logrotate.conf >/dev/null 2>&1
service crond restart

配置keepalived

wget http://www.keepalived.org/software/keepalived-1.2.15.tar.gz

tar -zxvf keepalived-1.2.15.tar.gz

cd keepalived-1.2.15

./configure --sysconf=/etc/  --with-kernel-dir=/usr/src/kernels/2.6.32-573.8.1.el6.x86_64

make && make install

ln -s /usr/local/sbin/keepalived  /sbin/  

配置keepalived.conf:

主:

! Configuration File for keepalived
global_defs {
   notification_email {
    test@163.com
   }
   notification_email_from keepalived@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Haprxoy_Master    
}
vrrp_script check_haproxy {
  script "/usr/local/src/check_haproxy.sh"
  interval 4
  weight 2
}
vrrp_instance VI_1 {
 #state MASTER
  state BAKCUP
  nopreempt 
  interface bond0
  smtp_alert
  virtual_router_id 66
  priority 100
  advert_int 1
  authentication {
  auth_type PASS
  auth_pass 1111
 }
 track_script {
  check_haproxy
 }
 virtual_ipaddress {
  192.168.15.135/24 broadcast 192.168.15.255 dev bond0 label bond0:1
 }
}

备:

! Configuration File for keepalived
global_defs {
   notification_email {
     test@163.com
   }
   notification_email_from keepalived@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Haprxoy_BACKUP   
}
vrrp_script check_haproxy {
 script "/usr/local/src/check_haproxy.sh"
 interval 4
 weight 2
}
vrrp_instance VI_1 {
  state BACKUP
  interface bond0
  smtp_alert
  virtual_router_id 66
  priority 88
  advert_int 1
  authentication {
  auth_type PASS
  auth_pass 1111
 }
 track_script {
  check_haproxy
 }
 virtual_ipaddress {
  192.168.15.135/24 broadcast 192.168.15.255 dev bond0 label bond0:1
 }
}

为防止haproxy异常关闭导致keepalived不自动切换

#!/bin/bash
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then
     /etc/init.d/haproxy  start
fi
sleep 3
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then
       /etc/init.d/keepalived stop
fi

chmod +x /usr/local/src/check_haproxy.sh

Keepalived.conf配置完毕,启动keepalived服务:/etc/init.d/keepalived start

关闭其中任何一个服务,访问正常,测试OK。

未分类

未分类

未分类

遇到的问题:

备机启动报错“Starting proxy LOADBAL: cannot bind socket”,原因为nginx进程占用80端口造成,停止nginx后正常。如果“ip_nonlocal_bind”未设置为1(启动haproxy的时候,允许忽视VIP的存在)也会造成相同问题

启动keepalived后日志出现“didn’t respond to SIGTERM”,需将“interval”时间设置相对较长(同时检查iptables状态)

CentOS7 nginx keepalived主备实例配置

nginx1 ip:192.168.12.4 #MASTER
nginx2 ip:192.168.12.10 #BACKUP
nginx_vip :192.168.12.100

原理可参考:
http://www.keepalived.org/documentation.html
系统为CentOS7

1、配置一下yum源

curl -L http://mirrors.aliyun.com/repo/Centos-7.repo > /etc/yum.repos.d/CentOS-Base.repo
curl -L http://mirrors.aliyun.com/repo/epel-7.repo > /etc/yum.repos.d/epel.repo

yum -y install keepalived nginx

2、设置服务器基本环境

关闭防火墙:iptables -F;service iptables save
关闭seLinux:setenforce 0;sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux

3、配置一下nginx,好区分测试环境

192.168.12.4:
echo 192.168.12.4 > /usr/share/nginx/html/index.html

192.168.12.10:
echo 192.168.12.10 > /usr/share/nginx/html/index.html

4、配置keepalived.conf

[root@192.168.12.4]# cat keepalived.conf 
! Configuration File for keepalived
global_defs {
notification_email {
notification@mail.com
}
notification_email_from fromnotification@mail.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

vrrp_script check_nginx {
script "sh /etc/keepalived/check_nginx.sh" 
interval 2 
}

vrrp_instance VI_1 {
state MASTER
interface eth0
mcast_src_ip 192.168.12.4
virtual_router_id 51
priority 100
advert_int 2
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.12.100
}
track_script {
check_nginx
}
}

[root@192.168.12.10]# cat keepalived.conf 
! Configuration File for keepalived
global_defs {
notification_email {
notification@mail.com
}
notification_email_from fromnotification@mail.com
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL
}

vrrp_script check_nginx {
script "sh /etc/keepalived/check_nginx.sh" 
interval 2 
}

vrrp_instance VI_1 {
state BACKUP
interface eth0
mcast_src_ip 192.168.12.10
virtual_router_id 51
priority 99
advert_int 2
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.12.100
}
track_script {
check_nginx
}
}

脚本check_nginx.sh内容如下

#!/bin/bash

A=`pgrep nginx|wc -l` 
if [ $A -eq 0 ];then 
/bin/systemctl start nginx.service
if [ `pgrep nginx|wc -l` -eq 0 ];then
/bin/systemctl stop keepalived.service
fi
fi

5、启动

在两个服务器执行启动命令

service nginx start
service keepalived start

6、检查

[root@192.168.12.4 keepalived]# ip addr
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host 
valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:85:83:e8 brd ff:ff:ff:ff:ff:ff
inet 192.168.12.4/24 brd 192.168.12.255 scope global eth0
valid_lft forever preferred_lft forever
inet 192.168.12.100/32 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe85:83e8/64 scope link 
valid_lft forever preferred_lft forever
[root@192.168.12.10 keepalived]# ip addr
1: lo:  mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host 
valid_lft forever preferred_lft forever
2: eth0:  mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:62:6a:50 brd ff:ff:ff:ff:ff:ff
inet 192.168.12.10/24 brd 192.168.12.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe62:6a50/64 scope link 
valid_lft forever preferred_lft forever

仔细观察可以发现192.168.12.4的服务器多了一个IP,就是192.168.12.100,这个就是VIP
再看日志发现主服务器日志有这下面一条:

Jul 12 10:30:57 localhost Keepalived_vrrp[2510]: VRRP_Instance(VI_1) Entering MASTER STATE

备服务器日志

Jul 11 00:01:00 localhost Keepalived_vrrp[111937]: VRRP_Instance(VI_1) Entering BACKUP STATE

综上主备已搭建成功

7、模拟主nginx宕机

双机高可用、负载均衡、MySQL(读写分离、主从自动切换)架构设计

架构简介

 

前几天网友来信说帮忙实现这样一个架构:只有两台机器,需要实现其中一台死机之后另一台能接管这台机器的服务,并且在两台机器正常服务时,两台机器都能用上。于是设计了如下的架构。
高可用/集群
此架构主要是由keepalived实现双机高可用,维护了一个外网VIP,一个内网VIP。正常情况时,外网VIP和内网VIP都绑定在server1服务器,web请求发送到server1的nginx,nginx对于静态资源请求就直接在本机检索并返回,对于php的动态请求,则负载均衡到server1和server2。对于SQL请求,会将此类请求发送到Atlas MySQL中间件,Atlas接收到请求之后,把涉及写操作的请求发送到内网VIP,读请求操作发送到mysql从,这样就实现了读写分离。

 

当主服务器server1宕机时,keepalived检测到后,立即把外网VIP和内网VIP绑定到server2,并把server2的mysql切换成主库。此时由于外网VIP已经转移到了server2,web请求将发送给server2的nginx。nginx检测到server1宕机,不再把请求转发到server1的php-fpm。之后的sql请求照常发送给本地的atlas,atlas把写操作发送给内网VIP,读操作发送给mysql从,由于内网VIP已经绑定到server2了,server2的mysql同时接受写操作和读操作。

 

当主服务器server1恢复后,server1的mysql自动设置为从,与server2的mysql主同步。keepalived不抢占server2的VIP,继续正常服务。

 

架构要求

 

要实现此架构,需要三个条件:

  • 1、服务器可以设置内网IP,并且设置的内网IP互通;
  • 2、服务器可以随意绑定IDC分配给我们使用的外网IP,即外网IP没有绑定MAC地址;
  • 3、MySQL服务器支持GTID,即MySQL-5.6.5以上版本。

 

环境说明

 

server1

  • eth0: 10.96.153.110(对外IP)
  • eth1: 192.168.1.100(对内IP)

server2

  • eth0: 10.96.153.114(对外IP)
  • eth1: 192.168.1.101(对内IP)

系统都是CentOS-6。

 

对外VIP: 10.96.153.239
对内VIP: 192.168.1.150

 

hosts设置

 

/etc/hosts:
192.168.1.100 server1
192.168.1.101 server2

 

Nginx PHP MySQL Memcached安装

 

这几个软件的安装推荐使用EZHTTP来完成。

 

解决session共享问题

 

php默认的session存储是在/tmp目录下,现在我们是用两台服务器作php请求的负载,这样会造成session分布在两台服务器的/tmp目录下,导致依赖于session的功能不正常。我们可以使用memcached来解决此问题。
上一步我们已经安装好了memcached,现在只需要配置php.ini来使用memcached,配置如下,打开php.ini配置文件,修改为如下两行的值:

  1. session.save_handler = memcache
  2. session.save_path = "tcp://192.168.1.100:11211,tcp://192.168.1.101:11211"

之后重启php-fpm生效。

 

Nginx配置

 

Server1配置

  1. http {
  2. […]
  3.     upstream php-server {
  4.            server 192.168.1.101:9000;
  5.            server 127.0.0.1:9000;
  6.            keepalive 100;
  7.     }
  8. […]
  9.  server {
  10.     […]
  11.         location ~ .php$ {
  12.                         fastcgi_pass   php-server;
  13.                         fastcgi_index  index.php;
  14.                         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
  15.                         include        fastcgi_params;
  16.         }
  17.     […]
  18.  }
  19. […]
  20. }

 

Server2配置

  1. http {
  2. […]
  3.     upstream php-server {
  4.            server 192.168.1.100:9000;
  5.            server 127.0.0.1:9000;
  6.            keepalive 100;
  7.     }
  8. […]
  9.  server {
  10.     […]
  11.         location ~ .php$ {
  12.                         fastcgi_pass   php-server;
  13.                         fastcgi_index  index.php;
  14.                         fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
  15.                         include        fastcgi_params;
  16.         }
  17.     […]
  18.  }
  19. […]
  20. }

这两个配置主要的作用是设置php请求的负载均衡。

 

MySQL配置

 

mysql util安装

我们需要安装mysql util里的主从配置工具来实现主从切换。

  1. cd /tmp
  2. wget http://dev.mysql.com/get/Downloads/MySQLGUITools/mysql-utilities-1.5.3.tar.gz
  3. tar xzf mysql-utilities-1.5.3.tar.gz
  4. cd mysql-utilities-1.5.3
  5. python setup.py build
  6. python setup.py install

 

mysql my.cnf配置

server1:

  1. [mysql]
  2. […]
  3. protocol=tcp
  4. […]
  5. […]
  6. [mysqld]
  7. […]
  8. # BINARY LOGGING #
  9. log-bin = /usr/local/mysql/data/mysql-bin
  10. expire-logs-days = 14
  11. binlog-format= row
  12. log-slave-updates=true
  13. gtid-mode=on
  14. enforce-gtid-consistency =true
  15. master-info-repository=TABLE
  16. relay-log-info-repository=TABLE
  17. server-id=1
  18. report-host=server1
  19. report-port=3306
  20. […]

server2:

  1. [mysql]
  2. […]
  3. protocol=tcp
  4. […]
  5. [mysqld]
  6. […]
  7. # BINARY LOGGING #
  8. log-bin = /usr/local/mysql/data/mysql-bin
  9. expire-logs-days = 14
  10. binlog-format= row
  11. log-slave-updates=true
  12. gtid-mode=on
  13. enforce-gtid-consistency =true
  14. master-info-repository=TABLE
  15. relay-log-info-repository=TABLE
  16. server-id=2
  17. report-host=server2
  18. report-port=3306
  19. […]

这两个配置主要是设置了binlog和启用gtid-mode,并且需要设置不同的server-id和report-host。

 

开放root帐号远程权限

我们需要在两台mysql服务器设置root帐号远程访问权限。

  1. mysql> grant all on *.* to ‘root’@’192.168.1.%’ identified by ‘Xp29at5F37’ with grant option;
  2. mysql> grant all on *.* to ‘root’@’server1’ identified by ‘Xp29at5F37’ with grant option;
  3. mysql> grant all on *.* to ‘root’@’server2’ identified by ‘Xp29at5F37’ with grant option;
  4. mysql> flush privileges;

 

设置mysql主从

在任意一台执行如下命令:

  1. mysqlreplicate –master=root:Xp29at5F37@server1:3306 –slave=root:Xp29at5F37@server2:3306 –rpl-user=rpl:o67DhtaW

# master on server1: … connected.
# slave on server2: … connected.
# Checking for binary logging on master…
# Setting up replication…
# …done.

 

显示主从关系

  1. mysqlrplshow –master=root:Xp29at5F37@server1 –discover-slaves-login=root:Xp29at5F37

# master on server1: … connected.
# Finding slaves for master: server1:3306

# Replication Topology Graph
server1:3306 (MASTER)
|
+— server2:3306 – (SLAVE)

 

检查主从状态

  1. mysqlrplcheck –master=root:Xp29at5F37@server1 –slave=root:Xp29at5F37@server2

# master on server1: … connected.
# slave on server2: … connected.
Test Description Status
—————————————————————————
Checking for binary logging on master [pass]
Are there binlog exceptions? [pass]
Replication user exists? [pass]
Checking server_id values [pass]
Checking server_uuid values [pass]
Is slave connected to master? [pass]
Check master information file [pass]
Checking InnoDB compatibility [pass]
Checking storage engines compatibility [pass]
Checking lower_case_table_names settings [pass]
Checking slave delay (seconds behind master) [pass]
# …done.

 

Keepalived配置

 

keepalived安装(两台都装)

  1. yum -y install keepalived
  2. chkconfig keepalived on

 

keepalived配置(server1)

  1. vi /etc/keepalived/keepalived.conf
  1. vrrp_sync_group VG_1 {
  2. group {
  3. inside_network
  4. outside_network
  5. }
  6. }
  7.  
  8. vrrp_instance inside_network {
  9. state BACKUP
  10. interface eth1
  11. virtual_router_id 51
  12. priority 101
  13. advert_int 1
  14. authentication {
  15. auth_type PASS
  16. auth_pass 3489
  17. }
  18. virtual_ipaddress {
  19. 192.168.1.150/24
  20. }
  21. nopreempt
  22. notify /data/sh/mysqlfailover-server1.sh
  23. }
  24.  
  25. vrrp_instance outside_network {
  26. state BACKUP
  27. interface eth0
  28. virtual_router_id 50
  29. priority 101
  30. advert_int 1
  31. authentication {
  32. auth_type PASS
  33. auth_pass 3489
  34. }
  35. virtual_ipaddress {
  36. 10.96.153.239/24
  37. }
  38. nopreempt
  39. }

 

keepalived配置(server2)

  1. vrrp_sync_group VG_1 {
  2. group {
  3. inside_network
  4. outside_network
  5. }
  6. }
  7.  
  8. vrrp_instance inside_network {
  9. state BACKUP
  10. interface eth1
  11. virtual_router_id 51
  12. priority 100
  13. advert_int 1
  14. authentication {
  15. auth_type PASS
  16. auth_pass 3489
  17. }
  18. virtual_ipaddress {
  19. 192.168.1.150
  20. }
  21. notify /data/sh/mysqlfailover-server2.sh
  22. }
  23.  
  24. vrrp_instance outside_network {
  25. state BACKUP
  26. interface eth0
  27. virtual_router_id 50
  28. priority 100
  29. advert_int 1
  30. authentication {
  31. auth_type PASS
  32. auth_pass 3489
  33. }
  34. virtual_ipaddress {
  35. 10.96.153.239/24
  36. }
  37. }

此keepalived配置需要注意的是:

  • 1、两台server的state都设置为backup,server1增加nopreempt配置,并且server1 priority比server2高,这样用来实现当server1从宕机恢复时,不抢占VIP;
  • 2、server1设置notify /data/sh/mysqlfailover-server1.sh,server2设置notify /data/sh/mysqlfailover-server2.sh,作用是自动切换主从

/data/sh/mysqlfailover-server1.sh脚本内容:

  1. #!/bin/bash
  2.  
  3. sleep 10
  4. state=$3
  5. result=`mysql -h127.0.0.1 -P3306 -uroot -pXp29at5F37 -e ‘show slave status;’`
  6. [[ "$result" == "" ]] && mysqlState="master" || mysqlState="slave"
  7.  
  8. if [[ "$state" == "MASTER" ]];then
  9.   if [[ "$mysqlState" == "slave" ]];then
  10.     mysqlrpladmin –slave=root:Xp29at5F37@server1:3306 failover
  11.   fi
  12.  
  13. elif [[ "$state" == "BACKUP" ]];then
  14.   if [[ "$mysqlState" == "master" ]];then
  15.     mysqlreplicate –master=root:Xp29at5F37@server2:3306 –slave=root:Xp29at5F37@server1:3306 –rpl-user=rpl:o67DhtaW
  16.   fi
  17. fi
  18.  
  19. sed -i ‘s/proxy-read-only-backend-addresses.*/proxy-read-only-backend-addresses = 192.168.1.150:3306/’ /usr/local/mysql-proxy/conf/my.cnf
  20. mysql -h127.0.0.1 -P2345 -uuser -ppwd -e "REMOVE BACKEND 2;"

/data/sh/mysqlfailover-server2.sh脚本内容:

  1. #!/bin/bash
  2.  
  3. sleep 10
  4. state=$3
  5. result=`mysql -h127.0.0.1 -P3306 -uroot -pXp29at5F37 -e ‘show slave status;’`
  6. [[ "$result" == "" ]] && mysqlState="master" || mysqlState="slave"
  7.  
  8. if [[ "$state" == "MASTER" ]];then
  9.   if [[ "$mysqlState" == "slave" ]];then
  10.     mysqlrpladmin –slave=root:Xp29at5F37@server2:3306 failover
  11.   fi
  12.  
  13. elif [[ "$state" == "BACKUP" ]];then
  14.   if [[ "$mysqlState" == "master" ]];then
  15.     mysqlreplicate –master=root:Xp29at5F37@server1:3306 –slave=root:Xp29at5F37@server2:3306 –rpl-user=rpl:o67DhtaW
  16.   fi
  17. fi
  18.  
  19. sed -i ‘s/proxy-read-only-backend-addresses.*/proxy-read-only-backend-addresses = 192.168.1.150:3306/’ /usr/local/mysql-proxy/conf/my.cnf
  20. mysql -h127.0.0.1 -P2345 -uuser -ppwd -e "REMOVE BACKEND 2;"

 

Atlas设置

 

atlas安装

到这里下载最新版本,https://github.com/Qihoo360/Atlas/releases

  1. cd /tmp
  2. wget https://github.com/Qihoo360/Atlas/releases/download/2.2.1/Atlas-2.2.1.el6.x86_64.rpm
  3. rpm -i Atlas-2.2.1.el6.x86_64.rpm

 

atlas配置

  1. cd /usr/local/mysql-proxy/conf
  2. cp test.cnf my.cnf
  3. vi my.cnf

调整如下参数,

  1. proxy-backend-addresses = 192.168.1.150:3306
  2. proxy-read-only-backend-addresses = 192.168.1.101:3306
  3. pwds = root:qtyU1btXOo074Itvx0UR9Q==
  4. event-threads = 8

注意:
proxy-backend-addresse设置为内网VIP
proxy-read-only-backend-addresses设置为server2的IP
root:qtyU1btXOo074Itvx0UR9Q==设置数据库的用户和密码,密码是通过/usr/local/mysql-proxy/bin/encrypt Xp29at5F37生成。
更详细参数解释请查看,Atlas配置详解

 

启动atlas

  1. /usr/local/mysql-proxy/bin/mysql-proxy –defaults-file=/usr/local/mysql-proxy/conf/my.cnf

之后程序里配置mysql就配置127.0.0.1:1234就好。

 

部署atlas自动维护脚本

在两台机器都部署此脚本,并添加定时任务(如每2分钟运行一次)我们把脚本放在/data/sh/auto_maintain_atlas.sh,脚本内容为:

  1. #!/bin/bash
  2.  
  3. count=`mysql -N -h127.0.0.1 -P2345 -uuser -ppwd -e "select * from backends;" | wc -l`
  4.  
  5. if [[ "$count" == "1" ]];then
  6.   result=`mysql -hserver1 -P3306 -uroot -pXp29at5F37 -e ‘show slave statusG’`
  7.   if echo "$result" | grep Slave_IO_State;then
  8.     slaveIP=192.168.1.100
  9.   else
  10.     result=`mysql -hserver2 -P3306 -uroot -pXp29at5F37 -e ‘show slave statusG’`
  11.     slaveIP=192.168.1.101
  12.   fi
  13.  
  14.         slaveIORunning=`echo "$result" | awk -F’:’ ‘/Slave_IO_Running:/{print $2}’`
  15.         slaveSQLRunning=`echo "$result" | awk -F’:’ ‘/Slave_SQL_Running:/{print $2}’`
  16.         SlaveSQLRunning_State=`echo "$result" | awk -F’:’ ‘/Slave_SQL_Running_State:/{print $2}’`
  17.     
  18.   if [[ "$slaveIORunning" =~ "Yes" && "$slaveSQLRunning" =~ "Yes" && "$SlaveSQLRunning_State" =~ "Slave has read all relay log" ]];then
  19.     mysql -h127.0.0.1 -P2345 -uuser -ppwd -e "add slave ${slaveIP}:3306;"
  20.   fi
  21. fi

为什么需要这个脚本呢?假设目前mysql主服务器在s1,s1宕机后,s2接管VIP,接着删除atlas中设置的slave backend,其mysql提升为主。过一段时间后,s1从宕机中恢复,这时候s1的mysql自动切换为从,接着删除atlas中设置的slave backend,开始连接s2的mysql主同步数据。到这个时候我们发现,已经不存在读写分离了,所有的sql都发送给了s2的mysql。auto_maintain_atlas.sh脚本就派上用场了,此脚本会定时的检查主从是否已经同步完成,如果完成就自动增加slave backend,这样读写分离又恢复了,完全不需要人工干预。

 

server1主宕机测试

 

测试keepalived是否工作正常

我们来模拟server1宕机。
在server1上执行shutdown关机命令。
此时我们登录server2,执行ip addr命令,输出如下:
1: lo: mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:81:9d:42 brd ff:ff:ff:ff:ff:ff
inet 10.96.153.114/24 brd 10.96.153.255 scope global eth0
inet 10.96.153.239/24 scope global secondary eth0
inet6 fe80::20c:29ff:fe81:9d42/64 scope link
valid_lft forever preferred_lft forever
3: eth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:81:9d:4c brd ff:ff:ff:ff:ff:ff
inet 192.168.1.101/24 brd 192.168.1.255 scope global eth1
inet 192.168.1.150/32 scope global eth1
inet6 fe80::20c:29ff:fe81:9d4c/64 scope link
valid_lft forever preferred_lft forever

我们看到对外VIP 10.96.153.239和对内IP 192.168.1.150已经转移到server2了,证明keepalived运行正常。

 

测试是否自动切换了主从

登录server2的mysql服务器,执行show slave status;命令,如下:
mysql> show slave statusG
Empty set (0.00 sec)

我们发现从状态已经为空,证明已经切换为主了。

 

测试server1是否抢占VIP

为什么要测试这个呢?如果server1恢复之后抢占了VIP,而我们的Atlas里后端设置的是VIP,这样server1启动之后,sql的写操作就会向server1的mysql发送,而server1的mysql数据是旧于server2的,所以这样会造成数据不一致,这个是非常重要的测试。
我们先来启动server1,之后执行ip addr,输出如下:
1: lo: mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:f1:4f:4e brd ff:ff:ff:ff:ff:ff
inet 10.96.153.110/24 brd 10.96.153.255 scope global eth0
inet6 fe80::20c:29ff:fef1:4f4e/64 scope link
valid_lft forever preferred_lft forever
3: eth1: mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:f1:4f:58 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.100/24 brd 192.168.1.255 scope global eth1
inet6 fe80::20c:29ff:fef1:4f58/64 scope link
valid_lft forever preferred_lft forever

我们看到,server1并没有抢占VIP,测试正常。不过另人郁闷的是,在虚拟机的环境并没有测试成功,不知道为什么。

 

测试server2的atlas是否已经删除slave backend

我们测试这个是为了保证atlas已经没有slave backend,也就是没有从库的设置了,否则当server1恢复时,有可能会把读请求发送给server1的mysql,造成读取了旧数据的问题。

[root@server1 ~]# mysql -h127.0.0.1 -P2345 -uuser -ppwd
mysql> select * from backends;
+————-+——————–+——-+——+
| backend_ndx | address | state | type |
+————-+——————–+——-+——+
| 1 | 192.168.1.150:3306 | up | rw |
+————-+——————–+——-+——+
1 rows in set (0.00 sec)
如果看到只有一个后端,证明运作正常。

 

测试server1 mysql是否设置为从

serve1恢复后,登录server1的mysql服务器,执行show slave status;命令,如下:

mysql> show slave statusG
*************************** 1. row ***************************
Slave_IO_State: Opening tables
Master_Host: server1
Master_User: rpl
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000015
Read_Master_Log_Pos: 48405991
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 361
Relay_Master_Log_File: mysql-bin.000015
Slave_IO_Running: Yes
Slave_SQL_Running: yes

 

测试是否自动恢复读写分离

server1恢复后一段时间,我们可以看是读写分离是否已经恢复。

[root@server1 ~]# mysql -h127.0.0.1 -P2345 -uuser -ppwd
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 1
Server version: 5.0.99-agent-admin

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type ‘help;’ or ‘h’ for help. Type ‘c’ to clear the current input statement.

mysql> select * from backends;
+————-+——————–+——-+——+
| backend_ndx | address | state | type |
+————-+——————–+——-+——+
| 1 | 192.168.1.150:3306 | up | rw |
| 2 | 192.168.1.100:3306 | up | ro |
+————-+——————–+——-+——+
2 rows in set (0.00 sec)

我们看到server1已经被添加为slave backend了。这表示已经成功恢复读写分离。

双机热备+负载均衡线上方案(Heartbeat+DRBD+NFS+Keepalived+Lnmp)

我们下面来实现一个架构,heartbeat+drbd+nfs实现mysql和网站数据的同步,keepalived实现nginx的高可用,而用nginx和dns轮询实现负载均衡。

架构说明

目录规划

/usr/local/src/lnmp:用来存放源码工具等等
/data:用来存放所有数据和NFS以及DRBD的挂载
/data/shell:用来存放所有管理脚本
/data/mysql:用来挂载DRBD的mysql资源,以供mysql存放数据库
/data/wwwnfs:用来挂载DRBD生成的www资源,以供两个节点挂载到各个节点的/data/www目录,以供论坛等程序数据使用
/data/www:用来挂载NFS资源,用来存放论坛(网站)等程序数据

拓扑工作原理

内网:
1,DRBD网络存储创建出两个资源,一个mysql给mysql数据库同步用,一个www给web(论坛)数据NFS共享挂载用,虚拟出两个虚拟IP,一个是 192.168.1.100,用来连接数据库,一个是192.168.1.200,用来给节点挂载NFS
注意:NFS底下挂载了三次:DRBD挂载一次,文件系统挂载一次,客户端挂载一次
2,Heartbeat来实现DRBD的HA,同时虚拟出两个内网IP,并管理NFS,MySQL的启动和关闭

外网:
1,两个节点都用Nginx做均衡器,通过内网调度负载两个节点,实现内部均衡
2,DNS配置双IP对应一个域名的方式来实现DNS轮询,实现外网均衡
3,Keepalived使用双主(master)配置虚拟出两个虚拟IP:节点一 12.12.12.100和节点二 12.12.12.200,同时共外网访问,两个节点互为主从关系,当某个节点挂掉的时候,另外一个节点将同时是两个资源的master,同时拥有两个虚拟IP,实现资源转移。

我们知道DNS的缺点就是生效慢,分配资源不合理,理论上有可能把所有的请求都发送给同一节点,导致均衡不合理导致所有资源不可用,这里我们由于有了NGINX内部负载,就不怕DNS轮询不均衡了,因为NGINX内部有严谨的调度方式,不管那台请求有多少,在内部都能实现理想的调度,这样就能把DNS负载均衡和NGINX完美结合,是硬件资源得到合理的利用,然后利用keepalive保证了每个节点的可靠性,几乎完美!
拓扑图如下:
高可用/集群

架构实现

LNMP架构配置

配置LNMp架构需要注意两点:
注意一:这里MYSQL都不要初始化,不要启动!后面有专门的配置的
注意二:nginx所有端口都改成 8080,因为一会还要安装nginx来做均衡器并对外提供服务,所以不要用默认的80
注意三、nginx和php-fpm运行的用户都是www。

安装配置NFS

1、安装NFS

  1. yum install nfs-utils nfs4-acl-tools portmap

2、配置/etc/exports

  1. /data/wwwnfs 192.168.1.0/24(rw,,no_root_squash,sync,anonuid=502,anongid=502)

注意:
/data/wwwnfs:就是给两个节点挂载的目录,所有网站程序都放在这里,实现论坛程序等数据的共享(同步)
anonuid=502,anongid=502:这个表示客户端上任何用户进入到挂载目录都以uid=502和gid=502身份,我这里这个代表的是www用户
3、启动

  1. service portmap start
  2. service nfs start

切忌,必须先启动portmap

  1. chkconfig  nfs off
  2. chkconfig  portmap on

注意:portmap服务器必须常驻,且不收heartbeat管理;而nfs这必须要用heartbeat来管理他的启动和关闭,所以这里要关闭nfs开机自动启动

同时要启动锁机制,因为同时有两个节点要使用同一份数据,所以需要有总裁,这个尤其是在NFS给mysql用的时候是必须要用的,对于论坛或网站,要看情况,如果存在对同一文件同时修改的时候必须要启动NFS锁机制,如果没有这种情况,那么建议不要启动,启动了会降低NFS的性能:

  1. /sbin/rpc.lockd
  2. echo "/sbin/rpc.lockd" >>/etc/rc.local

4、开机自动挂载

  1. echo "sleep 20" >>/etc/rc.local
  2. echo "/bin/mount -t nfs 192.168.1.200:/data/wwwnfs /data/www" >>/etc/rc.local

为什么为延迟20秒再挂载nfs?因为如果不等待立即挂载,会发现挂载不上,这是由于heartbeat启动用的vip还没设置好的原因。
立即挂载:

  1. mount -a

安装配置DRBD

安装方法见:http://devops.webres.wang/2012/02/drbd-compile-install-deploy/

配置文件

DRBD有三种配置文件:
/usr/local/drbd/etc/drbd.conf
/usr/local/drbd/etc/drbd.d/global_common.conf
/usr/local/drbd/etc/drbd.d/*.res
1、drbd.conf

  1. include "drbd.d/global_common.conf";
  2. include "drbd.d/*.res";

2、global_common.conf

  1. global {
  2.   usage-count yes;
  3. }
  4. common {
  5.   net {
  6.     protocol C;
  7.   }
  8. }

3、mysql.res和www.res
mysql.res:

  1. vi /usr/local/drbd/etc/drbd.d/mysql.res
  1. #资源组的名称
  2. resource mysql{
  3.  
  4. #定义主服务器资源
  5.         on node1{
  6. #建立块设备文件
  7.         device /dev/drbd1;
  8. #要用于复制的分区
  9.         disk /dev/sdb1;
  10. #定义侦听IP和端口
  11.         address 192.168.1.10:7788;
  12. #meta data信息存放的方式,这里为内部存储,即和真实数据放在一起存储
  13.         meta-disk internal;
  14.                    }
  15.  
  16. #定义备服务器资源
  17.         on node2{
  18.         device /dev/drbd1;
  19.         disk /dev/sdb1;
  20.         address 192.168.1.20:7788;
  21.         meta-disk internal;
  22.                    }
  23.  
  24.                 }

www.res:

  1. vi /usr/local/drbd/etc/drbd.d/www.res
  1. #资源组的名称
  2. resource www{
  3.  
  4. #定义主服务器资源
  5.         on node2{
  6. #建立块设备文件
  7.         device /dev/drbd2;
  8. #要用于复制的分区
  9.         disk /dev/sdb2;
  10. #定义侦听IP和端口
  11.         address 192.168.1.20:7789;
  12. #meta data信息存放的方式,这里为内部存储,即和真实数据放在一起存储
  13.         meta-disk internal;
  14.                    }
  15.  
  16. #定义备服务器资源
  17.         on node1{
  18.         device /dev/drbd2;
  19.         disk /dev/sdb2;
  20.         address 192.168.1.10:7789;
  21.         meta-disk internal;
  22.                    }
  23.  
  24.                 }

最后复制这些文件到node2。

初始化DRBD资源

1)在各个节点启用资源mysql和www

  1. modprobe drbd
  2. dd if=/dev/zero of=/dev/sdb1 bs=1M count=10
  3. dd if=/dev/zero of=/dev/sdb2 bs=1M count=10
  4. drbdadm create-md mysql
  5. drbdadm create-md www
  6. drbdadm up mysql
  7. drbdadm up www

2),提升各个节点上的主
在node1上:

  1. drbdadm primary –force mysql

在node2上:

  1. drbdadm primary –force www

3)格式化drbd块设备
在node1上

  1. mkfs.ext3 /dev/drbd1

在node2上

  1. mkfs.ext3 /dev/drbd2

4)挂载分区
在node1上

  1. mount /dev/drbd1 /data/mysql

在node2上

  1. mount /dev/drbd2 /data/wwwnfs

安装配置heartbeat

1、安装heartbeat

  1. yum install heartbeat

安装完后会自动建立用户hacluster和组haclient
确保两个节点上hacluster用户的的UID和GID相同
2、同步两台节点的时间

  1. rm -rf /etc/localtime
  2. cp -f /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
  3. yum install -y ntp
  4. ntpdate -d cn.pool.ntp.org

3、配置/etc/ha.d/ha.cf

  1. debugfile /var/log/ha-debug                             #打开错误日志报告
  2. keepalive 2                                             #两秒检测一次心跳线连接
  3. deadtime 10                                             #10 秒测试不到主服务器心跳线为有问题出现
  4. warntime 6                                              #警告时间(最好在 2 ~ 10 之间)
  5. initdead 120                                            #初始化启动时 120 秒无连接视为正常,或指定heartbeat
  6.                                                         #在启动时,需要等待120秒才去启动任何资源。
  7.  
  8. udpport 694                                             #用 udp 的 694 端口连接
  9. ucast eth0 192.168.1.20                                #单播方式连接(主从都写对方的 ip 进行连接)
  10. node   node1                                           #声明主服(注意是主机名uname -n不是域名)
  11. node   node2                                           #声明备服(注意是主机名uname -n不是域名)
  12. auto_failback on                                        #自动切换(主服恢复后可自动切换回来)这个不要开启
  13. respawn hacluster /usr/lib/heartbeat/ipfail           #监控ipfail进程是否挂掉,如果挂掉就重启它

4、/etc/ha.d/authkeys

  1. auth 1
  2. 1 crc

5、/etc/ha.d/haresources

  1. node1 IPaddr::192.168.1.100/24/eth0 drbddisk::mysql Filesystem::/dev/drbd1::/data/mysql::ext3 mysqld portmap
  2. node2 IPaddr::192.168.1.200/24/eth0 drbddisk::www Filesystem::/dev/drbd2::/data/wwwnfs::ext3 portmap nfs

6、创建nfs管理脚本

  1. vi /etc/ha.d/resource.d/nfs

写入:

  1. #!/bin/bash
  2.  
  3. NFSD=/etc/rc.d/init.d/nfs
  4. NFSDPID=`/sbin/pidof nfsd`
  5. case $1 in
  6. start)
  7. $NFSD start;
  8. ;;
  9. stop)
  10. $NFSD stop;
  11.         if [ "$NFSDPID" != " " ];then
  12.                 for NFSPID in $NFSDPID
  13.                 do /bin/kill -9 $NFSPID;
  14.                 done
  15.         fi
  16. ;;
  17. *)
  18. echo "Syntax incorrect. You need one of {start|stop }"
  19. ;;
  20. esac

先启动node1的heartbeat,再启动node2的heartbeat
启动成功后,这里有几项需要检查
node1:
1、执行ip a,检查是否已经设置有虚拟ip 192.168.1.100
2、执行cat /proc/drbd检查状态是否正常
3、执行df -h查看/dev/drbd1是否已经挂载到/data/mysql
4、执行service mysqld status查看mysql是否已经启动
node2:
1、执行ip a查看是否已经设置虚拟ip 192.168.1.200
2、执行cat /proc/drbd检查状态是否正常
3、执行df -h查看/dev/drbd2是否已经挂载到/data/wwwnfs和192.168.1.200:/data/wwwnfs是否已经挂载到/data/www

nginx均衡器配置

  1. user  www;
  2. worker_processes  1;
  3.  
  4. error_log  /var/log/nginx/error.log warn;
  5. pid        /var/run/nginx.pid;
  6.  
  7.  
  8. events {
  9.     worker_connections  1024;
  10. }
  11.  
  12.  
  13. http {
  14.     include       /etc/nginx/mime.types;
  15.     default_type  application/octet-stream;
  16.  
  17.     log_format  main  ‘$remote_addr – $remote_user [$time_local] "$request" ‘
  18.                       ‘$status $body_bytes_sent "$http_referer" ‘
  19.                       ‘"$http_user_agent" "$http_x_forwarded_for"’;
  20.  
  21.     access_log  /var/log/nginx/access.log  main;
  22.  
  23.     sendfile        on;
  24.     #tcp_nopush     on;
  25.  
  26.     keepalive_timeout  65;
  27.  
  28.     #gzip  on;
  29.  upstream devops.webres.wang_server
  30.   {
  31.   server 192.168.1.10:8080 weight=3 max_fails=2 fail_timeout=30s;
  32.   server 192.168.1.20:8080 weight=9 max_fails=2 fail_timeout=30s;
  33.   }
  34.   server
  35.   {
  36.     listen       80;
  37.     server_name  devops.webres.wang;
  38.     location / {
  39.     root /data/www/devops.webres.wang;
  40.     index index.php index.htm index.html;
  41.     proxy_redirect off;
  42.     proxy_set_header Host $host;
  43.     proxy_set_header X-Real-IP $remote_addr;
  44.     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  45.     proxy_pass http://devops.webres.wang_server;
  46.     }
  47.     access_log  off;
  48.   }
  49. server
  50.   {
  51.     listen       8080;
  52.     server_name  devops.webres.wang;
  53.     index index.html index.htm index.php;
  54.     root  /data/www/devops.webres.wang;
  55.     #limit_conn   crawler  20;
  56.  location ~ .php$ {
  57.         root           /data/www/devops.webres.wang;
  58.         fastcgi_pass   127.0.0.1:9000;
  59.         fastcgi_index  index.php;
  60.         fastcgi_param  SCRIPT_FILENAME  /data/www/devops.webres.wang/$fastcgi_script_name;
  61.         include        fastcgi_params;
  62.     }
  63.     location ~ .*.(gif|jpg|jpeg|png|bmp|swf)$
  64.     {
  65.       expires      30d;
  66.     }
  67.     location ~ .*.(js|css)?$
  68.     {
  69.       expires      1h;
  70.     }
  71.     access_log  off;
  72.       }
  73. }

这里定义了两台用于负载均衡的机子,分别是192.168.1.10:8080和192.168.1.20:8080,通过proxy_pass http://devops.webres.wang_server代理循询转发到这两台机,达到负载均衡的作用。
你可以建立index.php,里面写入:

  1. <?php
  2. echo $_SERVER[‘SERVER_ADDR’];
  3. ?>

如果连续刷新几次,得到不同的IP,证明已经均衡负载到不同的服务器。

Keepalived实现nginx和php的HA

1、keepalived安装
安装方法见:http://devops.webres.wang/2012/02/nginx-keepalived-high-availability/
2、配置
节点一node1配置如下:

  1. global_defs {
  2.    notification_email {
  3.      admin@webres.wang
  4.    }
  5.    notification_email_from keepalived@domain.com
  6.    smtp_server 127.0.0.1
  7.    smtp_connect_timeout 30
  8.    router_id LVS_DEVEL
  9. }
  10. vrrp_instance VI_1 {
  11.     state MASTER        ############ 辅机为 BACKUP
  12.     interface eth0
  13.     virtual_router_id 100
  14.     mcast_src_ip 192.168.1.10  ########### 本机IP
  15.     priority 102                  ########### 权值要比 back 高
  16.     advert_int 1
  17.     authentication {
  18.         auth_type PASS
  19.         auth_pass 1111
  20.     }
  21.     virtual_ipaddress {
  22.        12.12.12.100
  23.     }
  24. }
  25.  
  26. vrrp_instance VI_1 {
  27.     state BACKUP
  28.     interface eth0
  29.     virtual_router_id 200
  30.     mcast_src_ip 192.168.1.101 ########### 本机IP
  31.     priority 101              ##########权值 要比 master 低。。
  32.     advert_int 1
  33.     authentication {
  34.         auth_type PASS
  35.         auth_pass 1111
  36.     }
  37.     virtual_ipaddress {
  38.        12.12.12.200
  39.     }
  40. }

节点二配置:

  1. global_defs {
  2.    notification_email {
  3.      admin@webres.wang
  4.    }
  5.    notification_email_from keepalived@domain.com
  6.    smtp_server 127.0.0.1
  7.    smtp_connect_timeout 30
  8.    router_id LVS_DEVEL
  9. }
  10. vrrp_instance VI_1 {
  11.     state BACKUP
  12.     interface eth0
  13.     virtual_router_id 100
  14.     mcast_src_ip 192.168.1.20 ########### 本机IP
  15.     priority 101              ##########权值 要比 master 低。。
  16.     advert_int 1
  17.     authentication {
  18.         auth_type PASS
  19.         auth_pass 1111
  20.     }
  21.     virtual_ipaddress {
  22.        12.12.12.100
  23.     }
  24. }
  25.  
  26. vrrp_instance VI_1 {
  27.     state MASTER        ############ 辅机为 BACKUP
  28.     interface eth0
  29.     virtual_router_id 200
  30.     mcast_src_ip 192.168.1.103  ########### 本机IP
  31.     priority 102                  ########### 权值要比 back 高
  32.     advert_int 1
  33.     authentication {
  34.         auth_type PASS
  35.         auth_pass 1111
  36.     }
  37.     virtual_ipaddress {
  38.        12.12.12.200
  39.     }
  40. }

3、创建监控脚本
node1监控脚本:

  1. vi /opt/check.sh
  1. #!/bin/bash
  2. while  :
  3. do
  4. mysqlcheck=`/usr/bin/mysqladmin -uroot ping 2>&1`
  5. mysqlcode=`echo $?`
  6. heartbeat=`ps -C heartbeat –no-header | wc -l`
  7. if [ $mysqlcode -ne 0 ] ;then
  8.  if [ $heartbeat-ne 0 ];then
  9. service heartbeat stop
  10. fi
  11. fi
  12. phpcheck=`ps -C php-fpm –no-header | wc -l`
  13. nginxcheck=`ps -C nginx –no-header | wc -l`
  14. keepalivedcheck=`ps -C keepalived –no-header | wc -l`
  15. if [ $nginxcheck -eq 0 ]|| [ $phpcheck -eq 0 ];then
  16.                 if [ $keepalivedcheck -ne 0 ];then
  17.                    killall -TERM keepalived
  18.                 else
  19.                    echo "keepalived is stoped"
  20.                 fi
  21.         else
  22.                 if [ $keepalivedcheck -eq 0 ];then
  23.                    /etc/init.d/keepalived start
  24.                 else
  25.                    echo "keepalived is running"
  26.                 fi
  27. fi
  28. sleep 5
  29. done

node2监控脚本:

  1. #!/bin/bash
  2. while  :
  3. do
  4. phpcheck=`ps -C php-cgi –no-header | wc -l`
  5. nginxcheck=`ps -C nginx –no-header | wc -l`
  6. keepalivedcheck=`ps -C keepalived –no-header | wc -l`
  7. if [ $nginxcheck -eq 0 ]|| [ $phpcheck -eq 0 ];then
  8.                 if [ $keepalivedcheck -ne 0 ];then
  9.                    killall -TERM keepalived
  10.                 else
  11.                    echo "keepalived is stoped"
  12.                 fi
  13.         else
  14.                 if [ $keepalivedcheck -eq 0 ];then
  15.                    /etc/init.d/keepalived start
  16.                 else
  17.                    echo "keepalived is running"
  18.                 fi
  19. fi
  20. sleep 5
  21. done

这个监控代码实现了mysql,nginx,php-fpm的HA。
加上权限,并执行

  1. chmod +x /opt/check.sh
  2. nohup sh /opt/check.sh &

设置开机启动:
echo “nohup sh /opt/check.sh &” >> /etc/rc.local

4、测试keepalived
分别启动keepalived

  1. service keepalived start

1)执行ip a检查node1和node2是否已经存在vip:12.12.12.100和12.12.12.200
2)测试nginx和php-fpm的HA。在node1执行service nginx stop或者service php-fpm stop停止nginx或php-fpm,过几秒钟后你会发现node2已经接管了vip 12.12.12.100,并且使用vip 12.12.12.100或12.12.12.200浏览nginx网页你会发现网页显示的IP一直是192.168.1.20,表明keepalived已经成功接管node1的vip和nginx或php-fpm服务。
3)测试mysql HA。在node1执行service mysqld stop停止mysql服务,几秒后在node2查看,发现node2已经接管vip 192.168.1.100,并且已经启动mysql服务。
注意:在恢复mysql或nginx,php-fpm时,先停止监控脚本,要不heartbeat或keepalived还没实现接管又被停止。
参考:http://bbs.ywlm.net/thread-965-1-1.html

nginx+keepalived实现双机热备的高可用

这篇文章简单介绍利用keepalived软件,实现对nginx服务器的高可用,即实现故障自动切换。假设你已经安装好nginx,下面介绍keepalived的安装和使用。

keepalived安装

  1. yum install openssl-devel
  2. cd /tmp
  3. wget http://www.keepalived.org/software/keepalived-1.2.2.tar.gz
  4. tar xzf keepalived-1.2.2.tar.gz
  5. cd keepalived-1.2.2
  6. ./configure
  7. make && make install
  8. cp /usr/local/etc/rc.d/init.d/keepalived /etc/init.d/
  9. cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
  10. chmod +x /etc/init.d/keepalived
  11. chkconfig –add keepalived
  12. chkconfig keepalived on
  13. mkdir /etc/keepalived
  14. ln -s /usr/local/sbin/keepalived /usr/sbin/

keepalived的配置

更详细的keepalived配置文件说明可以执行man keepalived.conf查看。
我们假设主服务器IP:192.168.1.103,从服务器ip:192.168.1.101 虚拟ip:192.168.1.110
下面对主服务器的keepalived进行配置:

  1. vi /etc/keepalived/keepalived.conf
  1. global_defs {
  2.    notification_email {
  3.      admin@webres.wang
  4.    }
  5.    notification_email_from keepalived@domain.com
  6.    smtp_server 127.0.0.1
  7.    smtp_connect_timeout 30
  8.    router_id LVS_DEVEL
  9. }
  10. vrrp_script chk_http_port {
  11.                 script "/opt/nginx_pid.sh"
  12.                 interval 2
  13.                 weight 2
  14. }
  15. vrrp_instance VI_1 {
  16.     state MASTER        ############ 辅机为 BACKUP
  17.     interface eth0
  18.     virtual_router_id 51
  19.     mcast_src_ip 192.168.1.103
  20.     priority 102                  ########### 权值要比 back 高
  21.     advert_int 1
  22.     authentication {
  23.         auth_type PASS
  24.         auth_pass 1111
  25.     }
  26. track_script { 
  27.         chk_http_port ### 执行监控的服务 
  28.         }
  29.     virtual_ipaddress {
  30.        192.168.1.110
  31.     }
  32. }

从服务器:

  1. global_defs {
  2.    notification_email {
  3.      admin@webres.wang
  4.    }
  5.    notification_email_from keepalived@domain.com
  6.    smtp_server 127.0.0.1
  7.    smtp_connect_timeout 30
  8.    router_id LVS_DEVEL
  9. }
  10. vrrp_script chk_http_port {
  11.                 script "/opt/nginx_pid.sh"
  12.                 interval 2
  13.                 weight 2
  14. }
  15. vrrp_instance VI_1 {
  16.     state BACKUP
  17.     interface eth0
  18.     virtual_router_id 51
  19.     mcast_src_ip 192.168.1.101
  20.     priority 101              ##########权值 要比 master 低。。
  21.     advert_int 1
  22.     authentication {
  23.         auth_type PASS
  24.         auth_pass 1111
  25.     }
  26. track_script { 
  27.         chk_http_port ### 执行监控的服务 
  28.         }
  29.     virtual_ipaddress {
  30.        192.168.1.110
  31.     }
  32. }

之后分别在主从服务器建立nginx的监控脚本:

  1. vi /opt/nginx_pid.sh
  1. #!/bin/bash
  2. A=`ps -C nginx –no-header |wc -l`               
  3. if [ $A -eq 0 ];then                                       
  4.                 /usr/local/nginx/sbin/nginx
  5.                 sleep 3
  6.                 if [ `ps -C nginx –no-header |wc -l` -eq 0 ];then
  7.                        killall keepalived
  8.                 fi
  9. fi

然后分别启动主从服务器的keepalived:

  1. service keepalived start

keepalived的测试

我们在主服务器上执行命令ip a,显示如下:

  1. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
  2.     link/ether 00:0c:29:aa:a1:e4 brd ff:ff:ff:ff:ff:ff
  3.     inet 192.168.1.103/24 brd 255.255.255.255 scope global eth0
  4.     inet 192.168.1.110/32 scope global eth0

证明主服务器已经绑定了虚拟ip 192.168.1.110
在从服务器上执行命令ip a,显示如下:

  1. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
  2.     link/ether 00:0c:29:2b:94:3b brd ff:ff:ff:ff:ff:ff
  3.     inet 192.168.1.101/24 brd 255.255.255.255 scope global eth0

显示表明从服务器上没有绑定vip 192.168.1.110,只有本机真实ip192.168.1.101
下面我们停止主服务器的nginx进程,再看看ip绑定情况:
主服务器的情况:

  1. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
  2.     link/ether 00:0c:29:aa:a1:e4 brd ff:ff:ff:ff:ff:ff
  3.     inet 192.168.1.103/24 brd 255.255.255.255 scope global eth0

从服务器的情况:

  1. 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
  2.     link/ether 00:0c:29:2b:94:3b brd ff:ff:ff:ff:ff:ff
  3.     inet 192.168.1.101/24 brd 255.255.255.255 scope global eth0
  4.     inet 192.168.1.110/32 scope global eth0

由此可见vip已经指向了从服务器。
参考:http://www.keepalived.org/pdf/UserGuide.pdf