Tycho Blog
专注于信息、技术分享

Elasticsearch7.7告警模块Elastalert

tycho_yang阅读(2423)

一、简介

Elastalert是通过查询ElasticSearch中的记录进行比对,对服务报警规则对日志发送报警邮件

支持报警规则有:

  • blacklist类型:黑名单规则将检查黑名单中的某个字段,如果它在黑名单中则匹配。
  • whitelist类型:与黑名单类似,此规则将某个字段与白名单进行比较,如果列表中不包含该字词,则匹配。
  • change类型:此规则将监视某个字段,并在该字段更改时进行匹配,该领域必须相对于最后一个事件发生相同的变化。
  • frequency类型:当给定时间范围内至少有一定数量的事件时,此规则匹配。 这可以按照每个query_key来计数。
  • spike类型:当某个时间段内的事件量比上一个时间段的spike_height时间大或小时,这个规则是匹配的。它使用两个滑动窗口来比较事件的当前和参考频率。 我们将这两个窗口称为“参考”和“当前”。
  • flatline类型:当一个时间段内的事件总数低于一个给定的阈值时,匹配规则。
  • cardinality类型:当一个时间范围内的特定字段的唯一值的总数高于或低于阈值时,该规则匹配。
  • percentage match类型:当计算窗口内的匹配桶中的文档的百分比高于或低于阈值时,此规则匹配。计算窗口默认为buffer_time。

支持对报警方式有:

  • Email
  • JIRA
  • OpsGenie
  • Commands
  • HipChat
  • MS Teams
  • Slack
  • Telegram
  • AWS SNS
  • VictorOps
  • PagerDuty
  • Exotel
  • Twilio
  • Gitter

二、软件环境

  1. CentOS Linux release 7.8.
  2. Elasticsearch 7.7.1
  3. Kibana 7.7.1

三、服务部署

1、ElastAlert配置文件

点击下载elastalert.tar.gz

2、拷贝到/opt/目录下并解压elastalert.tar.gz

cp elastalert.tar.gz /opt/
tar -zxvf elastalert.tar.gz

3、配置文件说明:

主要配置文件是:config.yaml

  • es_host: elasticsearch地址(可以用容器名,用容器名的时候各个服务的--network efk要一致)
  • es_port: elasticsearch端口
  • dingtalk_access_token: 钉钉机器人的token
  • dingtalk_secret: 钉钉机器人的加签值
  • dingtalk_security_type: 这个钉钉机器人安全设置有sign/keyword/whitelist(对应加签,关键字,IP地址白名单)

该配置文件:smtp_auth.yaml为邮箱账户密码

  • user: "admin@163.com"
  • password: "sdfaHAKNQ"

4、ElastAlert 镜像启动:

docker run -d -p 3030:3030 -p 3333:3333 -e"ELASTICSEARCH_HOST=elasticsearch771" \
           -v /opt/elastalert/config/config.yaml:/opt/elastalert/config.yaml \
           -v /opt/elastalert/config/smtp_auth.yaml:/opt/elastalert/smtp_auth.yaml \
           -v /opt/elastalert/rules:/opt/elastalert/rules \
           -v /opt/elastalert/rule_templates:/opt/elastalert/rule_templates \
           -v /etc/localtime:/etc/localtime:ro \
           -e "CONTAINER_TIMEZONE=Asia/Shanghai" \
           -e "TZ=Asia/Shanghai" \
           -e "ELASTALERT_DINGTALK_ACCESS_TOKEN=80d0034ef56a3988d0073e66900f713c92bf54ed5ae2563976b41c014776f981" \
           -e "ELASTALERT_DINGTALK_SECURITY_TYPE=sign" \
           -e "ELASTALERT_DINGTALK_SECRET=SEC203b230a30790e352741008e49ef160ae0a4b836fc85d2cf9ae6b2dfe1acc0e4" \
           --network efk --name elastalert3 anjia0532/elastalert-docker:v0.2.4

5、告警模板

       rules目录下的yaml都是告警模板,根据自己需求修改

6、钉钉告警效果

Zabbix自动发现Spring Boot下各服务的可用性

tycho_yang阅读(4818)

一、Spring Boot 获取健康状态数据

        先要Springboot 把/actuator/health健康检查打开,另外需要能抓到eureka的各应用状态数据,访问http://ip:8000/actuator/health|jq . 可以获取下面数据即可

         上面这图的数字代表该应用对应副本有几个是存活的,3是有3个副本是正常状态,2是2个副本是正常状态,1也是类似,只有小于1也就是0的情况就是故障,根据这种情况可以后面zabbix定制触发器的时候定制小于1的时候告警,当然这个可以灵活如果你生产所有应用的副本都给固定比如5个副本,那触发器可以做小于5的时候告警,这样可以知道哪个应用有副本故障,只是个别副本故障的应用还是可以正常访问的。

二、定制Zabbix模板跟服务发现规则

1、写服务发现脚本

