注册用户享全站资源 并成为粉丝 不定时福利发放
 
非盈利性学习社区
分享网站

分享网站

让更多人可以获取免费教程

文章分类导航

文章分类导航

精品

合作广告

合作广告

最大优惠

人事面试

人事面试

套路太深

面试过程中,面试官会向应聘者发问,而应聘者的回答将成为面试官考虑是否接受他的重要依据。对应聘者而言,了解这些问题背...

部分企业人事部收到求职者简历后,会预先进行一轮电话面试,来考察求职者的综合素质,因此了解懂得求职面试的基本技巧,将...

1、着装要适当  穿着不一定要名贵,但一定要合体、干净、整洁,而且颜色和图案的搭配一定要协调。鞋子应该是舒服而又引...

一、隐瞒真实个人资料的不诚实者简历是求职的第一步,只有面试官对你的简历有兴趣才会通知你面试。在简历中适当地突出个人...

一、首先你得已经成为公司里“最好”的程序员,或者你已经找不到可作为老师和导师的人关于这一点,很多人都会过度自信,所...

程序人生

程序人生

技术的另一面

2017年初,网上流传华为公司正在清理34岁以上的员工。"中国区开始集中清理34+的交付员工,......去向是跟...

程序员不是你们眼中的程序猿-后IT时代。程序猿是一种非常特殊的、可以从事程序开发、维护的动物。

1.某程序员的QQ签名:为API生,为框架死,为debug奋斗一辈子,吃符号亏,上大小写的当,最后死在需求上2.去...

Web应用,最常见的研发语言是Java和PHP。后端服务,最常见的研发语言是Java和C/C++。大数据,最常见的...

1、第一份工作的选择很重要。不要想着我没有选择的机会,有份工作就不错了,现实情况是进了一行,想出来很难,想转行更难...

程序员段子

程序员段子

乐一乐

皇上太拼了......  被电视剧蒙骗了好多年,三观毁灭!  这是传说中“帅气的王爷”与“美腻的王妃”,像不像屠夫...

足够自信的程序猿自信是通往成功路上的指明灯,自信的程序员更是加班夜里的探照灯,总能让BUG无所遁形。效率高的程序猿...

最近这段时间,小编絮絮叨叨说了很多严肃的东西,今天说点好玩的,轻松一下。娱乐圈有潜规则,小编认为IT圈一样,也有潜...

今天来说说一位女青年的老公以及他们的事儿。如有雷同,纯属巧合。十一年前我和程序猿第一次见面,还是大一军训期间。我甚...

公司高层公司副总A:咱们开个会研究一下这个事情怎么处理。公司副总B:如果老板没有救成功,下任是谁呢?会不会影响公司...

day03.集群部署zookeeper【大数据教程】

发表时间:2018-05-16 18:55


day03.集群部署zookeeper【大数据教程】

一、Nginx/keepalived/lvs的介绍

1. nginx

1.1. nginx简介

Nginx是一个自由、开源、高性能及轻量级的HTTP服务器及反转代理服务器。Nginx以其高性能、稳定、功能丰富、配置简单及占用系统资源少而著称。

Nginx 超越 Apache 的高性能和稳定性,使得国内使用 Nginx 作为 Web 服务器的网站也越来越多.

1.2. 基础功能

反向代理加速,简单的负载均衡和容错;

1.3. 优势

1Nginx专为性能优化而开发,性能是其最重要的考量, 实现上非常注重效率 。有报告表明能支持高达 50,000 个并发连接数。

2Nginx具有很高的稳定性。其它HTTP服务器,当遇到访问的峰值,或者有人恶意发起慢速连接时,也很可能会导致服务器物理内存耗尽频繁交换,失去响应,只能重启服务器。

例如当前apache一旦上到200个以上进程,web响应速度就明显非常缓慢了。而Nginx采取了分阶段资源分配技术,使得它的CPU与内存占用率非常低。

3nginx官方表示保持10,000个没有活动的连接,它只占2.5M内存,就稳定性而言, nginx比其他代理服务器更胜一筹。

4Nginx支持热部署。它的启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够在不间断服务的情况下,对软件版本进行进行升级。

5Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都高很多。

1.4. 安装

见文档

2. keepalived

2.1. 简介

Keepalived的作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除,当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的web服务器。

2.2. 作用

主要用作RealServer的健康状态检查以及LoadBalance主机和BackUP主机之间failover的实现。


3. lvs

3.1. LVS是什么

1LVS的英文全称是Linux Virtual Server,即Linux虚拟服务器。

2、它是我们国家的章文嵩博士的一个开源项目。

3.2. LVS能干什么

1、 LVS主要用于多服务器的负载均衡。

2、 它工作在网络层,可以实现高性能,高可用的服务器集群技术。

3、 它可把许多低性能的服务器组合在一起形成一个超级服务器。

4、 它配置非常简单,且有多种负载均衡的方法。

5、 它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。

6、 可扩展性也非常好。

3.3. nginxlvs作对比的结果:

1nginx工作在网络的应用层,主要做反向代理;lvs工作在网络层,主要做负载均衡。nginx也同样能承受很高负载且稳定,但负载度和稳定度不及lvs。  

2nginx对网络的依赖较小,lvs就比较依赖于网络环境。

3、在使用上,一般最前端所采取的策略应是lvsnginx可作为lvs节点机器使用。

3.4. 负载均衡机制

前面我们说了LVS是工作在网络层。相对于其它负载均衡的解决办法,它的效率是非常高的。LVS的通过控制IP来实现负载均衡。IPVS是其具体的实现模块。IPVS的主要作用:安装在Director Server上面,在Director Server虚拟一个对外访问的IPVIP)。用户访问VIP,到达Director ServerDirector Server根据一定的规则选择一个Real Server,处理完成后然后返回给客户端数据。这些步骤产生了一些具体的问题,比如如何选择具体的Real ServerReal Server如果返回给客户端数据等等。IPVS为此有三种机制:

1. VS/NAT(Virtual Server via Network Address Translation),即网络地址翻转技术实现虚拟服务器。

当请求来到时,Diretor server上处理的程序将数据报文中的目标地址(即虚拟IP地址)改成具体的某台Real Server,端口也改成Real Server的端口,然后把报文发给Real ServerReal Server处理完数据后,需要返回给Diretor Server,然后Diretor server将数据包中的源地址和源端口改成VIP的地址和端口,最后把数据发送出去。由此可以看出,用户的请求和返回都要经过Diretor Server,如果数据过多,Diretor Server肯定会不堪重负。

2. VS/TUNVirtual Server via IP Tunneling,IP隧道技术实现虚拟服务器。

IP隧道(IP tunneling)是将一个IP报文封装在另一个IP报文的技术,这可以使得目标为一个IP地址的数据报文能被封装和转发到另一个IP地址。IP隧道技术亦称为IP封装技术(IP encapsulation)。它跟VS/NAT基本一样,但是Real server是直接返回数据给客户端,不需要经过Diretor server,这大大降低了Diretor server的压力。

3. VS/DRVirtual Server via Direct Routing),即用直接路由技术实现虚拟服务器。

跟前面两种方式,它的报文转发方法有所不同,VS/DR通过改写请求报文的MAC地址,将请求发送到Real Server,而Real Server将响应直接返回给客户,免去了VS/TUN中的IP隧道开销。这种方式是三种负载调度机制中性能最高最好的,但是必须要求Director ServerReal Server都有一块网卡连在同一物理网段上。



二、Nginx/keepalived/lvs安装使用

nginx安装文档

1. 安装依赖包

2. 安装nginx

2.1. 上传

2.2. 解压

2.3. 重命名

2.4. 安装nginx

3. 安装JDK

3.1. 切换到root用户:

3.2. 查看以前是不是安装了openjdk

3.3. 卸载openjdk

(其中参数“tzdata-java-2013g-1.el6.noarch”为上面查看中显示的结果,粘进来就行)

3.4. 安装sunjdk

3.4.1. 上传

3.4.2. 解压

3.4.3. 创建快捷方式

3.4.4. 配置环境变量

3.4.5. 重新编译环境变量

4. 安装tomcat

5. 重新配置nginx

1cd /usr/local/nginx  

2vi /usr/local/nginx/nginx.conf

user  nobody nobody; #定义Nginx运行的用户和用户组

worker_processes  4; #nginx进程数,建议设置为等于CPU总核心数。

error_log  logs/error.log info; #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]

worker_rlimit_nofile 1024; #一个nginx进程打开的最多文件描述符数目,所以建议与ulimit -n的值保持一致。

pid logs/nginx.pid; #进程文件

#工作模式及连接数上限

events {

use epoll;#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型

   worker_connections  1024;#单个进程最大连接数(最大连接数=连接数*进程数)

}

#设定http服务器,利用它的反向代理功能提供负载均衡支持

http {

   include       mime.types;#文件扩展名与文件类型映射表

   default_type  application/octet-stream;#默认文件类型

#设定负载均衡的服务器列表

upstream  tomcatxxxcom  {  

    server   192.168.56.200:8080;  

    server   192.168.56.201:8080;

}

#设定日志格式

   log_format  www_xy_com  '$remote_addr - $remote_user [$time_local] "$request" '

                     '$status $body_bytes_sent "$http_referer" '

                     '"$http_user_agent" "$http_x_forwarded_for"';

 

   sendfile        on;#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off

   keepalive_timeout  65; #长连接超时时间,单位是秒

   #gzip  on;

#设定虚拟主机,默认为监听80端口

   server {

       listen       80;

       server_name  tomcat.xxx.com;#域名可以有多个,用空格隔开

       #charset koi8-r;

#设定本虚拟主机的访问日志

       access_log  /data/logs/access.log  www_xy_com;

#"/" 启用反向代理

  location / {

  proxy_pass        http://tomcatxxxcom;  

              proxy_set_header   Host             $host;  

              proxy_set_header   X-Real-IP        $remote_addr;  

              proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

       }

       

       #error_page   500 502 503 504  /50x.html;

       location = /50x.html {

           root   html;

       }

   }

}

3、创建logs所需要的文件夹/data /logs/

cd /

mkdir –m 755 data

cd data

mkdir –m 755 logs

4、启动tomcatnginx

/usr/local/tomcat/bin/startup.sh

/usr/local/nginx/sbin/nginx

5、修改hosts,加入

192.168.56.99 tomcat.xxx.com

6、访问http:// tomcat.xxx.com

keepalived安装文档


1. 安装依赖

su - root

yum -y install kernel-devel*

yum -y install openssl-*

yum -y install popt-devel

yum -y install lrzsz

yum -y install openssh-clients

2. 安装keepalived

2.1. 上传

1cd /usr/local

2rz –y

3、选择keepalived安装文件

2.2. 解压

tar –zxvf keepalived-1.2.2.tar.gz

2.3. 重命名

mv keepalived-1.2.2 keepalived

2.4. 安装keepalived

1cd keepalived

2、执行命令

./configure --prefix=/usr/local/keepalived -enable-lvs-syncd --enable-lvs --with-kernel-dir=/lib/modules/2.6.32-431.el6.x86_64/build

3、编译

make

4、安装

make install

2.5. 配置服务和加入开机启动

cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/

cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/

mkdir -p /etc/keepalived

cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/

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

chkconfig keepalived on

2.6. 修改配置文件

1、 vi /etc/keepalived/keepalived.conf

2、 详解:

global_defs {

  notification_email {#指定keepalived在发生切换时需要发送email到的对象,一行一个

    #acassen@firewall.loc

    #failover@firewall.loc

    #sysadmin@firewall.loc

  }

  notification_email_from Alexandre.Cassen@firewall.loc#指定发件人

  #smtp_server 192.168.200.1#指定smtp服务器地址

  #smtp_connect_timeout 30 #指定smtp连接超时时间

  router_id LVS_DEVEL#运行keepalived机器的一个标识

}

vrrp_instance VI_1 {

   state BACKUP#指定那个为master,那个为backup

   interface eth1#设置实例绑定的网卡

   virtual_router_id 51#同一实例下virtual_router_id必须相同

   priority 100#定义优先级,数字越大,优先级越高,备机要小于主

advert_int 1#MASTERBACKUP负载均衡器之间同步检查的时间间隔,单位是秒

nopreempt#设置为不抢占,从启动后主不会自动切换回来, 注:这个配置只能设置在backup主机上,而且这个主机优先级要比另外一台高

   

   authentication {#设置认证

       auth_type PASS

       auth_pass 1111

   }

  virtual_ipaddress {#设置vip

       192.168.56.70#虚拟IP

   }

}

virtual_server 192.168.56.70 8080 {

   delay_loop 6#健康检查时间间隔

   lb_algo rr #调度算法rr|wrr|lc|wlc|lblc|sh|dh

   lb_kind DR #负载均衡转发规则NAT|DR|RUN

   #nat_mask 255.255.255.0 #需要验证

   persistence_timeout 1#会话保持时间

   protocol TCP#使用的协议

   real_server 192.168.56.201 8080 {

       weight 10 #默认为1,0为失效

       SSL_GET {

           url { #检查url,可以指定多个

             path /

             digest ff20ad2481f97b1754ef3e12ecd3a9cc #检查后的摘要信息

           }

           url {

             path /mrtg/

             digest 9b3a0c85a887a256d6939da88aabd8cd

           }

           connect_timeout 3#连接超时时间

           nb_get_retry 3#重连次数

           delay_before_retry 3#重连间隔时间

       }

   }

}  

3. 按照上面步骤安装备机器

注意:备的配置文件不相同。

4. 两台机器启动keepalived

service keepalived start

5. 验证

ip a

6. 监控

因为keepalive只能监控机器的死活,所以当软件死掉后,keepalived仍然不会切换;

所以需要写一个脚本,监控软件的死活。

运行wangsf.sh,监控软件


lvs安装文档

1. 安装lvs应用模块

1、安装依赖包:

yum -y install ipvs*

2、验证本机ip_vs模块是否加载

[root@client lvs]# grep -i 'ip_vs' /boot/config-2.6.32-431.el6.x86_64

CONFIG_IP_VS=m

CONFIG_IP_VS_IPV6=y

# CONFIG_IP_VS_DEBUG is not set

CONFIG_IP_VS_TAB_BITS=12

CONFIG_IP_VS_PROTO_TCP=y

CONFIG_IP_VS_PROTO_UDP=y

CONFIG_IP_VS_PROTO_AH_ESP=y

CONFIG_IP_VS_PROTO_ESP=y

CONFIG_IP_VS_PROTO_AH=y

CONFIG_IP_VS_PROTO_SCTP=y

CONFIG_IP_VS_RR=m

CONFIG_IP_VS_WRR=m

CONFIG_IP_VS_LC=m

CONFIG_IP_VS_WLC=m

CONFIG_IP_VS_LBLC=m

CONFIG_IP_VS_LBLCR=m

CONFIG_IP_VS_DH=m

CONFIG_IP_VS_SH=m

CONFIG_IP_VS_SED=m

CONFIG_IP_VS_NQ=m

CONFIG_IP_VS_FTP=m

CONFIG_IP_VS_PE_SIP=m


2. 安装lvs

2.1. 编写lvs drsrever脚本:

2.1.1. 修改functions权限:

functions这个脚本是给/etc/init.d里边的文件使用的(可理解为全局文件)。)

chmod 755 /etc/rc.d/init.d/functions

2.1.2. 创建lvs文件夹

cd /usr/local

mkdir –m 755 lvs

cd /lvs

2.1.3. 编写脚本

vi  lvs_dr.sh

#!/bin/bash

#description:start lvs server

echo "1" >/proc/sys/net/ipv4/ip_forward    #开启ip转发

WEB1=192.168.56.200      #真实的webip

WEB2=192.168.56.201      #真实的webip

VIP1=192.168.56.80      #虚拟lvsip

/etc/rc.d/init.d/functions    #初始化function

case "$1" in        #第一个参数

start)         #第一个参数是start

echo "start LVS of directorServer"    #打印

/sbin/ifconfig eth0:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up  #设置虚拟网络

/sbin/ipvsadm C     #清除内核虚拟服务器表中的所有记录,清除lvs设置

/sbin/ipvsadm -A -t $VIP1:8080 -s rr #设置rr模式,轮询模式

/sbin/ipvsadm -a -t $VIP1:8080 -r $WEB1:8080 –g  #轮询的机器,-g采用DR模式

/sbin/ipvsadm -a -t $VIP1:8080 -r $WEB2:8080 –g

/sbin/ipvsadm        #启动lvs

;;

stop)       #如果第一个参数是stop

echo "close LVS directorserver"  #打印

echo "0" >/proc/sys/net/ipv4/ip_forward #关闭ip转发

