数据库原理

事务

我们很熟悉,事务必须符合原子性,一致性,隔离性,持久性。简称ACID。其中隔离性最复杂,有四个隔离级别
+ 未提交读 事务中的修改,即使没有提交,也对其他事务可见
+ 提交读(不可重复读) 事务在执行过程中,可以看到其他事务提交的结果。也就是说,连续读取两次,读取的结果可能发生变化
+ 可重复读。解决了上述问题。但是还是有幻读的问题。这是因为只使用了行级锁(如果使用范围锁或者表锁就不会出现这个问题)。在两次查询统一范围内的数据时,会发现数据变多了。Innodb通过MVCC机制解决了幻读的问题。这个级别是Mysql的默认事务隔离级别
+ 串行化。没有任何并发问题。

一阶段锁协议和两阶段锁协议

一阶段锁协议要求事务在执行前对自己需要的所有资源一次性加锁。
二阶段锁协议不要求对自己所需要的所有资源一次性加锁。可以在使用前加锁。但是所有加锁操作必须在所有解锁操作之前。
一阶段锁协议显然符合二阶段锁协议。
二阶段锁协议可能带来死锁。可以证明,如果事务是良构的且是两阶段的,那么任何一个合法的调度都是隔离的。。良构表示非死锁情况,隔离指隔离的最高等级(可串行化),意思是和串行执行的结果相同。

Mysql的innodb引擎采用的就是两阶段锁协议。锁只有在ROLLBACK或者COMMIT时才会一次性释放。

MVCC

多版本并发控制。简单而讲,同一份数据临时保留多版本的方式。
每一个数据行都有自己的一个版本标志。数据库保证每个事务的ID都是递增的。每一个数据行的版本标志就是修改它的事务ID。同一时刻内一行数据会有多个版本。
MVCC 数据库需要更一个一条数据记录的时候,它不会直接用新数据覆盖旧数据,而是将旧数据标记为过时(obsolete)并在别处增加新版本的数据。这样就会有存储多个版本的数据,但是只有一个是最新的。这种方式允许读者读取在他读之前已经存在的数据。
MVCC的核心优点在于读不加锁,读写不冲突。

UNDO和REDO机制

redo undo机制是在数据库引擎曾实现的。

UNDO机制如下:
假设有A、B两个数据,值分别为1,2。
A.事务开始.
B.记录A=1到undo log.
C.修改A=3.
D.记录B=2到undo log.
E.修改B=4.
F.将undo log写到磁盘。
G.将数据写到磁盘。
H.事务提交
在过程中任何时刻决定回滚,只要放弃当前事务redo日志即可。
核心在于先写redo到磁盘,再写数据。这样,如果系统再FG崩溃,重启系统只需要按照undo重写即可。这个机制保证了事务的原子性,缺点在于每次日志提交都要更新redo日志,存在大量的磁盘IO。所以,引入了redo+undo的机制。
A.事务开始.
B.记录A=1到undo log.
C.修改A=3.
D.记录A=3到redo log.
E.记录B=2到undo log.
F.修改B=4.
G.记录B=4到redo log.
H.将redo log写入磁盘。
J.事务提交
在过程中任何时刻决定回滚,先吧undo写入磁盘,再把redo写入磁盘。之所以不采用放弃redo日志的方法,是因为redo日志为了提高效率,设计为只能追加。
这样,系统崩溃后,只需要先运行redo log即可。

数据恢复与binlog

和redo和undo日志不同,binlog实在数据库服务器层实现的,会记录所有引擎的工作记录。所有对数据库数据进行更新的操作都会记录binlog。对于使用redo机制来的innodb来说,binlog显然要保持和redo日志的同步,binlog的在事务最终提交前写入,而redo日志则在事务运行期间就会追加。
数据库可以设置binlog在多少个事务或多长周期写入磁盘。如果使用不支持事务的存储引擎,如果在这期间系统崩溃就会造成数据丢失。binlog和redo/undo日志都可以用户数据恢复。对于支持事务的数据库,选择后者才能保证数据完整。

集群

主从集群,效果是主库可以写,从库只能读。在主库宕机后,从库可以切换为主库。
数据库原理
这种方案会导致主从之间的延迟问题。
非主从的集群有很多种方案,我们只分析 LVS+Keepalived+MySQL Cluster
+ LVS(提供负载均衡)+Keepalived(提供心跳监测)+MySQL Cluster
数据库原理
其中MySQL Cluster的原理如下
数据库原理

Mysql集群比mysql单机效率肯定低。

脑裂问题

在高可用(HA)系统中,当联系2个节点的“心跳线”断开时,本来为一整体、动作协调的HA系统,就分裂成为2个独立的个体。由于相互失去了联系,都以为是对方出了故障。

分布式事务(XA)