[root@test zabbix_agentd.d]# vi ../zabbix_scripts/spring_discovery.sh
#!/bin/bash
proarray=($(curl -s http://101.211.1.33:8000/actuator/health |jq . | python -c "import sys, json; print json.load(sys.stdin)['details']['discoveryComposite']['details']['discoveryClient']['details']['services']"|sed "s/u'/ /g"|sed "s/'\,/ /g"|sed "s/\[/ /g"|sed "s/'\]/ /g"))
length=${#proarray[@]}
printf "{\n"
printf  '\t'"\"data\":["
printf "\t"
for ((i=0;i<$length;i++))
do
        printf '\n\t\t{'
        printf "\"{#SPRING}\":\"${proarray[$i]}\"}"
        if [ $i -lt $[$length-1] ];then
                printf ','
        fi
done
printf  "\n\t]\n"
printf    "}\n"

          脚本说明
          执行如下
          转成Zabbix对应的格式

2、写获取的Spring Boot 对应应用的状态值脚本

       zabbix获取状态值脚本内容如下:

[root@test zabbix_agentd.d]# vi ../zabbix_scripts/springboot_status.sh 
#!/bin/bash
spring_name=`echo $1  | tr '[a-z]' '[A-Z]'`
curl -s http://101.211.1.33:8000/actuator/health |jq . | python -c "import sys, json; print json.load(sys.stdin)['details']['discoveryComposite']['details']['eureka']['details']['applications']['$spring_name']"

        执行脚本结果如下即可:

[root@test zabbix_agentd.d]# ../zabbix_scripts/springboot_status.sh zipkinserver
2

        数据处理完的就定制Zabbix模板

三、Zabbix 模板定制

        定制方法就不详细说明的,跟自定义模板方法类似网络上很多就不说明,文章后面会附件相关模板。

1、zabbix监控视图效果如下

        如果服务多的这样一个一个很麻烦可以通过Grafana把这些服务聚合在一个视图里面,多条线来区分

2、Grafana 服务聚合

2.1、安装Grafana zabbix插件

        首先先安装插件Zabbix plugin for Grafana(alexanderzobnin-zabbix-app),官方插件地址:https://grafana.com/grafana/plugins/alexanderzobnin-zabbix-app;官方页面安装

2.2、配置Grafana zabbix源

        然后导入我的附件里面的Spring Boot 的Dashboards模板,效果如下
        监控脚本模板下载zabbix_springboot,记得修改本解压文件里面脚本的IP跟端口

Jenkins Pipeline + Kubernetes (CICD)

tycho_yang阅读(2807)

Jenkins Pipeline + Kubernetes 动态获取Harbor仓库镜像(CICD)

Jenkins 在Kubernetes 中的Pipeline应用流程图

下面简化Demo视频演示

Ceph luminous + bluestore存储引擎部署

tycho_yang阅读(5353)

BlueStore存储介绍

Bluestore 建立在块设备之上,采用rocksdb作为元数据存储,数据直接在块设备上写入,bluestore自己实现了委派规则(allocation code,to allocate which block-device shall be written);关键点(key-challenge):块设备需要与rocksdb共享,包括持久化数据、日志等需要写入块设备中,自此实现自制的rocksdb,并实现了最简化的文件系统bluefs用来做元数据的基本读写操作,并与bluestore共享块设备信息。

Bluestore= block(device) + NewStore

bluestore的诞生是为了解决filestore自身维护一套journal并同时还需要基于系统文件系统的写放大问题,并且filestore本身没有对SSD进行优化,因此bluestore相比于filestore主要做了两方面的核心工作:

  • 去掉journal,直接管理裸设备
  • 针对SSD进行单独优化

BlueStore的整体架构如下图所示:

 

BlueStore元数据

在存储引擎filestore里,对象的表现形式是对应到文件系统里的文件,默认4MB大小的文件,但是在bluestore里,已经没有传统的文件系统,而是自己管理裸盘,因此需要有元数据来管理对象,对应的就是Onode,Onode是常驻内存的数据结构,持久化的时候会以kv的形式存到rocksdb里。

在onode里又分为lextent,表示逻辑的数据块,用一个map来记录,一个onode里会存在多个lextent,lextent通过blob的id对应到blob(bluestore_blob_t ),blob里通过pextent对应到实际物理盘上的区域(pextent里就是offset和length来定位物理盘的位置区域)。一个onode里的多个lextent可能在同一个blob里,而一个blob也可能对应到多个pextent。
另外还有Bnode这个元数据,它是用来表示多个object可能共享extent,目前在做了快照后写I/O触发的cow进行clone的时候会用到。

环境:

OS:Centos 7.5.1804
内核版本:3.10.0-862.14.4.el7.x86_64
Ceph版本:luminous 12.2.8(当前最新稳定版)

192.168.3.81   ceph-kub-81   mon,mgr,mds
192.168.3.82   ceph-kub-82   mon,mgr,mds
192.168.3.83   ceph-kub-83   mon,osd
192.168.3.84   ceph-kub-84   osd
192.168.3.85   ceph-kub-85   osd

osd节点:每台磁盘分区sdb,sdc(sdb 分3个区存储wal,db,osd,最好用SSD硬盘)

修改HOST解析

vi /etc/hosts

192.168.3.81 ceph-kub-81
192.168.3.82 ceph-kub-82
192.168.3.83 ceph-kub-83
192.168.3.84 ceph-kub-84
192.168.3.85 ceph-kub-85

安装ntp

yum installl ntp

启动ntp服务

systemctl restart ntpd.service
systemctl enable ntpd.service

修改sudoers
sudo visudo
找到
Defaults requiretty
选项直接注释掉

在所有节点创建用户(每个节点都创建ceph用户)

useradd ceph

授权ceph权限
vi /etc/sudoers

ceph ALL=(ALL) NOPASSWD: ALL

管理节点执行

切换用户

su ceph

生成秘钥,免密码登陆

ssh-keygen
ssh-copy-id ceph@ceph-kub-81
ssh-copy-id ceph@ceph-kub-82
ssh-copy-id ceph@ceph-kub-83
ssh-copy-id ceph@ceph-kub-84
ssh-copy-id ceph@ceph-kub-85

安装ceph-deploy

sudo yum install ceph-deploy

修改ceph-deploy配置工具(修改替换ceph官方源,走官方源除非有翻墙,不然执行这个)
vi /usr/lib/python2.7/site-packages/ceph_deploy/hosts/centos/install.py

...
def install(distro, version_kind, version, adjust_repos, **kw):
    packages = map_components(
        NON_SPLIT_PACKAGES,
        kw.pop('components', [])
    )

    gpgcheck = kw.pop('gpgcheck', 1)
    adjust_repos = False                                         ###新增这条###
    logger = distro.conn.logger
    machine = distro.machine_type
    repo_part = repository_url_part(distro)
    dist = rpm_dist(distro)

    distro.packager.clean()
...

创建目录

mkdir ceph-cluster
chown -R ceph:ceph ceph-cluster
chmod -R 755 ceph-cluster

添加Ceph repo源
vi /etc/yum.repos.d/ceph.repo

[ceph]
name=ceph
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/x86_64/
gpgcheck=0
priority=1

[ceph-noarch]
name=cephnoarch
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/noarch/
gpgcheck=0
priority=1

[ceph-source]
name=Ceph source packages
baseurl=http://mirrors.aliyun.com/ceph/rpm-luminous/el7/SRPMS
gpgcheck=0
priority=1

关闭防火墙或者在防火墙开放对应端口

vi /etc/sysconfig/iptables

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 6789 -j ACCEPT                                        ##新增##
-A INPUT -p tcp -m state --state NEW -m tcp --dport 6800:7300 -j ACCEPT                                   ##新增##
-A INPUT -p tcp -m state --state NEW -m tcp --dport 7480 -j ACCEPT                                        ##新增##
-A INPUT -p tcp -m state --state NEW -m tcp --dport 7000 -j ACCEPT                                        ##新增##
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

重启iptables服务

sudo service iptables restart

创建monitor节点,所有节点安装ceph

ceph-deploy new ceph-kub-81 ceph-kub-82 ceph-kub-83
ceph-deploy install --release luminous ceph-kub-81 ceph-kub-82 ceph-kub-83 ceph-kub-84 ceph-kub-85

初始化mon

ceph-deploy mon create-initial

配置admin key 到每个节点

ceph-deploy admin ceph-kub-81 ceph-kub-82 ceph-kub-83 ceph-kub-84 ceph-kub-85

创建管理daemon节点

[ceph@ceph-kub-81 ceph-cluster]$ ceph-deploy mgr create ceph-kub-81 ceph-kub-82
[ceph_deploy.conf][DEBUG ] found configuration file at: /home/ceph/.cephdeploy.conf
[ceph_deploy.cli][INFO ] Invoked (2.0.1): /usr/bin/ceph-deploy mgr create ceph-kub-81 ceph-kub-82
[ceph_deploy.cli][INFO ] ceph-deploy options:
[ceph_deploy.cli][INFO ] username : None
[ceph_deploy.cli][INFO ] verbose : False
[ceph_deploy.cli][INFO ] mgr : [('ceph-kub-81', 'ceph-kub-81'), ('ceph-kub-82', 'ceph-kub-82')]
[ceph_deploy.cli][INFO ] overwrite_conf : False
[ceph_deploy.cli][INFO ] subcommand : create
[ceph_deploy.cli][INFO ] quiet : False
[ceph_deploy.cli][INFO ] cd_conf : <ceph_deploy.conf.cephdeploy.Conf instance at 0x7f26bd1ab638>
[ceph_deploy.cli][INFO ] cluster : ceph
[ceph_deploy.cli][INFO ] func : <function mgr at 0x7f26bda0d0c8>
[ceph_deploy.cli][INFO ] ceph_conf : None
[ceph_deploy.cli][INFO ] default_release : False
[ceph_deploy.mgr][DEBUG ] Deploying mgr, cluster ceph hosts ceph-kub-81:ceph-kub-81 ceph-kub-82:ceph-kub-82

创建MGR节点

ceph-deploy mgr create ceph-kub-81 ceph-kub-82

登陆到每个OSD节点,使用ceph-volume lvm来管理磁盘,block.db,block.wal建议存放在SSD硬盘介质上(我们这里sdb是SSD硬盘)
LVM创建磁盘

pvcreate /dev/sdb
vgcreate ceph-pool /dev/sdb
lvcreate -n osd0.wal -L 10G ceph-pool
lvcreate -n osd0.db -L 10G ceph-pool
lvcreate -n osd0 -l 100%FREE ceph-pool
pvcreate /dev/sdc
vgcreate osd-pool /dev/sdc
lvcreate -n osd1 -l 100%FREE osd-pool

创建OSD

管理节点执行:

ceph-deploy --overwrite-conf osd create ceph-node-43 --data ceph-pool/osd0 --block-db ceph-pool/osd0.db --block-wal ceph-pool/osd0.wal --bluestore
ceph-deploy --overwrite-conf osd create ceph-node-44 --data ceph-pool/osd0 --block-db ceph-pool/osd0.db --block-wal ceph-pool/osd0.wal --bluestore 
ceph-deploy --overwrite-conf osd create ceph-node-44 --data ceph-pool/osd0 --block-db ceph-pool/osd0.db --block-wal ceph-pool/osd0.wal --bluestore 
ceph-deploy --overwrite-conf osd create ceph-node-43 --data osd-pool/osd1 --block-db ceph-pool/osd0.db --block-wal ceph-pool/osd0.wal --bluestore
ceph-deploy --overwrite-conf osd create ceph-node-44 --data osd-pool/osd1 --block-db ceph-pool/osd0.db --block-wal ceph-pool/osd0.wal --bluestore 
ceph-deploy --overwrite-conf osd create ceph-node-44 --data osd-pool/osd1 --block-db ceph-pool/osd0.db --block-wal ceph-pool/osd0.wal --bluestore

查看状态

[ceph@ceph-kub-81 root]$ sudo ceph -s
  cluster:
    id:     d5de5c6d-50d9-4ea6-9c0f-3a83b49f13dc
    health: HEALTH_OK
 
  services:
    mon: 3 daemons, quorum ceph-kub-81,ceph-kub-82,ceph-kub-83
    mgr: ceph-kub-81(active), standbys: ceph-kub-82
    mds: kube_cephfs-1/1/1 up  {0=ceph-kub-81=up:active}, 1 up:standby
    osd: 6 osds: 6 up, 6 in
 
  data:
    pools:   2 pools, 256 pgs
    objects: 21 objects, 4.80KiB
    usage:   6.03GiB used, 324GiB / 330GiB avail
    pgs:     256 active+clean
[ceph@ceph-kub-81 root]$ sudo ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 0.32217 root default
-3 0.10739 host ceph-kub-83
0 hdd 0.05859 osd.0 up 1.00000 1.00000
3 hdd 0.04880 osd.3 up 1.00000 1.00000
-5 0.10739 host ceph-kub-84
1 hdd 0.05859 osd.1 up 1.00000 1.00000
4 hdd 0.04880 osd.4 up 1.00000 1.00000
-7 0.10739 host ceph-kub-85
2 hdd 0.05859 osd.2 up 1.00000 1.00000
5 hdd 0.04880 osd.5 up 1.00000 1.00000

配置dashboard
在mgr节点上执行:

ceph config-key put mgr/dashboard/server_addr 0.0.0.0(这条可以先不执行)
ceph config-key put mgr/dashboard/server_port 7000
sudo ceph mgr module enable dashboard

访问dashboard
http://192.168.3.81:7000

CephFs 创建

  • 当前一套集群只能有一个文件系统存在。
  • 一个 Ceph 文件系统需要至少两个 RADOS 存储池,一个用于数据、一个用于元数据。配置这些存储池时需考虑:
    为元数据存储池设置较高的副本水平,因为此存储池丢失任何数据都会导致整个文件系统失效。
    为元数据存储池分配低延时存储器(像 SSD ),因为它会直接影响到客户端的操作延时。

创建mds

ceph-deploy mds create ceph-kub-81 ceph-kub-82

创建存储池

sudo ceph osd pool create kube 128
sudo ceph osd pool create kube_metadata 128

确定 pg_num 取值是强制性的,因为不能自动计算。下面是几个常用的值:

  • 少于 5 个 OSD 时可把 pg_num 设置为 128
  • OSD 数量在 5 到 10 个时,可把 pg_num 设置为 512
  • OSD 数量在 10 到 50 个时,可把 pg_num 设置为 4096
  • OSD 数量大于 50 时,你得理解权衡方法、以及如何自己计算 pg_num 取值
  • 自己计算 pg_num 取值时可借助 pgcalc 工具

随着 OSD 数量的增加,正确的 pg_num 取值变得更加重要,因为它显著地影响着集群的行为、以及出错时的数据持久性(即灾难性事件导致数据丢失的概率)。

创建文件系统

sudo ceph fs new kube_cephfs kube_metadata kube

查看信息

[ceph@ceph-kub-81 root]$ sudo ceph fs ls
name: kube_cephfs, metadata pool: kube_metadata, data pools: [kube ]

 

其他常用服务启动命令列举一些

systemctl start ceph-mon@ceph-node-43
systemctl start ceph-mgr@ceph-node-41
systemctl start ceph-mds@ceph-kub-82

systemctl start ceph-osd@1
systemctl start ceph-osd@5

Docker 容器中Supervisor守护进程配置管理并在前台输出日志

tycho_yang阅读(3667)

       在k8s生产环境使用中,避免不了要对所有容器的日志进行收集,最简单高效的方法就是在宿主上收集所有Docker容器中应用日志,通常需要在制作镜像时将应用日志输出到前台即可,Docker推荐一个容器跑一个程序,如果多个程序就需要用其他手段去启动多余的程序,这里简单介绍下supervisor,supervisor是可以在Docker中管理多个程序,被supervisor接管后,之前的将应用日志软链接到/dev/stdout就变成无效,需要重新到supervisor重新进行配置,才能将日志输出到前台

环境:

Centos 7.4 64bit 镜像
supervisor 3.1.4
nginx 1.14.0
php 5.6.36

安装supervisor,Docker镜像中安装需要用dockerfile对原镜像做升级,或者启动一个镜像容器然后进入该容器安装后再对该容器重新生成镜像,进去该容器后的安装可以看成宿主一样的方式

yum install supervisor

配置supervisor,打开supervisor配置文件

vi /etc/supervisord.conf

[program:ssh]
command = /usr/sbin/sshd -D
;autorestart=true
autostart=true

[program:nginx]
command = /usr/sbin/nginx -g 'daemon off;'
autostart=true
autorestart=true
;stopsignal=QUIT

priority=10
stdout_events_enabled=true
stderr_events_enabled=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0

[program:php]
command = /usr/sbin/php-fpm --nodaemonize
autostart=true
autorestart=true

保存退出

现在看Kubernetes UI,看看相关的pod对应的容器日志有没有输出

生产环境使用 percona-toolkit 检查修复

tycho_yang阅读(2874)

        Mysql 在生产环境中总会遇到主从数据不一致引起的同步中断,或同步中断忽略跳过错误,就会出现数据不一致,通常要修复数据不一致,最有效方法就是主库锁库备份从库恢复数据,但实际生产环境中由于数据量大,备份恢复时间长,在恢复过程严重影响业务正常使用,所以这种方式很少在实际业务中用于修复数据,以下提供可以用于检测修复主从数据一致性工具

percona提供了一个很好的工具:percona-toolkit中的 pt-table-checksum 和 pt-table-sync

        pt-table-checksum是著名的 percona-toolkit 工具集的工具之一。它通过在主库执行基于statement的sql语句来生成主库数据块的checksum,把相同的sql语句传递到从库,并在从库上计算相同数据块的checksum,最后,比较主从库上相同数据块的checksum值,由此判断主从数据是否一致。这种校验是分表进行的,在每个表内部又是分块进行的,而且pt工具本身提供了非常多的限流选项,因此对线上服务的冲击较小。

checksum计算原理

1. 单行数据checksum值的计算

        pt工具先检查表的结构,并获取每一列的数据类型,把所有数据类型都转化为字符串,然后用 concat_ws() 函数进行连接,由此计算出该行的checksum值。checksum默认采用crc32,你可以自己定义效率更高的udf。

2. 数据块checksum值的计算

        如果一行一行的计算checksum再去和从库比较,那么效率会非常低下。pt工具选择智能分析表上的索引,然后把表的数据split成一个个chunk,计算的时候也是以chunk为单位。因此引入了聚合函数 BIT_XOR() 。它的功能可以理解为把这个chunk内的所有行的数据拼接起来,再计算crc32的值,就得到这个chunk的checksum值。这其中还有count(*),用来计算chunk包含的行数。每一次对chunk进行checksum后,pt工具都会对耗时进行统计分析,并智能调整下一个chunk的大小,避免chunk太大对线上造成影响,同时也要避免chunk太小而效率低下。

3. 一致性如何保证

        当pt工具在计算主库上某chunk的checksum时,主库可能还在更新,同时从库可能延迟使得relay-log中还有与这个chunk数据相关的更新,加for update当前读锁,这保证了主库的某个chunk内部数据的一致性。否则,1000个人chekcusm同样的1000行数据,可能得到1000个不同的结果,你无法避开mvcc的干扰!获得for update锁后,pt工具开始计算chunk的checksum值,并把计算结果保存到pt工具自建的结果表中(采用replace into select的方式),然后释放锁。该语句最终会传递到从库并执行相同的计算逻辑。

环境如下:

centos 6.9 64bit
mysql 5.6.35 x64

安装percona-toolkit工具

yum install https://www.percona.com/redir/downloads/percona-release/redhat/0.1-6/percona-release-0.1-6.noarch.rpm
yum install percona-toolkit

常用选项:

–check-replication-filters 是否检查复制过滤规则
–check-slave-tables 检查是否所有从库都有被检查的表和列
–chunk-size-limit 每个chunk最大不能超过这个大小,超过就忽略它

–check-interval 多久检查一次主从延迟、主库负载是否达到上限
–check-slave-lag 是否只检查这个从库的延迟
–max-lag 最大延迟,超过这个就等待
–max-load 最大负载,超过这个就等待

–databases 只检查某些库
–tables 只检查某些表

–resume 因某种原因中断,下次接着执行,不用从头开始
–chunk-time 每个chunk被计算的时间,一般默认为0.5秒

–recursion-method:发现从库的方式。pt-table-checksum 默认可以在主库的 processlist 中找到从库复制进程,从而识别出有哪些从库,但如果使用是非标准3306端口,会导致找不到从库信息。此时就会自动采用host方式,但需要提前在从库 my.cnf 里面配置report_host、report_port信息,如:
report_host = MASTER_HOST
report_port = 13306

分别在主从master/slave服务器授权用户的权限

GRANT SELECT, INSERT, UPDATE, DELETE, PROCESS, SUPER, REPLICATION SLAVE ON *.* TO 'percona_tk'@'192.168.%' IDENTIFIED BY '123456';

在master服务器上执行

pt-table-checksum --no-check-binlog-format --replicate=test1.checksums --databases=test1 h=MASTER_HOST,u=percona_tk,p='123456',P=3306 --recursion-method=processlist

[root@zk-kafka-n4 soft]# pt-table-checksum --no-check-binlog-format --replicate=test1.checksums --databases=test1 h=127.0.0.1,u=percona_tk,p=123456,P=3306 --recursion-method=processlist
Checking if all tables can be checksummed ...
Starting checksum ...
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-21T10:57:42 0 0 4 0 1 0 0.259 test1.test
  • TS :完成检查的时间戳。
  • ERRORS :检查时候发生错误和警告的数量。
  • DIFFS :不一致的chunk数量。当指定 --no-replicate-check 即检查完但不立即输出结果时,会一直为0;当指定 --replicate-check-only 即不检查只从checksums表中计算crc32,且只显示不一致的信息(毕竟输出的大部分应该是一致的,容易造成干扰)。
  • ROWS :比对的表行数。
  • CHUNKS :被划分到表中的块的数目。
  • SKIPPED :由于错误或警告或过大,则跳过块的数目。
  • TIME :执行的时间。
  • TABLE :被检查的表名

用dsns方式检测连接从,适合于主从非默认端口,processlist方式连接不上,host方式修改配置文件不想重启服务等。

REPLICA_HOST:3306 从库
PTCHECK_HOST pt-table-checksum所在服务器
DSN_DBHOST,记录从库(连接)dsns的数据库

dsn指定从库了,在同网段数据库主机里装上 percona-toolkit,不一定要在主从的服务器上使用

在DSN_DBHOST 数据库实例上创建DSNs表:

create database percona;
CREATE TABLE `percona`.`dsns` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent_id` int(11) DEFAULT NULL,
`dsn` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
);
GRANT ALL PRIVILEGEES on percona.* to percona_tk@'PTCHECK_HOST' IDENTIFIED BY 'percona_pass';

有多个实例要检查,可以创建多个类似的dsns表。上面的percona_tk用户只是用来访问dsn库。插入从库信息:

use percona;
insert into dsns(dsn) values('h=REPLICA_HOST,P=3306,u=repl_user,p=repl_pass');

DSNs记录dsn列格式如 h=REPLICA_HOST,u=repl_user,p=repl_pass

在 PTCHECK_HOST 上执行检查命令:

pt-table-checksum --no-check-binlog-format --replicate=test1.checksums --databases=test1 h=MASTER_HOST,u=percona_tk,p='123456',P=3306 --recursion-method dsn=h=DSN_DBHOST,u=percona_tk,p='percona_pass',P=3306,D=percona,t=dsns

percona提供了pt-table-sync 用于修复主从数据的一致性

pt-table-sync [OPTIONS] DSN [DSN]。
pt-table-sync: 高效的同步MySQL表之间的数据,他可以做单向和双向同步的表数据。他可以同步单个表,也可以同步整个库。它不同步表结构、索引、或任何其他模式对象。所以在修复一致性之前需要保证他们表存在。

打印修复的SQL语句(只打印不修复)

[root@zk-kafka-n4 soft]# pt-table-sync --print --replicate=test1.checksums --databases=test1 h=192.168.3.68,u=percona_tk,p=123456,P=3306 h=192.168.3.67,u=percona_tk,p=123456,P=3306
DELETE FROM `test1`.`test` WHERE `sdf`='888' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=zk-kafka-n3,p=...,u=percona_tk lock:1 transaction:1 changing_src:test1.checksums replicate:test1.checksums bidirectional:0 pid:16264 user:root host:zk-kafka-n4*/;
DELETE FROM `test1`.`test` WHERE `sdf`='990' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=zk-kafka-n3,p=...,u=percona_tk lock:1 transaction:1 changing_src:test1.checksums replicate:test1.checksums bidirectional:0 pid:16264 user:root host:zk-kafka-n4*/;

先MASTER的IP,再SLAVE的IP
以上是打印出同步语句

参数选项:

  • --replicate= :指定通过pt-table-checksum得到的表,这2个工具差不多都会一直用。
  • --databases= : 指定执行同步的数据库,多个用逗号隔开。
  • --tables= :指定执行同步的表,多个用逗号隔开。
  • --sync-to-master :指定一个DSN,即从的IP,他会通过show processlist或show slave status 去自动的找主。
  • h=127.0.0.1 :服务器地址,命令里有2个ip,第一次出现的是M的地址,第2次是Slave的地址。
  • u=root :帐号。
  • p=123456 :密码。
  • --print :打印,但不执行命令。
  • --execute :执行命令。

执行数据修复:

[root@zk-kafka-n4 soft]# pt-table-sync --execute --replicate=test1.checksums --databases=test1 h=192.168.3.68,u=percona_tk,p=123456,P=3306 h=192.168.3.67,u=percona_tk,p=123456,P=3306 --no-check-slave --print
DELETE FROM `test1`.`test` WHERE `sdf`='888' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=zk-kafka-n3,p=...,u=percona_tk lock:1 transaction:1 changing_src:test1.checksums replicate:test1.checksums bidirectional:0 pid:16276 user:root host:zk-kafka-n4*/;
DELETE FROM `test1`.`test` WHERE `sdf`='990' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=zk-kafka-n3,p=...,u=percona_tk lock:1 transaction:1 changing_src:test1.checksums replicate:test1.checksums bidirectional:0 pid:16276 user:root host:zk-kafka-n4*/;

检查修复结果:

[root@zk-kafka-n4 soft]# pt-table-checksum --no-check-binlog-format --replicate=test1.checksums --databases=test1 h=127.0.0.1,u=percona_tk,p=123456,P=3306 --recursion-method=processlist
Checking if all tables can be checksummed ...
Starting checksum ...
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-21T17:34:17 0 0 6 0 1 0 0.257 test1.test

数据破坏测试,在从机插入3条数据:

检测如下:

[root@zk-kafka-n4 soft]# pt-table-checksum --no-check-binlog-format --replicate=test1.checksums --databases=test1 h=127.0.0.1,u=percona_tk,p=123456,P=3306 --recursion-method=processlist
Checking if all tables can be checksummed ...
Starting checksum ...
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-21T17:41:17 0 1 8 3 1 0 0.259 test1.test

检测发现3条数据异常。

通过slave1-192.168.3.67上的所有数据和主库是同步的(建议用此方式修复,不需要输入master信息),对从机比对主机进行修复(以master数据为参照对象)

[root@zk-kafka-n4 soft]# pt-table-sync --execute --sync-to-master --databases=test1 h=192.168.3.67,u=percona_tk,p=123456,P=3306 --no-check-slave --print
REPLACE INTO `test1`.`checksums`(`db`, `tbl`, `chunk`, `chunk_time`, `chunk_index`, `lower_boundary`, `upper_boundary`, `this_crc`, `this_cnt`, `master_crc`, `master_cnt`, `ts`) VALUES ('test1', 'test', '1', 0.000956, NULL, NULL, NULL, 'e31529f0', '8', 'e31529f0', '8', '2018-06-21 17:41:17') /*percona-toolkit src_db:test1 src_tbl:checksums src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:checksums dst_dsn:P=3306,h=192.168.3.67,p=...,u=percona_tk lock:1 transaction:1 changing_src:1 replicate:0 bidirectional:0 pid:16298 user:root host:zk-kafka-n4*/;
DELETE FROM `test1`.`test` WHERE `sdf`='11234' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=192.168.3.67,p=...,u=percona_tk lock:1 transaction:1 changing_src:1 replicate:0 bidirectional:0 pid:16298 user:root host:zk-kafka-n4*/;
DELETE FROM `test1`.`test` WHERE `sdf`='5655' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=192.168.3.67,p=...,u=percona_tk lock:1 transaction:1 changing_src:1 replicate:0 bidirectional:0 pid:16298 user:root host:zk-kafka-n4*/;
DELETE FROM `test1`.`test` WHERE `sdf`='7744' LIMIT 1 /*percona-toolkit src_db:test1 src_tbl:test src_dsn:P=3306,h=192.168.3.68,p=...,u=percona_tk dst_db:test1 dst_tbl:test dst_dsn:P=3306,h=192.168.3.67,p=...,u=percona_tk lock:1 transaction:1 changing_src:1 replicate:0 bidirectional:0 pid:16298 user:root host:zk-kafka-n4*/;

修复后再检测下,看检测结果是否修复:

[root@zk-kafka-n4 soft]# pt-table-checksum --no-check-binlog-format --replicate=test1.checksums --databases=test1 h=127.0.0.1,u=percona_tk,p=123456,P=3306 --recursion-method=processlist
Checking if all tables can be checksummed ...
Starting checksum ...
TS ERRORS DIFFS ROWS DIFF_ROWS CHUNKS SKIPPED TIME TABLE
06-21T17:42:42 0 0 8 0 1 0 0.016 test1.test

显示无异常数据

 

 

WEB 应用防火墙实现(WAF) Centos 7 基于Nginx + ModSecurity 3.X

tycho_yang阅读(3683)

系统环境
centos 7.4 , nginx 1.14.0 , modsecurity-v3.0.2.tar.gz

安装依赖库

yum install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel doxygen zlib-devel GeoIP-data GeoIP
yum install gcc-c++ flex bison curl-devel curl libxml2-devel doxygen zlib-devel git automake libtool pcre-devel

编译libModSecurity

cd /data
###################################################### |
git clone https://github.com/SpiderLabs/ModSecurity    |
cd ModSecurity                                         |
git checkout -b v3/master origin/v3/master             |  官方直接用这种方式安装,经过多次测试效果不好,
sh build.sh                                            |  建议用下面这个下载后编译。
git submodule init                                     |
git submodule update                                   |
###################################################### |

wget https://github.com/SpiderLabs/ModSecurity/releases/download/v3.0.2/modsecurity-v3.0.2.tar.gz
tar -zxvf modsecurity-v3.0.2.tar.gz
mv modsecurity-v3.0.2 ModSecurity
cd ModSecurity
./configure
make
make install

安装完成后路径在

/usr/local/modsecurity/lib

安装nginx connector组件

export MODSECURITY_INC="/data/ModSecurity/headers/"
export MODSECURITY_LIB="/data/ModSecurity/src/.libs/"
cd /data
git clone https://github.com/SpiderLabs/ModSecurity-nginx
[root@10-9-168-43 soft]# nginx -V
nginx version: nginx/1.14.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

官网下载nginx 对应源码版本

wget http://nginx.org/download/nginx-1.14.0.tar.gz
tar -zxvf nginx-1.14.0.tar.gz
cd nginx-1.14.0

复制上面nginx -V 输出的configure arguments 后面的参数,再添加--add-dynamic-module=/data/ModSecurity-nginx参数上去

[root@10-9-168-43 nginx-1.14.0]# ./configure --prefix=/etc/nginx --add-dynamic-module=/data/ModSecurity-nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'

编译modules

make modules

编译完成的.so文件路径在当前目录下

./objs/ngx_http_modsecurity_module.so

复制链接库

cp ./objs/ngx_http_modsecurity_module.so /etc/nginx/modules/

在nginx 配置文件目录下创建个modsecurity 配置文件目录

mkdir -p /etc/nginx/modsec
cd /etc/nginx

下载modsecurity 规则库

wget https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/v3.0.2.tar.gz
tar -zxvf v3.0.2.tar.gz

解压完后删除v3.0.2.tar.gz 包

rm -rf v3.0.2.tar.gz
cd owasp-modsecurity-crs-3.0.2

复制个配置文件为crs‑setup.conf

cp crs-setup.conf.example crs-setup.conf

cd /etc/nginx/modsec
wget https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended
mv modsecurity.conf-recommended modsecurity.conf

查找
# SecRuleEngine DetectionOnly
替换为
SecRuleEngine On

_______________________________
创建 ModSecurity WAF 主配置文件,/etc/nginx/modsec/main.conf,用于引用modsecurity 所有相关配置文件,内容如下:

# Include the recommended configuration
Include /etc/nginx/modsec/modsecurity.conf

# A test rule
SecRule ARGS:testparam "@contains test" "id:1234,deny,log,status:403"

# OWASP CRS v3 rules
Include /etc/nginx/owasp-modsecurity-crs-3.0.2/crs-setup.conf
Include /etc/nginx/owasp-modsecurity-crs-3.0.2/rules/*.conf
_______________________________

修改nginx主配置文件

vim /etc/nginx/nginx.conf

增加一行,加载modsecurity.so 模块

load_module /etc/nginx/modules/ngx_http_modsecurity_module.so

创建测试配置文件

vi /etc/nginx/conf.d/echo.conf

server {
listen 0.0.0.0:8088;

location / {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
default_type text/plain;
return 200 "Thank you for requesting ${request_uri}\n";
}
}
curl -i http://127.0.0.1:8088/foo?testparam=dalongtest

已被拦截

查看日志

tail -f /var/log/modsec_audit.log
---dG6xPLPF---A--
[01/Jun/2018:16:28:46 +0800] 152784172665.503402 127.0.0.1 40172 127.0.0.1 8088
---dG6xPLPF---B--
GET /foo?testparam=dalongtest HTTP/1.1
User-Agent: curl/7.29.0
Host: 127.0.0.1:8088
Accept: */*

---dG6xPLPF---D--

---dG6xPLPF---E--
<html>\x0d\x0a<head><title>403 Forbidden</title></head>\x0d\x0a<body bgcolor="white">\x0d\x0a<center><h1>403 Forbidden</h1></center>\x0d\x0a<hr><center>nginx/1.14.0</center>\x0d\x0a</body>\x0d\x0a</html>\x0d\x0a

---dG6xPLPF---F--
HTTP/1.1 403
Server: nginx/1.14.0
Date: Fri, 01 Jun 2018 08:28:46 GMT
Content-Length: 169
Content-Type: text/html
Connection: keep-alive

---dG6xPLPF---H--
ModSecurity: Access denied with code 403 (phase 1). Matched "Operator `Contains' with parameter `test' against variable `ARGS:testparam' (Value: `dalongtest' ) [file "/etc/nginx/modsec/main.conf"] [line "115"] [id "1234"] [rev ""] [msg ""] [data ""] [severity "0"] [ver ""] [maturity "0"] [accuracy "0"] [hostname "127.0.0.1"] [uri "/foo"] [unique_id "152784172665.503402"] [ref "o6,4v19,10"]

---dG6xPLPF---I--

---dG6xPLPF---J--

---dG6xPLPF---Z--