1 Star 0 Fork 1

ywangji / 面试

forked from Pipi / 面试 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
项目.md 114.88 KB
一键复制 编辑 原始数据 按行查看 历史
Pipi 提交于 2021-08-13 12:41 . R

项目一、批量卸载组网用户

坏境:华为有自己的操作系统LMT,该操作系统主要用于控制和管理一个地区的通话,基于华为自己开发MML开发语言;

​ 我拿到的需求是,在当前版本上面新建一个命令set xxx,来实现批量卸载一个pool组网中的MSISDN和IMS用户

​ 交代一下通信的基本背景,pool组网相当于一个池子,这个池子的用户

定义 组成
MSISDN 用户的手机号 CC+NDC+SN CC国家码中国86
NDC就是139、137那些,国内网络接入号
SN用户号码,手机号后8位。
IMSI 国际移动用户识别码,即 sim 卡的识别码 IMSI共有15位,其结构如下:
MCC+MNC+MIN
MCC:Mobile Country Code,移动国家码,共3位,中国为460;
MNC:Mobile Network Code,移动网络码,共2位,移动为00,一个典型的IMSI号码为460030912121001;
MIN共有10位,其结构如下: 09+M0M1M2M3+ABCD
其中的M0M1M2M3和MDN号码中的H0H1H2H3可存在对应关系,ABCD四位为自由分配。
可以看出IMSI在MIN号码前加了MCC,可以区别出每个用户的来自的国家,因此可以实现国际漫游。在同一个国家内,如果有多个CDMA运营商,可以通过MNC来进行区别说白了就是网络内部识别SIM的唯一号码。
  • 分析要添加的命令,set batchoffload 命令因为是要实现批量卸载,而想要做到批量卸载用户就需要用户输入具体卸载规则,才会匹配一堆用户;

    这个规则肯定要自己添加上,想到了这个肯定是和sql结合

    分析整个逻辑得出得出:set batchoffload只是一个开关,这条命令需要后面跟上选项和确认,这个选项对应卸载哪个规则,确认对应执行卸载;而背后的sql文件才是关键,匹配pool组网中的用户

    因此除了在操作系统上要添加该命令还要添加4个命令来管理sql,增删改查

  • 分析sql文件对应的表,和增删改改查逻辑

    所需要的表字段,包括id,用户类型,具体规则

    分析sql文件,每个sql文件需要传入参数(用户输入命令后,会再跟一些选项),就是现在页面呈现的效果

    添加规则:用户类型,规则。

    查看规则:无。

    修改规则:id,用户类型,规则。

    删除规则:id

  • 分析的只是内部的实现原理,接下来要把主页面展现出来,主界面的实现要通话模板,这个机制是公司内部的,主要是填写建立的表的信息,表字段,设计的参数,每个sql文件的信息,数据类型等等。

  • 把模板填写完成,导出包,看系统主页面是否显示是否按照预期的,测试模板是否正确

以上几步都是问题出的最多的,因为要反复沟通,是否合理,每个过程要实现的页面都要申请,流程

  • 写sql文件:分析每个sql文件具体书写情况。

    添加:发现是否存在,添加的是否合法。

    修改:修改的是否合法。

    删除:删除是否已经是正在卸载的状态

  • 先测试sql文件书写情况,看sql文件是否按预期实现。

  • 写主代码,配合sql文件,调通主程序,完善异常情况。

  • 分析异常情况:1.如果一个人要卸载100万条,而另外一个人要改或者使用,这是和se协商过的,理解成会加锁,不需要负责

    ​ 2.自增规则,12345,删除了2,自增的话会变成6,慢慢的,前面空的规则越来越多,这种情况忽略

    ​ 3.配置不支持正则

    ​ 4.查看是否已经存在,添加的规则合理。12xx,再添加12xxxxx不可以,反之可以

1.消除pclint告警--学代码规范

如果能够在代码提交测试之前发现这些潜在的错误,就能够极大地减轻测试人员的压力,减少软件项目的除错成本,可是传统的C/C++编译器对此已经无能为力,这个任务只能由专用的代码检查工具完成。

​ 1.传参必须再赋值使用

​ 2.地址长度不够用

​ 3.代码缩进不符合规范

​ 4.库函数使用不规范,例如malloc和strcpy

2.开发mml命令,总结组内mml开发语言的流程

3.处理问题单

二、ansbile

Ansible介绍

1.ansible简介

Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具。

它用Python写成,类似于saltstack和Puppet,但是有一个不同和优点是我们不需要在节点中安装任何客户端。

它使用SSH来和节点进行通信。Ansible基于 Python paramiko 开发,分布式,无需客户端,轻量级,配置语法使用 YMAL 及 Jinja2模板语言,更强的远程命令执行操作。

2.ansible 的特点

  1. 部署简单,没有客户端,只需在主控端部署Ansible环境,被控端无需做任何操作;
  2. 模块化:调用特定的模块,完成特定任务
  3. 默认使用SSH协议对设备进行管理;
  4. 主从集中化管理;
  5. 配置简单、功能强大、扩展性强;
  6. 支持API及自定义模块,可通过Python轻松扩展;
  7. 通过Playbooks来定制强大的配置、状态管理
  8. 对云计算平台、大数据都有很好的支持;
  9. 具有幂等性:一个操作在一个主机上执行一遍和执行N遍的结果是一样的

3.ansible原理

ansible架构

  • 核心:ansible
  • 核心模块(Core Modules):这些都是ansible自带的模块
  • 扩展模块(Custom Modules):如果核心模块不足以完成某种功能,可以添加扩展模块
  • 插件(Plugins):完成模块功能的补充
  • 剧本(Playbooks):ansible的任务配置文件,将多个任务定义在剧本中,由ansible自动执行
  • 连接插件(Connectior Plugins):ansible基于连接插件连接到各个主机上,虽然ansible是使用ssh连接到各个主机的,但是它还支持其他的连接方法,所以需要有连接插件
  • 主机群(Host Inventory):主机清单,定义ansible管理的主机

1.部署Ansible

1.1准备基础环境

1. 控制节点操作

1.1做域名解析

1.2配置SSH密钥实现免密码登录

​ Ansible是基于SSH远程的原理实现远程控制,如果控制端主机无法免密登录被管理端主机,后续的所有试验都会失败!!

1.3 部署Ansible软件。

2. 被控制节点要求:

  • Ansible默认通过SSH协议管理机器
  • 被管理主机要开启SSH服务,并允许控制主机登录
  • 被管理主机需要安装有Python

1.2 修改配置文件

主配置文件说明:

主配置文件ansible.cfg(主配置文件的内容可以参考/etc/ansible/ansible.cfg)

ansible配置文件查找顺序

首先检测ANSIBLE_CONFIG变量定义的配置文件

其次检查当前目录下的./ansible.cfg文件

再次检查当前用户家目录下~/ansible.cfg文件

最后检查/etc/ansible/ansible.cfg文件

1.2.1 修改主配置文件

[root@control ~]# mkdir  ~/ansible
[root@control ~]# vim  ~/ansible/ansible.cfg
[defaults]
inventory = ~/ansible/inventory             #主机清单配置文件(inventory可以是任意文件名),英语词汇:inventory(清单、财产清单)
#forks = 5                                    #ssh并发数量
#ask_pass = True                             #使用密钥还是密码远程,True代表使用密码
#host_key_checking = False                  #是否校验密钥(第一次ssh时是否提示yes/no)

1.2.2 修改主机清单文件

(清单文件名必须与主配置文件inventory定义的一致)
[root@control ~]# vim  ~/ansible/inventory
[test]					#定义主机组(组名称任意)
node1					#定义组中的具体主机,组中包括一台主机node1
[proxy]                    #定义主机组(组名称任意),英语词汇:proxy(代理人,委托人)
node2                      #proxy组中包括一台主机node2
[webserver]
node[3:4]                 #这里的node[3:4]等同于node3和node4
[database]
node5
[cluster:children]		#嵌套组(children为关键字),不需要也可以不创建嵌套组
webserver                  #嵌套组可以在组中包含其他组
database

2. Ansible ad-hoc 命令

ansible  主机集合   -m    模块名    -a    "参数"

[root@control ~]# cd  ~/ansible							#非常重要,必须把主控节点切到这个目录下才能运行
ansible-doc-l			#列出所有模块
ansible-doc  yum		#查看模块帮助

1)查看主机列表

[root@control ansible]# ansible  all  --list-hosts           #查看所有主机列表
  1. 测试远程主机是否能ping通。
[root@control ansible]# ansible  node1  -m  ping          	#调用ping模块
[root@control ansible]# ansible  node1,webserver  -m  ping		#当需要远程多个主机或者多个组时,中间使用逗号分隔!!!

Shell模块

command和shell模块的区别,command不支持bash的特性(bash有哪些特性可以参考Shell课程第一天的PPT),如管道和重定向等功能,但是shell模块可以支持。

不可以使用shell模块执行交互命令,如vim、top等。

script模块

script模块会把-a后面的脚本拷贝到被管理端主机,然后执行这个脚本。

[root@control ansible]# ansible  test  -m script  -a  "./test.sh"    
#test是主机组的名称,-m调用script模块,-a后面的./test.sh是上面创建脚本的相对路径和文件名
#./是当前目录的意思,在当前目录下有个脚本叫test.sh

file模块

file模块可以创建文件、目录、链接;修改权限与属性等(ansible-doc file)

[root@control ansible]# ansible  test  -m  file  -a  "path=/tmp/file.txt 	state=touch/directory/absent"	
[root@control ansible]# ansible test   -m  file -a "src=/etc/hosts  path=/tmp/host.txt state=link" 
[root@control ansible]# ansible  test  -m  file -a  "path=/tmp/file.txt  owner=sshd  group=adm  mode=0777"

copy模块

copy模块可以将文件拷贝到远程主机 (ansible-doc copy)。

ansible test -m copy -a "src=~/a3.txt dest=/root/"
#把管理端本机的a3.txt文件,拷贝到test组中所有主机的/root/目录
#src代表源文件,dest代表目标文件

fetch模块

fetch模块与copy类似,但是作用相反,可以将其他主机的文件拷贝到本地(ansible-doc fetch)。

[root@control ansible]# ansible test -m fetch -a "src=/etc/hostname   dest=~/"
#将远程test组中所有主机的hostname文件下载到本地家目录
#src代表源文件,dest代表目标文件

lineinfile|replace模块

在修改单个文件的单行内容时可以使用lineinfile模块。 lineinfile会替换一整行,replace可以替换关键词(ansible-doc replace)。

[root@control ansible]# ansible 主机名 -m lineinfile  -a "path=路径  line='内容'"
#在/路径文件中添加一行内容,默认添加到最后,line后面跟的是需要添加的文件内容

[root@control ansible]# ansible test -m lineinfile -a "path=路径 line='insert' insertafter='Kernel'"
#将line后面的内容插入到/etc/issue文件中Kernel行的后面
[root@control ansible]# ansible test -m lineinfile  -a "path=/etc/issue  line='hello world'"
#在/etc/issue文件中添加一行内容hello world,默认添加到最后,line后面跟的是需要添加的文件内容

[root@control ansible]# ansible test -m lineinfile -a "path=/etc/issue line='insert' insertafter='Kernel'"
#将line后面的内容插入到/etc/issue文件中Kernel行的后面

[root@control ansible]# ansible test -m replace -a  "path=/etc/issue.net  regexp=Kernel  replace=Ocean"
#将node1主机中/etc/issue.net文件全文所有的Kernel替换为Ocean
#regexp后面是需要替换的旧内容;replace后面是需要替换的新内容

user模块

user模块可以实现Linux系统账户管理(ansible-doc user),新建,删除权限,改密码,删除。

[root@control ansible]# ansible  test  -m user -a "name=tuser1  【uid=1010 group=adm groups=daemon,root home=/home/tuser2】"
#远程test组中的所有主机并创建系统账户tuser1,默认state的值为present,代表创建用户
[root@control ansible]# ansible test -m user -a "name=tuser1 password={{'abc'| password_hash('sha512')}}"
[root@control ansible]# ansible test -m user -a "name=tuser1 state=absent"
#删除账户tuser1,state=absent代表删除账户的意思,name指定要删除的用户名是什么
#账户的家目录不会被删除,相当于执行userdel tuser1

[root@control ansible]# ansible test -m user -a "name=tuser2 state=absent remove=true"
#删除tuser2账户同时删除家目录、邮箱,相当于执行userdel  -r  tuser2

yum_repository模块

使用yum_repository可以创建或修改yum源配置文件(ansible-doc yum_repository)。

ansible test -m yum_repository -a "name=myyum description=test baseurl=ftp://192.168.4.254/centos gpgcheck=yes gpgkey=…"															#修改yum源文件内容
ansible test -m yum_repository -a "name=myyum state=absent"							#删除yum源文件myyum

yum模块

使用yum模块可以安装、卸载、升级软件包(ansible-doc yum),state: present(安装)|absent(卸载)|latest(升级)。

[root@control ansible]# ansible test -m yum -a "name=unzip state=present/latest/absent"

service模块(服务)

service为服务管理模块(启动、关闭、重启服务等),

state:started|stopped|restarted,enabled:yes设置开机启动。

[root@control ansible]# ansible test -m yum -a "name=httpd state=started|stopped|restarted"

逻辑卷相关模块

lvg模块:创建、删除卷组(VG),修改卷组大小,

state:present(创建)|absent(删除)。

lvol模块:创建、删除逻辑卷(LV),修改逻辑卷大小,

state:present(创建)|absent(删除)。

