Mysql 配置 master/slave

2012年3月12日 没有评论

关于mysql master/slave的应用场景就不做介绍,本文主要讲解是配置。配置相对还是比较简单,只需要在master和slave的mysql的配置文件中增加几行就可以了。

Master上修改:

修改master配置文件,linux默认为/etc/my.cnf,在 mysqld 段中添加如下配置。

server-id = 1
# 唯一ID,master/slave 集群中不能重复,默认master使用 1
log-bin = mysql-bin
# 同步事件的日志记录文件,master/slave通过该文件来达到同步的目的

binlog-do-db = db_name
# 需要同步的数据库名,如果多个库,重复设置binlog-do-db即可
# 如果指定,mysql服务器只会记录指定库的操作日志到mysql-bin中
# 也可以不指定,此时除binlog-ignore-db中指定的库外,其它所有库的操作日志都会记录在mysql-bin中

binlog-ignore-db = db_name1
# 忽略同步的数据库名,如果多个库,重复设置binlog-ignore-db即可
# 可以不指定

另外需要在master上需要创建一个用户,并且赋予其replication slave的权限,例如:

grant replication slave on *.* to slaveuser@192.168.1.3 identified by '123456';

其中slaveuser是用户名,192.168.1.3是slave的ip,可以使用通配符,例如192.168.1.%表示192.168.1.0 – 192.168.1.255这个网段所有slave都可以能通过该用户来访问master,123456是slaveuser对应的密码。

slave上修改:

修改配置文件,在 mysqld 段中增加如下配置:

server-id   = 2
# 唯一ID,不能与master或其他slave重复

master-host	= master ip
master-port = 3306
# master 服务的端口

master-user = slaveuser
master-password = 123456
# master上已授权replication slave的用户和密码

replicate-do-db = tagphi_asm
# 需要同步的数据库名,如果多个库,重复设置replicate-do-db即可
# 如果指定,slave上只会同步更新制定的库,其他库的更新将被忽略
# 可以不指定,此时slave会更新master上mysql-bin日志中记录所有库

上面主要讲了 master/slave 的配置细节,接下来通过实例来说明。

如果对于一个全新的环境,假设master服务器的ip为192.168.1.68,需要同步的库为testDB,

master 配置:

server-id   = 1
log-bin = mysql-bin
binlog-do-db = testDB

创建并授权用户:

grant replication slave on *.* to slaveuser@192.168.1.3 identified by '123456';

slave 配置:

server-id   = 2
master-host=192.168.1.68
master-port=3306
master-user=slaveuser
master-password=123456
replicate-do-db=testDB

配置到此就完成了,分别重启master和slave上的mysql服务器。

在master上使用如下命令:

show master status;

输出结果为:
+------------------+----------+--------------+-------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB              |
+------------------+----------+--------------+-------------------------------+
| mysql-bin.000016 |      892 |   testDB     |                               |
+------------------+----------+--------------+-------------------------------+

在slave上使用如下命令:

show slave status \G

如果输出的Slave_IO_Running和Slave_SQL_Running都为yes说明master,slave正常工作。现在在master创建数据库testDB以及其对应的表,应该在slave上会同步创建testDB库和表,同时如果master上的testDB中的表中数据有变化(插入、更新、删除),slave上对应的表也会做相应的变化。

上面的配置实例是在一开始规划数据库的部署就是用master,slave的情况,但现实中往往可能是先有一台mysql服务器,系统运行一段时间后,才准备使用master、slave的架构,这时我们的数据库中已经有了数据,另外记录log的文件也可能清除过,而且数据库的数据随时都可能变化,这种情况下,配置同上面的几乎一致,但需要额外处理一些其他的事,。这里也假设master服务器的ip为192.168.1.68,需要同步的库为testDB。

master上服务器的配置修改同上,修改配置后重新mysql服务,另外需要把testDB数据库使用mysqldump备份出来,同时使用show master status命令把输出的结果中的File和Position信息记录下来,命令如下:

锁定数据库为只读状态,防止在备份数据库时外部程序对数据修改
flush tables with read lock;

查看master的状态,同时记录File和Position
show master status;
+------------------+----------+--------------+-------------------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB              |
+------------------+----------+--------------+-------------------------------+
| mysql-bin.000012 |      653 |   testDB     |                               |
+------------------+----------+--------------+-------------------------------+

