Archive for the ‘mysql’ Category.

mysql character_sets_dir

我们有一套环境使用的是MySQL的多实例,并且我们MySQL不是放在MySQL认为应该放的目录:/usr/local/mysql下,所以今天又一个悲剧了。
数据库主机创建了一个ascii为字符集的表,主机创建成功,但是传到备机执行的时候,出错:
110510 17:14:55 [Warning] Slave: Unknown character set: ‘ascii’ Error_code: 1115
也就是说备机没有ascii字符集。
好吧,那就SHOW CHARACTER SET来看看,确实没有。
但是主机确实是有的,主备机的SHOW CHARACTER SET是不一样的。。。

好吧,其实我们备机使用的是多实例,主机是单实例。并且备机的MySQL采用的是二进制包的绿色安装。
那么这里就有一个问题,我们使用的mysqld_multi启动MySQL时它采用的是什么样的默认配置,这样的配置是否都是正确的
我们其实并不是非常肯定。
这里ascii字符集就是一个问题。

mysql的字符集配置详细请见:http://dev.mysql.com/doc/refman/5.1/en/charset-configuration.html
这里我们的备机用mysqld_multi启动以后,
show variables like ‘character_sets_dir’;
显示为:/usr/local/mysql/share/charsets。
而这个目录根本就不存在。

解决这个问题其实有三个办法:
1、mkdir -p /usr/local/mysql/share/; ln -s /path/to/correct/share/charsets /usr/local/mysql/share/charsets。
2、修改mysqld_multi,使得指向正确的目录。(目前这个办法没有走通,有待跟进)
3、在my.cnf中添加:character_sets_dir=/path/to/correct/share/charsets/
由于这个参数是read-only的,你只能重启MySQL来使它生效了

唉,其实作为一个MySQL DBA,连MySQL的这些配套的脚本都没有详细的搞清楚,有点汗颜,需要好好看一下。
如果你嫌麻烦,还是建议你把MySQL的二进制包放在MySQL指定的/usr/local/mysql下把,避免意外。

may your success

mysql培训课程详细列表

为了提高开发人员和部门内部MySQL使用的技能和深度,我们特别制作了一些开发培训的计划,下面是一些主题

mysql应用开发培训
mysql安装的三种方式:rpm安装,tar.gz安装,configure安装
mysql 数据类型和函数,字节数,最大最小值,
mysql 适用SQL和不适用SQL。哪些SQL应该杜绝,哪些SQL应该避免,哪些在oracle适用但是尽量避免在MySQL中使用。
mysql 索引,约束,索引是否越多越好,覆盖索引,主键索引。
mysql 自定义函数以及procedure。delimiter,游标,调用,
mysql 视图,子查询,连接,union。不使用视图的原因,子查询的弊端,替换方案,内联接,外联接,union all和union的区别,使用场景。
mysql 分页limit,以及简单的实现原理
mysql 存储引擎介绍和比较。至少包括innodb,MyISAM,csv,memory,federated,ndb

mysql管理维护培训
mysql 备份和恢复。包括物理冷备;mysqldump; select into outfile;xtrabackup备份,优缺点,限制和使用场景。
mysql 复制搭建。步骤:备份并恢复数据;获得主机备份位置的binlog;change master
mysql binlog介绍。三种格式,分别的优缺点,statement复制的安全问题,row方式下目前我们遇到的几个问题。
mysql show processlist中,各个查询的状态的含义:query,NULL,executing,update等等。
mysql show engine innodb status介绍。
mysql show slave status输出详细解释。包括master.info,relay-log.info,logbin.index,relay-log.index, logbin.0001,relay-log.0001解释,slave io和slave sql 的不同状态含义
mysql 用户权限介绍。localhost,127.0.0.1,%的不同点。限制IP,限制数据库,限制表,限制字段,数据库或者表等的单字匹配以及多字匹配。
mysql 工具介绍:目前我们使用比较频繁的工具:mysql;mysqld_safe;mysqladmin;mysqlcheck;mysql_install_db;mysqlbinlog;mysqldump;mysqld_multi;以及第三方工具innotop;maatkit;mysqlsla
mysql my.cnf介绍。作用,mysql默认的位置,组的概念,工具特定参数介绍。
mysql 多实例概念和管理
mysql information_schema介绍,peconar新增信息介绍。
mysql ’mysql‘schema介绍,对应表信息。
mysql cluster介绍,性能问题,内存问题。

