关于吴 炳锡

数据库架构师 熟悉MySQL架构设计及数据库架构优化。 丰富的MySQL优化及高可用架构经验。

MySQL免费技术分享《百万级在线MySQL架构分享》

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

随着传统企业去IOE的声音越来越大,也有很多朋友来咨询MySQL的架构设计问题,所以决定做这个分享让决定或是想使用MySQL的朋友能从整体上了解一下如何利用MySQL构建一个百万级在线(或是百万并发的架构)
分享时间:2014年8月14日 20:30  在线技术分享

参加朋友加QQ群:159636401 
分享者介绍
吴炳锡 新媒传信 数据库架构师
Blog: http://mysqlsupport.cn

公司数据库托管平台设计及核心开发者
公司海量数据平台设计及开发人员
熟悉MySQL高可用原理及技术实现
丰富的基于MySQL架构设计及规划经验
MySQL中国用户组核心人员 (http://acmug.com/)

建议听众:
面向DBA人员,架构师,基于MySQL开发人员

分享目标:
让大家深入了解MySQL的特性
供基于MySQL开发的同学们做出最佳实践
全面整体上认识MySQL在架构设计中如何进行拆分
了解NoSQL和MySQL是如何结合使用优化架构

想参加分享的同学请提前加入Q群: 159636401  更多精彩分享等着你 :)

这只是一个开始,更多分享,一块来交流。

[TIPS]安装数据库提示无法解析机器名处理

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

在做MySQL初始化时,如果机器的名不能进行反解会出现以下错误:

WARNING: The host 'node2' could not be looked up with resolveip.
This probably means that your libc libraries are not 100 % compatible
with this binary MySQL version. The MySQL daemon, mysqld, should work
normally with the exception that host name resolving will not work.
This means that you should use IP addresses instead of hostnames
when specifying MySQL privileges !
#/usr/local/mysql/bin/resolveip node2

/usr/local/mysql/bin/resolveip: Unable to find hostid for ‘node2’: host not found

处理过程如下

1. 查看机器的名

#hostanme

node2

2. 查看/etc/hosts文件

#cat /etc/hosts

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

可见/etc/hosts中无相应的机器名

添ip(本机的ip) 到机器的对应到/etc/hosts中:

最终/etc/hosts内容如下:

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
10.10.60.148 node2

3.使用resolveip确认是否ok

#/usr/local/mysql/bin/resolveip node2

IP address of node2 is 10.10.60.148

4. 在次运行初始化程序

cd /usr/local/mysql
./script/mysql_db_install

Good luck!

TIPS:MySQL 改库名操作

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

MySQL在5.1引入了一个rename database操作,但在MySQL5.1.23后又不支持这个命令。可以说是一个实验性的功能,没有在生产中支持过(mysql-5.1 release在mysql-5.1.30),那么生产中我们有时为了追求完美需要改一下库名。怎么操作呢?
这里提供一个变通的方法。
1. 创建出新库名:

mysql>create database db_v2;
  1. 生成rename语句,从olddb里迁移,我这里olddb里sbtest;
mysql>select concat("rename table ",table_schema,".",table_name," to db_v2.",table_name,";") into outfile '/tmp/rename_to_db_v2.sql' from information_schema.tables where table_schema='sbtest';

3.执行生成的sql

mysql>source /tmp/rename_to_db_v2.sql

就这么简单可以搞定了。
Good luck!

Antelope 和Barracuda区别

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#163.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

Antelope是innodb-base的文件格式, Barracude是innodb-plugin后引入的文件格式,同时Barracude也支持Antelope文件格式。两者区别在于:

文件格式 支持行格式 特性
Antelope

(Innodb-base)

ROW_FORMAT=COMPACT

ROW_FORMAT=REDUNDANT

Compact和redumdant的区别在就是在于首部的存存内容区别。

compact的存储格式为首部为一个非NULL的变长字段长度列表

redundant的存储格式为首部是一个字段长度偏移列表(每个字段占用的字节长度及其相应的位移)。

在Antelope中对于变长字段,低于768字节的,不会进行overflow page存储,某些情况下会减少结果集IO.

Barracuda

(innodb-plugin)

ROW_FORMAT=DYNAMIC

ROW_FORMAT=COMPRESSED

 

这两者主要是功能上的区别功能上的。 另外在行里的变长字段和Antelope的区别是只存20个字节,其它的overflow page存储。

另外这两都需要开启innodb_file_per_table=1

(这个特性对一些优化还是很有用的)

备注:

这里有一点需要注意,如果要使用压缩,一定需要先使用innodb_file_format =Barracuda格式,不然没作用。

下面我们看一下区别:

(testing)root@localhost [(none)]> use wubx;

Database changed

(testing)root@localhost [wubx]> CREATE TABLE t1

->  (c1 INT PRIMARY KEY)

->  ROW_FORMAT=COMPRESSED

->  KEY_BLOCK_SIZE=8;

Query OK, 0 rows affected, 4 warnings (0.01 sec)

报出来4个warnings查看一下报错:

(testing)root@localhost [wubx]> show warnings;

+———+——+———————————————————————–+

| Level   | Code | Message                                                               |

+———+——+———————————————————————–+

| Warning | 1478 | InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.        |

| Warning | 1478 | InnoDB: ignoring KEY_BLOCK_SIZE=8.                                    |

| Warning | 1478 | InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. |

| Warning | 1478 | InnoDB: assuming ROW_FORMAT=COMPACT.                                  |

+———+——+———————————————————————–+

4 rows in set (0.00 sec)

从以上报错可以看出来不支持压缩。但看一下表结构如下:

(testing)root@localhost [wubx]> show create table t1;

+——-+———————————————————————————————————————————————–+

| Table | Create Table                                                                                                                                  |

