keepalived是什么 keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障,它可以自动检测集群中服务器的健康状况,比如主从模式时,当主服务器发生故障时,Keepalived会根据服务器的VRRP优先级来选举一个从服务器成为主服务器,实现主从的无缝切换,保证持续的提供服务,并且Keepalived也会及时的通过邮件通知到相关负责人进行维护出现问题的服务器。
keepalived工作原理 keepalived是以VRRP协议为实现基础的,VRRP全称Virtual Router Redundancy Protocol,即虚拟路由冗余协议。 虚拟路由冗余协议,可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面有一个master和多个backup,master上面有一个对外提供服务的vip(该路由器所在局域网内其他机器的默认路由为该vip),master会发组播,当backup收不到vrrp包时就认为master宕掉了,这时就需要根据VRRP的优先级来选举一个backup当master。这样的话就可以保证路由器的高可用了。 keepalived主要有三个模块,分别是core、check和vrrp。core模块为keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。check负责健康检查,包括常见的各种检查方式。vrrp模块是来实现VRRP协议的。
keepalived的配置文件 和Nginx类似,keepalived也只有一个核心的配置文件keepalived.conf,使用Keepalived的各种功能,我们只需要对这个文件进行相关的配置即可。keepalived.conf里面主要包括以下几个配置区域,分别是global_defs、static_ipaddress、static_routes、vrrp_script、vrrp_instance和virtual_server。 下面是配置文件的一张结构图,每个节点都有相应的解析。 global_defs区域 主要是配置故障发生时的通知对象以及机器标识 global_defs { notification_email { ... } smtp_server smtp.163.com smtp_connect_timeout 30 enable_traps router_id host163 } 解析: • notification_email 故障发生时给谁发邮件通知。 • notification_email_from 通知邮件从哪个地址发出。 • smpt_server 通知邮件的smtp地址。 • smtp_connect_timeout 连接smtp服务器的超时时间。 • enable_traps 开启SNMP陷阱(Simple Network Management Protocol)。 • router_id 标识本节点的字条串,通常为hostname,但不一定非得是hostname。故障发生时,邮件通知会用到。
vrrp_script区域
用来做健康检查的,当检查失败时会将vrrp_instance的priority减少相应的值。 vrrp_script chk_http_port { script "</dev/tcp/192.168.22.227/80" interval 1 weight -10 }
vrrp_instance和vrrp_sync_group区域
vrrp_instance用来定义对外提供服务的VIP区域及其相关属性。 vrrp_rsync_group用来定义vrrp_intance组,使得这个组内成员动作一致。 举个例子来说明一下其功能:
两个vrrp_instance同属于一个vrrp_rsync_group,那么其中一个vrrp_instance发生故障切换时,另一个vrrp_instance也会跟着切换(即使这个instance没有发生故障)。 vrrp_sync_group VG_1 { group { inside_network # name of vrrp_instance (below) outside_network # One for each moveable IP. ... } notify_master /path/to_master.sh notify_backup /path/to_backup.sh notify_fault "/path/fault.sh VG_1" notify /path/notify.sh smtp_alert } vrrp_instance VI_1 { state MASTER interface eth0 use_vmac <VMAC_INTERFACE> dont_track_primary track_interface { eth0 eth1 } mcast_src_ip <IPADDR> lvs_sync_daemon_interface eth1 garp_master_delay 10 virtual_router_id 1 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 12345678 } virtual_ipaddress { 10.210.214.253/24 brd 10.210.214.255 dev eth0 192.168.1.11/24 brd 192.168.1.255 dev eth1 } virtual_routes { 172.16.0.0/12 via 10.210.214.1 192.168.1.0/24 via 192.168.1.1 dev eth1 default via 202.102.152.1 } track_script { chk_http_port } nopreempt preempt_delay 300 debug notify_master <STRING>|<QUOTED-STRING> notify_backup <STRING>|<QUOTED-STRING> notify_fault <STRING>|<QUOTED-STRING> notify <STRING>|<QUOTED-STRING> smtp_alert } 解析: • notify_master/backup/fault 分别表示切换为主/备/出错时所执行的脚本。 • notify 表示任何一状态切换时都会调用该脚本,并且该脚本在以上三个脚本执行完成之后进行调用,keepalived会自动传递三个参数($1 = "GROUP"|"INSTANCE",$2 = name of group or instance,$3 = target state of transition(MASTER/BACKUP/FAULT))。 • smtp_alert 表示是否开启邮件通知(用全局区域的邮件设置来发通知)。 • state 可以是MASTER或BACKUP,不过当其他节点keepalived启动时会将priority比较大的节点选举为MASTER,因此该项其实没有实质用途,可以理解为初始值,运行时根据priority的值改变。 • interface 节点固有IP(非VIP)的网卡名称,用来发VRRP包。 • use_vmac 是否使用VRRP的虚拟MAC地址。 • dont_track_primary 忽略VRRP网卡错误。(默认未设置) • track_interface 监控以下网卡,如果任何一个不通就会切换到FALT状态。(可选项) • mcast_src_ip 修改vrrp组播包的源地址,默认源地址为master的IP。(由于是组播,因此即使修改了源地址,该master还是能收到回应的) • lvs_sync_daemon_interface 绑定lvs syncd的网卡。 • garp_master_delay 当切为主状态后多久更新ARP缓存,默认5秒。 • virtual_router_id 取值在0-255之间,用来区分多个instance的VRRP组播。配置为主从的两个节点该值需要相等。 • priority 用来选举master的,要成为master,那么这个选项的值最好高于其他机器50个点,该项取值范围是1-255(在此范围之外会被识别成默认值100) • advert_int 发VRRP包的时间间隔,即多久进行一次master选举(可以认为是健康查检时间间隔)。 • authentication 认证区域,认证类型有PASS和HA(IPSEC),推荐使用PASS(密码只识别前8位),配置主从的话,主从的认证方式和密码要一致 • virtual_ipaddress 即VIP,配置的虚拟ip,主从节点VIP要一致。 • virtual_routes 虚拟路由,当IP漂过来之后需要添加的路由信息。 • virtual_ipaddress_excluded 发送的VRRP包里不包含的IP地址,为减少回应VRRP包的个数。在网卡上绑定的IP地址比较多的时候用。 • track_script 设置健康检查的脚本 • nopreempt 允许一个priority比较低的节点作为master,即使有priority更高的节点启动。 在这有必要细说一下,首先nopreemt必须在state为BACKUP的节点上才生效(因为是BACKUP节点决定是否来成为MASTER的),其次要实现类似于关闭auto failback的功能需要将所有节点的state都设置为BACKUP。使用nopreempt可以避免抢占master的情况,比如一般情况下主节点宕机,从节点会升级为主节点,当主节点恢复后,会抢占成为master,从节点被迫降级。如果网站访问量较大的话,这样难免会出现问题。
virtual_server_group和virtual_server区域
virtual_server_group一般在超大型的LVS中用到,一般LVS用不到这东西,因此不多说。 virtual_server IP Port { delay_loop <INT> lb_algo rr|wrr|lc|wlc|lblc|sh|dh lb_kind NAT|DR|TUN persistence_timeout <INT> persistence_granularity <NETMASK> protocol TCP ha_suspend virtualhost <STRING> alpha omega quorum <INT> hysteresis <INT> quorum_up <STRING>|<QUOTED-STRING> quorum_down <STRING>|<QUOTED-STRING> sorry_server <IPADDR> <PORT> real_server <IPADDR> <PORT> { weight <INT> inhibit_on_failure notify_up <STRING>|<QUOTED-STRING> notify_down <STRING>|<QUOTED-STRING> # HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK HTTP_GET|SSL_GET { url { path <STRING> # Digest computed with genhash digest <STRING> status_code <INT> } connect_port <PORT> connect_timeout <INT> nb_get_retry <INT> delay_before_retry <INT> } } } 解析: • delay_loop 延迟轮询时间(单位秒)。 • lb_algo 后端调试算法(load balancing algorithm)。 • lb_kind LVS调度类型NAT/DR/TUN。 • virtualhost 用来给HTTP_GET和SSL_GET配置请求header的。 • sorry_server 当所有real server宕掉时,sorry server顶替。 • real_server 真正提供服务的服务器。 • weight 权重。 • notify_up/down 当real server宕掉或启动时执行的脚本。 • 健康检查的方式,N多种方式。 • path 请求real serserver上的路径。 • digest/status_code 分别表示用genhash算出的结果和http状态码。 • connect_port 健康检查,如果端口通则认为服务器正常。 • connect_timeout,nb_get_retry,delay_before_retry分别表示超时时长、重试次数,下次重试的时间延迟。
static_ipaddress和static_routes区域
static_ipaddress和static_routes区域配置的是是本节点的IP和路由信息。如果你的机器上已经配置了IP和路由,那么这两个区域可以不用配置。其实,一般情况下你的机器都会有IP地址和路由信息的,因此没必要再在这两个区域配置。 关于Keepalived的原理和基本配置信息就说到这里,这些 理论上的知识了解一下即可,重要的是根据这些配置,自己动手尝试做个demo,实际验证一下这些配置的作用,这样才会认识的深刻。下篇博客会使用Keepalived做个实践:通过Keepalived实现Nginx的高可用。 原理图 开始搭建 一、配置VIP 关于VIP (即虚拟IP)的作用,上篇博客《Keepalived原理篇》已经介绍过了。227 和228服务器需要配置相同的VIP,虚拟IP在某时刻只能属于某一个节点,另一个节点作为备用节点存在。当主节点不可用时,备用节点接管虚拟IP,成为主节点(即虚拟IP漂移至从节点),提供正常服务。这个VIP就像个墙头草,两头跑,谁是主他就为谁服务。配置VIP的博客,上面也有链接哦。 二、安装软件 按照上面的表格,在相应服务器上安装软件,安装过程不再多说了,有问题可以点击上面的博客链接哦。 三、配置Nginx 227服务器上的Nginx配置: user nobody; worker_processes 2; events{ worker_connections 1024; } http{ #设置默认类型为二进制流 default_type application/octet-stream; server_names_hash_bucket_size 128; #指定来自客户端请求头的headerbuffer大小,设置为32KB client_header_buffer_size 32k; #指定客户端请求中较大的消息头的缓存最大数量和大小,这里是4个32KB large_client_header_buffers 4 32k; #上传文件大小 client_max_body_size 356m; #nginx的HttpLog模块指定,指定nginx日志的输出格式,输出格式为access log_format access '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; #access日志存在未知 access_log /usr/local/nginx/logs/access.log access; #开启高效模式文件传输模式,将tcp_nopush和tcp_nodelay两个指另设置为on,用于防止网络阻塞。 sendfile on; tcp_nopush on; tcp_nodelay on; #设置客户端连接保持活动的超时时间 keepalive_timeout 65; server_tokens off; #客户端请求主体读取缓存 client_body_buffer_size 512k; proxy_connect_timeout 5; proxy_send_timeout 60; proxy_read_timeout 5; proxy_buffer_size 16k; proxy_buffers 4 64k; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 128k; #fastcgi_connect_timeout 300; #fastcgi_send_timeout 300; #fastcgi_read_timeout 300; #fastcgi_buffer_timeout 300; #fastcgi_buffers 4 64k; #fastcgi_busy_buffers_size 128k; #fastcgi_temp_file_write_size 128k; #开启gzip gzip on; #允许压缩的最小字节数 gzip_min_length 1k; #4个单位为16k的内存作为压缩结果流缓存 gzip_buffers 4 16k; #设置识别HTTP协议版本,默认是1.1 gzip_http_version 1.1; #gzip压缩比,可在1~9中设置,1压缩比最小,速度最快,9压缩比最大,速度最慢,消耗CPU gzip_comp_level 2; #压缩的类型 gzip_types text/plain application/x-javascript text/css application/xml; #让前端的缓存服务器混村经过的gzip压缩的页面 gzip_vary on; upstream mycluster{ server 192.168.22.229:8080 weight=1; server 192.168.22.230:8080 weight=1; } server{ listen 8088; server_name 192.168.22.227; charset utf-8; #设置编码为utf-8 #root html; #location / { # root html; # index index.html index.htm; #} #location ~ .*\.(jsp|do|action)$ location / { proxy_next_upstream http_502 http_504 error timeout invalid_header; proxy_pass http://mycluster; # 真实的客户端IP proxy_set_header X-Real-IP $remote_addr; # 请求头中Host信息 proxy_set_header Host $host; # 代理路由信息,此处取IP有安全隐患 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 真实的用户访问协议 proxy_set_header X-Forwarded-Proto $scheme; } #静态文件交给nginx处理 location ~ .*\.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$ { root /usr/local/webapps; expires 30d; } #静态文件交给nginx处理 location ~ .*\.(js|css)?$ { root /usr/local/webapps; expires 1h; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 228服务器上的Nginx配置: user nobody; worker_processes 2; events{ worker_connections 1024; } http{ #设置默认类型为二进制流 default_type application/octet-stream; server_names_hash_bucket_size 128; #指定来自客户端请求头的headerbuffer大小,设置为32KB client_header_buffer_size 32k; #指定客户端请求中较大的消息头的缓存最大数量和大小,这里是4个32KB large_client_header_buffers 4 32k; #上传文件大小 client_max_body_size 356m; #nginx的HttpLog模块指定,指定nginx日志的输出格式,输出格式为access log_format access '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; #access日志存在未知 access_log /usr/local/nginx/logs/access.log access; #开启高效模式文件传输模式,将tcp_nopush和tcp_nodelay两个指另设置为on,用于防止网络阻塞。 sendfile on; tcp_nopush on; tcp_nodelay on; #设置客户端连接保持活动的超时时间 keepalive_timeout 65; server_tokens off; #客户端请求主体读取缓存 client_body_buffer_size 512k; proxy_connect_timeout 5; proxy_send_timeout 60; proxy_read_timeout 5; proxy_buffer_size 16k; proxy_buffers 4 64k; proxy_busy_buffers_size 128k; proxy_temp_file_write_size 128k; #fastcgi_connect_timeout 300; #fastcgi_send_timeout 300; #fastcgi_read_timeout 300; #fastcgi_buffer_timeout 300; #fastcgi_buffers 4 64k; #fastcgi_busy_buffers_size 128k; #fastcgi_temp_file_write_size 128k; #开启gzip gzip on; #允许压缩的最小字节数 gzip_min_length 1k; #4个单位为16k的内存作为压缩结果流缓存 gzip_buffers 4 16k; #设置识别HTTP协议版本,默认是1.1 gzip_http_version 1.1; #gzip压缩比,可在1~9中设置,1压缩比最小,速度最快,9压缩比最大,速度最慢,消耗CPU gzip_comp_level 2; #压缩的类型 gzip_types text/plain application/x-javascript text/css application/xml; #让前端的缓存服务器混村经过的gzip压缩的页面 gzip_vary on; upstream mycluster{ server 192.168.22.229:8080 weight=1; server 192.168.22.230:8080 weight=1; } server{ listen 8088; server_name 192.168.22.228; charset utf-8; #设置编码为utf-8 #root html; #location / { # root html; # index index.html index.htm; #} #location ~ .*\.(jsp|do|action)$ location / { proxy_next_upstream http_502 http_504 error timeout invalid_header; proxy_pass http://mycluster; # 真实的客户端IP proxy_set_header X-Real-IP $remote_addr; # 请求头中Host信息 proxy_set_header Host $host; # 代理路由信息,此处取IP有安全隐患 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 真实的用户访问协议 proxy_set_header X-Forwarded-Proto $scheme; } #静态文件交给nginx处理 location ~ .*\.(htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$ { root /usr/local/webapps; expires 30d; } #静态文件交给nginx处理 location ~ .*\.(js|css)?$ { root /usr/local/webapps; expires 1h; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } } 另外还需要在227,228服务器上新建一个目录/usr/local/webapps/drp/img,在img文件夹中存放图片girl.jpg。如果Nginx服务器较多的话,可以使用Rsync做服务端自动同步或者使用NFS、MFS分布式共享存储,避免一个个拷贝文件。 还有,这块Nginx配置是做过一些优化的,比如开启gzip压缩,开启高效文件传输模式,设置缓存,动静分离,负载均衡等,可以直接拿到项目中使用。 四、配置Keepalived 227服务器上的Keepalived配置: ! Configuration File for keepalived #配置邮件相关信息 global_defs { notification_email { } smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL } #配置Nginx健康监测脚本 vrrp_script check_nginx { script "</dev/tcp/127.0.0.1/8088" interval 3 weight -2 } vrrp_instance VI_1 { state MASTER #网卡名称 interface eno16777736 virtual_router_id 151 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } track_script { check_nginx } virtual_ipaddress { 192.168.22.231 } } 228服务器上的Keepalived配置: ! Configuration File for keepalived global_defs { notification_email { } smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL } vrrp_script check_nginx { #script "/opt/chknginx.sh" script "</dev/tcp/127.0.0.1/8088" interval 3 weight -2 } vrrp_instance VI_1 { state MASTER interface eno16777736 virtual_router_id 151 priority 99 advert_int 1 authentication { auth_type PASS auth_pass 1111 } track_script { check_nginx } virtual_ipaddress { 192.168.22.231 } } 特别注意,Nginx健康监测脚本。在本地写一个shell脚本,Keepalived监测不到。不知道为什么,网上的博客都是这么写的。但是在我这里就不行。最后直接在Keepalived配置文件的script标签中写了这段监测的脚本,才得以成功。 vrrp_script chk_http_port { script "</dev/tcp/192.168.22.227/80" interval 1 weight -10 另外,如果你不明白某些配置的意思,可以查看上篇博客,里面针对每条配置文件都做了详细解析。 五、Tomcat配置 229服务器,添加默认页 在Tomcat的webapps目录下新建文件夹drp,并且创建index.jsp页面 <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <HTML> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030"> <title>Nginx+Keepalived高可用,负载均衡,动静分离测试</title> </head> <body> <h1>您正在访问服务器:192.168.22.229</h1> <img src="/drp/img/girl.jpg" alt="女孩" /> </body> </html> 230服务器同上 六、启动服务并测试 分别启动各个服务器上的Nginx、Keepalived、Tomcat,并测试能否正常访问。 ①启动测试Tomcat 可以看到229和230服务器上的Tomcat已经可以正常访问,图片没有加载出来,是因为图片没有在Tomcat服务器上存储,而放在了Nginx上。 ②启动测试Nginx 可以看到227和228上的Nginx启动成功,并且实现了负载均衡和动静分离的效果,图片被成功的加载了出来。 ③ 保证所有服务均可正常访问后,启动Keepalived测试。 192.168.22.231是咱们设置的虚拟ip,在访问网站的时候不在通过Nginx的ip了,而要通过这个vip进行访问。 Keepalived启动后咱们可以通过查看/var/log 下的messages文件(日志文件),查看主从状态。
查看227服务器/var/log/messages: 可以看到227为Master服务器,那么咱们现在通过192.168.22.231访问的就是227上的Nginx。 Nginx高可用测试 现在咱们通过两个方面来测试高可用: ① 服务器层的双机热备,模拟方式为关闭服务器,或者关闭Keepalived。 a. 关闭227Keepalived进程 现在提供服务的是227服务器,使用命令service keepalived stop将227上的Keepalived进程关闭掉之后。 查看227服务器messas日志: 将192.168.22.231这个虚拟ip移除,关闭Keepalived。 查看228服务器messages日志: 228原来为从服务器,当227服务器宕机后,228服务器由从服务器升级为主服务器,并且绑定上192.168.22.231这个虚拟IP,以继续提供服务,网站能够继续访问。
b. 启动227Keepalived 查看227服务器messas日志: Keepalived成功启动后,227服务器继续接管192.168.22.231,成为MASTER服务器,继续提供服务。 查看228服务器messages日志: 相应的228服务器,转变为BACKUP服务器,并且移除VIP。 ② 应用层的双机热备,模拟方式为Kill掉Nginx进程 a. 关闭227Nginx 查看227服务器messages日志: VRRP_Script(check_nginx) failed ,意思是健康监测脚本执行失败,表明Nginx服务坏掉,或者没有启动。然后Keepalived会使227服务器转变为BACKUP状态,移除VIP。 查看228服务器messages日志: 当然不出所料,228服务器已经变为MASTER状态,从而继续提供服务。 b. 重新启动227Nginx 查看227服务器messages日志: VRRP_Script(check_nginx) succeeded ,意思是健康监测脚本执行成功,Nginx正常运行。然后227服务器就会转变为MASTER状态,并提供服务。 228服务器已经变为BUCKUP状态。
|