mysql高级培训
mysql configure安装的配置参数
mysql 源码框架和文件介绍
mysql binlog格式,二进制解释。文件头,event分类,二进制格式。
innodb 物理文件格式介绍以及数据恢复方法,实用案例分析,最终导出数据展示。
innodb 锁介绍
mysql 参数介绍。
mysql 状态变量介绍.目前在性能视图中的变量有哪些
mysql 大事务情况下,show slave status锁分析,解决方案。
mysql 唯一约束和普通索引在加锁上的区别。

sql培训单独列出,不包含在这些内容里面

heartbeat替换集群中的一台主机

今天完成了替换双master其中一台主机的任务。特将具体过程记录下来以供以后参考。
背景描述:
a,b互为主备,a提供应用访问。c是a的备机,画一个最挫的图如下
a<->b
|
c
现在,我想用c替换掉b。
a和b是用heartbeat来做HA的,要求在替换主机过程中,应用不能停,对应用必须要透明。
方案:
我们采用修改b的IP,并停掉b。然后把c的hostname,IP修改为b的方法,顶替b来避免对应用的影响
1、停止主机a的slave。这个是为了避免c替换掉b的IP起来的时候,a从错误的位置开始复制binlog。因为b和c的binlog不可能为同一个位置
2、b修改Ip并停机。修改/etc/sysconfig/network-scripts/ifcfg-bond0中的IP;/etc/init.d/network restart重启网络;poweroff关机
3、用c顶替b。
a)修改主机名。利用hostname命令设置主机名;修改/etc/hosts中的节点名称;修改/etc/sysconfig/network中的主机名
b)修改IP.同2.
c)修改heartbeat。这里是比较关键的地方,经过详细测试得出:
一:如果是全新安装的机器,需要从主机a中拷贝ha.cf,authkey,cib.xml以及通过crm_uuid -w 生成正确的uuid
二:如果是从a拷贝过来的heartbeat,那么需要删除(我的安装目录为/usr/heartbeat):
/usr/heartbeat/var/lib/heartbeat/hostcache
/usr/heartbeat/var/lib/heartbeat/hb_uuid
/usr/heartbeat/var/lib/heartbeat/hb_generation
hostcache为缓存主备机节点以及uuid的地方,
hb_uuid为本节点的uuid,
hb_generation为主备机协商时握手的数值。
hb_uuid和hb_generation如果顶替的时候跟之前的节点不一样,那么主机就会报:heartbeat[11165]: 2011/03/21_18:19:40 ERROR: should_drop_message: attempted replay attack [jyl-idle-db3b]? [gen = 1245825415, curgen = 1245825416]错误。
hb_uuid需要用crm_uuid -w 来生成,不能由heartbeat默认生成。从主机a的/usr/heartbeat/var/lib/heartbeat/hostcache获得b机器的uuid,然后crm_uuid -w uuid生成。
具体的信息可以参照下面的介绍:
4.5.2. Heartbeat
The seven-step guide to replacing an existing cluster node:
Make sure the old node is completely stopped
Give the new machine the same hostname as the old one
Go to an active cluster node and look up the UUID for the old node in /var/lib/heartbeat/hostcache
Install the cluster software
Copy ha.cf and authkeys to the new node
On the new node, populate it’s UUID using crm_uuid -w and the UUID from step 2
Start the new cluster node
http://www.clusterlabs.org/doc/en-US/Pacemaker/1.0/html/Pacemaker_Explained/s-replace-heartbeat.html
4、主机a,change master 搭建c到a的复制(这里可以随意的在c上show master status获得位置,因为c是备机,它自己没有应用访问生成binlog)
5、启用c机器的heartbeat和MySQL。检查crm_resource的输出
may your success

mysql默认登录账户

