[翻译]重做日志在MySQL InnoDB表中是如何工作的

MySQLzgtlm 发表了文章 • 0 个评论 • 523 次浏览 • 2016-11-20 14:43 • 来自相关话题

在本文中,我将描述日志在MySQL和InnoDB中是如何工作的。在手册中很少有相关的资料。这些是在我研究我们的新的书时候(SQL性能调优 by GPeter Gulutzan and Trudy Pelzer),从源代码收集到的信息。

如果你曾经使用过MySQL和InnoDB表,本文会给你一些其他地方找不到的“内幕”知识,所以请坐下来准备阅读吧!

## 当执行数据修改语句时会发生什么?

当你用更新、插入或删除请求改变数据的时候,你将在两个地方改变数据:日志缓冲和数据缓冲。缓冲是有固定长度的,通常512字节的倍数,它们保存在内存中——InnoDB还没有把他们写入磁盘。
```
LOG BUFFER(日志缓冲)           DATA BUFFER(数据缓冲)
=================        ===============
= Log Record #1 =                = Page Header =
= Log Record #2 =                = Data Row    =
= Log Record #3 =                = Data Row    =
= Log Record #4 =                = Data Row    =
=================        ===============
```
例如,在“INSERT INTO Jobs VALUES (1,2,3)“之后,日志缓冲将会有一个新的日志记录——称之为 “Log Record #5” 包含一个行标识符和这行的新内容。与此同时,数据缓冲将有一个新行,但它也将有一个在页面头部写入“这个页面的最新日志记录是 Log Record #5”。在这个例子中“#5”表示日志序列号(LSN),这对后面的调度操作是至关重要的。

一些关于数据修改的详细信息:
(a)插入日志记录只包含新的数据,这就足够了。这个过程在必要时可以在同一页重做。这就是所谓的“重做”条目。
(b)LSN不是日志记录的一个字段,而是,它是文件和字节偏移量的绝对地址。

InnoDB后改变了日志缓冲和缓冲的数据,一切都结束了,但磁盘还在写入。这正是事情变得复杂地方。有几个线程监控缓冲活动和并且有三种情况:溢出,Checkpoint和提交--这些情况会导致磁盘写。

## 当溢出时会发生什么?

溢出是罕见的,因为InnoDB采取积极的措施以防止缓冲用完(参见下面的“当Checkpoint时会发生什么”)。不过,让我们来讨论两种可能的情况。

情况一:如果日志缓冲满了,InnoD会在缓冲“结束”的地方写日志。我把“结束”一词写在引号里是因为一个日志文件,或更准确说的一组日志文件,看起来像一条蛇吞下它的尾巴。假设空间只够写四个日志记录,当我们写 #5的时候,那么它必须写在文件的开始。
```
写日志记录#5之前的日志文件
=================
= Log Record #1 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =
=================
```
```
写日志记录#5之后的日志文件
=================
= Log Record #5 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =
=================
```
不会有日志一直增长的情况出现。尽管InnoDB使用一些压缩技巧,日志文件也不会太大以至于任何磁盘驱动器都写不下。由于InnoDB会“循环”写入,这意味着它必须覆盖旧的日志记录。这个循环日志记录策意味着之后会再从这个地方写。

情况二:如果数据缓冲满了,InnoDB会将最近最少使用的缓冲写入数据库——但不是很快发生!这是页面头部里的LSN变得有用的地方。首先,InnoDB检查头部的LSN是否大于日志文件中的LSN。如果是大于,那么InnoDB必须先写日志,直到日志赶上数据页头部的LSN,才可以写入数据。换句话说数据页不会写入,直到已经写入相应的日志。这是常见的“写前先记日志”的原则,这对所有重要的DBMS来说都是通用的,除了InterBase。

## 当Checkpoint时会发生什么?

我之前说过InnoDB会对溢出采取一些积极的措施,其中最重要的措施是Checkpoint。有一个单独的线程,或者说独立于change buffer的联合线程。在固定时间间隔检Checkpoint线程会唤醒,查看缓冲的变化,确保发生写入。

据我所知,此时大多数DBMS的会把所有的东西都写入,这时就没有已改变但还没有写入的缓冲存在了。用常用的术语来说,DBMS将用“Sharp Checkpoint”Flush掉所有的“脏”缓冲。但InnoDB只确保:(a)日志和数据缓冲没有达到固定阈值点,(b)写数据页之前先写日志,(c)数据缓冲的页面头部的LSN对应的日志记录不会被覆盖。用行话来说,这意味着InnoDB是一个“Fuzzy Checkpoint”的粉丝。

在Checkpoint发生的时候,可能会写另一个日志记录说:当这个Checkpoint发生的时候,它是确定数据库是最新的,除了几个脏页,这是脏页的列表。当发生恢复过程的时候,这个信息可能非常有用,所以我之后会再次提到它。

## 当提交时会发生什么?

当提交时,InnoDB不会把所有脏数据页写到磁盘上。我之所以强调这一点,是因为很容易认为提交更改意味着将所有的变更写入到持久的介质上。InnoDB的人在这一点上更聪明。他们意识到只有日志需要写入。脏数据页可以在发生溢出或Checkpoint的时候写入,因为它们的内容是冗余的。假如在崩溃的时候日志存活,使用日志中的信息来重建数据页是可行的。

所以InnoDB应该只写日志。或者确切地说,InnoDB应该写日志,直到它将所有正在提交的事务的日志写入完成。因为所有日志写作是串行,这意味着InnoDB也必须为其他事务写日志,但是这没关系。

这里我必须把它放到关键位置,因为这不是InnoDB**必定**会做的。如果在MySQL的配置文件my.cnf中将innodb_flush_log_at_trx_commit参数的开关设为0,那么InnoDB在提交时会避免写日志。这意味着,一个成功的提交不会**保证**所有的数据变更被持久化了,虽然这是ANSI/ISO标准要求的。只有在Checkpoint发生的时候才能保证持久化。

无论如何,你可以将innodb_flush_log_at_trx_commit设置为1,在这种情况下一切就没问题了,InnoDB会写日志,并且InnoDB会Flush到磁盘上。
我最好解释Flush是什么,嗯?通常仅仅是写入就足够了,但所有现代操作系统出于效率原因会缓存写操作。为了“保证”数据被写入,InnoDB必须坚持告诉操作系统“我的意思是真正的写,我想要磁盘上的写入磁头写入数据,不要返回给我直到这个物理操作完成。”这意味着在Windows系统上InnoDB会调用Windows api函数FlushFilBuffers,这个调用意思是“Flush缓存”。这里InnoDB与微软的:SQL Server 2000 在写入时一样使用“Write though”选项,而不是写后再刷新。

## 恢复

我们现在回到这一点,使记录麻烦的日志变得有价值的地方:如果发生崩溃,你可以恢复你的数据。

当崩溃发生时数据没有融合到磁盘,恢复是自动的。InnoDB读取最后一个Checkpoint日志记录,查看一下“脏页”是否在崩溃之前写入了,并且(如果他们不是)读取影响这些脏页的日志,并且应用到这些脏页上。这就是所谓的“前滚”,有两个原因使其变得很容易: (1)由于LSN的存在,所以InnoDB只需要比较LSN数字就可以让其同步,(2)因为我遗漏了一些细节。

很好。现在,崩溃的数据是否真的融合到了磁盘驱动器上了吗?那么恢复场景取决于你的准备工作。

场景一:日志了丢失了。好吧,你应该准备在一个单独的驱动器上保留一个日志拷贝。InnoDB没有这样明确的选项,但是有专门的操作系统方法。

场景二:数据库丢失并且日志被覆盖了。嗯,你应该预料到,当日志循环记录时,日志记录#5会将日志记录#1覆盖。还记得吗?因此如果你没有在写入日志记录#1之后后进行备份,你已经丢失了数据。

场景三:数据库丢失但日志是完好的。在这种情况下,祝贺你。你只需要恢复你最后的备份,并且让整个日志前滚。如果你自上次完全备份后又备份了几次(“归档日志”)会有抱怨信息,但我假定这个选项是不可操作的。顺便说一下,我不是讨论MySQL的binlog。虽然这是对恢复过程是必不可少的,但是这不是InnoDB的一部分,超出了讨论范围。

## 结论

当理解了InnoDB的日志,你知道有一些需要注意地方。排名不分先后
- 使用较大的日志文件让上一次备份之后的日志不会被覆盖
- 让日志文件和数据文存储在不同的磁盘上
- 确保innodb_flush_log_at_trx_commit被正确的设置

希望本文能够帮助阐明严重缺乏文档的 MySQL InnoDB表的日志功能。如果你有任何问题或评论请用下面的论坛链接进讨论。

