Chinaunix首页 | 论坛 | 博客
  • 博客访问: 738793
  • 博文数量: 38
  • 博客积分: 587
  • 博客等级: 中士
  • 技术积分: 579
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-17 14:32
文章存档

2013年(15)

2012年(23)

分类: Mysql/postgreSQL

2013-04-16 10:12:35

 
【问题背景】
     1、数据库从库复制中断, SQL Thread的Error如下:
      Last_SQL_Error: Error 'Table '.orders' doesn't exist' on query. Default database: ''. Query: 'LOAD DATA INFILE '/tmp/SQL_LOAD-2-3-1.data' IGNORE INTO  TABLE `tb_name` 
     FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (id, 省略...
 
2、开发人员在主库执行了以下命令
   mysql -uxxxx -hxxxxx -Pxxxx -p -e"load data local infile '/tmp/SQL_LOAD-2-3-1.data' into table db_name.tb_name";

3、从库的/tmp目录下,近8G的数据文件堆积,用户为mysql.mysql, 且注意1中的Error信息里SQL_LOAD-2-3-1.data文件就在/tmp下,请见下图:


注意: 和负责的DBA确认后, 早上7过执行过4次 SQL_SLAVE_SKIP_COUNTER , 到公司后又执行过一次,操作完全正常
4、主,从库db_name.tb_name的表ibd文件大小相差很大: 主库为21G, 从库为12G,很明显上面的导数据操作,在从库都没有执行成功。
【问题分析】
   1、从库复制中断原因: 从错误信息及SQL命令很显可见, 是在从库执行load data file时, Default database为'', 所以找不到tb_name表(原因主库做了复制过滤,所以每次操作都必须以default database为准)。
       这个直接把开发人员的SQL修改为以下两种都可(标色部分为修改):
                mysql -uxxxx -hxxx  -Pxxx-p  -D  db_name  -e"load data local infile '/tmp/SQL_LOAD-2-3-1.data' into table tb_name";
                 mysql -uxxxx -hxxx  -Pxxx -p -e"use db_name load data local infile '/tmp/SQL_LOAD-2-3-1.data' into table tb_name";

  2、为何主库导入数据文件,会堆积到从库的/tmp目录中呢:
     2.1 MySQL的load data [local] infile 操作,主库的导入文件(如此例中的/tmp/SQL_LOAD-2-3-1.data), 会被完整地复制到从库的 slave_load_tmpdir系统参数指定的目录下;
         而从库在执行完load data infile后,此文件会被删除, 但如果失败了,文件就会堆积。 可以看到几个文件,用户都mysql, 因为由MySQL的进程创建的。
                

   2.2  根据以上, 7点左右出现过4个文件,负责的DBA 执行SQL_SLAVE_SKIP_COUNTER了4次, 近9点时又有一个文件;所以skip counter跳过的是一个事务(即 Binlog event group), 理解这个很重要。

    总结:开发人员私自导入数据,还是比较不靠谱。


【Load Data INFILE的浅析】
 这里简单说明load data infile的本地及远程导入的注意事项。

1、导入的数据文件在数据库服务器上:
     1.1 此操作必须同时,具备3条件: 1) 执行SQL的MySQL用户必须具有FILE权限, 2)启动mysqld进程用户(一般是mysql.mysql用户), 有这个数据文件的读取权限。3)当然导入表的insert权限必须有。

     1.2 执行的SQL命令为:LOAD DATA INFILE "数据文件" INTO TABLE 表名;   此命令可以在MySQL服务器运行, 也可能通过其他进行,使用mysql远程连接MySQL进行操作(这个得理解)
    
     1.3 示例: 数据文件/tmp/data.dat 存放在A机上;远程机器B连接A的MySQL执行load data操作。

     示例1: 当mysql用户不具有FILE权限, Error: Access denied for user (using password: YES)
        
      示例2:  mysql用户有FILE权限,但mysql进程,不能访问数据文件:/tmp/data.dat,  错误提示信息:ERROR 29 (HY000): File '/tmp/data.dat' not found (Errcode: 13)
      
  
       
  1.4 总结: 如果数据文件存在mysql机器上,所以使用load data file, 可从本机, 或其他机器执行。
