`
shenchunhui
  • 浏览: 146196 次
  • 来自: 杭州
社区版块
存档分类
最新评论

Hbase 源码分析之当regionserver挂掉以后

阅读更多
当Master通过ZK获知Regionserver挂掉以后,通过调用expireServer接口进行处理
public synchronized void Hmaster.ServerManager.expireServer(final HServerInfo hsi){
获取serverName
从onlineserverlist中获取serverinfo
如果serverinfo为空,则抛sever不在线上的警告,return
如果已经存在于deadservers中,则抛警告,return
加到deadservers中
从onlineservers中删除
删除与该server的rpc连接
如果集群处于关闭中,则return
通过CatalogTracker判断挂掉的server之前是否有分配root或meta region
然后分别调用
this.services.getExecutorService().submit(new MetaServerShutdownHandler(this.master,this.services, this.deadservers, info, carryingRoot, carryingMeta));
或者
1 this.services.getExecutorService().submit(ServerShutdownHandler(this.master,this.services, this.deadservers, info));
//这两者的区别是 MetaServerShutdownHandler恢复时需要assignRoot()或assignMeta()
}


1.ServerShutdownHandler的procss接口如下
public void ServerShutdownHandler.process(){
1.1 split hlog
    获取挂掉的regionserver上的regionstate列表
判断是否需要assign root 或者 meta region
while(!this.server.isStopped()){
  try{
     等待meta恢复
      通过meta表获取挂掉的regionserver上所有Hregioninfo信息hris
     break
}catch(){}
}
遍历获取到的regionstate列表,hris中删除那些state不是CLOSING且不是PENDING_CLOSE的region
遍历hris中的region:
    //如果region所在的表disable或者该region已经split 则返回否
    if(检查是否需要assign)
1.2      this.services.getAssignmentManager().assign(e.getKey(), true);
}


1.1 split hlog
public void hbase.master. MasterFileSystem. splitLog(final String serverName){
获取splitLog锁
获取hdfs中挂掉的regionserver的hlog目录所在位置(默认为.logs/servername)
创建对象HLogSplitter splitter
1.1.1 调用splitter.splitLog()切分hlog
释放splitLog锁
}


1.1.1 splitter.splitLog()
public List<Path> hbase.regionserver.wal.HLogSplitter.splitLog(){
检查是否hasSplit
hasSplit置为true
对hdfs上的hlog目录做一些检查,如是否存在,目录下是否存在文件,没问题的话就调用
1.1.1.a List<Path> splitLog(logfiles)
}


1.1.1.a splitlog时,会有一个entryBuffers,读线程从hlog中读取edit放入entryBuffers,而写线程则从中获取buffer,写到hdfs中对应的region目录下recover.edits目录中
private List<Path> hbase.regionserver.wal.HLogSplitter.splitLog(final FileStatus[] logfiles){
new两个list processedLogs和corruptedLogs 用于存放已正常处理的logs和已损坏的logs
获取是否skipErrors = conf.getBoolean("hbase.hlog.split.skip.errors", true);
//负责将entryBuffers中的数据写入到hdfs中各个region目录下的recover.edits目录中
启动写线程outputSink.startWriterThreads(entryBuffers);默认为3个("hbase.regionserver.hlog.splitlog.writer.threads", 3);
遍历logfiles中的logfile{
通过lease机制检查logfile是否能够append
解析logfile,将其中的内容加载到内存,即放入entryBuffers中
}
对logfiles进行归档,把有损坏并且跳过的移到.corrupt目录中 
把处理好的移到.oldlogs中,然后删除.logs/挂掉的regionserver目录
等待写线程完毕
返回新写的在region目录/recover.edits目录下的各个logfile路径
}


1.2 分配region,分配前先检查region所在的表是否disable和是否集群处于关闭中,是的话就跳过,不然就加到rit后(RegionInTransaction),开始分配
private void hbase.master.AssignmentManager.assign(final RegionState state, final boolean setOfflineInZK,final boolean forceNewPlan)
{
将region在zk上的状态置为offline
获取regionplan(将region随机分配给在线的一个regionserver)
将region状态置为PENDING_OPEN
1.2.1向regionserver发送openregion的rpc请求(regionserver调用openregionopenRegion(HRegionInfo region)接口)
}


1.2.1 openRegion处理
regionserver异步地执行openRegionHandler
regionserver到zk上将该region的状态置为RS_ZK_REGION_OPENING
master检测到zk上该region状态为RS_ZK_REGION_OPENING后,会将该region状态置为OPENING,并定期检查opening状态有没有timeout
hregion执行replayRecoveredEditsIfAny(),即从log中将数据还原到table中。方法是将log解析出来后写到内存中(store),然后累积到一定值后直接刷到磁盘上
更新META表,写入该region信息
到zk上将该region状态置为RS_ZK_REGION_OPENED
master检测到RS_ZK_REGION_OPENED后,再把region状态更新为OPEN
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics