高可用负载均衡集群实践简明教程

1. 前言

灵活多样、开源、兼容性以及免费等特性成就了Linux。自然也无可避免存在各种碎片化问题。比如,Linux发行版过多,多个工具能解决同样的问题,知识体系过多对新手不太友好。一个常见的例子就是: Android 。

当基于Linux搭建集群时,理所当然的会面临最严重的问题:知识体系过多导致的碎片化。这么多选择,我该怎么办?选什么好呢?怎么搭建?诚然,看相关的博客、文章、图书以及文档是好的选择。但是,大多数时候需要的东西都是零散存在的。

所以,提供一个容易搭建、经过实践、可用并且成体系的集群解决方案是编写本书的目的。

2. 本书的读者

本书可以作为搭建Web服务集群的一本入门指南或教程。它主要是为新手而设计,不过对于有经验的运维(System Administrator,简称SA)来说,它同样有用。

本书假设读者具有初步的 Linux 使用经验。了解 Linux 的基本工作原理,熟悉常用 Shell 命令。

3. 起步

我们从介绍Web集群相关的一些背景知识开始。 通过本章的学习,您应该了解各个部分在集群中发挥的作用。

3.1. CentOS

集群中的作用:操作系统

CentOS
Figure 1: CentOS
CentOS 7 桌面
Figure 2: CentOS 7 桌面

CentOS 是一个由社区支持的发行版本,它是由Red Hat公开的Red Hat Enterprise Linux(RHEL)源代码所衍 生出来的。因此,CentOS Linux以兼容 RHEL的功能为目标。CentOS计划对组件的修改主要是去除上游提供者的商标及美工图。CentOS是 免费的及可自由派发的。每个CentOS版本均获得长达十年的维护(通过安全更新 —— 支持期的长短取决于Red Hat发行的源代码的更改)。 新版本的CentOS大约每两年发行一次,而每个版本的CentOS更会定期(大概每六个月)更新一次,以便支持新的硬件。这最终构建了一个 安全的、低维护的、稳定的、高预测性的、高重复性的Linux环境。

3.1.1. 版本

CentOS 7

最新版本,相对于其它版本变动较大,目前使用较少。估计2016年到2017年会成为大多数新服务器的首选

CentOS 6

较新并且成熟的版本,目前大多数新服务器使用的版本。本书也将使用CentOS6做演示

CentOS 5

老旧维护版本,仅仅会bugfix。不会增加任何新特性或者功能

选择

在整个Linux生态链中,有一些共识

开发者

维护一个稳定版本、开发一个新版本

使用者

老旧服务器保持所有组件大版本不变,仅仅需要打补丁即可
新服务器使用当前较新并且稳定的版本,会刻意避免使用最新的版本

最新版本对上线的生产服务器来说,相对不够稳定,服务器开发或维护人员对新版本的认识和使用经验还不足。通俗来讲,新版本是一个 “填坑”的过程。当使用的数量足够大并且时间足够长新版会暴露一些问题,从而得到修复。所以,对我们来说,7.0时只是一个开始。 我们会大批量使用在生产服务器时应该是7.1+或7.2+ 。

选择版本的经验,适用于任何操作系统、软件或工具。

3.2. iptables

集群中的作用:防火墙

iptables 是一个用户空间命令行程序,用以配置Linux 2.4及其以上版本内核包过滤规则集,类似于Windows系统的防火墙。

3.3. Linux Virtual Server

集群中的作用:负载均衡和高可用

Linux Virtual Server

Linux Virtual Server (LVS) 是一个建立在多个Real Server集群之上的高度可扩展且高可用服务器,使负载均衡运行于Linux系统之上。 服务器集群的结构是完全向最终用户透明的,对用户来说就像是一个独立的高性能虚拟服务器。

工作原理分别如下:

LVS 工作原理

由于LVS的成功,从Linux 2.4内核开始,LVS已经被合并到了内核代码中。

本项目在1998年5月由章文嵩博士创建。此后一直作为Linux内核开发者。 目前,章文嵩博士任阿里集团副总裁、高级研究员。

更加详细的介绍,请访问 http://www.linuxvirtualserver.org/zh

3.4. Keepalived

集群中的作用:负载均衡和高可用

Keepalived 是一个用C编写的路由软件。项目的主要目标是基于Linux系统提供简单稳定的负载均衡和高可用性基础设施。负载均衡框架依赖于鼎鼎大名的Linux虚拟服务器 (IPVS)内核模块提供Layer4负载均衡。Keepalived实现了一套校验器,能够根据健康状态自动管理维护负载均衡服务协议。另一方面,高可用性依靠VRRP协议实现。

工作原理分别如下:

Keepalived 工作原理

Keepalived根据配置文件设置负载均衡主服务器和从服务器,分别在主和从上增加Real Server到本机的LVS中。

主和从服务器: 每台主从服务器通过VRRP协议相互检测对方是否工作正常,如不正常,会做主和从之间的角色切换。

Real Server: 一般通过端口或HTTP URL返回值检测Real Server是否工作正常,如不正常,则从LVS规则中剔除。

3.5. MySQL

集群中的作用:数据库

MySQL

MySQL 是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司。体积小、使用简单、容 易维护、高性能、成熟稳定以及开放源码等特点使MySQL成为大多数人的首选。特别是Linux+Apache/Nginx+MySQL+PHP(LAMP/LNMP)这样的 组合,突出了高性能和快速开发的优势,使MySQL应用更加广泛。

凡是需要数据库的地方,都可以看到MySQL的身影。比如,阿里(淘宝、天猫)、亚马逊、YouTube、Facebook、Google等等。其中,阿里、 亚马逊、Facebook、Google等企业甚至修改MySQL代码以支撑自身的应用需求。

MySQL软件采用了双授权政策,它分为社区版和商业版。

3.6. Network File System

集群中的作用:文件存储

Network File System (NFS) 是一种分布式文件系统协议,最初由Sun Microsystems 公司开发,并于1984年发布。其功能旨在允许客户端主机可以像访问本地存储一样通过网络访问服务器端文件。

NFS在RFC中是一个开放、标准的协议,任何人或组织都可以依据标准实现它。

3.7. Nginx

集群中的作用:Web 服务器

CentOS

Nginx 是一个HTTP、反向代理、邮件代理、TCP代理服务器。很长一段时间里,许多大访问量的俄罗斯网站都运行于Nginx之上。2015年7月,Nginx服务或代理了最繁忙站点中的22.27%。

Nginx最初是为俄罗斯访问量第二的Rambler.ru开发的。意识到Ningx对整个互联网的作用,最后Nignx被开源出来。随后Apache的垄断地位被颠覆。 起初,没人想用 C 重写一个“Apache”,写出来能比Apache好吗?

3.8. Rsync

集群中的作用:文件同步与备份

Rsync 是一个用于文件快速增量传输的开源工具。在行业内,常用来做文件的增量同步或增量备份。

4. 网络拓扑

在我们动手搭建集群之前,非常有必要熟悉整体结构。

4.1. 总览

总览
Figure 1: 总览

4.2. Web负载均衡与高可用(LVS+Keepalived)

Web负载均衡与高可用(LVS+Keepalived)
Figure 2: Web负载均衡与高可用(LVS+Keepalived)

4.3. Web文件存储

Web文件存储
Figure 3: Web文件存储

4.4. DB高可用(LVS+Keepalived,无负载均衡)

DB高可用(LVS+Keepalived,无负载均衡)
Figure 4: DB高可用(LVS+Keepalived,无负载均衡)

4.5. DB主主复制

DB主主复制
Figure 5: DB主主复制

4.6. 备份

备份
Figure 6: 备份

5. 服务器与规划

没有足够的实践经验,难以选择集群适用的硬件,也难以合理的规划系统分区等,并应用到集群。本书根据内容需求,提供一个硬件选择与系统规划方案。

5.1. 服务器及其配件选购

Table 1. 服务器
主机名 网口数量 CPU 硬盘 内存 用途

Server1

推荐2

至少两核

2x任意

至少2G

负载均衡

Server2

至少2

至少两核

推荐2xSAS 1T或以上

至少2G

负载均衡&备份

Server3

推荐4

至少两核

推荐2xSAS 1T或以上

至少2G

文件存储

Server4

至少2

推荐四核

推荐2xSAS 500G或以上

推荐16G或以上

数据库服务

Server5

至少2

推荐四核

推荐2xSAS 500G或以上

推荐16G或以上

数据库服务

Server6

至少2

至少两核

推荐2xSATA 500G或以上

推荐8G或以上

Web服务

Server7

至少2

至少两核

推荐2xSATA 500G或以上

推荐8G或以上

Web服务

Table 2. 配件
名称 数量(根) 备注

千兆网线

5

需要4根,备用1根