+——-+———————————————————————————————————————————————–+

| t1    | CREATE TABLE t1 (

c1 int(11) NOT NULL,

PRIMARY KEY (c1)

) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8 |

+——-+———————————————————————————————————————————————–+

1 row in set (0.00 sec)

这个是比较坑的地方,所以在使用压缩需要注意。

 

(testing)root@localhost [wubx]>create table t2 ( c1 int(11) NOT NULL, primary key(c1));

(testing)root@localhost [wubx]> insert into t2 select * from t1;

Query OK, 5417760 rows affected (37.12 sec)

Records: 5417760  Duplicates: 0  Warnings: 0

 

创建支持压缩的表:

(testing)root@localhost [wubx]>SET GLOBAL  innodb_file_per_table=1

(testing)root@localhost [wubx]>SET GLOBAL innodb_file_format=Barracuda;

(testing)root@localhost [wubx]>CREATE TABLE t3

(c1 INT PRIMARY KEY)

ROW_FORMAT=COMPRESSED

KEY_BLOCK_SIZE=8;

(testing)root@localhost [wubx]> insert into t3 select * from t1;

Query OK, 5417760 rows affected (1 min 10.98 sec)

Records: 5417760  Duplicates: 0  Warnings: 0

 

看一下表的物理大小如下:

-rw-rw—- 1 mysql mysql 8.4K Jul  5 16:58 t1.frm

-rw-rw—- 1 mysql mysql 136M Jul  5 19:40 t1.ibd

-rw-rw—- 1 mysql mysql 8.4K Jul  5 19:43 t2.frm

-rw-rw—- 1 mysql mysql 136M Jul  5 19:44 t2.ibd

-rw-rw—- 1 mysql mysql 8.4K Jul  5 19:46 t3.frm

-rw-rw—- 1 mysql mysql  96M Jul  5 19:47 t3.ibd

 

可见t1, t2都没进行压缩, t3是支持压缩的。

 

 

cpuspeed和irqbalance服务器的两大性能杀手

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

最近在一个性能测试中遇到机器的CPU频率不对。查了一下原来是irqbalance和cpuspeed搞出来问题。
irqbalance 理论上:
启用 irqbalance 服务,既可以提升性能,又可以降低能耗。
irqbalance 用于优化中断分配,它会自动收集系统数据以分析使用模式,并依据系统负载状况将工作状态置于 Performance mode 或 Power-save mode。
处于 Performance mode 时,irqbalance 会将中断尽可能均匀地分发给各个 CPU core,以充分利用 CPU 多核,提升性能。
处于 Power-save mode 时,irqbalance 会将中断集中分配给第一个 CPU,以保证其它空闲 CPU 的睡眠时间,降低能耗。
但实际中往往影响cpu的使用均衡,建议服务器环境中关闭。

cpuspeed这个也算是遇到一个大坑,如果bios中已经开启了max performance但cpu主频还是不对,那就是cpuspeed搞出来的鬼(笔记本可以保留这些服务用于省电)。

service irqbalance stop
service cpuspeed stop
chkconfig irqbalance off
chkconfig cpuspeed off

其实相对一个数据库服务器对Linux服务可以进行以下操作:

cd /etc/rc3.d/
mkdir ~/rc3
mv * ~/rc3/
chkconfig --level 3 crond
chkconfig --level 3 sshd on
chkconfig --level 3 rsyslog on
chkconfig --level 3 network on
ln -s /etc/rc.local S99local

最小化的开启服务,如果在需要其它可以手工再开启。

Good Luck.

优化MySQL的21个建议

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

今天一个朋友向我咨询怎么去优化 MySQL,我按着思维整理了一下,大概粗的可以分为21个方向。 还有一些细节东西(table cache, 表设计,索引设计,程序端缓存之类的)先不列了,对一个系统,初期能把下面做完也是一个不错的系统。

1. 要确保有足够的内存

数据库能够高效的运行,最关建的因素需要内存足更大了,能缓存住数据,更新也可以在内存先完成。但不同的业务对内存需要强度不一样,一推荐内存要占到数据的15-25%的比例,特别的热的数据,内存基本要达到数据库的80%大小。

2. 需要更多更快的CPU

MySQL 5.6可以利用到64个核,而MySQL每个query只能运行在一个CPU上,所以要求更多的CPU,更快的CPU会更有利于并发。

3. 要选择合适的操作系统

在官方建议估计最推荐的是Solaris, 从实际生产中看CentOS, REHL都是不错的选择,推荐使用CentOS, REHL 版本为6以后的,当然Oracle Linux也是一个不错的选择。虽然从MySQL 5.5后对Windows做了优化,但也不推荐在高并发环境中使用windows.

4. 合理的优化系统的参数

更改文件句柄  ulimit –n 默认1024 太小

进程数限制  ulimit –u   不同版本不一样

禁掉NUMA  numctl –interleave=all

5. 选择合适的内存分配算法

默认的内存分配就是c的malloc 现在也出现许多优化的内存分配算法:

jemalloc and tcmalloc

从MySQL 5.5后支持声明内存储方法。

[mysqld_safe]

malloc-lib = tcmalloc

 

或是直接指到so文件

[mysqld_safe]

malloc-lib=/usr/local/lib/libtcmalloc_minimal.so

 

6. 使用更快的存储设备ssd或是固态卡

存储介质十分影响MySQL的随机读取,写入更新速度。新一代存储设备固态ssd及固态卡的出现也让MySQL 大放异彩,也是淘宝在去IOE中干出了一个漂亮仗。

7. 选择良好的文件系统

推荐XFS, Ext4,如果还在使用ext2,ext3的同学请尽快升级别。 推荐XFS,这个也是今后一段时间Linux会支持一个文件系统。

文件系统强烈推荐: XFS

 

8. 优化挂载文件系统的参数