3.sudo提权

sudo(superuser or another do)让普通用户可以以超级管理员或其他人的身份执行命令。想要实现每个主机上的alice用户都可以和root的权限一样

sudo基本流程如下:

  1. 管理员需要先授权(修改/etc/sudoers文件)
  2. 普通用户以sudo的形式执行命令

授权格式如下

用户或组 主机列表=(提权身份) [NOPASSWD]:命令列表

注意事项:命令需要写绝对路径,对组授权需要在组名称前面加%。

[root@control ansible]# ansible all -m lineinfile -a "path=/etc/sudoers line='alice  ALL=(ALL) 	NOPASSWD:ALL'"

4. yaml语句

1.YAML定义

  • YAML是一个可读性高、用来表达数据序列的格式语言
  • YAML以数据为中心,重点描述数据的关系和结构

2.YAML的格式:

  • "#"代表注释,一般第一行为三个横杠(---)
  • 键值(key/value)对使用":"表示,数组使用"-"表示
  • key和value之间使用":"分隔
  • ":"后面必须有空格
  • 一般缩进由两个或以上空格组成
  • 相同层级的缩进必须对齐,缩进代表层级关系
  • 全文不可以使用tab键
  • 区分大小写
  • 扩展名为yml或者yaml
  • 跨行数据需要使用>或者|,其中|会保留换行符

5. playbook

Playbook语法格式要求如下:

  • playbook采用YAML格式编写

  • playbook文件中由一个或多个play组成

  • 每个play中可以包含:

    hosts(主机)、tasks(任务)、vars(变量)等元素组成, 使用ansible-playbook命令运行playbook剧本

vim  文件名.yml
---
- hosts: 主机或组(逗号分隔)
  tasks:
    任务1
    任务2
- hosts: 主机或组(逗号分隔)
  tasks:
    - name: This is my first playbook     #name后面的内容可以任意,就是一个标识功能
        ping:
    - name: Run a shell command
        shell: touch ~/shell.txt
#执行:ansible-playbook ~/ansible/test.yml  -f 5        **-f选项自定义并发量**。

6.Ansible进阶

6.1特殊模块

setup模块

ansible_facts用于采集被管理设备的系统信息,所有收集的信息都被保存在变量中,每次执行playbook默认第一个任务就是Gathering Facts,使用setup模块可以查看收集到的facts信息。

[root@control ansible]# ansible test -m setup
192.168.4.10 | SUCCESS => {
"ansible_facts": {
   "ansible_all_ipv4_addresses": [
… 省略部分内容…

试试自己找出下列变量:

  • ansible_all_ipv4_addresses #IP地址
  • ansible_bios_version #主板BIOS版本
  • ansible_memtotal_mb #总内存
  • ansible_hostname #主机名
  • ansible_fqdn #主机的域名
  • ansible_devices.sda.partitions.sda1.size #某个磁盘分区的大小

debug模块

debug模块可以显示变量的值,可以辅助排错,通过msg可以显示变量的值,变量需要使用{{}}扩起来。

[root@control ansible]# vim ~/ansible/debug.yml
---
- hosts: test
  tasks:
    - debug:
        msg: "主机名是:{{ ansible_hostname }}"
    - debug:
        msg: "总内存大小:{{ ansible_memtotal_mb }}"
#备注调用debug模块显示某些具体的变量值
#debug模块可以显示变量的值,可以辅助排错

6.2 定义变量的方法

1)Inventory变量

(在主机清单配置文件中定义变量)。
[root@control ansible]# vim ~/ansible/inventory
[test]
node1  iname="nb" 		#备注,在node1主机后面给该主机添加变量iname,值为nb.

#(在剧本中需要调用变量是要使用{{}}),name: "{{ iname }}"

2)Host Facts变量

ansible收集的系统信息,setup模块能直接查看到

3)Playbook变量

(使用vars关键词可以在playbook内定义变量)
---
- hosts: test
  vars:                                     #vars是关键词,用来定义变量用的
    iname: heal                            #具体变量名是iname,值是heal
    ipass: '123456'                       #再定义一个变量名是ipass,值是12345

4)Playbook提示变量

(根据提示输入变量的值)
[root@control ansible]# vim ~/ansible/prompt_var.yml
---
- hosts: test
  vars_prompt:                         #vars_prompt是关键词,定义提示变量
    - name: iname                      #通过name定义变量名为iname
      prompt: "请输入用户名"           #执行剧本时提示信息
      private: no                      #是否是隐私数据,no代表不是(屏幕可以显示)                                              
    - name: ipasswd                   #通过name再定义变量,变量名为ipasswd
      prompt: "请输入密码"             #执行剧本时提示信息
      private: yes                     #是否是隐私数据,yes代表是(隐私数据屏幕不显示)                                              
  tasks:                               #定义剧本需要执行的任务
    - name: Create a user.           #定义第一个任务的描述信息
      user:                            #调用user模块创建用户,设置用户密码
        name: "{{ iname }}"          #用户名是前面创建的变量iname
        password: "{{ ipasswd | password_hash('sha512') }}"
#密码是前面定义的变量ipasswd,密码管道给password_hash加密.

5)单独定义个变量文件

在playbook中用vars_files调用该文件,当变量比较多时,专门定义一个文件用来存变量
[root@control ansible]# vim ~/ansible/file_var.yml
---
- hosts: test
  vars_files: variables.yml             #当变量比较多时,专门定义一个文件用来存变量
  tasks:
    - name: create user.
      user:
        name: "{{ iname }}"
        password: "{{ ipass | password_hash('sha512') }}"
#调用user模块创建用户
#用户名是变量文件variables.yml中定义的变量iname,密码也是变量文件中定义的变量
[root@control ansible]# vim  ~/ansible/variables.yml
---
iname: cloud
ipass: '123456'

6)执行ansible-playbook -e参数定义变量

[root@control ansible]# ansible-playbook command_var.yml -e iname="beth" -e ipass="123456"
#可以在剧本里直接调用

6.3 模块应用

firewalld模块

使用firewalld模块可以配置防火墙策略。

[root@control ~]#  vim ~/ansible/firewall.yml
---
- hosts: test                           #hosts定义需要远程的主机
  tasks:                                 #tasks定义需要执行哪些任务
    - name: install firewalld.         #name为第一个任务定义描述信息
      yum:                               #第一个任务调用yum模块安装软件
        name: firewalld                 #需要安装的软件名称为firewalld
        state: present                  #state等于present代表安装软件
    - name: run firewalld.             #定义第二个任务的描述信息
      service:                          #第二个任务调用service模块启动服务
        name: firewalld                #启动的服务名称为firewalld
        state: started                 #state等于started代表启动服务
        enabled: yes                    #enabled等于yes是设置服务为开机自启动
    - name: set firewalld rule.       #第三个任务的描述信息
      firewalld:                        #第三个任务调用firewalld模块设置防火墙规则
        port: 80/tcp                    #在防火墙规则中添加一个放行tcp,80端口的规则
        permanent: yes                  #permaenent 是设置永久规则
        immediate: yes                  #immediate 是让规则立刻生效
        state: enabled                  #state等于enabled是添加防火墙规则
#最终:在默认zone中添加一条放行80端口的规则

template模块

copy模块可以将一个文件拷贝给远程主机,但是如果希望每个拷贝的文件内容都不一样呢?如何给所有web主机拷贝index.html内容是各自的IP地址?

Ansible可以利用Jinja2模板引擎读取变量,之前在playbook中调用变量,也是Jinja2的功能,Jinja2模块的表达式包含在分隔符"{{ }}"内。

这里,我们给webserver主机拷贝首页,要求每个主机内容不同。

[root@control ansible]# mkdir ~/ansible/template

[root@control ansible]# vim ~/ansible/template/index.html
Welcome to {{ansible_hostname}} on {{ ansible_eth0.ipv4.address }}. 
#注意网卡名称根据实际情况填写,不可以完全照抄,不知道网卡名可以通过ip a s查询!
#{{ansible_hostname}}和{{ ansible_eth0.ipv4.address }}是ansible自动的facts变量。   

编写Playbook将网页模板文件拷贝到远程主机。

[root@control ansible]# vim ~/ansible/template.yml
---
- hosts: webserver
  tasks:
    - name: use template copy index.html to webserver.
      template:
        src: ~/ansible/template/index.html
        dest: /tmp/index.html
#hosts定义需要远程的目标主机是谁;tasks定义需要执行的任务是什么
#- name定义任务的描述信息;任务需要调用的模块是template模块
#template模块需要两个参数,src指定需要拷贝的源文件,dest指定需要拷贝的目标位置
#src: ~/ansible/template/index.html是上面创建的文件,文件中包含变量
#dest: /tmp/index.html拷贝到目标主机放在/tmp目录下

error错误处理

默认ansible在遇到error会立刻停止playbook,使用ignore_errors可以忽略错误,继续后续的任务。

下面这个Playbook在执行时因为忽略了错误(针对某一个任务),不会被中断。

[root@control ansible]# vim ~/ansible/error.yml
---
- hosts: test
  ignore_errors: true      #针对playbook全局忽略错误      
  tasks:
    - name: start a service that does not exist.
      service:
        name: hehe
        state: started
      ignore_errors: true       #针对某一个任务忽略错误(ignore_errors是关键词)                          
    - name: touch a file.
      file:
        path: /tmp/service.txt
        state: touch

handlers模块(触发)

在剧本中tasks用来定义任务(一定会执行),handlers也可以定义任务(不一定执行),handlers任务要想执行必须要被别人触发才能执行

实例草稿:
---
- hosts: test
  tasks:
    - 任务1
	  nofify:任务5
	- 任务2
  handlers:
    - 任务5
	- 任务6
#tasks状态为changed时才会通过notify触发执行handlers下面的任务,
#所以多次执行该剧本时,handlers任务不会被重复执行,

when条件判断

when可以定义判断条件,条件为真时才执行某个任务。

常见条件操作符有:==、!=、>、>=、<、<=。

多个条件可以使用and(并且)或or(或者)分割,when表达式中调用变量不要使用{{ }}。

[root@control ansible]# vim ~/ansible/when_1.yml
---
- hosts: test
  tasks:
    - name: check memory size.
      service:
        name: NetworkManager
        state: stopped
      when: >			#YAML的语法格式中>支持多行输入,但不保留换行符。
      ansible_memfree_mb < 700 
      【ansible_distribution == "RedHat"   and ansible_distribution_major_version == "8"

block任务块(多个条件)

如果我们需要当条件满足时执行N个任务,我们可以给N个任务后面都加when判断(但是很麻烦),此时可以使用block定义一个任务块,当条件满足时执行整个任务块.

任务块就是把一组任务合并为一个任务组,使用block语句可以将多个任务合并为一个任务组。

[root@control ansible]# vim ~/ansible/block_1.yml
---
- hosts: test
  tasks:
    - name: define a group of tasks.
      block:                                          #block是关键词,定义任务组
        - name: install httpd                       #任务组中的第一个任务
          yum:                                        #调用yum模块安装httpd软件包
            name: httpd
            state: present
        - name: start httpd                          #任务组中的第二个任务
          service:                                    #调用service模块启动httpd服务
            name: httpd
            state: started
      when: ansible_distribution == "RedHat"       #仅当条件满足再执行任务组
#注意:when和block是对齐的,他们在一个级别,当条件满足时要执行的是任务组(不是某一个任务)
#判断条件是看远程的目标主机使用的Linux发行版本是否是RedHat.

对于block任务块,我们可以使用rescue语句定义在block任务执行失败时要执行的其他任务,

还可以使用always语句定义无论block任务是否成功,都要执行的任务。

[root@control ansible]# vim ~/ansible/block_2.yml
---
- hosts: test
  tasks:
    - block:
        - name: touch a file test1.txt
          file:
            name: /tmp/test1.txt      #如果修改为/tmp/xyz/test1.txt就无法创建成功                        
            state: touch
      rescue:
        - name: touch a file test2.txt
          file:
            name: /tmp/test2.txt
            state: touch
      always:
        - name: touch a file test3.txt
          file:
            name: /tmp/test3.txt
            state: touch
#默认在/tmp/目录下创建test1.txt会成功,所以不执行rescue(创建test2.txt)
#如果我们把block中的任务改为创建/tmp/xyz/test1.txt(因为没有xyz目录所以会失败)
#当block默认任务失败时就执行rescue任务(创建test2.txt)
#但是不管block任务是否成功都会执行always任务(创建test3.txt)

loop循环

相同模块需要反复被执行怎么处理?使用loop循环可以避免重复。

编写Playbook,循环创建目录。

[root@control ansible]# vim ~/ansible/simple_loop.yml
---
- hosts: test
  tasks:
    - name: mkdir multi directory.
      file:
        path=/tmp/{{item}}       #注意,item是关键字,调用loop循环的值                                
        state=directory
      loop:                       #loop是关键词,定义循环的值,下面是具体的值
        - School
        - Legend
        - Life
#最终在/tmp目录下创建三个子目录.file模块被反复执行了三次。
#mkdir  /tmp/School;  mkdir  /tmp/Legend;   mkdir  /tmp/Life。

6.4 加密敏感数据ansible-vault

使用ansible-vault处理敏感数据

加密敏感数据

encrypt(加密)、decrypt(解密)、view(查看)。

[root@control ansible]# ansible-vault encrypt data.txt      #加密文件
[root@control ansible]# ansible-vault view data.txt         #查看加密文件

修改密码(rekey)

