标签归档:负载均衡器

keepalived 源代码编译安装及配置文件讲解

何为Keepalived?

Keepalived是一个基于vrrp协议来实现的服务器高可用解决方案,可以利用其实现避免IP单点故障,类似的工具还有heartbeat、corosync。不过其不会单独出现,而是搭配着 LVS、Nginx、HAproxy,一起协同工作达到高可用的目的。

何为VRRP协议?

VRRP全称Vritual Router Redundancy Protocol,虚拟路由冗余协议。通过把几台提供路由功能的设备组成一个虚拟路由设备,使用一定的机制保证虚拟路由的高可用,从而达到保持业务的连续性与可靠性。

在配置组成的一个虚拟路由器中,有MASTER和BACKUP之分。MASTER是主节点,在一个虚拟路由器中,只能有一个MASTER,但可以有多个BACKUP,BACKUP是备用节点,也就是当master挂掉之后,BACKUP接管MASTER节点的所有资源,当有多个BACKUP节点时,根据其priority(优先级)的值的大小,来选举谁作为MASTER的替代者。当BACKUP节点的优先级值相同时,根据其IP地址的大小,来决定。

先决条件:

  • 节点之间的时间必须同步。
  • 确保FirewalldSELinux不会成为阻碍。
  • 各节点用于集群服务的网络接口必须支持MULTICAST(多播)通信。采用D类地址(224-239)。多播地址建议手动定义,因为若有多个集群服务都使用默认的,虽有认证机制,但仍会互发信息,可能会影响性能,更会产生无用日志信息。

1.时间同步

请参阅《Centos 7 Chrony 设置服务器集群系统时间同步》。

2.Firewalld防火墙配置

$ firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --in-interface eth0 --destination 224.0.0.111 --protocol vrrp -j ACCEPT
$ firewall-cmd --direct --permanent --add-rule ipv4 filter OUTPUT 0 --out-interface eth0 --destination 224.0.0.111 --protocol vrrp -j ACCEPT
$ firewall-cmd --reload

3.开启路由转发

$ echo "net.ipv4.ip_forward=1" >>/etc/sysctl.conf
$ echo 1 > /proc/sys/net/ipv4/ip_forward

4.安装keepalived

$ cd /tmp
$ wget //www.keepalived.org/software/keepalived-1.3.9.tar.gz
$ tar xvf keepalived-1.3.9.tar.gz
$ cd keepalived-1.3.9
$ ./configure --prefix=/usr/local/keepalived
$ make && make install
$ ln -s /usr/local/keepalived/sbin/keepalived /usr/sbin
$ mkdir /etc/keepalived/
$ ln -s /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/

在安装过程中可能出现以下错误:

可能报错1:

checking for gcc... no
checking for cc... no
checking for cl.exe... no
configure: error: in `/tmp/keepalived-1.3.9':
configure: error: no acceptable C compiler found in $PATH
See `config.log' for more details

解决方案:

$ yum install gcc -y

可能报错2:

configure: error:
!!! OpenSSL is not properly installed on your system. !!!
!!! Can not include OpenSSL headers files.            !!!

解决方案:

$ yum install openssl-devel -y

可能报错3:

*** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.

解决方案:

$ yum install libnl-devel

可能报错4:

checking libnfnetlink/libnfnetlink.h usability... no
checking libnfnetlink/libnfnetlink.h presence... no
checking for libnfnetlink/libnfnetlink.h... no
configure: error: libnfnetlink headers missing

解决方案:

$ yum install libnfnetlink-devel -y

安装总结:

一个最小化安装的Centos 7系统,在源代码编译安装keepalived时,首先安装以下依赖包,再编译安装keepalived就不会出现以上错误了。

安装依赖包:

$ yum install gcc openssl-devel libnl-devel libnfnetlink-devel ipvsadm -y

5.keepalived配置文件讲解

# 全局配置,包含两个子配置块:全局定义和静态地址和路由。

