CentOS7 安装Keepalived以及基本配置

一、去官方网站下载最新版本的软件包 http://www.keepalived.org/software/keepalived-1.2.22.tar.gz

准备3台服务器,可以使用VMware虚拟机

IP  192.168.1.104  Windows7 用来测试

IP  192.168.1.107  Linux 主机

IP  192.168.1.108  Linux 主机

虚拟IP 192.168.1.220

二、安装

1:加压缩

tar -zxvf keepalived-1.2.2.tar.gz

2:进入到解压完的目录

cd keepalived-1.2.2

3:配置安装位置,在这步之前需要安装 openssl 和 openssl-devel  YUM分别安装 yum install openssl  和 yum install openssl-devel

./configure –prefix=/home/wangpl/mine/soft/keepalived-1.2.2    (/home/wangpl/mine/soft/keepalived-1.2.2路径随便哪里都可以)

成功以后的样子,注意 USE IPVS Framework 一定要先已经装载,否则先安装LVS

LVS的RPM包地址 http://www.linuxvirtualserver.org/software/kernel-2.6/ipvsadm-1.26-1.src.rpm 直接用YUM安装

4:编译与安装
make && make install

5:安装完成后系统会在/home/wangpl/mine/soft/keepalived-1.2.2目录下生成 bin  etc  sbin  share 这 4 个目录。

其中一个模板的配置文件(keepalived.conf)在 /home/wangpl/mine/soft/keepalived-1.2.2/etc/keepalived 这个路径下

创建一个目录,并拷贝配置文件

mkdir -p /etc/keepalived/       keepalived启动时默认去这个路径加载配置文件

cp /home/wangpl/mine/soft/keepalived-1.2.2/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf

6:修改配置文件

默认的配置文件中,使用第三方smtp服务器,但这在现实中几乎没有意义(需要验证的原因),我们将其指定为localhost, 将通知信息的发送交给本地sendmail服务处理。查阅说明文档得知route_id配置是为了标识当前节点,我将其设置为NodeA。当然两个节点的此项设置可相同,也可不相同。

  1. ! Configuration File for keepalived
  2. global_defs {
  3.     notification_email {
  4.      root@localhost
  5.    }
  6.    notification_email_from root@localhost
  7.    smtp_server localhost
  8.    smtp_connect_timeout 30
  9.    router_id  NodeA
  10. }
  11. vrrp_instance VI_1 {
  12.     state MASTER   #指定A节点为主节点 备用节点上设置为BACKUP即可
  13.     interface eth0   #绑定虚拟IP的网络接口  
  14.     virtual_router_id 51  #VRRP组名,两个节点的设置必须一样,以指明各个节点属于同一VRRP
  15.     priority 100   #主节点的优先级(1-254之间),备用节点必须比主节点优先级低
  16.     advert_int 1   #组播信息发送间隔,两个节点设置必须一样
  17.     authentication {   #设置验证信息,两个节点必须一致
  18.         auth_type PASS
  19.         auth_pass 1111
  20.     }
  21.     virtual_ipaddress {   #指定虚拟IP, 两个节点设置必须一样
  22.         192.168.1.220
  23.     }
  24. }

需要注意的是

<span style="color:#ff0000;">interface eth0  这个的网卡名称一定别弄错了,要弄成自己的。可以使用 ip a 命令查看</span>

 

按同样的方法配置节点B并修改配置文件,可将A节点的配置文件复制到B节点,并修改以下几项:
router_id  NodeB

state   BACKUP

priority   99

其它项不必修改。

 

7:启动keepalived

/home/wangpl/mine/soft/keepalived-1.2.2/sbin/keepalived -D

8:查看进程

ps aux | grep keepalived

Keepalived 正常运行时,共启动 3 个进程,其中一个进程是父进程,负责监控其子进程;一个是 vrrp 子进程;另外一个是 checkers 子进程

9:我们可以在查看网卡绑定情况,可以看到虚拟IP已经绑定到网卡上了。

10:测试

在192.168.1.104  Windows7机器上可以 ping 192.168.1.220 ,发现可以通了。也可以在俩台主机上开启tomcat测试。

我们通过ARP -a 命令来查看220的MAC地址,看它现在绑定在哪台服务器上,下图可以看到绑定在了107上,

现在让我们把107关机,再看看效果。发现MAC地址马上绑定在108主机上了。也就是说虚拟IP已经漂到备机上了。

11、在真实环境中,如果出现VIP访问不到的情况,我们可以使用抓包工具来分析数据包,解决问题。

CentOS7 下配置Keepalived为系统服务,开机自动启动

keepalived的安装以及基本配置

1.我的keepalived 安装在 /home/wangpl/mine/soft/keepalived-1.2.2目录下。

  1. cd /home/wangpl/mine/soft/keepalived-1.2.2
  2. ls -l

drwxr-xr-x. 2 root root 20 7月   8 15:10 bin
drwxr-xr-x. 5 root root 50 7月   8 15:10 etc
drwxr-xr-x. 2 root root 23 7月   8 15:10 sbin
drwxr-xr-x. 3 root root 16 7月   8 15:10 share

keepalived启动后默认去这个(/etc/keepalived/keepalived.conf)位置读取配置文件,除非另行制定,需要将安装文件下带的配置文件拷贝过去。

2.创建keepalived.service文件。