一定要购买质量好的千兆网线。
质量差的千兆网线,在使用过程当中会从1000M变成100M,导致性能相差10倍。
  • Server2和Server3尽量采用相同大小的硬盘。如果Server3硬盘故障,可以用Server2的硬盘直接替换,快速解决问题。

  • 为提升数据库服务性能,一般采用CPU和内存换性能的方法。所以,Server4和Server5需要尽量多的CPU和内存。

  • 文件存储和数据库服务都需要大量读写硬盘文件,需要更多的硬盘IO和更高的稳定性。推荐SAS硬盘,如果条件允许甚至可以选择SSD硬盘 或15000 RPM的SAS硬盘。当然,用SSD硬盘做缓存也是可以的,这个需要结合集群框架来实现。

5.2. 网卡连接与网卡-IP映射

网卡连接与网卡-IP映射
Figure 2: 网卡连接与网卡-IP映射

5.3. IP地址表

Table 3. IP地址表
类型 主机名 网络接口 IP 地址 网络类型

Master LVS

Server1

eth0

192.168.1.70

Public IP

eth0:lan

10.10.10.70

Private IP

eth0:db

10.10.10.100

Virtual IP

eth0:web

192.168.1.200

Virtual IP

Backup LVS&备份

Server2

eth0

192.168.1.80

Public IP

eth0:lan

10.10.10.80

Private IP

eth0:db

10.10.10.100

Virtual IP

eth0:web

192.168.1.200

Virtual IP

eth1

12.12.12.80

Private IP

Web文件存储

Server3

eth0

192.168.1.90

Public IP

eth1

11.11.11.90

Private IP

eth2

12.12.12.90

Private IP

MySQL1

Server4

eth0

192.168.1.101

Public IP

eth0:lan

10.10.10.101

Private IP

eth1

13.13.13.101

Private IP

MySQL2

Server5

eth0

192.168.1.102

Public IP

eth0:lan

10.10.10.102

Private IP

eth1

13.13.13.102

Private IP

Nginx1

Server6

eth0

192.168.1.201

Public IP

eth0:lan

10.10.10.201

Private IP

eth1

11.11.11.201

Private IP

Nginx2

Server7

eth0

192.168.1.202

Public IP

eth0:lan

10.10.10.202

Private IP

eth1

14.14.14.202

Private IP

5.4. 分区规划

正常情况,安装完CentOS后,根分区使用1.5G左右。 为保证根分区在现在和未来都足够大,此处分配50G。

Table 4. Server1/2/3/4/5/6/7
分区 大小 挂载点

/dev/sda1

50G

/

/dev/sda2

sda剩余可用空间

/data2

/dev/sdb1

sdb全部可用空间

/data

为方便使用,可以增加链接 ln -s /data2 /data/data2

本书没有为虚拟内存(SWAP)单独分区,打算使用单独的文件(/var/swap.file)作虚拟内存。 当然,为演示目的不设置任何虚拟内存也是可以的。只要保证内存没使用完即可。
/dev/sda2 和 /dev/sdb1 可以加入LVM卷组,并将所有空间划分到同一个逻辑卷,然后挂载到/data。 但是,为了维护性并没有使用LVM。因为,sda或sdb中任意一个硬盘出现故障时,无法保证数据完整。

6. 安装设置CentOS6

集群服务是网络服务的一个子集,在一切开始以前,需要先准备好网络。

6.1. 安装CentOS6

6.1.1. 获取

访问 http://wiki.centos.org/Download 选择 “CentOS-6”→“x86_64”,选择最快的镜像下载“CentOS-6.7-x86_64-minimal.iso”。

推荐安装迷你版本,这是最小化安装。占用最少的硬盘空间,安装最少的软件包。

6.1.2. 安装

限于篇幅,本书不涉及具体的安装过程。

详细的安装文档,请访问: Red Hat Enterprise Linux 6 Installation Guide

6.1.3. 安装软件包

缓存软件包列表:yum makecache

安装:yum install -y curl rsync vim wget mysql

6.1.4. 设置系统

禁用SELINUX,必须重启才能生效

echo SELINUX=disabled>/etc/selinux/config

echo SELINUXTYPE=targeted>>/etc/selinux/config

清除iptables的默认规则

iptables -F

service iptables save

ssh登录时,登录ip被会服务端反向解析为域名,导致ssh登录缓慢

sed -i "s/#UseDNS yes/UseDNS no/" /etc/ssh/sshd_config

ssh登录时,GSSAPIAuthentication认证会导致登录缓慢

sed -i "s/GSSAPIAuthentication yes/GSSAPIAuthentication no/" /etc/ssh/sshd_config

对新手来说SELINUX和默认的iptables规则带来太多麻烦。搭建集群时,我们暂时禁用和关闭它们。 整个集群成功后,可以考虑启用它们。

6.2. 配置公有网络

配置对外提供服务的IP地址。

严格意义上讲,192.168.0.0/16 属于私有网络,私有网络的IP无法直接连接互联网,需要公网IP转发。 本书为演示目的,广义上称 192.168.0.0/16 网络为公有网络(公网), 10.0.0.0/811.0.0.0/812.0.0.0/8 以及 13.0.0.0/8 网络为私有网络(内网)。
本书假设网卡前缀为常用的eth。根据网卡类型的不同,CentOS会修改网卡前缀为em或eno等等。
内网不需要配置网关和DNS。

按照以下命令操作后,

  • 记得重启网络服务 service network restart

  • 通过命令 ip a ,查看IP配置是否生效

  • 通过命令 cat /etc/resolv.conf ,查看DNS配置是否生效。但是,本书推荐直接 ping qq.com 看看能否解析出IP地址

PS: 为什么用 ping qq.com 代替cat命令?因为打字少啊!

ifconfig命令已经过时,建议使用ip命令代替。

6.2.1. 服务器 Server1

IP地址:192.168.1.70

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.70
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.2.2. 服务器 Server2

IP地址:192.168.1.80

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.80
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.2.3. 服务器 Server3

IP地址:192.168.1.90

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.90
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.2.4. 服务器 Server4

IP地址:192.168.1.101

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.101
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.2.5. 服务器 Server5

IP地址:192.168.1.102

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.102
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.2.6. 服务器 Server6

IP地址:192.168.1.201

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.201
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.2.7. 服务器 Server7

IP地址:192.168.1.202

网卡eth0
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.202
NETMASK=255.255.255.0
GATEWAY=192.168.1.1
DNS1=223.5.5.5
DNS2=223.6.6.6
EOF

6.3. 配置基于交换机的内网

内网不需要配置网关和DNS。

按照以下命令操作后,

  • 记得重启网络服务 service network restart

  • 通过命令 ip a ,查看IP配置是否生效

  • 通过命令 cat /etc/resolv.conf ,查看DNS配置是否生效。但是,本书推荐直接 ping qq.com 看看能否解析出IP地址

PS: 为什么用 ping qq.com 代替cat命令?因为打字少啊!

ifconfig命令已经过时,建议使用ip命令代替。

6.3.1. 服务器Server1

IP地址:10.10.10.70

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.70
NETMASK=255.255.255.0
EOF

6.3.2. 服务器 Server2

IP地址:10.10.10.80

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.80
NETMASK=255.255.255.0
EOF

6.3.3. 服务器 Server3

IP地址:10.10.10.90

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.90
NETMASK=255.255.255.0
EOF

6.3.4. 服务器 Server4

IP地址:10.10.10.101

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.101
NETMASK=255.255.255.0
EOF

6.3.5. 服务器 Server5

IP地址:10.10.10.102

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.102
NETMASK=255.255.255.0
EOF

6.3.6. 服务器 Server6

IP地址:10.10.10.201

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.201
NETMASK=255.255.255.0
EOF

6.3.7. 服务器 Server7

IP地址:10.10.10.202

网卡eth0:lan
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth0:lan
DEVICE=eth0:lan
BOOTPROTO=none
ONBOOT=yes
IPADDR=10.10.10.202
NETMASK=255.255.255.0
EOF

6.4. 配置基于千兆网线的内网

为什么又看到这个提示?因为…​…​重要的事情说三遍。
内网不需要配置网关和DNS。

按照以下命令操作后,

  • 记得重启网络服务 service network restart

  • 通过命令 ip a ,查看IP配置是否生效

  • 通过命令 cat /etc/resolv.conf ,查看DNS配置是否生效。但是,本书推荐直接 ping qq.com 看看能否解析出IP地址

PS: 为什么用 ping qq.com 代替cat命令?因为打字少啊!

ifconfig命令已经过时,建议使用ip命令代替。

6.4.1. 配置NFS存储内网

Server3作为NFS服务端,Server2&6&7作为NFS客户端。Server2&3、Server3&6以及Server3&7之间使用千兆网线直连,需要配置各自的内网。

Server2&3

12.12.12.0/24

Server3&6

