2012年4月5日星期四

SAS & SATA

经常听到硬盘有SAS/SATA/SCSI...之分(当然还不包括SSD/FUSION IO)那么他们到底有什么关系和区别呢?
从网上找了一篇文章,记录一下:

一、SASSATA本质区别 
  1SAS SATA发展由来
SATASerial ATA,串行ATA由并行ATA(PATA)发展而来
     SAS  Serial Attached SCSI ,是新一代的SCSI技术;

  2SASSATA都是采用串行技术以获得更高的传输速度,
      SAS直接支持3.0Gbps(300MB/s),后继发展可支持12.0Gbps,即1.2GB/s 
  3SAS适配器
    其实就类似于SCSI控制芯片,因为现在的主板上基本都没有集成支持SAS的控制芯片,所以需要使用额外的扩展卡,    就类似于SCSI控制卡这种概念。目前提供这种控制卡的主要是业界著名的LSI LogicAdaptec。(LSI 9260-8i
4SAS的接口技术可以向下兼容SATA
  SAS的接口技术可以向下兼容SATASATASAS的一个子集,SATA系统不兼容SAS,所以SAS驱动器不能连接到SATA接口上。
二者的兼容性主要体现在物理层和协议层的兼容。
在物理层,SAS接口和SATA接口完全兼容,SATA硬盘可以直接使用在SAS的环境中,从接口标准上而言,SATASAS的一个子标准,因此SAS控制器可以直接操控SATA硬盘,但是SAS却不能直接使用在SATA的环境中,因为SATA控制器并不能对SAS硬盘进行控制;
在协议层,SAS3种类型协议组成,根据连接的不同设备使用相应的协议进行数据传输。其中串行SCSI协议(SSP)用于传输SCSI命令;SCSI管理协议(SMP)用于对连接设备的维护和管理;SATA通道协议(STP)用于数据的传输。


SATA 控制器
SAS 控制器
SATA HDD
SAS  HDD
×

5SAS实现了全双工,点对点的传输。SAS所采用SCSI协议是全双工的,通过将一路数据所需的流控信息与反向传送的数据混合在一起,从而在同样的数据线上实现全双工。
 SASSATA应用领域的差异及联系
SATA硬盘应用于桌面PC机及个人计算机客户端;
SAS硬盘适合小型负载的应用,例如在1,000人以下的电子邮件系统,或者规模不大的ERPCRM系统,很多国内中小企业就相当适合。而像是大型的ERPCRM系统,或是在线实时交易系统等,因为传输量大,反应速度需要实时快速,所以还是应当采用更高端的光纤信道硬盘。
SAS目前的不足:
1                  硬盘、控制芯片种类少  只有希捷、迈拓以及富士通硬盘厂商推出了SAS接口硬盘,品种太少,其他厂商处在产品内部测试阶段。此外周边的SAS控制器芯片或者一些SAS转接卡的种类更是不多,多数集中在LSI以及Adaptec公司手中。
2                硬盘价格太贵  如果用户想要做个简单的RAID级别,那么不仅需要购买多块SAS硬盘,还要购买昂贵的RAID卡,价格基本上和硬盘相当。
3                 用户追求成熟、稳定的产品  SAS硬盘更多的被应用在高端4路服务器上, 他们需要的应该是成熟、稳定的硬件产品,虽然SAS接口服务器和SCSI接口产品在速度、稳定性上差不多,但目前的技术和产品都还不够成熟。
随着SAS的相关产品技术会逐步成熟,价格也会逐步滑落,早晚都会成为服务器硬盘的主流接口。

所以明白了SAS和SATA的关系,那么ATA与SCSI直接的关系也就能大概知道了,因为SATA是在ATA上的加强,而SAS则是在SCSI上的加强。

附:名词解释
HBA : 主机汇流排适配器(Hose Bus Adapter
IC :  集成电路  (integrated circuit )
SAS: 串行连接 (Serial Attached SCSI)
SCSI : 小型计算机系统界面 (small computer system interface)
SATA: 串行高级技术附件(Serial Advanced Technology Attachment
RAID: 指冗余磁盘阵列技术 Redundant Array of Independent Disks

2012年4月4日星期三

对innodb MVCC实现的一点点思考

不得不说MVCC思想对关系数据库的影响很大,读不阻塞写,写也不会阻塞读,大大提高了并发性。当前主流的数据库基本上都实现了MVCC,比如Oracle、MySQL、PostgreSQL等等。现在来谈谈MySQL(innodb)是怎么实现MVCC的,它的优缺点是什么。

innodb对MVCC的实现是通过在每个事物开启时创建一个当前系统活跃事务的副本(read_view),然后每次读取行的时候,通过这个行上的trx_id与read_view里面的trx_id进行比较。说到行上的trx_id,那么首先得说明一下innodb在每行上有三个隐藏字段:DB_ROW_ID、DB_TX_ID(这个就是行上的事务id)、DB_ROLL_PTR(指向当前行的回滚段指针)。具体的源码如下:

/*********************************************************************//**
Checks if a read view sees the specified transaction.
@return TRUE if sees */
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);
}

在我参考的一片文章[1]里面,作者说每次与行上的trx_id比较的时候
并不是根据当前事务的tx id,而是根据read view最早一个事务的tx id(read view->up_limit_id)来做比较的,我觉得作者只说对了一部分,这个read_view->up_limit_id确实是一个参考的参数(up_limit_id是当前事务的read_view里面trx_id最小的,这就好比我们求素数的时候,首先直接将n%2==0的剔除,这里的与read_view->up_limit_id比较也是一样的效果,实际上再源码里面也有说明),而在for循环里面我们可以看到,从read_view里面找到一个view_trx_id >= trx_id(行当前的事务id),至于为什么trx_id!=view_trx_id,这是因为两者相等的话,那就是同一个事务id,与自己比较没有意义。那么最后return(TRUE)呢?这是因为如果事务开启的时候没有活动的事务,那么read_view也就为空(本质上是view_n_trx_ids=0)这种情况自然事务可以读当前行。

那么innodb这样设计有什么缺点吗?依据我自己的见解,这样中设计比较浪费内存,因为如果在极端的情况下,有些事务耗时比较长,系统事务比较多的情况下,那么每一个新的事务开启的时候,都会导致read_view(当前活动事务副本)需要被创建一份,而且创建read_view的开销肯定也不小。Oracle的设计就不同,貌似它是在每个block(或者行)上有一个事务槽,所以每次去判断是直接读当前行还是读undo段时就利用当前事务的id与槽里面的事务id进行比较,这样应该来得比较innodb这种设计高效吧。




参考文章:


2012年4月3日星期二

sed在指定行插入新的一行

前些天备份使用mysqldump备份出的数据文件(insert形式),里面的内容没有use db_name这个语句,所以如果在脚本中执行,那么会提示no database selected,所以就想在里面添加一个use db_name的语句。但是因为数据文件太大,如果直接vim打开恐怕不行。所以想到sed,然后上网找了一下sed在指定行插入的命令,然而需要注意的是,这些命令虽然可以直接定位到行,但最终如果要文件内容被更新掉还是要花费一定的时间的,但是这样会比直接vim打开文件然后插入一行效率更高。
下面贴出具体的命令:
1.在指定行前插入一行
sed '2 ittt' -i a.txt # 在第2行前插入ttt,并且将结果更新到a.txt(如果不想将插入真正更新到文件,去掉后面的-i选项就可以)

2.在指定行后插入一行
sed '2 attt' -i a.txt #在第2行后插入ttt,并且将结果更新到a.txt(如果不想更新原文件,去掉-i)

3.在指定的多行前面插入
sed 'n,m ittt' -i a.txt #看得懂了吧

4.在指定的多行后面插入
sed 'n,m attt' -i a.txt #看得懂了吧


sed提供了功能太强大了,以后还需要好好学习它,好记性不如烂笔头哈~~

2012年4月1日星期日

mysql 5.1中DDL语句对Transaction的影响


这个问题是从mysqlperformance上发现的,挺有意思,分享一下。DDL语句对transaction的影响。下面贴出自己的实验过程:
mysql-5.5

session1:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test;
+----+------+
| id | name |
+----+------+
|  1 | xxx  |
|  2 | xxx  |
|  3 | xxx  |
|  4 | xxx  |
+----+------+
4 rows in set (0.00 sec)

session2:
mysql> alter table test add column pas varchar(20) ;
(下面的结果是session1 commit之后的,session1没有commit,session2一直被阻塞)
Query OK, 4 rows affected (18.55 sec)
Records: 4  Duplicates: 0  Warnings: 0
---------------------------------------------------------------------------------
下面来测试mysql5.1
mysql5.1


session1:
root@localhost test 10:17:18 >start transaction;
Query OK, 0 rows affected (0.00 sec)

root@localhost test 10:17:38 >select * from test;
+----+------+
| id | name |
+----+------+
|  1 | xx   |
|  2 | xx   |
|  3 | xx   |
|  4 | xx   |
+----+------+
4 rows in set (0.00 sec)

session2:
root@localhost test 10:17:29 >alter table test add column pas varchar(20);
(session2并没有被阻塞,结果瞬间出来)
Query OK, 4 rows affected (0.12 sec)
Records: 4  Duplicates: 0  Warnings: 0

此时在session1里面再次执行命令:
session1:
root@localhost test 10:17:52 >select * from test;
Empty set (0.00 sec)
可以看出,此时得到的结果集为空

注意上面的测试是在隔离级别为 REPEATABLE-READ ,将隔离级别设置为READ-COMMITTED,再次进行测试
mysql5.1

session1:
root@localhost test 10:49:46 >set tx_isolation = 'read-committed';
Query OK, 0 rows affected (0.00 sec)
root@localhost test 10:50:13 >start transaction;
Query OK, 0 rows affected (0.00 sec)

root@localhost test 10:50:19 >select * from test;
+----+------+------+
| id | name | pas  |
+----+------+------+
|  1 | xx   | NULL |
|  2 | xx   | NULL |
|  3 | xx   | NULL |
|  4 | xx   | NULL |
+----+------+------+
4 rows in set (0.00 sec)

session2:
root@localhost test 10:44:07 >alter table test drop column pas;
Query OK, 4 rows affected (0.08 sec)
Records: 4  Duplicates: 0  Warnings: 0

session2不被阻塞是预期的,那么如果此时在session1再次查询呢?

session1:
root@localhost test 10:50:27 >select * from test;
+----+------+
| id | name |
+----+------+
|  1 | xx   |
|  2 | xx   |
|  3 | xx   |
|  4 | xx   |
+----+------+
4 rows in set (0.00 sec)

可以看出,session1此时能得到最新的结果,因为此时的隔离级别为READ-COMMITTED,读提交,自然能读到最新的数据。
现在来解释这些现象,在mysql 5.1里面,开启一个事务,如果对表的操作仅有读操作,那么不会对表加上meta lock(也就是锁住表的结构),所以在前面的测试中可以看到session1中开启一个事务读表,session2中可以修改表结构。如果事务里面对表有写操作,那么结果肯定是session2的DDL操作肯定会被阻塞,我已经测试过了。

那么在REPEATABLE-READ隔离级别下为什么同一个事务里面读到结果不一样?一个事务里面(这里是session1)只有读操作,那么这个表就可以在其他事务中被执行DDL操作,而当session1里面再次去读表时,发现这个表结构已经被修改了,于是只好去读副本。而mysql ALTER TABLE的操作原理是:创建一个临时表、将数据插入临时表、删掉原表、重命名临时表。那么由于REPEATABLE-READ的特性,新表里面的数据肯定是读不到的(因为事务开启时间早于新表的创建时间),所以说读到的数据也就是empty set。而你可能会问为什么不去读那个原表的数据?这是因为DDL语句是不可rollback,所以之前删除原表的操作也就不会创建回滚数据。不过幸好是这个问题在mysql 5.5里面已经修正了,因此我在用mysql 5.5做测试时也就看不到mysql 5.1里面出现的现象。

对于这个问题最需要注意的地方就是在利用mysqldump备份的时候,虽然你可能使用了参数--single-transaction,结果很有可能不是你所预期的(导出来的数据是一张空表,empty set),所以要小心了。





2012年3月31日星期六

flush tables with read lock的一个潜在问题

    看了mysqlperformance的一篇关于flush tables with read lock的文章,里面提到了它可能引发一些问题。好了,现学现卖,分享给大家。
    现在很多的mysql备份工具在实现原理上都利用到了flush tables with read lock。这是为备份myisam表而设计的。像xtrabackup备份innodb表时并不会锁表,因为它也会备份在备份过程中新发生的事务日志,而对于myisam表的备份则是通过发出命令flush tables with read lock,然后拷贝myisam的相关表文件。那么在实际备份过程中可能会出现什么问题呢?答案是:有可能导致备份的时间严重的增长。下面来说说为什么会这样。
    flush tables with read lock,也就是将所有的脏页都要刷新到磁盘,然后对所有的表加上了读锁,于是这时候直接拷贝数据文件也就是安全的。但是如果你发出命令flush tables with read lock时,还有其他的操作,而起是很耗时的操作呢?先说写操作,这个FTWRL肯定是得等的,等写操作完成才能执行FTWRL,这个很好理解。那么对于其他的读操作呢?比如说在FLWRL发出之前有一个query:select count(*) from tb,那么FTWRL也得等待(show processlist可以看到 waiting for table flush)。你可能会说在mysql中读与读不是不会排斥的吗,为什么需要等待呢?因为FTWRL是要flush脏页的,只有这样才真的能保证数据一致性(比如说在xtrabackup备份myisam表的时候),而在select count(*) from tb执行的时候,因为所有的操作都是在内存中操作,所以此时还不能完全flush,因此FTWRL就得等待。或许你还会有疑问,select的页不是脏页,为什么FTWRL还要等待呢?难道mysql不能做得更完善点吗?我觉得mysql还不是不会做的这么简单吧,等待的原因是因为这个表很大,无法一次性将所有的页都读到内存中来,而query具有原子性,总不可能执行一般被堵塞吧,所以说还是得乖乖的让它执行然,所以FTWRL就得等待了。
    所以在利用xtrabackup、ibbackup这种备份工具的时候,也要考虑到这点。

2012年3月25日星期日

mysql报错:two many connections/two many open files的解决方法

最近在论坛里面看到有几个朋友都发帖求助,原因是mysql报错:
[ERROR] Error in accept: Two many open files。
而且这位朋友还说他并没有同时打开这么多文件,那么这是什么原因呢?

首先,我们需要了解的是,在linux里面打开文件是以文件描述符(FD,file descripter)的形式打开的,每打开一次文件,那么os就分配给你一个文件描述符,对于同一个文件如果有多个进程打开,那么就可以分配多个文件描述符。

好了,现在我们回到这个问题上,这位朋友说他并没有一次性打开这么多的文件,怎么会出现这个问题呢?刚才说了,每个进程打开同一个文件都可能分配一个独立的FD,而mysql正是这么做的,每个session开打的数据文件的描述符都是独立的,而对于索引文件则是所有的session贡献,我先将手册里面的原话贴出来:


MySQL is multi-threaded, so there may be many clients issuing queries for a given table simultaneously. To minimize the problem with multiple client sessions having different states on the same table, the table is opened independently by each concurrent session. This uses additional memory but normally increases performance. WithMyISAMtables, one extra file descriptor is required for the data file for each client that has the table open. (By contrast, the index file descriptor is shared between all sessions.)

好了,那你现在应该明白了,为什么并没有同时打开那么文件,但是却有那么多的文件描述符。弄清楚问题,那么现在就来解决这个问题。
首先是增大table_open_cache,具体用法参考手册上说明
然后根本解决方法是在os上增大mysqld这个线程的最大开打文件数,在linux里面可以通过编辑文件 /etc/security/limits.conf
然后里面的信息如下:

# /etc/security/limits.conf
#
#Each line describes a limit for a user in the form:
#
#<domain>        <type>  <item>  <value>
#
#Where:
#<domain> can be:
#        - an user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#
#<type> can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
#<item> can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open files
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to
#        - rtprio - max realtime priority
#
#<domain>      <type>  <item>         <value>
#

这个里面可以对进程需要的很多资源进行配置,比如说我们现在需要就是onfile这个选项
open file
而且我们有两种配置方式,第一是针对用户组的形式,第二具体用户的形式
比如有mysql用户
mysql        soft    nofile          131072
上面就限制了mysql用户最大的打开文件数。同时可以通过ulimit命令来查看这些信息。

但有时候,我们遇到的不是two many open files 而是 two many connections,这个就是并发的连接数,通过修改参数mysql的max_connections来解决,但是需要注意的是当这个参数增大的时候,同时可能会引发two many open files的问题,原因上面已经解释过了。

自己并没有遇到过这个问题,只是简单模拟了一下,如果有错误,欢迎指正。


2012年3月24日星期六

shell命令 2>&1

在unix高级环境编程第三章的习题有一个问题:
./a.out > outfile 2>&1  # 1
./a.out 2&1 > outfile  # 2
问这两者有什么区别。

这个首先的说明几点:
1.在unix和类unix(linux之类)中以文件描述符的形式打开一个文件,这个文件描述符是一个非负数。
2.0代表标准输入,1代表标准输出,2代表标准错误输出
3.默认的情况下是1 所以> equal 1>,比如我们用文件描述符5打开了一个文件a,可以写成5>
4.shell命令的执行是从左往右

那么现在来看这两者有什么区别
对于第一条shell,首先是将a.out的内容标准输出,然后通过>(等价于1>,所以只对标准输出起作用)重定向到outfile,然后2>&1说明标准错误输出也往标准输出去,而由于之前标准输出以及重定向到了outfile,所以这里的错误输出也会重定向到outfile。

再看第二天shell,首先是a.out到标准输出,然后2>&1,所以标准错误输出也重定向到保准输出(注意此时的标准输出没有被重定向,所以默认是终端上),然后 > outfile ,这个说明此时再将标准输出到outfile,但是请注意标准错误输出2>不会也跟着被重定向到outfile,因为更改标准输出重定向在2>&1的后面。

至此你明白了吧,不信你可以自己试试这个结果,比如按照我下面的:

angbosen@db-9:~/shell-comand$ echo "aaa" > out.file 2>&1
angbosen@db-9:~/shell-comand$ cat out.file
aaa
angbosen@db-9:~/shell-comand$ echo "aaa" 2>&1 > out2.file
angbosen@db-9:~/shell-comand$ cat out2.file
aaa
angbosen@db-9:~/shell-comand$ cmd "aaa" 2>&1 > out2.file
-bash: cmd: command not found
hangbosen@db-9:~/shell-comand$ cmd "aaa" > out.file 2>&1
angbosen@db-9:~/shell-comand$ cat out.file
-bash: cmd: command not found

理解了吧,真的挺有意思的。