vim /lib/systemd/system/keepalived.service
  1. [Unit]
  2. Description=Keepalived
  3. After=syslog.target network.target remote-fs.target nss-lookup.target
  4. [Service]
  5. Type=forking
  6. PIDFile=/var/run/keepalived.pid
  7. ExecStart=/home/wangpl/mine/soft/keepalived-1.2.2/sbin/keepalived -D
  8. ExecReload=/bin/kill -s HUP $MAINPID
  9. ExecStop=/bin/kill -s QUIT $MAINPID
  10. PrivateTmp=true
  11. [Install]
  12. WantedBy=multi-user.target

 

PIDFile=/var/run/keepalived.pid 这个路径是keepalived默认存放pid的位置。
<pre name="code" class="java">ExecStart=/home/wangpl/mine/soft/keepalived-1.2.2/sbin/keepalived  这个是keepalived的启动文件  -D的意思是 输出详细日志

 

3.配置systemctl

1;systemctl daemon-reload  重新加载

2:systemctl enable keepalived.service  设置开机自动启动

3:systemctl disable keepalived.service 取消开机自动启动

4:systemctl start keepalived.service 启动

5:systemctl stop keepalived.service停止

4.查看效果

systemctl status keepalived.service
可以看到keep运行正常,并且已经绑定VIP到网卡en16777736

ip a  命令查看网卡已经绑定了VIP,说明已经成功。

KeepAlived+Redis | 高可用 | 主从复制 | 健康检查 | 故障自动切换

https://blog.csdn.net/nimasike/article/details/52487452

本文讲解如何使用KeepAlived配合健康检查脚本来配置Redis高可用(主从数据同步,故障自动切换)。

PS:在使用前请先安装好KeepAlived Redis等相关软件,需要设置为系统服务,但不要设置成为开机启动。

软件环境

CentOS7  X64   |  Keepalived v1.2.22   |   redis-3.2.0

系统架构图

1:正常情况下VIP绑定到Redis-Master主服务器上(128),由主服务器对外提供服务,Redis-Slave(132)为备用服务器,异步备份主服务器上的数据。
2:当Redis-Master出现故障后,VIP绑定到Redis-Slave服务器上(132),这时通过脚本提升 Redis-Slave 为新的主,对外提供服务。
3:当Redis-Master服务器恢复正常后,通过脚本将它设置备用服务器,同时设置它去新的主服务器(132)上同步数据。
4:只要俩台服务器不同时宕机,即可实现Redis的高可用,故障自动切换功能。
PS:上诉架构仍然存在一些问题,就是当主服务器的缓存内容改变后,此时备份服务器还没来得急更新数据,如果在这时主服务器宕机,那么备份服务器会丢失这部分数据。

命令脚本

1:redis-to-master.sh   当Redis提升为主时执行的脚本。
  1. #!/bin/sh
  2. # redis-to-master.sh
  3. rediscli=“/home/redis/redis-3.2.0/src/redis-cli”
  4. $rediscli slaveof no one
  5. perl -pi -e ‘s/^slaveof.*/slaveof no one/’ /home/redis/redis-3.2.0/redis.conf
  6. echo $(date “+%Y-%m-%d %H:%M:%S”) “the redis is to be the master.” >> /home/redis/redis_rdb/redis-keepalived.log
rediscli=”/home/redis/redis-3.2.0/src/redis-cli”   定义redis客户端的位置。
$rediscli slaveof no one  执行Redis客户端命令,设置不去任何地方同步数据(提升为主)。
perl -pi -e ‘s/^slaveof.*/slaveof no one/’ /home/redis/redis-3.2.0/redis.conf   修改配置文件
echo $(date “+%Y-%m-%d %H:%M:%S”) “the redis is to be the master.” >> /home/redis/redis_rdb/redis-keepalived.log   记录日志。
2:redis-to-slave.sh  当Redis变成备时执行的脚本
  1. #!/bin/sh
  2. # redis-to-slave.sh
  3. rediscli=“/home/redis/redis-3.2.0/src/redis-cli”
  4. PEER_HOST=“192.168.80.132”
  5. PEER_PORT=6379
  6. $rediscli slaveof $PEER_HOST $PEER_PORT
  7. perl -pi -e “s/^slaveof.*/slaveof $PEER_HOST $PEER_PORT/” /home/redis/redis-3.2.0/redis.conf
  8. echo $(date “+%Y-%m-%d %H:%M:%S”) “the redis is to be the slave.” >> /home/redis/redis_rdb/redis-keepalived.log

$rediscli slaveof $PEER_HOST $PEER_PORT   执行Redis客户端命令,设置其去主服务器同步数据(变成备)。

3:redis-check.sh  KeepAlived健康检查脚本。
  1. #!/bin/sh
  2. # redis-check.sh
  3. rediscli=“/home/redis/redis-3.2.0/src/redis-cli”
  4. logfile=“/home/redis/redis_rdb/redis-keepalived.log”
  5. # echo $(date “+%Y-%m-%d %H:%M:%S”) keepaliced checking >> $logfile
  6. for TRIES in `seq 1 3`
  7. do
  8. RESULT=`$rediscli ping`
  9. if [ “${RESULT}” = “PONG” ]; then
  10. exit 0
  11. fi
  12. echo $(date “+%Y-%m-%d %H:%M:%S”) “ping failed ${TRIES}” >> $logfile
  13. sleep 1
  14. done
  15. echo $(date “+%Y-%m-%d %H:%M:%S”) “redis server was down. shutdown keepalived.” >> $logfile
  16. systemctl stop keepalived.service
  17. exit 1