11.11.11.0/24

Server3&7

14.14.14.0/24

服务器 Server2

IP地址:12.12.12.80

网卡eth1
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=12.12.12.80
NETMASK=255.255.255.0
EOF
服务器 Server3

IP地址:

  • 11.11.11.90

  • 12.12.12.90

  • 14.14.14.90

网卡eth1
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=11.11.11.90
NETMASK=255.255.255.0
EOF
网卡eth2
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth2
DEVICE=eth2
BOOTPROTO=none
ONBOOT=yes
IPADDR=12.12.12.90
NETMASK=255.255.255.0
EOF
网卡eth3
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth3
DEVICE=eth3
BOOTPROTO=none
ONBOOT=yes
IPADDR=14.14.14.90
NETMASK=255.255.255.0
EOF
服务器 Server6

IP地址:11.11.11.201

网卡eth1
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=11.11.11.201
NETMASK=255.255.255.0
EOF
服务器 Server7

IP地址:14.14.14.202

网卡eth1
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=14.14.14.202
NETMASK=255.255.255.0
EOF

6.4.2. 配置MySQL内网

Server4/5 都是MySQL服务器,使用千兆网线直连在第二个网卡。

服务器 Server4

IP地址:13.13.13.101

网卡eth1
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=13.13.13.101
NETMASK=255.255.255.0
EOF
服务器 Server5

IP地址:13.13.13.102

网卡eth1
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-eth1
DEVICE=eth1
BOOTPROTO=none
ONBOOT=yes
IPADDR=13.13.13.102
NETMASK=255.255.255.0
EOF

7. Nginx服务

在Server3上,仅仅安装Nginx,不需要配置、启动和测试。

仅仅是为了使系统用户nginx存在。NFS服务器共享文件给Nginx服务器使用,而NFS共享的目录对系统用户nginx来说是可读写的。 需要保证这些服务器上都存在系统用户nginx。

在Server6&7上,分别安装Nginx并测试。

7.1. 获取

访问 http://nginx.org/en/linux_packages.html#stable 获取Nginx安装包。

7.2. 安装

在Server3&6&7上执行以下操作:

安装Nginx YUM源

rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm

安装Nginx

yum install -y nginx

7.3. 配置

在Server6&7上执行以下操作:

开机启动Nginx服务

chkconfig nginx on

立即启动Nginx服务

service nginx start

本书不涉及具体的参数调整,仅仅需要启动Nginx,保证80端口可以访问即可。

7.4. 测试

在Server6&7上测试Nginx服务。

7.4.1. 检查80端口

在终端中执行 ss -t4nlp|grep ':80'

# ss -t4nlp|grep ':80'
LISTEN     0      128                       *:80                       *:*      users:(("nginx",20736,6),("nginx",20738,6))

根据输出我们可以看到Nginx已经启动成功。

netstat命令已经过时,建议使用ss命令代替。

7.4.2. 测试访问

在终端中执行 curl -I localhost

# curl -I localhost
HTTP/1.1 200 OK
Server: nginx/1.8.0
Date: Tue, 11 Aug 2015 16:54:56 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 21 Apr 2015 15:38:08 GMT
Connection: keep-alive
ETag: "55366ee0-264"
Accept-Ranges: bytes
当然,你也可以在自己的电脑上,通过浏览器 http://192.168.1.201http://192.168.1.202 测试访问。

8. MySQL服务

在Server4&5上,分别安装MySQL并测试。

8.1. 安装

Server4&5 分别安装并设置开机启动。

yum install -y mysql mysql-server

设置开机启动MySQL服务

chkconfig mysqld on

8.2. 配置

初始化MySQL数据库。

Server4&5执行
ls /etc/my.cnf.init.bak >/dev/null 2>&1 || cp /etc/my.cnf /etc/my.cnf.init.bak

sed -i 's#datadir=/var/lib/mysql#datadir=/data/mysql#g' /etc/my.cnf

mkdir /data/mysql

mysql_install_db

service mysqld start

mysqladmin -uroot password "rootpassword"
本书不涉及具体的参数优化,仅会设置MySQL集群需要的参数。保证3306端口能够连接即可。

8.3. 测试

分别测试Server4&5

8.3.1. 检查3306端口

在终端中执行 ss -t4nlp|grep ':3306'

Server4&5输出
# ss -t4nlp|grep ':3306'
LISTEN     0      50                        *:3306                     *:*      users:(("mysqld",22131,10))

根据输出我们可以看到MySQL已经启动成功。

netstat命令已经过时,建议使用ss命令代替。

8.3.2. 测试连接

在终端中执行 mysql -uroot -prootpassword

Server4&5输出
# mysql -uroot -prootpassword
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.1.73 Source distribution

Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

8.4. 常见的复制模式

MySQL支持多种不同的复制拓扑。

常见的MySQL复制拓扑
Figure 1: 常见的MySQL复制拓扑

8.4.1. 主从

这是最常见的也是最易于配置和管理的拓扑形式。在这种拓扑下我们有两台服务器,一台做主机,一台做从机。写操作都在主机上执行而 读操作可以分散到主机和从机之间 。

8.4.2. 一主多从

这种场景下多台从机连到主机。这可以大幅度水平扩展系统,但代价是增加了管理成本。

8.4.3. 多主

在主/主配置下,两台服务器组合成一个链,互为主从。虽然,这种配置带来了能够在任一个系统中写数据的好处,但确实明显增加了设置、 配置和管理的复杂度。另外,除非你用MySQLCluster,否则不会有冲突检测机制以至于应用程序必须确定不去更新还没有被复制的行。也可 以用几台MySQL服务器搭成环状,得到更高水平的扩展性和性能(假设应用程序能避免向不同服务器的相同的行发送冲突的更新数据)。 MySQL5.5 引入了新的过滤特性,能够更好地处理当一台服务器正在更新复制到环中其他服务器时发生故障的情况。

多主环
Figure 2: 多主环

当在使用多主复制的同时用了自动增长的列,你应该在每台服务器上使用auto_increment_offset和auto_increment_increment参数来确 保不会重复分配值。例如两台服务器的情况如下图所示。

避免自动增长冲突的参数值
Figure 3: 避免自动增长冲突的参数值

多主一从(多源) MySQL目前还不支持这种复制拓扑。在多主的配置下,从机基本上“为两台主机服务”,意味着从机从超过一台的主机复制变化。由于MySQL Cluster允许多台MySQL服务器写到同一个Cluster,因此在一些合适的应用场景,如果需要的话配置这种功能是可能的(每台MySQL服务器仅 仅是一台主机的从机)。

8.4.4. 复制模式的选择

MySQL的主-主复制架构是企业环境中常见的解决方案。此方案具备高可用、可扩展、易管理的特点。主主复制是通 过两台MySQL Server通过MySQL Replication互为主从。两台MySQL Server互相将对方作为自己的(主库)Master,自己又同时作为 对方的(备库)Slave来进行复制。实现高可用架构中的数据同步功能,下文将介绍的Keepalived实现高可用架构中的故障迁移功能。

优点
  • 数据同步写入,多点读取

  • 配合Keepalived能做完善的高可用框架

缺点
  • 自动增长的列冲突(配置参数解决)

  • MySQL Server数量增加时,明显增加了配置管理的复杂度(本书演示集群只有两台,复杂度可以忽略不计)

所以,我们选择 多主(主-主)复制模式

8.5. MySQL配置文件

Server4执行
rm -f /etc/my.cnf
wget -c http://fifilyu.github.io/halcpgb/file/Server4.etc.my.cnf -O /etc/my.cnf

mkdir /data2/mysql_binlogs
chown -R mysql /data2/mysql_binlogs
service mysqld restart
Server5执行
rm -f /etc/my.cnf
wget -c http://fifilyu.github.io/halcpgb/file/Server5.etc.my.cnf -O /etc/my.cnf

mkdir /data2/mysql_binlogs
chown -R mysql /data2/mysql_binlogs
service mysqld restart

sync_binlog,innodb_flush_log_at_trx_commit,innodb_support_xa三个选项都是出于安全目的设置的,不是复制的必须选项。 如果没设置的话,一旦主服务器宕机,数据可能来不及写入磁盘,从而导致从服务器在复制过程中出现类似下面的错误:

Client requested master to start replication from impossible position

因为日志数据已经丢失了。 所以此类问题基本上不能处理,只能重新安装同步从服务器。

8.6. 主-主复制

8.6.1. 配置Server4-Server5主从复制

Server4,第一MySQL主服务器

主-主模式,两个MySQL服务器中,其中一个宕机。当恢复正常时,主-主之间会相互进行同步,可能出现死锁和IO问题。所以,其中一个MySQL服务器默认不启动slave服务。本书设置如下:

  • 第二MySQL从服务器(Server4)默认不启动slave服务。脚本(/opt/check_mysql_slave.sh)每两分钟检测一次slave服务,如未启动slave服务则启动之

  • 第一MySQL从服务器(Server5)默认启动slave服务

