咱们在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,阐明磁盘写入实现。
这期间最耗时的操作并没有加锁,其余内存操作的加锁,然而速度比拟快,采纳在这种分段加锁的形式和双缓冲机制,大大提高了性能。