[root@control ansible]# ansible-vault rekey data.txt             #修改密码
Vault password: <旧密码>
New Vault password: <新密码>
Confirm New Vault password:<确认新密码>

解密文件

[root@control ansible]# ansible-vault decrypt data.txt      #解密文件
[root@control ansible]# cat data.txt

使用密码文件

加密、解密每次都输入密码很麻烦,可以将密码写入文件。

[root@control ansible]# echo "I'm secret data" > data.txt       #需要加密的敏感数据
[root@control ansible]# echo 123456 > pass.txt                   #加密的密码
[root@control ansible]# ansible-vault  encrypt --vault-id=pass.txt  data.txt 
[root@control ansible]# cat data.txt
[root@control ansible]# ansible-vault decrypt --vault-id=pass.txt data.txt
[root@control ansible]# cat data.txt

6.5 Ansible Roles

用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。

roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

三、Zabbix

1.Zabbix介绍

Zabbix简介

zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。 zabbix由zabbix server与可选组件zabbix agent两部门组成。 zabbix server可以通过SNMP,zabbix agent,ping,端口监视等方法提供对远程服务器/网络状态的监视。 zabbix agent需要安装在被监视的目标服务器上,它主要完成对硬件信息或与操作系统有关的内存,CPU等信息的收集。

zabbix的主要特点

安装与配置简单,学习成本低

支持多语言(包括中文)

免费开源

自动发现服务器与网络设备

分布式监视以及WEB集中管理功能

可以无agent监视

用户安全认证和柔软的授权方式

通过WEB界面设置或查看监视结果

email等通知功能

Zabbix主要功能

CPU负荷,内存使用,磁盘使用,网络状况,端口监视,日志监视

各组件介绍

zabbix agent: 部署在被监控主机上,负责被监控主机的数据,并将数据发送给zabbix server。 zabbix server: 负责接收agent发送的报告信息,并且负责组织配置信息、统计信息、操作数据等。 zabbix database:用于存储所有zabbix的配置信息、监控数据的数据库。 zabbix web:zabbix的web界面,管理员通过web界面管理zabbix配置以及查看zabbix相关监控信息,可以单独部署在独立的服务器上。 zabbix proxy:可选组件,用于分布式监控环境中,zabbix proxy代表server端,完成局部区域内的信息收集,最终统一发往server端。Zabbix proxy 可以替Zabbix Server收集性能和可用性数据。Proxy代理服务器是Zabbix软件可选择部署的一部分;当然,Proxy代理服务器可以帮助单台Zabbix Server分担负载压力。

工作原理

Zabbix有两种监控模式:

1、被动模式。(默认模式) zabbix_agent等待zabbix_server发送指令后再去获取监控数据; zabbix_server会按照预设规则,周期性的向zabbix_agent索取数据。 这种模式下,最大的问题是,增加了zabbix_server负载。 当agent数量达到一定量级时,zabbix_server不能及时获取到最新的监控数据,影响我们判断分析。 2、主动模式。 zabbix_agent会主动采集数据并发送给zabbix_server。 使用主动模式,在一定程度上减轻了zabbix_server负载。 zabbix_server接收到监控数据后,将数据存储到数据库mysql中,经过php+apache处理,最终在web界面进行展现和绘图。

主机(host):                     被监控的网络设备,可以写IP或者DNS;
主机组(host group):        主机组用于管理主机,可以批量设置权限;
监控项(item):                 具体监控项,items值由独立的keys进行识别;
触发器(trigger):             为某个items设置触发器,达到触发器会执行action动作;
事件(event):                  例如达到某个触发器,称之为一个事件;
动作(action):                 对于特定事件事先定义的处理方法,默认可以发送信息及发送命令;
报警升级(escalation):     发送警报或执行远程命令的自定义方案,如隔5分钟发送一次警报,共发送5次等。
媒介(media):                 发送通知的方式,可以支持Mail、SMS、Scripts等;
通知(notification):         通过设置的媒介向用户发送的有关某事件的信息;
远程命令                达到触发器,可以在被监控端执行命令;
模板(template):              可以快速监控被监控端,模块包含:item、trigger、graph、screen、application;
web场景(web scennario)用于检测web站点可用性,监控HTTP关键词;
web前端(frontend):       Zabbix的web接口;
图形(graph)                    监控图像;
屏幕(screens)                  屏幕显示;
幻灯(slide show)             幻灯显示

2. Zabbix部署

部署监控服务器

  • 安装LNMP环境

    Zabbix监控管理控制台需要通过Web页面展示出来,并且还需要使用MySQL来存储数据,因此需要先为Zabbix准备基础LNMP环境。

  • 修改Nginx配置文件

    配置Nginx支持PHP动态网站,因为有大量PHP脚本需要执行,因此还需要开启Nginx的各种fastcgi缓存,加速PHP脚本的执行速度。

    #缓存php生成的页面内容,8个16k #缓存php生产的头部信息,32k #连接PHP的超时时间, #发送请求的超时时间, #读取请求的超时时间,300秒

  • 关闭SELinux与防火墙,启动服务

  • 源码安装Zabbix Server

    多数源码包都是需要依赖包的,zabbix也一样,源码编译前需要先安装相关依赖包。

  • 创建并初始化数据库

创建数据库,并授权用户密码,传入的数据都保存在这个库中,最好实现同步一下,数据库,用户密码和配置文件一一对应

  • 修改zabbix_server配置并启动监控服务

    修改Zabbix_server配置文件,设置数据库相关参数,启动Zabbix_server服务(vim /usr/local/etc/zabbix_server.conf)

    定义哪台主机为数据库主机,localhost为本机,#95行,设置数据库名称,日志的位置,排错使用

  • 修改Zabbix_agent配置文件,启动Zabbix_agent服务,

监控本机:允许哪些主机监控本机,允许哪些主机通过主动模式监控本机,设置日志文件

  • 浏览器访问Zabbix_server服务器的Web页面

    #第一次访问,初始化PHP页面会检查计算机环境是否满足要求,如果不满足会给出修改建议 #默认会提示PHP的配置不满足环境要求,需要修改PHP配置文件

  • 修改PHP配置文件

    最大执行时间,POST数据最大容量,服务器接收数据的时间限制,内存容量限制

部署被监控主机

  • 源码安装Zabbix agent软件

  • 修改agent配置文件,启动Agent

    允许哪些主机监控本机,允许哪些主机通过主动模式监控本机,设置日志文件

3.配置及使用Zabbix监控系统

添加主机,创建模板,绑定

1.在zabbix图形页面——配置——主机——创建主机(定义主机名称、添加群组、填写被监控端主机IP地址)——

2.配置------ 模板——选定要监控的模板(httpd sshd服务)——选择——添加(添加连接模板)——添加(添加主机)

3.点击Monitoring(监控中)—> Latest data(最新数据),正过滤器中填写过滤条件,根据监控组和监控主机选择需要查看哪些监控数据-----------Graph(图形)

查看监控图形,

4.自定义Zabbix监控项目

  • 有的时候zabbix提供的监控项目,不能满足我们生产环境下的监控需求,此时我们就要按照zabbix的规范自定义监控项目,达到监控的目的

  • item: Items是从agnet主机里面获取的所有数据。通常情况下我叫itme为监控项,item由key+参数组成

  • Key:我们可以理解为key是item的唯一标识,在agent端有很多监控项,zabbix-server根据key区分不同的监控项

  • trigger:触发器是建立在item数据上的,具有阈值触发事件的功能

    基本格式: :.()}

  • server:agent名称,加入主机时配置的

  • key:就是上面说的key

  • function:对阈值进行操作的函数,以下函数

  • operate:表达式

  • constant:常量

  • zabbix_server通过发送key给zabbix_agent,然后agent端口根据key,把所要监控的item的最新数据返回给server端

  1. 被监控主机修改agent端配置文件,自定义key

    UnsafeUserParameters=1     						# 默认为0,表示不允许自定义key
    UserParameter = 自定义key名称,命令。				#自定义key语法格式为
  2. web创建监控模板

    模板、应用集与监控项目的关系: 模板里面有很多应用集,应用集里面包含很多监控项目

    1.添加监控模板

    ​ 登录Zabbix Web监控控制台,通过Configuration(配置)-->Template(模板)-->Create template(创建模板),填写模板名称,新建模板群组

    2.创建应用集

    ​ 创建完成模板后,默认模板中没有任何应用集、监控项、触发器、图形等资源。这里需要点击模板后面的Application(应用集)链接打开创建应用的页面。

    3.点击Application(应用集)后,在该页面中点击Create application(创建应用集)按钮。

    ​ 设置应用名称,名称可以任意。

    4.创建监控项目item(监控项)

    ​ 与创建应用一样,在模板中还需要创建监控项目,点击items(监控项),并在刷新出的新页面中选择Create items(创建监控项)创建项目

    还需要给项目设置名称(名称可以任意)及对应的自定义key(必须与前面自定义的监控key名称一致)。

    5.创建图形

    ​ 为了后期可以通过图形的方式展示监控数据,还需要在模板中创建图形,设置方法与前面的步骤一致,在监控模板后面点击Graph(图形)即可创建图形,设置监控图形基于什么监控数据。

    6.将模板链接到被监控主机

    ​ 将完整的监控模板制作完成后,就可以将模板链接到主机实现监控功能了。首先找到被监控主机Configuration(配置)-->Hosts(主机)。

    7.查看监控数据图形

    ​ 点击Monitoring(监控中)-->Craphs(图形),根据需要选择条件,查看监控图形

5.Zabbix报警功能

自定义的监控项默认不会自动报警,首页也不会提示错误,需要配置触发器与报警动作才可以自定报警。

触发器(trigger)

表达式,如内存不足300M,用户超过30个等

当触发条件发生后,会导致一个触发事件

触发事件会执行某个动作

动作(action)

动作是触发器的条件被触发后所执行的行为

可以是发送邮件、也可以是重启某个服务等

5.1 创建触发器规则

1.创建触发器

模板中有应用集、监控项、触发器、图形

创建触发器时强烈建议使用英文的语言环境,通过Configuration(配置)--> Templates(模板),点击模板后面的triggers(触发器)

创建触发器时需要定义表达式,触发器表达式(Expression)是触发异常的条件,触发器表达式格式如下:

{<server>:<key>.<function>(<parameter>)}<operator><constant>

{主机:key.函数(参数)}<表达式>常数

2.配置触发器

设置触发器名称,点击add添加表达式,填写表达式:监控项为账户数量,最近账户数量大于35(根据系统账户数量实际填写)

选择触发器报警级别:warning,disaster,high

5.2 设置邮件

1)创建Media

通过Administration(管理)-->Media Type(报警媒体类型)-->选择Email(邮件)。

设置邮件服务器信息,设置邮件服务器及发件人邮件账户信息(选择本机localhost)

2)为用户添加Media(设置收件人信息)

在Administration(管理)-->Users(用户)中找到选择admin账户

点击Admin账户后,在弹出的界面中选择Media(报警媒介)菜单-->点击Add(添加)报警媒介

点击Add(添加)后,在Meida Type(类型)中填写报警类型,收件人,时间等信息

5.3 创建Action动作

1)Action动作

Action(动作)是定义当触发器被触发时的时候,执行什么行为。

通过Configuration(配置)-->Actions(动作)-->Create action(创建动作),注意事件源选择触发器

2)配置Action动作的触发条件

填写Action动作的名称,配置什么触发器被触发时会执行本Action动作(账户数量大于35)

3)配置Action动作的具体行为

配置动作的具体操作行为(发送信息或执行远程命令),无限次数发送邮件,60秒1次,发送给Admin用户

6. Zabbix自动发现

自动发现(Discovery)

当Zabbix需要监控的设备越来越多,手动添加监控设备越来越有挑战,

可以考虑使用自动发现功能,自动添加被监控主机,实现自动批量添加一组监控主机功能。

自动发现可以实现:

  • 自动发现、添加主机,自动添加主机到组;
  • 自动连接模板到主机,自动创建监控项目与图形等。

自动发现(Discovery)流程:

  • 创建自动发现规则
  • 创建Action动作,说明发现主机后自动执行什么动作
  • 通过动作,执行添加主机,链接模板到主机等操作

6.1 自动发现规则

1)创建自动发现规则

通过Configuration(配置)-->Discovery(自动发现)-->Create discovery rule(创建发现规则)

2)填写规则

填写自动发现的IP范围(逗号隔开可以写多个),多久做一次自动发现(默认为1小时,仅实验修改为1m),

配置检查的方式:Ping、HTTP、FTP、Agent的自定义key等检查

6.2 创建动作

1)创建Action动作

通过Configuration(配置)--> Actions(动作)--> Actions Event source(事件源):自动发现(Discovery)-->Create action(创建动作)

2)配置Action动作具体行为

配置动作,添加动作名称,添加触发动作的条件

点击操作(触发动作后要执行的操作指令),操作细节:添加主机到组,与模板链接(HTTP模板)

7. Zabbix主动监控

修改被监控主机agent为主动监控模式

克隆模板,修改模板为主动监控模板

添加监控主机,并链接主动监控模板

被动监控、主动监控

默认zabbix采用的是被动监控,主动和被动都是对被监控端主机而言的

被动监控:Server向Agent发起连接,发送监控key,Agent接受请求,响应监控数据。

主动监控:Agent向Server发起连接,Agent请求需要检测的监控项目列表,Server响应Agent发送一个items列表,Agent确认收到监控列表,TCP连接完成,会话关闭,Agent开始周期性地收集数据。

区别:Server不用每次需要数据都连接Agent,Agent会自己收集数据并处理数据,Server仅需要保存数据即可。