for TRIES in `seq 1 3`  循环3次

RESULT=`$rediscli ping`   执行客户端命令Ping
if [ “${RESULT}” = “PONG” ]; then   exit 0   如果返回正常值,则退出脚本。
否则记录日志,暂停1秒,等3次循环结束则 结束keepalived服务 systemctl stop keepalived.service
PS:当停掉主服务器(128)上的KeepAlived后,VIP会票到备份服务器(132)上面,同时出发脚本提成(132)上面的Redis为主。

KeepAlived配置文件

主服务器配置:
  1. ! Configuration File for keepalived
  2. global_defs {
  3. notification_email {
  4. root@localhost
  5. }
  6. notification_email_from root@localhost
  7. smtp_server localhost
  8. smtp_connect_timeout 30
  9. router_id NodeA
  10. }
  11. vrrp_instance VI_1 {
  12. state BACKUP
  13. interface eno16777736
  14. virtual_router_id 51
  15. priority 100
  16. nopreempt
  17. advert_int 5
  18. authentication {
  19. auth_type PASS
  20. auth_pass 1111
  21. }
  22. virtual_ipaddress {
  23. 192.168.80.120
  24. }
  25. notify_master /home/redis/redis-shell/redis-to-master.sh
  26. notify_backup /home/redis/redis-shell/redis-to-slave.sh
  27. #notify_fault /home/keepshell/notify_fault.sh
  28. #notify_stop /home/keepshell/notify_stop.sh
  29. }
  30. virtual_server 127.0.0.1 16379 {
  31. delay_loop 5
  32. lb_algo rr
  33. real_server 127.0.0.1 6379 {
  34. MISC_CHECK {
  35. misc_path “/home/redis/redis-shell/redis-check.sh”
  36. misc_timeout 30
  37. }
  38. }
  39. }
备服务器配置: 只贴出不同之处。
router_id  NodeB (名字不同)
priority 90   (权重低一些)。
PS: nopreempt:不抢占VIP    state BACKUP(全不都为BACKUP模式)  需要注意无论主备服务器都需要设置为BACKUP,与以往KeepAlived的配置不同,其目的就是防止主服务器恢复后重新抢回VIP,导致Redis切换从而影响稳定。
==========================================================================
notify_master /home/redis/redis-shell/redis-to-master.sh
当KeepAlived提升为主时执行的脚本,设置Redis变成主。
notify_backup /home/redis/redis-shell/redis-to-slave.sh
当KeepAlived变成Backup时执行的脚本,设置Redis变成备,并且去主同步数据。
misc_path “/home/redis/redis-shell/redis-check.sh”
健康检查脚本,默认执行间隔时间5秒,脚本中如果连续3次ping redis失败,则停止KeepAlived服务。

系统测试

1:首先启动主服务器的redis与keepalived

systemctl start redis.service
systemctl status keepalived.service
启动后观察日志: cat /home/redis/redis_rdb/redis-keepalived.log
  1. 20160909 17:20:00 the redis is to be the slave.
  2. 20160909 17:20:19 the redis is to be the master.

可以看到先执行了 notify_backup  这是因为主服务器上的KeepAlived也设置成了BACKUP模式,keep启动后会先成为BACKUP。然后由于只有它自己,所以它接下来会接管VIP,变成Master。然后执行notify_master

这个时候主服务器上的Redis与Keep就正常了,通过客户端插入一些值,怎么插入就不做介绍了
可以看到值已经插入进去了。

2:启动备服务器的Redis与KeepAlived。

systemctl start redis.service
systemctl start keepalived.service
查看日志:cat /home/redis/redis_rdb/redis-keepalived.log
2016-09-09 17:28:11 the redis is to be the slave.

可以看到备服务器启动后KeepAlived执行了 notify_backup  设置redis为备,同时去主服务器同步数据。

3:测试数据同步与客户端连接。

1、可以在主服务器写入数据,然后去备服务器查看数据是否同步,这里就不做截图演示了。
2、写一个客户端去连接VIP上的Redis读取数据。
  1. package com;
  2. import java.util.ArrayList;
  3. import java.util.HashSet;
  4. import java.util.List;
  5. import java.util.Random;
  6. import java.util.Set;
  7. import java.util.concurrent.LinkedBlockingQueue;
  8. import java.util.concurrent.ThreadPoolExecutor;
  9. import java.util.concurrent.TimeUnit;
  10. import redis.clients.jedis.HostAndPort;
  11. import redis.clients.jedis.Jedis;
  12. import redis.clients.jedis.JedisCluster;
  13. import redis.clients.jedis.JedisPool;
  14. import redis.clients.jedis.JedisPoolConfig;
  15. import redis.clients.jedis.JedisShardInfo;
  16. import redis.clients.jedis.ShardedJedis;
  17. import redis.clients.jedis.ShardedJedisPool;
  18. import redis.clients.util.ClusterNodeInformationParser;
  19. public class RedisDemo {
  20. public static void main(String[] args) throws Exception {
  21. JedisPoolConfig cfg = new JedisPoolConfig();
  22. final JedisPool pool = new JedisPool(cfg, “192.168.80.120”, 6379, 8000);
  23. ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 0,
  24. TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
  25. for (int i = 0; i < 1000; i++) {
  26. Jedis jedis = null;
  27. try {
  28. jedis = pool.getResource();
  29. System.out.println(jedis.keys(“*”));
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. } finally {
  33. if (jedis != null) {
  34. jedis.close();
  35. }
  36. }
  37. Thread.sleep(2000);
  38. }
  39. pool.destroy();
  40. }
  41. }