/sbin/ipvsadm C     #清除内核虚拟服务器表中的所有记录

/sbin/ipvsadm Z     #虚拟服务表计数器清零(清空当前的连接数量等)

;;

*)        #如果第一个参数是其他任何值

echo "usage:$0 {start|stop}"   #打印:提示输入start或者stop

exit 1       #退出

esac        #循环结束

2.1.4. 执行脚本

chmod 755 lvs_dr.sh

./lvs-dr.sh  start

2.1.5. 查看:

ipvsadm –ln

看到上面信息说明ipvsadm启动成功。

2.2. 编写lvs realserver脚本

2.2.1. web1 web2机器上修改functions权限:

functions这个脚本是给/etc/init.d里边的文件使用的(可理解为全局文件)。)

chmod 755 /etc/rc.d/init.d/functions

2.2.2. 在分别在web1 web2服务器上创建lvs文件夹:

cd /usr/local

mkdir –m 755 lvs

cd lvs

rz –y

2.2.3. 编写监本

vi  lvs-rs.sh

#!/bin/sh

VIP1=192.168.56.80     #虚拟ip

/etc/rc.d/init.d/functions    #初始化function

case "$1" in       #第一个参数

start)        #如果第一个参数是start

echo "start LVS of realserver"    #打印

/sbin/ifconfig lo:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up #设置虚拟网络

echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore  #定义接收到ARP请求时的响应级别

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)        #如果第一个参数是stop

/sbin/ifconfig lo:0 down     #停止网卡

echo "close lvs dirctorserver"    #打印

echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore  #定义接收到ARP请求时的响应级别

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

2.2.4. 启动在web1 web2机器上lvs

chmod 755 lvs-rs.sh

./lvs-rs.sh start

3. 设置dr机器上设置连接超时值()

ipvsadm --set 1 1 1

4. 关闭

./lvs-rs.sh stop

./lvs-dr.sh stop




三、Nginx/keepalived/lvs集群安装


1. 安装tomcat

2. 安装nginx

配置文件和之前的一样

user  nobody nobody; #定义Nginx运行的用户和用户组

worker_processes  4; #nginx进程数,建议设置为等于CPU总核心数。

error_log  logs/error.log info; #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]

worker_rlimit_nofile 1024; #一个nginx进程打开的最多文件描述符数目,所以建议与ulimit -n的值保持一致。

pid logs/nginx.pid; #进程文件

#工作模式及连接数上限

events {

use epoll;#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型

   worker_connections  1024;#单个进程最大连接数(最大连接数=连接数*进程数)

}

#设定http服务器,利用它的反向代理功能提供负载均衡支持

http {

   include       mime.types;#文件扩展名与文件类型映射表

   default_type  application/octet-stream;#默认文件类型

#设定负载均衡的服务器列表

upstream  tomcatxxxcom  {  

    server   192.168.56.200:8080;  

    server   192.168.56.201:8080;

}

#设定日志格式

   log_format  www_xy_com  '$remote_addr - $remote_user [$time_local] "$request" '

                     '$status $body_bytes_sent "$http_referer" '

                     '"$http_user_agent" "$http_x_forwarded_for"';

 

   sendfile        on;#开启高效文件传输模式,sendfile指令指定nginx是否调用sendfile函数来输出文件,对于普通应用设为 on,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度,降低系统的负载。注意:如果图片显示不正常把这个改成off

   keepalive_timeout  65; #长连接超时时间,单位是秒

   #gzip  on;

#设定虚拟主机,默认为监听80端口

   server {

       listen       80;

       server_name  tomcat.xxx.com;#域名可以有多个,用空格隔开

       #charset koi8-r;

#设定本虚拟主机的访问日志

       access_log  /data/logs/access.log  www_xy_com;

#"/" 启用反向代理

  location / {

  proxy_pass        http://tomcatxxxcom;  

              proxy_set_header   Host             $host;  

              proxy_set_header   X-Real-IP        $remote_addr;  

              proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;

       }

       

       #error_page   500 502 503 504  /50x.html;

       location = /50x.html {

           root   html;

       }

   }

}

3. 安装lvs

lvs-dr.sh:和之前对比,变化之处就是vip和转发的端口。

#!/bin/bash

#description:start lvs server

echo "1" >/proc/sys/net/ipv4/ip_forward

WEB1=192.168.56.200

WEB2=192.168.56.201

VIP1=192.168.56.90

/etc/rc.d/init.d/functions

case "$1" in

start)

echo "start LVS of directorServer"

#set the Virtual address and sysctl parameter

/sbin/ifconfig eth1:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up

#clear ipvs table

/sbin/ipvsadm -C

#set LVS

#web apache or tomcat

/sbin/ipvsadm -A -t $VIP1:80 -s rr

/sbin/ipvsadm -a -t $VIP1:80 -r $WEB1:80  -g

/sbin/ipvsadm -a -t $VIP1:80 -r $WEB2:80  -g

#run LVS

/sbin/ipvsadm

;;

stop)

echo "close LVS directorserver"

echo "0" >/proc/sys/net/ipv4/ip_forward

/sbin/ipvsadm -C

/sbin/ipvsadm -Z

;;

*)

echo "usage:$0 {start|stop}"

exit 1

esac

lvs-rs.sh:与之前的不同在于修改了vip

#!/bin/sh

#description start realserver

#chkconfig 235 26 26

VIP1=192.168.56.90

/etc/rc.d/init.d/functions

case "$1" in

start)

echo "start LVS of realserver"

/sbin/ifconfig lo:0 $VIP1 broadcast $VIP1 netmask 255.255.255.255 up

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)

/sbin/ifconfig lo:0 down