翻译自 How Logs Work On MySQL With InnoDB Tables
[原文链接](http://www.devarticles.com/c/a ... ables/)

水平有限,如有问题,欢迎指正。 查看全部
在本文中,我将描述日志在MySQL和InnoDB中是如何工作的。在手册中很少有相关的资料。这些是在我研究我们的新的书时候(SQL性能调优 by GPeter Gulutzan and Trudy Pelzer),从源代码收集到的信息。

如果你曾经使用过MySQL和InnoDB表,本文会给你一些其他地方找不到的“内幕”知识,所以请坐下来准备阅读吧!

## 当执行数据修改语句时会发生什么?

当你用更新、插入或删除请求改变数据的时候,你将在两个地方改变数据:日志缓冲和数据缓冲。缓冲是有固定长度的,通常512字节的倍数,它们保存在内存中——InnoDB还没有把他们写入磁盘。
```
LOG BUFFER(日志缓冲)           DATA BUFFER(数据缓冲)
=================        ===============
= Log Record #1 =                = Page Header =
= Log Record #2 =                = Data Row    =
= Log Record #3 =                = Data Row    =
= Log Record #4 =                = Data Row    =
=================        ===============
```
例如,在“INSERT INTO Jobs VALUES (1,2,3)“之后,日志缓冲将会有一个新的日志记录——称之为 “Log Record #5” 包含一个行标识符和这行的新内容。与此同时,数据缓冲将有一个新行,但它也将有一个在页面头部写入“这个页面的最新日志记录是 Log Record #5”。在这个例子中“#5”表示日志序列号(LSN),这对后面的调度操作是至关重要的。

一些关于数据修改的详细信息:
(a)插入日志记录只包含新的数据,这就足够了。这个过程在必要时可以在同一页重做。这就是所谓的“重做”条目。
(b)LSN不是日志记录的一个字段,而是,它是文件和字节偏移量的绝对地址。

InnoDB后改变了日志缓冲和缓冲的数据,一切都结束了,但磁盘还在写入。这正是事情变得复杂地方。有几个线程监控缓冲活动和并且有三种情况:溢出,Checkpoint和提交--这些情况会导致磁盘写。

## 当溢出时会发生什么?

溢出是罕见的,因为InnoDB采取积极的措施以防止缓冲用完(参见下面的“当Checkpoint时会发生什么”)。不过,让我们来讨论两种可能的情况。

情况一:如果日志缓冲满了,InnoD会在缓冲“结束”的地方写日志。我把“结束”一词写在引号里是因为一个日志文件,或更准确说的一组日志文件,看起来像一条蛇吞下它的尾巴。假设空间只够写四个日志记录,当我们写 #5的时候,那么它必须写在文件的开始。
```
写日志记录#5之前的日志文件
=================
= Log Record #1 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =
=================
```
```
写日志记录#5之后的日志文件
=================
= Log Record #5 =
= Log Record #2 =
= Log Record #3 =
= Log Record #4 =
=================
```
不会有日志一直增长的情况出现。尽管InnoDB使用一些压缩技巧,日志文件也不会太大以至于任何磁盘驱动器都写不下。由于InnoDB会“循环”写入,这意味着它必须覆盖旧的日志记录。这个循环日志记录策意味着之后会再从这个地方写。

情况二:如果数据缓冲满了,InnoDB会将最近最少使用的缓冲写入数据库——但不是很快发生!这是页面头部里的LSN变得有用的地方。首先,InnoDB检查头部的LSN是否大于日志文件中的LSN。如果是大于,那么InnoDB必须先写日志,直到日志赶上数据页头部的LSN,才可以写入数据。换句话说数据页不会写入,直到已经写入相应的日志。这是常见的“写前先记日志”的原则,这对所有重要的DBMS来说都是通用的,除了InterBase。

## 当Checkpoint时会发生什么?

我之前说过InnoDB会对溢出采取一些积极的措施,其中最重要的措施是Checkpoint。有一个单独的线程,或者说独立于change buffer的联合线程。在固定时间间隔检Checkpoint线程会唤醒,查看缓冲的变化,确保发生写入。

据我所知,此时大多数DBMS的会把所有的东西都写入,这时就没有已改变但还没有写入的缓冲存在了。用常用的术语来说,DBMS将用“Sharp Checkpoint”Flush掉所有的“脏”缓冲。但InnoDB只确保:(a)日志和数据缓冲没有达到固定阈值点,(b)写数据页之前先写日志,(c)数据缓冲的页面头部的LSN对应的日志记录不会被覆盖。用行话来说,这意味着InnoDB是一个“Fuzzy Checkpoint”的粉丝。

在Checkpoint发生的时候,可能会写另一个日志记录说:当这个Checkpoint发生的时候,它是确定数据库是最新的,除了几个脏页,这是脏页的列表。当发生恢复过程的时候,这个信息可能非常有用,所以我之后会再次提到它。

## 当提交时会发生什么?

当提交时,InnoDB不会把所有脏数据页写到磁盘上。我之所以强调这一点,是因为很容易认为提交更改意味着将所有的变更写入到持久的介质上。InnoDB的人在这一点上更聪明。他们意识到只有日志需要写入。脏数据页可以在发生溢出或Checkpoint的时候写入,因为它们的内容是冗余的。假如在崩溃的时候日志存活,使用日志中的信息来重建数据页是可行的。

所以InnoDB应该只写日志。或者确切地说,InnoDB应该写日志,直到它将所有正在提交的事务的日志写入完成。因为所有日志写作是串行,这意味着InnoDB也必须为其他事务写日志,但是这没关系。

这里我必须把它放到关键位置,因为这不是InnoDB**必定**会做的。如果在MySQL的配置文件my.cnf中将innodb_flush_log_at_trx_commit参数的开关设为0,那么InnoDB在提交时会避免写日志。这意味着,一个成功的提交不会**保证**所有的数据变更被持久化了,虽然这是ANSI/ISO标准要求的。只有在Checkpoint发生的时候才能保证持久化。

无论如何,你可以将innodb_flush_log_at_trx_commit设置为1,在这种情况下一切就没问题了,InnoDB会写日志,并且InnoDB会Flush到磁盘上。
我最好解释Flush是什么,嗯?通常仅仅是写入就足够了,但所有现代操作系统出于效率原因会缓存写操作。为了“保证”数据被写入,InnoDB必须坚持告诉操作系统“我的意思是真正的写,我想要磁盘上的写入磁头写入数据,不要返回给我直到这个物理操作完成。”这意味着在Windows系统上InnoDB会调用Windows api函数FlushFilBuffers,这个调用意思是“Flush缓存”。这里InnoDB与微软的:SQL Server 2000 在写入时一样使用“Write though”选项,而不是写后再刷新。

## 恢复

我们现在回到这一点,使记录麻烦的日志变得有价值的地方:如果发生崩溃,你可以恢复你的数据。

当崩溃发生时数据没有融合到磁盘,恢复是自动的。InnoDB读取最后一个Checkpoint日志记录,查看一下“脏页”是否在崩溃之前写入了,并且(如果他们不是)读取影响这些脏页的日志,并且应用到这些脏页上。这就是所谓的“前滚”,有两个原因使其变得很容易: (1)由于LSN的存在,所以InnoDB只需要比较LSN数字就可以让其同步,(2)因为我遗漏了一些细节。

很好。现在,崩溃的数据是否真的融合到了磁盘驱动器上了吗?那么恢复场景取决于你的准备工作。

场景一:日志了丢失了。好吧,你应该准备在一个单独的驱动器上保留一个日志拷贝。InnoDB没有这样明确的选项,但是有专门的操作系统方法。

场景二:数据库丢失并且日志被覆盖了。嗯,你应该预料到,当日志循环记录时,日志记录#5会将日志记录#1覆盖。还记得吗?因此如果你没有在写入日志记录#1之后后进行备份,你已经丢失了数据。

场景三:数据库丢失但日志是完好的。在这种情况下,祝贺你。你只需要恢复你最后的备份,并且让整个日志前滚。如果你自上次完全备份后又备份了几次(“归档日志”)会有抱怨信息,但我假定这个选项是不可操作的。顺便说一下,我不是讨论MySQL的binlog。虽然这是对恢复过程是必不可少的,但是这不是InnoDB的一部分,超出了讨论范围。

## 结论

当理解了InnoDB的日志,你知道有一些需要注意地方。排名不分先后
- 使用较大的日志文件让上一次备份之后的日志不会被覆盖
- 让日志文件和数据文存储在不同的磁盘上
- 确保innodb_flush_log_at_trx_commit被正确的设置

希望本文能够帮助阐明严重缺乏文档的 MySQL InnoDB表的日志功能。如果你有任何问题或评论请用下面的论坛链接进讨论。

翻译自 How Logs Work On MySQL With InnoDB Tables
[原文链接](http://www.devarticles.com/c/a ... ables/)

水平有限,如有问题,欢迎指正。

Keepalived在故障切换过程中出现多个检查脚本进程初探

MySQLkjy8460106 回复了问题 • 6 人关注 • 1 个回复 • 1111 次浏览 • 2016-11-16 11:16 • 来自相关话题

Percona新出的监控工具PMM

MySQLrenguanya 发表了文章 • 1 个评论 • 1375 次浏览 • 2016-11-15 10:41 • 来自相关话题

1.1 PMM简介
PMM is a free and open-source solution that you can run in your own environment for maximum security and reliability. It provides thorough time-based analysis for MySQL and MongoDB servers to ensure that your data works as efficiently as possible.
The following diagram illustrates how PMM is currently structured:

PMM Client is distributed as a tarball that you can install on any database host that you want to monitor.

PMM Server is distributed as a Docker image that you can use to run a container on the machine that will be your central monitoring host.

1.2 PMM安装
1.2.1 安装docker
[root@bogon ~]# rpm -iUvh http://dl.fedoraproject.org/pu ... h.rpm
[root@bogon ~]# yum install docker-io -y
[root@bogon ~]# /etc/init.d/docker start
1.2.2 安装pmm
Step 1. Create a PMM Data Container
To create a container for persistent PMM data, run the following command:
此步如果执行不成功,则需要翻墙,因为需要把docker pmm-server的镜像拉取下来
docker create \
-v /opt/prometheus/data \
-v /opt/consul-data \
-v /var/lib/mysql \
--name pmm-data \
percona/pmm-server:1.0.4 /bin/true
Step 2. Create and Run the PMM Server Container
To run PMM Server, use the following command:
docker run -d \
-p 80:80 \
--volumes-from pmm-data \
--name pmm-server \
--restart always \
percona/pmm-server:1.0.4
Step 3. Verify Installation
When the container starts, you should be able to access the PMM web interfaces using the IP address of the host where the container is running. For example, if it is running on 192.168.100.1 with default port 80, you should be able to access the following:
需要翻墙,才能看到

Installing PMM Client¶
PMM Client is a package of agents and exporters installed on a MySQL or MongoDB host that you want to monitor. The components collect various data about general system and database performance, and send this data to corresponding PMM Server components.
Before installing the PMM Client package on a database host, make sure that your PMM Serverhost is accessible. For example, you can ping 192.168.100.1 or whatever IP address PMM Server is running on.
You will need to have root access on the database host where you will be installing PMM Client(either logged in as a user with root privileges or be able to run commands with sudo). PMM Clientshould run on any modern Linux distribution.
The minimum requirements for Query Analytics (QAN) are:
• MySQL 5.1 or later (if using the slow query log)
• MySQL 5.6.9 or later (if using Performance Schema)
Note
You should not install agents on database servers that have the same host name, because host names are used by PMM Server to identify collected data.
1. Download the latest package From
https://www.percona.com/downlo ... EST/. For example, you can use wget as follows:
wget https://www.percona.com/downlo ... 4.rpm
2. Install the package:
rpm -ivh pmm-client-1.0.4-1.x86_64.rpm
Connecting to PMM Server
To connect the client to PMM Server, specify the IP address using the pmm-admin config --server command. For example, if PMM Server is running on 192.168.100.1, and you installedPMM Client on a machine with IP 192.168.200.1:
$ sudo pmm-admin config --server 192.168.100.1
OK, PMM server is alive.

PMM Server | 192.168.100.1
Client Name | ubuntu-amd64
Client Address | 192.168.200.1
Note
If you changed the default port 80 when creating the PMM Server container, specify it after the server’s IP address. For example:
pmm-admin config --server 192.168.100.1:8080
Starting Data Collection
To enable data collection, use the pmm-admin add command.
For general system metrics, MySQL metrics, and query analytics:
sudo pmm-admin add mysql
For general system metrics and MongoDB metrics:
sudo pmm-admin add mongodb
To see what is being monitored:
sudo pmm-admin list
For example, if you enable general OS and MongoDB metrics monitoring, output should be similar to the following:
$ sudo pmm-admin list
pmm-admin 1.0.4

PMM Server | 192.168.100.1
Client Name | ubuntu-amd64
Client Address | 192.168.200.1
Service manager | linux-systemd

---------------- ------------- ------------ -------- --------------- --------
METRIC SERVICE NAME CLIENT PORT RUNNING DATA SOURCE OPTIONS
---------------- ------------- ------------ -------- --------------- --------
linux:metrics ubuntu-amd64 42000 YES -
mongodb:metrics ubuntu-amd64 42003 YES localhost:27017
For more information about adding instances, run pmm-admin add --help.
For more information about managing PMM Client with the pmm-admin tool, see Managing PMM Client.
报错:
[root@bogon ~]# pmm-admin add mysql --socket=/tmp/mysql3306.sock
[linux:metrics] OK, already monitoring this system.
[mysql:metrics] Cannot connect to MySQL: Error 1045: Access denied for user 'root'@'localhost' (using password: NO)

Verify that MySQL user exists and has the correct privileges.
Use additional flags --user, --password, --host, --port, --socket if needed.
成功:
[root@bogon ~]# pmm-admin add mysql --socket=/tmp/mysql3306.sock --password=123456
[linux:metrics] OK, already monitoring this system.
[mysql:metrics] OK, now monitoring MySQL metrics using DSN root:***@unix(/tmp/mysql3306.sock)
[mysql:queries] OK, now monitoring MySQL queries from slowlog using DSN root:***@unix(/tmp/mysql3306.sock)
[root@bogon ~]# pmm-admin list
pmm-admin 1.0.4

PMM Server | 10.0.0.5
Client Name | bogon
Client Address | 10.0.0.5
Service manager | unix-systemv

-------------- ------ ------------ -------- ----------------------------------- ---------------------
SERVICE TYPE NAME CLIENT PORT RUNNING DATA SOURCE OPTIONS
-------------- ------ ------------ -------- ----------------------------------- ---------------------
linux:metrics bogon 42000 YES -
mysql:queries bogon 42001 YES root:***@unix(/tmp/mysql3306.sock) query_source=slowlog
mysql:metrics bogon 42002 YES root:***@unix(/tmp/mysql3306.sock)
添加多实例使用方法:
[root@bogon ~]# pmm-admin add mysql --help
This command adds the given MySQL instance to system, metrics and queries monitoring.

When adding a MySQL instance, this tool tries to auto-detect the DSN and credentials.
If you want to create a new user to be used for metrics collecting, provide --create-user option. pmm-admin will create
a new user 'pmm@' automatically using the given (auto-detected) MySQL credentials for granting purpose.

Table statistics is automatically disabled when there are more than 10000 tables on MySQL.

[name] is an optional argument, by default it is set to the client name of this PMM client.

Usage:
pmm-admin add mysql [name] [flags]

Examples:
pmm-admin add mysql --password abc123
pmm-admin add mysql --password abc123 --create-user

Flags:
--create-user create a new MySQL user
--create-user-maxconn uint max user connections for a new user (default 5)
--create-user-password string optional password for a new MySQL user
--defaults-file string path to my.cnf
--disable-binlogstats disable binlog statistics
--disable-processlist disable process state metrics
--disable-tablestats disable table statistics (disabled automatically with 10000+ tables)
--disable-userstats disable user statistics
--force force to create/update MySQL user
--host string MySQL host
--password string MySQL password
--port string MySQL port
--query-source string source of SQL queries: auto, slowlog, perfschema (default "auto")
--socket string MySQL socket
--user string MySQL username

Global Flags:
-c, --config-file string PMM config file (default "/usr/local/percona/pmm-client/pmm.yml")
--service-port uint service port
Security Features in Percona Monitoring and Management
You can protect PMM from unauthorized access using the following security features:
• HTTP password protection adds authentication when accessing the PMM Server web interface
• SSL encryption secures traffic between PMM Client and PMM Server
Enabling Password Protection
You can set the password for accessing the PMM Server web interface by passing the SERVER_PASSWORD environment variable when creating and running the PMM Server container. To set the environment variable, use the -e option. For example, to set the password to pass1234:
-e SERVER_PASSWORD=pass1234
By default, the user name is pmm. You can change it by passing the SERVER_USER variable.
For example:
docker run -d -p 80:80 \
--volumes-from pmm-data \
--name pmm-server \
-e SERVER_USER=xiaoya \
-e SERVER_PASSWORD=123456 \
--restart always \
percona/pmm-server:1.0.4
PMM Client uses the same credentials to communicate with PMM Server. If you set the user name and password as described, specify them when Connecting to PMM Server:
pmm-admin config --server 192.168.100.1 --server-user jsmith --server-password pass1234 查看全部
1.1 PMM简介
PMM is a free and open-source solution that you can run in your own environment for maximum security and reliability. It provides thorough time-based analysis for MySQL and MongoDB servers to ensure that your data works as efficiently as possible.
The following diagram illustrates how PMM is currently structured:

PMM Client is distributed as a tarball that you can install on any database host that you want to monitor.

PMM Server is distributed as a Docker image that you can use to run a container on the machine that will be your central monitoring host.

1.2 PMM安装
1.2.1 安装docker
[root@bogon ~]# rpm -iUvh http://dl.fedoraproject.org/pu ... h.rpm
[root@bogon ~]# yum install docker-io -y
[root@bogon ~]# /etc/init.d/docker start
1.2.2 安装pmm
Step 1. Create a PMM Data Container
To create a container for persistent PMM data, run the following command:
此步如果执行不成功,则需要翻墙,因为需要把docker pmm-server的镜像拉取下来
docker create \
-v /opt/prometheus/data \
-v /opt/consul-data \
-v /var/lib/mysql \
--name pmm-data \
percona/pmm-server:1.0.4 /bin/true
Step 2. Create and Run the PMM Server Container
To run PMM Server, use the following command:
docker run -d \
-p 80:80 \
--volumes-from pmm-data \
--name pmm-server \
--restart always \
percona/pmm-server:1.0.4
Step 3. Verify Installation
When the container starts, you should be able to access the PMM web interfaces using the IP address of the host where the container is running. For example, if it is running on 192.168.100.1 with default port 80, you should be able to access the following:
需要翻墙,才能看到

Installing PMM Client¶
PMM Client is a package of agents and exporters installed on a MySQL or MongoDB host that you want to monitor. The components collect various data about general system and database performance, and send this data to corresponding PMM Server components.
Before installing the PMM Client package on a database host, make sure that your PMM Serverhost is accessible. For example, you can ping 192.168.100.1 or whatever IP address PMM Server is running on.
You will need to have root access on the database host where you will be installing PMM Client(either logged in as a user with root privileges or be able to run commands with sudo). PMM Clientshould run on any modern Linux distribution.
The minimum requirements for Query Analytics (QAN) are:
• MySQL 5.1 or later (if using the slow query log)
• MySQL 5.6.9 or later (if using Performance Schema)
Note
You should not install agents on database servers that have the same host name, because host names are used by PMM Server to identify collected data.
1. Download the latest package From
https://www.percona.com/downlo ... EST/. For example, you can use wget as follows:
wget https://www.percona.com/downlo ... 4.rpm
2. Install the package:
rpm -ivh pmm-client-1.0.4-1.x86_64.rpm
Connecting to PMM Server
To connect the client to PMM Server, specify the IP address using the pmm-admin config --server command. For example, if PMM Server is running on 192.168.100.1, and you installedPMM Client on a machine with IP 192.168.200.1:
$ sudo pmm-admin config --server 192.168.100.1
OK, PMM server is alive.

PMM Server | 192.168.100.1
Client Name | ubuntu-amd64
Client Address | 192.168.200.1
Note
If you changed the default port 80 when creating the PMM Server container, specify it after the server’s IP address. For example:
pmm-admin config --server 192.168.100.1:8080
Starting Data Collection
To enable data collection, use the pmm-admin add command.
For general system metrics, MySQL metrics, and query analytics:
sudo pmm-admin add mysql
For general system metrics and MongoDB metrics:
sudo pmm-admin add mongodb
To see what is being monitored:
sudo pmm-admin list
For example, if you enable general OS and MongoDB metrics monitoring, output should be similar to the following:
$ sudo pmm-admin list
pmm-admin 1.0.4

PMM Server | 192.168.100.1
Client Name | ubuntu-amd64
Client Address | 192.168.200.1
Service manager | linux-systemd

---------------- ------------- ------------ -------- --------------- --------
METRIC SERVICE NAME CLIENT PORT RUNNING DATA SOURCE OPTIONS
---------------- ------------- ------------ -------- --------------- --------
linux:metrics ubuntu-amd64 42000 YES -
mongodb:metrics ubuntu-amd64 42003 YES localhost:27017
For more information about adding instances, run pmm-admin add --help.
For more information about managing PMM Client with the pmm-admin tool, see Managing PMM Client.
报错:
[root@bogon ~]# pmm-admin add mysql --socket=/tmp/mysql3306.sock
[linux:metrics] OK, already monitoring this system.
[mysql:metrics] Cannot connect to MySQL: Error 1045: Access denied for user 'root'@'localhost' (using password: NO)

Verify that MySQL user exists and has the correct privileges.
Use additional flags --user, --password, --host, --port, --socket if needed.
成功:
[root@bogon ~]# pmm-admin add mysql --socket=/tmp/mysql3306.sock --password=123456
[linux:metrics] OK, already monitoring this system.
[mysql:metrics] OK, now monitoring MySQL metrics using DSN root:***@unix(/tmp/mysql3306.sock)
[mysql:queries] OK, now monitoring MySQL queries from slowlog using DSN root:***@unix(/tmp/mysql3306.sock)
[root@bogon ~]# pmm-admin list
pmm-admin 1.0.4

PMM Server | 10.0.0.5
Client Name | bogon
Client Address | 10.0.0.5
Service manager | unix-systemv

-------------- ------ ------------ -------- ----------------------------------- ---------------------
SERVICE TYPE NAME CLIENT PORT RUNNING DATA SOURCE OPTIONS
-------------- ------ ------------ -------- ----------------------------------- ---------------------
linux:metrics bogon 42000 YES -
mysql:queries bogon 42001 YES root:***@unix(/tmp/mysql3306.sock) query_source=slowlog
mysql:metrics bogon 42002 YES root:***@unix(/tmp/mysql3306.sock)
添加多实例使用方法:
[root@bogon ~]# pmm-admin add mysql --help
This command adds the given MySQL instance to system, metrics and queries monitoring.

When adding a MySQL instance, this tool tries to auto-detect the DSN and credentials.
If you want to create a new user to be used for metrics collecting, provide --create-user option. pmm-admin will create
a new user 'pmm@' automatically using the given (auto-detected) MySQL credentials for granting purpose.

Table statistics is automatically disabled when there are more than 10000 tables on MySQL.

[name] is an optional argument, by default it is set to the client name of this PMM client.

Usage:
pmm-admin add mysql [name] [flags]

Examples:
pmm-admin add mysql --password abc123
pmm-admin add mysql --password abc123 --create-user

Flags:
--create-user create a new MySQL user
--create-user-maxconn uint max user connections for a new user (default 5)
--create-user-password string optional password for a new MySQL user
--defaults-file string path to my.cnf
--disable-binlogstats disable binlog statistics
--disable-processlist disable process state metrics
--disable-tablestats disable table statistics (disabled automatically with 10000+ tables)
--disable-userstats disable user statistics
--force force to create/update MySQL user
--host string MySQL host
--password string MySQL password
--port string MySQL port
--query-source string source of SQL queries: auto, slowlog, perfschema (default "auto")
--socket string MySQL socket
--user string MySQL username

Global Flags:
-c, --config-file string PMM config file (default "/usr/local/percona/pmm-client/pmm.yml")
--service-port uint service port
Security Features in Percona Monitoring and Management
You can protect PMM from unauthorized access using the following security features:
• HTTP password protection adds authentication when accessing the PMM Server web interface
• SSL encryption secures traffic between PMM Client and PMM Server
Enabling Password Protection
You can set the password for accessing the PMM Server web interface by passing the SERVER_PASSWORD environment variable when creating and running the PMM Server container. To set the environment variable, use the -e option. For example, to set the password to pass1234:
-e SERVER_PASSWORD=pass1234
By default, the user name is pmm. You can change it by passing the SERVER_USER variable.
For example:
docker run -d -p 80:80 \
--volumes-from pmm-data \
--name pmm-server \
-e SERVER_USER=xiaoya \
-e SERVER_PASSWORD=123456 \
--restart always \
percona/pmm-server:1.0.4
PMM Client uses the same credentials to communicate with PMM Server. If you set the user name and password as described, specify them when Connecting to PMM Server:
pmm-admin config --server 192.168.100.1 --server-user jsmith --server-password pass1234

传统复制迁移到GTID复制上?

MySQLA390_Fander 回复了问题 • 2 人关注 • 1 个回复 • 697 次浏览 • 2016-11-15 02:04 • 来自相关话题

shell小招 自动 切换当前会话目录

LinuxA390_Fander 回复了问题 • 4 人关注 • 2 个回复 • 851 次浏览 • 2016-11-15 01:37 • 来自相关话题

记录一次诡异的慢查询问题

MySQLyaowenlong 发表了文章 • 2 个评论 • 618 次浏览 • 2016-11-09 16:11 • 来自相关话题

第一次写事故记录,思路有些混乱,大家将就看一下哈   
   昨天公司促销,今天,研发过来找到我们说他们有个sql跑不出来结果(PS:大促降级我们设置有pt-kill,5秒不出结果的查询会被kill)
我们首先想到的是看监控,从监控数据上看:
系统现象1:cpuload很高,直接打到了10;
     2:网络连接状态正常;
     3:内存使用正常还有30G物理内存:
     4:磁盘io正常,util不到1.
发现只有cpuload很高,并且是user时间占用高,不是sys占用时间。
继续查看mysql的监控数据:连接数正常,300左右,
                活跃连接数正常,10以内。
                qps,2k左右,也不高
               没有超长的锁等待时间,说明不是锁引起,确实是查询很慢。
               还没找到问题所在,继续排查,慢日志,





只有两条,
查看第一条的执行计划:





 
执行计划有 Using filesort ,但是两个查询rows 为1; select 结果基本只有1条少量可能有几条(在研发出了解到);从sql和执行计划来看没发现什么问题,是很简单的查询。
于是想到是否是配置参数的问题,比如innodb_buffer_pool_size配置小了,
发现是80G,并不小;顺便查看了一下状态:

mysql> show status like '%buffer_pool%';
+---------------------------------------+--------------+
| Variable_name                         | Value        |
+---------------------------------------+--------------+
| Innodb_buffer_pool_pages_data         | 5242872      |
| Innodb_buffer_pool_pages_dirty        | 26725        |
| Innodb_buffer_pool_pages_flushed      | 928942474    |
| Innodb_buffer_pool_pages_free         | 3            |
| Innodb_buffer_pool_pages_misc         | 1            |
| Innodb_buffer_pool_pages_total        | 5242876      |
| Innodb_buffer_pool_read_ahead_rnd     | 0            |
| Innodb_buffer_pool_read_ahead         | 12430752     |
| Innodb_buffer_pool_read_ahead_evicted | 53538        |
| Innodb_buffer_pool_read_requests      | 371347304415 |
| Innodb_buffer_pool_reads              | 34573956     |
| Innodb_buffer_pool_wait_free          | 0            |
| Innodb_buffer_pool_write_requests     | 12426911055  |
看起来没有异常;
至此感觉进入了迷茫期了,只是发现了莫名其妙的cpuload高,其它没发现任何异常,诡异啊!
然后继续理清思路,该实例只是一个sharing的一个从库,为啥就这台有问题,其他3台都没有问题。于是开始对比该机器和其他从的机器参数。
发现,numa都是关闭了,磁盘一样,内存一样,等等,cpu貌似不对,有问题的这台机器的cpu核心只有24个,主频只有1.8GHZ,其它是机器是32核心,主频是2.3GHZ;难道问题就这个?cpu太烂?
感觉发现了新大陆一样,等等 不对呀,cpu至少还是24核1.8GHZ,pci-e卡,128G内存的服务器的mysql跑这么简单的sql,QPS只能跑到2k,而且5s都不能出数据,想想都不合理啊。但是到目前都还没发现其它有力证据说明是其他问题,难道需要换服务器,没资源啊。于是就开始浮想翩翩了。不了了之,问题也不能富县,姑且就当是一个灵异事件吧;
然后想着在看看这个sql吧。
mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )     ORDER BY shipping_no;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.01 sec)

mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )     ORDER BY shipping_no;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.01 sec)
连续执行2次,都是0.01秒
去掉order by 子句

mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )   ;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.00 sec)

mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )   ;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.00 sec)
连续执行两次都是0.00秒,sql问题? 虽然不确定是这个问题但是修改后效果确实是有的,于是准备找研发沟通一下是否可以修改一下sql;………………饭点到了,先吃了饭在说吧 这个反正不急(准时吃饭还是有好处呀,不然可能就找不到真实原因了!!)
 
在休的时候,研发有来找我们,说问题有出现了,查不出结果了。
登陆服务器继续排查问题,这次虽然抓住了现场,但是除了之前监控发现的问题,没有任何新的进展!总觉得这个机器不会骗人,哪里来的那么多诡异事件呢,于是继续排查问题,对比一下参数:
问题机器:
mysql>  show variables like '%buff%';
+------------------------------+-------------+
| Variable_name                | Value       |
+------------------------------+-------------+
| bulk_insert_buffer_size      | 8388608     |
| innodb_buffer_pool_instances | 4           |
| innodb_buffer_pool_size      | 85899345920 |
| innodb_change_buffering      | inserts     |
| innodb_log_buffer_size       | 16777216    |
| join_buffer_size             | 67108864    |
| key_buffer_size              | 536870912   |
| myisam_sort_buffer_size      | 8388608     |
| net_buffer_length            | 16384       |
| preload_buffer_size          | 32768       |
| read_buffer_size             | 67108864    |
| read_rnd_buffer_size         | 67108864    |
| sort_buffer_size             | 536870912   |
| sql_buffer_result            | OFF         |
+------------------------------+-------------+
14 rows in set (0.00 sec)
正常机器:
mysql> show variables like '%buff%';
+------------------------------+-------------+
| Variable_name                | Value       |
+------------------------------+-------------+
| bulk_insert_buffer_size      | 8388608     |
| innodb_buffer_pool_instances | 4           |
| innodb_buffer_pool_size      | 85899345920 |
| innodb_change_buffering      | inserts     |
| innodb_log_buffer_size       | 16777216    |
| join_buffer_size             | 2097152     |
| key_buffer_size              | 536870912   |
| myisam_sort_buffer_size      | 8388608     |
| net_buffer_length            | 16384       |
| preload_buffer_size          | 32768       |
| read_buffer_size             | 2097152     |
| read_rnd_buffer_size         | 2097152     |
| sort_buffer_size             | 2097152     |
| sql_buffer_result            | OFF         |
 