4:模拟服务器异常。

1、首先停掉主服务器上的redis ,查看日志,看到keep也已经被停止了,这时VIP会漂到备机上。
  1. 20160909 17:20:00 the redis is to be the slave.
  2. 20160909 17:20:19 the redis is to be the master.
  3. 20160909 17:34:14 ping failed 1
  4. 20160909 17:34:15 ping failed 2
  5. 20160909 17:34:16 ping failed 3
  6. 20160909 17:34:17 redis server was down. shutdown keepalived.

2、查看备机的日志,看到备机已经提升为主,客户端连接VIP仍然可用。

  1. 20160909 17:28:11 the redis is to be the slave.
  2. 20160909 17:34:23 the redis is to be the master.

3、这时恢复主服务器,重新启动Redis与KeepAlived

systemctl start redis.service
systemctl start keepalived.service
通过客户端 INFO 命令查看状态,可以看到原来的主,现在变成了备份服务器。又变成了新一轮的主备模式。

 

CentOS7.2下unison+inotify的Web目录同步方案

源码包下载地址:

https://github.com/bcpierce00/unison/releases

 

CentOS7.2下unison+inotify的Web目录同步方案

@(学习)[unison]

1. 背景

最近需要上线一个公司展厅项目,项目中主要是后台图片管理。因此它基本不会出现多人同时修改同一图片的情况,这样做双机的情况下,WEB目录最好是双向同步。

在Linux下做WEB目录文件同步,一般有如下几种方式:

  1. nfs实现web数据共享
  2. rsync +inotify实现web数据同步
  3. rsync+sersync更快更节约资源实现web数据同步
  4. unison+inotify实现web数据双向同步

他们各有优缺点,这里我根据实际情况,选择方案4。

2. Unison简介

Alt text

Unison是一款跨平台的文件同步工具,不仅支持本地对本地同步,也支持通过SSH、RSH和Socket等网络协议进行同步。更棒的是,Unison支持双向同步操作,你既可以从A同步到B,也可以从B同步到A,这些都不需要额外的设定。

官方文档:
http://www.seas.upenn.edu/~bcpierce/unison//download/releases/stable/unison-2.48.4-manual.html

3. 环境准备

CentOS7.2 2台:
show160 10.1.0.160
show161 10.1.0.161

4. 安装Objective Caml compiler

Objective Caml compiler (version 3.11.2 or later) 官网地址:http://caml.inria.fr/

cd /tmp
wget http://caml.inria.fr/pub/distrib/ocaml-4.03/ocaml-4.03.0.tar.gz
tar -zxvf ocaml-4.03.0.tar.gz
cd ocaml-4.03.0
./configure
make configure
make world opt
make install
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

5. 安装unison

如果需要同步到远程目录,则远程机器也需要安装unison。

yum -y install ctags-etags  # 缺少此安装包时下面make步骤会报错
cd /tmp
wget http://www.seas.upenn.edu/~bcpierce/unison//download/releases/stable/unison-2.48.4.tar.gz
mkdir unison-2.48.4 && cd unison-2.48.4
tar -zxvf /tmp/unison-2.48.4.tar.gz
cd src
make UISTYLE=text THREADS=true
cp unison /usr/local/bin/
unison -version  # 有版本信息出现,则安装成功
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

6. 安装inotify

inotify官方地址:https://en.wikipedia.org/wiki/Inotify

yum -y install inotify-tools
  • 1

7. 配置双机ssh信任

show160上生成密钥,不输入私钥密码。

[root@show160 src]# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
d6:3b:8a:47:23:04:5d:31:9a:97:d2:d3:5c:1b:f7:a3 root@show160
The key's randomart image is:
+--[ RSA 2048]----+
|     . .+.  o .  |
|    . .+ = . + . |
|     .+ = o .  ..|
|      .o o    . .|
|     .  S .  E   |
|      ..o  .     |
|       o .o      |
|       ... .     |
|      ...        |
+-----------------+
[root@show160 src]# cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys 
[root@show160 src]# chmod 700 ~/.ssh
[root@show160 src]# chmod 600 ~/.ssh/authorized_keys 
[root@show160 src]# rsync -avz /root/.ssh/authorized_keys root@10.1.0.161:/root/.ssh/authorized_keys 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

show161上生成密钥,不输入私钥密码。

[root@show161 tomcat]# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
e8:b4:f7:91:ad:a0:83:fb:00:55:c2:c6:2c:65:08:91 root@show161
The key's randomart image is:
+--[ RSA 2048]----+
|o+ *+ .          |
|E o.=o           |
|   o.            |
|   .   .         |
|  .   o S        |
|   . o .   o     |
|    ..o o o .    |
|    ...o o o     |
|    .oo.  o      |
+-----------------+
[root@show161 tomcat]# cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys 
[root@show161 tomcat]# rsync -avz /root/.ssh/authorized_keys root@10.1.0.160:/root/.ssh/authorized_keys 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在2台机器上分别ssh对方IP,能无密码登录则表示配置成功。

8. unison的使用

unison的用法非常灵活和简单,可以通过如下三种方式调用unison。
第一种方式:”unison profile_name [options]”
unison默认会读取~/.unison目录下的配置文件”profile_name.prf”。

