NIUCLOUD是一款SaaS管理后台框架多应用插件+云编译。上千名开发者、服务商正在积极拥抱开发者生态。欢迎开发者们免费入驻。一起助力发展! 广告
[TOC] # 0. 介绍 ``` Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障。一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备份服务器,当备份服务器收不到这个消息的时候,即主服务器宕机的时候, 备份服务器就会接管虚拟IP,继续提供服务,从而保证了高可用性。Keepalived是VRRP的完美实现。 ``` # 1.实验架构图 ![](https://box.kancloud.cn/f85093a1eae1c025b0a88c5aa3d39ea1_722x540.png) # 2. 服务架构 > 192.168.116.129 mode01 lvs+keepalive > 192.168.116.130 mode02 lvs+keepalive > 192.168.116.131 mode03 haproxy > 192.168.116.132 mode04 haproxy > 192.168.116.133 mode05 nginx web > 192.168.116.134 mode06 nginx web # 3.环境依赖 ``` upsmart@mode01:/etc/apt$ cat /etc/issue Ubuntu 14.04.5 LTS \n \l upsmart@mode01:/etc/apt$ uname -a Linux mode01 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:07:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux sudo apt-get update echo "*/5 * * * * /usr/sbin/ntpdate pool.ntp.org >/dev/null 2>&1" |sudo tee -a /var/spool/cron/crontabs/root ``` # 4.安装lvs+keepalive ``` mode01 mode02 sudo apt-get install ipvsadm keepalived -y 开启转发 sudo sysctl -p net.ipv4.ip_forward = 1 ``` # 5.配置keepalive(主 备) ``` !Configuration File for keepalived global_defs { notification_email { admin@localhost } notification_email_from admin@localhost smtp_server 127.0.0.1 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 101 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.116.135 } } virtual_server 192.168.116.135 80 { delay_loop 6 lb_algo rr lb_kind DR nat_mask 255.255.255.0 persistence_timeout 0 protocol TCP real_server 192.168.116.131 80 { weight 1 HTTP_GET { url { path / status_code 200 #digest ff20ad2481f97b1754ef3e12ecd3a9cc } connect_timeout 2 nb_get_retry 3 delay_before_retry 1 } } real_server 192.168.116.132 80 { weight 1 HTTP_GET { url { path / status_code 200 } connect_timeout 2 nb_get_retry 3 delay_before_retry 1 } } } or real_server 172.16.202.145 { weight 1 TCP_CHECK { connect_timeout 8 nb_get_retry 3 delay_before_retry 3 connect_port 80 ``` # 6.安装nginx,web段。 ``` > 192.168.116.133 mode05 nginx web > 192.168.116.134 mode06 nginx web sudo apt-get install -y nginx sudo apt-get install nginx cd /usr/share/nginx/html echo "this is node01"|sudo tee /usr/share/nginx/html/index.html echo "this is node02"|sudo tee /usr/share/nginx/html/index.html web端执行脚本(vip绑定及arp抑制): cat ipvs_client #!/bin/bash #set -x VIP=192.168.116.135 ##/etc/rc.d/init.d/functions case "$1" in start) echo "start LVS of RealServer IP" for ((i=0;i<`echo ${#VIP[*]}`;i++)) do interface="lo:`echo ${VIP[$i]}|awk -F . '{print $4}'`" /sbin/ifconfig $interface ${VIP[$i]} broadcast ${VIP[$i]} netmask 255.255.255.255 up route add -host ${VIP[$i]} dev $interface done echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce ;; stop) for ((i=0;i<`echo ${#VIP[*]}`;i++)) do interface="lo:`echo ${VIP[$i]}|awk -F . '{print $4}'`" /sbin/ifconfig $interface ${VIP[$i]} broadcast ${VIP[$i]} netmask 255.255.255.255 down route del -host ${VIP[$i]} dev $interface done echo "STOP LVS of RealServer IP" #echo "0" > /proc/sys/net/ipv4/conf/lo/arp_ignore #echo "0" > /proc/sys/net/ipv4/conf/lo/arp_announce #echo "0" > /proc/sys/net/ipv4/conf/all/arp_ignore #echo "0" > /proc/sys/net/ipv4/conf/all/arp_announce ;; *) echo "Usage:$0 {start|stop}" exit 1 esac ``` # 7.如果后端服务器全挂了,提供友好提示 在keepalived.conf最后加入 ``` sorry_server 127.0.0.1 80 本地开启nginx服务用来提示 echo "If you see this page,Website is currently under maintenance, please come back later! "|sudo tee /usr/share/nginx/html/index.html ``` # 8.安装haproxy haproxy1.4.24 ## haproxy原理 > haproxy提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。 haproxy特别适用于那些负载特别大的web站点,这些站点通常又需要会话保持或七层处理。haproxy运行在时下的硬件上,完全可以支持数以万计的并发连接,并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。 haproxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。 事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space)实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以使每个CPU时间片(Cycle)做更多的工作。 ## HAProxy优点: > a.免费开源,稳定性也是非常好,这个可通过我做的一些小项目可以看出来,单Haproxy也跑得不错,稳定性可以与LVS相媲美; >b.根据官方文档,HAProxy可以跑满10Gbps-New benchmark of HAProxy at 10 Gbps using Myricom’s 10GbE NICs (Myri-10G PCI-Express),这个作为软件级负载均衡,也是比较惊人的; >c.HAProxy可以作为MySQL、邮件或其它的非web的负载均衡,我们常用于它作为MySQL(读)负载均衡; >d.自带强大的监控服务器状态的页面,实际环境中我们结合Nagios进行邮件或短信报警,这个也是我非常喜欢它的原因之一; >e.HAProxy支持虚拟主机。 ## HAProxy的balance8种负载均衡算法 1、roundrobin 表示简单的轮询,每个服务器根据权重轮流使用,在服务器的处理时间平均分配的情况下这是最流畅和公平的算法。该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。 2、leastconn 连接数最少的服务器优先接收连接。leastconn建议用于长会话服务,例如LDAP、SQL、TSE等,而不适合短会话协议。如HTTP.该算法是动态的,对于实例启动慢的服务器权重会在运行中调整。 3、static-rr 每个服务器根据权重轮流使用,类似roundrobin,但它是静态的,意味着运行时修改权限是无效的。另外,它对服务器的数量没有限制。 该算法一般不用; 4、source 对请求源IP地址进行哈希,用可用服务器的权重总数除以哈希值,根据结果进行分配。只要服务器正常,同一个客户端IP地址总是访问同一个服务器。如果哈希的结果随可用服务器数量而变化,那么客户端会定向到不同的服务器; 该算法一般用于不能插入cookie的Tcp模式。它还可以用于广域网上为拒绝使用会话cookie的客户端提供最有效的粘连; 该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。 5、uri 表示根据请求的URI左端(问号之前)进行哈希,用可用服务器的权重总数除以哈希值,根据结果进行分配。只要服务器正常,同一个URI地址总是访问同一个服务器。一般用于代理缓存和反病毒代理,以最大限度的提高缓存的命中率。该算法只能用于HTTP后端; 该算法一般用于后端是缓存服务器; 该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。 6、url_param 在HTTP GET请求的查询串中查找<param>中指定的URL参数,基本上可以锁定使用特制的URL到特定的负载均衡器节点的要求; 该算法一般用于将同一个用户的信息发送到同一个后端服务器; 该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。 7、hdr(name) 在每个HTTP请求中查找HTTP头<name>,HTTP头<name>将被看作在每个HTTP请求,并针对特定的节点; 如果缺少头或者头没有任何值,则用roundrobin代替; 该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。 8、rdp-cookie(name) 为每个进来的TCP请求查询并哈希RDP cookie<name>; 该机制用于退化的持久模式,可以使同一个用户或者同一个会话ID总是发送给同一台服务器。如果没有cookie,则使用roundrobin算法代替; 该算法默认是静态的,所以运行时修改服务器的权重是无效的,但是算法会根据“hash-type”的变化做调整。 常用算法:roundrobin、source、lestconn ``` > 192.168.116.131 mode03 haproxy > 192.168.116.132 mode04 haproxy ``` ## 安装haproxy ``` sudo apt-get update sudo apt-get install haproxy 安装haproxy1.6 # apt-get install software-properties-common # add-apt-repository ppa:vbernat/haproxy-1.6 # apt-get update # apt-get install haproxy=1.6.\* ``` ## 配置haproxy ``` sudo vi /etc/security/limits.conf * soft nofile 150000 * hard nofile 180000 sudo vi /etc/default/haproxy ENABLED=1 HAProxy配置中分五大部分: global:全局配置参数,进程级的,用来控制Haproxy启动前的一些进程及系统设置 defaults:配置一些默认的参数,可以被frontend,backend,listen段继承使用 frontend:用来匹配接收客户所请求的域名,uri等,并针对不同的匹配,做不同的请求处理 backend:定义后端服务器集群,以及对后端服务器的一些权重、队列、连接数等选项的设置,我将其理解为Nginx中的upstream块 listen:我将其理解为frontend和backend的组合体 sudo vi /etc/haproxy/haproxy.cfg global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 65535 user haproxy group haproxy nbproc 1 daemon defaults log global mode http option httplog option dontlognull retries 3 option redispatch maxconn 2000 #balance roundrobin #stats uri /haproxy-stats contimeout 5000 clitimeout 50000 srvtimeout 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http listen status bind 0.0.0.0:1080 mode http # option httplog maxconn 10 stats refresh 30s stats uri /haproxy?stats stats realm upsmart test haproxy stats auth admin:admin stats auth Frank:Frank stats hide-version frontend server1 bind *:80 mode http acl test hdr_beg(host) -i 192.168.116.135 use_backend webapp if test # use_backend webapp1 if test default_backend webapp backend webapp mode http option abortonclose cookie SERVERID balance roundrobin option forwardfor header X-REAL-IP option httpchk GET /index.html server webapp_1 192.168.116.131:8080 cookie 1 check inter 2000 rise 3 fall 3 weight 1 server webapp_2 192.168.116.132:8080 cookie 2 check inter 2000 rise 3 fall 3 weight 1 # server webapp_bak 10.12.25.79:80 cookie 3 check inter 1500 rise 3 fall 3 backup ``` ## haproxy相关命令 > 手动启动haproxy命令:sudo haproxy -f /etc/haproxy/haproxy.cfg 手动关闭haproxy命令:sudo killall haproxy 重载haproxy配置:sudo haproxy -f /etc/haproxy/haproxy.cfg -sf 重载haproxy配置(不中断服务):sudo haproxy -f /etc/haproxy/haproxy.cfg -p /var/run/haproxy.pid -sf $(cat /var/run/haproxy.pid) haproxy开机启动:将启动命令添加到文件/etc/rc.local中 参考:https://www.iyunv.com/thread-40056-1-1.html https://www.cnblogs.com/ilanni/p/4750081.html # 9.架构压测分析 压测工具:ab Vegeta ``` ab -n 100 -c 100 http://192.168.116.135/index.html c 100 即:每次并发100 个 n 1000 即: 共发送10000 个请求 ab -t 60 -c 100 http://192.168.0.10/ 在60秒内发请求,一次100个请求。 解释: 测试总次数为1000,并发数为100(相当于100个用户同时访问,他们总共访问1000次)。我们输入命令ab -n 1000 -c 100 ab -n 100 -c 100 http://192.168.116.135/index.html 测试结果: This is ApacheBench, Version 2.3 <$Revision: 1528965 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking 192.168.116.135 (be patient) Completed 1111 requests Completed 2222 requests Completed 3333 requests Completed 4444 requests Completed 5555 requests Completed 6666 requests Completed 7777 requests Completed 8888 requests Completed 9999 requests Completed 11110 requests Finished 11111 requests Server Software: nginx/1.4.6 Server Hostname: 192.168.116.135 Server Port: 80 Document Path: /index.html Document Length: 15 bytes Concurrency Level: 111 #测试的并发数 Time taken for tests: 126.546 seconds #整个测试持续的时间 Complete requests: 11111 #完成的请求数量 Failed requests: 26 #失败的请求数量 (Connect: 0, Receive: 0, Length: 26, Exceptions: 0) Non-2xx responses: 26 Total transferred: 2810043 bytes #整个过程中的网络传输量 HTML transferred: 169083 bytes #整个过程中的HTML内容传输量 Requests per second: 87.80 [#/sec] (mean) #最重要的指标之一,相当于LR中的每秒事务数,后面括号中的mean表示这是一个平均值 Time per request: 1264.204 [ms] (mean) #最重要的指标之二,相当于LR中的平均事务响应时间,后面括号中的mean表示这是一个平均值 Time per request: 11.389 [ms] (mean, across all concurrent requests) #每个连接请求实际运行时间的平均值 Transfer rate: 21.69 [Kbytes/sec] received #平均每秒网络上的流量,可以帮助排除是否存在网络流量过大导致响应时间延长的问题 Connection Times (ms) min mean[+/-sd] median max Connect: 0 28 1212.0 0 63164 Processing: 0 148 1278.5 12 20047 Waiting: 0 148 1278.5 12 20047 Total: 0 177 1908.6 12 83149 Percentage of the requests served within a certain time (ms) 50% 12 66% 16 75% 20 80% 22 90% 31 95% 75 98% 1012 99% 5005 100% 83149 (longest request) #整个场景中所有请求的响应情况。在场景中每个请求都有一个响应时间,其中50%的用户响应时间小于 12毫秒,66%的用户响应时间小于16毫秒,最大的响应时间小于 83149毫秒。对于并发请求,cpu实际上并不是同时处理的,而是按照每个请求获得的时间片逐个轮转处理的,所以基本上第一个Time per request时间约等于第二个Time per request时间乘以并发请求数。 ``` 压测参考:https://www.cnblogs.com/276815076/p/8004039.html ## haproxy一些优化 https://www.linangran.com/?p=547 https://blog.csdn.net/libaineu2004/article/details/79192016 https://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=2653548665&idx=1&sn=c0d489dcacd0c7c05e579ed74c9050c9&scene=21#wechat_redirect ``` sysctl.conf 配置 ### 系统中所允许的文件句柄的最大数目 fs.file-max = 12553500 ### 单个进程所允许的文件句柄的最大数目 fs.nr_open = 12453500 ### 内核允许使用的共享内存大 Controls the maximum number of shared memory segments, in pages kernel.shmall = 4294967296 ###单个共享内存段的最大值 Controls the maximum shared segment size, in bytes kernel.shmmax = 68719476736 ### 内核中消息队列中消息的最大值 Controls the maximum size of a message, in bytes kernel.msgmax = 65536 ### 系统救援工具 kernel.sysrq = 0 ### 在每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到缓存队列的数据包的最大数目 net.core.netdev_max_backlog = 2000000 ### 默认的TCP数据接收窗口大小(字节) net.core.rmem_default = 699040 ### 最大的TCP数据接收窗口(字节) net.core.rmem_max = 50331648 ### 默认的TCP数据发送窗口大小(字节) net.core.wmem_default = 131072 ### 最大的TCP数据发送窗口(字节) net.core.wmem_max = 33554432 ### 定义了系统中每一个端口最大的监听队列的长度,这是个全局的参数 net.core.somaxconn = 65535 ### TCP/UDP协议允许使用的本地端口号 net.ipv4.ip_local_port_range = 15000 65000 net.ipv4.ip_nonlocal_bind = 1 ### 对于本端断开的socket连接,TCP保持在FIN-WAIT-2状态的时间(秒) net.ipv4.tcp_fin_timeout = 7 ### TCP发送keepalive探测消息的间隔时间(秒),用于确认TCP连接是否有效 net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_max_orphans = 3276800 ### 对于还未获得对方确认的连接请求,可保存在队列中的最大数目 net.ipv4.tcp_max_syn_backlog = 655360 net.ipv4.tcp_max_tw_buckets = 6000000 ### 确定TCP栈应该如何反映内存使用,每个值的单位都是内存页(通常是4KB) ### 第一个值是内存使用的下限;第二个值是内存压力模式开始对缓冲区使用应用压力的上限;第三个值是内存使用的上限. net.ipv4.tcp_mem = 94500000 915000000 927000000 ### 为自动调优定义socket使用的内存。 ### 第一个值是为socket接收缓冲区分配的最少字节数; ### 第二个值是默认值(该值会被rmem_default覆盖),缓冲区在系统负载不重的情况下可以增长到这个值; ### 第三个值是接收缓冲区空间的最大字节数(该值会被rmem_max覆盖) net.ipv4.tcp_rmem = 32768 699040 50331648 ### 为自动调优定义socket使用的内存。 ### 第一个值是为socket发送缓冲区分配的最少字节数; ### 第二个值是默认值(该值会被wmem_default覆盖),缓冲区在系统负载不重的情况下可以增长到这个值; ### 第三个值是发送缓冲区空间的最大字节数(该值会被wmem_max覆盖) net.ipv4.tcp_wmem = 32768 131072 33554432 net.ipv4.tcp_slow_start_after_idle = 0 net.ipv4.tcp_synack_retries = 2 ### 表示是否打开TCP同步标签(syncookie),同步标签可以防止一个套接字在有过多试图连接到达时引起过载 ### 内核必须打开了CONFIG_SYN_COOKIES项进行编译, net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_syn_retries = 2 ### 表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭 net.ipv4.tcp_tw_recycle = 1 ### 允许将TIME-WAIT sockets重新用于新的TCP连接,默认为0,表示关闭 net.ipv4.tcp_tw_reuse = 1 ### 启用RFC 1323定义的window scaling,要支持超过64KB的TCP窗口,必须启用该值(1表示启用), ### TCP窗口最大至1GB,TCP连接双方都启用时才生效,默认为1 net.ipv4.tcp_window_scaling = 1 ### 最大限度使用物理内存 vm.swappiness = 0 ```