read_buffer_size,join_buffer_size,sort_buffer_size,read_rnd_buffer_size
这几个参数的值区别有点大呢,是不是这个问题?老师说这些参数最好不要改大了,不然容易oom,但是没说会影响性能啊,管他呢,先改一波,改小应该没有风险,直接都改小。
重启连接池。问题貌似解决了,至今没有发现问题
然后去官网查了这个几个参数的解释:
 
join_buffer_size:
说了一段这个:Memory allocation time can cause substantial performance drops if the global size is larger than needed by most queries that use it.
sort_buffer_size:
, there are thresholds of 256KB and 2MB where larger values may significantly slow down memory allocation, so you should consider staying below one of those values. Experiment to find the best value for your workload
两个的大意都是说分配内容需要花费很多时间,如果分配或多会严重影响查询效率;
 
经过这次问题:得到两点心得:
       1、找问题一定要有耐性,需要思路清晰,不要轻易相信有灵异事件发生。
       2、遇到所谓的灵异事件,坚持的越久,越可能找到问题所在。
       3、多看官方文档,这个很重要!! 查看全部
第一次写事故记录,思路有些混乱,大家将就看一下哈   
   昨天公司促销,今天,研发过来找到我们说他们有个sql跑不出来结果(PS:大促降级我们设置有pt-kill,5秒不出结果的查询会被kill)
我们首先想到的是看监控,从监控数据上看:
系统现象1:cpuload很高,直接打到了10;
     2:网络连接状态正常;
     3:内存使用正常还有30G物理内存:
     4:磁盘io正常,util不到1.
发现只有cpuload很高,并且是user时间占用高,不是sys占用时间。
继续查看mysql的监控数据:连接数正常,300左右,
                活跃连接数正常,10以内。
                qps,2k左右,也不高
               没有超长的锁等待时间,说明不是锁引起,确实是查询很慢。
               还没找到问题所在,继续排查,慢日志,

慢查询.png

只有两条,
查看第一条的执行计划:

执行计划.png

 
执行计划有 Using filesort ,但是两个查询rows 为1; select 结果基本只有1条少量可能有几条(在研发出了解到);从sql和执行计划来看没发现什么问题,是很简单的查询。
于是想到是否是配置参数的问题,比如innodb_buffer_pool_size配置小了,
发现是80G,并不小;顺便查看了一下状态:

mysql> show status like '%buffer_pool%';
+---------------------------------------+--------------+
| Variable_name                         | Value        |
+---------------------------------------+--------------+
| Innodb_buffer_pool_pages_data         | 5242872      |
| Innodb_buffer_pool_pages_dirty        | 26725        |
| Innodb_buffer_pool_pages_flushed      | 928942474    |
| Innodb_buffer_pool_pages_free         | 3            |
| Innodb_buffer_pool_pages_misc         | 1            |
| Innodb_buffer_pool_pages_total        | 5242876      |
| Innodb_buffer_pool_read_ahead_rnd     | 0            |
| Innodb_buffer_pool_read_ahead         | 12430752     |
| Innodb_buffer_pool_read_ahead_evicted | 53538        |
| Innodb_buffer_pool_read_requests      | 371347304415 |
| Innodb_buffer_pool_reads              | 34573956     |
| Innodb_buffer_pool_wait_free          | 0            |
| Innodb_buffer_pool_write_requests     | 12426911055  |
看起来没有异常;
至此感觉进入了迷茫期了,只是发现了莫名其妙的cpuload高,其它没发现任何异常,诡异啊!
然后继续理清思路,该实例只是一个sharing的一个从库,为啥就这台有问题,其他3台都没有问题。于是开始对比该机器和其他从的机器参数。
发现,numa都是关闭了,磁盘一样,内存一样,等等,cpu貌似不对,有问题的这台机器的cpu核心只有24个,主频只有1.8GHZ,其它是机器是32核心,主频是2.3GHZ;难道问题就这个?cpu太烂?
感觉发现了新大陆一样,等等 不对呀,cpu至少还是24核1.8GHZ,pci-e卡,128G内存的服务器的mysql跑这么简单的sql,QPS只能跑到2k,而且5s都不能出数据,想想都不合理啊。但是到目前都还没发现其它有力证据说明是其他问题,难道需要换服务器,没资源啊。于是就开始浮想翩翩了。不了了之,问题也不能富县,姑且就当是一个灵异事件吧;
然后想着在看看这个sql吧。
mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )     ORDER BY shipping_no;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.01 sec)

mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )     ORDER BY shipping_no;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.01 sec)
连续执行2次,都是0.01秒
去掉order by 子句

mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )   ;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.00 sec)

mysql> SELECT  so.shipping_no,se.total_deal_price,se.after_discount_price, so.shipping_no  FROM `shipping_order_110` AS `so`  LEFT JOIN `shipping_ext_110` AS `se`  USING (`shipping_no`)  WHERE  (`so`.`order_id` = '810103370')  AND ( `so`.`uid` = '69208878' )   ;
+-------------+------------------+----------------------+-------------+
| shipping_no | total_deal_price | after_discount_price | shipping_no |
+-------------+------------------+----------------------+-------------+
|  1018668733 |           188.00 |               188.00 |  1018668733 |
+-------------+------------------+----------------------+-------------+
1 row in set (0.00 sec)
连续执行两次都是0.00秒,sql问题? 虽然不确定是这个问题但是修改后效果确实是有的,于是准备找研发沟通一下是否可以修改一下sql;………………饭点到了,先吃了饭在说吧 这个反正不急(准时吃饭还是有好处呀,不然可能就找不到真实原因了!!)
 
在休的时候,研发有来找我们,说问题有出现了,查不出结果了。
登陆服务器继续排查问题,这次虽然抓住了现场,但是除了之前监控发现的问题,没有任何新的进展!总觉得这个机器不会骗人,哪里来的那么多诡异事件呢,于是继续排查问题,对比一下参数:
问题机器:
mysql>  show variables like '%buff%';
+------------------------------+-------------+
| Variable_name                | Value       |
+------------------------------+-------------+
| bulk_insert_buffer_size      | 8388608     |
| innodb_buffer_pool_instances | 4           |
| innodb_buffer_pool_size      | 85899345920 |
| innodb_change_buffering      | inserts     |
| innodb_log_buffer_size       | 16777216    |
| join_buffer_size             | 67108864    |
| key_buffer_size              | 536870912   |
| myisam_sort_buffer_size      | 8388608     |
| net_buffer_length            | 16384       |
| preload_buffer_size          | 32768       |
| read_buffer_size             | 67108864    |
| read_rnd_buffer_size         | 67108864    |
| sort_buffer_size             | 536870912   |
| sql_buffer_result            | OFF         |
+------------------------------+-------------+
14 rows in set (0.00 sec)
正常机器:
mysql> show variables like '%buff%';
+------------------------------+-------------+
| Variable_name                | Value       |
+------------------------------+-------------+
| bulk_insert_buffer_size      | 8388608     |
| innodb_buffer_pool_instances | 4           |
| innodb_buffer_pool_size      | 85899345920 |
| innodb_change_buffering      | inserts     |
| innodb_log_buffer_size       | 16777216    |
| join_buffer_size             | 2097152     |
| key_buffer_size              | 536870912   |
| myisam_sort_buffer_size      | 8388608     |
| net_buffer_length            | 16384       |
| preload_buffer_size          | 32768       |
| read_buffer_size             | 2097152     |
| read_rnd_buffer_size         | 2097152     |
| sort_buffer_size             | 2097152     |
| sql_buffer_result            | OFF         |
 
read_buffer_size,join_buffer_size,sort_buffer_size,read_rnd_buffer_size
这几个参数的值区别有点大呢,是不是这个问题?老师说这些参数最好不要改大了,不然容易oom,但是没说会影响性能啊,管他呢,先改一波,改小应该没有风险,直接都改小。
重启连接池。问题貌似解决了,至今没有发现问题
然后去官网查了这个几个参数的解释:
 
join_buffer_size:
说了一段这个:Memory allocation time can cause substantial performance drops if the global size is larger than needed by most queries that use it.
sort_buffer_size:
, there are thresholds of 256KB and 2MB where larger values may significantly slow down memory allocation, so you should consider staying below one of those values. Experiment to find the best value for your workload
两个的大意都是说分配内容需要花费很多时间,如果分配或多会严重影响查询效率;
 
经过这次问题:得到两点心得:
       1、找问题一定要有耐性,需要思路清晰,不要轻易相信有灵异事件发生。
       2、遇到所谓的灵异事件,坚持的越久,越可能找到问题所在。
       3、多看官方文档,这个很重要!!

docker 安装 及简单使用

DockerA128_huanggr 发表了文章 • 0 个评论 • 706 次浏览 • 2016-09-27 23:35 • 来自相关话题

安装docker推荐用安装 centos7系统
yum install libdevmapper* -y
yum install docker -y
centos7默认没有ifconfig命令 要用ifconfig : yum -y install net-tools
 
service docker start 启动docker

docker search centos6.8 搜索 官方镜像 
INDEX       NAME                                        DESCRIPTION                                    STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/644597521/centos6.8               centos6.8 from official                        1                    
docker.io   docker.io/tian/centos6.8-lamp-base                                                         1                    
docker.io   docker.io/13652604711/centos6.8-ssh                                                        0                    
docker.io   docker.io/13652604711/centos6.8-ssh-squid                                                  0                    
docker.io   docker.io/13652604711/centos6.8-ssh-ssr                                                    0                    
docker.io   docker.io/13652604711/centos6.8-ssh-vpn                                                    0                    
docker.io   docker.io/algoblu/centos6.8                                                                0                    
docker.io   docker.io/andrewvergel/centos6.8            Develoment Image                               0                    
docker.io   docker.io/confused123/centos6.8-ssh                                                        0                    
docker.io   docker.io/djatlantic/centos6.8                                                             0                    
docker.io   docker.io/finance/centos6.8                                                                0                    
docker.io   docker.io/finance/centos6.8-base            基于centos6.8构建的基本镜像。基...                        0                    
docker.io   docker.io/kxdmmr/centos6.8                                                                 0                    
docker.io   docker.io/lanceyuan/centos6.8                                                              0                    
docker.io   docker.io/leonjones/centos6.8                                                              0                    
docker.io   docker.io/ryus1234/centos6.8                                                               0                    
docker.io   docker.io/scummos/centos6.8-qt5.7           CentOS 6.8 with Qt 5.7, Python 3.5, LLVM 3.8   0                    
docker.io   docker.io/sgclark/centos6.8-qt5.7                                                          0                    
docker.io   docker.io/tian/centos6.8-64bit-base                                                        0     
              
docker pull docker.io/644597521/centos6.8  下载基础镜像
 
查看镜像
docker images 
 
做服务镜像
在系统上建设一个目录,并在目录下建Dockerfile 文件
cat Dockerfile
 
FROM docker.io/644597521/centos6.8
MAINTAINER guirong huang "149951292@qq.com"
RUN yum install -y curl sysstat openssh-server openssh openssh-clients vim libaio iotop tar gcc
RUN mkdir -p /data/redis307/data && mkdir /data/redis307/logs && mkdir /data/redis307/conf
COPY redis-3.0.7.tar.gz /data/ #拷贝包装包到镜像/data目录中
Add redis.conf /data/redis307/conf/ #添加redis配置文件到镜像/data/redis307/conf/目录中
RUN cd /data && tar xvf redis-3.0.7.tar.gz
RUN cd /data/redis-3.0.7 && make MALLOC=libc && make  PREFIX=/usr/local/redis307/ install
RUN groupadd redis && useradd -g redis redis
RUN cd /usr/local/ && chown -R redis.redis redis307 && cd /data && chown -R redis.redis redis307
RUN rm -fr /data/redis-3.0.7.tar.gz
EXPOSE 6379
CMD ["-D"]
创建服务镜像命令
docker build -t="redis:3.0.7" .
创建redis容器
docker run --name redis3.0.7 restart=always -p 6379:6379 -v /data/redis:/data/redis -dit redis:3.0.7 bash  
注:--name指定容器名字,restart=always 让服务在docker重启时容器的服务也是随着重启,-p 容器端口6379映射到宿主机6379端口,-v 批挂载/data/redis目录到容器中/data/redis目录中,-dit指后台运行启动容器
docker ps 查看启动的容器
docker exec -it 容器id bash  进入容器
 
 
MySQL Dockerfile文件
FROM centos:6.7
  
MAINTAINER guirong huang "149951292@qq.com"  
  
RUN yum install -y curl openssh-server openssh openssh-clients vim libaio  tar wget perl-DBD* perl-Time* rsync
  
COPY mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz /root/
#RUN cd /root && curl -s http://cdn.mysql.com/archives/ ... ar.gz -o mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz
Add my.cnf /etc/
Add mysql.sh /root/
RUN /bin/bash /root/mysql.sh && \
rm -f /root/mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz
EXPOSE 3306 
VOLUME  ["/data/mysql"] 
CMD ["-D"] 查看全部
安装docker推荐用安装 centos7系统
yum install libdevmapper* -y
yum install docker -y
centos7默认没有ifconfig命令 要用ifconfig : yum -y install net-tools
 
service docker start 启动docker

docker search centos6.8 搜索 官方镜像 
INDEX       NAME                                        DESCRIPTION                                    STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/644597521/centos6.8               centos6.8 from official                        1                    
docker.io   docker.io/tian/centos6.8-lamp-base                                                         1                    
docker.io   docker.io/13652604711/centos6.8-ssh                                                        0                    
docker.io   docker.io/13652604711/centos6.8-ssh-squid                                                  0                    
docker.io   docker.io/13652604711/centos6.8-ssh-ssr                                                    0                    
docker.io   docker.io/13652604711/centos6.8-ssh-vpn                                                    0                    
docker.io   docker.io/algoblu/centos6.8                                                                0                    
docker.io   docker.io/andrewvergel/centos6.8            Develoment Image                               0                    
docker.io   docker.io/confused123/centos6.8-ssh                                                        0                    
docker.io   docker.io/djatlantic/centos6.8                                                             0                    
docker.io   docker.io/finance/centos6.8                                                                0                    
docker.io   docker.io/finance/centos6.8-base            基于centos6.8构建的基本镜像。基...                        0                    
docker.io   docker.io/kxdmmr/centos6.8                                                                 0                    
docker.io   docker.io/lanceyuan/centos6.8                                                              0                    
docker.io   docker.io/leonjones/centos6.8                                                              0                    
docker.io   docker.io/ryus1234/centos6.8                                                               0                    
docker.io   docker.io/scummos/centos6.8-qt5.7           CentOS 6.8 with Qt 5.7, Python 3.5, LLVM 3.8   0                    
docker.io   docker.io/sgclark/centos6.8-qt5.7                                                          0                    
docker.io   docker.io/tian/centos6.8-64bit-base                                                        0     
              
docker pull docker.io/644597521/centos6.8  下载基础镜像
 
查看镜像
docker images 
 
做服务镜像
在系统上建设一个目录,并在目录下建Dockerfile 文件
cat Dockerfile
 