注意,在这种方式下,命令行中并没有指出要进行同步的两个地址,所以,此种调用unison的方式必须在配置文件profile_name.prf中通过相关的root指令设置同步的路径和同步的参数,如:

#Unison preferences file 
root = /tmp/test 
root = ssh://root@10.1.0.161//tmp/test/ 
#force = 
#ignore = 
batch = true 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第二种方式:”unison profile root1 root2 [options]”
root1、root2分别表示要执行同步的两个路径。这两个路径可以是本地目录路径,也可以是远程服务器的路径,如ssh://username@//tmp/test 。由于同步的路径已经在命令行指定了,所以这里无需在profile.prf配置文件中进行root指令的相关设置。

第三种方式:”unison root1 root2 [options]”
这种方式相当于执行”unison default root1 root2”命令,即unison默认读取default.prf的配置。

9. 配置双机web目录同步

[root@show160 src]# mkdir -p /root/.unison/
[root@show160 src]# vim /root/.unison/default.prf
  • 1
  • 2
#Unison preferences file 
root = /data/showroom/
root = ssh://root@10.1.0.161//data/showroom/
#force = 
#ignore = 
batch = true
maxthreads = 300
#repeat = 1 
#retry = 3 
owner = true
group = true
perms = -1
fastcheck = false
rsync = false
sshargs = -C
xferbycopying = true
log = true
logfile = /root/.unison/unison.log
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
[root@show161 tmp]# mkdir -p /root/.unison/
[root@show161 tmp]# vim /root/.unison/default.prf
  • 1
  • 2
#Unison preferences file 
root = /data/showroom/
root = ssh://root@10.1.0.160//data/showroom/
#force = 
#ignore = 
batch = true
maxthreads = 300
#repeat = 1 
#retry = 3 
owner = true
group = true
perms = -1
fastcheck = false
rsync = false
sshargs = -C
xferbycopying = true
log = true
logfile = /root/.unison/unison.log
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

相关注解如下:
force表示会以本地所指定文件夹为标准,将该目录同步到远端。这里需要注意,如果指定了force参数,那么Unison就变成了单项同步了,也就是说会以force指定的文件夹为准进行同步,类似与rsync。
Unison双向同步基本原理是:假如有A B两个文件夹,A文件夹把自己的改动同步到B,B文件夹也把自己的改动同步到A,最后A B两文件夹的内容相同,是AB文件夹的合集。
Unison双向同步的一个缺点是,对于一个文件在两个同步文件夹中都被修改时,unison是不会去同步的,因为unison无法判断以那个为准。
ignore = Path表示忽略指定目录,即同步时不同步它。
batch = true,表示全自动模式,接受缺省动作,并执行。
-fastcheck true 表示同步时仅通过文件的创建时间来比较,如果选项为false,Unison则将比较两地文件的内容。
log = true 表示在终端输出运行信息。
logfile 指定输出的log文件。

另外,Unison有很多参数,这里仅介绍常用的几个,详细的请参看Unison官方手册。
-auto //接受缺省的动作,然后等待用户确认是否执行。
-batch //batch mode, 全自动模式,接受缺省动作,并执行。
-ignore xxx //增加 xxx 到忽略列表中
-ignorecase [true|false|default] //是否忽略文件名大小写
-follow xxx //是否支持对符号连接指向内容的同步
owner = true //保持同步过来的文件属主
group = true //保持同步过来的文件组信息
perms = -1 //保持同步过来的文件读写权限
repeat = 1 //间隔1秒后,开始新的一次同步检查
retry = 3 //失败重试
sshargs = -C //使用ssh的压缩传输方式
xferbycopying = true”
-immutable xxx //不变目录,扫描时可以忽略
-silent //安静模式
-times //同步修改时间
-path xxx 参数 //只同步 -path 参数指定的子目录以及文件,而非整个目录,-path 可以多次出现。

注意:Windows下的unison配置文件默认位于C:\Documents and Settings\currentuser.unison目录,默认的配置文件名是default.prf。

在两台机器都添加如下脚本,并使用nohup方式运行。有需要则将脚本添加到/etc/rc.local中。

#/bin/bash 

src="/data/showroom/"

/usr/bin/inotifywait -mrq -e create,delete,modify,move $src | while read line; do
    /usr/local/bin/unison 
    echo -n "$(date +%F-%T) $line" >> /var/log/inotify.log
done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

10. 总结

经过以上介绍,我们大体知道了unison的使用方法。它的双向同步的确给我们带来了极大的方便,但同时也有一个缺点:对于一个文件在两个同步文件夹中都被修改时,unison是不会去同步的,因为unison无法判断以哪个为准,需要人工干预处理,这就需要我们自己权衡利弊。

在 Shell 脚本中启用语法检查调试模式

在 Shell 脚本中启用语法检查调试模式

回到我们主题的重点,-n 激活语法检查模式。它会让 shell 读取所有的命令,但是不会执行它们,它(shell)只会检查语法。

一旦 shell 脚本中发现有错误,shell 会在终端中输出错误,不然就不会显示任何东西。

激活语法检查的命令如下:

$ bash -n script.sh
  • 1

因为脚本中的语法是正确的,上面的命令不会显示任何东西。所以,让我们尝试删除结束 for 循环的 done 来看下是否会显示错误:

redhat7 配置使用centos的yum源

新安装了redhat7.安装后,登录系统,使用yum update 更新系统。提示:

This system is not registered to Red Hat Subscription Management. You can use subscription-manager to register.