前几天,一个测试的哥们来找我,问我mysql登录,如果不输入用户名,那么默认使用的那个账户登录,我一想,不就是当前你登录的账户吗?用whoami就可以得到。
但是,我错了!
我们测试了这样一个场景
场景1:先登录root账户,然后su – mysql,此时,mysql登录进去以后一看,还是以root账户登录mysql的
场景2:如果我们直接以mysql登录这台主机,输入mysql登录,提示是默认用mysql账户登录MySQL数据库的。
这样的话,我们怀疑su – mysql 把一些环境变量带到mysql账户中。但是检查了env和set输出的内容,却没有发现异常。
没辙了,请教传奇人物我们的系统管理员:库哥。检查来检查去,最后库哥通过strace为我们释疑了。
(可能我自己好好看看MySQL的源代码也可以看到原因,但是偷懒了,值得批评!)
原因如下:mysql获得默认账户是这样获得的,它首先readlink /proc/self/fd/0获得登录账户的pts,
类似于
[mysql@PLATQA153004 ~]$ readlink /proc/self/fd/0
/dev/pts/5
然后通过/var/run/utmp来获得对应的用户,/var/run/utmp不是纯文本文件,但是你用root登录主机和mysql登录主机可以明显看到对应的用户名是不一样的。
那么也就是说,mysql是以你登录主机的pts账户作为默认账户的,su 等操作对它都没有影响。
摘录几个man介绍如下:
/proc/self
This  directory  refers to the process accessing the /proc filesystem, and is identical to the /proc directory named by the process ID of the
same process.
/proc/[number]/fd
This  is  a subdirectory containing one entry for each file which the process has open, named by its file descriptor, and which is a symbolic
link to the actual file.  Thus, 0 is standard input, 1 standard output, 2 standard error, etc.
我们在linux上面经常用的0,1,2就在这里了,哈哈
In a multithreaded process, the contents of this directory are not available if the main thread has already terminated (typically by  calling
pthread_exit(3)).
Programs  that will take a filename, but will not take the standard input, and which write to a file, but will not send their output to stan-
dard output, can be effectively foiled this way, assuming that -i is the flag designating an input file and -o is  the  flag  designating  an
output file:
foobar -i /proc/self/fd/0 -o /proc/self/fd/1 …
and you have a working filter.
/proc/self/fd/N  is  approximately  the  same  as /dev/fd/N in some UNIX and UNIX-like systems.  Most Linux MAKEDEV scripts symbolically link
/dev/fd to /proc/self/fd, in fact.
The  utmp  file  allows  one  to  discover information about who is currently using the system.  There may be more users currently using the system,
because not all programs use utmp logging.

xtrabackup Bad file descriptor问题解决

一直使用xtrabackup来备份MySQL,之前也没有出过特别的问题,但是在备份我们的一个库的时候,出现了:Bad file descriptor的错误
具体错误类似如下:
InnoDB: Operating system error number 9 in a file operation.
InnoDB: Error number 9 means ‘Bad file descriptor’.
InnoDB: Some operating system error numbers are described at
InnoDB: http://dev.mysql.com/doc/refman/5.1/en/operating-system-error-codes.html
InnoDB: File operation call: ‘close’.
InnoDB: Cannot continue operation.

仔细检查,发现用户的权限有点问题;修改好了以后,再次备份,还是有问题。
然后看看这个机器跟其他机器的不同点:他的数据文件是链接到另外的mount点的,但是这个为什么会影响xtrabackup出错真是搞不懂。
有问题找google,还好搜到一篇好文章,有人也碰到了这个问题。

https://bugs.launchpad.net/percona-xtrabackup/+bug/568087