备份数据库
mysqldump -uroot -p123456 testDB > testDB.sql

备份完数据库后解除数据库的锁定
unlock tables;

slave配置也同上,注意此时启动slave的mysql服务时不启动slave服务,可以通过在配置文件中使用

skip-slave-start = true

来实现。启动mysql服务后,先在上面创建数据库testDB,然后将master上备份导入到testDB中,在mysql客户端下执行如下命令:

设定master信息,其中MASTER_LOG_FILE和MASTER_LOG_POS就是上面记录的File和Position的值

CHANGE MASTER TO MASTER_HOST='192.168.1.68',
MASTER_USER='slaveuser',
MASTER_PASSWORD='123456',
MASTER_LOG_FILE='mysql-bin.000012',
MASTER_LOG_POS=653;

启动slave

start slave;

不出意外,master,slave就正常工作了,另外把配置文件skip-slave-start去掉,下次重启slave上的mysql服务就会自动启动slave的。

Mysql 存储过程注释问题

2012年3月9日 没有评论

Mysq支持单行和多行这两种注释代码的方式,单行使用两个减号,多行使用/* */

--  单行注释

/*
   多行注释,第一行
   第二行
   第三行
*/

曾经碰到过在本机window的mysql客户端下可以顺利创建存储过程,拿到linux服务器的客户端中创建的时候老是提示存储过程有错误,错误的原因就是因为单行注释造成,在大部分linux(至少我所接触过的所有linux中)的mysql客户端下单行注释符号和注释的内容之间至少要有一个空格,不能使用tab代替空格。

为了保证存储过程的兼容性,在使用单行注释的时,在注释符号后增加两个空格。

Mysql 存储过程查询结果赋值到变量的方法

2012年3月9日 没有评论

把查询结果赋值到变量,大部分情况下使用游标来完成,但是如果明确知道查询结果只有一行(例如统计记录的数量,某个字段求和等),其实可以使用set或into的方式来实现赋值。示例代码:

drop table if exists test_tbl;
create table test_tbl (name varchar(20), status int(2));
insert into test_tbl values('abc', 1),('edf', 2),('xyz', 3);

drop procedure IF EXISTS pro_test_3;
delimiter //
create procedure pro_test_3()
begin
--  方式 1
	DECLARE cnt INT DEFAULT 0;
	select count(*) into cnt from test_tbl;
	select cnt;

--  方式 2
	set @cnt = (select count(*) from test_tbl);
	select @cnt;

--  方式 3
	select count(*) into @cnt1 from test_tbl;
	select @cnt1;

--  多个列的情况下似乎只能用 into 方式
	select max(status), avg(status) into @max, @avg from test_tbl;
	select @max, @avg;
end
//
delimiter ;

call pro_test_3();

Mysql存储过程参数名和表列明相同引起的问题

2012年3月9日 1 条评论

下面存储过程原本是想根据传入的status值来更新对应列的name,代码如下:

drop table if exists test_tbl;

create table test_tbl (
	name varchar(20),
	status int(2)
);

insert into test_tbl values
('abc', 1),
('edf', 2),
('xyz', 3);

drop procedure IF EXISTS pro_test_1;
delimiter //
create procedure pro_test_1(in status int(2))
begin	
	update test_tbl set name = concat(name, '_new') where test_tbl.status = status;
end
//
delimiter ;

call pro_test_1(1);

select * from test_tbl;

调用上述存储过程后发现所有记录的name都被更新了,存储过程就只有一个update语句,而且执行了,问题出在where条件上,原意是where的第一个status为表的列名,第二个是参数,此处被存储过程都理解为参数,所以where条件永远是true。因此一定要注意列名和参数名相同问题,否则在执行delete或update时会酿成大祸。解决方法有3中,一是修改参数的名字,二是在字段前加上表名,第三种是update使用预处理语句的方式。代码如下:

第二种方法代码:

update test_tbl set name = concat(name, '_new') where status = status;
修改为:
update test_tbl set name = concat(name, '_new') where test_tbl.status = status;

第三种方法代码:

	set @t = status;
	PREPARE STMT FROM "
		update test_tbl  set name = concat(name, '_new') where status = ?
	";
	EXECUTE STMT USING @t;