当监控主机达到一定量级后,Zabbix服务器会越来越慢,此时,可以考虑使用主动监控,释放服务器的压力。

7.1添加被监控主机

修改agent配置文件,将agent监控模式修改为主动模式。

[root@web2 ~]# vim /usr/local/etc/zabbix_agentd.conf 
#Server=127.0.0.1,192.168.2.5							#93行,注释该行,允许谁监控本机
StartAgents=0											#118行,被动监控时启动几个Agent进程监听10050端口
														#设置为0,则禁止被动监控,不启动zabbix_agentd服务及端口
ServerActive=192.168.2.5								#134行,允许哪些主机监控本机(主动模式),一定要取消127.0.0.1

7.2 创建主动监控的监控模板

1)修改模板中的监控项目的监控模式

将模板中的所有监控项目全部修改为主动监控模式,通过Configuration(配置)-->Templates(模板)-->选择新克隆的模板,点击后面的Items(监控项)-->点击全选,选择所有监控项目,点击批量更新,将类型修改为:Zabbix Agent(Active主动模式)

2)禁用部分监控项目

批量修改监控项的监控模式后,并非所有监控项目都支持主动模式,批量修改后,会发现有几个没有修改主动模式成功,说明,这些监控项目不支持主动模式,关闭即可。

7.3 添加监控主机

1)手动添加监控主机(主动模式监控)

在Zabbix监控服务器,添加被监控的主机(主动模式),设置主机名称:web2 (必须与被监控端的配置文件Hostname一致),将主机添加到Linux servers组,IP地址修改为0.0.0.0,端口设置为0

为主机添加监控模板,选择刚刚创建的模板(主动模式),添加链接模板到主机

2)验证监控效果

查看数据图表,通过Monitoring(监控中)-->Graphs(图形)菜单,选择需要查看的主机组、主机以及图形,查看效果

8.拓扑图与聚合图形

创建修改拓扑图

创建聚合图形

创建拓扑图

绘制拓扑图可以快速了解服务器架构,通过Monitoring(监控中)-->Maps(拓扑图),选择默认的Local network拓扑图,编辑即可(也可以新建一个拓扑图)

拓扑图图表说明

  • Icon(图标),添加新的设备后可以点击图标修改属性
  • Shape(形状)
  • Link(连线),先使用Ctrl选择两个图标,再选择连线
  • 完成后,点击Update(更新)

创建聚合图形

1)创建聚合图形

聚合图形可以在一个页面显示多个数据图表,方便了解多组数据。

通过Monitoring(监控中)-->Screens(聚合图形)-->Create screen(创建聚合图形)即可创建聚合图形

修改聚合图形参数如下:

  • Owner:使用默认的Admin用户
  • Name:名称设置为web2_host
  • Columns:列数设置为2列
  • Rows:行数设置为2行

2)为聚合图形中添加监控图形

选择刚刚创建的聚合图形(web2_host),点击后面的构造函数(constructor),点击Change(更改),设置每行每列需要显示的数据图表

9.分布式监控(Zabbix proxy)

一个帮助Zabbix Server收集数据,分担Zabbix Server的负载的程序 Zabbix Proxy是一个可以从一个或多个受监控设备收集监控数据,并将信息发送到Zabbix sever的进程,基本上是代表sever工作的。 所有收集的数据都在本地进行缓存,然后传送到proxy所属的Zabbix sever。 部署Proxy是可选的,但是可能非常有益于分散单个Zabbix sever的负载。 如果只有proxy收集数据,sever上的进程就会减少CPU消耗和磁盘I / O负载。 Zabbix proxy是完成远程区域、分支机构、没有本地管理员的网络的集中监控的理想解决方案。 Zabbix proxy需要使用独立的数据库。

10.如果去到一家新的公司,如何入手监控?

  • 1.硬件监控——路由器、交换机、防火墙
  • 2.系统监控——cpu、内存、磁盘、网络、进程、tcp
  • 3.服务监控——nginx、php、tomcat、redis、memcache、mysql
  • 4.web监控——响应时间、加载时间、渲染时间
  • 5.日志监控——ELK、(收集、存储、分析、展示)日志
  • 6.安全监控——firewalld、WAF(nginx+lua)、安全宝、牛盾云、安全狗

四、数据库

1.数据库主从同步

复制概述

复制是指将主数据库的DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。

MySQL支持一台主库同时向多台从库进行复制, 从库同时也可以作为其他从服务器的主库,实现链状复制。

复制原理

主从复制主要有三个线程:binlog线程,I/O线程,SQL线程。

  • binlog线程:负责将主服务器上的数据更改写入到二进制日志(Binary log)中。
  • I/O线程:负责从主服务器上读取二进制日志(Binary log),并写入从服务器的中继日志(Relay log)中。
  • SQL线程:负责读取中继日志,解析出主服务器中已经执行的数据更改并在从服务器中重放
  1. Master在每个事务更新数据完成之前,将操作记录写入到binlog中。
  2. Slave从库连接Master主库,并且Master有多少个Slave就会创建多少个binlog dump线程。当Master节点的binlog发生变化时,binlog dump会通知所有的Slave,并将相应的binlog发送给Slave。
  3. I/O线程接收到binlog内容后,将其写入到中继日志(Relay log)中。
  4. SQL线程读取中继日志,并在从服务器中重放。

复制优势

MySQL 复制的有点主要包含以下三个方面:

  • 主库出现问题,可以快速切换到从库提供服务。
  • 可以在从库上执行查询操作,从主库中更新,实现读写分离,降低主库的访问压力。
  • 可以在从库中执行备份,以避免备份期间影响主库的服务。

1.1 配置主服务器

1)启用binlog日志

2)用户授权

用户名自定义、客户端地址使用% 或 只指定 从服务器的地址 都可以、只给复制数据的权限即可。

3)查看binlog日志信息

查看日志文件名 和 偏移量位置。

mysql> show master status\G;

1.2 配置从服务器

1)指定server_id

Server_id值可以自定义,但不可以与主服务器相同。

2)确保与主服务器数据一致

3)指定主服务器信息

数据库管理员root本机登录,指定主服务器信息,其中日志文件名和偏移量 写allbak.sql文件记录的。

2.Maxscale数据库读写分离

随着用户量的增多,数据库操作往往会成为一个系统的瓶颈所在,而且一般的系统“读”的压力远远大于“写”,通过设置主从数据库实现读写分离,主数据库负责“写操作”,从数据库负责“读操作”,根据压力情况,从数据库可以部署多个提高“读”的速度,借此来提高系统总体的性能。

MaxScale是maridb开发的一个mysql数据中间件,通过指定只读,只写服务器来实现读写分离。

搭建MySQL一主一从同步结构

配置代理服务器

1)环境准备

关闭防火墙和SElinux,保证yum源可以正常使用,安装提供服务的软件

2)修改主配置文件

maxscale的主配置文件:/etc/maxscale.cnf

定义数据库服务器--主和从

定义监控的数据库服务器,监控用户和密码

定义读写分离服务,路由用户和密码

定义读写服务端口

定义管理用户端口

]# vim /etc/maxscale.cnf
[maxscale]
threads=auto			//运行的线程的数量

[server1]			//定义数据库服务器
type=server
address=192.168.4.51		//主服务器ip
port=3306
protocol=MySQLBackend		

[server2]
type=server
address=192.168.4.52		//从服务器IP
port=3306
protocol=MySQLBackend


[MySQL Monitor]				//定义监控的数据库服务器
type=monitor
module=mysqlmon
servers=server1, server2			//监控的数据库列表,不能写ip
user=maxscalemon					//监控用户
passwd=123qqq...A					//密码
monitor_interval=10000		



#[Read-Only Service]		//不定义只读服务
#type=service
#router=readconnroute
#servers=server1
#user=myuser
#passwd=mypwd
#router_options=slave

[Read-Write Service]			//定义读写分离服务
type=service
router=readwritesplit
servers=server1, server2
user=maxscalerouter				//路由用户
passwd=123qqq…A					//密码
max_slave_connections=100%

[MaxAdmin Service]		//定义管理服务
type=service
router=cli

#[Read-Only Listener]		//不定义只读服务使用的端口号
#type=listener
#service=Read-Only Service
#protocol=MySQLClient
#port=4008

[Read-Write Listener]			//定义读写服务使用的端口号
type=listener
service=Read-Write Service
protocol=MySQLClient
port=4006

[MaxAdmin Listener]		//管理服务使用的端口号
type=listener
service=MaxAdmin Service
protocol=maxscaled
socket=default
port=4016	 //手动添加,不指定时使用的是默认端口在启动服务以后可以知道默认端口是多少

3)添加授权用户

根据maxscale.cnf文件配置,在主/从服务器上添加对应的授权用户,因为2台数据库服务器是主从同步结构,只在主数据库服务器添加用户即可,从服务器会自动同步

mysql> grant replication slave,replication client on *.* to  maxscalemon@'%' identified by "123qqq…A"; 		//授权监控用户
mysql> grant select on mysql.* to maxscalerouter@"%" identified by "123qqq…A"; 								//授权路由用户

4)启动服务代理服务

maxscale -f  /etc/maxscale.cnf   

3. MyCAT

数据库分片

简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。

数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。

垂直拆分 水平切分
介绍 原来一个表的信息,拆分到两个或者多个表中,通过主键来进行关联。依据业务的耦合性进行拆分,将关联度低的不同表存储在不同的数据库。 把一个表的数据按照某种规则划分到不同表或数据库里。(水平拆分行,行数据拆分到不同表中)
优点 数据库的拆分简单明了,拆分规则明确; 应用程序模块清晰明确,整合容易; 数据维护方便易行,容易定位; 解决单表大数据量性能遇到瓶颈的问题; 应用程序端整体架构改动相对较少; 事务处理相对简单; 只要切分规则能够定义好,基本上较难遇到扩展性限制;
缺点 部分表关联无法在数据库级别完成,需要在程序中完成; 单表大数据量仍然存在性能瓶颈; 事务处理相对更为复杂; 切分达到一定程度之后,扩展性会遇到限制; 切分规则相对更为复杂,很难抽象出一个能够满足整个数据库的切分规则; 后期数据的维护难度有所增加,人为手工定位数据更困难; 应用系统各模块耦合度较高,可能会对后面数据的迁移拆分造成一定的困难。

mycat分片原理

​ 一个新颖的数据库中间件产品支持mysql集群,或者mariadb cluster,提供高可用性数据分片集群。你可以像使用mysql一样使用mycat。对于开发人员来说根本感觉不到mycat的存在。

Mycat有三个配置文件: server.xml:Mycat的配置文件,配置账号密码及逻辑库等 schema.xml:Myvat对应的物理数据库和数据库表的配置 rule.xml:Mycat分片(分库分表)规则

​ mycat里面通过定义路由规则来(路由规则里面会定义分片字段,以及分片算法)。分片算法有多种,你所说的hash是其中一种,还有取模、按范围分片等等。在mycat里面,首先对SQL语句做了一些特定的分析:如分片分析、路由分析、读写分离分析、缓存分析等,然后将此SQL发往后端的真实数据库,并将返回的结果做适当的处理,最终再返回给用户。(路由处理的依据就是表是否分片,如果分片,那么需要依据分片字段和对应的分片算法来判断sql应该传递到哪一个、或者哪几个、又或者全部节点去执行)

1.配置分片服务器

1)部署MyCat 运行环境jdk

2)安装提供服务的软件包

3)设置连接账号

[root@mycat56 ~]# vim /usr/local/mycat/conf/server.xml
<user name="root">															//连接mycat服务时使用的用户名
     <property name="password">123456</property> 							//用户连接mycat用户时使用的密码
     <property name="schemas">TESTDB</property> 							//逻辑库名
</user>

<user name="user">
                <property name="password">user</property>
                <property name="schemas">TESTDB</property>
                <property name="readOnly">true</property>	//只读权限,连接mycat服务后只有读记录的权限,不写这一行则是可读可写	
</user>
:wq

4)配置数据分片

[root@mycat56 conf]# vim  	/usr/local/mycat/conf/schema.xml 
<?xml version="1.0"?>
<!DOCTYPE mycat:schema SYSTEM "schema.dtd">
<mycat:schema xmlns:mycat="http://io.mycat/">
       <schema name="TESTDB" checkSQLschema="false" sqlMaxLimit="100">			//对TESTDB库下的表做分片存储
                <!-- auto sharding by id (long) -->
                <table name="travelrecord" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" />  //对travelrecord表做分片存储
                <!-- global table is auto cloned to all defined data nodes ,so can join
                        with any table whose sharding node is in the same data node -->
                <table name="company" primaryKey="ID" type="global" dataNode="dn1,dn2,dn3" />  //对company表做分片存储
               ...
//定义数据库主机名及存储数据的库
<dataNode name="dn1" dataHost="localhost53" database="db1" /> 
<dataNode name="dn2" dataHost="localhost54" database="db2" />
<dataNode name="dn3" dataHost="localhost55" database="db3" />

//定义localhost53,54,55主机名对应的数据库服务器ip地址
<dataHost name="localhost53" maxCon="1000" minCon="10" balance="0"
                          writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100"> 
                <heartbeat>select user()</heartbeat>
                <writeHost host="hostM53" url="192.168.4.53:3306" user="adminplj"
                                   password="123qqq...A">
                </writeHost> 
 </dataHost>

5)配置数据库服务器

根据分片文件的设置在对应的数据库服务器上创建存储数据的数据库

根据分片文件配置,在对应的数据库服务器上创建授权用户(3台数据库服务器都要添加,在数据库服务器本机管理员root用户登录后执行授权命令)

6)启动mycat服务

测试授权用户:在192.168.4.56主机,使用授权用户分别连接3台数据库服务器,若连接失败,请检查数据库服务器是否有对应的授权用户。

启动服务

2.连接分片服务器存储数据

sharding-by-intfile枚举分片规则

1)查看配置文件

 得知使用sharding-by-intfile枚举分片规则的表名
[root@mycat56 ~]# vim 	/usr/local/mycat/conf/schema.xml
<table name="employee" primaryKey="ID" dataNode="dn1,dn2,dn3 rule="sharding-by-intfile" />

2)查看规则文件

得知sharding-by-intfile分片规则使用的函数
[root@mycat56 ~]# vim /usr/local/mycat/conf/rule.xml
<tableRule name="sharding-by-intfile">
         <rule>
                 <columns>sharding_id</columns>  //数据分片字段名
                 <algorithm>hash-int</algorithm> //使用的函数名
         </rule>
</tableRule>

<function name="hash-int"
                class="io.mycat.route.function.PartitionByFileMap">
                <property name="mapFile">partition-hash-int.txt</property> 		//函数调用的配置文件
</function>

3)修改函数配置文件,添加dn3 数据节点

[root@mycat56 ~]# vim  /usr/local/mycat/conf/partition-hash-int.txt
10000=0   		//当sharding_id字段的值是10000时,数据存储在数据节点dn1里
10010=1   		//当sharding_id字段的值是10010时,数据存储在数据节点dn2里
10020=2   		//当sharding_id字段的值是10020时,数据存储在数据节点dn3里
:wq

4)重启mycat服务,使其修改有效

5)客户端连接分片服务器,存取数据

6)在数据库服务器本机,查看表记录

mod-long分片规则的使用

1)查看配置文件

得知使用mod-long分片规则的表名
注意要删除 primaryKey="ID" autoIncrement="true" 不然无法存储数据
[root@mycat56 ~]# vim /usr/local/mycat/conf/schema.xml
<table name="hotnews" dataNode="dn1,dn2,dn3" rule="mod-long" />
:wq

2)查看规则文件

得知 mod-long分片规则使用的函数
[root@mycat56 ~]# vim /usr/local/mycat/conf/rule.xml
<tableRule name="mod-long">
                <rule>
                        <columns>id</columns>  //数据分片字段
                        <algorithm>mod-long</algorithm> //函数名
                </rule>
        </tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
                <!-- how many data nodes -->
                <property name="count">3</property> //指定求模数字
</function>
:wq

3)重启mycat服务,使其修改有效

4)客户端连接分片服务器,存取数据

5)在数据库服务器本机,查看表记录

4.MHA

一、MHA介绍

​ MHA(MasterHigh Availability)是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。MHA 的出现就是解决MySQL 单点的问题。MySQL故障切换过程中,MHA能做到0-30秒内自动完成故障切换操作。MHA能在故障切换的过程中最大程度上保证数据的一致性,以达到真正意义上的高可用。

MHA 的组成

MHA Node(数据节点) MHA Node 运行在每台 MySQL 服务器上。

node工具包

save_binary_logs:保存和复制 Master 的 binlog 日志。 apply_diff_relay_logs:识别差异的中级日志时间并将其应用到其他 Slave。

MHA Manager(管理节点) MHA Manager 可以单独部署在一台独立的机器上,管理多个 master-slave 集群;也可以部署在一台 slave 节点上。 MHA Manager 会定时探测集群中的 master 节点。当 master 出现故障时,它可以自动将最新数据的 slave 提升为新的 master, 然后将所有其他的 slave 重新指向新的 master。整个故障转移过程对应用程序完全透明。

manager工具包

masterha_check_ssh:检查 MHA 的 SSH 配置情况。 masterha_check_repl:检查 MySQL 复制状况。 masterha_manager:启动 MHA。 masterha_check_status:检测当前 MHA 运行状态。 masterha_master_monitor:检测 Master 是否宕机。 masterha_master_switch:控制故障转移(自动或手动)。 masterha_conf_host:添加或删除配置的 server 信息。

MHA 的特点

  • 自动故障切换过程中,MHA试图从宕机的主服务器上保存二进制日志,最大程度的保证数据不丢失。(但这并不总是可行的。例如,如果主服务器硬件故障或无法通过ssh访问,MHA没法保存二进制日志,只进行故障转移而丢失了最新的数据。所以半同步复制,)
  • 使用半同步复制,可以大大降低数据丢失的风险,如果只有一个slave已经收到了最新的二进制日志,MHA可以将最新的二进制日志应用于其他所有的slave服务器上,因此可以保证所有节点的数据一致性
  • 目前MHA支持一主多从架构,最少三台服务,即一主两从

二、MHA工作原理:

  1. 从宕机崩溃的 Master 保存二进制日志事件(binlog event);
  2. 识别含有最新更新的 Slave;
  3. 应用差异的中继日志(relay log)到其他 Slave;
  4. 应用从 Master 保存的二进制日志事件;
  5. 提升一个 Slave 为新的 Master;
  6. 使其他的 Slave 连接新的 Master 进行复制;

故障切换的过程

当master_manager监控到主库mysqld服务停止后,首先对主库进行SSH登录检查(save_binary_logs -command=test),然后对mysqld服务进行健康检查(PING(SELECT)每个3秒检查一次,持续3次),最后作出Master is down!的判断,master failover开始

第1步:检查并列出所有服务器状态; 先根据配置文件检测当前的复制环境中有哪些服务器,MHA也会校验诸如复制异常以及是否存在一些从库有不同的主库,启动failover(排除上次failover失败或者failover时间间隔太短)----

第2步:停掉主库vip; 隔离master server,把故障主库的VIP停掉(前提是你需要指定相关的脚本,比如:如果有master_ip_failover_script则会调用脚本停掉VIP、如果有shutdown_script脚本则调用脚本关闭master避免脑裂,在安装包的samples/scriptes目录下)

第3步:选举新主库并尽量补全新主库的数据。

3.1 获取同步位置最靠前的从库:对比所有从库的master_log_file和read_master_log_pos位置找出执行位置最新和最旧的从库对应的故障主库的binlog位置。

3.2保存dead master的binlog:在故障主库上执行save_binary_logs命令获得lastest slave同步位置与master间的binlog差异(使用3.1步骤找到的同步最靠前的从库binlog位置,如果故障主库系统没挂的情况下)并scp到monitor server上。

文件名是以从库名为前缀

3.3 确定新的主库:先使用命令apply_diff_relay_logs --command=find把前面3.1步骤中找出的同步位置最靠前和最靠后的对应主库的binlog位置作为参数,在同步位置最靠前的从库上执行这个命令在其中继日志中找出两个binlog位置之间的relay log并生成文件用于恢复其他从库(这里就是检查同步最靠前的从库是否有从最老的位置开始的中继日志,这也是为什么MHA环境中执行过的中继日志不能删除的原因,否则这个对比就比较麻烦)。

接着寻找及决定新的主库,根据配置选择如何提升新主库(检查是否有设置candidate_master=1和no_master=1,如果有设置候选主库,那么候选主库中标,但候选库不一定就是有最新数据的slave,所以需要跟其他从库进行比较,当然如果候选主库恰好是同步位置最靠前的从库,就不需要跟其他从库进行relay log比较了;如果没有设置候选主库,那么同步位置最靠前的从库中标)。monitor server也会将之前复制的差异binlog复制到新主库上。

3.4 新的主库应用日志(如果有任何错误从这个阶段会发生,需要手动恢复):新的主库首选需要对比master_log_file=relay_master_log_file,read_master_log_pos=exec_master_log_pos确认自己已经执行完成复制,如果新的主库不是同步位置最靠前的从库,那么需要使用apply_diff_relay_logs --command=generate_and_send命令比较自己和同步位置最靠前的从库之间的relay log是否存在差异,如果存在则需要生成一个差异relay log(如果新主库就是同步位置最靠前的从库,那么只需要执行monitor server发过来的差异日志即可),然后使用这两个差异日志进行恢复数据(apply_diff_relay_logs --command=apply命令)。恢复完成后获取binlog位置并生成change master语句准备用于其他从库change master到新的主库上,并设置read_only=0。然后把VIP绑定到新的主库上。到这步骤新的主库切换完成。

第4步:其他从库恢复:将其他从库数据尽量补全(所有从库并行执行)。

4.1 并行使用apply_diff_relay_logs --command=generate_and_send命令判断各个从库的relay log位置和同步位置最靠前的从库之间的relay log差异,并把差异文件从同步位置最靠前的从库上发送到对应的各个从库上。

4.2 并行使用两个差异日志进行恢复:将monitor server上的binlog差异拷贝到各个从库上,然后各个从库通过master_log_file=relay_master_log_file,read_master_log_pos=exec_master_log_pos先确认自己已经执行完成复制,再应用两个差异日志恢复数据。最后,执行reset slave,并重新CHANG MASTER到新主库上。

第5步:新主库执行reset slave操作清除之前slave信息,到这里故障主库切换到新主库完成。

三、准备MHA集群环境

配置SSH免密登录

安装依赖包

配置MySQL一主多从结构

四、部署MHA集群

1.配置管理节点

1)安装软件

2)编辑主配置文件

指定后端数据库服务器,授权用户,监控用户

[root@mgm57 ~ ]#  vim /etc/mha/app1.cnf   															//编辑主配置文件
 [server default]     											//管理服务默认配置
  manager_workdir=/etc/mha    									//工作目录
  manager_log=/etc/mha/manager.log   							//日志文件
  master_ip_failover_script=/etc/mha/master_ip_failover 		//故障切换脚本
  ssh_user=root  												//访问ssh服务用户
  ssh_port=22    												//ssh服务端口

  repl_user=repluser   	    									//主服务器数据同步授权用户
  repl_password=123qqq…A    									//密码

  user=root 		          									//监控用户
  password=123qqq…A 	          								//密码
[server1]   														//指定第1台数据库服务器
hostname=192.168.4.51												//服务器ip地址
port=3306															//服务端口
candidate_master=1   												//竞选主服务器

3)创建故障切换脚本

[root@mgm57 ~]# vim +35 /etc/mha/master_ip_failover
my $vip = '192.168.4.100/24';  								# Virtual IP  						//定义VIP地址
my $key = "1"; 														//定义变量$key
my $ssh_start_vip = "/sbin/ifconfig eth0:$key $vip"; 				//部署vip地址命令
my $ssh_stop_vip = "/sbin/ifconfig eth0:$key down"; 				//释放vip地址命令

4)在当前主服务器部署vip地址

[root@host51 ~]# ifconfig  eth0:1  192.168.4.100  //部署vip地址
[root@host51 ~]# ifconfig  eth0:1 //部署后查看
eth0:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.4.100  netmask 255.255.255.0  broadcast 192.168.4.255
        ether 52:54:00:d8:10:d7  txqueuelen 1000  (Ethernet)

2.配置数据节点

1)在所有数据库服务器上,安装mha-node软件包

2)在所有数据服务器上添加监控用户

可以只在host51主机执行授权命令,host52和host53 会自动同步授权

3)在2台从服务器上添加,数据同步连接用户

4)修改数据库服务运行参数

配置3台数据服务器(根据管理主机配置文件的设置,优化一主多从同步结构的配置)
1  启用主从角色数据库服务的半同步复制模式
2  在备用数据库服务器53/52主机启用binlog日志并添加repluser用户  						#以防一个坏了,这个被定成主服务器
3  在3台数据库服务器上禁止自动删除本机的中继日志文件

修改主服务器host51

[root@host51 ~]# vim /etc/my.cnf
[mysqld]
plugin-load="rpl_semi_sync_master=semisync_master.so;rpl_semi_sync_slave=semisync_slave.so" //加载模块
rpl_semi_sync_master_enabled=1  								//启用master模块
rpl_semi_sync_slave_enabled=1     								//启用slave模块
relay_log_purge=0   											//禁止自动删除中继日志文件
:wq
[root@host51 ~]#  systemctl  restart  mysqld  //重启服务

五、测试配置

1.测试集群环境

masterha_check_ssh --conf=/etc/mha/app1.cnf 			                   #在管理主机,测试ssh配置
masterha_check_repl --conf=/etc/mha/app1.cnf			                   #在管理主机,测试主从同步
masterha_manager --conf=/etc/mha/app1.cnf  --remove_dead_master_conf --ignore_last_failove		#启动管理服务
masterha_check_status  --conf=/etc/mha/app1.cnf						       #查看服务状态

2.访问集群

1)在主服务器51 添加访问数据的连接用户

2)客户端50 连接vip地址访问集群

3)在从服务器host52 查看数据

4)在从服务器host53 查看数据

3.测试高可用

1)停止主服务器51的mysql服务

2)查看管理服务 ,输出的监控信息

[root@mgm57 ~]# masterha_check_status  --conf=/etc/mha/app1.cnf
app1 is stopped(2:NOT_RUNNING).  						//监控到主服务器宕机 管理服务自动停止

3)客户端依然连接vip地址,可以访问到数据

4)查看vip地址

在host52主机查看到vip地址,说明host52 主机被选举为主服务器,在host53主机未查看到vip地址,说明host53主机是当前host52的从服务器

4.修复故障服务器

1)配置数据库服务器

  • 启动host51主机的数据库服务
  • 与主服务器数据一致----主机使用备份文件恢复数据
  • 指定主服务器信息---主从
  • 启动slave进程

