一点关于MySQL参数delay_key_write、myisam_recover_options的使用经验

        最近在做数据库实例迁移的时候遇到了几个比较诡异的问题:
  1. MyISAM实例正常shutdown后rsync数据文件到另外一台机器上起实例后,访问表时提示表自动修复失败需要repair table。提示信息:Table './test/record_03' is marked as crashed and last (automatic?) repair failed
  2. 表损坏后,利用repair table命令将表修复时提示表里存在很多的duplicate key.
     warning  : Duplicate key for record at 129584986 against record at 62008769
     warning  : Duplicate key for record at 104678355 against record at 61426294
     warning  : Duplicate key for record at 297493788 against record at 61697778
     warning  : Duplicate key for record at 209950328 against record at 61548867
     warning  : Duplicate key for record at 105894968 against record at 61866949
...
...
补充一下当时的环境信息:
1.MySQL版本为官方版的5.5.12,表引擎是MyISAM
2.迁移的步骤:stop slave->flush tables->正常shutdown实例->rsync表文件->在新机器上起实例。rsync前后表文件MD5值一样。

3.表的结构类似这样:

create table test (
id int auto_increment primary key,
a varchar(100) not null,
b int not null,
c int,
unique key (a,b)
)



        首先说第一个问题,这里分两点:1.为什么会需要修复?2.为什么自动修复失败?
  1. 我是正常关闭实例,不明白表需要修复的原因于是请淘宝丁奇帮忙分析了数据文件,显示文件头里记录显示表被关闭仍有6个线程在访问。但我可以确定当时rsync数据文件前是正常shutdown实例的,这个可能是MyISAM本身的问题或者是本身数据文件就已经存在问题都不得而知,总而言之当我迁移过来后访问表时需要修复这点是合理的,因为表被关闭时还有线程在访问,这会被MySQL认为表非正常关闭,需要修复。
  2. 为什么会自动修复失败,这是由于我配置了参数myisam_recover_options=default,这个配置表示每次访问MyISAM表之前都会先检测表是否需要修复,如果需要则自动进行,这也就是前面看到信息last (automatic?) repair failed。而修复失败是因为这个参数带来的修复行为默认是从key cache里面找需要修复的数据,而我当时是shutdown实例,rsync到新环境中起实例,此时已没有当时的现场(key cache环境),加上default不会强制进行修复(强制修复表如果索引文件和数据文件数据不一致则自动进行删除或者增加行),(如果是myisam_recover_options=force,那么即使此时key cache不存在了也会进行强制修复,此时做的就是对比数据文件和索引文件,然后删除数据文件中多余的行,因此这样可能会丢数据)。在自动修复时可以再error log中看到如下信息:
130410  9:31:23 [ERROR] /usr/local/mysql55/bin/mysqld: Table './image_0/record_00' is marked as crashed and should be repaired
130410  9:31:23 [Warning] Checking table:   './image_0/record_00'
130410  9:31:24 [ERROR] Got an error from unknown thread, /export/home/pb2/build/sb_0-3198286-1302530066.93/mysql-5.5.12/storage/myisam/ha_myisam.cc:868
130410  9:31:24 [Warning] Recovering table: './image_0/record_00'
130410  9:31:28 [Note] Retrying repair of: './image_0/record_00' with keycache
130410  9:31:37 [ERROR] Couldn't repair table: image_0.record_00


接着说第二个问题,在第一个问题中提示表损坏,需要手工repair table,而我执行了这条命令后提示表里存在很多重复键数据:
warning  : Duplicate key for record at 129584986 against record at 62008769
warning  : Duplicate key for record at 104678355 against record at 61426294
warning  : Duplicate key for record at 297493788 against record at 61697778
warning  : Duplicate key for record at 209950328 against record at 61548867
warning  : Duplicate key for record at 105894968 against record at 61866949
这个重复键指的是唯一键(a,b),然后进行了一个小测试验证是数据文件里面有重复的行(在a,b字段上)。逻辑图大概是这样
id a b c
1  1 2 3
2  1 2 4
3  2 3 55
4  2 3 54


        上面这个列表是我自己模拟的,在(a,b)上有唯一键约束,但是在数据文件中却存在(a,b)重复的行。验证方法较简单:
/*强制走全表扫描*/select * from test where a=val1 and b=val2;
结果集有2行
/*强制走索引*/select * from test where a=val1 and b=val2;

结果集只有1行


        当时遇到问题第一反应是开发人员那边是不是曾经导过数据且导数据的时候禁止了唯一约束检查,但是事实上开发说自己没这么干过,于是开发说这是MySQL的bug,我怎么也觉得MySQL不会存在这样大的bug,一直觉得是对MySQL使用方法不对。于是对迁移前后的环境做了对比检查终于发现了疑点:老的环境中配置了delay_key_write=ALL,myisam_recover_options=OFF(默认是OFF)。而我的新环境中则是delay_key_write=ON,myisam_recover_options=default 。

简单解释下delay_key_write,每次更新MyISAM表索引后不立即将更新flush到物理磁盘上,这些修改依然保留在内存中,直到这个表被关闭时再flush,ALL表示对所有的表都使用这一行为,ON表示对创建表时使用了delay_key_write的表使用这个功能。OFF表示不进行delay key write。而官方建议在使用delay_key_write时同时用myisam_recover_options这样才能保证数据一致性,否则,举个最简单的例子,索引数据一致都没flush到磁盘上,突然表被非正常关闭,等下次表被访问如果不进行相应的检测修复,那么就会出现数据文件与索引不一致的情况,这样就会导致数据不一致。

再简单解释下myisam_recover_options,default表示每次访问表时会先判断是否需要修复,但是不会强制修复(仅仅尝试从key cache中修复),backup表示修复时会先将老的数据文件先做个备份,force表示强制修复,具体用法见下图。











        此时就大致可以确定是由于MySQL参数使用不合理导致的数据不一致问题,所以在使用MyISAM时如果配置了delay_key_write,就千万记得同时配置一个myisam_recover_options这样才可能防止数据不一致性的情况出现。那么我是怎么解决这个问题的呢?目前来说还是通过迁移后的MySQL配置参数环境保持与老环境一致,否则如果我现在强制加上参数myisam_recover_options,那么就会导致所有的表损坏,损坏之后恢复的唯一途径就是repair table,这会丢失数据(或者配置myisam_recover_options=force,backup,这个效果是跟repair table一样,且同时对将要修改的MYD文件做一个备份),因为对于重复键的行,如果是利用repair table去做的话,我无法干预MySQL留下其中具体的哪行,所以如果强行repair table虽然可以解决重复键错误,但是最终留下的哪行不一定是用户想要的那行数据。当然还有另外两种可行的方法,第一,咨询业务负责人后手工删除重复键中不需要的行。第二,强制repair table 然后将老的数据留一份做备份,然后用户端发现异常了再进行数据恢复,不过这个做法不可取,否则都会被用户投诉致死。


        总之,都21世纪了,都5.6了,不要再用MyISAM了吧,我这是历史系统,没办法,后期进行升级改造也是必须进行的。

阅读更多
换一批

关于review的一点经验

05-26

