配置keepalived+haproxy+nginx架构
服务架构介绍
- | - | - |
---|
主机名 | IP地址 | 安装服务(角色) | porxy | 192.168.0.10 | 客户端测试访问 | web1 | 192.168.0.20 | nginx | web2 | 192.168.0.21 | nginx | haproxy-0001 | 192.168.0.22 | haproxy,keepalived | haproxy-0002 | 192.168.0.23 | haproxy,keepalived | vip | 192.168.0.100 | keepalived提供的vip |
vip
客户端
keepalived
haproxy
nginx
haproxy介绍
-
haproxy
- HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP(四层)和HTTP七层)的应用程序代理。
- HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。能够补充Nginx的一些缺点比如Session的保持,Cookie的引导;能够支持url检测后端的服务器。单纯从效率上来讲HAProxy比Nginx有更出色的负载均衡速度。
- HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进当前的架构中,同时可以保护web服务器不被暴露到网络上。
- HAProxy实现了一种事件驱动,单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。但可以通过优化每个CPU时间片(Cycle)提高性能。
- HAProxy支持多种负载均衡算法:Round-robin(轮循)、Weight-round-robin(带权轮循)、source(原地址保持)、RI(请求URL)、rdp-cookie(根据cookie)
- HAProxy可以对Mysql进行负载均衡,对后端的DB节点进行检测和负载均衡。
- HAProxy不能做Web服务器即Cache。
keepalived介绍
-
keepalived
- Keepalived顾名思义,保持存活,在网络里面就是保持在线了,也就是所谓的高可用或热备,用来防止单点故障(单点故障是指一旦某一点出现故障就会导致整个系统架构的不可用)的发生。
- Keepalived起初是为LVS设计的,专门用来监控集群系统中各个服务节点的状态,它根据TCP/IP参考模型的第三、第四层、第五层交换机制检测每个服务节点的状态,如果某个服务器节点出现异常,或者工作出现故障,Keepalived将检测到,并将出现的故障的服务器节点从集群系统中剔除,这些工作全部是自动完成的,不需要人工干涉,需要人工完成的只是修复出现故障的服务节点。
- 后来Keepalived又加入了VRRP的功能,VRRP(Vritrual Router Redundancy Protocol,虚拟路由冗余协议)出现的目的是解决静态路由出现的单点故障问题,通过VRRP可以实现网络不间断稳定运行,因此Keepalvied 一方面具有服务器状态检测和故障隔离功能,另外一方面也有HA cluster功能。
- 虚拟路由器由多个VRRP路由器组成,每个VRRP路由器都有各自的IP和共同的VRID(0-255),其中一个VRRP路由器通过竞选成为MASTER,占有VIP,对外提供路由服务,其他成为BACKUP,MASTER以IP组播(组播地址:224.0.0.18)形式发送VRRP协议包,与BACKUP保持心跳连接,若MASTER不可用(或BACKUP接收不到VRRP协议包),则BACKUP通过竞选产生新的MASTER并继续对外提供路由服务,从而实现高可用。
- Keepalived检查主备节点的健康状态,通过IP漂移,实现主备冗余的服务高可用,服务器集群共享一个虚拟IP,同一时间只有一个服务器占有虚拟IP并对外提供服务,若该服务器不可用,则虚拟IP漂移至另一台服务器并对外提供服务,解决单点故障问题。
配置keepalived+haproxy+nginx架构
安装nginx,配置网站服务
配置web1
安装nginx
[root@web1 ~]
[root@web1 ~]
[root@web1 ~]
[root@web1 ~]
[root@web1 ~]
[root@web1 nginx-1.17.6]
[root@web1 nginx-1.17.6]
[root@web1 nginx-1.17.6]
conf html logs sbin
[root@web1 nginx-1.17.6]
[root@web1 nginx]
65 location ~ \.php$ {
66 root html;
67 fastcgi_pass 127.0.0.1:9000;
68 fastcgi_index index.php;
69
70 include fastcgi.conf;
71 }
配置网站
[root@web1 nginx]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@web1 nginx]
<pre>
<?PHP
//phpinfo();
//$arr = array("id" => random_int(0000,9999));
foreach (array("REMOTE_ADDR", "REQUEST_METHOD", "HTTP_USER_AGENT", "REQUEST_URI") as $i) {
$arr[$i] = $_SERVER[$i];
}
if($_SERVER['REQUEST_METHOD']=="POST"){
$arr += $_POST;
}else{
$arr += $_GET;
}
print_R($arr);
print_R("php_host: \t".gethostname()."\n");
$n = 0;
$start = 1;
$end = isset($_GET["id"])? $_GET["id"] : 10000 ;
for($num = $start; $num <= $end; $num++) {
if ( $num == 1 ) continue;
for ($i = 2; $i <= sqrt($num); $i++) {
if ($num % $i == 0) continue 2;
}
$n++;
}
print_R($n."\n");
?>
安装php
yum -y install php
yum -y install php-fpm
启动服务
[root@web1 nginx]
[root@web1 nginx]
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@web1 nginx]
[root@web1 nginx]
tcp LISTEN 0 511 *:80 *:* users:(("nginx",pid=16056,fd=6),("nginx",pid=16055,fd=6))
[root@web1 nginx]
tcp LISTEN 0 128 127.0.0.1:9000 *:* users:(("php-fpm",pid=16052,fd=0),("php-fpm",pid=16051,fd=0),("php-fpm",pid=16050,fd=0),("php-fpm",pid=16049,fd=0),("php-fpm",pid=16048,fd=0),("php-fpm",pid=16047,fd=6))
[root@web1 ~]
配置nginx开机自启
把nginx加入系统服务,使用systemctl控制(笔者采用此种方法)
[root@web1 ~]
[Unit]
Description=The Nginx HTTP Server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT ${MAINPID}
[Install]
WantedBy=multi-user.target
[root@web1 ~]
[root@web1 ~]
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
[root@web1 ~]
tcp LISTEN 0 511 *:80 *:* users:(("nginx",pid=1748,fd=6),("nginx",pid=1747,fd=6))
把nginx启动命令写入开机启动脚本
echo "/usr/local/nginx/sbin/nginx" >> /etc/rc.local
本机访问查看
[root@web1 nginx]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@web1 nginx]
<pre>
Array
(
[REMOTE_ADDR] => 127.0.0.1
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
配置web2
安装nginx同web1
[root@web2 ~]
[root@web2 ~]
[root@web2 ~]
[root@web2 ~]
[root@web2 ~]
[root@web2 nginx-1.17.6]
[root@web2 nginx-1.17.6]
[root@web2 nginx-1.17.6]
[root@web2 nginx]
65 location ~ \.php$ {
66 root html;
67 fastcgi_pass 127.0.0.1:9000;
68 fastcgi_index index.php;
69
70 include fastcgi.conf;
71 }
配置网站
[root@web2 nginx]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@web2 nginx]
<pre>
<?PHP
//phpinfo();
//$arr = array("id" => random_int(0000,9999));
foreach (array("REMOTE_ADDR", "REQUEST_METHOD", "HTTP_USER_AGENT", "REQUEST_URI") as $i) {
$arr[$i] = $_SERVER[$i];
}
if($_SERVER['REQUEST_METHOD']=="POST"){
$arr += $_POST;
}else{
$arr += $_GET;
}
print_R($arr);
print_R("php_host: \t".gethostname()."\n");
$n = 0;
$start = 1;
$end = isset($_GET["id"])? $_GET["id"] : 10000 ;
for($num = $start; $num <= $end; $num++) {
if ( $num == 1 ) continue;
for ($i = 2; $i <= sqrt($num); $i++) {
if ($num % $i == 0) continue 2;
}
$n++;
}
print_R($n."\n");
?>
安装php
yum -y install php
yum -y install php-fpm
启动服务
[root@web2 nginx]
[root@web2 nginx]
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@web2 nginx]
[root@web2 nginx]
udp UNCONN 0 0 *:68 *:* users:(("dhclient",pid=580,fd=6))
tcp LISTEN 0 511 *:80 *:* users:(("nginx",pid=13691,fd=6),("nginx",pid=13690,fd=6))
[root@web2 nginx]
tcp LISTEN 0 128 127.0.0.1:9000 *:* users:(("php-fpm",pid=13687,fd=0),("php-fpm",pid=13686,fd=0),("php-fpm",pid=13685,fd=0),("php-fpm",pid=13684,fd=0),("php-fpm",pid=13683,fd=0),("php-fpm",pid=13682,fd=6))
[root@web2 ~]
配置nginx开机自启
把nginx加入系统服务,使用systemctl控制(笔者采用此种方法)
[root@web2 ~]
[Unit]
Description=The Nginx HTTP Server
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx
ExecReload=/usr/local/nginx/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT ${MAINPID}
[Install]
WantedBy=multi-user.target
[root@web2 ~]
[root@web2 ~]
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
[root@webw ~]
tcp LISTEN 0 511 *:80 *:* users:(("nginx",pid=1748,fd=6),("nginx",pid=1747,fd=6))
把nginx启动命令写入开机启动脚本
[root@web2 ~]
本机访问查看
[root@web2 nginx]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@web2 nginx]
<pre>
Array
(
[REMOTE_ADDR] => 127.0.0.1
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
安装haproxy,配置haproxy代理nginx服务
haproxy-0001 haproxy-0002配置相同
安装haproxy
- 一款实现负载均衡的调度器
- 适用于负载特别大的web站点
- HAProxy的工作模式:
- mode http:只适用于web服务
- mode tcp:适用于各种服务
- mode health:仅做健康检查,很少使用
[root@haproxy-0001 ~]
配置haproxy
vim /etc/haproxy/haproxy.cfg
61 listen myweb 0.0.0.0:80
62 balance roundrobin
63 server web1 192.168.0.20 check inter 2000 rise 2 fall 5
64 server web2 192.168.0.21 check inter 2000 rise 2 fall 5
启动服务
systemctl enable haproxy.service --now
ss -utnlp | grep 80
tcp LISTEN 0 1024 *:80 *:* users:(("haproxy",pid=10946,fd=5))
访问测试haproxy-0001
[root@haproxy-0001 ~]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@haproxy-0001 ~]
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
访问测试 haproxy-0002
[root@haproxy-0002 ~]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@haproxy-0002 ~]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@haproxy-0002 ~]
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.23
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.23
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.23
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.23
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.23
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.23
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web1
1229
安装keepalived,配置vip,启动keepalived
配置haproxy-0001
[root@haproxy-0001 ~]
[root@haproxy-0001 ~]
12 router_id haproxy-0001
13 vrrp_iptables
14 vrrp_skip_check_adv_addr
15 vrrp_strict
16 vrrp_garp_interval 0
17 vrrp_gna_interval 0
18 }
19
20 vrrp_instance VI_1 {
21 state MASTER
22 interface eth0
23 virtual_router_id 51
24 priority 100
25 advert_int 1
26 authentication {
27 auth_type PASS
28 auth_pass 1111
29 }
30 virtual_ipaddress {
31 192.168.0.100/24
32 }
33 }
启动 keepalived服务
[root@haproxy-0001 ~]
[root@haproxy-0001 ~]
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
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: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether fa:16:3e:e0:38:4e brd ff:ff:ff:ff:ff:ff
inet 192.168.0.22/24 brd 192.168.0.255 scope global noprefixroute dynamic eth0
valid_lft 84683sec preferred_lft 84683sec
inet 192.168.0.100/24 scope global secondary eth0
valid_lft forever preferred_lft forever
inet6 fe80::f816:3eff:fee0:384e/64 scope link
valid_lft forever preferred_lft forever
配置haproxy-0002
[root@haproxy-0002 ~]
[root@haproxy-0002 ~]
12 router_id haproxy-0002
13 vrrp_iptables
14 vrrp_skip_check_adv_addr
15 vrrp_strict
16 vrrp_garp_interval 0
17 vrrp_gna_interval 0
18 }
19
20 vrrp_instance VI_1 {
21 state BACKUP
22 interface eth0
23 virtual_router_id 51
24 priority 80
25 advert_int 1
26 authentication {
27 auth_type PASS
28 auth_pass 1111
29 }
30 virtual_ipaddress {
31 192.168.0.100/24
32 }
33 }
启动 keepalived服务
[root@haproxy-0002 ~]
访问测试
云主机需要关闭服务器的源目的地址检查,haproxy-0001,haproxy-0002都需要关闭
[root@proxy ~]
<html>
<marquee behavior="alternate">
<font size="12px" color=
</marquee>
</html>
[root@proxy ~]
<pre>
Array
(
[REMOTE_ADDR] => 192.168.0.22
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /test.php
)
php_host: web2
1229
为keepalived的vip绑定弹性公网ip
详细步骤请参考https://support.huaweicloud.com/usermanual-vpc/zh-cn_topic_0067802474.html
登录管理控制台。
在管理控制台左上角单击,选择区域和项目。 在系统首页,选择“网络>虚拟私有云”。 进入“我的VPC”页面。
在左侧导航栏,选择“虚拟私有云 > 子网”。
在子网列表中,单击虚拟IP地址所属子网名称,进入子网。
选择“IP地址管理”页签,先申请虚拟IP地址。
申请虚拟IP地址
虚拟IP申请成功后,为虚拟IP绑定实例,可绑定多个实例。
笔者这里申请的为keepalievd设置的虚拟IP192.168.0.100,把虚拟IP绑定给实例haproxy-0001和proxy-0002
给虚拟ip绑定弹性公网IP
选择需要绑定的弹性公网IP地址或弹性云服务器(及网卡)。 笔者把新购买的弹性公网IP绑定到虚拟IP192.168.0.100
绑定完成
说明:
弹性云服务器多网卡时,建议绑定主网卡。
一个弹性云服务器的网卡可以绑定多个虚拟IP。
IPv6的虚拟IP仅支持绑定一个网卡(双栈网卡),如需进行服务器的主备切换,请通过调用API方式。具体请参考配置云服务器高可用的IPv6虚拟IP功能。
为已绑定虚拟IP的弹性云服务器手工配置虚拟IP地址。
访问虚拟IP对应的的弹性公网IP测试
|