Server4执行
cat <<EOF >/opt/check_mysql_slave.sh
mysql_cmd="/usr/bin/mysql -uroot -prootpassword -e"
\$mysql_cmd "show slave status\G;"|grep "Slave_IO_Running: Yes" >/dev/null || \$mysql_cmd "start slave;"
EOF

echo "*/2 * * * * /bin/sh /opt/check_mysql_slave.sh >/dev/null 2>&1" >> /var/spool/cron/root

在Server4上,登录MySQL Shell:

mysql -uroot -prootpassword

在MySQL Shell中执行

Server5执行
SHOW MASTER STATUS;

grant all privileges on *.* to root@"10.10.10.70"  identified by 'rootpassword';

grant all privileges on *.* to root@"10.10.10.80"  identified by 'rootpassword';

grant all privileges on *.* to root@"10.10.10.100"  identified by 'rootpassword';

grant all privileges on *.* to root@"10.10.10.201"  identified by 'rootpassword';

grant all privileges on *.* to root@"10.10.10.202"  identified by 'rootpassword';

grant replication slave on *.* to slaveuser@"13.13.13.101"  identified by 'slaveuserpassword';

grant replication slave on *.* to slaveuser@"13.13.13.102"  identified by 'slaveuserpassword';

flush privileges;
13.13.13.0/24是Server4&5服务器之间使用千兆网线直连的网络。允许Keepalived和Nginx服务器(10.10.10.70&80&201&202)可以远程访问MySQL。
Server4输出
# mysql -uroot -prootpassword
......
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      106 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

mysql> grant all privileges on *.* to root@"10.10.10.70" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on *.* to root@"10.10.10.80" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.02 sec)

mysql> grant all privileges on *.* to root@"10.10.10.100" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.02 sec)

mysql> grant replication slave on *.* to root@"10.10.10.201" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.02 sec)

mysql> grant replication slave on *.* to root@"10.10.10.202" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.02 sec)

mysql> grant replication slave on *.* to slaveuser@"13.13.13.101" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.02 sec)

mysql> grant replication slave on *.* to slaveuser@"13.13.13.102" identified by 'slaveuserpassword';
Query OK, 0 rows affected (0.02 sec)

mysql>

按Ctrl+C退出MySQL Shell。

获取到列“File”的值mysql-bin.000001,列“Position”的值106。

此时,Server4上的MySQL不要做任何。防止主服务器状态值变化。

Server5,第一MySQL从服务器
  1. 设置第一MySQL从服务器

登录MySQL Shell:

mysql -uroot -prootpassword

在MySQL Shell中执行:

Server2执行
change master to master_host='13.13.13.101',
master_user='slaveuser',
master_password='slaveuserpassword',
master_log_file='mysql-bin.000001',
master_log_pos=106;

start slave;

show slave status\G;
Server5输出
# mysql -uroot -prootpassword
......
mysql> change master to master_host='13.13.13.101',
    -> master_user='slaveuser',
    -> master_password='slaveuserpassword',
    -> master_log_file='mysql-bin.000001',
    -> master_log_pos=450;
