使用RPM&YUM进行基础软件管理
2011年05月25日 1 Comment
上周花时间研究了下RPM打包的方法,今天和团队分享了一次。之前我们采用shell脚本进行批量的MySQL安装,虽然通过不断改进的脚本,批量安装部署的效率已经算不错。但即使是安装MySQL这样简单的事情,不断提升效率,在大规模的环境中也是会带来更多的收益。
追求简单,做到极致,共勉之。
NinGoo's blog
2011年05月25日 1 Comment
上周花时间研究了下RPM打包的方法,今天和团队分享了一次。之前我们采用shell脚本进行批量的MySQL安装,虽然通过不断改进的脚本,批量安装部署的效率已经算不错。但即使是安装MySQL这样简单的事情,不断提升效率,在大规模的环境中也是会带来更多的收益。
追求简单,做到极致,共勉之。
2011年03月24日 6 Comments
InnoDB是支持MVCC多版本一致性读的,因此和其他实现了MVCC的系统如Oracle,PostgreSQL一样,读不会阻塞写,写也不会阻塞读。虽然同样是MVCC,各家的实现是不太一样的。Oracle通过在block头部的事务列表,和记录中的锁标志位,加上回滚段,个人认为实现上是最优雅的方式。 而PostgreSQL则更是将多个版本的数据都放在表中,而没有单独的回滚段,导致的一个结果是回滚非常快,却付出了查询性能降低的代价。
InnoDB的实现更像Oracle,同样是将数据的旧版本存放在单独的回滚段中,但是也有不同。之前还以为整体实现都会跟Oracle不会有太大的出入,也一直没有太在意去看具体实现。今晚晚上下班准备回家时,刚好路过几个同事在交流分享这个问题,遇到一个疑问:
我们知道,InnoDB表会有三个隐藏字段,6字节的DB_ROW_ID,6字节的DB_TX_ID,7字节的DB_ROLL_PTR(指向对应回滚段的地址),这个可以通过innodb monitor看到,当然如果你熟悉innodb文件结构,也可以直接od ibd文件来验证。一致性读主要跟后两者有关系。InnoDB内部维护了一个递增的tx id counter,其当前值可以通过show engine innodb status获得
echo "show engine innodb status\G" | mysql -uroot | grep "Trx id counter"
假设有一个表,当前已经有两条记录。这时候我们开始一个实验,开启两个session,A和B,都设置autocommit=0
MySQL>set global autocommit=0;
T1时间:
A开始一个事务,执行一条select,可以看到已有的两条记录,show engine innodb status可以知道A的tx id,假设为7430
T2时间:
B开始一个事务,执行一条select,可以看到已有的两条记录,可以知道B的tx id,为7431
T3时间:
A中insert一条记录,此时A再select能看到,所以返回三条记录,而B无法看到,还是返回两条记录。
T4时间:
A中执行commit提交事务,分别在A和B中select,得到的结果和T3时间相同。
Ok,假设一致性读是根据事务先后,也就是tx id来比较的话,如果B事务的一致性读是通过B的tx id即7431来和A事务中insert的这条记录的tx id即7430来比较的话,由于A.tx_id < B.tx_id,那么B应该能都到A的记录(tx id是递增的,所以越小说明事务越早开始),但如果能读到,则显然不符合多版本一致性。
因此结果是正确的,那么就是InnoDB的一致性读的实现方式不是像我们按照经验来测试的那样了。通过google和察看代码,原来InnoDB还真是有一个感觉上很山寨的设计,由于tx id是事务一开始就分配的,事务中的变化也没有记录一个类似于Oracle的SCN的逻辑时钟,于是由了如下的实现:
InnoDB每个事务在开始的时候,会将当前系统中的活跃事务列表(trx_sys->trx_list)创建一个副本(read view),然后一致性读去比较记录的tx id的时候,并不是根据当前事务的tx id,而是根据read view最早一个事务的tx id(read view->up_limit_id)来做比较的,这样就能确保在事务B之前没有提交的所有事务的变更,B事务都是看不到的。当然,这里还有个小问题要处理一下,就是当前事务自身的变更还是需要看到的。
有兴趣的可以去仔细看看代码的实现,在storage/innobase/read/read0read.c中实现了创建read view的函数read_view_open_now,在storage/innobase/include/read0read.ic中实现了判断一致性读是否可见的read_view_sees_trx_id。以下代码摘自5.5.8:
UNIV_INTERN
read_view_t*
read_view_open_now(
/*===============*/
trx_id_t cr_trx_id, /*!< in: trx_id of creating
transaction, or 0 used in purge */
mem_heap_t* heap) /*!< in: memory heap from which
allocated */
{
read_view_t* view;
trx_t* trx;
ulint n;
ut_ad(mutex_own(&kernel_mutex));
view = read_view_create_low(UT_LIST_GET_LEN(trx_sys->trx_list), heap);
view->creator_trx_id = cr_trx_id;
view->type = VIEW_NORMAL;
view->undo_no = 0;
/* No future transactions should be visible in the view */
view->low_limit_no = trx_sys->max_trx_id;
view->low_limit_id = view->low_limit_no;
n = 0;
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
/* No active transaction should be visible, except cr_trx */
while (trx) {
if (trx->id != cr_trx_id
&& (trx->conc_state == TRX_ACTIVE
|| trx->conc_state == TRX_PREPARED)) {
read_view_set_nth_trx_id(view, n, trx->id);
n++;
/* NOTE that a transaction whose trx number is <
trx_sys->max_trx_id can still be active, if it is
in the middle of its commit! Note that when a
transaction starts, we initialize trx->no to
IB_ULONGLONG_MAX. */
if (view->low_limit_no > trx->no) {
view->low_limit_no = trx->no;
}
}
trx = UT_LIST_GET_NEXT(trx_list, trx);
}
view->n_trx_ids = n;
if (n > 0) {
/* The last active transaction has the smallest id: */
view->up_limit_id = read_view_get_nth_trx_id(view, n - 1);
} else {
view->up_limit_id = view->low_limit_id;
}
UT_LIST_ADD_FIRST(view_list, trx_sys->view_list, view);
return(view);
}
UNIV_INLINE
ibool
read_view_sees_trx_id(
/*==================*/
const read_view_t* view, /*!< in: read view */
trx_id_t trx_id) /*!< in: trx id */
{
ulint n_ids;
ulint i;
if (trx_id < view->up_limit_id) {
return(TRUE);
}
if (trx_id >= view->low_limit_id) {
return(FALSE);
}
/* We go through the trx ids in the array smallest first: this order
may save CPU time, because if there was a very long running
transaction in the trx id array, its trx id is looked at first, and
the first two comparisons may well decide the visibility of trx_id. */
n_ids = view->n_trx_ids;
for (i = 0; i < n_ids; i++) {
trx_id_t view_trx_id
= read_view_get_nth_trx_id(view, n_ids - i - 1);
if (trx_id <= view_trx_id) {
return(trx_id != view_trx_id);
}
}
return(TRUE);
}
参考:
http://dev.mysql.com/doc/refman/5.1/en/innodb-multi-versioning.html
http://wangyuanzju.blog.163.com/blog/static/130292009107101544125/
http://bbs.chinaunix.net/thread-1773206-1-1.html
2010年12月16日 5 Comments
在这几天的OOW上没怎么听到MySQL的消息,session少而且很多讲师是sales,忽悠成份居多。倒是今天一大早在Google Reader上看到MySQL5.5.8 GA版本发布了,真是期待了很久的消息。当然,官方网站上宣传的在windows性能提升540%,在Linux上性能提升370%,未必有那么靠谱,尤其是已经使用了innodb plugin的,那这么高的性能提升就更是浮云了。
但是,MySQL5.5还是有很多值得期待的特性,其中比较吸引人的,像semi-replication,replication heartbeat,以及partition的可用性提升等。MySQL5.5.8已经将Innodb Plugin1.1.4版本做为内建的Innodb引擎。
MySQL5.5.8源代码编译工具在Linux平台放弃了autotool,而是采用了跨平台的cmake。因此从源代码编译的过程有些不一样。如果系统中没有cmake,还需要先安装:
sudo apt-get install cmake
tar zxvf mysql-5.5.8.tar.gz cd mysql-5.5.8 CFLAGS="-O3 -g" CXX=gcc CXXFLAGS="-O3 -g -felide-constructors -fno-exceptions -fno-rtti" export CFLAGS CXX CXXFLAGS cmake -DCMAKE_INSTALL_PREFIX=/opt/mysql -DSYSCONFDIR=/opt/mysql make -j 2 make install
关于MySQL5.5.8更多cmake选项,请参考文档。
2010年11月01日 3 Comments
我不是HR,只是一个普通的技术人员,下面也不是标准的JD,只是我想到的一些要点,如果你能满足其中大部分要求,如果你对运维几百台上千台MySQL数据库有兴趣,如果你对研究MySQL源码有野心,如果你对PostgreSQL有研究,如果你对NoSQL有好奇,请给我简历 jiangfeng#taobao.com 或者 seaman.ning#gmail.com (请将其中的#替换成@),电话初面,合则约见。工作地点可以是杭州或者北京。
如需要进一步了解相关信息,欢迎在twitter或者新浪微博私信给我。
MySQL开发工程师(开发或者修改MySQL相关patch):
1. 对Linux很熟悉,如果有内核hack经验更佳
2. 对c/c++很熟悉,至少写过几千行Linux下的c/c++代码
3. 熟悉gdb调试工具,能debug程序问题
4. 熟悉关系数据库基本原理,了解MySQL/PostgreSQL数据库
5. 熟悉多线程和网络编程
6. 痴迷技术,热爱折腾
MySQL DBA
1. 对Linux很熟悉,会编译内核,了解ext3/xfs/ext4等文件系统
2. 了解c/c++或者java,有过实际编码经验尤佳
3. 熟悉MySQL或者PostgreSQL,有100台以上规模数据库运维经验更佳
4. 熟悉shell/perl/python等脚本语言中的一种,善于利用脚本解决重复问题
5. 痴迷技术,热爱折腾
近期评论