! Configuration File for keepalived
global_defs {               # 全局定义
   notification_email {     # 通知邮件相关设置
    acassen@firewall.loc    # 邮件发送目标地址
   }
   notification_email_from rwl@renwole.com  # 发件人
   smtp_server 127.0.0.1    # 使用本机邮件服务
   smtp_connect_timeout 30  # 设置连接smtp server的超时时间
   router_id LVS_DEVEL      # 标识当前节点唯一,节点间不能相同
   # 检查vrrp报文中的所有地址比较耗时
   # 设置此标志的意思是如果接收的到报文和上一个报文来至同一个路由器,则不执行检查。默认是跳过检查
   vrrp_skip_check_adv_addr
   vrrp_strict              # 严格执行VRRP协议规范,此模式不支持节点单播
   # 小数类型,单位秒。
   # 在一个网卡上每组gratuitous arp消息之间的延迟时间。
   # 默认为0,一个发送的消息=n组 arp报文
   vrrp_garp_interval 0
   # 小数类型,单位秒
   # 在一个网卡上每组na消息之间的延迟时间,默认为0
   vrrp_gna_interval 0
}

# 此区域是VRRP配置,含两个子配置块:vrrp_sync_group/vrrp_instance,主要对外提供服务VIP区域及其相关属性

vrrp_instance VI_1 {     # VRRP实例
    state MASTER         # 只能有一个是MASTER,余下的都应该为BACKUP;
    interface eth1	 # 对外提供网络的接口
    virtual_router_id 65 # 虚拟路由id标识,数字,必须和backup里相同
    priority 100         # 优先级,数字必须比backup大
    advert_int 1         # 组播信息发送间隔,两个节点设置必须一样,秒
    authentication {	 # 设置验证信息,两个节点必须一致(明文)
        auth_type PASS
        auth_pass 1111
    }
	# 虚拟地址,即Floating IP
    virtual_ipaddress {  # 可简写为单个地址,系统会默认计算掩码和设备
	
        172.16.28.65
	# 172.16.28.65/24
        # 172.16.28.65/24 dev eth1
    }
	# 定义通知脚本(另添加)
        notify_master "/usr/local/keepalived/etc/keepalived/notify.sh master"
        notify_backup "/usr/local/keepalived/etc/keepalived/notify.sh backup"
        notify_fault "/usr/local/keepalived/etc/keepalived/notify.sh fault"
}

# 此区域是LVS配置。若用Keepalived+LVS,需要这段配置,若用其他,例如:Keepalived+Nginx,则无需配置。
# LVS包含两个子配置块:virtual_server_group/virtual_server
# virtual_server:虚拟服务器。每个虚拟服务器里面包含多个真实服务器real_server。

virtual_server 172.16.28.65 80 {  # 虚拟IP 监听80端口
    delay_loop 6		  # 健康检查时间间隔,秒
    lb_algo rr		          # 负载调度算法,常见使用wlc或rr
    lb_kind NAT		          # LVS负载转发规则,DR,NAT,TUN等
    persistence_timeout 50        # 会话保持时间,秒
    protocol TCP		  # 转发协议一般有tcp和udp两种

    real_server 172.16.28.65 80 { # 配置真实服务器的地址与端口
        weight 1		  # 权重
        SSL_GET {
            url {
              path /		  # 健康检查的页面
              digest ff20ad2481f97b1754ef3e12ecd3a9cc # 计算出的MD5值
            }
            url {
              path /mrtg/
              digest 9b3a0c85a887a256d6939da88aabd8cd
            }
            connect_timeout 3     # 连接超时时间,秒
            nb_get_retry 3	  # 失败重试次数,超过后移除
            delay_before_retry 3  # 失败重试间隔,秒
        }
    }
}
...

6.启动keepalived

在正确配置完keepalived.conf后,就可以启动keepalived,并且加入开机自启动服务。

