mysql数据一致性和副本复制-part3

1.5 加锁机制
    MVCC实质上是通过避免读写冲突来提升并发度,由于是通过读取快照数据来“避免”读写冲突,因而其查询结果不能作为update、delete、insert的依据,InnoDB使用锁机制来解决这类问题。InnoDB主要使用行级锁(row lock),其行锁是通过在索引项上加锁而实现的,如果mysql的执行计划没能用到索引,那么行锁就不会生效,这时加锁的粒度就会跃变成表锁,会严重降低性能。
(1)锁种类:
    a. Read lock:通常称作共享锁(S-lock),如果事务T给数据对象A加上了共享锁,
那么T只能读A不能修改A,其它事务只能给A加共享锁,并且直到A上共享锁全部释放后
才能给A加X-lock。这保证其它事务能看到A,并且在A上的共享锁释放之前不能对A做任何变更。(包括select lock in share mode;同时会强制进行当前读)
    b. Write lock:通常称作排它锁(X-lock),如果事务T给数据对象A加上了排它锁,
那么T可以读也可修改A。这保证其它事务不能给A加任何锁,并且在A上的排它锁释放之前不能对A做任何变更。(包括select for update、update, delete, insert;只有当autocommit=0或者以START TRANSACTION开始一个事务时select for update才会锁定,其它情况下不进行任何锁定;select for update等Write lock同时会强制进行当前读。)
    c. Table lock: 如果事务T给整张表加了共享锁,那么其它事务只能读这张表而不能写;如果事务T给整张表加了写锁,那么其它事务将不能增加记录和删除记录。
    d. Row-level locking:利用索引锁定数据库表中的一行。
(2)行锁类型
    InnoDB一般包含三种类型的锁,分别为record lock、gap lock、next_key lock,需要注意的是这三种锁都是在index上进行加锁,而不是在record上加锁。隔离级别Repeatable Read使用next-key lock和gap locking来进行加锁,避免phantom reads(比如,在同一个事务中,如果同一个select语句(select for update)执行两次,获得的结果不一样便被称为phantom read)。
    (2.1) Record lock 记录锁: a lock on an index record,典型的场景是对唯一索引且存在的行加锁,表现为仅仅锁住单独的一行记录,此时只有Record Lock。
    (2.2) GapLock 间隙锁:a lock on a gap between index records, or a lock on the gap before the first or after the last index record。
    a. 间隙锁也分为X、S,锁定的范围是开区间();
    b. 间隙锁仅仅是为了防止插入(purely inhibitive);
    c. 间隙锁之间无冲突;
    d. 由于间隙锁之间并无冲突,因此X间隙锁等价于S间隙锁,b和c的存在往往容易导致死锁的发生。显然GapLock很独特,不具有常规锁的特性,从某种意义上来说不算是锁。
    (2.3) NextKeyLock: an index-record lock plus a gap lock on the gap preceding the index record。需要明确的是NextKeyLock锁是索引记录的RecordLock加上该行前面的GapLock,是下届开,上界闭,一张表中的next-key锁包括:(负无穷大,最小的第一条记录],(记录之间],(最大的一条记录,正无穷大)。不同于GapLock, NextKeyLock具有常规锁的特性,加锁时需要等待锁可用,mysql通常用NextKeyLock来进行加锁。
    (2.4) I(插入意向锁):插入操作时使用的锁,插入意图锁实际上是Gap锁上加了一个LOCK_INSERT_INTENTION的标记,也就是说insert语句会对插入的行加一个X记录锁,但是在插入这个行的过程之前,会设置一个Insert intention的Gap锁,叫做Insert intention锁。
