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),所以要小心了。