挂载XFS参数:

(rw, noatime,nodiratime,nobarrier)

挂载ext4参数:

ext4 (rw,noatime,nodiratime,nobarrier,data=ordered)

如果使用SSD或是固态盘需要考虑:

• innodb_page_size = 4K

• Innodb_flush_neighbors = 0

 

9. 选择适合的IO调度

正常请下请使用deadline 默认是noop

echo dealine >/sys/block/{DEV-NAME}/queue/scheduler

 

10. 选择合适的Raid卡Cache策略

请使用带电的Raid,启用WriteBack, 对于加速redo log ,binary log, data file都有好处。

 

11. 禁用Query Cache

Query Cache在Innodb中有点鸡肋,Innodb的数据本身可以在Innodb buffer pool中缓存,Query Cache属于结果集缓存,如果开启Query Cache更新写入都要去检查query cache反而增加了写入的开销。

在MySQL 5.6中Query cache是被禁掉了。

 

12. 使用Thread Pool

现在一个数据对应5个以上App场景比较,但MySQL有个特性随着连接增多的情况下性能反而下降,所以对于连接超过200的以后场景请考虑使用thread pool. 这是一个伟大的发明。

13. 合理调整内存

13.1 减少连接的内存分配

连接可以用thread_cache_size缓存,观查属于比较属不如thread pool给力。数据库在连上分配的内存如下: max_used_connections * (

read_buffer_size +

read_rnd_buffer_size +

join_buffer_size +

sort_buffer_size +

binlog_cache_size +

thread_stack +

2 * net_buffer_length …

)

13.2 使较大的buffer pool

要把60-80%的内存分给innodb_buffer_pool_size.  这个不要超过数据大小了,另外也不要分配超过80%不然会利用到swap.

 

 

14. 合理选择LOG刷新机制

Redo Logs:

– innodb_flush_log_at_trx_commit  = 1 // 最安全

– innodb_flush_log_at_trx_commit  = 2 //  较好性能

– innodb_flush_log_at_trx_commit  = 0 //  最好的情能

binlog :

binlog_sync = 1  需要group commit支持,如果没这个功能可以考虑binlog_sync=0来获得较佳性能。

数据文件:

innodb_flush_method = O_DIRECT

 

15. 请使用Innodb表

可以利用更多资源,在线alter操作有所提高。 目前也支持非中文的full text, 同时支持Memcache API访问。目前也是MySQL最优秀的一个引擎。

如果你还在MyISAM请考虑快速转换。

 

16. 设置较大的Redo log

以前Percona 5.5和官方MySQL 5.5比拼性能时,胜出的一个Tips就是分配了超过4G的Redo log ,而官方MySQL5.5 redo log不能超过4G. 从 MySQL 5.6后可以超过4G了,通常建Redo log加起来要超过500M。 可以通过观查redo log产生量,分配Redo log大于一小时的量即可。

17. 优化磁盘的IO

innodb_io_capactiy 在sas 15000转的下配置800就可以了,在ssd下面配置2000以上。

在MySQL 5.6:

innodb_lru_scan_depth =  innodb_io_capacity / innodb_buffer_pool_instances

innodb_io_capacity_max  =  min(2000, 2 * innodb_io_capacity)

 

18. 使用独立表空间

目前来看新的特性都是独立表空间支持:

truncate table 表空间回收

表空间传输

较好的去优化碎片等管理性能的增加,

整体上来看使用独立表空间是没用的。

19. 配置合理的并发

innodb_thread_concurrency =并发这个参数在Innodb中变化也是最频繁的一个参数。不同的版本,有可能不同的小版本也有变动。一般推荐:

在使用thread pool 的情况下:

innodb_thread_concurrency = 0 就可以了。

如果在没有thread pool的情况下:

5.5 推荐:innodb_thread_concurrency =16 – 32

5.6 推荐innodb_thread_concurrency = 36

20. 优化事务隔离级别

默认是 Repeatable read

推荐使用Read committed  binlog格式使用mixed或是Row

较低的隔离级别 = 较好的性能

21. 注重监控

任环境离不开监控,如果少了监控,有可能就会陷入盲人摸象。 推荐zabbix+mpm构建监控。

MySQL整型数据溢出的处理策略

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

今天接到一个朋友电话说是觉的数据库被别人更改了,出现数据不对的问题 。经过很久的排查是数据类型溢出了(发生问题的版本是MySQL 5.1)。后来通过给朋友那边把MySQL 5.1升级到MySQL 5.5去解决这个问题。 这也让我有兴趣去了解一下MySQL不同版本数据类型溢出的处理机制。

先看一下MySQL支持的整型数及大小,存储空间:

Type Storage Minimum Value Maximum Value 存储大小
  (Bytes) (Signed/Unsigned) (Signed/Unsigned) byte
TINYINT 1 -128 127 1 byte
    0 255  
SMALLINT 2 -32768 32767 2 bytes
    0 65535  
MEDIUMINT 3 -8388608 8388607 3 bytes
    0 16777215  
INT 4 -2147483648 2147483647 4 bytes
    0 4294967295  
BIGINT 8 -9223372036854775808 9223372036854775807 8 bytes
    0 18446744073709551615  

另外请记着mysql的数据处理会转成bigint处理,所以这里就用bigint几个测试:

SELECT CAST(0 AS UNSIGNED) - 1;

SELECT 9223372036854775807 + 1;

MySQL 5.1 下:

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
+-------------------------+
| CAST(0 AS UNSIGNED) - 1 |
+-------------------------+
|    18446744073709551615 |
+-------------------------+
1 row in set (0.01 sec)

mysql> SELECT 9223372036854775807 + 1;
+-------------------------+
| 9223372036854775807 + 1 |
+-------------------------+
|    -9223372036854775808 |
+-------------------------+
1 row in set (0.01 sec)