echo "close lvs dirctorserver"

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

4. 安装keepalived

注意:在用keepalivedtomcatnginx的热备时,需要加入realserver的配置。但是做lvs的热备则不需要配置realserver,因为keepalivedlvs的配置参数。

backup

! Configuration File for keepalived

global_defs {

  notification_email {

    #acassen@firewall.loc

    #failover@firewall.loc

    #sysadmin@firewall.loc

  }

  notification_email_from Alexandre.Cassen@firewall.loc

  #smtp_server 192.168.200.1

  #smtp_connect_timeout 30

  router_id LVS_DEVEL

}

vrrp_instance VI_1 {

   state BACKUP

   interface eth1

lvs_sync_daemon_inteface eth1

   virtual_router_id 51

   priority 100

nopreempt

   advert_int 1

   authentication {

       auth_type PASS

       auth_pass 1111

   }

   virtual_ipaddress {

       192.168.56.90

   }

}

virtual_server 192.168.56.90 80 {

   delay_loop 6

   lb_algo rr

   lb_kind DR

   #nat_mask 255.255.255.0

   persistence_timeout 1

   protocol TCP

}

master

! Configuration File for keepalived

global_defs {

  notification_email {

    #acassen@firewall.loc

    #failover@firewall.loc

    #sysadmin@firewall.loc

  }

  notification_email_from Alexandre.Cassen@firewall.loc

  #smtp_server 192.168.200.1

  #smtp_connect_timeout 30

  router_id LVS_DEVEL

}

vrrp_instance VI_1 {

   state MASTER

   interface eth1

lvs_sync_daemon_inteface eth1

   virtual_router_id 51

   priority 200

   advert_int 1

   authentication {

       auth_type PASS

       auth_pass 1111

   }

   virtual_ipaddress {

       192.168.56.90

   }

}

virtual_server 192.168.56.90 80 {

   delay_loop 6

   lb_algo rr

   lb_kind DR

   #nat_mask 255.255.255.0

   persistence_timeout 1

   protocol TCP

}


四、Zookeeper

1. Zookeeper概念简介:

Zookeeper是一个分布式协调服务;就是为用户的分布式应用程序提供协调服务

A、zookeeper是为别的分布式程序服务的

B、Zookeeper本身就是一个分布式程序(只要有半数以上节点存活,zk就能正常服务)

C、Zookeeper所提供的服务涵盖:主从协调、服务器节点动态上下线、统一配置管理、分布式共享锁、统一名称服务……

D、虽然说可以提供各种服务,但是zookeeper在底层其实只提供了两个功能:

管理(存储,读取)用户程序提交的数据;

并为用户程序提供数据节点监听服务;

Zookeeper常用应用场景:

Zookeeper集群的角色:  Leader 和  follower  Observer

只要集群中有半数以上节点存活,集群就能提供服务

2. zookeeper集群机制

半数机制:集群中半数以上机器存活,集群可用。

zookeeper适合装在奇数台机器上!!!

3. 安装

3.1. 安装

3.1.1. 机器部署

安装到3台虚拟机上

安装好JDK


3.1.2. 上传

上传用工具。


3.1.3. 解压

su – hadoop(切换到hadoop用户)

tar -zxvf zookeeper-3.4.5.tar.gz(解压)


3.1.4. 重命名