无法更新。

redhat 默认自带的 yum 源需要注册,才能更新。我们想不花钱也可以更新,需要替换掉redhat的yum源。

 

1.检查是否安装yum包

查看RHEL是否安装了yum,若是安装了,那么又有哪些yum包:

[root@syq yum.repos.d]# rpm -qa |grep yum
yum-3.4.3-118.el7.noarch
yum-utils-1.1.31-24.el7.noarch
yum-rhn-plugin-2.0.1-4.el7.noarch
PackageKit-yum-0.8.9-11.el7.x86_64
yum-langpacks-0.4.2-3.el7.noarch
yum-metadata-parser-1.1.4-10.el7.x86_64

2 删除redhat自带的yum包

卸载上面显示的所有yum包:

[root@localhost ~]# rpm -qa|grep yum|xargs rpm -e –nodeps(不检查依赖,直接删除rpm包)

再用

[root@localhost ~]# rpm -qa |grep yum

[root@localhost ~]#

查看,无信息显示表示已经卸载完成。

3.下载新的yum包。使用Centos7的yum包

wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-metadata-parser-1.1.4-10.el7.x86_64.rpm

wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-3.4.3-150.el7.centos.noarch.rpm

wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-plugin-fastestmirror-1.1.31-40.el7.noarch.rpm

wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/yum-utils-1.1.31-40.el7.noarch.rpm

wget https://mirrors.aliyun.com/centos/7/os/x86_64/Packages/python-urlgrabber-3.10-8.el7.noarch.rpm     ( rpm -qa|grep python-urlgrabber|xargs rpm -e –nodeps )

安装yum软件包

注意:单个的安装包可能会依赖其它包(例如yum和yum-fastestmirror会相互依赖),所以我们可以把所有这些包放在一起,用一行命令将它们同时安装即可:

rpm -ivh python-urlgrabber-3.10-8.el7.noarch.rpm

rpm -ivh yum-metadata-parser-1.1.4-10.el7.x86_64.rpm yum-3.4.3-150.el7.centos.noarch.rpm yum-plugin-fastestmirror-1.1.31-40.el7.noarch.rpm

4.更换yum源。使用阿里云的源

第一步:备份你的原镜像文件,以免出错后可以恢复。

mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
第二步:下载新的CentOS-Base.repo 到/etc/yum.repos.d/
CentOS 5
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.repo

CentOS 6
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
CentOS 7
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
更改CentOS-Media.repo使其为不生效:
enabled=0
第三步:修改CentOS-Base.repo文件中的$releasever全部替换为版本号7.

第四步:运行yum makecache生成缓存
yum clean all
yum makecache
yum update

keepalived 问题解决

关闭之后重启无法启动,报错信息如下:

Sep  2 09:54:07 tc_198_80 Keepalived_vrrp: VRRP_Instance(vi_mysql_11) ignoring received advertisment…
Sep  2 09:54:08 tc_198_80 Keepalived_vrrp: receive an invalid passwd!
Sep  2 09:54:08 tc_198_80 Keepalived_vrrp: bogus VRRP packet received on eth1.260 !!!
Sep  2 09:54:08 tc_198_80 Keepalived_vrrp: VRRP_Instance(vi_mysql_11) ignoring received advertisment…
Sep  2 09:54:09 tc_198_80 Keepalived_vrrp: receive an invalid passwd!
Sep  2 09:54:09 tc_198_80 Keepalived_vrrp: bogus VRRP packet received on eth1.260 !!!
Sep  2 09:54:09 tc_198_80 Keepalived_vrrp: VRRP_Instance(vi_mysql_11) ignoring received advertisment…
Sep  2 09:54:10 tc_198_80 Keepalived_vrrp: receive an invalid passwd!
Sep  2 09:54:10 tc_198_80 Keepalived_vrrp: bogus VRRP packet received on eth1.260 !!!
Sep  2 09:54:10 tc_198_80 Keepalived_vrrp: VRRP_Instance(vi_mysql_11) ignoring received advertisment…

解决方案:

改变配置文件/etc/keepalived/keepalived.conf virtual_route_id的值

比如

 virtual_router_id 60 主从方都要改,默认为51

keepalived的一些问题解决

keepalived的一些。。

继续采坑。。有些坑,踩了才知道。

1.文件位置不能错。

首先是安装, 源码编译,–prefix=/usr/local/keepalive

然后用 sbin/keepalive -f  …conf

那就发现根本生成不了vip ,虚拟ip ,因为你的配置文件没有放在 /etc/keepalived/keepalived.conf ,不生效的。。即使你指定了-f 。

解决方案是

$ cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/keepalived
$ cp /usr/local/keepalived/sbin/keepalived /usr/sbin/
$ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
$ mkdir -p /etc/keepalived/
$ cp /usr/local/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf 

或者干脆用yum 安装,centos 里面有包。能省不少麻烦。

2.virtual_router_id

如果猛报错,像这种

VRRP_Instance(VI_1) Dropping received VRRP packet…
Feb 20 23:21:52 localhost Keepalived_vrrp[1125]: ip address associated with VRID not present in received packet : 192.168.51.230
Feb 20 23:21:52 localhost Keepalived_vrrp[1125]: one or more VIP associated with VRID mismatch actual MASTER advert
Feb 20 23:21:52 localhost Keepalived_vrrp[1125]: bogus VRRP packet received on eth0 !!!

说明网段内的机器有keepalive 了。需要修改。