另外定义游标时候可能也会出现这样的问题,解决方法跟上面类似,注意游标在申明前不能使用set,示例代码:

drop table if exists test_tbl;

create table test_tbl (
	name varchar(20),
	status int(2)
);

insert into test_tbl values
('abc', 1),
('edf', 2),
('xyz', 3);

drop procedure IF EXISTS pro_test_2;
delimiter //
create procedure pro_test_2(in status int(2))
begin	
	DECLARE done INT DEFAULT 0;
	DECLARE na varchar(50) DEFAULT NULL;

	DECLARE cur CURSOR FOR 
		select name from test_tbl where test_tbl.status = status;
--  或
--  	select name from test_tbl t where t.status = status;
--  再或, 注意后面需要为 @s 赋值
--  	select name from test_tbl where test_tbl.status = @s;

	DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

--  set @s = status;

	open cur;
	REPEAT
		FETCH cur INTO na;
		if not done then
			select na;				
		end if;
 	UNTIL done END REPEAT;
	CLOSE cur;	
end
//
delimiter ;

call pro_test_2(1);

mysql 存储过程中使用多游标

2012年3月2日 没有评论

mysql的存储过程可以很方便使用游标来实现一些功能,存储过程的写法大致如下:

先创建一张表,插入一些测试数据:

DROP TABLE IF EXISTS netingcn_proc_test;

CREATE TABLE `netingcn_proc_test` (
  `id` INTEGER(11) NOT NULL AUTO_INCREMENT,
  `name` VARCHAR(20),
  `password` VARCHAR(20),
  PRIMARY KEY (`id`)
)ENGINE=InnoDB;

insert into netingcn_proc_test(name, password) values
('procedure1', 'pass1'),
('procedure2', 'pass2'),
('procedure3', 'pass3'),
('procedure4', 'pass4');

下面就是一个简单存储过程的例子:

drop procedure IF EXISTS test_proc;
delimiter //
create procedure test_proc()
begin
	-- 声明一个标志done, 用来判断游标是否遍历完成
	DECLARE done INT DEFAULT 0;

	-- 声明一个变量,用来存放从游标中提取的数据
	-- 特别注意这里的名字不能与由游标中使用的列明相同,否则得到的数据都是NULL
	DECLARE tname varchar(50) DEFAULT NULL;
	DECLARE tpass varchar(50) DEFAULT NULL;

	-- 声明游标对应的 SQL 语句
	DECLARE cur CURSOR FOR
		select name, password from netingcn_proc_test;

	-- 在游标循环到最后会将 done 设置为 1
	DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

	-- 执行查询
	open cur;
	-- 遍历游标每一行
	REPEAT
		-- 把一行的信息存放在对应的变量中
		FETCH cur INTO tname, tpass;
		if not done then
			-- 这里就可以使用 tname, tpass 对应的信息了
			select tname, tpass;
		end if;
 	UNTIL done END REPEAT;
	CLOSE cur;
end
//
delimiter ;

-- 执行存储过程
call test_proc();

需要注意的是变量的声明、游标的声明和HANDLER声明的顺序不能搞错,必须是先声明变量,再申明游标,最后声明HANDLER。上述存储过程的例子中只使用了一个游标,那么如果要使用两个或者更多游标怎么办,其实很简单,可以这么说,一个怎么用两个就是怎么用的。例子如下: 阅读全文…

mysqldump 每条记录都用insert

2012年2月28日 没有评论

默认情况下,使用mysqldump备份出来的表记录都是在一条insert语句,这样对于导入来说效率要高些,但是遇到记录很多的大表,可能会超过缓存区的大小,从而导致备份失败,可以使用参数实现一条记录一个insert语句,例如:

mysqldump -uroot -p --skip-opt dbname > bak.sql

Mongodb 备份与恢复

2012年2月23日 没有评论

可以使用Mongodb自带的mongodump和mongorestore工具来实现数据库的备份和恢复。其用法比较简单,可以使用如下命令来获取帮助信息:

mongodump --help

mongorestore --help

备份使用命令mongodump,如果执行该命令不带任何参数,会把本机上运行的在默认端口的mongodb中的除local数据库外的所有数据库备份下来,存放在当前执行命令的目录下的dump(如果不存在该目录会自动创建)目录中,并按照数据库的名字存放在不同的不同的目录下,例如有个数据库名为test,那么其备份的文件存放的位置为./dump/test目录下。大部分情况下,我们可能不会这么干,那么可以通过-d来指定需要备份的数据,-o来指定备份存放的位置,同时可以使用-h来指定需要备份的主机地址。例如:

mongodump -h 127.0.0.1:27017 -d atagdata -o /data/dump
或
mongodump -h 127.0.0.1 --port 27017 -d atagdata -o /data/dump
备份本机上的atagdata数据库中的所有collections到/data/dump目录中
每个collections都是以一个文件独立存在,存放路径为/data/dump/atagdata/collections_name.bson

mongodump -h 192.168.1.211 --port 27017 -d atagdata -o /data/dump
备份远程数据库到本地

mongodump -h 127.0.0.1:27017 -d atagdata -c log_01 -o /data/dump
备份atagdata数据库中collections名为log_01的数据

注意:备份不能一次指定多个数据库,也不能一次指定多个collections,也就是说,要么一次备份下来所有数据库,要么一次只备份一个指定的库,同理,在指定了数据库的情况下,要么全部备份该库下的所有collections,要么只备份指定的一个collections,所以要想只备份几个指定的库或collections时,可以多次执行备份命令,修改其数据库名或collections名即可。另外如果数据库需要认证,可以使用-u和-p来指定用户名和密码。

上述用mongodump备份下来的文件,可以通过mongorestore来进行恢复。可以mongodb实例没有启动的情况下执行恢复操作,这个时候必须使用dbpath来指定存放恢复数据的目录,另外可以使用directoryperdb来指定数据库的数据文件是否按文件夹来区分;当然在mongodb已经启动情况下,也是可以执行恢复操作的,这时候dbpath参数不是必须的,如果指定dbpath,那么dbpath不能指定为当前mongodb实例相同的dppath,反之mongorestore会根据当前运行的实例获取dbpath、directoryperdb信息,把备份数据恢复当前的mongodb的dbpath中。例如:

mongorestore /data/dump/
把/data/dump/下所有数据库恢复到当前mongodb中,数据库名字跟备份时名字相同

mongorestore -d test /data/dump/test
恢复test数据库到当前mongodb中test数据库

mongorestore -d new_test /data/dump/test
恢复test数据库到当前mongodb中,并且数据库的名字为new_test

mongorestore -d test --drop /data/dump/test
使用drop参数,在恢复前会删除已有的collections

mongorestore --dbpath /data/db_1 --directoryperdb --drop /data/dump/
把/data/dump/下所有数据库恢复到/data/db_1目录中,数据库名字跟备份时名字相同

MongoDB Replica Set 配置

2012年2月21日 没有评论

Replica Set 节点类型分为三种:

  • standard:常规节点,它存储一份完整的数据副本,参与选举投票,有可能成为primary节点;
  • passive:存储了完整的数据副本,参与投票,不能成为primary节点;
  • arbiter:仲裁节点,只参与投票,不接收复制的数据,也不能成为primary节点。

本文配置使用2个常规节点和一个arbiter节点,arbiter节点由于不同步数据,所以负载会很小,部署对硬件没有太大的要求。

假设192.168.1.211、192.168.1.212为常规节点,192.168.1.68为arbiter节点。三个节点上的mongodb都是用下面的配置文件,文件存放在/etc/mongodb.cnf:

dbpath = /data/db/
logpath = /data/log/m.log
logappend = true
port = 27017
fork = true
directoryperdb = true
journal = true
replSet = test
rest = true

其中replSet 的 Id 为 test,这个值对应initiate中的”_id”,使用rest参数后可以在web管理界面中显示Replica Set中其他mongodb实例的信息。

使用命令

/usr/local/mongodb/bin/mongod --config /etc/mongodb.cnf

分别启动三个机器上的mongodb实例,使用mongodb客户端登陆两个常规节点中的任何一个,执行如下命令:

rs.initiate(
	{"_id" : "test",
	 "members" : [
		{"_id" : 1, "host" : "192.168.1.211"},
		{"_id" : 2, "host" : "192.168.1.212"},
		{"_id" : 3, "host" : "192.168.1.68", "arbiterOnly" : true}
	]
});

或

