hadoop实现原理(一)配置信息处理
2015-04-04 20:47
239 查看
Hadoop作为一个复杂的软件系统,使用一个配置模块提高其适应性或扩展性,作为其扩展、定制的手段和方式。
为什么不直接使用java.util.Properties类?
Properties类继承自Hashtable,它并不能支持INI文件的“节”,对配置项进行分类。Properties类提供了load()方法加载,该方法从输入流中读入key-value对,而store()方法则将Properties表中的属性列表写入输出流。还提供了loadFromXML()和storeToXML()方法。相应get和set方法:
public String getProperty(String key)
public String getProperty(String key, String defaultValue)
public synchronized Object setProperty(String key, String value)
由于java.util.Properties提供的能力有限,Java社区出现了大量的配置信息读写方案,其中比较著名的是Apache Jakarta Commons工具集中提供的Commons Configuration。
Hadoop没有使用Properties类,也没有使用Commons Configuration来管理配置文件,而使用了一套独有的配置文件管理系统,并提供自己的API,即使用org.apache.hadoop.conf.Configuration。
Hadoop配置文件的格式
Hadoop配置文件的根元素是configuration,一般只包含子元素property。Hadoop可以合并资源将多个配置文件合并,产生一个配置。如下:
Configurationconf = new Configuration();
conf.addResource(“core-default.xml”);
conf.addResource(“core-site.xml”)
如果这两个资源都包含了相同的配置项,而且前一个资源的配置项没有标记为final,那么,后面的配置将覆盖前面的配置。如果第一个资源中某配置项标记了final,那么,在加载第二个资源的时候,会有警告提示。
Hadoop配置系统还有一个重要的功能,就是属性扩展。如配置项项dfs.name.dir的值是Hadoop.tmp.dir/dfs/name,其中,{Hadoop.tmp.dir}会使用Configuration中的相应属性值进行扩展。
Configuration的成员变量
![](https://oscdn.geek-share.com/Uploads/Images/Content/202010/16/1366719d9bd74cf8761590048e393c5a)
使用Configuration类的一般过程是:构造Configuration对象,并通过类的addResource()方法添加需要加载的资源:然后就可以用get*方法和set*方法访问和设置配置项。
quitemode,用来设置加载配置的模式,quite=true则不输出日志信息,方便调试。
Resources保存了所有通过addResource()方法添加Configuration对象的资源。Configuration.addResource()有如下4种形式:
在HDFS的DataNode中,加载两个默认资源:
// 代码来自org.apache.hadoop.hdfs.server.datanode.DataNode
static{
Configuration.addDefaultResource(“hdfs-default.xml”);
Configuration.addDefaultResource(“hdfs-site.xml”)
}
properties和overlay成员变量都是前面介绍过的java.util.Properties,Hadoop配置文件解析后的key-value对都存在properties中,变量finalParameters的类型是Set,用来保存所有在配置文件中已经声明为fianl的键,变量overlay用于记录通过set()方式改变的配置项,也就是应用设置的。
资源加载
资源通过对象的addResource()方法或类的静态addDefaultResource()方法(设置了loadDefault标志)添加到Configuration对象中,添加的资源并不会立即被加载,只是通过reloadConfiguration()方法清空properties和finalParameters。相关代码如下:
静态方法addDefaultResource()也能清空Configuration对象中的数据,这是通过类的静态成员REGISTRY作为媒介进行的。
成员变量properties中的数据,直到需要的时候才会加载进来。在getProps()方法中,如果发现properties为空,将触发loadResources()方法加载配置资源。延迟加载的设计模式,当真需要配置数据的时候,才开始解析配置文件。
由于Hadoop的配置文件都是很小的文件,因此Configuration使用DOM处理XML。
使用get*和set*访问和设置配置项
get方法在Configuration对象中获取相应的配置信息。
Configuration.get()会调用Conguration的私有方法substituteVars(),完成配置属性的扩展,也就是把包含${key}这种格式的变量,自动替换成对应的值。substituteVars的工作依赖于正则表达式:
varPat: $\\{[^\\}\$\u0020]+\}
如果一次属性扩展完成以后,得到的表达式里仍然包含可扩展的变量,那么,substituteVars()需要再次进行属性扩展。为了避免进入死循环,substituteVars()使用一个非常简单而有效的策略,即属性扩展只能进行一次的次数(20次,通过Configuration的静态成员变量MAX_SUBST定义)。
为什么不直接使用java.util.Properties类?
Properties类继承自Hashtable,它并不能支持INI文件的“节”,对配置项进行分类。Properties类提供了load()方法加载,该方法从输入流中读入key-value对,而store()方法则将Properties表中的属性列表写入输出流。还提供了loadFromXML()和storeToXML()方法。相应get和set方法:
public String getProperty(String key)
public String getProperty(String key, String defaultValue)
public synchronized Object setProperty(String key, String value)
由于java.util.Properties提供的能力有限,Java社区出现了大量的配置信息读写方案,其中比较著名的是Apache Jakarta Commons工具集中提供的Commons Configuration。
Hadoop没有使用Properties类,也没有使用Commons Configuration来管理配置文件,而使用了一套独有的配置文件管理系统,并提供自己的API,即使用org.apache.hadoop.conf.Configuration。
Hadoop配置文件的格式
<?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="configuration.xsl"?> <configuration> <property> <name>hadoop.tmp.dir</name> <value>/tmp/hadoop-${user.name}</value> </property> <property> <name>fs.default.name</name> <value>hdfs://localhost:54310</value> </property> <property> <name>mapred.job.tracker</name> <value>hdfs://localhost:54311</value> </property> <property> <name>dfs.replication</name> <value>8</value> </property> <property> <name>mapred.child.java.opts</name> <value>-Xmx512m</value> </property> </configuration>
Hadoop配置文件的根元素是configuration,一般只包含子元素property。Hadoop可以合并资源将多个配置文件合并,产生一个配置。如下:
Configurationconf = new Configuration();
conf.addResource(“core-default.xml”);
conf.addResource(“core-site.xml”)
如果这两个资源都包含了相同的配置项,而且前一个资源的配置项没有标记为final,那么,后面的配置将覆盖前面的配置。如果第一个资源中某配置项标记了final,那么,在加载第二个资源的时候,会有警告提示。
Hadoop配置系统还有一个重要的功能,就是属性扩展。如配置项项dfs.name.dir的值是Hadoop.tmp.dir/dfs/name,其中,{Hadoop.tmp.dir}会使用Configuration中的相应属性值进行扩展。
Configuration的成员变量
使用Configuration类的一般过程是:构造Configuration对象,并通过类的addResource()方法添加需要加载的资源:然后就可以用get*方法和set*方法访问和设置配置项。
quitemode,用来设置加载配置的模式,quite=true则不输出日志信息,方便调试。
Resources保存了所有通过addResource()方法添加Configuration对象的资源。Configuration.addResource()有如下4种形式:
public void addResource(InputStream in) public void addResource(Path file) public void addResource(String name) public void addResource(URL url)
在HDFS的DataNode中,加载两个默认资源:
// 代码来自org.apache.hadoop.hdfs.server.datanode.DataNode
static{
Configuration.addDefaultResource(“hdfs-default.xml”);
Configuration.addDefaultResource(“hdfs-site.xml”)
}
properties和overlay成员变量都是前面介绍过的java.util.Properties,Hadoop配置文件解析后的key-value对都存在properties中,变量finalParameters的类型是Set,用来保存所有在配置文件中已经声明为fianl的键,变量overlay用于记录通过set()方式改变的配置项,也就是应用设置的。
资源加载
资源通过对象的addResource()方法或类的静态addDefaultResource()方法(设置了loadDefault标志)添加到Configuration对象中,添加的资源并不会立即被加载,只是通过reloadConfiguration()方法清空properties和finalParameters。相关代码如下:
public void addResource(String name){ addResourceObject(name); } private synchronized void addResourceObject(Object resource) { Resources.add(resource); reloadConfiguration(); } public synchronized void reloadConfiguration(){ Properties = null; finalParameters.clear(); }
静态方法addDefaultResource()也能清空Configuration对象中的数据,这是通过类的静态成员REGISTRY作为媒介进行的。
public static synchronized void addDefaultResource(String name) { if(!defaultResources.contains(name)) { defaultResources.add(name); for(Configuration conf : REGISTRY.keySet()) { if(conf.loadDefaults) { conf.reloadConfiguration(); } } } }
成员变量properties中的数据,直到需要的时候才会加载进来。在getProps()方法中,如果发现properties为空,将触发loadResources()方法加载配置资源。延迟加载的设计模式,当真需要配置数据的时候,才开始解析配置文件。
private synchronized Properties getProps() { if (properties == null) { properties = new Properties(); loadResources(properties, resources, quietmode); if (overlay!= null) { properties.putAll(overlay); if (storeResource) { for (Map.Entry<Object,Object> item: overlay.entrySet()) { updatingResource.put((String) item.getKey(), "Unknown"); } } } } return properties; }
由于Hadoop的配置文件都是很小的文件,因此Configuration使用DOM处理XML。
private void loadResources(Properties properties, ArrayList resources, boolean quiet) { if(loadDefaults) { for (String resource : defaultResources) { loadResource(properties, resource, quiet); } //support the hadoop-site.xml as a deprecated case if(getResource("hadoop-site.xml")!=null) { loadResource(properties, "hadoop-site.xml", quiet); } } for (Object resource : resources) { loadResource(properties, resource, quiet); } } private void loadResource(Properties properties, Object name, boolean quiet) { try { DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); //ignore all comments inside the xml file docBuilderFactory.setIgnoringComments(true); //allow includes in the xml file docBuilderFactory.setNamespaceAware(true); try { docBuilderFactory.setXIncludeAware(true); } catch (UnsupportedOperationException e) { LOG.error("Failed to set setXIncludeAware(true) for parser " + docBuilderFactory + ":" + e, e); } DocumentBuilder builder = docBuilderFactory.newDocumentBuilder(); Document doc = null; Element root = null; if (name instanceof URL) { // an URL resource URL url = (URL)name; if (url != null) { if (!quiet) { LOG.info("parsing " + url); } doc = builder.parse(url.toString()); } } else if (name instanceof String) { // a CLASSPATH resource URL url = getResource((String)name); if (url != null) { if (!quiet) { LOG.info("parsing " + url); } doc = builder.parse(url.toString()); } } else if (name instanceof Path) { // a file resource // Can't use FileSystem API or we get an infinite loop // since FileSystem uses Configuration API. Use java.io.File instead. File file = new File(((Path)name).toUri().getPath()) .getAbsoluteFile(); if (file.exists()) { if (!quiet) { LOG.info("parsing " + file); } InputStream in = new BufferedInputStream(new FileInputStream(file)); try { doc = builder.parse(in); } finally { in.close(); } } } else if (name instanceof InputStream) { try { doc = builder.parse((InputStream)name); } finally { ((InputStream)name).close(); } } else if (name instanceof Element) { root = (Element)name; } if (doc == null && root == null) { if (quiet) return; throw new RuntimeException(name + " not found"); } if (root == null) { root = doc.getDocumentElement(); } if (!"configuration".equals(root.getTagName())) LOG.fatal("bad conf file: top-level element not <configuration>"); NodeList props = root.getChildNodes(); for (int i = 0; i < props.getLength(); i++) { Node propNode = props.item(i); if (!(propNode instanceof Element)) continue; Element prop = (Element)propNode; if ("configuration".equals(prop.getTagName())) { loadResource(properties, prop, quiet); continue; } if (!"property".equals(prop.getTagName())) LOG.warn("bad conf file: element not <property>"); NodeList fields = prop.getChildNodes(); String attr = null; String value = null; boolean finalParameter = false; for (int j = 0; j < fields.getLength(); j++) { Node fieldNode = fields.item(j); if (!(fieldNode instanceof Element)) continue; Element field = (Element)fieldNode; if ("name".equals(field.getTagName()) && field.hasChildNodes()) attr = ((Text)field.getFirstChild()).getData().trim(); if ("value".equals(field.getTagName()) && field.hasChildNodes()) value = ((Text)field.getFirstChild()).getData(); if ("final".equals(field.getTagName()) && field.hasChildNodes()) finalParameter = "true".equals(((Text)field.getFirstChild()).getData()); } // Ignore this parameter if it has already been marked as 'final' if (attr != null) { if (value != null) { if (!finalParameters.contains(attr)) { properties.setProperty(attr, value); if (storeResource) { updatingResource.put(attr, name.toString()); } } else if (!value.equals(properties.getProperty(attr))) { d0cc LOG.warn(name+":a attempt to override final parameter: "+attr +"; Ignoring."); } } if (finalParameter) { finalParameters.add(attr); } } } } catch (IOException e) { LOG.fatal("error parsing conf file: " + e); throw new RuntimeException(e); } catch (DOMException e) { LOG.fatal("error parsing conf file: " + e); throw new RuntimeException(e); } catch (SAXException e) { LOG.fatal("error parsing conf file: " + e); throw new RuntimeException(e); } catch (ParserConfigurationException e) { LOG.fatal("error parsing conf file: " + e); throw new RuntimeException(e); } }
使用get*和set*访问和设置配置项
get方法在Configuration对象中获取相应的配置信息。
public String get(String name, String defaultValue)
Configuration.get()会调用Conguration的私有方法substituteVars(),完成配置属性的扩展,也就是把包含${key}这种格式的变量,自动替换成对应的值。substituteVars的工作依赖于正则表达式:
varPat: $\\{[^\\}\$\u0020]+\}
如果一次属性扩展完成以后,得到的表达式里仍然包含可扩展的变量,那么,substituteVars()需要再次进行属性扩展。为了避免进入死循环,substituteVars()使用一个非常简单而有效的策略,即属性扩展只能进行一次的次数(20次,通过Configuration的静态成员变量MAX_SUBST定义)。
private String substituteVars(String expr) { if (expr == null) { return null; } Matcher match = varPat.matcher(""); String eval = expr; for(int s=0; s<MAX_SUBST; s++) { match.reset(eval); if (!match.find()) { return eval; } String var = match.group(); var = var.substring(2, var.length()-1); // remove ${ .. } String val = null; try { val = System.getProperty(var); } catch(SecurityException se) { LOG.warn("Unexpected SecurityException in Configuration", se); } if (val == null) { val = getRaw(var); } if (val == null) { return eval; // return literal ${var}: var is unbound } // substitute eval = eval.substring(0, match.start())+val+eval.substring(match.end()); } throw new IllegalStateException("Variable substitution depth too large: " + MAX_SUBST + " " + expr); }
相关文章推荐
- Hadoop技术内幕——Hadoop配置信息处理
- Hadoop详解(七)——Hive的原理和安装配置和UDF,flume的安装和配置以及简单使用,flume+hive+Hadoop进行日志处理
- 2.hadoop配置信息处理
- Hadoop技术内幕——Hadoop配置信息处理
- Hadoop配置信息处理
- Hadoop技术内幕——Hadoop配置信息处理
- Hadoop技术内幕-Hadoop配置信息处理
- Log4j配置学习文档之二 处理日滚文件-实现原理
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[上篇]
- [InfoPath] 如何配置实现InfoPath的大小类的联动和信息查询?
- MOSS字段编辑权限控制方案的实现(1)-管理页面的开发和配置信息的持久化
- jQuery的实现原理的模拟代码 -3 事件处理
- [原创] WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[上篇]
- 【视频】配置信息管理 的 使用方法(六):实现添加、修改、查询
- MOSS字段编辑权限控制方案的实现(1)-管理页面的开发和配置信息的持久化
- 【视频】配置信息管理 的 使用方法(六):实现添加、修改、查询
- 遭遇:“说明: 在处理向该请求提供服务所需的配置文件时出错。请检查下面的特定错误详细信息并适当地修改配置文件。”错误
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
- [原创] WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
- 动态获取Nhibernate的ORM配置信息,实现系统历史记录功能