CSE_lecture9:Atomicity
Consistency under failure: The requirement of atomicity
即使不考虑分布式,故障的发生也可能引发不一致性
fail-stop发生时,整个系统的所有部分都出现failure
以下面的代码为例,必须保证bank(a) + bank(b)不变:
1 | |
其中fsync的本质是将内存页表的数据一个接一个写回到磁盘中,分为Write(A)和Write(B)两步
如果error发生在fsync前,不会发生问题,因为没有修改文件;但如果error发生在fsync执行过程中,比如写到一半就挂了,就可能出现问题。因此需要系统提供atomicity的能力,即保证一系列操作all-or-nothing
shadow copy的思想为先不修改原来的文件,而是备份一个正确的数据,修改copy的数据,最后将copy的数据变成原来的数据即可
1 | |
当crash发生在fcopy或者fsync执行时,由于bank本身没有被修改,所以不影响一致性;当crash发生在rename执行时,由于bank_temp和bank这两个文件都是保证了一致性的,因此问题在于filesystem的实现,严重时可能导致filesystem挂掉
原来的rename操作需要依次修改inode num和refcnt,因此需要让filesystem也具备all-or-nothing,现在不能再使用shadow copy了,否则会递归下去。使用journaling的方法,其思想为允许数据被改错,只要能保证能修复即可,在进行正式的数据更新前,先把即将进行的修改内容记录到日志文件中
journaling的方法为:
- 将修改记录在journal中
- 提交journal,即将journal写入磁盘
- 更新,按照journal进行真正的数据修改
如果crash发生在commit前,数据并没有真正修改;发生在commit后时,将journal里的操作重做一次即可
通过journaling进行rename的操作为:
涉及到多个block修改的操作都可以通过journaling来保证一致性,如append a file:
journaling也有缺点:需要额外的写操作(两倍),当文件极大时磁盘压力很大。解决方法为选择快速操作,只保证一部分重要的操作是原子性的,因此journaling只用于关键的操作,这也是shadow copy依然需要的原因
当crash发生在journal commit时,由于厂商保证disk写入一个sector时一定是原子性的,故journal commit也是all-or-nothing的;即使没有,也可以使用校验码验证,但有开销
现在shadow copy就实现原子性了,但其有一定缺点:
- 一次只能进行一个操作:多个client同时操作同一个文件的不同部分时,直接copy会导致覆写,此时只能共享文件,且必须等待所有client完成时才能写回。这样的性能很差,故shadow copy只用于简单的场景
- 难以修改多个文件:需要大量的复制,同时只有放在同一目录下才能勉强保证原子性
- 微小的改动都会引发整个文件的copy,可以通过copy-on-write优化