Query OK, 0 rows affected (0.04 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 13.13.13.101
                  Master_User: slaveuser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 450
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 595
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
......
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
1 row in set (0.00 sec)

ERROR:
No query specified

mysql>

如果Slave_IO_Running和Slave_SQL_Running状态为Yes,Last_SQL_Errno为0,则表示主从配置成功。

8.6.2. 配置Server5-Server4主从复制

Server5,第二MySQL主服务器

查看Master状态

Server5执行
mysql -uroot -prootpassword -e "SHOW MASTER STATUS;"
Server5输出
# mysql -uroot -prootpassword -e "SHOW MASTER STATUS;"
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000001 |      450 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

按Ctrl+C退出MySQL Shell。

获取到列“File”的值mysql-bin.000001,列“Position”的值450。

Server4,第二MySQL从服务器
  1. 设置第二MySQL从服务器

登录Server4的MySQL Shell执行

Server4执行
change master to master_host='13.13.13.102',
master_user='slaveuser',
master_password='slaveuserpassword',
master_log_file='mysql-bin.000001',
master_log_pos=450;

start slave;

show slave status\G;
Server4输出
# mysql -uroot -prootpassword
......
mysql> change master to master_host='13.13.13.102',
    -> master_user='slaveuser',
    -> master_password='slaveuserpassword',
    -> master_log_file='mysql-bin.000001',
    -> master_log_pos=450;
Query OK, 0 rows affected (0.02 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 13.13.13.102
                  Master_User: slaveuser
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
          Read_Master_Log_Pos: 450
               Relay_Log_File: mysql-relay-bin.000002
                Relay_Log_Pos: 251
        Relay_Master_Log_File: mysql-bin.000001
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
.....
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
1 row in set (0.00 sec)

ERROR:
No query specified

如果Slave_IO_Running和Slave_SQL_Running状态为Yes,Last_SQL_Errno为0,则表示主从配置成功。

8.6.3. 测试

测试Server4-Server5主从

在第一主库上创建数据库 testdb ,在第一从库查看是否同步创建。

Server4 MySQL Shell
# mysql -uroot -prootpassword
......
mysql> create database testdb;
Query OK, 1 row affected (0.01 sec)

mysql>
Server5 MySQL Shell
# mysql -uroot -prootpassword
......
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
| testdb             |
+--------------------+
4 rows in set (0.00 sec)

mysql>
测试Server5-Server4主从

在第二主库上删除数据库 testdb ,在第二从库查看是否同步删除。

Server5 MySQL Shell
# mysql -uroot -prootpassword
......
mysql> drop database testdb;
Query OK, 0 rows affected (0.04 sec)

mysql>
Server4 MySQL Shell
# mysql -uroot -prootpassword
......
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

mysql>

9. LVS与Keepalived服务

本章是本书的重点,介绍和演示如何安装配置LVS与Keepalived服务。

9.1. 安装

在Server1&2上安装包ipvsadm以及keepalived

yum install -y ipvsadm keepalived

9.2. LVS工作模式与负载调度算法

9.2.1. 工作模式

  1. Virtual Server via Network Address Translation(VS/NAT)

    通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。
  2. Virtual Server via IP Tunneling(VS/TUN)

    采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,调度器把请求报文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。由于一般网络服务应答比请求报文大许多,采用 VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。
  3. Virtual Server via Direct Routing(VS/DR)

    VS/DR通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。同VS/TUN技术一样,VS/DR技术可极大地提高集群系统的伸缩性。这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。

9.2.2. 负载调度算法

针对不同的网络服务需求和服务器配置,IPVS调度器实现了如下八种负载调度算法:

  1. 轮叫(Round Robin)

    调度器通过"轮叫"调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。
  2. 加权轮叫(Weighted Round Robin)

    调度器通过"加权轮叫"调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
  3. 最少链接(Least Connections)

    调度器通过"最少连接"调度算法动态地将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用"最小连接"调度算法可以较好地均衡负载。
  4. 加权最少链接(Weighted Least Connections)

    在集群系统中的服务器性能差异较大的情况下,调度器采用"加权最少链接"调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
  5. 基于局部性的最少链接(Locality-Based Least Connections)

    "基于局部性的最少链接"调度算法是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用"最少链接"的原则选出一个可用的服务 器,将请求发送到该服务器。
  6. 带复制的基于局部性最少链接(Locality-Based Least Connections with Replication)

    "带复制的基于局部性最少链接"调度算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务器组,按"最小连接"原则从服务器组中选出一台服务器,若服务器没有超载,将请求发送到该服务器,若服务器超载;则按"最小连接"原则从这个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。
  7. 目标地址散列(Destination Hashing)

    "目标地址散列"调度算法根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。
  8. 源地址散列(Source Hashing)

    "源地址散列"调度算法根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。

9.2.3. 选择

本书演示的集群是构建在同一个物理网络下,并且需要简单易学。所以,我们选择

  • 工作模式选择VS/DR

  • 负载调度算法选择轮叫(rr)

9.3. LVS体验

本节仅仅体验如何使用LVS。此时不会修改任何系统配置文件,所有设置都是重启后即被还原。

9.3.1. Director

Server1执行
ip addr add 192.168.1.200/24 broadcast 192.168.1.255 dev eth0

ipvsadm -A -t 192.168.1.200:80 -s rr
ipvsadm -a -t 192.168.1.200:80 -r 10.10.10.201 -g
ipvsadm -a -t 192.168.1.200:80 -r 10.10.10.202 -g

通过命令 ipvsadm -ln 查看增加的LVS设置

Server1输出
# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.200:80 rr
  -> 10.10.10.201:80              Route   1      0          0
  -> 10.10.10.202:80              Route   1      0          0
说明
ip addr add 192.168.1.200/24 broadcast 192.168.1.255 dev eth0

增加192.168.1.200到网卡eth0

ipvsadm -A -t 192.168.1.200:80 -s rr
  • -A 增加虚拟服务器

  • -t 虚拟服务地址[:端口]

  • -s 负载调度算法,rr表示轮叫

ipvsadm -a -t 192.168.1.200:80 -r 10.10.10.201 -g
  • -a 增加真实服务

  • -r 虚拟服务地址

  • -g LVS工作模式:VS/DR

更多ipvsadm信息,请 ipvsadm --help 查看

9.3.2. Real Server(Server6&7)

Server6&7执行
ip addr add 192.168.1.200/32 dev lo
ip route add 192.168.1.200/32 dev lo

sysctl -w net.ipv4.conf.lo.arp_ignore=1
sysctl -w net.ipv4.conf.lo.arp_announce=2
sysctl -w net.ipv4.conf.all.arp_ignore=1
sysctl -w net.ipv4.conf.all.arp_announce=2
说明
ip addr add 192.168.1.200/32 dev lo

增加192.168.1.200到网卡lo

ip route add 192.168.1.200/32 dev lo

增加192.168.1.200路由

arp_ignorearp_announce

使真实服务器不回应网卡lo以外的arp包

*.arp_ignoreall.arp_ignore 值不同时,取值最大的值生效。 lo.arp_ignore=0,all.arp_ignore=1,生效的是1。所以,网卡和all必须同时设置。 sysctl所有参数的取值模式都是这样。
参数文档
arp_announce - INTEGER
Define different restriction levels for announcing the local source IP address from IP packets in ARP requests sent on interface:

0 - (default) Use any local address, configured on any interface

1 - Try to avoid local addresses that are not in the target's subnet for this interface. This mode is useful when target hosts reachable via this interface require the source IP address in ARP requests to be part of their logical network configured on the receiving interface. When we generate the request we will check all our subnets that include the target IP and will preserve the source address if it is from such subnet. If there is no such subnet we select source address according to the rules for level 2.

2 - Always use the best local address for this target. In this mode we ignore the source address in the IP packet and try to select local address that we prefer for talks with the target host. Such local address is selected by looking for primary IP addresses on all our subnets on the outgoing interface that include the target IP address. If no suitable local address is found we select the first local address. we have on the outgoing interface or on all other interfaces, with the hope we will receive reply for our request and even sometimes no matter the source IP address we announce.

The max value from conf/{all,interface}/arp_announce is used.

Increasing the restriction level gives more chance for receiving answer from the resolved target while decreasing the level announces more valid sender's information.
arp_ignore - INTEGER
Define different modes for sending replies in response to received ARP requests that resolve local target IP addresses:

0 - (default): reply for any local target IP address, configured on any interface

1 - reply only if the target IP address is local address configured on the incoming interface

2 - reply only if the target IP address is local address configured on the incoming interface and both with the sender's IP address are part from same subnet on this interface

3 - do not reply for local addresses configured with scope host, only resolutions for global and link addresses are replied

4-7 - reserved

8 - do not reply for all local addresses

The max value from conf/{all,interface}/arp_ignore is used when ARP request is received on the {interface}

9.3.3. 测试

创建测试页面
Server6&7执行
html_page=/usr/share/nginx/html/index.html
ip_addr=`ip a|grep '10.10.10'|awk '{print $2}'|awk -F'/' '{print $1}'`

echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">' >$html_page
echo "这个是一个测试页面。<br>">>$html_page
echo "你看到内容来自 Real Server: $ip_addr" >>$html_page
测试访问

在浏览器里面访问 http://192.168.1.200 。 我们有两台Real Server,应该有的效果是每次刷新网页,会显示不同的内容。

为了测试的准确性,请直接使用 Ctrl+F5强制刷新 网页,这样浏览器才不会显示缓存的内容。
浏览器输出
这个是一个测试页面。
你看到内容来自 Real Server: 10.10.10.201
浏览器输出
这个是一个测试页面。
你看到内容来自 Real Server: 10.10.10.202

通过命令 ipvsadm -ln 查看访问分配情况

Server1输出
# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.1.200:80 rr
  -> 10.10.10.201:80              Route   1      1          2
  -> 10.10.10.202:80              Route   1      0          2
ActiveConn

活动连接数,也就是TCP连接状态的ESTABLISHED

InActConn

除了状态是ESTABLISHED的TCP连接

当LVS配置成功后,不断的访问 ActiveConnInActConn 会持续变化。 两个值都为0时,说明LVS配置出现错误。

9.3.4. 清空临时配置

重启Server1&6&7,清空所有临时配置。

9.3.5. 总结

本章只是为后面Keepalived的学习做一些铺垫。熟悉LVS原理和使用后,更加容易理解Keepalived。

9.4. Keepalived配置文件

Server1执行
#备份默认配置文件
ls /etc/keepalived/keepalived.conf.init.bak >/dev/null 2>&1 || cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.init.bak

#删除默认配置文件
rm -f /etc/keepalived/keepalived.conf

#下载配置文件
wget -c http://fifilyu.github.io/halcpgb/file/Server1.etc.keepalived.keepalived.conf -O /etc/keepalived/keepalived.conf
Server2执行
#备份默认配置文件
ls /etc/keepalived/keepalived.conf.init.bak >/dev/null 2>&1 || cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.init.bak

#删除默认配置文件
rm -f /etc/keepalived/keepalived.conf

#下载配置文件
wget -c http://fifilyu.github.io/halcpgb/file/Server2.etc.keepalived.keepalived.conf -O /etc/keepalived/keepalived.conf

9.5. Keepalived环境配置

9.5.1. Keepalived

Server1&2执行
echo "/sbin/service keepalived stop" >/opt/stop_keepalived.sh
echo "/sbin/service keepalived status|grep '(pid ' || /sbin/service keepalived start" >/opt/check_keepalived.sh
chmod +x /opt/stop_keepalived.sh /opt/check_keepalived.sh

#增加计划任务,每分钟执行一次脚本。当Keepalived服务停止时,该脚本会启动服务
#此任务与Keepalived配置文件中使用/opt/stop_keepalived.sh脚本结合起来,组成了一个启动和停止服务的环路。
#配合实现MySQL的高可用框架。
echo "*/1 * * * * /bin/sh /opt/check_keepalived.sh >/dev/null 2>&1" >> /var/spool/cron/root

chkconfig keepalived on
service keepalived start

ipvsadm -ln

当服务器(Server1&2)的Keepalived(vrrp_instance)为Master状态时,无法访问以下地址:

  • 192.168.1.200的80端口

  • 10.10.10.100的3306端口

细心的话,会发现我们使用Keepalived对80端口和3306端口做了高可用和负载均衡。

也就是说,Keepavelid将VIP绑定到网卡上时,本机无法访问VIP+Keepalived监控的端口。

9.5.2. Real Server

Server4&5
Server4&5执行
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-lo:vip
DEVICE=lo:vip
BOOTPROTO=none
IPADDR=10.10.10.100
NETMASK=255.255.255.255
EOF

cat << EOF > /etc/sysconfig/network-scripts/route-lo
10.10.10.100/32 dev lo
EOF

#当前系统生效
ip addr add 10.10.10.100/32 dev lo
ip route add 10.10.10.100/32 dev lo

cat <<EOF >>/etc/sysctl.conf
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
EOF

sysctl -p
Server6&7
Server6&7执行
cat << EOF > /etc/sysconfig/network-scripts/ifcfg-lo:vip
DEVICE=lo:vip
BOOTPROTO=none
IPADDR=192.168.1.200
NETMASK=255.255.255.255
EOF

cat << EOF > /etc/sysconfig/network-scripts/route-lo
192.168.1.200/32 dev lo
EOF

#当前系统生效
ip addr add 192.168.1.200/32 dev lo
ip route add 192.168.1.200/32 dev lo

cat <<EOF >>/etc/sysctl.conf
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
EOF

sysctl -p

9.6. 测试

9.6.1. 测试Web服务负载均衡

Web访问测试,和之前 LVS-测试访问 一样。

反复停止Server1/2上的Keepalived服务,观察VIP地址192.168.1.200以及10.10.10.100是否在两台服务器之间来回切换。 反复停止Server6/7上的Nginx服务,观察访问 http://192.168.1.200 会有什么变化。

停止Nginx服务

service nginx stop

9.6.2. 测试数据库服务高可用

在Server6&7上连接MySQL测试。

Server6&7执行
mysql -h 10.10.10.100 -uroot -prootpassword -e "SELECT @@hostname hostname;"

如果成功,则能看到 Server5 字样。

Server6&7输出
# mysql -h 10.10.10.100 -uroot -prootpassword -e "SELECT @@hostname hostname;"
+----------+
| hostname |
+----------+
| Server5  |
+----------+

此时,如果停止Server5上的Keepalived服务,执行同样的命令,会看到 Server4 字样。表示MySQL高可用配置成功。

Server6&7输出
# mysql -h 10.10.10.100 -uroot -prootpassword -e "SELECT @@hostname hostname;"
+----------+
| hostname |
+----------+
| Server4  |
+----------+
停止MySQL服务

service mysqld stop

10. NFS文件存储

本章是本书的重点之一,演示如何配置并使用NFS作共享存储,一般是用来存储静态文件。

在Web领域,网页文件一般分为两大类:

动态文件

由某种编程语言(Python、Ruby、C/C++、PHP、JSP、JAVA等)书写的文件。这种文件需要Web容器(Apache、Nginx、Tomcat等)转换为HTML,才能被浏览器显示为网页。比如,.py、.php、.jsp等等

静态文件

不需要Web容器(Apache、Nginx、Tomcat等)也能被浏览器显示的文件。比如,.js、.css、图片(.jpg/.png/.gif)等等

10.1. 安装

在Server2&3&6&7上安装包nfs-utils以及rpcbind

yum install -y nfs-utils rpcbind

其中,Server3为NFS服务端,Server2&6&7为NFS客户端。

在Server3设置开机启动

Server3执行
chkconfig rpcbind on
chkconfig nfs on

10.2. 文档

10.2.1. 服务端文档

有两种方法配置NFS服务端

  • 手动编辑NFS配置文件/etc/exports

  • 使用命令exportfs,通过命令行配置

/etc/exports文件
语法规则

/etc/exports配置的文件系统将按照指定的选项共享到远程主机。此文件遵循以下语法规则:

  • 忽略空白行

  • 以井号开始的行为注释

  • 以反斜线续行

  • 每行配置共享一个文件系统

  • 共享的文件系统后面,所有授权主机列表必须以空格跟分隔

  • 每个主机的选项必须直接放在主机标识符之后的圆括号里,主机和第一个圆括号之间不能有任何空格

结构

每行配置遵循以下结构:

export host(options)

上述结构采用了以下变量:

export

被共享的目录

host

目录被共享给指定的主机或网络

options

被主机使用的选项

可以指定多个主机,并为每个主机指定选项。为了在同一行配置多个的主机(以空格分隔),每个主机名后都将各自的选项填写在圆括号中,如:

export host1(options1) host2(options2) host3(options3)

关于指定主机名的方法,请查阅 "主机名格式"。

最简单的/etc/exports文件仅仅指定共享的目录和允许的主机,比如:

Example 1. /etc/exports文件

/exported/directory bob.example.com

此时,bob.example.com(主机)能够挂载来自NFS服务端的/exported/directory/。因为此时没有选项被指定,NFS将使用默认设置。

选项
ro(默认值)

允许读取数据。共享的文件系统只读,远程主机不能修改此文件系统上的数据

rw

允许读写数据

sync(默认值)

同步写入。在读写模式下,上一个请求写完数据到硬盘之前,NFS服务端不能回应请求。要启用异步写入,需要指定 async 选项

wdelay(默认值)

假如NFS服务端认为另一个写请求已迫在眉睫,它会延迟写入数据到硬盘。这样能够提升性能,因为此策略能够减少写命令必须访问 硬盘的次数。要禁止这个选项,需要指定 no_wdelay 选项。 只有 sync 选项指定时, no_wdelay 才有效

root_squash(默认值)

这个选项可以防止root用户远程连接(相对于本地),从而具有root权限。相反,NFS服务端会映射root用户到匿名用户(nfsnobody)。这样有效的“压缩”远程root用户的权利为最低权限的本地用户,防止在远程服务器上出现可能未经授权的写操作

all_squash

远程用户(包括root)映射为匿名用户(nfsnobody)

anonuid

远程访问的用户映射为指定的本地用户

anongid

远程访问的用户组映射为指定的本地用户组

主机名格式

主机可以为以下形式:

单个机器

完全形式的域名(能够被服务器解析的),主机名(能够被服务器解析的)或者IP地址

使用通配符指定多个机器
  • 使用星号(*)或者问号(?)匹配一个字符串

  • 通配符不能被用于IP地址

  • 如果递归DNS查找失败,通配符会尽可能的工作

  • 当在完全形式的域名中指定通配符时,通配符不会包含点(.)。比如,*.example.com包括one.example.com,但不包括one.two.example.com

IP网络
  • 格式a.b.c.d/z,a.b.c.d是网络,z是子网掩码位(比如,192.168.0.0/24)

  • 格式a.b.c.d/netmask,a.b.c.d是网络,netmask是子网掩码(比如,192.168.100.8/255.255.255.04)

网络组

格式@group-name,group-name表示NIS网络组名称。更多关于NIS的信息,请访问 网络信息服务

10.2.2. 客户端文档

10.3. 配置

10.3.1. 服务端(Server3)

Server3执行
chown -R nginx:nginx /data
uid=`id -u nginx`
gid=`id -g nginx`
cat << EOF > /etc/exports
/data 11.11.11.0/24(rw,sync,all_squash,anonuid=$uid,anongid=$gid) 12.12.12.0/24(rw,sync,all_squash,anonuid=$uid,anongid=$gid) 14.14.14.0/24(rw,sync,all_squash,anonuid=$uid,anongid=$gid)
EOF

service rpcbind start
service nfs start

显示NFS服务端的共享列表

Server3输出
---
# showmount -e
Export list for Server3:
/data 14.14.14.0/24,12.12.12.0/24,11.11.11.0/24
---

显示以上结果,表示成功。

10.3.2. Server2客户端

显示NFS服务端的共享列表

Server2输出
# showmount -e 12.12.12.90
Export list for 12.12.12.90:
/data 14.14.14.0/24,12.12.12.0/24,11.11.11.0/24

挂载NFS共享目录/data到本地/nfs

Server2执行
mkdir /nfs
echo "12.12.12.90:/data  /nfs   nfs4      noatime,nolock,intr,bg,tcp     0 0" >>/etc/fstab
mount -a

最重要的是这两个参数:

bg

后台挂载。常见的情况是,CentOS开机过程中,可能网络有问题无法连接NFS服务端。此时,如果没指定bg,开机过程会卡很久

tcp

使用TCP协议挂载NFS。因为UDP协议允许丢包,可能会导致NFS数据丢失或不稳定。相反,TCP协议会校验接收的包数据是否完整有效

10.3.3. Server6&7客户端

显示NFS服务端的共享列表

Server6输出
# showmount -e 11.11.11.90
Export list for 11.11.11.90:
/data 14.14.14.0/24,12.12.12.0/24,11.11.11.0/24
Server7输出
# showmount -e 14.14.14.90
Export list for 14.14.14.90:
/data 14.14.14.0/24,12.12.12.0/24,11.11.11.0/24

挂载NFS共享目录/data到本地/nfs

Server6执行
mkdir /nfs
chown -R nginx:nginx /nfs
echo "11.11.11.90:/data  /nfs   nfs4      noatime,nolock,intr,bg,tcp     0 0" >>/etc/fstab
mount -a
Server7执行
mkdir /nfs
chown -R nginx:nginx /nfs
echo "14.14.14.90:/data  /nfs   nfs4      noatime,nolock,intr,bg,tcp     0 0" >>/etc/fstab
mount -a

检查是否挂载成功

Server6输出
# df -h
Filesystem         Size  Used Avail Use% Mounted on
/dev/sda1           48G  2.0G   44G   5% /
tmpfs              246M     0  246M   0% /dev/shm
/dev/sdb1          493G   70M  467G   1% /data
/dev/sda2          444G   70M  422G   1% /data2
11.11.11.90:/data  1.4T   70M  1.3T   1% /nfs
Server7输出
# df -h
Filesystem         Size  Used Avail Use% Mounted on
/dev/sda1           48G  2.0G   44G   5% /
tmpfs              246M     0  246M   0% /dev/shm
/dev/sdb1          493G   70M  467G   1% /data
/dev/sda2          444G   70M  422G   1% /data2
14.14.14.90:/data  1.4T   70M  1.3T   1% /nfs

看到/nfs已经挂载成功。

10.4. 测试

10.4.1. 检查挂载

在Server2&6&7上执行 df -h|grep '/nfs'

Server2输出
# df -h|grep '/nfs'
12.12.12.90:/data  1.4T   70M  1.3T   1% /nfs
Server6输出
# df -h|grep '/nfs'
11.11.11.90:/data  1.4T   70M  1.3T   1% /nfs
Server7输出
# df -h|grep '/nfs'
14.14.14.90:/data  1.4T   70M  1.3T   1% /nfs

看到/nfs,则表示已经挂载成功。

10.4.2. 读写文件

Server2&6&7执行
dd if=/dev/zero of=/nfs/`hostname`.file bs=1024 count=10000
"bs=1024 count=10000" 表示建立10M大小的空文件。 为了测试千兆网线的性能,可以修改为"bs=1024 count=1000000",建立1G的文件。 在建立完毕后,会显示"xxx MB/秒"的字样,基本可以确定网线速度。
Server2输出
# dd if=/dev/zero of=/nfs/`hostname`.file bs=1024 count=10000
记录了10000+0 的读入
记录了10000+0 的写出
10240000字节(10 MB)已复制,0.169929 秒,60.3 MB/秒
Server6输出
# dd if=/dev/zero of=/nfs/`hostname`.file bs=1024 count=10000
记录了10000+0 的读入
记录了10000+0 的写出
10240000字节(10 MB)已复制,0.372033 秒,27.5 MB/秒
Server7输出
# dd if=/dev/zero of=/nfs/`hostname`.file bs=1024 count=10000
记录了10000+0 的读入
记录了10000+0 的写出
10240000字节(10 MB)已复制,0.602732 秒,17.0 MB/秒

因为本书测试集群是在虚拟机上测试的,显示的文件读写速度和真实集群是不一致的。

虚拟机是"60.3 MB/秒"、"27.5 MB/秒"或"17.0 MB/秒",而真实集群(千兆网线)则会是"100.0 MB/秒"、"120.0 MB/秒"或"125.0 MB/秒" 等。

千兆网线传输文件的理论值是1000/8=125MB/秒。

最终,Server3的/data目录和Server2&6&7的/nfs目录会显示同样的内容。

Server3输出
# ls /data
Server2.file  Server6.file  Server7.file  lost+found
Server2&6&7输出
# ls /nfs
lost+found  Server2.file  Server6.file  Server7.file

至此,已经测试完毕。

11. 备份

为了降低学习难度,本书仅演示基于文件系统的同机房异机备份。

一般情况下,建议基于文件系统备份即可。对于数据安全要求非常高的情况,肯定是基于硬件和文件系统混合备份,冷&热备份也同时进行。

11.1. 常见的备份方式

11.1.1. 备份存储方式

按照备份存储方式,可以分为:

基于硬件

一般使用RAID阵列卡+硬盘做RAID 1/5,多个硬盘中损坏一个也不会导致数据丢失

  • 优点

    1. 实时备份

    2. 与操作系统无关

    3. 硬盘损坏时,如服务器支持热插拔硬盘,可以实现在线替换硬盘

    4. 服务器管理人员仅仅需要懂RAID阵列卡的设置,即可完成设置操作

    5. 备份操作不会占用硬盘IO

  • 缺点

    1. 结构无法横向扩展

    2. 数据无法迁移

    3. 占用硬盘容量。比如,2个500G的硬盘,最终只能使用500G

    4. RAID阵列卡需要占用一定的预算

    5. 恢复备份时,需要RAID相关的专业人士。需要进行恢复操作时,千万别让第三方人员代为操作。出现误操作导致数据丢失的风险非常大

    6. 断电等故障可能导致RAID硬件信息丢失,出现RAID无法识别等情况。此时,只能高价请专业数据恢复公司恢复数据

基于文件系统

通过文件复制方式,进行本机或者异机(异地)备份。
一般使用rsync做文件复制备份,而MySQL常见情况是使用主从复制做备份(虽然是基于MySQL本身的功能,实际上也是基于文件系统)。

  • 优点

    1. 灵活可控

    2. 低成本

    3. 简单

    4. 数据对人类可见,文件或目录等信息一目了然,确认数据完整性非常方便

    5. 不会占用硬盘容量

    6. 可以无限横向扩展,随意增删备份服务器

    7. 数据可以随意迁移

  • 缺点

    1. 对服务器管理人员要求较高

    2. 需要各个工具配合完成备份,可能出现更多的故障点

    3. 备份或恢复数据时,如果文件非常多或者很大,短时间内会占用硬盘IO

    4. 恢复备份时,需要非常熟悉各个环节,同第一点

11.1.2. 备份操作方式

按照备份操作方式,可以分为:

热备份

一般是指实时备份,不会丢失数据的备份操作。

冷备份

一般是指非实时的备份,会丢失数据的备份操作。比如,冷备份是一天备份一次。如果从冷备份恢复数据,则会丢失上次备份到下次备份之间的数据,也就是一天之内的数据。

11.2. 备份策略

重要的数据,一般指数据库。必须冷&热备份同时进行。比如MySQL服务器,需要同时做冷&热备份。

不太重要的数据,一般指网页文件。仅仅做冷备份即可。比如NFS存储服务器以及Nginx服务器上的网页文件,一般做冷备份即可。

NFS
  • 冷备份,由固定时间执行脚本实现

Nginx
  • 冷备份,由固定时间执行脚本实现

MySQL
  • 热备份,由MySQL的主-主复制+日志实现

  • 冷备份,由固定时间执行脚本实现

11.3. 设置备份

更多关于rsyncd.conf的信息,请访问 Manual page rsyncd.conf

11.3.1. NFS存储备份源

Server3执行
rm -f /etc/rsyncd.conf
wget -c http://fifilyu.github.io/halcpgb/file/Server3.etc.rsyncd.conf -O /etc/rsyncd.conf

rsync --daemon
echo "/usr/bin/rsync --daemon" >>/etc/rc.local

11.3.2. Nginx文件备份源

假设所有的动态网页文件全部存放在 /data 目录。
Server7执行
rm -f /etc/rsyncd.conf
wget -c http://fifilyu.github.io/halcpgb/file/Server7.etc.rsyncd.conf -O /etc/rsyncd.conf

rsync --daemon
echo "/usr/bin/rsync --daemon" >>/etc/rc.local

11.3.3. MySQL冷备份源

Server5执行
rm -f /etc/rsyncd.conf /opt/bak_db_dump.sh /opt/bak_db_binlog.sh
wget -c http://fifilyu.github.io/halcpgb/file/Server5.etc.rsyncd.conf -O /etc/rsyncd.conf
wget -c http://fifilyu.github.io/halcpgb/file/Server5.opt.bak_db_dump.sh -O /opt/bak_db_dump.sh
wget -c http://fifilyu.github.io/halcpgb/file/Server5.opt.bak_db_binlog.sh -O /opt/bak_db_binlog.sh

chmod 700 /opt/bak_db_dump.sh /opt/bak_db_binlog.sh

rsync --daemon
echo "/usr/bin/rsync --daemon" >>/etc/rc.local

# bak_db_binlog.sh必须在bak_db_dump.sh之前运行
echo "1 1 * * * /bin/sh /opt/bak_db_binlog.sh" >>/var/spool/cron/root

echo "1 2 * * 0 /bin/sh /opt/bak_db_dump.sh" >>/var/spool/cron/root

11.3.4. 备份客户端

Server2执行
rm -f /opt/rsync_all_bak.sh
wget -c http://fifilyu.github.io/halcpgb/file/Server2.opt.rsync_all_bak.sh -O /opt/rsync_all_bak.sh

chmod 700 /opt/rsync_all_bak.sh

echo "1 5 * * * /bin/sh /opt/rsync_all_bak.sh" >>/var/spool/cron/root

11.3.5. 确认设置

Rsync服务
  • 检查Rsync服务是否成功启动

Server3&5&7执行
ss -lpn|grep rsync
Server3输出
# ss -lpn|grep rsync
LISTEN     0      5               12.12.12.90:873                      *:*      users:(("rsync",1573,4))
Server5输出
# ss -lpn|grep rsync
LISTEN     0      5               10.10.10.102:873                      *:*      users:(("rsync",1560,4))
Server7输出
# ss -lpn|grep rsync
LISTEN     0      5               10.10.10.202:873                      *:*      users:(("rsync",1233,4))
计划任务
  • 检查MySQL服务器定时备份是否设置

Server5执行
crontab -l|egrep '(bak_db_binlog.sh)|(bak_db_dump.sh)'
Server5输出
# crontab -l|egrep '(bak_db_binlog.sh)|(bak_db_dump.sh)'
1 1 * * * /bin/sh /opt/bak_db_binlog.sh
1 2 * * 0 /bin/sh /opt/bak_db_dump.sh
  • 检查备份服务器定时备份是否设置

Server2执行
crontab -l|egrep rsync_all_bak.sh
Server2输出
# crontab -l|egrep rsync_all_bak.sh
1 5 * * * /bin/sh /opt/rsync_all_bak.sh

11.4. 使用备份

整个恢复过程看似简单,但实际操作会问题多多。限于篇幅,本书没有详细解读。
在生产服务器上,需要从备份数据恢复时,必须在专业人士的协助下操作,或由专业人士直接操作。操作前,一定要备份当前数据避免"次生灾害"。

11.4.1. 恢复MySQL备份

MySQL备份是导出(mysqldump)所有MySQL数据库数据为SQL文件,加上binlog日志来实现的。比如操作失误删除部分数据,要从备份恢复。请按照以下步骤操作:

  1. 备份当前MySQL的所有数据(通过mysqldump导出为SQL文件或者直接备份MySQL数据库物理文件)

  2. 修改当前MySQL服务器的配置文件my.cnf,禁用binlog,并重启MySQL

  3. 关闭所有主从复制

  4. 使用 scprsync 命令,将SQL文件传输到MySQL服务器,然后执行 mysql -uroot -prootpassword < 备份文件名.sql (导入时间和备份文件的大小成正比)

  5. 使用 mysqlbinlog 日志文件1 日志文件2 …​ 日志文件N |mysql -uroot -prootpassword ,按照日志回滚数据

  6. 日志回滚完毕后,启用binlog参数,重启MySQL,最后启动主从复制

以上步骤并非标准,需要根据实际情况调整。

更多关于binlog解释,请访问 The Binary Log

11.4.2. 恢复Web数据

Web数据备份包括NFS储存文件和Nginx服务器文件。按照以下步骤操作:

  1. 停止所有Web相关的服务,包括Nginx、LVS以及Keepalived等等,使服务器处于完全空闲状态

  2. 使用 rsync 命令,将文件从备份服务器传输到NFS储存服务器或Nginx服务器。比如NFS服务的 /data/image 目录丢失部分图片文件,直接使用 rsync 将备份服务器的 /data/backup/nfs/source/image 目录增量同步丢失的文件到NFS服务的 /data/image 目录即可

  3. 启动所有Web相关服务

以上步骤并非标准,需要根据实际情况调整。

12. 防火墙

12.1. 选择

我们选择操作系统提供的iptables软件作为防火墙。

为什么不使用硬件防火墙?

在日常的企业活动中,一般企业没有能力或者需求自己购买硬件防火墙,然后托管到电信机房中。 一般意义上的服务器安全都交由操作系统提供的防火墙软件来防护。 而电信机房托管的硬件防火墙更多时候,充当的是一个“阀门”。专门处理明显异常的网络流量,比如 DDoS攻击SYN攻击UDP攻击等等。往往这样的攻击都伴随超大的网络带宽输入,导致服务器甚至电信机房网络瘫痪。一般要防御这种类型的攻击,要购买硬件防火墙、超大的网络带宽(非常昂贵)以及托管服务,是非常不划算的。

所以,一般情况下,明显异常的网络流量都不需要自己管理,默认由电信公司提供最基本的网络稳定保障。我们也就专注服务器本身的事情。

除非一次性向电信公司购买(租用)一个机柜(12台1U服务器)的托管业务。否则,是没有机会在电信机房上自己的交换机或防火墙之类的设备的。

12.2. 设置

如果配置错误,被DROP的访问会记录在日志文件 /var/log/iptables.log 中。通过日志文件的内容排除错误。

12.2.1. Server1&2

Server1&2执行
#添加系统日志设置,将iptables日志写入/var/log/iptables.log
echo "kern.warning /var/log/iptables.log" >> /etc/rsyslog.conf
service rsyslog restart

#清空iptables默认链表规则
iptables -F

#放行本机网络
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 10.10.10.70 -j ACCEPT
iptables -A INPUT -s 10.10.10.80 -j ACCEPT

#放行千兆网线组建的内网网段
iptables -A INPUT -s 12.12.12.0/24 -j ACCEPT

#允许任何人SSH(22)端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

#允许公网访问本机的HTTP(80)端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

#允许访问本机以外的HTTP(80)、Rsync(873)以及MySQL(3306)端口
iptables -A INPUT -p tcp --sport 80 -j ACCEPT
iptables -A INPUT -p tcp --sport 873 -j ACCEPT
iptables -A INPUT -p tcp --sport 3306 -j ACCEPT

#允许Nginx服务器访问MySQL(3306)端口
iptables -A INPUT -p tcp -s 10.10.10.201 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 10.10.10.202 --dport 3306 -j ACCEPT

#将DROP信息写入日志文件/var/log/iptables.log
iptables -A INPUT -p tcp -j LOG --log-prefix "*** TCP-INPUT-DROP *** " --log-tcp-options --log-ip-options

#除以上规则外,公网不能访问本机任何TCP端口
iptables -A INPUT -p tcp -j DROP

#保存iptables规则到默认配置文件
service iptables save

12.2.2. Server3

Server3执行
#添加系统日志设置,将iptables日志写入/var/log/iptables.log
echo "kern.warning /var/log/iptables.log" >> /etc/rsyslog.conf
service rsyslog restart

#清空iptables默认链表规则
iptables -F

#放行本机网络
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 10.10.10.201 -j ACCEPT
iptables -A INPUT -s 10.10.10.202 -j ACCEPT

#放行千兆网线组建的内网网段
iptables -A INPUT -s 11.11.11.0/24 -j ACCEPT
iptables -A INPUT -s 12.12.12.0/24 -j ACCEPT

#允许任何人SSH(22)端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

#允许备份服务器访问Rsync(873)端口
iptables -A INPUT -p tcp -s 10.10.10.80 --dport 873 -j ACCEPT

#允许访问本机以外的HTTP(80)端口
iptables -A INPUT -p tcp --sport 80 -j ACCEPT

#将DROP信息写入日志文件/var/log/iptables.log
iptables -A INPUT -p tcp -j LOG --log-prefix "*** TCP-INPUT-DROP *** " --log-tcp-options --log-ip-options

#除以上规则外,公网不能访问本机任何TCP端口
iptables -A INPUT -p tcp -j DROP

#保存iptables规则到默认配置文件
service iptables save

12.2.3. Server4&5

Server4&5执行
#添加系统日志设置,将iptables日志写入/var/log/iptables.log
echo "kern.warning /var/log/iptables.log" >> /etc/rsyslog.conf
service rsyslog restart

#清空iptables默认链表规则
iptables -F

#放行本机网络
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 10.10.10.101 -j ACCEPT
iptables -A INPUT -s 10.10.10.102 -j ACCEPT

#放行千兆网线组建的内网网段
iptables -A INPUT -s 13.13.13.0/24 -j ACCEPT

#允许任何人SSH(22)端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

#允许备份服务器访问Rsync(873)端口
iptables -A INPUT -p tcp -s 10.10.10.80 --dport 873 -j ACCEPT

#允许访问本机以外的HTTP(80)端口
iptables -A INPUT -p tcp --sport 80 -j ACCEPT

#允许WEB相关的服务器访问MySQL(3306)端口
iptables -A INPUT -p tcp -s 10.10.10.70 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 10.10.10.80 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 10.10.10.100 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 10.10.10.201 --dport 3306 -j ACCEPT
iptables -A INPUT -p tcp -s 10.10.10.202 --dport 3306 -j ACCEPT

#将DROP信息写入日志文件/var/log/iptables.log
iptables -A INPUT -p tcp -j LOG --log-prefix "*** TCP-INPUT-DROP *** " --log-tcp-options --log-ip-options

#除以上规则外,公网不能访问本机任何TCP端口
iptables -A INPUT -p tcp -j DROP

#保存iptables规则到默认配置文件
service iptables save

12.2.4. Server6&7

Server6&7执行
#添加系统日志设置,将iptables日志写入/var/log/iptables.log
echo "kern.warning /var/log/iptables.log" >> /etc/rsyslog.conf
service rsyslog restart

#清空iptables默认链表规则
iptables -F

#放行本机网络
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -s 10.10.10.201 -j ACCEPT
iptables -A INPUT -s 10.10.10.202 -j ACCEPT

#允许任何人SSH(22)端口
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

#允许备份服务器访问Rsync(873)端口
iptables -A INPUT -p tcp -s 10.10.10.80 --dport 873 -j ACCEPT

#禁止访问本机公网IP上监听的HTTP(80)端口,仅允许访问本机内网IP上监听的HTTP(80)端口
iptables -A INPUT -p tcp -s 192.168.1.200 --dport 80 -j DROP
iptables -A INPUT -p tcp -d 192.168.1.202 --dport 80 -j DROP
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

#允许访问本机以外的HTTP(80)和MySQL(3306)端口
iptables -A INPUT -p tcp --sport 80 -j ACCEPT
iptables -A INPUT -p tcp --sport 3306 -j ACCEPT

#将DROP信息写入日志文件/var/log/iptables.log
iptables -A INPUT -p tcp -j LOG --log-prefix "*** TCP-INPUT-DROP *** " --log-tcp-options --log-ip-options

#除以上规则外,公网不能访问本机任何TCP端口
iptables -A INPUT -p tcp -j DROP

#保存iptables规则到默认配置文件
service iptables save