3.weight

好像有好多种设置方法。实践下来,都设置成master ,然后安装优先级来抢占vip 。

vrrp_script chk_http_port {
script “/opt/chk.sh”
interval 2
weight -2
}

 

假设这台机器是优先级比较高的master ,脚本执行失败,也就是返回非0 ,就优先级-2 。然后另外的机器就抢到vip 了。自动切为backup

然后 chk.sh里面可以这样写,比如检测 httpd 进程的

num=`pgrep httpd|wc -l `

if [ $num -eq “0” ] ;

then #没有进程,让脚本返回1

exit 1

else  #有进程,脚本返回0 ,正常

exit 0

fi

里面也可以加上 killall keepalived ,把自己杀了,就不会再切回来。

 

我的配置文件是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
! 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_script chk_http_port {
    script "/opt/chk.sh"
    interval 2
    weight -2    这里是负数。
}
vrrp_instance VI_1 {
    state MASTER 都是master
    interface eth0
    virtual_router_id 52  这个保持一致。
    priority 100   两者不要差太多。
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
#        192.168.200.16
#        192.168.200.17
#        192.168.200.18
    192.168.51.230   vip
    }
track_script {  注意有个空格。中间。
    chk_http_port
}
}

实验起来很简单,就开个httpd ,然后主页改下不同,访问vip ,关httpd ,看keepalived 能不能切到 另一台机器上去。如果能的话,网页会显示会不同。网上文章还不少!

keepalived 问题解决

双主架构中,keepalived日志出现:

more /var/log/message
Oct 9 03:16:22 mysql-dzg-60-148 Keepalived_vrrp[8526]: VRRP_Instance(VI_1) Dropping received VRRP packet…
Oct 9 03:16:23 mysql-dzg-60-148 Keepalived_vrrp[8526]: ip address associated with VRID not present in received packet : 172.28.60.149
Oct 9 03:16:23 mysql-dzg-60-148 Keepalived_vrrp[8526]: one or more VIP associated with VRID mismatch actual MASTER advert
Oct 9 03:16:23 mysql-dzg-60-148 Keepalived_vrrp[8526]: bogus VRRP packet received on bond0 !!!

查看中发现,该平台的Virtual_router_id与其它平台的Virtual_router_id重复。

修改keepalived的 Virtual_router_id值 ,使其唯一,之后重启keepalived:

又出现了两台主库上都有vip的情况,而且通过普通的service keepalived stop,kill pid还不能是VIP消失。

最后通过同时killall掉所有机器上的keepalived之后就好了
出现这个问题的原因应该是mysql主备反复重启诱发keepalived低版本bug

CLOSE_WAIT状态的原因与解决方法

http://blog.csdn.net/lishenglong666/article/details/45335589

说起CLOSE_WAIT状态,如果不知道的话,还是先瞧一下TCP的状态转移图吧。

关闭socket分为主动关闭(Active closure)和被动关闭(Passive closure)两种情况。前者是指有本地主机主动发起的关闭;而后者则是指本地主机检测到远程主机发起关闭之后,作出回应,从而关闭整个连接。将关闭部分的状态转移摘出来,就得到了下图:

TCP 状态变化

产生原因
通过图上,我们来分析,什么情况下,连接处于CLOSE_WAIT状态呢?
在被动关闭连接情况下,在已经接收到FIN,但是还没有发送自己的FIN的时刻,连接处于CLOSE_WAIT状态。
通常来讲,CLOSE_WAIT状态的持续时间应该很短,正如SYN_RCVD状态。但是在一些特殊情况下,就会出现连接长时间处于CLOSE_WAIT状态的情况。

出现大量close_wait的现象,主要原因是某种情况下对方关闭了socket链接,但是我方忙与读或者写,没有关闭连接。代码需要判断socket,一旦读到0,断开连接,read返回负,检查一下errno,如果不是AGAIN,就断开连接。

参考资料4中描述,通过发送SYN-FIN报文来达到产生CLOSE_WAIT状态连接,没有进行具体实验。不过个人认为协议栈会丢弃这种非法报文,感兴趣的同学可以测试一下,然后把结果告诉我;-)

为了更加清楚的说明这个问题,我们写一个测试程序,注意这个测试程序是有缺陷的。
只要我们构造一种情况,使得对方关闭了socket,我们还在read,或者是直接不关闭socket就会构造这样的情况。

server.c:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <netinet/in.h>
  4. #define MAXLINE 80
  5. #define SERV_PORT 8000
  6. int main(void)
  7. {
  8. struct sockaddr_in servaddr, cliaddr;
  9. socklen_t cliaddr_len;
  10. int listenfd, connfd;
  11. char buf[MAXLINE];
  12. char str[INET_ADDRSTRLEN];
  13. int i, n;
  14. listenfd = socket(AF_INET, SOCK_STREAM, 0);
  15. int opt = 1;
  16. setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  17. bzero(&servaddr, sizeof(servaddr));
  18. servaddr.sin_family = AF_INET;
  19. servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  20. servaddr.sin_port = htons(SERV_PORT);
  21. bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  22. listen(listenfd, 20);
  23. printf(“Accepting connections …\n”);
  24. while (1) {
  25. cliaddr_len = sizeof(cliaddr);
  26. connfd = accept(listenfd,
  27. (struct sockaddr *)&cliaddr, &cliaddr_len);
  28. //while (1)
  29. {
  30. n = read(connfd, buf, MAXLINE);
  31. if (n == 0) {
  32. printf(“the other side has been closed.\n”);
  33. break;
  34. }
  35. printf(“received from %s at PORT %d\n”,
  36. inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
  37. ntohs(cliaddr.sin_port));
  38. for (i = 0; i < n; i++)
  39. buf[i] = toupper(buf[i]);
  40. write(connfd, buf, n);
  41. }
  42. //这里故意不关闭socket,或者是在close之前加上一个sleep都可以
  43. //sleep(5);
  44. //close(connfd);
  45. }
  46. }

 