我是个懒人兼笨人,但是不小心答应了别人要发贴子,所以只好献丑了。rnrnreview,根据一些软件工程书籍上的讲述,以及我自己的亲身体验,是项目开发中极为重要的一环,对于保证项目的质量,提高项目的可维护性,乃至加快开发速度,都有着极为显著的效果。rnrn所谓的review,简而言之,就是在项目开发的过程中,对于每一个阶段的工作,在完成之后,在尽可能大的范围内,对该阶段生成的产品进行校验。rnrn在尽可能大的范围内,指的是在项目组范围内,有尽可能多的人参与。我说校验不说检查或审查,是因为review的目的,只是修正错误,而并不是判定产品的质量,并不是决定产品是否合乎要求。rnrn结合实际来说,在项目开发中,如果按照软件工程的要求,一般可以分为7个阶段:需求分析,概要设计,详细设计,code,单元测试,功能测试(系统联调),和系统测试。这7个阶段,每个阶段都应该进行review。rnrn具体的做法是,在一个阶段的产品初步完成之后,召集尽可能多的同项目组成员,大家一起检查这个产品。一般可以由产品的作者为大家讲解自己的产品,大家来进行提问和质疑。rnrn那么,在提问和质疑的时候,依据什么呢?依据上一个阶段的产品。也就是说,review概要设计的设计书的时候,大家应该拿着需求分析,看看概要设计是否真的满足了需求分析中所提到的,所需要实现的功能,在实现的时候,所采用的方法是否很好,是否能满足系统的需求。而review详细设计的时候,就依据概要设计来进行。以此类推。rnrn需要注意的是,此时每个阶段的输入和输出,最好都是单一的,即每个阶段只依据上一个阶段所产生的的产品,而阶段结束的时候,所生成的,也应该是一份单独的产品。(此处我没有包含XP等特殊的开发模式。review在XP中的运用稍有不同)rnrn不管在哪个阶段,review的基本形式都是一样的,那就是由产品的负责人向大家讲述自己的产品,大家来进行质询。rnrnreview都应该有谁参加呢?一般来说,尽可能的大范围。项目经理,还有项目的主要技术负责人,一定要参加。其他的人员,可以灵活掌握。rnrnreview之后,应当由被review产品的负责者,根据review中所提出的意见,对产品进行修改。rnrn下面具体讨论每个阶段的review。rnrn需求分析阶段。需求分析阶段review的目的,是让项目组中所有的成员能够尽快的达成共识,让大家拥有一个共同的信念,对未来的最终软件产品有一个比较一致的想象。当需求分析的负责人向项目的成员讲述自己的设计的时候,就是,也应当是尽可能的向大家传达关于需求的信息的时候,也是领导者向开发者们表达自己的想法和理念的时候。开发者越能够理解领导者的理念,越能和领导者达成一致,也就越能出色的完成领导者的理念。而且,,通过开发者来检验一下领导者想法的正确性,也是需求分析阶段review的目的。rnrn概要设计和详细设计阶段。这两个阶段review没有什么特殊之处,总的来说,就是集思广益,找到最优设计以及把错误扼杀在萌芽状态。rnrncode阶段的review,就是拿着代码看了,一般我见过的经典场景就是一手详细设计,一手代码,在看。code review可以采用多次,小量进行的方式,就是每完成若干代码,就可以review一次,不然都攒在一起的话,数量比较庞大,review的效率会比较低。rnrn单元测试阶段。这个阶段的如果不先写测试用例的话,一般没有什么可review。单元测试的程序一般是没有必要review的。rnrn功能测试/系统测试阶段。理论上,功能测试的测试用例应当根据概要设计产生,系统测试的测试用例应当根据需求分析产生,这两个阶段的review,主要就是检查测试用例产生的是否合理。rnrnreview有几大好处。第一,项目经理和技术负责人全程参与review,可以很好的掌控和了解项目的进行状况;第二,review是最快的,将项目组的所有成员水平提高到大致相同档次的方法;第三,技术负责人可以很好的掌握项目的质量,可以监督整个项目的走向。rnrnreview的问题就是它要花费代价,要消耗相当的时间。在我的经验中,review一天,两天,都是很常见的。rnrn光听我说也许对review的必要性还会存有怀疑,这就需要亲身的试验。我相信你尝试之后,就会和我一样,在项目开发中离不开review了。rnrn(我的桌子太高了,弄的我的手腕很痛,写到后面自己也不知所云了,各位多多包涵。以后再补充吧)rn

没有更多推荐了,返回首页