$ systemctl start keepalived
$ systemctl enable keepalived

keepalived源码编译安装完毕。

说明:此文章主要介绍何为Keepalived及如何安装keepalived与注解keepalived的配置文件作用,无具体实验或生产配置。

欲了解生产环境中的keepalived各种模式配置,请参阅以下文章:

Keepalived单网络主备单主配置模式(实战)
Keepalived单网络双活双主配置模式
Keepalived双网络(内外网)故障非同步漂移主备单主模式
Keepalived双网络(内外网)故障同步漂移主备单主模式
Keepalived双网络(内外网)故障非同步漂移双活双主模式
Keepalived双网络(内外网)故障同步漂移双活双主模式

Redisson 缓存 Tomcat Redis Session Manager 变量

部署负载均衡时,使用一台Nginx作为前端服务器,多台Tomcat作为后端服务器。Nginx 会根据负载策略把请求分发给Tomcat服务器。默认Tomcat服务器的session(共享会话)是不可跨越服务器的,若是同一个用户的不同请求被分发到不同的Tomcat服务器,就会造成 session 变量丢失,需要用户重新登录。在讲解Redisson之前,我先来分析以下两种方案的Session会话共享。

方案一:Nginx原生 Upstream ip_hash

ip_hash 是根据请求的IP进行分发,对于同一个IP的请求会转发到同一台Tomcat服务器。

1.Nginx 配置如下:《Nginx 1.3 集群负载均衡器 反向代理安装配置优化

 upstream webservertomcat {
 ip_hash;
 server 10.10.204.63:8023 weight=1 max_fails=2 fail_timeout=2;
 server 10.10.204.64:8023 weight=1 max_fails=2 fail_timeout=2;
 #server 127.0.0.1:8080 backup;
 }
 server {
 listen 80;
 server_name www.myname.com myname.com;
 location / {
 proxy_pass //webservertomcat;
 proxy_redirect off;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
 client_max_body_size 10m;
 client_body_buffer_size 128k;
 proxy_connect_timeout 90;
 proxy_send_timeout 90;
 proxy_read_timeout 90;
 proxy_buffer_size 4k;
 proxy_buffers 4 32k;
 proxy_busy_buffers_size 64k;
 proxy_temp_file_write_size 64k;
 add_header Access-Control-Allow-Origin *;
 }
 }

以上配置生产环境不建议使用,原因有二:

1.Nginx可能不是最前端的服务器,如Squid或CDN作为前端缓存,则Nginx实际是拿Squid或CDN服务器的IP地址,达不到根据客户端请求IP分流的效果。
2.有些机构是使用动态虚拟IP或有多个出口IP,用户访问会切换IP,则无法将某个用户的请求固定到同一个Tomcat服务器。

方案二:Nginx_Upstream_jvm_route

Nginx_upstream_jvm_route 是一个第三方 nginx 扩展模块,该模块通过 session cookie 实现 session 会话粘性,如果在cookie和url中并没有session,则这只是个简单的round-robin 负载均衡。

实现方法:用户初次请求分发到后端Server时;会把响应的Server标识添加到名称为JSESSIONID的cookie中,再次请求时;jvm_route看到session中有后端服务器的名称,它就把请求转到对应的服务器上。模块地址://code.google.com/archive/p/nginx-upstream-jvm-route/

1.Nginx配置如下:

 upstream tomcats_jvm_route {
 server 10.10.204.63:8023 srun_id=tomcat1;
 server 10.10.204.64:8023 srun_id=tomcat2;
 jvm_route $cookie_JSESSIONID|sessionid reverse;
 }

2.在多个Tomcat的server.xml添加配置如下:

 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
 <Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat2">

3.配置后,请求的名称为JSESSIONID的cookie末尾会被添加服务器标识,如下:

 JSESSIONID=33775B80D8E0DB5AEAD61F86D6666C45.tomcat2;

4.生产环境不建议使用,原因:

4.1根据tomcat的特性,当server.xml配置文件中加了jvmRoute值后,会给sessionid加上jvmRoute值的后缀,根据这一特性 nginx_upstream_jvm_route对每次访问请求中的sessionId的值自动匹配对应的server。这样就会每次都访问都会到同一个Tomcat Server,这样就解决了访问不同tomcat节点session发生变化的问题。但是这种方式会出现一个问题,当一直被访问的Tomcat服务器宕机后,负载就会将用户分配到其他Server,这样就会造成session发生变化,从而就需要重新登录。

方案三:Tomcat Redis Session Manager

使用 Redis 共享 session,也就是本节中重点讲解的部分。以上两种方案均是将Session存储在Tomcat容器中,当请求从一个Tomcat转发到另一个Tomcat时,Session就会失效,因为Session在各个Tomcat中不能共享。如果使用Redis等缓存数据库系统存储Session,就可以在Tomcat实例之间实现Session共享。

Java框架redisson实现Tomcat会话管理器(Tomcat Session Manager),支持Apache Tomcat 6.x,7.x和8.x。配置方法如下:

1.编辑 TOMCAT_BASE/conf/context.xml 文件节点,添加以下内容:

<Manager className="org.redisson.tomcat.RedissonSessionManager"<Manager className="org.redisson.tomcat.RedissonSessionManager"  configPath="${catalina.base}/redisson-config.json" />

注:configPath – 是指的Redisson的JSON或YAML格式的配置文件路径。配置文件详见这里

2.拷贝相应的***两个***JAR包到指定的TOMCAT_BASE/lib目录下:

适用于 JDK 1.8+

redisson-all-3.5.0.jar

for Tomcat 6.x

redisson-tomcat-6-3.5.0.jar

for Tomcat 7.x

redisson-tomcat-7-3.5.0.jar

for Tomcat 8.x

redisson-tomcat-8-3.5.0.jar

3.按照 [Single instance mode]单实例模式的说明,创建编辑 Json 格式的 redisson-config.json 文件,添加以下内容,并将其上传到TOMCAT_BASE下,重载Tomcat服务即可。

{
 "singleServerConfig":{
 "idleConnectionTimeout":10000,
 "pingTimeout":1000,
 "connectTimeout":10000,
 "timeout":3000,
 "retryAttempts":3,
 "retryInterval":1500,
 "reconnectionTimeout":3000,
 "failedAttempts":3,
 "password":null,
 "subscriptionsPerConnection":5,
 "clientName":null,
 "address": "redis://127.0.0.1:6379",
 "subscriptionConnectionMinimumIdleSize":1,
 "subscriptionConnectionPoolSize":50,
 "connectionMinimumIdleSize":10,
 "connectionPoolSize":64,
 "database":0,
 "dnsMonitoring":false,
 "dnsMonitoringInterval":5000
 },
 "threads":0,
 "nettyThreads":0,
 "codec":null,
 "useLinuxNativeEpoll":false
 }

4.开始测试session。创建session.jsp并添加以下代码,上传到TOMCAT_BASE/webapps/ROOT/下。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>shared session</title>
</head>
<body>
<br>session id=<%=session.getId()%>
</body>
</html>

5.浏览器访问会出现以下会话信息

 session id=1D349A69E8F5A27E1C12DEEFC304F0DC

6.现在查看Redis中是否存储了该值,如果存在会话值,此时你重启Tomcat后,该会话值也不会发生变化。

 # redis-cli
 127.0.0.1:6379> keys *
 1) "redisson_tomcat_session:1D349A69E8F5A27E1C12DEEFC304F0DC"

已经存储成功。

如果是Redis集群或多实例模式,可参阅以下更多资料进行配置:

//github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks#144-tomcat-redis-session-manager
//github.com/redisson/redisson/wiki/2.-Configuration
//github.com/redisson/redisson/wiki/2.-%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95 (中文文档)