rs.initiate(
	{"_id" : "test",
	 "members" : [
		{"_id" : 1, "host" : "192.168.1.211"},
		{"_id" : 2, "host" : "192.168.1.212"}
	]
});

rs.addArb('192.168.1.68');

可以使用rs.conf()查看配置情况,rs.status()查看各个节点的状态,经过一小段时间后,他们会选一台作为PRIMARY,其他的常规节点为SECONDARY,同时在js shell中看到提示符从“>”变为对应的 “PRIMARY>” 或 “SECONDARY>” 或 “ARBITER>”。可以在PRIMARY是通过rs.stepDown()来切换PRIMARY,执行此命令后会在剩余的常规节点选一个来充当PRIMARY。

关于初始化中配置members的其他可选参数,可以到官网上查看,地址:http://www.mongodb.org/display/DOCS/Replica+Set+Configuration

MongoDB的启动和停止脚本

2012年2月20日 1 条评论

Mongodb脚本:把命令行的内容保存到一个文件中,把该文件放在/usr/bin(或任何系统设置的PATH路径中)下,就可以直接用该文件来启动或停止服务了。

本人比较倾向把启动mongodb的参数放在配置文件中,直观且便于管理,例如把参数写入/etc目录下的mongodb.cnf文件中,参数设置如下:

#configuration Options for MongoDB
#
# For More Information, Consider:
# - Configuration Parameters: http://www.mongodb.org/display/DOCS/Command+Line+Parameters
# - File Based Configuration: http://www.mongodb.org/display/DOCS/File+Based+Configuration
dbpath = /data/db/
logpath = /data/log/m.log
logappend = true

#bind_ip = 127.0.0.1
port = 27017
fork = true
#auth = true
noauth = true
directoryperdb = true
journal = true

可以使用命令:

/usr/local/mongodb/bin/mongod --config /etc/mongodb.cnf

来启动mongodb,所以启动脚本就可以这么写

#!/bin/sh

/usr/local/mongodb/bin/mongod --config /etc/mongodb.cnf

假设该文件命名为mongodb-start,存放于/usr/bin下,现在就可以直接用mongodb-start来启动服务了,注意,该文件要有执行的权限。

停止mongodb服务脚步如下:

#!/bin/bash

pid=`ps -o pid,command ax | grep mongod | awk '!/awk/ && !/grep/ {print $1}'`;
if [ "${pid}" != "" ]; then
    kill -2 ${pid};
fi

其实就是通过ps、grep、awk命令找到mongod的进程号,在通过kill来关闭mongod服务,当然查询进程号的命令还有很多,任取一种即可,例如:

ps -C mongod -f | grep mongod |tr -s ' ' | cut -d ' ' -f 2
或
ps aux | grep mongod | grep -v "grep" | awk -F" "  '{print $2}'

linux下MongoDB开机自启动的问题

2012年2月17日 没有评论

按照常理,把如下命令

/usr/local/mongodb/bin/mongod --dbpath=/data/db/ --fork --logpath=/data/log/m.log --directoryperdb

放在/etc/rc.local文件中就可以实现开机自启动了,第一次重启机器发现mongodb顺利启动了,再次重启机器后,通过ps没有查看到相应mongod进程,也就是启动失败了。原因是由于重启机器,导致非正常停止mongod服务,mongod.lock中还记录了上次运行的进程号,为了数据的安全需要执行 /usr/local/mongodb/bin/mongod –repair,当然如果直接把mongod.lock文件删除也可以重新启动了,例如:

/usr/local/mongodb/bin/mongod --repair
/usr/local/mongodb/bin/mongod --dbpath=/data/db/ --fork --logpath=/data/log/m.log --directoryperdb

或
rm -rf /data/db/mongod.lock
/usr/local/mongodb/bin/mongod --dbpath=/data/db/ --fork --logpath=/data/log/m.log --directoryperdb

注意上述启动Mongodb都是没有增加journal参数,如果带了此参数就不会那么麻烦了,例如

/usr/local/mongodb/bin/mongod --dbpath=/data/db/ --fork --logpath=/data/log/m.log --directoryperdb --journal

就可以了,就算是非正常重启机器,mongodb也会根据日志去修复数据库的。

另外,如果mongodb的数据目录是通过mount的NFS文件夹,自启动好像有问题的。

分类: Linux, MongoDB 标签:

无觅相关文章插件,快速提升流量