MySQL 5.5, 5.6, 5.7下:

mysql> SELECT CAST(0 AS UNSIGNED) - 1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(cast(0 as unsigned) - 1)'
mysql> 
mysql> 
mysql> 
mysql> SELECT 9223372036854775807 + 1;
ERROR 1690 (22003): BIGINT value is out of range in '(9223372036854775807 + 1)'

所在处理这类数据是一定要小心溢出(如早期有做弊冲Q币就是利用这个方法处理)

这个问题有可能会出现积分消息,积分相加, 或是一些钱相关的业务中出现, 主库5.1 ,从库MySQL 5.5情况也会出现不同步的问题。
建议:这类业务系统尽可能的升级到MySQL 5.5后版本 

更多详情参考: http://dev.mysql.com/doc/refman/5.7/en/out-of-range-and-overflow.html

MHA 参数列表详解

作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

MHA 参数列表

  • Local : 指每一个配置块内部。 Local功能的参数需要放置在[server_xxx] 块下面
  • App : 参数作用于master/slave, 这些参数需要配置在[server_default]块的下面
  • Global : 作用于master/slave, Global级别的参数用于管理多组master/slave结构,可以统一化管理一些参数。 

    hostname

    配置MySQL服务器的机器名或是IP地址,这个配置项是必须的,而且只能配置在[server_xxx]这个块下面。
    如:

    参数名 是否必须 作用域 默认值 例子及说明
    hostname Yes Local Only hostname=mysql_server1, hostname=192.168.0.1, etc

    ip

    MySQL服务器的ip地址。 默认从gethostname($hostname)中获得。 默认不用配置这个参数,MHA可以通过hostname自动获取,MHA通过IP地址连接MySQL服务器及SSH连接。
    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ip No Local Only 通过gethostbyname($hostname)获得 ip=192.168.1.3

    port

    MySQL运行的端口号。 默认是3306. MHA使用IP和端口号连接MySQL
    如:

    参数名 是否必须 作用域 默认值 例子及说明
    port No Local/App/Glbal 3306 port=3306

    ssh_host

    (从MHA 0.53后开始支持) MHA要ssh上MySQL目标服务器使用hostname 或是ip地址。这个参数主要用于在使用多个VLAN的环境中。为了安全原因ssh默认不允许。默认这个参数和hostname相同。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ssh_host No Local Only 和hostname相同 ssh_host=mysql_server1, ssh_host=192.168.0.1, etc

    ssh_ip

    (从MHA 0.53后开始支持) 和ssh_host作用相同。 默认是gethostname($ssh_host)获得。 

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ssh_ip No Local Only gethostbyname($ssh_host) ssh_ip=192.168.1.3

    ssh_port

    (从MHA 0.53后开始支持) SSH使用的端口号,默认是22.
    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ssh_port No Local/App/Global 22 ssh_port=22

    ssh_connection_timeout

    (从MHA 0.54后支持)默认是5秒。在没添加这个参数之前ssh超时时间是写死的。
    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ssh_connection_timeout No Local/App/Global 5 ssh_connect_timeout=5

    ssh_options

    (从MHA 0.53后支持) 添加ssh命令行的支持参数,例如加上特别文件名的key的支持等。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ssh_options No Local/App/Global “” 空的 ssh_options=”-i /root/.ssh/id_dsa2″

    candidate_master

    你可能对于同一组slave中有着不同的规划,有的其望在Master故障时,提升为新的Master(如: Raid1的slave比Raid0的slave更适合做Master)

    这个参数的作用是当设计candidate_master = 1时,这个服务器有较高的优先级提升为新的master(还要具备: 开启binlog, 复制没有延迟)。 所以当设置了candidate_master = 1的机器在master故障时必然成为新的master. 但这是很有用的设置优先级的一个参数。

    如果设置了多台机器的caddidate_master = 1 , 优先策略依赖于块名字([server_xxx]). [server_1] 优衔权高于[server_2].

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    candidate_master No Local Only 0 candidate_mast=1

    no_master

    当设置了no_master = 1的服务器,这个服务器永远不会提升为新的master. 这个参数据对于永远不期望成为master的机器很有用。 如: 你可能需要在使用raid0的机器上设置no_master = 1 或是你希望在远程的idc里运行一个slave. 注意: 当没有可以成为新master的机器是MHA就直接退出来了同时停止监控和master故障切换。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    no_master No Local Only 0 no_master=1

    ignore_fail

    在默认情况下,MHA manager不会在slave存在故障的情况下(已经不能通过SSH/MySQL进行连接,或是SQL Thread已经停止出错,其它原因)的情况下进行Master的故障切换(当不存在slave时MHA manager也会退出)。 但有些情况下你期望在slave存在问题的情况下,也进行故障切换。 所以当设置了ignore_fail = 1时,MHA会在所有的机器有问题的时间也会进行故障切换。 默认是0.

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ignore_fail No Local Only 0 ignore_fail=1

    #skip_init_ssh_check#
    在MHA manager启动时跳过ssh检查。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    skip_init_ssh_check No Local Only 0 skip_init_ssh_check=1

    skip_reset_slave

    (从MHA 0.56开始支持) Master故障切换后新的master上执行RESET SLAVE(ALL).

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    skip_reset_slave No Local/App/Global 0 skip_reset_slave=1

    user

    用于管理MySQL的用户名。这个最后需要root用户,因为它需要执行:stop slave; change master to , reset slave. 默认: root

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    user No Local/App/Global root user=mysql_root

    password

    MySQL的管理用户的密码。 默认是空的

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    password No Local/App/Global 空的 password=rootpass

    repl_user

    MySQL用于复制的用户,也是用于生成CHANGE MASTER TO 每个slave使用的用户。 这个用户必须有REPLICATION SLAVE权限在新的Master上。默认情况下 repl_user会在将来成为master的机器上运行show slave status获取到。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    repl_user No Local/App/Global 从show slave status repl_user=repl

    repl_password

    MySQL中repl_user用户的密码。 默认是当前复制用的密码。  当你使用online_master_switch时,当使用–orig_master_is_new_slave(原来的Master成为新Master的一个slave)时,如果没有repl_password 开启同步就会失败了。因为当前master上用于复制的用户名和密码都是空的(MHA在原来的Master上执行change master to 时没有带复制的密码,虽然其它slave上设置了复制的密码)

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    repl_password No Local/App/Global 当前复制用的密码 repl_password=replpas

    disable_log_bin

    当设置了这个参数,在slave应用差异的relay log时不会产生二进制日志。 内部实现通过mysqlbinlog的disable-log-bin实现。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    disable_log_bin No Local/App/Global 0 disable_log_bin=1

    master_pid_file

    指定MySQL的pid文件。 这个参数在一台服务器上运行多个MySQL服务进程时非常有用。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    master_pid_file No Local/App/Global master_pid_file=/var/lib/mysql/master1.pid

    ssh_user

    MHA Mananger, MHA node系统上的用户。 这个帐号需要在远程机器上有执行权限(Manager->MySQL),在slave成员之间复制差异的relay-log(MySQL->MySQL)

    这个用户必须有读取MySQL的binary/relay日志和relay_log.info的权限,还需要对远程MySQL上remote_workdir目录的写权限。

    这个用户还必须可以直接ssh到远程机顺上, 推荐使用ssh pbulic key . 一般使用的ssh_user也是运行manager那个那个用户。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ssh_user No Local/App/Global 当前使用的系统用户 ssh_user=root

    remote_workdir

    MHA node上工作目录的全路径名。如果不存在,MHA node会自动创建,如果不允许创建,MHA Node自动异常退出。 需要注意MHA manager 或是MHA node上需要检查空间是否可用,所以需要注意检查这个。 一般默认, remote_workdir是的”/var/tmp”

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    remote_workdir No Local/App/Global /var/tmp remote_workdir=/var/log/masterha/app1

    master_binlog_dir

    master上用于存储binary日志的全路径。这个参数用于当master上mysql死掉后,通过ssh连到mysql服务器上,找到需要binary日志事件。这个参数可以帮助用于无法找到master进程死掉后binary日志存储位置。

    一般: master_binlog_dir是”/var/lib/mysql/, /var/log/mysql”. “/var/lib/mysql/”是大多数系统发行版本的存放位置,”/var/log/mysql”是ubuntu发行版本的存放位置。 你也可以设置多个存放位置用逗号隔开。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    master_binlog_dir No Local/App/Gobal /var/lib/mysql master_binlog_dir=/data/mysql1,/data/mysql2

    log_level

    设置MHA manager记录LOG的级别。 默认是info级别而且大多数情况也是比较适合。 同样可以设置为: debug/info/warning/error.

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    log_level No App/Global info log_level=debug

    manager_workdir

    用于指定mha manager产生相关状态文件全路径。 如果没设置 默认是/var/tmp

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    manager_workdir No App /var/tmp manager_workdir=/var/log/masterha

    manager_log

    指定mha manager的绝对路径的文件名日志文件。 如果没设置MHA Manager将打印到STDOUT/STDERR。 当手工执行故障切换(交互模式切换),MHA Manager会忽略manager_log设置直接将日志输出到STDOUT/STDERR.

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    manager_log No App STDERR manager_log=/var/log/masterha/app1.log

    check_repl_delay

    在默认情况下,当一个slave同步延迟超过100M relay log(需要应用超过100M relay log), MHA在做故障切换时不会选择这个slave做为新的master,因为恢复需要经过很长时间.当设置了check_repl_delay = 0, MHA将忽略被选择的slave上的同步延迟。 这个选项在设置了candidate_master = 1特声明的期望这台机器成为master的情况下特别有用。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    check_repl_delay No App/Golbal 1 check_repl_delay=0

    check_repl_filter

    在默认下情况,当master和slave设置了不同了binary log/replication 过滤规则时,MHA直接报错不会进行监控和故障切换。 这些将会导致出现一些异想不到的错误”Table not exists”。如果你100%确认不同的过滤规则不会导致恢复中的错误,设置check_repl_filter=0。 需要注意: 当使用了check_repl_filter = 0时,MHA不会检查过滤规则在应用差异的relay日志,所以有可能会出现”Table not exists”的错误。当你设置了这个参数请小心处理。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    check_repl_filter No App/Global 1 check_repl_filter=0

    latest_priority

    在默认情况下,和Master最接近的slave(一个slave从Master上获得了最一个binlog事件)是最有优先权成为新的master。 如果你想控制一下切换的策略(如: 先选择host2,如果不行,选host3;host3不行,选host4…) 那么设置latest_priority = 0 就可以了。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    latest_priority No App/Global 1 latest_priority=0

    multi_tier_slave

    从MHA 0.52开始, 多层复制可以支持了。在默认情况下,不支持三层或是更多层的复制配置。 如果: host2从host1上复制,host3从host2上复制。 在默认配置的情况下不支持写host{1,2,3},因为这是一个三层的复制,MHA Manager会停止报错。 当设置了multi_tier_slave, MHA Manager就不会在三层复制报错停止。 但是会忽略第三层的机器。也就是如果host1挂了,host2将会成为新的master,host3还是从host2上进行复制。

    这个参数在MHA Manager 0.52后的版开始支持。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    muli_tier_slave No App/Global 0 multi_tier_slave=1

    ping_interval

    这个参数设置MHA Manager多长时间去ping一下master(执行一些SQL语句). 当失去和master三次偿试,MHA Manager会认为MySQL Master死掉了。也就是说,最大的故障切换时间是4次ping_interval的时间,默认是3秒。

    如果MHA Manager在和MySQL创建连接时都收到多连接错误或是认证错误,这个就不做重试就会认为master已经挂掉。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ping_interval No App/Global 3 ping_interval=5

    ping_type

    (从MHA 0.53后开始支持) 在默认情况下, MHA manager和MySQL创建一个连接执行”select 1″(ping_type=select)用于检查master是否健康。 但有一些情况: 每次检测都连接/然后断开会比较好一点,这样对于tcp方面的错误感知更快一点。设置ping_type=CONNECT 就行了。从MHA 0.56后pint_type=INSERT也被添加。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    ping_type No App/Global SELECT ping_type=CONNECT

    secondary_check_script

    一般来讲, 非常推荐使用更多网络上机器是不同路由策略上的机器来检查MySQL Master是否存活。 默认情况下,只有MHA Manager通过一个路由来检查Master是否存活。这个也是不推荐的。MHA可以通过外部secondary_check_script配置的脚本来做到从多个路由策略下进行检查。

    secondary_check_script = masterha_secondary_check -s remote_host1 -s remote_host2

    secondary_check_script包含在MHA Manager发行包中。 MHA中内置的secondary_check_script在大多数情况下工作良好,但并不是任何地都可以使用这个脚本。

    在上面的例子中, MHA Manager通过Manager->(A)->remote_host1->(B)->master_host 和Manager->(A)-remote_host2->(B)->master_host来检查MySQL master是否存活。如果在连接过程中通过A可以都成功,通过B是都失败,secondary_\check_\script返回0,而且认为master已经死掉,进行故障切换。如果通过A成功,但返回代码为: 2,则MHA manager有会认为是网络问题,则不会进行故障切换。如果A成功,B也成功,masterha_secondary_check 退出返回:3 则MHA Manager就为认为MySQL Master为存活状态, 则不会进行故障切换。

    一般来讲, remote_host1和remote_host2是和MHA Manager及MySQL Server位于不同的网段中。

    MHA会调用secondary_check_script声明的脚本并自动带上一些参数。 masterha_secondary_check在很多场景都是适用的,但是你也可以自已实现这个程序带有更多的功能。

  • –user=(在远程机器上使用的SSH用户名。 ssh_user的值将被使用)
  • –master_host = (master的hostname)
  • –master_ip = (master的ip地址)
  • –master_port = ( master的端口号)

    注意: 内置的masterha_secondary_check脚本依赖于的Perl的IO::Socket::INET(Perl 5.6.0中是默认支持包含这个模块)。 masterha_secondary_check需要通过ssh连接到远程的机器上,所以需要manager到远程机器上建立public key信任。另外masterha_secondary_check是通过和Master建立TCP的连接测试Master是否存活,所以mysql设置的max_connections不起作用。 但每次TCP连接成功后,MySQL的Aborted_connects 值都会加1。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    secondary_check_script No App/Global null secondary_check_script= masterha_secondary_check -s remote_dc1 -s remote_dc2

    master_ip_failover_script

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    master_ip_failover_script No App/Global null master_ip_failover_script=/usr/local/custom_script/master_ip_failover

    master_ip_online_changes_script

    这个参数有点类似于master_ip_failover_script,但这个参数不用于master 故障转意,只使用到master在线的切换。

  • 冻结Master写的过程:

    –command=stop or stopssh
    –orig_master_host = (当前master的主机名)
    –orig_master_ip = (当前master的ip地址)
    –orig_master_port = (当前master的port端口号)
    –orig_master_user = (当前master的用户)
    –orig_master_password = (当前master的用户名)
    –orig_master_ssh_user = (从0.56支持,当前master的ssh的用户名)
    –orig_master_is_new_slave =  (从 0.56 ,是否把原Master更改为新的slave)

  • 新的Master接受写的过程:

    –command=start
    –orig_master_host = ( 原master的机器名 )
    –orig_master_ip = ( 原master的ip )
    –orig_master_port = ( 原master的端口号 )
    –new_master_host = (新master的机器名)
    –new_master_ip = (新master的ip)
    –new_master_port = (新master的端口号)
    –new_master_user = (新master上的用户名)
    –new_master_password = (新master上的用户名及密码)
    –new_master_ssh_user = (从0.56支持, 新master上的ssh用户)

    MHA在冻结写的切换过程中会在Master上执行FlUSH TABLES WITH READ LOCK,在这个优雅的切换过程不会有任何写入的。在新的Master在开始授权写的过程中,你可以做和master_ip_failover_script一样的事情。 例如: 创建用户及权限, 执行set global read_only=0, 更新数据库路由表竺。 如果脚本执行退出码不是0 或是10, MHA Manager异常退出并发不会继续进行master切换。

    默认这个参数是空的,所以MHA Manager在默认情况下什么也不做。

    可以在(MHA Manager package)/samples/scripts/master_ip_online_change。里找到例子脚本。例子脚本包含于MHA Manager源文件或是GitHub的分支中。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    master_ip_online_change_script No App/Global null master_ip_online_change_script= /usr/local/custom_script/master_ip_online_change

    shutdown_script

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    shutdown_script No App/Global null shutdown_script= /usr/local/custom_script/master_shutdown

    report_script

    在Master故障完毕后,也许想发一个送一个报告(如email)报告一下切换完毕或是发生的错误。report_script可以完成这个工作。MHA Manager可以通过以下参数使用:

  • –orig_master_host = (死掉master机器名)
  • –new_master_host = (新的master机器名)
  • –new_slave_hosts = (新的slave机器名列表,用逗号隔开)
  • –subject = (邮件名)
  • –body = (正文)

    默认这些参数是空的。 所以默认MHA Manager什么事情也不做。

    可以在(MHA Manager package)/samples/scripts/send_report里找到例子脚本。例子脚本包含于MHA Manager源文件或是GitHub的分支中。

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    report_script No App/Global null report_script= /usr/local/custom_script/report

    init_conf_load_script

    这个参数用于不想设置明文在配置文件中(如:密码相关)。 只用返回”name=value”这样的值。 这个可以用来复盖global配置中的一些值。一个例子脚本如下。

    #!/usr/bin/perl

    print “password=$ROOT_PASS\n”;

    print “repl_password=$REPL_PASS\n”;

    如:

    参数名 是否必须 作用域 默认值 例子及说明
    init_conf_load_script No App/Global null report_script= /usr/local/custom_script/init_conf_loader
  • PHP调用存储过程返回值不一致的问题

    作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.
    今天遇一个同学聊存储过程返回值经常得到意外的值为null, 因为白天有事,晚上给做一个实验放在这里供有相应问题的同学查看一下。
    存储过程:

    delimiter //
    create procedure usp_s2(out par1 int)
    begin
    	select inet_ntoa(ip) , port from proxy_list limit 5;
    	select count(*) into par1 from proxy_list;
    END//
    delimiter ;
    

    session 1执行:

    mysql> call usp_s2(@a);
    +---------------+------+
    | inet_ntoa(ip) | port |
    +---------------+------+
    | 1.34.21.86    | 8088 |
    | 1.34.59.50    | 8088 |
    | 1.34.69.15    | 8088 |
    | 1.34.73.110   | 8088 |
    | 1.34.76.218   | 8088 |
    +---------------+------+
    5 rows in set (0.00 sec)
    
    Query OK, 1 row affected (0.01 sec)
    
    mysql> select @a;
    +------+
    | @a   |
    +------+
    | 4430 |
    +------+
    1 row in set (0.00 sec)
    

    session 2执行:

    mysql> select @a;
    +------+
    | @a   |
    +------+
    | NULL |
    +------+
    1 row in set (0.00 sec)
    

    可见两个session得到的结果不一致。 基本可以肯定两次调用落入不同的会话中会得到不同的值。
    为了一致可以如用如下调用:

    multi_query("call usp_s2(@total); select @total;");
    
    if ($result) {
            do {
            if ($r = $db->store_result()) {
                    if ( $r->field_count == 2){
                            while( $row = $r->fetch_row() ){
                                    print "ip: $row[0], port: $row[1]\n";
                            }
                    }else{
                            $row  = $r->fetch_row();
                            print "total: $row[0]\n";
                    }
            }
            } while ( $db->next_result() );
    }
    $db->close();
    ?>
    
    $php t_proc_return.php 
    ip: 1.34.21.86, port: 8088
    ip: 1.34.59.50, port: 8088
    ip: 1.34.69.15, port: 8088
    ip: 1.34.73.110, port: 8088
    ip: 1.34.76.218, port: 8088
    total: 4430
    

    Good luck.

    记录一次truncate操作数据恢复

    作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

    实际线上的场景比较复杂,当时涉及了truncate, delete 两个操作,经确认丢数据差不多7万多行,等停下来时,差不多又有共计1万多行数据写入。 这里为了简单说明,只拿弄一个简单的业务场景举例。

    测试环境: Percona-Server-5.6.16
    日志格式: mixed 没起用gtid

    表结构如下:

    CREATE TABLE `tb_wubx` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `name` varchar(32) DEFAULT NULL,
    PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

    基于某个时间点有一个备份或是有全量的binlog是能恢复数据的一个唯一保证。 例如我们的备份就是一个表结构创建语句,binlog pos相关信息: mysql-bin.000004 , 4,然后进行了如下:

    –t1时间 程序写入:
    insert into tb_wubx(name) values(‘张三’),(‘李四’);
    insert into tb_wubx(name) values(‘隔壁老王’);
    –t2时间 某个人员失误
    truncate table tb_wubx;
    –t3时间 程序写入
    insert into tb_wubx(name) values(‘老赵’);
    update tb_wubx set name=’老赵赵’ where id=1;

    现在表里的数据情况:

    mysql>select * from tb_wubx;
    +----+-----------+
    | id | name |
    +----+-----------+
    | 1 | 老赵赵 |
    +----+-----------+
    1 row in set (0.00 sec)
    

    可以见truncate table操作后,表的自增id又变更为从1开始,原来写入的数据应该是:
    +—-+———–+
    | id | name |
    +—-+———–+
    | 1 | 张三 |
    +—-+———–+
    | 2 | 李四 |
    +—-+———–+
    | 3 | 隔壁老王 |
    +—-+———–+

    如果没生truncate table操作,实际的数据应该为:
    +—-+———–+
    | id | name |
    +—-+———–+
    | 1 | 张三 |
    +—-+———–+
    | 2 | 李四 |
    +—-+———–+
    | 3 | 隔壁老王 |
    +—-+———–+
    | 4 | 老赵赵 |
    +—-+———–+

    而且线上的恢复那个表时和序序开发人员了解才知道,原来那个id和缓存及其它地方有依赖,因为id乱了,也会造成程序错乱。这个时间修复id在程序层错乱的事,留给开发人员了关建是给他们讲明白恢复的结果是什么样,我们的关建任务是把数据恢复出来。好,接下来的工作是开始从binlog中恢复数据。
    利用: show binary logs; 查看当的log文件分布, 然后利用show binlog events in ‘binary log文件’; 查看log文件的内容,目的是找到truncate发生的日志位置。
    另外因为基于备份(由log的启始位置)或是从量log, 如果基于备份有log的起始位置,我们需要处理的log文件是启始位置到发生truncate的日值(后面的数据处理不了,会发生主建冲突的错误造成truncate后的数据不能恢复),
    如果是全量日志,需要从创建完mysql后库后的日志去处理到当前的发生truncate的位置(后面数据会因为主建冲突写不进去)
    恢复准备工作,创建一个库用于恢复数据,这里创建了一个re_wubx, 及原结构的表: tb_wubx (相当于恢复了备份,过程省略)
    作者:吴炳锡 来源:http://www.mysqlsupport.cn/ 联系方式: wubingxi#gmail.com 转载请注明作/译者和出处,并且不能用于商业用途,违者必究.

    mysql> show binary logs;
    +------------------+-----------+
    | Log_name | File_size |
    +------------------+-----------+
    | mysql-bin.000001 | 143 |
    | mysql-bin.000002 | 261 |
    | mysql-bin.000003 | 562 |
    | mysql-bin.000004 | 1144 |
    +------------------+-----------+
    4 rows in set (0.00 sec)
    

    我这里有一个备份文件就是那个创建表的sql语句,位置是mysql-bin.000004 , 4
    在这个案例里我只用cover住mysql-bin.000004这个文件。

    mysql>show binlog events in 'mysql-bin.000004';
    +------------------+------+-------------+-----------+-------------+----------------------------------------------------+
    | Log_name         | Pos | Event_type    | Server_id   | End_log_pos | Info |
    +------------------+------+-------------+-----------+-------------+----------------------------------------------------+
    | mysql-bin.000004 | 4   | Format_desc   | 753306 | 120 | Server ver: 5.6.16-64.2-rel64.2-log, Binlog ver: 4 |
    | mysql-bin.000004 | 120 | Query         | 753306 | 209 | use `wubx`; truncate table tb_wubx |
    | mysql-bin.000004 | 209 | Query         | 753306 | 281 | BEGIN |
    | mysql-bin.000004 | 281 | Table_map     | 753306 | 334 | table_id: 91 (wubx.tb_wubx) |
    | mysql-bin.000004 | 334 | Write_rows    | 753306 | 393 | table_id: 91 flags: STMT_END_F |
    | mysql-bin.000004 | 393 | Xid           | 753306 | 424 | COMMIT /* xid=1073 */ |
    | mysql-bin.000004 | 424 | Query         | 753306 | 496 | BEGIN |
    | mysql-bin.000004 | 496 | Table_map     | 753306 | 549 | table_id: 91 (wubx.tb_wubx) |
    | mysql-bin.000004 | 549 | Write_rows    | 753306 | 602 | table_id: 91 flags: STMT_END_F |
    | mysql-bin.000004 | 602 | Xid           | 753306 | 633 | COMMIT /* xid=1074 */ |
    | mysql-bin.000004 | 633 | Query         | 753306 | 722 | use `wubx`; truncate table tb_wubx |
    | mysql-bin.000004 | 722 | Query         | 753306 | 794 | BEGIN |
    | mysql-bin.000004 | 794 | Table_map     | 753306 | 847 | table_id: 92 (wubx.tb_wubx) |
    | mysql-bin.000004 | 847 | Write_rows    | 753306 | 894 | table_id: 92 flags: STMT_END_F |
    | mysql-bin.000004 | 894 | Xid           | 753306 | 925 | COMMIT /* xid=1081 */ |
    | mysql-bin.000004 | 925 | Query         | 753306 | 997 | BEGIN |
    | mysql-bin.000004 | 997 | Table_map     | 753306 | 1050 | table_id: 92 (wubx.tb_wubx) |
    | mysql-bin.000004 | 1050 | Update_rows  | 753306 | 1113 | table_id: 92 flags: STMT_END_F |
    | mysql-bin.000004 | 1113 | Xid          | 753306 | 1144 | COMMIT /* xid=1084 */ |
    +------------------+------+-------------+-----------+-------------+----------------------------------------------------+
    19 rows in set (0.00 sec)

    看到这个表刚开始就发生一次truncate, 那其实也可以说明我就恢复刚开始那个truncate到后来那个误操作的truncate table的语句之间的数据就是丢失的数据。
    这个恢复可以从mysql-bin.000004 pos: 4到mysql-bin.000004 pos: 633 即:

    mysqlbinlog --rewrite-db='wubx->re_wubx' --start-position=4 --stop-position=633 mysql-bin.000004 |mysql -S /tmp/mysql.sock re_wubx

    恢复结果如下:

    mysql -S /tmp/mysql.sock re_wubx;
    mysql>select count(*) from tb_wubx;
    +----------+
    | count(*) |
    +----------+
    | 3 |
    +----------+
    1 row in set (0.02 sec)
    
    mysql>select * from tb_wubx;
    +----+--------------+
    | id | name |
    +----+--------------+
    | 1 | 张三 |
    | 2 | 李四 |
    | 3 | 隔壁老王 |
    +----+--------------+
    3 rows in set (0.00 sec)
    
    mysql>insert into tb_wubx(name) select name from wubx.tb_wubx;
    Query OK, 1 row affected (0.00 sec)
    Records: 1 Duplicates: 0 Warnings: 0
    
    mysql> rename table wubx.tb_wubx to wubx.bak_tb_wubx;
    Query OK, 0 rows affected (0.04 sec)
    
    mysql> rename table re_wubx.tb_wubx to wubx.tb_wubx;
    Query OK, 0 rows affected (0.03 sec)
    
    mysql> select * from wubx.tb_wubx;
    +----+--------------+
    | id | name |
    +----+--------------+
    | 1 | 张三 |
    | 2 | 李四 |
    | 3 | 隔壁老王 |
    | 4 | 老赵赵 |
    +----+--------------+
    4 rows in set (0.00 sec)
    

    恢复完成。
    想一想,如果我跳过那个truncate继续执行那些binlog会怎么样 ?