问题一样,还有人解决了,一直追到:http://bazaar.launchpad.net/~percona-dev/percona-xtrabackup/trunk/revision/133
仔细一看,这个版本是release版本之后的修改,也就是说,现成的rpm包我们是没有办法用了。
只好自己编译。
好吧,那就自己编译,还好之前在solaris上编译有经验。
这里也简单记录一下编译的一些步骤:
1、133版 http://bazaar.launchpad.net/~percona-dev/percona-xtrabackup/trunk/revision/133 下只有xtrabackup.c下载,我们可以自己到http://launchpad.net/percona-xtrabackup/release-1.2/1.2/+download/xtrabackup-1.2.tar.gz下载1.2版的源码。并把里面的xtrabackup.c替换掉。
2、xtrabackup-1.2/utils对应的目录里面有build51tree.sh, buildtree.sh分别是在linux下编译5.0和5.1版xtrabackup的脚本
3、正常的话,按照xtrabackup-1.2/Makefile里面的默认的配置是MySQL Plugin并使用XTRADB。而我并不想这样,所以我注释掉了DEFS+=  -DXTRADB_BASED和#MySQL Plugin下面的那些编译项。但是编译还是报错,查看了之前solaris编译时的注意实现发现要注释掉#MySQL 5.1下的第二个INNODBOBJS=。不知道为什么Makefile这边有两个这样的INNODBOBJS=,管它,注释掉第二个以后编译就成功。
用新版本备份,备份成功。

其实后面看了一下这个版本修改的代码:
2326
2326

2327
2327
/* close */
2328
2328
printf(“        …done\n”);
2329

os_file_close(src_file);

2329
if (!node->open) {

2330
os_file_close(src_file);

2331
}
2330
2332
os_file_close(dst_file);
2331
2333
ut_free(buf2);
2332
2334
return(FALSE);
2333
2335
error:
2334

if (src_file != -1)

2336
if (src_file != -1 && !node->open)
2335
2337
os_file_close(src_file);
2336
2338
if (dst_file != -1)
2337
2339
os_file_close(dst_file);
就那么几行,是因为没有判断节点是否还打开,结果导致出错,唉,程序的异常处理确实需要比程序本身的逻辑复杂很多啊。
不过还是没有想明白为什么这台机器就有问题,其他的都没有问题。

may your success.

主备备的两个备机转为双master时出现的诡异slave lag问题

有三台MySQL服务器,a,b和c,复制关系为 a -> b -> c。a,b,c的server_id分别为1,2,3
因为需要切换为 a b <-> c,也就是说,a单独出来,b和c作为双master结构时。
这种切换会经常出现在需要搭建备机把数据备份出来,然后把a独立出来的case中。

昨天,我就做了这样的切换,结果发现出现莫名奇妙的slave lag。
Seconds_Behind_Master一下子为0,一下子变成几千秒。
使用mysqlbinlog查看,binlog日志里面也有很多时间在几小时以前的event数据。
为了验证复制是否正常,我特别测试了一下,在b建一个表,并插入时间数据,到c上一看,表已经复制过来了,时间数据也是正确。
询问了一下同事,他说应该是MySQL的bug,在这种切换的情况下很容易触发这个bug,可以采用stop slave;change master; start slave;的方法来修复。但是实际的数据其实完全没有影响,复制还是正常的。

于是我按照这个办法:
stop slave io_thread;
stop slave;
show slave status\G
(这里先停io_thread是为了SQL thread和IO thread都执行到了同一个位置,change master 的时候没有风险)
stop slave;change master to … ; start slave;
(change master到show slave status的Master_Log_File:和Exec_Master_Log_Pos:位置,也就是说,其实根本没有改变复制的位置)

结果slave lag依然故我。这个问题就比较郁闷了。时间已经过了午夜,脑袋也转不动了,想过不管它了,反正复制没有问题。但是问题没有解决总觉得什么东西卡在喉咙一样。各种资料,各种变量都参考了一遍,最后,基本不太意识的输入:
show master logs;
show binlog events in ‘mysql-bin.000680′ from 34385301;
想看看最新产生的event,结果就发现不对的地方了。
这个最新产生的event有很多,并且server_id是1,1是a的server_id啊,应用访问的是b啊,怎么会在b上面产生a的server_id列,MySQL哪里出问题了?