mv zookeeper-3.4.5 zookeeper(重命名文件夹zookeeper-3.4.5zookeeper


3.1.5. 修改环境变量

1su – root(切换用户到root)

2vi /etc/profile(修改文件)

3、添加内容:

export ZOOKEEPER_HOME=/home/hadoop/zookeeper

export PATH=$PATH:$ZOOKEEPER_HOME/bin

4、重新编译文件:

source /etc/profile

5、注意:3zookeeper都需要修改

6、修改完成后切换回hadoop用户:

su - hadoop


3.1.6. 修改配置文件

1、用hadoop用户操作

cd zookeeper/conf

cp zoo_sample.cfg zoo.cfg

2vi zoo.cfg

3、添加内容:

dataDir=/home/hadoop/zookeeper/data

dataLogDir=/home/hadoop/zookeeper/log

server.1=slave1:2888:3888 (主机名, 心跳端口、数据端口)

server.2=slave2:2888:3888

server.3=slave3:2888:3888

4、创建文件夹:

cd /home/hadoop/zookeeper/

mkdir -m 755 data

mkdir -m 755 log

5、在data文件夹下新建myid文件,myid的文件内容为:

cd data

vi myid

添加内容:略


3.1.7. 将集群下发到其他机器上

scp -r /home/hadoop/zookeeper hadoop@slave2:/home/hadoop/

scp -r /home/hadoop/zookeeper hadoop@slave3:/home/hadoop/


3.1.8. 修改其他机器的配置文件

slave2上:修改myid为:2

slave3上:修改myid为:3


3.1.9. 启动(每台机器

zkServer.sh start


3.1.10. 查看集群状态

1、 jps(查看进程)

2、 zkServer.sh status(查看集群状态,主从信息)


4. zookeeper结构和命令

4.1. zookeeper特性

1Zookeeper:一个leader,多个follower组成的集群

2、全局数据一致:每个server保存一份相同的数据副本,client无论连接到哪个server,数据都是一致的

3、分布式读写,更新请求转发,由leader实施

4、更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行

5、数据更新原子性,一次数据更新要么成功,要么失败

6、实时性,在一定时间范围内,client能读到最新数据


4.2. zookeeper数据结构

1、层次化的目录结构,命名符合常规文件系统规范(见下图)

2、每个节点在zookeeper中叫做znode,并且其有一个唯一的路径标识

3、节点Znode可以包含数据和子节点(但是EPHEMERAL类型的节点不能有子节点,下一页详细讲解)

4、客户端应用可以在节点上设置监视器(后续详细讲解)


4.3. 数据结构的图

4.4. 节点类型

1Znode有两种类型:

短暂(ephemeral)(断开连接自己删除)

持久(persistent)(断开连接不删除)

2Znode四种形式的目录节点(默认是persistent

PERSISTENT

PERSISTENT_SEQUENTIAL(持久序列/test0000000019

EPHEMERAL

EPHEMERAL_SEQUENTIAL

3、创建znode时设置顺序标识,znode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护

4、在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序


4.5. zookeeper命令行操作

运行 zkCli.sh server <ip>进入命令行工具

1、使用 ls 命令来查看当前 ZooKeeper 中所包含的内容:

[zk: 202.115.36.251:2181(CONNECTED) 1] ls /

2、创建一个新的 znode ,使用 create /zk myData 。这个命令创建了一个新的 znode 节点“ zk ”以及与它关联的字符串:

[zk: 202.115.36.251:2181(CONNECTED) 2] create /zk "myData“

3、我们运行 get 命令来确认 znode 是否包含我们所创建的字符串:

[zk: 202.115.36.251:2181(CONNECTED) 3] get /zk

#监听这个节点的变化,当另外一个客户端改变/zk,它会打出下面的

#WATCHER::

#WatchedEvent state:SyncConnected type:NodeDataChanged path:/zk

[zk: localhost:2181(CONNECTED) 4] get /zk watch

4、下面我们通过 set 命令来对 zk 所关联的字符串进行设置:

[zk: 202.115.36.251:2181(CONNECTED) 4] set /zk "zsl“

5、下面我们将刚才创建的 znode 删除:

[zk: 202.115.36.251:2181(CONNECTED) 5] delete /zk

6、删除节点:rmr

[zk: 202.115.36.251:2181(CONNECTED) 5] rmr /zk

4.6. zookeeper-api应用

4.6.1. 基本使用

org.apache.zookeeper.Zookeeper是客户端入口主类,负责建立与server的会话

它提供了表 1 所示几类主要方法  

功能

描述

create

在本地目录树中创建一个节点

delete

删除一个节点

exists

测试本地是否存在目标节点

get/set data

从目标节点上读取 / 写数据

get/set ACL

获取 / 设置目标节点访问控制列表信息

get children

检索一个子节点上的列表

sync

等待要被传送的数据

1 ZooKeeper API 描述


4.6.2. demo增删改查

public class SimpleDemo {

// 会话超时时间,设置为与系统默认时间一致

private static final int SESSION_TIMEOUT = 30000;

// 创建 ZooKeeper 实例

ZooKeeper zk;

// 创建 Watcher 实例

Watcher wh = new Watcher() {

public void process(org.apache.zookeeper.WatchedEvent event)

{

System.out.println(event.toString());

}

};

// 初始化 ZooKeeper 实例

private void createZKInstance() throws IOException

{

zk = new ZooKeeper("weekend01:2181", SimpleDemo.SESSION_TIMEOUT, this.wh);

}

private void ZKOperations() throws IOException, InterruptedException, KeeperException

{

System.out.println("/n1. 创建 ZooKeeper 节点 (znode : zoo2, 数据: myData2 ,权限: OPEN_ACL_UNSAFE ,节点类型: Persistent");

zk.create("/zoo2", "myData2".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

System.out.println("/n2. 查看是否创建成功: ");

System.out.println(new String(zk.getData("/zoo2", false, null)));

System.out.println("/n3. 修改节点数据 ");

zk.setData("/zoo2", "shenlan211314".getBytes(), -1);

System.out.println("/n4. 查看是否修改成功: ");

System.out.println(new String(zk.getData("/zoo2", false, null)));

System.out.println("/n5. 删除节点 ");

zk.delete("/zoo2", -1);

System.out.println("/n6. 查看节点是否被删除: ");

System.out.println(" 节点状态: [" + zk.exists("/zoo2", false) + "]");

}

private void ZKClose() throws InterruptedException

{

zk.close();

}

public static void main(String[] args) throws IOException, InterruptedException, KeeperException {

SimpleDemo dm = new SimpleDemo();

dm.createZKInstance();

dm.ZKOperations();

dm.ZKClose();

}

}

Zookeeper的监听器工作机制

监听器是一个接口,我们的代码中可以实现Wather这个接口,实现其中的process方法,方法中即我们自己的业务逻辑

监听器的注册是在获取数据的操作中实现:

getData(path,watch?)监听的事件是:节点数据变化事件

getChildren(path,watch?)监听的事件是:节点下的子节点增减变化事件

4.7. zookeeper应用案例(分布式应用HA||分布式锁)

4.7.1 实现分布式应用的(主节点HA)及客户端动态更新主节点状态

某分布式系统中,主节点可以有多台,可以动态上下线

任意一台客户端都能实时感知到主节点服务器的上下线

A、客户端实现

public class AppClient {

private String groupNode = "sgroup";

private ZooKeeper zk;

private Stat stat = new Stat();

private volatile List<String> serverList;

/**

* 连接zookeeper

*/

public void connectZookeeper() throws Exception {

zk

= new ZooKeeper("localhost:4180,localhost:4181,localhost:4182", 5000, new Watcher() {

public void process(WatchedEvent event) {

// 如果发生了"/sgroup"节点下的子节点变化事件, 更新server列表, 并重新注册监听

if (event.getType() == EventType.NodeChildrenChanged

&& ("/" + groupNode).equals(event.getPath())) {

try {

updateServerList();

} catch (Exception e) {

e.printStackTrace();

}

}

}

});

updateServerList();

}

/**

* 更新server列表

*/

private void updateServerList() throws Exception {

List<String> newServerList = new ArrayList<String>();

// 获取并监听groupNode的子节点变化

// watch参数为true, 表示监听子节点变化事件.

// 每次都需要重新注册监听, 因为一次注册, 只能监听一次事件, 如果还想继续保持监听, 必须重新注册

List<String> subList = zk.getChildren("/" + groupNode, true);

for (String subNode : subList) {

// 获取每个子节点下关联的server地址

byte[] data = zk.getData("/" + groupNode + "/" + subNode, false, stat);

newServerList.add(new String(data, "utf-8"));

}

// 替换server列表

serverList = newServerList;

System.out.println("server list updated: " + serverList);

}

/**

* client的工作逻辑写在这个方法中

* 此处不做任何处理, 只让client sleep

*/

public void handle() throws InterruptedException {

Thread.sleep(Long.MAX_VALUE);

}

public static void main(String[] args) throws Exception {

AppClient ac = new AppClient();

ac.connectZookeeper();

ac.handle();

}

}

B、服务器端实现

public class AppServer {

private String groupNode = "sgroup";

private String subNode = "sub";

/**

* 连接zookeeper

* @param address server的地址

*/

public void connectZookeeper(String address) throws Exception {

ZooKeeper zk = new ZooKeeper(

"localhost:4180,localhost:4181,localhost:4182",

5000, new Watcher() {

public void process(WatchedEvent event) {

// 不做处理

}

});

// 在"/sgroup"下创建子节点

// 子节点的类型设置为EPHEMERAL_SEQUENTIAL, 表明这是一个临时节点, 且在子节点的名称后面加上一串数字后缀

// 将server的地址数据关联到新创建的子节点上

String createdPath = zk.create("/" + groupNode + "/" + subNode, address.getBytes("utf-8"),

Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);

System.out.println("create: " + createdPath);

}


/**

* server的工作逻辑写在这个方法中

* 此处不做任何处理, 只让server sleep

*/

public void handle() throws InterruptedException {

Thread.sleep(Long.MAX_VALUE);

}


public static void main(String[] args) throws Exception {

// 在参数中指定server的地址

if (args.length == 0) {

System.err.println("The first argument must be server address");

System.exit(1);

}


AppServer as = new AppServer();

as.connectZookeeper(args[0]);

as.handle();

}

}

4.7.2分布式共享锁的简单实现

客户端A

public class DistributedClient {

   // 超时时间

   private static final int SESSION_TIMEOUT = 5000;

   // zookeeper server列表

   private String hosts = "localhost:4180,localhost:4181,localhost:4182";

   private String groupNode = "locks";

   private String subNode = "sub";

   private ZooKeeper zk;

   // 当前client创建的子节点

   private String thisPath;

   // 当前client等待的子节点

   private String waitPath;

   private CountDownLatch latch = new CountDownLatch(1);

   /**

    * 连接zookeeper

    */

   public void connectZookeeper() throws Exception {

       zk = new ZooKeeper(hosts, SESSION_TIMEOUT, new Watcher() {

           public void process(WatchedEvent event) {

               try {

                   // 连接建立时, 打开latch, 唤醒wait在该latch上的线程

                   if (event.getState() == KeeperState.SyncConnected) {

                       latch.countDown();

                   }

                   // 发生了waitPath的删除事件

                   if (event.getType() == EventType.NodeDeleted && event.getPath().equals(waitPath)) {

                       doSomething();

                   }

               } catch (Exception e) {

                   e.printStackTrace();

               }

           }

       });

       // 等待连接建立

       latch.await();

       // 创建子节点

       thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

               CreateMode.EPHEMERAL_SEQUENTIAL);

       // wait一小会, 让结果更清晰一些

       Thread.sleep(10);

       // 注意, 没有必要监听"/locks"的子节点的变化情况

       List<String> childrenNodes = zk.getChildren("/" + groupNode, false);

       // 列表中只有一个子节点, 那肯定就是thisPath, 说明client获得锁

       if (childrenNodes.size() == 1) {

           doSomething();

       } else {

           String thisNode = thisPath.substring(("/" + groupNode + "/").length());

           // 排序

           Collections.sort(childrenNodes);

           int index = childrenNodes.indexOf(thisNode);

           if (index == -1) {

               // never happened

           } else if (index == 0) {

               // inddx == 0, 说明thisNode在列表中最小, 当前client获得锁

               doSomething();

           } else {

               // 获得排名比thisPath前1位的节点

               this.waitPath = "/" + groupNode + "/" + childrenNodes.get(index - 1);

               // 在waitPath上注册监听器, 当waitPath被删除时, zookeeper会回调监听器的process方法

               zk.getData(waitPath, true, new Stat());

           }

       }

   }

   private void doSomething() throws Exception {

       try {

           System.out.println("gain lock: " + thisPath);

           Thread.sleep(2000);

           // do something

       } finally {

           System.out.println("finished: " + thisPath);

           // 将thisPath删除, 监听thisPath的client将获得通知

           // 相当于释放锁

           zk.delete(this.thisPath, -1);

       }

   }

   public static void main(String[] args) throws Exception {

       for (int i = 0; i < 10; i++) {

           new Thread() {

               public void run() {

                   try {

                       DistributedClient dl = new DistributedClient();

                       dl.connectZookeeper();

                   } catch (Exception e) {

                       e.printStackTrace();

                   }

               }

           }.start();

       }

       Thread.sleep(Long.MAX_VALUE);

   }

}

分布式多进程模式实现:

public class DistributedClientMy {


// 超时时间

private static final int SESSION_TIMEOUT = 5000;

// zookeeper server列表

private String hosts = "spark01:2181,spark02:2181,spark03:2181";

private String groupNode = "locks";

private String subNode = "sub";

private boolean haveLock = false;

private ZooKeeper zk;

// 当前client创建的子节点

private volatile String thisPath;

/**

* 连接zookeeper

*/

public void connectZookeeper() throws Exception {

zk = new ZooKeeper("spark01:2181", SESSION_TIMEOUT, new Watcher() {

public void process(WatchedEvent event) {

try {

// 子节点发生变化

if (event.getType() == EventType.NodeChildrenChanged && event.getPath().equals("/" + groupNode)) {

// thisPath是否是列表中的最小节点

List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

String thisNode = thisPath.substring(("/" + groupNode + "/").length());

// 排序

Collections.sort(childrenNodes);

if (childrenNodes.indexOf(thisNode) == 0) {

doSomething();

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

});

// 创建子节点

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

// wait一小会, 让结果更清晰一些

Thread.sleep(new Random().nextInt(1000));

// 监听子节点的变化

List<String> childrenNodes = zk.getChildren("/" + groupNode, true);

// 列表中只有一个子节点, 那肯定就是thisPath, 说明client获得锁

if (childrenNodes.size() == 1) {

doSomething();

thisPath = zk.create("/" + groupNode + "/" + subNode, null, Ids.OPEN_ACL_UNSAFE,

CreateMode.EPHEMERAL_SEQUENTIAL);

}

}

/**

* 共享资源的访问逻辑写在这个方法中

*/

private void doSomething() throws Exception {

try {

System.out.println("gain lock: " + thisPath);

Thread.sleep(2000);

// do something

} finally {

System.out.println("finished: " + thisPath);

// 将thisPath删除, 监听thisPath的client将获得通知

// 相当于释放锁

zk.delete(this.thisPath, -1);

}

}

public static void main(String[] args) throws Exception {

DistributedClientMy dl = new DistributedClientMy();

dl.connectZookeeper();

Thread.sleep(Long.MAX_VALUE);

}

}

5. zookeeper原理

Zookeeper虽然在配置文件中并没有指定masterslave

但是,zookeeper工作时,是有一个节点为leader,其他则为follower

Leader是通过内部的选举机制临时产生的

5.1. zookeeper的选举机制(全新集群paxos

以一个简单的例子来说明整个选举的过程.
假设有五台服务器组成的zookeeper集群,它们的id1-5,同时它们都是最新启动的,也就是没有历史数据,在存放数据量这一点上,都是一样的.假设这些服务器依序启动,来看看会发生什么.
1) 服务器1启动,此时只有它一台服务器启动了,它发出去的报没有任何响应,所以它的选举状态一直是LOOKING状态
2) 服务器2启动,它与最开始启动的服务器1进行通信,互相交换自己的选举结果,由于两者都没有历史数据,所以id值较大的服务器2胜出,但是由于没有达到超过半数以上的服务器都同意选举它(这个例子中的半数以上是3),所以服务器1,2还是继续保持LOOKING状态.
3) 服务器3启动,根据前面的理论分析,服务器3成为服务器1,2,3中的老大,而与上面不同的是,此时有三台服务器选举了它,所以它成为了这次选举的leader.
4) 服务器4启动,根据前面的分析,理论上服务器4应该是服务器1,2,3,4中最大的,但是由于前面已经有半数以上的服务器选举了服务器3,所以它只能接收当小弟的命了.
5) 服务器5启动,4一样,当小弟.


5.2. 非全新集群的选举机制(数据恢复)

那么,初始化的时候,是按照上述的说明进行选举的,但是当zookeeper运行了一段时间之后,有机器down掉,重新选举时,选举过程就相对复杂了。

需要加入数据idleader id和逻辑时钟。

数据id:数据新的id就大,数据每次更新都会更新id

Leader id:就是我们配置的myid中的值,每个机器一个。

逻辑时钟:这个值从0开始递增,每次选举对应一个值,也就是说:  如果在同一次选举中,那么这个值应该是一致的 ;  逻辑时钟值越大,说明这一次选举leader的进程更新.

选举的标准就变成:

1、逻辑时钟小的选举结果被忽略,重新投票

2、统一逻辑时钟后,数据id大的胜出

3、数据id相同的情况下,leader id大的胜出

根据这个规则选出leader




Java帮帮公众号生态

Java帮帮公众号生态

总有一款适合你

Java帮帮-微信公众号

Java帮帮-微信公众号

将分享做到极致

Python帮帮-公众号

Python帮帮-公众号

人工智能,爬虫,学习教程

大数据驿站-微信公众号

大数据驿站-微信公众号

一起在数据中成长

九点编程-公众号

九点编程-公众号

深夜九点学编程

程序员服务区-公众号

程序员服务区-公众号

吃喝玩乐,听学吐画

Java帮帮学习群生态

Java帮帮学习群生态

总有一款能帮到你

Java学习群

Java学习群

与大牛一起交流

大数据学习群

大数据学习群

在数据中成长

九点编程学习群

九点编程学习群

深夜九点学编程

python学习群

python学习群

人工智能,爬虫

测试学习群

测试学习群

感受测试的魅力

Java帮帮生态承诺

Java帮帮生态承诺

一直坚守,不负重望

初心
勤俭
诚信
正义
分享
战略合作
关于我们
友链申请
友链交换:加帮主QQ2524138991 留言即可 24小时内答复  
快速换友链:在你的网站设置好Java帮帮-IT免费资源网友链,截图发给帮主即可
会员登录
获取验证码
登录
登录
我的资料
留言
回到顶部