2、导入的数据文件存放在客户器本地:开发人员的导入操作就是这类。
    2.1  此操作必须条件:1)数据库服务器的local_infile参数必须的ON(默认的) 2)必须有导入的insert权限, 但没有必要有FILE权限,3)所谓mysql client程序(如mysql命令)的local_infile也是ON的,这个没有要求。
    2.2  操作SQL:  LOAD DATA  LOCAL INFILE "数据文件" INTO TABLE 表名;  注意这里多个local, 这样就会从本地读取数据文件。
  2.3  示例: 数据文件/tmp/localdata.dat存在本地12.50机器上; 连接12.33数据库。 验证:可以不要FILE权限, local_infile必须打开。
  
   示例1:mysql用户无FILE权限, local_infile设置为ON, 验证能正常导入:
    

   示例2: mysql用户无FILE权限, local_infile设置为OFF, 验证不能导入,错误信息:ERROR 1148 (42000): The used command is not allowed with this MySQL version
        


关于load data infile的复制binlog event之前做过总结,没搞太明白,就放在这里吧:
2、关load data infile "" into table的操作的事件。
 在Master上执行 load data infile "/work/t_load.dat" into table t_load;  文件t_load.dat大小为29字节;事件显示如下:


当load进来的文件比较大时,大于read_buffer_size的长度时,就会分拆出现Append_block 事件。注意block_len的长度由启动时的:read_buffer_size,动态修改read_buffer_size对,block_size无影响。
| localhost-bin.000007 |     106 | Query              |         5 |         174 | BEGIN                                                                                                                                                                      |
| localhost-bin.000007 |     174 | Begin_load_query   |         5 |      131269 | ;file_id=2;block_len=131072                                                                                                                                                |
| localhost-bin.000007 |  131269 | Append_block       |         5 |      262364 | ;file_id=2;block_len=131072                                                                                                                                                |
| localhost-bin.000007 |  262364 | Append_block       |         5 |      393459 | ;file_id=2;block_len=131072  
-----------------------------------省略--------------------------------------------------------------
| localhost-bin.000007 | 2622074 | Append_block       |         5 |     2686248 | ;file_id=2;block_len=64151                                                                                                                                                 |
| localhost-bin.000007 | 2686248 | Execute_load_query |         5 |     2686471 | use `test`; LOAD DATA INFILE '/tmp/t_load.dat' INTO TABLE `t_load` FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (id, name) ;file_id=2 |
| localhost-bin.000007 | 2686471 | Xid                |         5 |     2686498 | COMMIT /* xid=92 */ 
 
相关事件说明:
2.1、 Query类型事件:
   Query Event是最广泛的一种类型,尤其是binlog_format为statement的场景下, 如事务的Begin, DDL, SBR下的语句操作。
   由于load data是一个组的操作,多次事件来完成一次操作,称为BEGIN的Query类型事件;与Xid Event类型的COMMIT(事务提交)事件相对应。

2.2、Begin_load_query:  Create File事件(告诉Slave以给定的ID创建一个文件,目的是复制 load data infile)和 Append_block事件,两个事件的组合。
  表示load data开始传输数据的事件,事件中提供了唯一的文件ID:file_id.  此file_id会分配给后面的Execute_load_query事件的执行语句。
此事件表示读取新文件开始,其后面会跟着0个或多个Append_block 事件。
2.3、Append_block事件:  告诉Slave将一个块附加到文件 ID有关的LOAD DATA INFILE.
文件从Begin_load_query事件开始传输数据,如果导入文件字节数据大于read_buffer_size(或max_allowed_packet), 剩余部分就由Append_block事件来完成传输。
2.4、Execute_load_query事件:这事件是Query事件的变种,包含load data infile语句, 只是文件名用file-id替换了。

3、 Xid事件: 事件组的COMMIT动作。
 记录要提交的事务ID,并作为两阶提交协议中的提交标记。

手册参考:
--slave-load-tmpdir=file_name
The name of the directory where the slave creates temporary files. This option is by default equal to the value of the tmpdir
system variable. When the slave SQL thread replicates a LOAD DATA INFILE statement, it extracts the file to be loaded
from the relay log into temporary files, and then loads these into the table. If the file loaded on the master is huge, the temporary
files on the slave are huge, too. Therefore, it might be advisable to use this option to tell the slave to put temporary files in a
directory located in some file system that has a lot of available space. In that case, the relay logs are huge as well, so you might
also want to use the --relay-log option to place the relay logs in that file system.

   





    
 
阅读(3249) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~