设为首页 收藏本站
查看: 843|回复: 0

[经验分享] 第七章:小朱笔记hadoop之源码分析-hdfs分析 第四节:namenode-SafeModeMonitor

[复制链接]

尚未签到

发表于 2016-12-13 09:09:22 | 显示全部楼层 |阅读模式
第七章:小朱笔记hadoop之源码分析-hdfs分析

第四节:namenode分析

4.7 namenode 安全模式SafeModeMonitor

      在分布式文件系统启动的时候,开始的时候会有安全模式,当分布式文件系统处于安全模式的情况下,文件系统中的内容不允许修改也不允许删除,直到安全模式结 束。安全模式主要是为了系统启动的时候检查各个DataNode上数据块的有效性,同时根据策略必要的复制或者删除部分数据块。运行期通过命令也可以进入 安全模式。在实践过程中,系统启动的时候去修改和删除文件也会有安全模式不允许修改的出错提示,只需要等待一会儿即可。       SafeModeException 异常,运行hadoop程序时,有时候会报以下错误:org.apache.hadoop.dfs.SafeModeException: Cannot delete/user/hadoop/input. Name node is in safe mode.只有离开安全模式,系统才会正常读写。

写道

$bin/hadoop dfsadmin -safemode leave //关闭Hadoop的安全模式

     NameNode在启动的时候首先进入安全模式,如果datanode丢失的block达到一定的比例(1- dfs.safemode.threshold.pct),则系统会一直处于安全模式状态即只读状态。 dfs.safemode.threshold.pct(缺省值0.999f)表示HDFS启动的时候,如果DataNode上报的block个数达到了 元数据记录的block个数的0.999倍才可以离开安全模式,否则一直是这种只读模式。如果设为1则HDFS永远是处于SafeMode。
(1)修改dfs.safemode.threshold.pct为一个比较小的值,缺省是0.999。
(2)hadoop dfsadmin -safemode leave命令强制离开
 

hadoop dfsadmin-safemode 命令  
格式:Usage: java DFSAdmin [-safemode enter | leave | get |wait]  
用户可以通过dfsadmin -safemode value 来操作安全模式,参数value的说明如下:  
enter - 进入安全模式  
leave - 强制NameNode离开安全模式  
get    - 返回安全模式是否开启的信息  
wait   - 等待,一直到安全模式结束。  
     FSNamesystem在初始化的时侯会首先进入安全模式状态并在之后开启一个后台工作线程——SafeModeMonitor来监控当前集群是否可以离开安全模式状态。 FSNamesystem是通过一个SafeModeInfo对象来保存当前集群的状态信息的。FSNamesystem在初始化的时侯会创建它对应的一个实例,并传入当前集群数据块的总数量。
 

    class SafeModeInfo {  
// 配置Field,从与配置文件相关的配置类实例获取到这些属性值   
/** 只有当条件(是个比率)大于threshold的时候,才能进入安全模式*/   
private double threshold;   
/** 进入安全模式 */   
private int extension;   
/** 安全模式要求的最小副本因子 */   
private int safeReplication;   
/**   
* 当达到threshold的值的时间  
* -1 离开安全模式  
* 0 正在安全模式下,但是threshold是不可达的   
*/   
private long reached = -1;      
/** 块总数 */   
int blockTotal;     
/** 安全的块的总数 */   
private int blockSafe;   
/** 输出最后状态的时间 */   
private long lastStatusReport = 0;   
/**
* Creates SafeModeInfo when the name node enters
* automatic safe mode at startup.
*   
* @param conf configuration
*/  
SafeModeInfo(Configuration conf) {  
this.threshold = conf.getFloat("dfs.safemode.threshold.pct", 0.95f);  
this.extension = conf.getInt("dfs.safemode.extension", 0);  
this.safeReplication = conf.getInt("dfs.replication.min", 1);  
this.blockTotal = 0;   
this.blockSafe = 0;  
}  
/**
* Creates SafeModeInfo when safe mode is entered manually.
*
* The {@link #threshold} is set to 1.5 so that it could never be reached.
* {@link #blockTotal} is set to -1 to indicate that safe mode is manual.
*  
* @see SafeModeInfo
*/  
private SafeModeInfo() {  
this.threshold = 1.5f;  // this threshold can never be reached  
this.extension = Integer.MAX_VALUE;  
this.safeReplication = Short.MAX_VALUE + 1; // more than maxReplication  
this.blockTotal = -1;  
this.blockSafe = -1;  
this.reached = -1;  
enter();  
reportStatus("STATE* Safe mode is ON.", true);  
}  
.......
}  
  
第一步:FSNamesystem的initialize 中会判断是否进入安全模式
 

    //加载安全模式信息,进入安全模式   
this.safeMode = new SafeModeInfo(conf);  
//将block的总数设置给safemode  
etBlockTotal();  
         当给SafeModeInfo对象设置当前集群中数据块总量的时候,它会判断当前集群是否应该进入安全模式状态,如果应该则它会让当前集群立即进入安全模 式。至于如何判断集群是否应该进入安全模式状态,主要是依据当前主节点收到数据节点报告的数据块Block处于安全状态的数量占集群总数据块的比重是否达 到系统设置的阈值threshold来确定的。
第二步:设置Block总数
 
 

    synchronized void setBlockTotal(int total) {  
this.blockTotal = total;   
checkMode();  
}  
 
第三步:datanode块汇报时不断调用checkMode方法
 

    synchronized void incrementSafeBlockCount(short replication) {  
if ((int)replication == safeReplication)  
this.blockSafe++;  
checkMode();  
}  
synchronized void decrementSafeBlockCount(short replication) {  
if (replication == safeReplication-1)  
this.blockSafe--;  
checkMode();  
}        

/**
* Check and trigger safe mode if needed.  
* 检查当前文件系统是否应该进入安全模式状态  
*/  
private void checkMode() {  
if (needEnter()) {  
enter();  
reportStatus("STATE* Safe mode ON.", false);  
return;  
}  
// the threshold is reached  
// //当前文件系统是否可以离开安全模式状态   
if (!isOn() ||                           // safe mode is off  
extension <= 0 || threshold <= 0) {  // don't need to wait  
this.leave(true); // leave safe mode  
return;  
}  
if (reached > 0) {  // threshold has already been reached before  
reportStatus("STATE* Safe mode ON.", false);  
return;  
}  
LOG.info("start monitor");  
// start monitor  
// 开启一个监控线程来判断当前文件系统是否可以真正离开   
reached = now();  
smmthread = new Daemon(new SafeModeMonitor());  
smmthread.start();  
reportStatus("STATE* Safe mode extension entered.", true);  
}  
         一个数据块Block处于安全状态指的是该数据块的副本数量(根据数据节点的数据块报告)达到了safeReplication。集群在进入安全模式之 后,主节点在处理数据节点关于数据块Block报告的过程中会不断的调用SafeModeInfo的checkMode()来判断当前集群中处于安全状态 的数据块占集群总数据块的比重是否达到系统设置的阈值threshold。
 
第四步:到达阀值,开启SafeModeMonitor线程如果块汇报到一定程度也就是安全状态的数据块占集群总数据块的比重是否达到系统设置的阈值threshold。系统会开启SafeModeMonitor 线程
 

    smmthread = new Daemon(new SafeModeMonitor());  
smmthread.start();  
  
第五步:稳定期过度canLeave到了这个阈值,集群也需要一个过渡期extension来确保当前安全数据块的数量是否已经稳定了。所以它会立即开启一个SafeModeMonitor 后台线程来通过轮询的方式判断当前集群是否度过了这个稳定期,如果在稳定期之后,当前就能的安全数据块数量任然超过了设定的阈值则此时集群可以真正离开安 全模式了。这里extension的默认值为0,但也可以通过配置文件来设置,对应的配置项为dfs.safemode.extention。
 

    /**  
* Safe mode can be turned off iff  
* the threshold is reached and  
* the extension time have passed.
* 判断当前集群是否可以离开安全模式 reached:到达阀值时间 extension:缓存时间
* @return true if can leave or false otherwise.
*/  
synchronized boolean canLeave() {  
if (reached == 0)  
return false;  
if (now() - reached < extension) {  
reportStatus("STATE* Safe mode ON.", false);  
return false;  
}  
return !needEnter();  
}  
第六步:离开安全模式
集群在离开安全模式的时候会对集群中的所有数据块Blocks进行处理。
 

      /**  
* 处理当前文件系统的所有数据块:  
*     1).无效数据块  
*     2).数据块副本不够  
*     3).数据块副本有多余  
*/   
private synchronized void processMisReplicatedBlocks() {  
long nrInvalid = 0, nrOverReplicated = 0, nrUnderReplicated = 0;  
neededReplications.clear();  
for(BlocksMap.BlockInfo block : blocksMap.getBlocks()) {  
INodeFile fileINode = block.getINode();  
//数据块已不属于任何文件,所以应该从所有存储该数据块副本的数据节点上清除它   
if(fileINode == null) {  
// block does not belong to any file  
nrInvalid++;  
addToInvalidates(block);  
continue;  
}  
// calculate current replication  
short expectedReplication = fileINode.getReplication();  
NumberReplicas num = countNodes(block);  
int numCurrentReplica = num.liveReplicas();  
// add to under-replicated queue if need to be  
//判断当前数据块是否还需要复制副本,如果需要则将其添加到待复制副本队列中   
if (neededReplications.add(block,   
numCurrentReplica,  
num.decommissionedReplicas(),  
expectedReplication)) {  
nrUnderReplicated++;  
}  
//处理数据块的多于副本   
if (numCurrentReplica > expectedReplication) {  
// over-replicated block  
nrOverReplicated++;  
processOverReplicatedBlock(block, expectedReplication, null, null);  
}  
}  
}  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-313558-1-1.html 上篇帖子: 第七章:小朱笔记hadoop之源码分析-hdfs分析 第四节:namenode-HeartbeatMonitor 下篇帖子: 大数据之hadoop,国内首部:Zookeeper从入门到精通
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表