仔细一想,明白了,事情是这样的:
a -> b -> c,a的event1(server_id为1)复制到b,也会复制到c,这个是正常的。
然后搭建c -> b的复制关系时,b需要断开a的连接,切换主库到c,在 change master 的位置在event1出现之前,那么event1肯定会被重新复制到b去,event1的server_id是1,那么b判断,这个event1不是我提交的,需要在本地执行,并且把它记录到了自己的binlog中;
由于b和c是双master结构,event1又复制到了c,c同样判断它不是我提交的,那么我需要在本地执行,并且记录到本地binlog中。
这样event1就在b和c之间循环往复,时间保持不变,MySQL的slave lag也就一下子是0,一下子是几千秒了。

这里,还需要说明一点,在环型复制里面,event之所以能够在环内只循环一次,而不是重复做,是因为提交的那个节点会发现这个event的server_id是自己的server_id,也就是说是自己提交的。那么,它就不会把这个event再应用一次,自然也不会记录到binlog。这个循环就结束了。除非你闲着没事做,设置了replicate-same-server-id参数。

那么解决问题怎么办列,很简单,把没有应用访问的c的server_id设置成a的server_id:
set global server_id=1;
看看时间差不多了,server_id为1的event都被干掉以后:
set global server_id=3;
然后再设置回来。
还好,MySQL 5.0和5.1的server_id都是动态的。

may your success.

xtrabackup 多实例MySQL备份

花了两个晚上,10来个小时,来测试如何让xtrabackup在多实例的MySQL上成功备份出来,最终找到了一个办法:–defaults-file=”fake/my.cnf.1″,也就是传递一个假的mysql配置文件,让它读取对应的实例数据,备份出来。这样,对每个实例做一个假的mysql配置文件,传给它让它备份出来。

其实我想到的第一个办法就是这个办法。但是作为程序员出身的我,有点追求完美的程序员,始终感觉这种方法太臭了。于是我开始尝试:
1、修改innobackupex-1.5.1的perl文件。
发现innobackupex-1.5.1脚本里面mysqld是写死的,也就是说它就只支持一个实例。好吧,那我就把mysqld全部修改成参数,然后通过参数传递进去(顺便再次温习了一下perl的GetOptions函数,呵呵)。这样总行把?不行。测试的结果报错,说
fatal error: OR no ‘datadir’ option in group ‘mysqld1′ in MySQL options
对应的代码如下:
if (!exists $config{$group}) {
# no group
print STDERR “$prefix fatal error: no ‘$group’ group in MySQL options\n”;
print STDERR “$prefix fatal error: OR no ‘datadir’ option in group ‘$group’ in MySQL options\n”;
exit(1);
}
而检查了以后发现是另外一个问题:
xtrabackup: Error: Please set parameter ‘datadir’
xtrabackup报错了,恩,只好仔细看看文件看看脚本了,发现read_config_file函数里面这么说的:
if ($option_defaults_file) {
$options = $options . ” –defaults-file=\”$option_defaults_file\” “;
}

$options = $options . “–print-param”;

