注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

网易杭研后台技术中心的博客

 
 
 
 
 

日志

 
 

mysql 行级binlog复制 的 attribute promotion 分析  

来自杜皮   2013-06-21 13:07:16|  分类: 默认分类 |举报 |字号 订阅

  下载LOFTER 我的照片书  |

基本概念:

mysql在做主备复制时,如果主备库的表定义不同, 也就意味着要做异构复制。 attribute promotion 就是当定义Binlog_Format = Row ,并且列属性不同时,slave端在apply binlog时做的结构转换。

按照官方文档来说,在mysql-5.1.21版本开始支持不同表定义之间的复制,主备上列的数目可以不同,属性也可以不同。列数目不同,意味着master的列数目要小于等于slave的列数目,两者的列顺序要一致,slave额外的列需要有defaults值.

主要来看列属性的不同的情况:

在5.1版本中:

row binlog 只支持类似于char(10) 到 char(25) 这样的复制,不允许不同int之间的转换,也不支持char类型的和大对象转换,只有在binlog中使用相同类型表示的列属性间可以转换。并且只支持master端列宽小于slave端的转换方式,而反之会导致truncate的转换是不被支持的。其次所有的前缀唯一索引,必须保证主备的前缀长度一致(否则会导致唯一性错误)

5.1支持的转换类型 (来自官方文档)

From (Master)To (Slave)
BINARYCHAR
BLOBTEXT
CHARBINARY
DECIMALNUMERIC
NUMERICDECIMAL
TEXTBLOB
VARBINARYVARCHAR
VARCHARVARBINARY


5.1 不支持的转换类型:


5.5.3版本开始,mysql按照之前mysql cluster的做法,引入了row binlog 的异构复制

row binlog 开始支持更多种类的列属性转换:

引入新参数 slave_type_conversion ,可以设置4个值 ALL_LOSSY(数据被truncate), ALL_NON_LOSSY(不需要被truncate的转换), ALL_LOSSY,ALL_NON_LOSSY(可以兼容以上两种转换),  EMPTY(不支持属性转换)


5.5 支持的转换类型(来自官方文档)


  • Between any of the integer types TINYINTSMALLINTMEDIUMINTINT, and BIGINT.

  • Between any of the decimal types DECIMALFLOATDOUBLE, and NUMERIC.

  • Between any of the string types CHARVARCHAR, and TEXT, including conversions between different widths.(不同字符集列之间不支持复制, 会出现主备不一致的状态)

  • Between any of the binary data types BINARYVARBINARY, and BLOB, including conversions between different widths.

  • Between any 2 BIT columns of any 2 sizes.


分析行级binlog attribute promotion的源代码


以下以mysql-5.5.22为例,主要的入口函数为 sql/log_event.cc 中的 Rows_log_event::do_apply_event(Relay_log_info const *rli),在打开表并加完锁之后需要检查是否需要转换。


TABLE *conv_table;

        if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),

                                             ptr->table, &conv_table))

        {

            ...

        }

        ptr->m_conv_table= conv_table;


mysql 遍历所有binlog涉及的表,检测主库binlog传过来的表信息是否和当前slave端的表定义相吻合。如果需要进行列属性转换,则为attribute promote 建立一张内存的临时表来完成,否则传出的conv_table为NULL


compatible_with() 方法流程

          1. 检测主备库的最小列数

          2. 针对这些列进行是否能转换的检测can_convert_field_to()

               a.  判断field->real_type 是否相等

               b.  如果real type 相等:

                    i.   判断metadata是否为0,metadata的size取决于field的real type(例如固定大小的int 类型metaData就为0,而char,varchar类型都有)

                    ii.  如果metadata为0,直接返回成功,否则的话要比较主备两列的field size 调用is_conversion_ok()

                                  (i) 根据slave_type_conversion 参数来判断是否能进行转换

                           

               c.  如果real type 不相等,又没有设置slave_type_conversion(也就是采用默认值EMPTY),返回上层错误

               d.  判断不同用类型之间能否转换(int之间,char到text等等) 先比较列的长度 compare_length()

                    i.    调用 max_display_length() 方法获得列的最大长度

                    再判断列类型能否转 is_conversion_ok()


          3. 如果检测出结果需要转换,并且临时表为NULL,则建立一张临时转换表create_conversion_table()

          4. 如果检测到列类型不能转换,向上层抛错

          5. 设置临时转换表中的属性类型



在设置完临时表convert table之后,真正使用是在unpack_current_row 中调用 rpl_record.cc 中的unpack_row


unpack_row () 方法流程:

          1. 根据本地表起始指针和结束指针,依次获取每个属性

                a. 判断对应的convert_table 是否是NULL, 如果不是NULL则采用convert_table的列,否则采用原本slave 表本身的列, 暂时称这列为f

                b. 检测f列的bitmap,并设置null_bits 和 null_mask, 如果有必要的话,设置default值

                c. 调用Field::unpack 方法,解析master传过来的binlog数据内容, 拷贝到f列

                d. 如果是该列是转换列那么source 和target 各自根据系统字符集开辟一块buffer, 此处是做真正的列类型转换, convert列和master一致,这里采用一个临时的Copy_field做转换,Copy_field是mysql专门用作列转换的辅助类,通过不同的source和target列类型,设置转换函数指针,将convert table中的数据拷贝到最终的slave对应的列中

                        i.         copy.set(*field_ptr, f, TRUE);     设置转换类的各个参数,包括转换函数

                        ii.        (*copy.do_copy)(&copy);  做拷贝操作

                    

          2. 将master data 中复制用不到的那些列丢弃

          3. 设置master side 的记录长度


自此attribute promotion 的主要流程完成。

  评论这张
 
阅读(726)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017