FROM docker.io/644597521/centos6.8
MAINTAINER guirong huang "149951292@qq.com"
RUN yum install -y curl sysstat openssh-server openssh openssh-clients vim libaio iotop tar gcc
RUN mkdir -p /data/redis307/data && mkdir /data/redis307/logs && mkdir /data/redis307/conf
COPY redis-3.0.7.tar.gz /data/ #拷贝包装包到镜像/data目录中
Add redis.conf /data/redis307/conf/ #添加redis配置文件到镜像/data/redis307/conf/目录中
RUN cd /data && tar xvf redis-3.0.7.tar.gz
RUN cd /data/redis-3.0.7 && make MALLOC=libc && make  PREFIX=/usr/local/redis307/ install
RUN groupadd redis && useradd -g redis redis
RUN cd /usr/local/ && chown -R redis.redis redis307 && cd /data && chown -R redis.redis redis307
RUN rm -fr /data/redis-3.0.7.tar.gz
EXPOSE 6379
CMD ["-D"]
创建服务镜像命令
docker build -t="redis:3.0.7" .
创建redis容器
docker run --name redis3.0.7 restart=always -p 6379:6379 -v /data/redis:/data/redis -dit redis:3.0.7 bash  
注:--name指定容器名字,restart=always 让服务在docker重启时容器的服务也是随着重启,-p 容器端口6379映射到宿主机6379端口,-v 批挂载/data/redis目录到容器中/data/redis目录中,-dit指后台运行启动容器
docker ps 查看启动的容器
docker exec -it 容器id bash  进入容器
 
 
MySQL Dockerfile文件
FROM centos:6.7
  
MAINTAINER guirong huang "149951292@qq.com"  
  
RUN yum install -y curl openssh-server openssh openssh-clients vim libaio  tar wget perl-DBD* perl-Time* rsync
  
COPY mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz /root/
#RUN cd /root && curl -s http://cdn.mysql.com/archives/ ... ar.gz -o mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz
Add my.cnf /etc/
Add mysql.sh /root/
RUN /bin/bash /root/mysql.sh && \
rm -f /root/mysql-5.6.29-linux-glibc2.5-x86_64.tar.gz
EXPOSE 3306 
VOLUME  ["/data/mysql"] 
CMD ["-D"]

520 Redis中国用户组成立啦,约吗?

activityzhangdh 发表了文章 • 0 个评论 • 456 次浏览 • 2016-05-21 00:45 • 来自相关话题

 Hello 大家好,

    很高兴告诉大家,Redis中国用户组经过一个多月的紧张筹备,终于在今天这个美好的日子和大家见面了!希望有更多的Redis爱好者加入到我们当中,共同致力为Redis技术的推广和应用,贡献绵薄之力。

    首先,我们非常感谢Antirez等大神为我们开发出了这么好用的工具,也非常感谢Rediser们为Redis版本的持续更新、功能改善和性能提高付出的努力,以及为建立健全的文档而付出的辛勤努力。我们注意到随着互联网技术的日益普及,Redis在国内被普遍应用,越来越多的人开始了解Redis,越来越多的企业开始应用Redis。但是对于Redis Cluster这种比较新的技术,在生产环境中还是使用较少的;在Redis的代码贡献上,还是不容乐观的。所以我们任重道远…

    Redis中国用户组,是由国内互联网公司的Redis一线工程师联合发起的非营利性技术组织。Redis中国用户组的成立得到了核心发起人李强和许瑞的大力支持,无私地将他们从2011年运营至今的redis.cn贡献出来,作为Redis中国用户组官网。不仅如此,我们还组建了Redis中国用户组QQ群521503946和微信群,提供给大家技术交流。并且Redis中国用户组也有了自己的官方微博(蓝V哦~)@Redis2016。除此之外,我们还第一时间组织力量给Redis官方发出认证函,以期得到官方的认可和支持(已经收到官方认可和支持的答复)。
    
    Redis中国用户组,在国内,作为Redis的一个核心组织,在今后的岁月里主要会从以下几个方面为持续推广普及Redis做出努力:
       1.延续redis.cn的光荣传统和使命,坚持不懈的继续翻译Redis官网和相关技术文章,期刊,新闻等,相信很多初学者都是从这里成长起来的
       2.不定期组织线上分享
       3.不定期组织线下交流活动,技术沙龙或联合举办技术大会
       4.逐步开始运营Redis中国用户组官方微信订阅号,推送经典技术文章,博客等
       5.邀请Redis技术大牛,讨论交流,并在Redis的代码贡献上持续发力
       6.有余力了,会以Redis中国用户组的名义出系列书籍

   写在最后,我们真诚地希望更多的Redis用户或爱好者能加入到我们的行列中,一起努力,创造Redis美好的明天。

   最后特别感谢Redis中国用户组核心成员(发起人):李强(创业)、张冬洪(微博)、王义成(阿里云)、许瑞(唯品会)、强昌金(去哪儿)、曹增涛(微博)、刘东辉(微博)、卓汝林(小米)、孙赫(今日头条)。
 
                                                                                                                                           Redis中国用户组
                                                                                                                                               2016-05-20 查看全部
redis_520_1(0).jpg

 Hello 大家好,

    很高兴告诉大家,Redis中国用户组经过一个多月的紧张筹备,终于在今天这个美好的日子和大家见面了!希望有更多的Redis爱好者加入到我们当中,共同致力为Redis技术的推广和应用,贡献绵薄之力。

    首先,我们非常感谢Antirez等大神为我们开发出了这么好用的工具,也非常感谢Rediser们为Redis版本的持续更新、功能改善和性能提高付出的努力,以及为建立健全的文档而付出的辛勤努力。我们注意到随着互联网技术的日益普及,Redis在国内被普遍应用,越来越多的人开始了解Redis,越来越多的企业开始应用Redis。但是对于Redis Cluster这种比较新的技术,在生产环境中还是使用较少的;在Redis的代码贡献上,还是不容乐观的。所以我们任重道远…

    Redis中国用户组,是由国内互联网公司的Redis一线工程师联合发起的非营利性技术组织。Redis中国用户组的成立得到了核心发起人李强和许瑞的大力支持,无私地将他们从2011年运营至今的redis.cn贡献出来,作为Redis中国用户组官网。不仅如此,我们还组建了Redis中国用户组QQ群521503946和微信群,提供给大家技术交流。并且Redis中国用户组也有了自己的官方微博(蓝V哦~)@Redis2016。除此之外,我们还第一时间组织力量给Redis官方发出认证函,以期得到官方的认可和支持(已经收到官方认可和支持的答复)。
    
    Redis中国用户组,在国内,作为Redis的一个核心组织,在今后的岁月里主要会从以下几个方面为持续推广普及Redis做出努力:
       1.延续redis.cn的光荣传统和使命,坚持不懈的继续翻译Redis官网和相关技术文章,期刊,新闻等,相信很多初学者都是从这里成长起来的
       2.不定期组织线上分享
       3.不定期组织线下交流活动,技术沙龙或联合举办技术大会
       4.逐步开始运营Redis中国用户组官方微信订阅号,推送经典技术文章,博客等
       5.邀请Redis技术大牛,讨论交流,并在Redis的代码贡献上持续发力
       6.有余力了,会以Redis中国用户组的名义出系列书籍

   写在最后,我们真诚地希望更多的Redis用户或爱好者能加入到我们的行列中,一起努力,创造Redis美好的明天。

   最后特别感谢Redis中国用户组核心成员(发起人):李强(创业)、张冬洪(微博)、王义成(阿里云)、许瑞(唯品会)、强昌金(去哪儿)、曹增涛(微博)、刘东辉(微博)、卓汝林(小米)、孙赫(今日头条)。
 
                                                                                                                                           Redis中国用户组
                                                                                                                                               2016-05-20

python 实现 mysql start | stop | restar | status 便捷管理命令

MySQLglon 发表了文章 • 1 个评论 • 764 次浏览 • 2016-05-16 17:27 • 来自相关话题

脚本还比较傻瓜,要求 MySQL 规范化部署。
basedir = /usr/local/mysql
datadir = /data/mysql/appname/data
conf_path: /data/mysql/appname/my%port.cnf
socket:/tmp/mysql%port.cnf
 
使用:
./mysqlCtrl {start|stop|restart|enter}
./mysqlCtrl -i mysql3316 -h 192.168.1.1 -u glon -p xxx -P3306 -o {start|stop|restart|enter}
 
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Author:glon
# date:2016-5-16 17:47:10

import sys
import os
import time
import getopt
import subprocess

app='mysql3316'
dbhost='localhost'
dbport=3316
dbuser='root'
dbpassword='123456'
operations = ['start','stop','restart','status','enter']

def usage():
print '''usage:
-i: app name.
-h: database host.
-P: databaee port
-u: database user
-p: database password
-o: database operation.{start|stop|restart|status|enter}

eg:
1) python mysqlCtrl.py -i mysql3316 -h 192.168.1.1 -u glon -p xxx -P3306 -o start
2) python mysqlCtrl.py start'''

def execCmd(cmd):
res = subprocess.Popen(cmd,stdout = subprocess.PIPE,shell = True)
return res.stdout.read()

def chkMySQL():
chk_mysql_process_cmd="ps aux | grep mysqld | grep %s | grep -v grep | wc -l" % dbport
chk_mysql_port_cmd ="netstat -tunlp | grep \":%s\" | wc -l" % dbport

mysql_process_num = execCmd(chk_mysql_process_cmd)
mysql_port_num = execCmd(chk_mysql_process_cmd)

return int(mysql_process_num and mysql_port_num)

def getOpts():
db_cfg = {}
opts, args = getopt.getopt(sys.argv[1:], 'i:h:P:u:p:o:', ['help'])
ops = dict(opts)
db_cfg['instance'] = ops['-i'] if ops.has_key('-i') else app
db_cfg['host'] = ops['-h'] if ops.has_key('-h') else dbhost
db_cfg['user'] = ops['-u'] if ops.has_key('-u') else dbuser
db_cfg['pwd'] = ops['-p'] if ops.has_key('-p') else dbpassword
db_cfg['port'] = ops['-P'] if ops.has_key('-P') else dbport

db_cfg['opt'] = None
if len(args) > 0:
for arg in args:
if operations.count(arg):
db_cfg['opt'] = arg
break

if ops.has_key('-o'):
db_cfg['opt'] = ops['-o']

return db_cfg

def startMySQL(dbconf):
if not chkMySQL():
cmd = "sudo /usr/local/mysql/bin/mysqld --defaults-file=/data/mysql/%s/my%s.cnf &" % (dbconf['instance'],dbconf['port'])
subprocess.Popen(cmd,stderr = subprocess.PIPE,shell=True)
print ">>> Start MySQL \033[32m [ OK ] \033[0m" if chkMySQL() > 0 else '>>> Start MySQL \033[31m [ FAIL ] \033[0m'
else:
print ">>> MySQL is already \033[32m [ EXIST ] \033[0m"

def stopMySQL(dbconf):
if not chkMySQL():
print ">>> Stop MySQL \033[32m [ OK ] \033[0m"
else:
cmd = "sudo /usr/local/mysql/bin/mysqladmin -S /tmp/mysql%s.sock shutdown -u%s -p%s" % (dbconf['port'],dbconf['user'],dbconf['pwd'])
subprocess.Popen(cmd,stderr = subprocess.PIPE,shell=True)
time.sleep(5)
print ">>> Stop MySQL \033[32m [ OK ] \033[0m" if chkMySQL() == 0 else '>>> Stop MySQL \033[31m [ FAIL ] \033[0m'

def enterMySQL(dbconf):
if chkMySQL():
cmd = "/usr/local/mysql/bin/mysql -S /tmp/mysql%s.sock -u%s -p%s" % (dbconf['port'],dbconf['user'],dbconf['pwd'])
os.system(cmd)
else:
print ">>> MySQL is \033[31m [ NOT EXIST ] \033[0m"