# read file to an array, one line per element
#file_to_array($filename, \@lines);
$cmdline = “$option_ibbackup_binary $options”;
@lines = `$cmdline`;
大家特别注意:”$option_ibbackup_binary $options”,翻译成白话文就是xtrabackup [--defaults-file=#] –print-param,也就是说innobackupex-1.5.1它自己没有处理mysql配置文件的地方,他让xtrabackup去处理,它只管拿现成的。他把这些东西通通放到hash map里面,通过get_option从hash里面获得datadir,innodb_data_home_dir等一系列信息。而xtrabackup解析文件的时候就报错,找不到mysqld组,所以,修改innobackupex-1.5.1是不可行的。

2、如果xtrabackup报错,那么修改xtrabackup的源文件来让它不报错可不可以列?
修改源码的事情比较不靠谱,就算我修改了,并且运行良好,xtrabackup以后的更新和bug修复我就赶不上了。先看看把,也许修改起来简单的。一看,虽然就一个xtrabackup.c文件,但是没有找到比较好下手的地方。罢了罢了,回归到骗人的把戏上吧。

3、骗人的把戏
查看xtrabackup的时候,倒是发现可以在my.cnf上配置xtrabackup的组,把备份的一些参数信息这样传给它。现在就有两个办法,
a、在mysql配置文件中放一个xtrabackup的组,把各个实例的配置信息轮询的更新到组里面,让xtrabackup备份
b、针对每个实例新建一个假的mysql配置文件,让xtrabackup的备份每次读取不同的文件来备份
呵呵,当然是第二个办法好了,于是测试开始,妈的,一直出错,传递的–default-file文件给它,它就是不读,倔强的报错。最后竟然发现是–defaults-file少了一个s,悲剧。好,这个搞定以后就没有什么问题了。建立两个假的mysql配置文件,让它备份把。
[pickup.lichun@alibaba-26841 xtrabackup-1.2]$ xtrabackup –defaults-file=’/tmp/my.cnf’ –print-param
# This MySQL options file was generated by XtraBackup.
[mysqld]
datadir = “/data/mysqldata1/mydata”
tmpdir = “/data/mysqldata1/tmpdir/”
innodb_data_home_dir = “/data/mysqldata1/innodb_ts”
innodb_data_file_path = “ibdata1:256M:autoextend”
innodb_log_group_home_dir = “/data/mysqldata1/innodb_log”
innodb_log_files_in_group = 2
innodb_log_file_size = 536870912

may your success.

admin账户下安装mysql

安装MySQL相信大家都会安装,但是如果现在你只有机器的admin账户,你不能够su到root下去,那么你怎么才能安装好mysql列。
至少我安装起来感觉缚手缚脚的,最终还是安装成功运行起来了,特别把一些需要注意的点记录下来。

1、my.cnf放在哪里?
从reference上抄录如下:
On Unix, Linux and Mac OS X, MySQL programs read startup options from the following files, in the specified order (top items are used first).
File Name     Purpose
/etc/my.cnf     Global options
/etc/mysql/my.cnf     Global options (as of MySQL 5.1.15)
SYSCONFDIR/my.cnf     Global options
$MYSQL_HOME/my.cnf     Server-specific options
defaults-extra-file     The file specified with –defaults-extra-file=path, if any
~/.my.cnf     User-specific options

~ represents the current user’s home directory (the value of $HOME).
前面的那些目录都没有权限,那么就只好在$HOME下放一个.my.cnf

2、目录配置
目录当然需要放在/home/admin下了,我这边的目录在[mysqld]组下设置如下:
basedir=/home/admin/mysql/mysql/
datadir=/home/admin/mysql/mysqldata/mydata
socket=/home/admin/mysql/mysqldata/sock/mysql.sock
pid-file=/home/admin/mysql/mysqldata/sock/mysql.pid
tmpdir=/home/admin/mysql/mysqldata/tmpdir
log-error=/home/admin/mysql/mysqldata/log/error.log
slow_query_log_file=/home/admin/mysql/mysqldata/log/slow-query.log
log-bin=/home/admin/mysql/mysqldata/binlog/mysql-bin
relay-log=/home/admin/mysql/mysqldata/relaylog/mysql-relay-bin
innodb_data_home_dir = /home/admin/mysql/mysqldata/innodb_ts
innodb_log_group_home_dir = /home/admin/mysql/mysqldata/innodb_log
本来basedir没有在这个.my.cnf里面,结果就出错了。
唉,还好 ./support-files/mysql.server 和 mysqld_safe是脚本,用bash -x 调试模式执行的时候仔细看还是能够找到对应的错误

对应的[client]需要指定:
socket = /home/admin/mysql/mysqldata/sock/mysql.sock

3、用户配置:
用户之前是用的mysql账户运行的,现在要用admin运行,所以修改[mysqld]组如下:
user=admin

4、./support-files/mysql.server修改
作为起停MySQL的脚本,它的basedir和datadir我都设置了
basedir=/home/admin/mysql/mysql/
datadir=/home/admin/mysql/mysqldata/mydata/

5、[mysqld_safe]设置
pid-file=/home/admin/mysql/mysqldata/sock/mysql.pid
本来我只设置了pid,并且在一台机器上启动MySQL成功了。但是在第二台机器上启动的时候失败了。
找了半天,才在mysqld_safe脚本里面找到出错的地方:
/home/admin/mysql/mysql//bin/mysqld_safe: line 137: /var/log/mysqld.log: Permission denied
对应的错误日志不对,于是,在.my.cnf的[mysqld_safe]组里加上
log-error=/home/admin/mysql/mysqldata/log/error.log
启动MySQL,没有异常。大功告成!

另外,也要注意把MySQL的bin目录加入到PATH里面去!

其实这里面最需要注意的就是出错的时候:
bash -x ./support-files/mysql.server start
或者
bash -x /home/admin/mysql/mysql//bin/mysqld_safe –datadir=/home/admin/mysql/mysqldata/mydata –pid-file=/home/admin/mysql/mysqldata/sock/mysql.pid &
查看到底是哪里出错了。根据具体的错误来定位和修改。

may your success!

双slave的server_id相同的问题

前段时间新来了一个机器,想要替换一个应用的备机。
已有的架构是这样的:A和B两个MySQL相互作为备机,A的性能比较好,B的性能比较差。
现在买了一台新的机器,新的机器c性能比较好,准备用来替换B。
安装MySQL和配置等等都不细说,比较顺利的。

但是安装好以后,配置复制的时候出现了问题,change master以后可以复制,但是数据库监控一直报错。
show slave status\G显示的Seconds_Behind_Master:的复制延迟一下子是0,一下子是90多w秒。
以前我们也遇到过类似的问题,具体原因不大记得了(唉,就是没有文档记录的错阿),最后好像是通过重做复制修复了。
尝试重新change master以后还是没有好转。查看错误日志显示如下:
100817 19:45:45 [Note] Slave I/O thread: Failed reading log event, reconnecting to retry, log ‘mysql-bin.000033′ at postion 271148235
100817 19:45:45 [Note] Slave: received end packet from server, apparent master shutdown:
100817 19:45:45 [Note] Slave I/O thread: Failed reading log event, reconnecting to retry, log ‘mysql-bin.000033′ at postion 271148235
100817 19:45:45 [Note] Slave: received end packet from server, apparent master shutdown:
并且不断的在刷,每秒钟有十来条记录。
通过对应的binlog file和binlog position去查看主机对应的记录都没有问题。并且主机到备机的复制只是时断时续,并没有一直停着不往前走。
实在没有办法,最后停掉了复制。这个事情因为并不是那么紧急,所以也暂时放在一边了。

偶尔的机会,我在备机B上也发现了同样的错误,也是Slave: received end packet from server, apparent master shutdown的错误。
并且change master以后,出现的频率变的非常高。
看了一下my.cnf配置文件,注意到B和C配置的server_id都是2,因为C当时是计划替换B的所以server_id也配置为一样了。
是不是这个问题引起的列?试试就知道了,把C的server_id配置成3,数据库B和数据库C检查复制状态,好了!

想起数据库复制的那一块代码。数据库连接master,请求复制开始的时候需要几个参数:
1、四个字节的数据文件开始位置
2、两个字节的binlog flag(目前还没有用上)
3、2个字节的binlog file名字字符串长度
4、4个字节的server_id
5、n个字节的binlog file名字字符串(在前面3里记录了它的长度)
这里向主机申请的时候,需要填写自己的server_id,来通知master连上来的是谁。
如果现在有两个slave连上来并都申明自己的server_id为2,MySQL的master就有点无所适从了。
初步怀疑是slave的IO线程连上以后,master过了一段时间(ms级别的)才发现,然后把新的连接断掉,所以slave io线程才会报警:
100817 19:45:45 [Note] Slave I/O thread: Failed reading log event, reconnecting to retry, log ‘mysql-bin.000033′ at postion 271148235
100817 19:45:45 [Note] Slave: received end packet from server, apparent master shutdown:
说收到主机发起的end packet(主机每次发送一个event过来,如果1、收到的包数据有误或者2、不能由接收到的包解出正确的event来,slave io判定复制有问题,
而其中end packet属于第一种情况
对应的代码为sql/slave.cc的read_event函数:
/* Check if eof packet */
if (len < 8 && mysql->net.read_pos[0] == 254)
{
sql_print_information(“Slave: received end packet from server, apparent ”
“master shutdown: %s”,
mysql_error(mysql));
DBUG_RETURN(packet_error);
}

由于MySQL的io有自动重连的机制,所以MySQL的io线程又连主机,并且还连上了。
master过了一段时间(ms级别的)又发现已经有了server_id=2的slave连着的,把它重新断掉了。
看了一下master的代码sql/sql_parse.cc的dispatch_command函数:
mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unregister_slave(thd,1,1);
发送binlog以后,它会做一个unregister_slave,它认为是同一个slave change master连接过来,“理所当然的”它就把前面的连接给干掉了。
周而复始,就产生了这样的错误。
解决的办法很简单,就是不要用同样的server_id的slave同时连一台master。server_id可以设置的很大,所以不要顾虑,赶紧重设吧。

不知道有没有人想过为什么server_id不能设置为0
在my.cnf里面是没有办法设置server_id=0的,不信的话,你试试,正常情况下,它不会让你start slave的。代码如下sql/slave.cc的start_slave_thread函数:
if (!server_id)
{
if (start_cond)
pthread_cond_broadcast(start_cond);
if (start_lock)
pthread_mutex_unlock(start_lock);
sql_print_error(“Server id not set, will not start slave”);
DBUG_RETURN(ER_BAD_SLAVE);
}
不过,我还真的没有测试过这种情况,呵呵。
当然,server_id设置为0的情况也有,但是不是你或者我,而是mysqlbinlog,它的server_id可以设置为0.
原因如下:如果mysqlbinlog的server_id为0的话,它就会把正常的slave给停掉了。万一它的server_id为5,它连上去以后就会把真正的server-id为5的slave断掉了。
server_id设置为0我印象中还有一个不同点,是关于MySQL master发送binlog是否会停止的,但是就是想不起来了,老了。代码也没有找到确凿的证据;先这样把

may your success!

my.cnf的[mysql]组放些什么

my.cnf里面有很多组,[mysqld],[client],[mysql],[mysqldump]等等。
mysql算是我们用的最多的工具,管理,数据订正,查看状态。。。
而每次mysql客户端启动的时候都会读取[mysql]的参数。大家都是怎么设置的列?
先说一下我的:
no-auto-rehash
prompt=”\\u@\\h : \\d \\R:\\m:\\s> ”
#tee=”/tmp/query.log”
#pager=”less -i -n -S”
max_allowed_packet = 4M
show-warnings
default-character-set = UTF8

no-auto-rehash是为了不让MySQL自动提示,这样对MySQL客户端有点慢。
#tee=”/tmp/query.log”是把你输入的SQL等导入到/tmp/query.log文件,如果你不怕这个文件太大可以设置这个参数
#pager=”less -i -n -S”是设置MySQL显示分页数据的工具,如果你安装了maatkit的visual EXPLAIN工具,可以设置为它,正常的情况下它表现和less一样,如果是显示查询计划,它就与众不同了。
max_allowed_packet = 4M就不说了

其他的三个我想特别说一下:
prompt=”\\u@\\h : \\d \\R:\\m:\\s> ” 这个是设置提示符用的,让你随时可以知道你在那个机器,那个库,时间等等,比如这个prompt对应的就是:root@localhost : mysql 10:21:24>。
show-warnings 可以让MySQL执行SQL出现warning的时候,把warning也打印出来,这个在你执行多条语句,但是第一条语句就有warning的时候非常有效。这个参数也可以减轻你的劳动力,每次warning出现的时候,你不用自己手工去输入命令show warnings;
default-character-set = UTF8 其实在client可能我们大部分同志会加这个。但是为什么在这里还要加一个列。mysqlbinlog不认default-character-set这个参数,有时候我们没有办法,只好注释掉default-character-set,如果mysqlbinlog查询binlog之后不记得恢复,那么你下次打开MySQL客户端的时候,你的客户端字符集就有可能没有设置。(这个问题也可以用loose_default-character-set来解决),但是在[mysql]里面加了这个以后,我们就没有这个担心了。这个参数我建议加到其他的客户端组比如[mysqldump]等。

may your success.