2)配置管理服务器

  • 修改配置文件,添加数据库服务器host51
]# vim /etc/mha/app1.cnf
 [server1 ]
hostname=192.168.4.51
port=3306
candidate_master=1
  • 测试集群环境

  • 重启管理服务

masterha_stop  --conf=/etc/mha/app1.cnf             #停止管理服务
masterha_manager --conf=/etc/mha/app1.cnf  --remove_dead_master_conf --ignore_last_failover #启动管理服务

5.PXC

PXC是针对MySQL用户的高可用性和扩展性解决方案,基于Percona Server 。

PXC优缺点

优点

  • 高可用性,节点不可用不影响集群正常运行,没有主从切换操作。

  • 强一致性,可以将读扩展到多个节点上。

  • 节点的增加数据同步自动化(IST,SST)。

  • 可实现多点读写,但写压力仍要同步到所有节点。、

  • 支持InnoDB存储引擎

  • 支持节点自动加入,无需手动拷贝数据

    缺点

  • 由于ddl需全局验证通过,则集群性能由集群中最差性能节点决定。

  • 为保证一致性,galera 总是优先保证数据一致性,在多点并发写时,锁冲突问题严重

  • 新节点加入或延后较大的节点重新加入需全量拷贝数据(sst),作为donor的节点在同步过程中无法提供读写

  • 数据冗余度为节点数

PXC工作原理

pxc是基于Galere协议的高可用方案,还有MariaDB Galera Cluster Galere架构是在所有mysql下通过wsrep API调用galera replication库来实现文件的同步复制,节点接收sql 请求后,对于ddl 操作,在commit之前,由wsrep API 调用galera 库进行集群内广播,所有其他节点验证成功后事务在集群所有节点进行提交,反之roll back。pxc 保证整个集群所有数据的强一致性,满足CAP理论中满足:Consistency 和 Availability。

PXC模式和Replication(传统主从)

PXC 集群方案所有节点都是可读可写的,Replication从节点不能写入,因为主从同步是单向的,无法从slave节点向master点同步

PXC 同步机制是同步进行的,这也是它能保证数据强一致性的根本原因,Replication同步机制是异步进行的,它如果从节点停止同步,依然可以向主节点插入数据,正确返回,造成数据主从数据的不一致性。

PXC 是用牺牲性能保证数据的一致性,Replication在性能上是高于PXC的。所以两者用途也不一致。PXC是用于重要信息的存储,例如:订单、用户信息等。Replication用于一般信息的存储,能够容忍数据丢失,例如:购物车,用户行为日志等。

特点 故障切换过程中最大限度保证数据库 支持InnoDB存储引擎 的一致性 部署使用简单 支持节点自动加入,无需手动拷贝数据 组成多个MHA Node(数据节点)1个MHA Manger(管理节点)最少三台

任意节点收到sql请求,对于代码更新操作失 Manger定时探测集群中的master节 误,在提交之前,有wsrep API调用galera库进 行售群内部广播,验证当前事务是否能在所有 点 工作过程 当master故障时,Manger自动将拥 节点中执行,验证通过后该事务真正提交到一 群所有节点执行,泛指roll back回漆。次验证 有最近数据的slave提升为master 机制是为了确保所有节点的数据-致性,

配罟MYSQL集群服务器,配罟一主 在几台(最少台)没有安装数据库服务器的 多从,半同步复制,配罟一台独立的 主机上直接安装pxc相关软件,句括在线执备 配置过程管理服务器,安装MHA软件包,指定MYSOL服务器集群,穿件故障切和集群服务等,修改配置文件,,指定集群ip 等,初始化启动,其他服务器正常启动会自动 换脚本,测试ssh和主从同步成功 完成与第一胎初始化启动的服务器同步数据。 后,启动管理服务。

PXC和MHA

MHA PXC
特点 可在0~30s内完成数据可自动故障切
故障切换过程中最大限度保证数据库
数据强一致性,无同步延迟 ,没有主从切换操作,无需使用虚拟IP
支持节点自动加入,无需手动拷贝数据
支持InnoDB存储引擎 ,部署使用简单
工作过程 Manger定时探测集群中的master节点,
当master故障时,Manger自动将拥有最近数据的slave提升为master
任意节点收到sql请求,对于代码更新操作失误,在提交之前,有wsrep API调用galera库进行集群内部广播,验证当前事务是否能在所有节点中执行,验证通过后该事务真正提交到一群所有节点执行,泛指roll back回滚。次验证机制是为了确保所有节点的数据一致性。
优点 成熟稳定、对MySQL侵入小、宕机后保证数据一致 实现了MySQL集群的高可用性和数据的强一致性;
完成了真正的多节点读写的集群方案:
改善了主从复制延迟的问题,基本上达到了实时同步;
新加入的节点可以自动同步数据,无需提前手动备份,维护方便:
由于是多节点写入,所以数据库故障切换很容
缺点 需要编写脚本或利用第三方工具来实现VIP的配置;
MHA启动后只会对主数据库进行监控;
需要基于SSH免认证配置,存在一定的安全隐患;
没有提供从服务器的读负载均衡功能
加入新节点时开销大,因为添加新节点时必须从现有节点之一复制完整的数据集,如果现有的数据库中数据为100GB,则复制100GB;
任何更新的事务都需要全局验证通过,才会在其他节点上执行,集群性能受限于最差的节点,也就是所谓的短板效应(木桶定律):
因为需要保证数据的一致性,PXC采用的实时基于存储引擎层来实现同步复制,所以在多节点并发写入时,锁冲突问题比较严重;
存在写扩大的问题,所有节点上都会发生写操作,对于写负载较大的场景,不推荐使用 PXC;
仅支持Innodb存储引擎

一、环境准备

配置主机名与ip地址绑定

配置服务器192.168.4.71;192.168.4.72;192.168.4.73

在任意一台服务器上ping 对方的主机名,ping通为配置成功。

安装软件包

在192.168.4.71 ;192.168.4.72 ;192.168.4.723服务器安装软件包

二、配置服务

  • 修改mysqld.cnf文件: 数据库服务运行参数配置文件
  • 修改mysqld_safe.cnf文件: perconca配置文件
  • 修改wsrap.cnf文件: pxc集群配置文件
  • 启动服务

1)修改mysqld.cnf文件,数据库服务运行参数配置文件

vim /etc/percona-xtradb-cluster.conf.d/mysqld.cnf					#三台
[mysqld]
server-id=71			      	//server-id 不允许重复
datadir=/var/lib/mysql		      	//数据库目录
socket=/var/lib/mysql/mysql.sock     	//socket文件
log-error=/var/log/mysqld.log		//日志文件
pid-file=/var/run/mysqld/mysqld.pid	//pid文件
log-bin					//启用binlog日志
log_slave_updates			//启用链式复制
expire_logs_days=7			//日志文件保留天数

2)修改mysqld_safe.cnf文件,perconca配置文件

#分别修改3台服务器的mysqld_safe.cnf (使用默认配置即可)
[root@pxcnode71 ~]# vim /etc/percona-xtradb-cluster.conf.d/mysqld_safe.cnf
[mysqld_safe]
pid-file = /var/run/mysqld/mysqld.pid
socket   = /var/lib/mysql/mysql.sock
nice     = 0

3)修改wsrep.cnf文件,pxc集群配置文件

#分别修改3台服务器的wsrep.cnf
[root@pxcnode71 ~]# vim /etc/percona-xtradb-cluster.conf.d/mysqld_safe.cnf
wsrep_cluster_address=gcomm://192.168.4.71,192.168.4.72,192.168.4.73//成员列表
wsrep_node_address=192.168.4.71 //本机ip
wsrep_cluster_name=pxc-cluster //集群名
wsrep_node_name=pxcnode71 //本机主机名
wsrep_sst_auth="sstuser:123qqq...A" //SST数据同步授权用户及密码

4)启动服务

[root@pxcnode71 ~]# ]# systemctl  start mysql@bootstrap.service  //启动集群服务

三、测试配置

查看集群信息

1)启动数据库服务

在任意一台数据查看都可以。

[root@pxcnode71 ~]# mysql -uroot -p123456
wsrep_incoming_addresses 192.168.4.71:3306,192.168.4.72:3306,192.168.4.73:3306 //集群成员列表 
wsrep_cluster_size       3 //集群服务器台数
wsrep_cluster_status   Primary     //集群状态                           
wsrep_connected        ON			//连接状态
wsrep_ready             ON           //服务状态

访问集群,存取数据

1)添加访问数据的连接用户 (在任意一台服务器上添加都可以,另外的2台服务器会自动同步授权用户)

2)客户端连接集群存取数据 (连接任意一台数据库服务器的ip地址都可以)

3)在另外2台数据库服务器查看数据,客户端连接数据库服务器71主机查看数据。

4)客户端连接数据库服务器73主机查看数据

测试故障自动恢复

1)停止数据库服务

停止3台服务器的任意一台主机的数据库服务都不会影响数据的存取。

3)启动71主机的数据库服务,数据库服务运行后,会自动同步宕机期间的数据。

6.Redis

Redis 是一个开源(BSD 许可)、基于内存、支持多种数据结构的存储系统,可以作为数据库、缓存和消息中间件。它支持的数据结构有字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等,除此之外还支持 bitmaps、hyperloglogs 和地理空间(geospatial )索引半径查询等功能。

Redis 集群的功能: 可以实现数据的自动备份

可以实现redis服务的高可用

分布式存储数据

初始化:			/utils/install  server.sh
主配置文件: 			/etc/redis/6379.conf
日志文件:			/var/log/redis_6379.log
数据库目录:			/var/lib/redis/6379
服务启动程序:			/usr/local/bin/redis-server
默认端口:				6379
管理命令:		redis-cli
			redis-trib.rb		集群管理命令

image-20210812180026158

部署redis集群

1.配置管理主机mgm57

1)部署ruby脚本运行环境

2)创建管理集群脚本

2.创建集群

1)启动服务器192.168.4.51-56的集群功能

2)改配置

[root@redisA ~]# vim /etc/redis/6379.conf 		//修改配置文件(端口)
bind 192.168.4.51								//修改ip
port 6351										//修改端口(可选配置)
cluster-enabled yes 							//启用集群功能
cluster-config-file nodes-6379.conf 			//存储集群信息的配置文件
cluster-node-timeout 5000						//集群节点通信超时时间

3)创建集群

[root@mgm57 ~]# redis-trib.rb 	create  --replicas   1 	192.168.4.51:6351  192.168.4.52:6352  192.168.4.53:6353 
192.168.4.54:6354  192.168.4.55:6355  192.168.4.56:6356
会分配出三个主,三个从

3.查看集群信息

 [root@mgm57 ~]# redis-trib.rb 	info 	192.168.4.51:6351 					//查看集群信息
 [root@mgm57 ~]# redis-trib.rb check 192.168.4.51:6351 					//检测集群

4.访问集群

#在客户端连接集群中的任意一台服务器存取数据
[root@client50 ~]# redis-cli  -c  -h 192.168.4.51 -p 6351 //连接服务器51

3.添加服务器

添加master角色主机到集群里(master需要槽)

1)在管理主机,添加master角色主机
[root@mgm57 ~]# redis-trib.rb  add-node  192.168.4.58:6358  192.168.4.53:6353  //执行添加命令

2) 在管理主机,查看集群新消息
[root@mgm57 ~]# redis-trib.rb 	info 	192.168.4.53:6353  //查看集群信息

3)在管理主机,检测集群
 [root@mgm57 ~]# redis-trib.rb 	check 192.168.4.53:6353  //检测集群,发现58没有槽,要划分

4)在管理主机,重新分配hash槽
[root@mgm57 ~]# redis-trib.rb  reshard  192.168.4.53:6353  
How many slots do you want to move (from 1 to 16384)?4096  //拿出4096个hash 槽给主机192.168.4.58
What is the receiving node ID?  c5e0da48f335c46a2ec199faa99b830f537dd8a0  //主机192.168.4.58的id值
Source node #1:all    //从当前所有master服务器获取hash槽
Do you want to proceed with the proposed reshard plan (yes/no)?yes //同意以上配置

5)在管理主机,查看集群信息
[root@mgm57 ~]# redis-trib.rb info 192.168.4.53:6353

添加slave角色主机到集群里(slave都是不需要槽的)

1)部署新的redis服务器 192.168.4.59
2)在管理主机,添加slave角色主机
[root@mgm57 ~]# redis-trib.rb add-node  --slave 192.168.4.59:6359  192.168.4.51:6351  	//执行添加命令

3) 在管理主机,查看集群新消息
4)在管理主机,检测集群
5)在客户端,访问从服务器59,查看数据

4.移除服务器

把slave服务器移除集群

在管理主机,移除slave服务器,从服务器没有槽,直接移除即可。
[root@HOST57 ~]# redis-trib.rb  del-node  192.168.4.53:6353 	e5e96b0e27c8007a274de6d4a28f8ad143c502d2

把master服务器移除集群,要先删槽

1)在管理主机,先删除master服务器占用的hash槽
[root@mgm57 ~]# redis-trib.rb  reshard	 192.168.4.53:6353
How many slots do you want to move (from 1 to 16384)?   4096 //移除4096个数槽
What is the receiving node ID?    bc5c4e082a5a3391b634cf433a6486c867cfc44b 	//要移动给谁的id即目标主机(这里可以随机写一个master的ID)  
Source node #1:     c5e0da48f335c46a2ec199faa99b830f537dd8a0					//从谁那移动即源主机(这里写4.58的ID)  
Source node #2:done        //设置完毕

