共计 1619 个字符,预计需要花费 5 分钟才能阅读完成。
咱们在 HDFS – 什么是元数据中提到了,元数据会存在与内存和磁盘中,内存为了进步响应速度,磁盘是为了长久化保证数据的平安,然而写磁盘的速度绝对于内存是慢了几个数量级的,如果 NameNode 每次都要把数据落到磁盘上那是没方法解决那么多客户端的申请的,所以 NameNode 用了双缓冲机制以及分段加锁。
所谓双缓冲就是定义了两个内存块,一个是 bufCurrent,用于以后写入元数据的,一个是 bufReady,用于写入磁盘的,两个内存块都是 512k。
第一把锁
线程 1 会先获取锁,而后会看看以后有没有在替换缓存(这里通过 isAutoSyncScheduled 来判断),如果没有,就去获取一个全局惟一的事务 ID,这个 ID 是递增的。拿到事务 ID 后,就开始写入 bufCurrent,写完后判断 bufCurrent 是否超过了 512k,如果没有,线程 1 的流程就完结了(前面完结的背景是红色的)。
因为线程 2,3,4 在线程 1 没开释锁的时候,都会始终等到,如果线程 2,3,4 拿到了锁,也会持续下面线程 1 的操作。
因为这个锁里的操作都是基于内存的,所以速度就会十分块。
咱们假如线程 4 写完后,发现 bufCurrent 内存超过了 512k,此时就会把 isAutoSyncScheduled 设置为 true,阐明要开始替换内存了,其余线程就不能做以上的操作了。这里的 bufCurrent 就是线程 1,2,3,4 写入的数据。
这个时候,线程 5 进来并拿到锁,咱们给拿锁的过程色彩标深一点,发现要开始替换内存了,于是他就是 wait 状态。
第二把锁
咱们假如接下来获取到锁的是线程 4。他发现此时并没有其余线程替换内存(这里通过 isSyncRunning 判断),于是他就开始 bufCurrent 和 bufReady 的内存进行了替换,替换后,bufCurrent 的数据就清空了。在这里还会把 isSyncRunning 设置 true,而后 isAutoSyncScheduled 设置为 false,最初就唤醒 wait 的线程。
线程 4 唤醒其余线程后,他就开始把 bufReady 的数据写入磁盘,这个操作是很耗时的,所以并没有加锁,然而他是运行状态,所以下图标记为绿色。
这里的 bufReady 就是线程 1,2,3,4 写入的数据。
此时是线程 5 获取了锁,发现内存替换结束了,开始往 bufCurrent 写数据。
尔后线程 6 拿到了锁,此时 bufCurrent 又超过了 512k 了,就会把 isAutoSyncScheduled 设置为 true,阐明开始替换内存,其余线程就不能往 bufCurrent 写入数据了。然而他发现 isSyncRunning 为 true,阐明有其余线程在写磁盘了,所以他就开始 wait。
第三把锁
此时线程 4 写完了磁盘,而后他获取到锁,就会把 synctxid 更改为本人的事务 ID,而后赋值 isSyncRunning 为 false,阐明磁盘写入实现了。最初唤醒其余 wait 的线程。
此时线程 6 从新拿到了锁,他发现 isSyncRunning 为 false 了,那就是阐明其余线程曾经把本人的内容刷入磁盘了,所以线程 6 开始了下面线程 4 的操作,替换内存,写入磁盘。
总结
第一把锁,次要是判断 isAutoSyncScheduled 以及对 isAutoSyncScheduled 的赋值,这个次要是阐明 bufCurrent 和 bufReady 开始替换内存了。
第二把锁,次要是判断 isSyncRunning 以及对 isSyncRunning 和 isAutoSyncScheduled 的赋值。isSyncRunning 是用来判断是否在写磁盘,isAutoSyncScheduled 用来判断是否在替换内存,如果在替换,就不能写入 bufCurrent,如果在写磁盘,那就不能写磁盘。
第三把锁,赋值 isSyncRunning,阐明磁盘写入实现。
这期间最耗时的操作并没有加锁,其余内存操作的加锁,然而速度比拟快,采纳在这种分段加锁的形式和双缓冲机制,大大提高了性能。