(3)加锁过程
mysql采用二阶段锁协议(2PL)进行加锁和解锁,对于UPDATE、DELETE,如果sql语句的条件表达式带有合适的索引,通常会在处理sql语句的搜索过程中,对搜索过的索引范围设置next-key锁,如果条件表达式中没有索引,会导致mysql对整张表加排它锁。
    (3.1)常见SQL语句加锁方式
    a. select:快照读,不加任何锁,除非隔离级别是 SERIALIZABLE;
    b. select lock in share mode:对搜索过程中遇到的所有索引项均加共享NextKeyLock;
    c. select for update:对搜索过程中遇到的所有索引项阻止其被加select lock in share mode;
    d. update:对搜索过程中遇到的所有索引项均加排它NextKeyLock;
    e. delete:对搜索过程中遇到的所有索引项均加排它NextKeyLock;
    f. insert:仅对新插入的这一行数据加排它锁,不加NextKeyLock也不加GapLock,但在插入前需要对插入区间先加插入意向锁,如果多个插入意向锁欲插入的位置没有冲突,则插入意向锁之间不需要相互等待,否则插入意向锁需要等待其它插入意向锁的释放。如果插入过程中出现 duplicate-key错误,会给duplicate key索引项加共享锁,某种情况下会导致死锁。
    g. insert on duplicate key update:和insert唯一不同的是当插入过程中出现 duplicate-key错误,会给duplicate key索引项加排它NextKeyLock。
    (3.2)删除一条不存在的记录会在删除记录所在的一个区间内加间隙锁,区间外是不加锁的。
    a. 如果是空表,则间隙锁的加锁区间为整个表的所有索引。
    b. 如果表中存在记录,删除操作的del_id大于表中记录id的最大值,则间隙锁的加锁区间为大于表中已存在记录id的所有索引。
    c. 如果表中存在记录,删除操作的del_id小于表中id的最小值,则间隙锁的加锁区间为小于表中已存在记录id最小值的所有索引。
    d. 如果表中存在记录,删除操作的del_id小于表中id的最大值,大于表中记录的最小值,则间隔锁加锁区间为表中小于del_id的存在的记录的最大id记为already_id_min至大于del_id的存在的记录的最小id记为already_id_max。
    (3.3)死锁
    死锁产生的原因本质还是因为多个进程之间的锁请求形成了环路等待,不同的SQL语句(或事务)对于同一索引加锁顺序的不确定性容易造成对索引的加锁请求形成环路等待,这种死锁比较的隐蔽。比如当两个事务分别先做一次删除操作(删除一条数据库中不存在的记录),然后再做一次insert操作,且两个间隙所加锁的区间有交集时,就会出现死锁。 InnoDB 会自动检测一个事务的死锁并回滚一个或多个事务来防止死锁。从 4.0.5 版开始,InnoDB 将设法提取小的事务来进行回滚。一个事务的大小由它所插入(insert)、更新(update)和删除(delete)的数据行数决定。 可以通过show engine innodb status\G查看数据库最近发生死锁的场景(InnoDB只显示了事务持有锁的相关简单信息,并且只显示了每个事务最后执行的语句,发生死锁的记录就是由于这些语句引起的。查看复杂的死锁信息还需要查看日志文件,才能找到真正引发冲突的语句)。
2、基于主备份协议-主从架构
    复制的重要性和作用就不再强调了,mysql提供了基于主备份协议即主从架构的复制方式,也是目前主流中广泛使用的复制架构模式,因为这种方式简单可靠,这一点十分重要。
    其特点是:所有的写操作均发生在固定的主库上,读操作既可以发生在主库上(实现强一致性读)也可以发生在从库上(实现弱一致性读),主库通知从库拉取更新内容,从库使用拉协议从主库拉取更新完成主从同步。
(1) Master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events)。
(2) Slave将Master的二进制日志事件(binary log events)拷贝到它的中继日志(relay log)。Slave服务器中有一个I/O线程(I/O Thread)在不停地监听Master的二进制日志(Binary Log)是否有更新:如果没有它会睡眠等待Master产生新的日志事件;如果有新的日志事件(Log Events),则会将其拷贝至Slave服务器中的中继日志(Relay Log)。
(3) Slave重做中继日志(Relay Log)中的事件,将Master上的改变反映到它自己的数据库中。Slave服务器中有一个SQL线程(SQL Thread)从中继日志读取事件,并重做其中的事件从而更新Slave的数据,使其与Master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小。
    需要注意的是,当出现主从明显延迟的时候,需要观察一下主库和从库上的时钟是否出现较大延迟,这也是导致主从同步出现明显延迟的一个可能原因。
全文参考资料:
1.https://github.com/ept/hermitage
2.http://queue.acm.org/detail.cfm?id=1394128
3.http://blog.csdn.net/chen77716/article/details/6742128
4.https://blogs.oracle.com/mysqlinnodb/entry/mysql_5_6_multi_threaded
5.http://www.xdata.me/?p=289
6.http://mysqldump.azundris.com/archives/77-Transactions-An-InnoDB-Tutorial.html
7.https://blogs.oracle.com/mysqlinnodb/
8.http://blog.chinaunix.net/uid-24111901-id-2627857.html
9.http://try.valinv.com/mysql/ee751bb5a9a94178173d5f28dd193d39.html
10.http://blog.csdn.net/youling_lh/article/details/10475377
11.http://www.zhdba.com/mysqlops/2012/04/06/innodb-log3/
12.https://www.percona.com/blog/2011/02/03/how-innodb-handles-redo-logging/
13.http://dev.mysql.com/doc/refman/5.0/en/innodb-record-level-locks.html
14.http://dev.mysql.com/doc/refman/5.0/en/innodb-next-key-locking.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值