client.c:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/socket.h>
  6. #include <netinet/in.h>
  7. #define MAXLINE 80
  8. #define SERV_PORT 8000
  9. int main(int argc, char *argv[])
  10. {
  11. struct sockaddr_in servaddr;
  12. char buf[MAXLINE];
  13. int sockfd, n;
  14. char *str;
  15. if (argc != 2) {
  16. fputs(“usage: ./client message\n”, stderr);
  17. exit(1);
  18. }
  19. str = argv[1];
  20. sockfd = socket(AF_INET, SOCK_STREAM, 0);
  21. bzero(&servaddr, sizeof(servaddr));
  22. servaddr.sin_family = AF_INET;
  23. inet_pton(AF_INET, “127.0.0.1”, &servaddr.sin_addr);
  24. servaddr.sin_port = htons(SERV_PORT);
  25. connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
  26. write(sockfd, str, strlen(str));
  27. n = read(sockfd, buf, MAXLINE);
  28. printf(“Response from server:\n”);
  29. write(STDOUT_FILENO, buf, n);
  30. write(STDOUT_FILENO, “\n”, 1);
  31. close(sockfd);
  32. return 0;
  33. }

结果如下:

  1. debian-wangyao:~$ ./client a
  2. Response from server:
  3. A
  4. debian-wangyao:~$ ./client b
  5. Response from server:
  6. B
  7. debian-wangyao:~$ ./client c
  8. Response from server:
  9. C
  10. debian-wangyao:~$ netstat -antp | grep CLOSE_WAIT
  11. (Not all processes could be identified, non-owned process info
  12. will not be shown, you would have to be root to see it all.)
  13. tcp 1 0 127.0.0.1:8000 127.0.0.1:58309 CLOSE_WAIT 6979/server
  14. tcp 1 0 127.0.0.1:8000 127.0.0.1:58308 CLOSE_WAIT 6979/server
  15. tcp 1 0 127.0.0.1:8000 127.0.0.1:58307 CLOSE_WAIT 6979/server

 

解决方法
基本的思想就是要检测出对方已经关闭的socket,然后关闭它。

1.代码需要判断socket,一旦read返回0,断开连接,read返回负,检查一下errno,如果不是AGAIN,也断开连接。(注:在UNP 7.5节的图7.6中,可以看到使用select能够检测出对方发送了FIN,再根据这条规则就可以处理CLOSE_WAIT的连接)
2.给每一个socket设置一个时间戳last_update,每接收或者是发送成功数据,就用当前时间更新这个时间戳。定期检查所有的时间戳,如果时间戳与当前时间差值超过一定的阈值,就关闭这个socket。
3.使用一个Heart-Beat线程,定期向socket发送指定格式的心跳数据包,如果接收到对方的RST报文,说明对方已经关闭了socket,那么我们也关闭这个socket。
4.设置SO_KEEPALIVE选项,并修改内核参数

前提是启用socket的KEEPALIVE机制:
//启用socket连接的KEEPALIVE
int iKeepAlive = 1;
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *)&iKeepAlive, sizeof(iKeepAlive));

tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)
The number of seconds between TCP keep-alive probes.

tcp_keepalive_probes (integer; default: 9; since Linux 2.2)
The  maximum  number  of  TCP  keep-alive  probes  to  send before giving up and killing the connection if no response is obtained from the other end.

tcp_keepalive_time (integer; default: 7200; since Linux 2.2)
The number of seconds a connection needs to be idle before TCP begins sending out  keep-alive  probes.   Keep-alives  are only  sent when the SO_KEEPALIVE socket option is enabled.  The default value is 7200 seconds (2 hours).  An idle connec‐tion is terminated after approximately an additional 11 minutes (9 probes an interval of 75  seconds  apart)  when  keep-alive is enabled.

echo 120 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 2 > /proc/sys/net/ipv4/tcp_keepalive_intvl
echo 1 > /proc/sys/net/ipv4/tcp_keepalive_probes

除了修改内核参数外,可以使用setsockopt修改socket参数,参考man 7 socket。

  1. int KeepAliveProbes=1;
  2. int KeepAliveIntvl=2;
  3. int KeepAliveTime=120;
  4. setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (void *)&KeepAliveProbes, sizeof(KeepAliveProbes));
  5. setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&KeepAliveTime, sizeof(KeepAliveTime));
  6. setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&KeepAliveIntvl, sizeof(KeepAliveIntvl));

 

参考:

http://blog.chinaunix.net/u/20146/showart_1217433.html
http://blog.csdn.net/eroswang/archive/2008/03/10/2162986.aspx
http://haka.sharera.com/blog/BlogTopic/32309.htm
http://learn.akae.cn/media/ch37s02.html
http://faq.csdn.net/read/208036.html
http://www.cndw.com/tech/server/2006040430203.asp
http://davidripple.bokee.com/1741575.html
http://doserver.net/post/keepalive-linux-1.php