September 2012

[MySQL源码] Facebook MySQL Rev3814 通过动态可调的FSEG_FILLFACTOR减少空闲Page

背景: –每个索引有两个segment,用于管理叶子节点和非叶子节点 –每个segment包含多个extend,extend是一次文件扩展单元(64个Page) –每个Page默认非压缩表为16K 相关Tips: SPACE HEADER :表空间的第一个Page中,用于管理所有下述结构, FILE SEGMENT INODE用于描述SEGMENT信息 每个EXTEND都对应一个EXTEND DESCRIPTOR,描述信息单独记录在一个Page中,占用40个字节,一个Page可以存放256个描述符,因此每隔(256*64)个Page会有一个单独的EXTEND DESCRIPTOR PAGE SEGMENT INODE 用于管理其对应的SEGMENT信息,其中记录了该SEGMENT拥有的EXTEND的相关信息(以及该SEGMENT内的碎片Page信息) ,一个Page内可以存储的SEGMENT INODE个数为FSP_SEG_INODES_PER_PAGE(zip_size)。SEGMENT INODE的位置信息可以由BTREE的根节点中的SEGMENT HEADER得到。 问题: 每个SEGMENT通过一个宏FSEG_FILLFACTOR来决定什么时候进行段扩展,默认为8,也就是说,当一个SEGMENT中保留的Page数少于1/8时,就要对其进行扩展一个EXTEND,也就是64个Page。这个值是硬编码的,Facebook将其修改成可动态调整的值,根据其测试,可以减少不少空闲Page(达到10%) 上述逻辑的判断是在函数fseg_alloc_free_page_low中实现,当然比描述的更加复杂(一堆if else :-(..) 把Patch backport到了5.5.18,并跑了下test case,两个相同结构的表,load相同的数据。 innodb_segment_reserve_factor = 8   ibd文件大小为20971520 innodb_segment_reserve_factor = 500, ibd文件大小为23068672 大约减小了9% 有兴趣的同学可以从mysqlatfacebook在lauchpad上的Rev3814 来获得diff 更主要的是从学习该patch的过程中,顺便了解了一下fsp相关知识。   关于Innodb表空间,有两篇不错的文章,介绍的比较详细: http://blog.chinaunix.net/uid-26586115-id-3052168.html http://blog.chinaunix.net/uid-26586115-id-3061127.html 原创文章,转载请注明: 转载自Simple Life 本文链接地址: [MySQL源码] Facebook MySQL Rev3814 通过动态可调的FSEG_FILLFACTOR减少空闲Page Post Footer automatically generated by wp-posturl plugin for wordpress.

[MySQL源码] Facebook对压缩表的改进

由于公司最近很多地方需要开始有使用压缩表的需求,但根据测试结果,压缩表对OLTP的性能相当不理想,在最近的一次测试中,UPDATE的性能最大可以下降到1/12,几乎不可接受。   Facebook从2011年开始对压缩表进行改进,花了两个星期从facebook的博客、facebook成员在官方list上提交的bug以及Mark在lauchpad上提交的patch着手调研,以下内容基本涵盖了Facebook对压缩表的改进,以及对应的Rev 接下来,需要做的就是研究这些Patch,如何为我所用。   注:除了以下内容,在查看facebook的bzr log时,还发现很多比较小的优化点(例如对innodb层线程调度的改进),但未公布出来,有兴趣的可以看看。   1.提供更多的信息来监控/诊断压缩表性能 MySQL本身(包括Percona版本)提供的压缩表内部信息非常少,很难通过这些信息来进行优化,Facebook增加了大量的信息用以显示。 从mysql@facebook的代码来看,为table_statistics增加了大量的统计数据,包括IO、索引、压缩表相关信息,我们关注如下几个跟压缩表相关的信息: COMPRESSED_PAGE_SIZE COMPRESS_PADDING PADDING_SAVINGS COMPRESS_OPS  COMPRESS_OPS_OK COMPRESS_PRIMARY_OPS COMPRESS_PRIMARY_OPS_OK  COMPRESS_USECS COMPRESS_OK_USECS COMPRESS_PRIMARY_USECS  COMPRESS_PRIMARY_OK_USECS UNCOMPRESS_OPS UNCOMPRESS_USECS 另外在update_global_table_stats函数中,facebook做了一些优化,通过原子操作代替锁操作,避免长期持有全局锁 LOCK_global_table_stats 相关:r3668, r3670,r3678 扩展innodb_cmp表的信息 r3679 更多的global status信息 r3672,r3671   2.从redo log中移除压缩Page,并为压缩表增加了一种新的日志记录 –r3641   3.增加adpative padding功能,减少每个page上的数据来降低压缩失败率 类似于在page上填写空白,当压缩失败率升高到某个层次时,加大pad值。当失败率维持在很低的水平时,则减小pad值。 动态padding实现 r3754, r3759, r3764, r3768 线性算法计算自适应padding值 r3820 4.减少分配的空白页,以降低文件的大小 相关bug: bug#64673 r3814   5.减少压缩Page的malloc/free次数 避免每次page 压缩/解压时频繁malloc/free 内存 r3808   6.更高效的压缩page checksum 对压缩page使用快速checksum r3824 related bug#49852 通过只在需要的时候计算压缩page/非压缩page的checksum来降低cpu占用 r3816 , r3817 related bug#64170   7.移除对adler32的调用 r3818   8.允许设置zlib的压缩级别 增加了新的参数innodb_compression_level来控制zlib的压缩级别 r3766   9. fix  bug#61341 r3675   10.其他 增加innochecksum工具对压缩表的支持 r3813 Fix bug#64258 可动态调整WAIT_FOR_READ r3792 跟压缩表相关,未具说明的bugfix r3779, r3780 (maybe […]

[MySQL调试] 集成breakpad到MySQL内核

基本参考twitter的实现,代码很简单,直接调用的breakpad的接口,关键是修改cmake文件比较蛋疼。 twitter的实现:https://github.com/twitter/mysql/commit/f95c5a49b4703779d05c200a9b282284248b7cb9 需要作部分修改,这里记录下我的操作步骤 1.下载google-breakpad,如果是在r1001之前的版本直接编译安装即可(未尝试),如果是checkout的最新版本,需要把源代码内的my_strchr全部替换掉,俺直接替换成bp_my_strchr,这个会和mysql的定义冲突。 2.配置环境变量BREAKPAD_ROOT,不然breakpad是不会编译到MySQL中的: $echo $BREAKPAD_ROOT /u01/project/breakpad 3.configure && make && make install 4. backport twitter的patch 有点小不一样,在MySQL5.5.20之前的版本,调用函数my_write_minidump是在mysqld.cc的handle_segfault中,而在之后的版本中,为了解决bug#54082,这部分代码独立在单独文件sql/signal_handler.cc文件中,因此需要在函数handle_fatal_signal中调用my_write_minidump cmake加上 -DENABLED_EMBEDDED_SERVER:BOOL=ON 5.用前几天report的一个bug尝试了一把,可以看到所有线程的堆栈/寄存器信息都被保存了下来,文件大小才629k。 通过minidump_stackwalk解析出来的部分内容如下: Thread 34 (crashed) 0 mysqld!google_breakpad::ExceptionHandler::WriteMinidump [exception_handler.cc : 534 + 0xd] rbx = 0x0000000000000000 r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000080 r15 = 0x00007f0834008f10 rip = 0x0000000000991d3c rsp = 0x00007f0891da4240 rbp = […]

[MySQL 调试] 初试breakpad

breakpad是google开源的一个崩溃报告工具,按照其声称,生成的core file相当小,近日开始调研将其集成到我们线上MySQL的可行性,以下是初步的安装尝试 1. checkout 代码 svn co http://google-breakpad.googlecode.com/svn/trunk  breakpad 2. configure && make && make install 3.暴力cp src/client/linux/libbreakpad_client.a 4.测试程序 #include “client/linux/handler/exception_handler.h” #include <cstdio> static bool dumpCallback(const google_breakpad::MinidumpDescriptor &md, void* context, bool succeeded) { printf(“Dump path: %s\n”, md.path()); return succeeded; } void crash() { volatile int* a = (int*)(NULL); *a = 1; } int main() { google_breakpad::MinidumpDescriptor […]

[MySQL学习] MySQL压缩表

以下是在阅读官方文档时的笔记 官方文档: http://dev.mysql.com/doc/refman/5.6/en/innodb-compression.html#innodb-compression-tuning //////////////////////////////////////////////////////////////////////// 关于压缩表,可以调整的参数看起来只有key_block_size,在建表时指定,意味着innodb会将page压缩到指定的大小,例如,如果设置Key_block_size=8,则将其压缩到8k。Key_block_size的值应根据记录的长度来确定,如果设置的过小,可能由于一个page无法压缩太多行而出现高概率的压缩失败,导致不得不split page.但设置为16k则不会取得太好的压缩效果,当然这种情况依然对存在长blob/varchar/text类型的列有好处,这可以避免过多的”overflow” page 在buffer pool中,压缩数据也以小page的形式存在,为了获取或更新数据,在innodb中也为解压数据创建了16kb的page,任何对解压page的修改,也会写入到压缩Page中。当空间不够时,解压page会被驱逐出bp。 注意实际的压缩算法并不受key_block_size的影响。 Key_block_size的默认值为8K。 在表上建立索引时create index指定row_format和key_block_size没有效果,这取决于建表时的设定。 总的来说,压缩表更加适用于合理长度的字符串,并且其数据读比写更多。何时使用压缩表并无定论,这取决于你的负载和数据集合,或者特定的配置。可以考虑如下因素: A.由于压缩本身通过识别数据块中的重复字符串来进行压缩,完全随机的数据可能会得到很差的效果。典型的数据通常有很多重复,因此能获得更好的压缩效果。字符串(char,  varchar, text 或者 blob)可以获得更好的效果。 可以从一个非压缩表中拷贝数据到一个相同的压缩表中,观察数据大小,来决定是否适合压缩。在INNODB_CMP中,通过观察COMPRESS_OPS_OK/COMPRESS_OPS来获得压缩成功率。如果该比率较高,则表明适合作为压缩表。 B.已经在应用中压缩过的数据,不适合存储到压缩表中。 C.通过like或order by来测试压缩后的索引性能 D.在应用中进行压缩(使用MySQL提供的COMPRESS/UNCOMPRESS函数进行压缩/解压) E.在表上的workload是一个关键性因素,如果更新主要作用在外部存储的长字符串的非索引列上,压缩的开销可能是可以接受的。如果你的负载是I/O bound而非CPU bound的,压缩可能会改善整体性能。 F.配置特性;压缩可以通过消耗CPU来减少IO,如果IO是相对紧缺的资源时,会获得更好的效果。 G.选择压缩Page的大小应该比记录更大,否则可能会引起大量的压缩失败。通常情况下key_block_size=8是比较安全的设置。 H.运行时监控压缩 a.CPU和IO利用率,数据文件大小等 b.通过innodb_cmp/innodb_cmp_reset表进行监控,如果COMPRESS_OPS_OK/COMPRESS_OPS的比率较高,说明系统工作的很好,如果很低,则表明innodb可能有太多的重新组织,重新压缩或B-TREE节点分裂。这种情况下避免压缩这些表,或调大key_block_size的值。 ###压缩表内部实现tips### Innodb使用的是zlib中的lz77算法 B-TREE Node中的某些系统信息并未压缩,这有利于in-place update,例如标记删除以及无需解压的删除操作。 为了避免DML产生的过多的解压/压缩,在每个B-TREE Page中,维持了一段非压缩的“modification log”,来记录Page上的更改。 当“modification log”过大时,innodb会解压Page,执行更新,然后重新压缩Page。如果重新压缩失败,就需要分裂B树节点。 通常情况下Innodb要求每个Page至少容纳2条记录,对于压缩表,这个限制被放松了,叶子节点可以只容纳一条记录,但是 but that record must fit in uncompressed form, in the per-page modification log(暂时没搞明白,待分析) 为了减少IO和解压Page的次数,在buffer pool中可能会维护Page的压缩和解压两类,当空间不够时,innodb可能将解压的page驱逐掉,保留压缩的page在bp中。如果一个page在一段时间内没有被使用,压缩格式的page也会被写会到磁盘中,以释放空间。 Innodb使用一个adaptive LRU算法来维持内存内压缩和非压缩Page的平衡,目的是为了避免在CPU繁忙时减少解压Page的开销,当CPU富余时避免过多的I/O。当系统是I/O BOUND时,倾向于选择驱逐Page的非压缩拷贝,以留下空间给其他读入磁盘的Page。当是CPU BOUND时,innodb选择驱逐压缩和非压缩这两种Page,这样内存可以更多的留给“hot page”,并减少内存中需要解压的Page。       原创文章,转载请注明: 转载自Simple Life 本文链接地址: [MySQL学习] MySQL压缩表 Post Footer automatically generated by wp-posturl plugin for wordpress.

[MySQL源码] 一条简单insert语句的调用栈

以下仅用于本人调试MySQL所用,不具备可读性。 ———————————————————– CREATE TABLE t1 (a INT PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; insert into t1 values (4,2); ha_innobase::write_row  |–>row_insert_for_mysql       |–>转换记录格式row_mysql_convert_row_to_innobase      |–>保存检查点savept = trx_savept_take(trx);      |–>row_ins_step         |–>加IX锁lock_table(0, node->table, LOCK_IX, thr)         |–> row_ins     //轮询索引,向表中插入记录,这里只有聚集索引         .   […]