if __name__== "__main__":
try:
db_conf = getOpts()
if db_conf['opt'] == 'start':
print '>>> starting MySQL on Port %s ...' % db_conf['port']
startMySQL(db_conf)
elif db_conf['opt'] == 'stop':
print '>>> stopping MySQL on Port %s ...' % db_conf['port']
stopMySQL(db_conf)
elif db_conf['opt'] == 'restart':
print '>>> restarting MySQL on Port %s...' % db_conf['port']
stopMySQL(db_conf)
startMySQL(db_conf)
elif db_conf['opt'] == 'status':
print '>>> MySQL is \033[32m [ RUNNING ] \033[0m on Port %s' % db_conf['port'] if chkMySQL() > 0 else '>>> MySQL is \033[31m [ NOT ON SERVICE ] \033[0m on Port %s' % db_conf['port']
elif db_conf['opt'] == 'enter':
enterMySQL(db_conf)
else:
print '>>> Nothing to do, plz input the right operation ...'
usage()


except getopt.GetoptError, err:
print str(err)
usage()
sys.exit(2) 查看全部
脚本还比较傻瓜,要求 MySQL 规范化部署。
basedir = /usr/local/mysql
datadir = /data/mysql/appname/data
conf_path: /data/mysql/appname/my%port.cnf
socket:/tmp/mysql%port.cnf
 
使用:
./mysqlCtrl {start|stop|restart|enter}
./mysqlCtrl -i mysql3316 -h 192.168.1.1 -u glon -p xxx -P3306 -o {start|stop|restart|enter}
 
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Author:glon
# date:2016-5-16 17:47:10

import sys
import os
import time
import getopt
import subprocess

app='mysql3316'
dbhost='localhost'
dbport=3316
dbuser='root'
dbpassword='123456'
operations = ['start','stop','restart','status','enter']

def usage():
print '''usage:
-i: app name.
-h: database host.
-P: databaee port
-u: database user
-p: database password
-o: database operation.{start|stop|restart|status|enter}

eg:
1) python mysqlCtrl.py -i mysql3316 -h 192.168.1.1 -u glon -p xxx -P3306 -o start
2) python mysqlCtrl.py start'''

def execCmd(cmd):
res = subprocess.Popen(cmd,stdout = subprocess.PIPE,shell = True)
return res.stdout.read()

def chkMySQL():
chk_mysql_process_cmd="ps aux | grep mysqld | grep %s | grep -v grep | wc -l" % dbport
chk_mysql_port_cmd ="netstat -tunlp | grep \":%s\" | wc -l" % dbport

mysql_process_num = execCmd(chk_mysql_process_cmd)
mysql_port_num = execCmd(chk_mysql_process_cmd)

return int(mysql_process_num and mysql_port_num)

def getOpts():
db_cfg = {}
opts, args = getopt.getopt(sys.argv[1:], 'i:h:P:u:p:o:', ['help'])
ops = dict(opts)
db_cfg['instance'] = ops['-i'] if ops.has_key('-i') else app
db_cfg['host'] = ops['-h'] if ops.has_key('-h') else dbhost
db_cfg['user'] = ops['-u'] if ops.has_key('-u') else dbuser
db_cfg['pwd'] = ops['-p'] if ops.has_key('-p') else dbpassword
db_cfg['port'] = ops['-P'] if ops.has_key('-P') else dbport

db_cfg['opt'] = None
if len(args) > 0:
for arg in args:
if operations.count(arg):
db_cfg['opt'] = arg
break

if ops.has_key('-o'):
db_cfg['opt'] = ops['-o']

return db_cfg

def startMySQL(dbconf):
if not chkMySQL():
cmd = "sudo /usr/local/mysql/bin/mysqld --defaults-file=/data/mysql/%s/my%s.cnf &" % (dbconf['instance'],dbconf['port'])
subprocess.Popen(cmd,stderr = subprocess.PIPE,shell=True)
print ">>> Start MySQL \033[32m [ OK ] \033[0m" if chkMySQL() > 0 else '>>> Start MySQL \033[31m [ FAIL ] \033[0m'
else:
print ">>> MySQL is already \033[32m [ EXIST ] \033[0m"

def stopMySQL(dbconf):
if not chkMySQL():
print ">>> Stop MySQL \033[32m [ OK ] \033[0m"
else:
cmd = "sudo /usr/local/mysql/bin/mysqladmin -S /tmp/mysql%s.sock shutdown -u%s -p%s" % (dbconf['port'],dbconf['user'],dbconf['pwd'])
subprocess.Popen(cmd,stderr = subprocess.PIPE,shell=True)
time.sleep(5)
print ">>> Stop MySQL \033[32m [ OK ] \033[0m" if chkMySQL() == 0 else '>>> Stop MySQL \033[31m [ FAIL ] \033[0m'

def enterMySQL(dbconf):
if chkMySQL():
cmd = "/usr/local/mysql/bin/mysql -S /tmp/mysql%s.sock -u%s -p%s" % (dbconf['port'],dbconf['user'],dbconf['pwd'])
os.system(cmd)
else:
print ">>> MySQL is \033[31m [ NOT EXIST ] \033[0m"

if __name__== "__main__":
try:
db_conf = getOpts()
if db_conf['opt'] == 'start':
print '>>> starting MySQL on Port %s ...' % db_conf['port']
startMySQL(db_conf)
elif db_conf['opt'] == 'stop':
print '>>> stopping MySQL on Port %s ...' % db_conf['port']
stopMySQL(db_conf)
elif db_conf['opt'] == 'restart':
print '>>> restarting MySQL on Port %s...' % db_conf['port']
stopMySQL(db_conf)
startMySQL(db_conf)
elif db_conf['opt'] == 'status':
print '>>> MySQL is \033[32m [ RUNNING ] \033[0m on Port %s' % db_conf['port'] if chkMySQL() > 0 else '>>> MySQL is \033[31m [ NOT ON SERVICE ] \033[0m on Port %s' % db_conf['port']
elif db_conf['opt'] == 'enter':
enterMySQL(db_conf)
else:
print '>>> Nothing to do, plz input the right operation ...'
usage()


except getopt.GetoptError, err:
print str(err)
usage()
sys.exit(2)

KeepAlived高可用切换脚本修改--基于 checkMySQL.sh

MySQLglon 发表了文章 • 2 个评论 • 978 次浏览 • 2016-05-10 18:24 • 来自相关话题

最近需要分离一个业务到 MySQL 上,使用 GTID 模型一主一从的复制结构,并使用 KeepAlived 做为高可用切换。
吴总说过,如果在切换的时候从库还没同步完成,会丢失数据,而网络抖动时切换,有可能导致脑裂。
基于这个,对原本简单的 mysql connect ping 做了一个扩展。
脚本中的 monitor 用户,拥有 replication slave 的权限。 
#!/usr/bin/python
#coding: utf-8
# author:hejinlong@yaochufa.com
# 2016-5-15 17:42:15

import sys
import os
import getopt
import MySQLdb
import logging
import subprocess
import datetime
import common as cm


dbhost='127.0.0.1'
dbport=3316
dbuser='monitor'
dbpassword='m0n1tor'
vip='192.168.1.123'
mail_to = '562071793@qq.com'
ka_conf = '/etc/keepalived/keepalived.conf'
app_env = 'online'

def checkMySQL():
global dbhost
global dbport
global dbuser
global dbpassword
global mail_to

shortargs='h:P:'
opts, args=getopt.getopt(sys.argv[1:],shortargs)
for opt, value in opts:
if opt=='-h':
dbhost=value
elif opt=='-P':
dbport=value

db = instanceMySQL(dbhost, dbport, dbuser, dbpassword)
util = Org(vip,mail_to,ka_conf,app_env)

# check mysql
if ( db.connect() != 0 ):
return 1
db.disconnect()

# check network for "Split Brain"
net_status = util.ping_vip()

is_vip = util.check_vip()
if is_vip == 1:#从库,则检查复制状态
repl_status = db.is_slave_sql_thread_done()

# 网络抖动时不切换
if net_status == 1:
return 0

# slave, repl delay
if (is_vip == 1) and (repl_status == 1):
return 1

return 0


class Org:
def __init__(self, vip=None, mail_to=None, conf=None, app_env=None):
self.vip=vip
self.mail_to=mail_to
self.conf=conf
self.app_env = app_env

def execCmd(self,cmd):
res = subprocess.Popen(cmd,stdout = subprocess.PIPE,shell = True)
return res.stdout.read()

def getNetInterface(self):
with open(self.conf, 'r') as f:
for line in f:
if line.find('interface') != -1:
return line.strip().split()[1]

#ping vip
def ping_vip(self):
logging.info('---------------- check network ----------------')
cmd = 'ping ' + self.vip + ' -c 4'
ping_res = os.system(cmd)

logging.info('>>> command: %s :', cmd)
logging.info('>>> %s', ping_res)

# ping_res: greater than 0 network is bad, 0 network is good
if ping_res > 0:
net_interface = self.getNetInterface()
cmd = "ifconfig {0}".format(net_interface) + " | grep 'inet addr:' | awk '{print $2}' | awk -F':' '{print $2}'"
local_ip = self.execCmd(cmd)
logging.info('>>> command:%s', cmd)
logging.info('>>> %s', local_ip)

logging.info('>>> sendmail when network is bad')
subject = '[ {0} ] network is bad!'.format(local_ip.strip())
msg = self.app_env + ' {0} network is bad!'.format(local_ip.strip())
cm.send_alert_mail(subject,msg,mail_to)
return 1
return 0

# is_vip
def check_vip(self):
logging.info('---------------- check vip ----------------')
cmd = "ip addr show | grep %s | wc -l" % self.vip
chk_res = self.execCmd(cmd)

logging.info('>>> command: %s :', cmd)
logging.info('>>> %s', chk_res)

# chk_res: greater than 0 is vip, 0 is not vip
if int(chk_res) == 0:
return 1
return 0


class instanceMySQL:
conn = None
def __init__(self, host=None,port=None, user=None, passwd=None):
self.dbhost= host
self.dbport = int(port)
self.dbuser = user
self.dbpassword = passwd

def is_slave_sql_thread_done(self):
logging.info('---------------- check repl is done ----------------')

self.connect()
sql="show slave status"
cursor = self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
cursor.execute(sql)
result = cursor.fetchall()

logging.info('>>> command: show slave status result')
logging.info('>>> %s', result)

if len(result) == 0:
return 0

row = result[0]
#if( row['Slave_IO_Running'] != 'Yes'):
# return 1
#if( row['Slave_SQL_Running'] != 'Yes'):
# return 1

logging.info('>>> Slave_IO_Running: %s', row['Slave_IO_Running'])
logging.info('>>> Slave_SQL_Running: %s', row['Slave_SQL_Running'])
logging.info('>>> Master_Log_File: %s', row['Master_Log_File'])
logging.info('>>> Relay_Master_Log_File: %s', row['Relay_Master_Log_File'])
logging.info('>>> Read_Master_Log_Pos: %s', row['Read_Master_Log_Pos'])
logging.info('>>> Exec_Master_Log_Pos: %s', row['Exec_Master_Log_Pos'])

if ( row['Master_Log_File'] == row['Relay_Master_Log_File']) and (row['Read_Master_Log_Pos'] == row['Exec_Master_Log_Pos'] ):
print 'repl done'
logging.info('>>> repl status: done')
cursor.close()
self.disconnect()
return 0
cursor.close()
self.disconnect()
logging.info('>>> repl status: delay')
return 1


def connect(self):
logging.info('---------------- connect mysql ----------------')
try:
self.conn=MySQLdb.connect(host="%s"%self.dbhost, port=self.dbport,user="%s"%dbuser, passwd="%s"%self.dbpassword)

logging.info('command: show master status')
sql="show master status"
cursor = self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
cursor.execute(sql)
result = cursor.fetchall()
logging.info('>>> %s', result)

logging.info('>>> connect: OK')
except Exception, e:
#print " Error"
print e
return 1
return 0

def disconnect(self):
logging.info('---------------- disconnect mysql ----------------')
if (self.conn):
self.conn.close()
self.conn = None
logging.info('>>> disconnect: OK')



if __name__== "__main__":
LOG_PATH = 'chk_logs'
EXPIRE_LOGS_DAYS = 3

log_path = os.path.join(sys.path[0],LOG_PATH)
current_date = datetime.datetime.now().strftime('%Y%m%d')
expired_date = datetime.date.today() - datetime.timedelta(days=EXPIRE_LOGS_DAYS)

next_log = 'chk_mysql.' + current_date
expired_log = 'chk_mysql.' + expired_date.strftime('%Y%m%d')
log_file = os.path.join(log_path,next_log)

if not os.path.exists(log_path):
os.mkdir(log_path)

logging.basicConfig(level=logging.DEBUG,
#format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
format='%(asctime)s %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename=log_file,
filemode='a')

logging.info(' ')
logging.info(' ')
logging.info(' ')
logging.info('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ init chk logs start ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
logging.info('>>> log_path: %s', log_path)
logging.info('>>> next_log: %s', next_log)
logging.info('>>> expired_log: %s', expired_log)

logs = []
cmd = "dir " + log_path
for i in os.popen(cmd).readlines():
logs.extend( i.split())

logging.info('---------------- logs exists ----------------')
logging.info('>>> %s', logs)

if len(logs) > EXPIRE_LOGS_DAYS:
for i in logs:
if i <= expired_log:
rm_log = os.path.join(log_path,i)
logging.info('>>> removeing expired log: %s',rm_log)
os.remove(rm_log)

logging.info('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ init chk logs end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
logging.info('###################################### begin checking ######################################')

st=checkMySQL()

if st == 0:
logging.info('Check Code is: %s, means good.', st)
else:
logging.info('Check Code is: %s, means bad.', st)

logging.info('###################################### end checking ######################################')
sys.exit(st)

对 python 不熟,写得不好,请多见谅。
这个脚本还没有加入一主多从的时候,选举新主的判断,大家可以尝试一下。
 
这个脚本有个小坑,永祥踩了,O(∩_∩)O哈哈~
要求配置文件的命名是带端口的,如 my3306.cnf,否则在判断 mysql 进程是否存在的时候会找不到,因为找到 mysqld 进程后,再次筛选端口号的时候就找不着了。
由此可以看出,这个脚本对规范部署的要求高,而且对多实例很管用~~ 查看全部
最近需要分离一个业务到 MySQL 上,使用 GTID 模型一主一从的复制结构,并使用 KeepAlived 做为高可用切换。
吴总说过,如果在切换的时候从库还没同步完成,会丢失数据,而网络抖动时切换,有可能导致脑裂。
基于这个,对原本简单的 mysql connect ping 做了一个扩展。
脚本中的 monitor 用户,拥有 replication slave 的权限。 
#!/usr/bin/python
#coding: utf-8
# author:hejinlong@yaochufa.com
# 2016-5-15 17:42:15

import sys
import os
import getopt
import MySQLdb
import logging
import subprocess
import datetime
import common as cm


dbhost='127.0.0.1'
dbport=3316
dbuser='monitor'
dbpassword='m0n1tor'
vip='192.168.1.123'
mail_to = '562071793@qq.com'
ka_conf = '/etc/keepalived/keepalived.conf'
app_env = 'online'

def checkMySQL():
global dbhost
global dbport
global dbuser
global dbpassword
global mail_to

shortargs='h:P:'
opts, args=getopt.getopt(sys.argv[1:],shortargs)
for opt, value in opts:
if opt=='-h':
dbhost=value
elif opt=='-P':
dbport=value

db = instanceMySQL(dbhost, dbport, dbuser, dbpassword)
util = Org(vip,mail_to,ka_conf,app_env)

# check mysql
if ( db.connect() != 0 ):
return 1
db.disconnect()

# check network for "Split Brain"
net_status = util.ping_vip()

is_vip = util.check_vip()
if is_vip == 1:#从库,则检查复制状态
repl_status = db.is_slave_sql_thread_done()

# 网络抖动时不切换
if net_status == 1:
return 0

# slave, repl delay
if (is_vip == 1) and (repl_status == 1):
return 1

return 0


class Org:
def __init__(self, vip=None, mail_to=None, conf=None, app_env=None):
self.vip=vip
self.mail_to=mail_to
self.conf=conf
self.app_env = app_env

def execCmd(self,cmd):
res = subprocess.Popen(cmd,stdout = subprocess.PIPE,shell = True)
return res.stdout.read()

def getNetInterface(self):
with open(self.conf, 'r') as f:
for line in f:
if line.find('interface') != -1:
return line.strip().split()[1]

#ping vip
def ping_vip(self):
logging.info('---------------- check network ----------------')
cmd = 'ping ' + self.vip + ' -c 4'
ping_res = os.system(cmd)

logging.info('>>> command: %s :', cmd)
logging.info('>>> %s', ping_res)

# ping_res: greater than 0 network is bad, 0 network is good
if ping_res > 0:
net_interface = self.getNetInterface()
cmd = "ifconfig {0}".format(net_interface) + " | grep 'inet addr:' | awk '{print $2}' | awk -F':' '{print $2}'"
local_ip = self.execCmd(cmd)
logging.info('>>> command:%s', cmd)
logging.info('>>> %s', local_ip)

logging.info('>>> sendmail when network is bad')
subject = '[ {0} ] network is bad!'.format(local_ip.strip())
msg = self.app_env + ' {0} network is bad!'.format(local_ip.strip())
cm.send_alert_mail(subject,msg,mail_to)
return 1
return 0

# is_vip
def check_vip(self):
logging.info('---------------- check vip ----------------')
cmd = "ip addr show | grep %s | wc -l" % self.vip
chk_res = self.execCmd(cmd)

logging.info('>>> command: %s :', cmd)
logging.info('>>> %s', chk_res)

# chk_res: greater than 0 is vip, 0 is not vip
if int(chk_res) == 0:
return 1
return 0


class instanceMySQL:
conn = None
def __init__(self, host=None,port=None, user=None, passwd=None):
self.dbhost= host
self.dbport = int(port)
self.dbuser = user
self.dbpassword = passwd

def is_slave_sql_thread_done(self):
logging.info('---------------- check repl is done ----------------')

self.connect()
sql="show slave status"
cursor = self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
cursor.execute(sql)
result = cursor.fetchall()

logging.info('>>> command: show slave status result')
logging.info('>>> %s', result)

if len(result) == 0:
return 0

row = result[0]
#if( row['Slave_IO_Running'] != 'Yes'):
# return 1
#if( row['Slave_SQL_Running'] != 'Yes'):
# return 1

logging.info('>>> Slave_IO_Running: %s', row['Slave_IO_Running'])
logging.info('>>> Slave_SQL_Running: %s', row['Slave_SQL_Running'])
logging.info('>>> Master_Log_File: %s', row['Master_Log_File'])
logging.info('>>> Relay_Master_Log_File: %s', row['Relay_Master_Log_File'])
logging.info('>>> Read_Master_Log_Pos: %s', row['Read_Master_Log_Pos'])
logging.info('>>> Exec_Master_Log_Pos: %s', row['Exec_Master_Log_Pos'])

if ( row['Master_Log_File'] == row['Relay_Master_Log_File']) and (row['Read_Master_Log_Pos'] == row['Exec_Master_Log_Pos'] ):
print 'repl done'
logging.info('>>> repl status: done')
cursor.close()
self.disconnect()
return 0
cursor.close()
self.disconnect()
logging.info('>>> repl status: delay')
return 1


def connect(self):
logging.info('---------------- connect mysql ----------------')
try:
self.conn=MySQLdb.connect(host="%s"%self.dbhost, port=self.dbport,user="%s"%dbuser, passwd="%s"%self.dbpassword)

logging.info('command: show master status')
sql="show master status"
cursor = self.conn.cursor(cursorclass=MySQLdb.cursors.DictCursor)
cursor.execute(sql)
result = cursor.fetchall()
logging.info('>>> %s', result)

logging.info('>>> connect: OK')
except Exception, e:
#print " Error"
print e
return 1
return 0

def disconnect(self):
logging.info('---------------- disconnect mysql ----------------')
if (self.conn):
self.conn.close()
self.conn = None
logging.info('>>> disconnect: OK')



if __name__== "__main__":
LOG_PATH = 'chk_logs'
EXPIRE_LOGS_DAYS = 3

log_path = os.path.join(sys.path[0],LOG_PATH)
current_date = datetime.datetime.now().strftime('%Y%m%d')
expired_date = datetime.date.today() - datetime.timedelta(days=EXPIRE_LOGS_DAYS)

next_log = 'chk_mysql.' + current_date
expired_log = 'chk_mysql.' + expired_date.strftime('%Y%m%d')
log_file = os.path.join(log_path,next_log)

if not os.path.exists(log_path):
os.mkdir(log_path)

logging.basicConfig(level=logging.DEBUG,
#format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
format='%(asctime)s %(levelname)s %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
filename=log_file,
filemode='a')

logging.info(' ')
logging.info(' ')
logging.info(' ')
logging.info('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ init chk logs start ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
logging.info('>>> log_path: %s', log_path)
logging.info('>>> next_log: %s', next_log)
logging.info('>>> expired_log: %s', expired_log)

logs = []
cmd = "dir " + log_path
for i in os.popen(cmd).readlines():
logs.extend( i.split())

logging.info('---------------- logs exists ----------------')
logging.info('>>> %s', logs)

if len(logs) > EXPIRE_LOGS_DAYS:
for i in logs:
if i <= expired_log:
rm_log = os.path.join(log_path,i)
logging.info('>>> removeing expired log: %s',rm_log)
os.remove(rm_log)

logging.info('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ init chk logs end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
logging.info('###################################### begin checking ######################################')

st=checkMySQL()

if st == 0:
logging.info('Check Code is: %s, means good.', st)
else:
logging.info('Check Code is: %s, means bad.', st)

logging.info('###################################### end checking ######################################')
sys.exit(st)

对 python 不熟,写得不好,请多见谅。
这个脚本还没有加入一主多从的时候,选举新主的判断,大家可以尝试一下。
 
这个脚本有个小坑,永祥踩了,O(∩_∩)O哈哈~
要求配置文件的命名是带端口的,如 my3306.cnf,否则在判断 mysql 进程是否存在的时候会找不到,因为找到 mysqld 进程后,再次筛选端口号的时候就找不着了。
由此可以看出,这个脚本对规范部署的要求高,而且对多实例很管用~~