2)在管理主机,查看集群信息
[root@mgm57 ~]# redis-trib.rb  info  192.168.4.51:6351
192.168.4.58:6358 (4fe1fa46...) -> 0 keys | 0 slots   | 0 slaves. //零个槽

3)在管理主机,移除master主机
[root@HOST57 ~]# redis-trib.rb  del-node  192.168.4.53:6354 2d1ecc690c0d841887693b3be09a41332918f55b

4)在管理主机,查看集群信息
[root@mgm57 ~]# redis-trib.rb  info  192.168.4.51:6351  

5.Redis主从复制

1) 每台redis服务器,默认都是主服务器;所以主服务器不需要配置。

设置为主从方法

1)命令行配置(马上生效)

192.168.4.52:6352> slaveof  192.168.4.51  6351  //指定主服务器ip地址与端口

2)永久配置(重新redis服务后,依然有效)

[root@redisB ~]# vim /etc/redis/6379.conf	
slaveof  192.168.4.51  6351    //在文件末尾添加或在原有配置项上修改都可以

7.Redis哨兵服务

哨兵服务介绍:监视master服务器,发现master宕机后,将从服务器升级为主服务器

主配置文件:sentinel.conf

模板文件:redis-4.0.8/sentinel.conf

配置哨兵服务

1) 安装源码软件redis ,无需做初始化配置。

2)编辑主配置文件

[root@redis57 redis]# vim  /etc/sentinel.conf  //创建主配置文件
sentinel   monitor   server51   192.168.4.51   6351   1 //监视主服务器
bind  0.0.0.0    //哨兵服务地址(表示本机所有网络接口)
sentinel auth-pass  server51   123456   //主服务器密码

3)启动哨兵服务

[root@redis57 redis]# redis-sentinel  /etc/sentinel.conf	//启动哨兵服务

测试配置

1)停止主服务器51的redis服务

2)在服务器52主机,查看复制信息

LVS

1.LVS介绍

LVS(Linux Virtual Server),是一个极好的负载均衡解决方案,它将一个真实服务器集群虚拟成一台服务器来对外提供服务,同时在真实服务器集群中实现了负载均衡。分发服务器以VIP对外提供服务器,当接收到客户端服务请求时,便根据预定的分发策略(例如轮询)将请求分发到Real Server中,由Real Server做实际的业务处理。当Real Server处理完成后,根据不同的模式,会使用不同的方式返回请求结果。( yum -y install ipvsadm)

ipvsadm命令用法

ipvsadm -A -t|u 192.168.4.5:80 -s wrr				#t,u分别tcp,udp协议,创建LVS虚拟集群服务器(算法为加权轮询:wrr)
ipvsadm -a -t 192.168.4.5:80 -r 192.168.2.100 		#为集群添加若干real server	
ipvsadm -e -t 192.168.4.5:80 -r 192.168.2.202 -g		#修改read server(使用-g选项,将模式改为DR模式。g-DR,i-隧道,m-NAT)
ipvsadm -Ln								#列出所有规则
ipvsadm -C								#清空所有规则
ipvsadm-save -n > /etc/sysconfig/ipvsadm					#永久保存所有规则

LVS的调度算法

LVS的调度算法是指LVS对于请求的分发方式。DS在向Real Server分发请求实现负载均衡时,有10种不同的算法: 轮询(Round Robin,rr):在Real Server之间轮流分配请求。 加权轮询(Weighted Round Robin,wrr):有权重地进行轮询。 最少链接(Least Connnections,lc):将请求发送给连接数最少的RS。 加权最少链接(Weighted Least Connnections,wlc):分发给基于权重的最少链接。 基于局部性的最少链接(Locality-Based Least Connections,lblc):首先根据目标IP地址找出最近使用的服务器,如果该服务器可用且没有超载(一半的工作负荷),则将请求发送到该服务器。否则,使用“最少链接”原则。 带复制的基于局部性最少链接(Locality-Based Least Connections with Replication,lblcr):它与lblc的不同之处是它要维护从一个目标IP到一组服务器的映射,而lblc值维护从一个目标IP到一台服务器的映射。 目标地址散列(Destination Hashing,dh):使用请求的目标IP地址作为散列键,从静态分配的散列表找出对应的服务器,若该服务器可用且未超载,则转发请求,否则返回空。 源地址散列(Source Hashing,sh):使用请求的源IP地址作为散列键,从静态分配的散列表找出对应的服务器,若该服务器可用且未超载,则转发请求,否则返回空。 最短期望延迟(Shortest Expected Delay,sed):“最短的期望的延迟”是基于WLC算法的,只是其计算方法不同。具体算法如下:(active+1)*256/weight 最少队列调度(Never Queue Scheduling):无需队列。如果有台 realserver的连接数=0就直接分配过去,不需要在进行SED运算。如果没有服务器连接数为空闲,则使用SED算法。

Lvs术语

LVS术语
Director Server 调度服务器 将负载分发到Real Server的服务器
Real Sever 真实服务器 真正提供应用的服务器
VIP 虚拟IP地址 公布给用户访问的虚拟IP地址
DIP 调度器连接后端节点服务器的IP地址
RIP 真实的IP地址 集群节点上使用的IP地址
CIP 客户端IP

2. LVS-NAT集群

通过网络地址转换实现的虚拟服务器,NAT(Network Address Translation)即网络地址转换,其作用是通过数据报头的修改,使得位于企业内部的私有IP地址可以访问外网,以及外部用用户可以访问位于公司内部的私有IP主机。(不是同一网段的,配两张网卡)

原理

  1. 用户通过互联网DNS服务器解析到公司负载均衡设备上面的外网地址VIP,分发服务器Director Server(后面简称DS)接受到请求后,通过分发策略得出要将此请求分发到Real Server1。于是将请求报文的目的地址改为RIP1,发送出去。
  2. Real Server1收到一个目标地址为自己的数据包,于是接受并进行处理。
  3. 处理完成后,Real Server1将RIP1——>CIP的数据包发送出去。
  4. DS接收到RIP1——>CIP的数据包后,将源地址改为VIP,然后发送出去:VIP——>CIP。 这个过程中,DS仅仅起到一个地址转换和分发的作用。 在NAT模式中,请求和响应报文都要通过DS,当真实服务器的数量越来越多时,分发器DS将会成为整个集群系统的性能瓶颈。下面的DR模式解决这个问题。

步骤

1)确认调度器的路由转发功能

[root@proxy ~]# echo 1 > /proc/sys/net/ipv4/ip_forward     #开启路由转发,临时有效(如果已经开启,可以忽略)
[root@proxy ~]# cat /proc/sys/net/ipv4/ip_forward          #查看效果
1
[root@proxy ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
#修改配置文件,设置永久规则,英语词汇:forward(转寄,转发,发送,向前)

2)创建集群服务器

3)添加真实服务器

4)查看规则列表

5)设置防火墙,SELinux

3. LVS-DR集群

直接使用路由技术实现虚拟服务器(后端服务器和lvs调度器都配置了vip)。该模式中LVS服务器仅承担数据的入站请求以及根据算法选出合理的真实服务器,最终由后端真实服务器负责将响应数据包发送返回给客户端。直接路由模式(DR模式)要求调度器与后端服务器必须在同一个局域网内,VIP地址需要在调度器与后端所有的服务器间共享。

原理

在DR模型中,只有在请求的时候会经过DR,响应的数据包由Real Server直接返回给用户,该模式是3中模式中最常用的。它的请求过程如下所示:

  1. DR接受到请求后,通过分发策略得出要将此请求分发到Real Server2。
  2. 当Real Server2 收到一个源地址为CIP目标地址为VIP的数据包时,Real Server2发现目标地址为VIP,而VIP是自己,于是接受数据包并给予处理。
  3. Real Server2处理完成后,会将一个源地址为VIP而目标地址为CIP的数据包发送出去,此时的响应请求就不会再经过DS,而是直接响应给用户了。 在这个过程中存在一个问题,由于RealServer也配置了VIP,那么当CIP——>VIP的数据包到达服务局域网,进行广播时,所有的服务器都会进行应答,此时先应答的服务器就会收到数据包,这样就失去了负载均衡的能力。因此在使用DR模式时,通常会采用一些方式来确保请求数据包只会由DS接收,例如抑制Real Server对广播的应答,或者直接在路由器中对DS进行绑定等。

步骤

1)安装软件

2)清理之前实验的规则,创建新的集群服务器规则

3)添加真实服务器(-g参数设置LVS工作模式为DR模式,-w设置权重)

4)查看规则列表

4. LVS-TUN集群

通过隧道方式实现虚拟服务器。TNU模式与DR模式非常相似,它同样是只有请求信息会经过DS,应答信息由Real Server直接返回给用户。不过DR模式中,要求DS和所有的Real Server必须在一个局域网中,而TNU模式去掉了这个限制。

IP隧道(IP tunning)是一种数据包封装技术,它可以将原始数据包封装并添加新的包头(内容包括新的源地址及端口、目标地址及端口),从而实现将一个目标为调度器的VIP地址的数据包封装,通过隧道转发给后端的真实服务器(Real Server),通过将客户端发往调度器的原始数据包封装,并在其基础上添加新的数据包头(修改目标地址为调度器选择出来的真实服务器的IP地址及对应端口),LVS(TUN)模式要求真实服务器可以直接与外部网络连接,真实服务器在收到请求数据包后直接给客户端主机响应数据。

5. LVS的优缺点

LVS的优点有: 1、 工作在网络层,可以实现高性能、高可用的服务器集群技术。 2、 廉价,可把许多低性能的服务器组合在一起形成一个水平扩展的集群服务器。 3、 易用,配置非常简单,且有多重负载均衡的方法 4、 稳定可靠,即使集群中的一台服务器挂掉,也不影响整体服务效果。 5、 可扩展性好,可以用户透明地进行水平扩展,加减机器非常方便。

LVS的缺点: 1、 由于是通用组件,因此不能对特定业务进行针对优化。 2、 对于长连接无法进行负载均衡。 3、 自身没有健康状态检查,需要结合脚本或者Keepalived等软件实现。

Keepalived

keepalived是集群管理中保证集群高可用的一个服务软件,其功能类似于heartbeat,用来防止单点故障。Keepalived通过请求一个vip来达到请求IP地址的功能,而VIP能够在一台机器发生故障时候,自动漂移到另外一台机器上,从来达到了高可用HA功能。

组件

1.watchDog监控checkers和VRRR进程的状态; 2.checkers负责真实服务器的健康监测healthchecking; 3.VRRR Stack负责负载均衡器之间的失败切换; 4.IPVS wrapper 用来发送设定的规则到内核IPVS代码 5.Netlink Reflector 用来设定VRRP的VIP地址等。

三大核心模块core、check、vrrp

1.core:keepalived的核心,负责主进程的启动、维护以及全局配置文件的加载和解析。 2.check:负责健康检查,包括常见的各种检查方式。 3.vrrp:用来实现VRRP协议。

原理

keepalived会让服务器争抢一个VIP,Keepalived Directors高可用对之间的故障切换转移,是通过 VRRP 协议(Virtual Router RedundancyProtocol中文虚拟路由器冗余协议)来实现的。 在Keepalived Directors正常工作时,先做健康检查,做完后可能会出现异常,主 Director 节点会不断的向备节点广播心跳消息,用以告诉备节点自己还活着,当主节点发生故障时,备节点就无法继续检测到主节点的心跳,进而调用自身的接管程序,接管主节点的IP资源及服务。而当主节点恢复故障时,备节点会释放主节点故障时自身接管的IP资源及服务,恢复到原来的自身的备用角色。

VRRP协议

keepalived高可用对之间是通过VRRP协议通信的,VRRP协议是通过竞选机制来确定主备的,主的优先级高于备,因此,工作时主会获得所有的资源,备节点等待状态,当主挂了时候,备节点,接管主节点的资源,然后顶替主节点对外提供服务。VRRP使用加密协议加密发送广播包。 在keepalived之间,只有作为主的服务器会一直发送VRRP广播包,告诉备他还活着,此时备不会抢占主,当主不可用时,即备监听不到主发送的广播包时,就会启动相关服务接管资源,保证业务的连续性。接管速度可以小于1秒。

健康检查

TCP_CHECK {     # 通过TcpCheck判断RealServer的健康状态
    connect_timeout 10    # 连接超时时间
    nb_get_retry 3        # 重连次数
    delay_before_retry 3  # 重连时间间隔
    connect_port 6500     # 检测端口
}		#配置文件可以配置HTTP_GET---MISC_CHECK

Keepalived对服务器运行状态和故障隔离的工作原理:keepalived的健康检查方式有三种,tcp_check、http_check、misc_check。 Keepalived工作在TCP/IP参考模型的三层、四层、五层(物理层,链路层): 网络层(3):Keepalived通过ICMP协议向服务器集群中的每一个节点发送一个ICMP数据包(有点类似与Ping的功能),如果某个节点没有返回响应数据包,那么认为该节点发生了故障,Keepalived将报告这个节点失效,并从服务器集群中剔除故障节点。

传输层(4):Keepalived在传输层里利用了TCP协议的端口连接和扫描技术来判断集群节点的端口是否正常,比如对于常见的WEB服务器80端口。或者SSH服务22端口,Keepalived一旦在传输层探测到这些端口号没有数据响应和数据返回,就认为这些端口发生异常,然后强制将这些端口所对应的节点从服务器集群中剔除掉。

应用层(5):,Keepalived的运行方式也更加全面化和复杂化,用户可以通过自定义Keepalived工作方式,例如:可以通过编写程序或者脚本来运行Keepalived,而Keepalived将根据用户的设定参数检测各种程序或者服务是否允许正常,如果Keepalived的检测结果和用户设定的不一致时,Keepalived将把对应的服务器从服务器集群中剔除。

部署Keepalived服务

1)安装Keepalived软件,配置ip(自身IP即可,因为VIP在配置文件中)

2)修改主备服务器Keepalived配置文件

[root@web1 ~]# vim /etc/keepalived/keepalived.conf
global_defs {
  router_id  web1		#12行,设置路由ID号(实验需要修改)
    vrrp_iptables			#13行,清除防火墙的拦截规则(实验需要修改,手动添加该行)
}
vrrp_instance VI_1 {
  state MASTER			#21行,主服务器为MASTER(备服务器需要修改为BACKUP)
  interface eth0			#22行,VIP配在哪个网卡(实验需要修改,不能照抄网卡名)
  virtual_router_id 51		#23行,主备服务器VRID号必须一致
  priority 100			#24行,服务器优先级,优先级高优先获取VIP
  advert_int 1
  authentication 
    auth_type pass
    auth_pass 1111  	 				
  }
  virtual_ipaddress {		#30~32行,谁是主服务器谁获得该VIP(实验需要修改)
192.168.4.80 
}    
}

4)启动服务

5)配置防火墙和SELinux

Keepalived+LVS服务器

  • LVS1调度器真实IP地址为192.168.4.5(服务器VIP地址设置为192.168.4.15)
  • LVS2调度器真实IP地址为192.168.4.6(服务器VIP地址设置为192.168.4.15)
  • 真实Web服务器地址分别为192.168.4.100、192.168.4.200(服务器VIP地址设置为192.168.4.15)

1.设置Web服务器的网络参数(不能照抄网卡名称)

为后端web服务器配置vip,因为和lvs相关

#注意:这里因为web1也配置与调度器一样的VIP地址,默认肯定会出现地址冲突。写入下面这四行的主要目的就是访问192.168.4.15的数据包,只有调度器会响应,其他主机都不做任何响应。
[root@web1 ~]# vim /etc/sysctl.conf
#手动写入如下4行内容
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
#当有arp广播问谁是192.168.4.15时,本机忽略该ARP广播,不做任何回应
#本机不要向外宣告自己的lo回环地址是192.168.4.15
[root@web1 ~]# sysctl  -p                #刷新,让配置文件立刻生效

2.调度器安装Keepalived与ipvsadm软件

3.部署Keepalived实现LVS-DR模式调度器的高可用

清理防火墙规则-----设置vrrp------配置vip-----配置lvs规则

[root@proxy ~]# vim /etc/keepalived/keepalived.conf
global_defs {
  router_id  lvs1		#12行,设置路由ID号(实验需要修改)
  vrrp_iptables			#13行,清除防火墙的拦截规则(实验需要修改,手动添加)   
}
vrrp_instance VI_1 {
  state MASTER			#21行,主服务器为MASTER
  interface eth0			#22行,定义网络接口(不能照抄网卡名)
  virtual_router_id 51		#23行,主辅VRID号必须一致
  priority 100			#24行,服务器优先级
  advert_int 1
  authentication {
    auth_type pass
    auth_pass 1111  	 				
  }
  virtual_ipaddress {		#30~32行,配置VIP(实验需要修改)
192.168.4.15 
 }   
}
virtual_server 192.168.4.15 80 {		#设置ipvsadm的VIP规则(实验需要修改)
  delay_loop 6						#默认健康检查延迟6秒
  lb_algo rr							#设置LVS调度算法为RR
  lb_kind DR							#设置LVS的模式为DR(实验需要修改)
  #persistence_timeout 50				#(实验需要删除)
#注意persistence_timeout的作用是保持连接
#开启后,客户端在一定时间内(50秒)始终访问相同服务器
  protocol TCP						#TCP协议
  real_server 192.168.4.100 80 {		#设置后端web服务器真实IP(实验需要修改)
    weight 1							#设置权重为1
    TCP_CHECK {						#对后台real_server做健康检查(实验需要修改)
	connect_timeout 3				#健康检查的超时时间3秒
	nb_get_retry 3					#健康检查的重试次数3次
	    delay_before_retry 3				#健康检查的间隔时间3秒
    }
  }
 real_server 192.168.4.200 80 {		#设置后端web服务器真实IP(实验需要修改)
    weight 2						#设置权重为2
    TCP_CHECK {					#对后台real_server做健康检查(实验需要修改)
	     connect_timeout 3			#健康检查的超时时间3秒
	nb_get_retry 3				#健康检查的重试次数3次
	delay_before_retry 3			#健康检查的间隔时间3秒
    }
  }
}
[root@proxy1 ~]# systemctl start keepalived
[root@proxy1 ~]# ipvsadm -Ln		#查看LVS规则
[root@proxy1 ~]# ip a  s			#查看VIP配置

HAProxy

一种高效、可靠、免费的高可用及负载均衡软件,非常适合于高负载站点的七层数据请求。客户端通过Haproxy代理服务器获得站点页面,而代理服务器收到客户请求后根据负载均衡的规则将请求数据转发给后端真实服务器

实现了一种事件驱动、单一进程模型,能支持非常大的并发连接数

原理

HAProxy是基于四层和七层代理技术的负载均衡

所谓的四层就是ISO参考模型中的第四层。四层负载均衡也称为四层交换机,它主要是通过分析IP层及TCP/UDP层的流量实现的基于IP加端口的负载均衡。常见的基于四层的负载均衡器有LVS、F5等。 以常见的TCP应用为例,负载均衡器在接收到第一个来自客户端的SYN请求时,会通过设定的负载均衡算法选择一个最佳的后端服务器,同时将报文中目标IP地址修改为后端服务器IP,然后直接转发给该后端服务器,这样一个负载均衡请求就完成了。从这个过程来看,一个TCP连接是客户端和服务器直接建立的,而负载均衡器只不过完成了一个类似路由器的转发动作。在某些负载均衡策略中,为保证后端服务器返回的报文可以正确传递给负载均衡器,在转发报文的同时可能还会对报文原来的源地址进行修改。

七层负载均衡器也称为七层交换机,位于OSI的最高层,即应用层,此时负载均衡器支持多种应用协议,常见的有HTTP、FTP、SMTP等。七层负载均衡器可以根据报文内容,再配合负载均衡算法来选择后端服务器,因此也称为“内容交换器”。

比如,对于Web服务器的负载均衡,七层负载均衡器不但可以根据“IP+端口”的方式进行负载分流,还可以根据网站的URL、访问域名、浏览器类别、语言等决定负载均衡的策略。例如,有两台Web服务器分别对应中英文两个网站,两个域名分别是A、B,要实现访问A域名时进入中文网站,访问B域名时进入英文网站,这在四层负载均衡器中几乎是无法实现的,而七层负载均衡可以根据客户端访问域名的不同选择对应的网页进行负载均衡处理。常见的七层负载均衡器有HAproxy、Nginx等。

这里仍以常见的TCP应用为例,由于负载均衡器要获取到报文的内容,因此只能先代替后端服务器和客户端建立连接,接着,才能收到客户端发送过来的报文内容,然后再根据该报文中特定字段加上负载均衡器中设置的负载均衡算法来决定最终选择的内部服务器。纵观整个过程,七层负载均衡器在这种情况下类似于一个代理服务器。

对比四层负载均衡和七层负载均衡运行的整个过程,可以看出,在七层负载均衡模式下,负载均衡器与客户端及后端的服务器会分别建立一次TCP连接,而在四层负载均衡模式下,仅建立一次TCP连接。由此可知,七层负载均衡对负载均衡设备的要求更高,而七层负载均衡的处理能力也必然低于四层模式的负载均衡。

部署HAProxy服务器

1)配置网络,安装软件 yum -y install haproxy

2)修改配置文件

[root@proxy ~]# vim /etc/haproxy/haproxy.cfg
global
 log 127.0.0.1 local2   ##[err warning info debug]
 pidfile /var/run/haproxy.pid ##haproxy的pid存放路径
 user haproxy
 group haproxy
 daemon                    ##以后台进程的方式启动服务
defaults
 mode http                ##默认的模式mode { tcp|http|health } 
option dontlognull      ##不记录健康检查的日志信息
 option httpclose        ##每次请求完毕后主动关闭http通道
 option httplog          ##日志类别http日志格式
 option redispatch      ##当某个服务器挂掉后强制定向到其他健康服务器
 timeout client 300000 ##客户端连接超时,默认毫秒,也可以加时间单位
 timeout server 300000 ##服务器连接超时
 maxconn  3000          ##最大连接数
 retries  3             ##3次连接失败就认为服务不可用,也可以通过后面设置
  
listen  websrv-rewrite 0.0.0.0:80          
   balance roundrobin
   server  web1 192.168.2.100:80 check inter 2000 rise 2 fall 5
   server  web2 192.168.2.200:80 check inter 2000 rise 2 fall 5
#定义集群,listen后面的名称任意,端口为80
#balance指定调度算法为轮询(不能用简写的rr)
#server指定后端真实服务器,web1和web2的名称可以任意
#check代表健康检查,inter设定健康检查的时间间隔,rise定义成功次数,fall定义失败次数
listen stats *:1080        #监听端口
    stats refresh 30s             #统计页面自动刷新时间
    stats uri /stats              #统计页面url
    stats realm Haproxy Manager #进入管理解面查看状态信息
    stats auth admin:admin       #统计页面用户名和密码设置

3)启动服务器并设置开机启动

客户端验证(页面)

客户端配置与HAProxy相同网络的IP地址,并使用火狐浏览器访问http://192.168.4.5,测试调度器是否正常工作,

客户端访问http://192.168.4.5:1080/stats测试状态监控页面是否正常。访问状态监控页的内容

Queue队列数据的信息(当前队列数量,最大值,队列限制数量);

Session rate每秒会话率(当前值,最大值,限制数量);

Sessions总会话量(当前值,最大值,总量,Lbtot: total number of times a server was selected选中一台服务器所用的总时间);

Bytes(入站、出站流量);

Denied(拒绝请求、拒绝回应);

Errors(错误请求、错误连接、错误回应);

Warnings(重新尝试警告retry、重新连接redispatches);

Server(状态、最后检查的时间(多久前执行的最后一次检查)、权重、备份服务器数量、down机服务器数量、down机时长)。

Nginx、LVS、Haproxy对比

Nginx(7层)的优点:

  • 工作在OSI第7层,可以针对http应用做一些分流的策略。比如针对域名、目录结构。它的正则比HAProxy更为强大和灵活;
  • Nginx对网络的依赖非常小,理论上能ping通就就能进行负载功能,这个也是它的优势所在;
  • Nginx安装和配置比较简单,测试起来比较方便;
  • 可以承担高的负载压力且稳定,一般能支撑超过几万次的并发量;
  • Nginx可以通过端口检测到服务器内部的故障,比如根据服务器处理网页返回的状态码、超时等等,并且会把返回错误的请求重新提交到另一个节点;
  • Nginx不仅仅是一款优秀的负载均衡器/反向代理软件,它同时也是功能强大的Web应用服务器。LNMP现在也是非常流行的web环境,大有和LAMP环境分庭抗礼之势,Nginx在处理静态页面、特别是抗高并发方面相对apache有优势;
  • Nginx现在作为Web反向加速缓存越来越成熟了,速度比传统的Squid服务器更快,有需求的朋友可以考虑用其作为反向代理加速器;

Nginx的缺点:

  • Nginx不支持url来检测。
  • Nginx仅能支持http和Email,这个它的弱势。
  • Nginx的Session的保持,Cookie的引导能力相对欠缺。
  • 不适用于高负载量的并发集群;

LVS(四层)优点

  • 抗负载能力强,强大的四层代理,媲美F5硬件的四层代理;
  • 对内存和 cpu 资源消耗比较低;
  • 配置性比较低;
  • 工作稳定,自身有完整的双机热备方案如 LVS+Keepalived;
  • 无流量,LVS 只分发请求,而流量并不从它本身出去,这点保证了均衡器 IO 的性能不会受到大流量的影响。
  • 会话保持;

LVS缺点

  • 健康检查:无法检查后端节点的健康情况;
  • 动静分离:不支持正则,无法区分请求;
  • 实现比较麻烦;
  • 网络环境依赖性较大;

Haproxy(四层、七层)优点:

  • 支持 Session 的保持,Cookie 的引导;同时支持通过获取指定的 url 来检测后端服务器的状态。

  • 基于TCP协议的负载效率高于Nginx;

  • 负载均衡策略非常多;

  • 动静分离:支持acl规则匹配;

  • 高效稳定;

  • 节点健康检查:支持多种方式检测,如端口、url;

Haproxy(四层、七层)缺点:

  • 扩展性差:添加新功能很费劲,对不断扩展的新业务,haproxy很难应对;
  • 在四层代理时,仅支持tcp协议的代理;

总结:

大型网站架构:对性能有严格要求的时候可以使用lvs或者硬件F5,单从负载均衡的角度来说,lvs也许会成为主流,更适合现在大型的互联网公司; 中型网站架构:对于页面分离请求由明确规定,并且性能有严格要求时,可以使用haproxy 中小型网站架构:比如日访问量小于1000万,需要进行高并发的网站或者对网络不太严格的时候,可以使用nginx

马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/ywangji/interview.git
git@gitee.com:ywangji/interview.git
ywangji
interview
面试
master

搜索帮助

344bd9b3 5694891 D2dac590 5694891