Hadoop配置机架感知
1. 引言
机架感知是 Hadoop 集群中的重要配置,它能让 NameNode 了解 DataNode 的物理位置(机架信息),从而在数据副本放置时考虑网络拓扑,提高数据可靠性和读取性能。本文将详细介绍 Hadoop 机架感知的配置方法。
2. 配置步骤
2.1 修改 core-site.xml
在 Hadoop 的配置文件中添加机架感知脚本路径:
<property> <name>net.topology.script.file.name</name> <value>/path/to/RackAware.py</value> </property>将/path/to/RackAware.py替换为实际的脚本路径。
2.2 创建机架感知脚本
创建RackAware.py脚本,内容如下:
#!/usr/bin/python # -*- coding: UTF-8 -*- import sys 主机名/IP地址到机架的映射表 rack = { "bs022.zx.nicx.cn": "rack1", "bs035.zx.nicx.cn": "rack2", "bs038.zx.nicx.cn": "rack2", "bs042.zx.nicx.cn": "rack3", "192.168.1.22": "rack1", "192.168.1.35": "rack2", "192.168.1.38": "rack2", "192.168.1.42": "rack3", } if name == "main": # 获取传入的主机名或IP地址参数 host = sys.argv[1] # 返回对应的机架路径 print("/" + rack.get(host, "default"))上述脚本使用硬编码的映射表,适用于小型固定集群。对于大型或动态变化的集群,建议使用以下更通用的脚本,支持从配置文件读取映射关系:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Hadoop 机架感知脚本 - 通用配置驱动版本 支持从 JSON/YAML 配置文件动态读取主机-机架映射关系 """ import sys import os import json import yaml import argparse from typing import Dict, Optional class RackAwarenessResolver: """机架感知解析器,支持多种配置源""" def __init__(self, config_path: str = None): """ 初始化解析器 Args: config_path: 配置文件路径,支持 JSON/YAML 格式 如果为 None,则使用默认配置文件路径 """ self.config_path = config_path or "/etc/hadoop/rack_mapping.conf" self.mapping = self._load_mapping() def _load_mapping(self) -> Dict[str, str]: """从配置文件加载主机-机架映射关系""" mapping = {} # 尝试从配置文件加载 if os.path.exists(self.config_path): try: with open(self.config_path, 'r', encoding='utf-8') as f: content = f.read().strip() # 根据文件扩展名选择解析器 if self.config_path.endswith('.json'): config = json.loads(content) mapping = config.get('rack_mapping', {}) elif self.config_path.endswith(('.yaml', '.yml')): config = yaml.safe_load(content) mapping = config.get('rack_mapping', {}) else: # 纯文本格式:每行 "主机名/IP 机架名" for line in content.split('\n'): line = line.strip() if line and not line.startswith('#'): parts = line.split() if len(parts) &gt;= 2: host, rack = parts[0], parts[1] mapping[host] = rack print(f"[INFO] 从 {self.config_path} 加载了 {len(mapping)} 条映射规则", file=sys.stderr) except Exception as e: print(f"[ERROR] 加载配置文件失败: {e}", file=sys.stderr) # 使用默认映射作为后备 mapping = self._get_default_mapping() else: print(f"[WARN] 配置文件 {self.config_path} 不存在,使用默认映射", file=sys.stderr) mapping = self._get_default_mapping() return mapping def _get_default_mapping(self) -> Dict[str, str]: """获取默认的硬编码映射(兼容旧脚本)""" return { "bs022.zx.nicx.cn": "rack1", "bs035.zx.nicx.cn": "rack2", "bs038.zx.nicx.cn": "rack2", "bs042.zx.nicx.cn": "rack3", "192.168.1.22": "rack1", "192.168.1.35": "rack2", "192.168.1.38": "rack2", "192.168.1.42": "rack3", } def resolve_rack(self, host: str) -> str: """ 解析主机名/IP地址对应的机架 Args: host: 主机名或IP地址 Returns: 机架名称,如果未找到则返回 "default" """ # 首先尝试精确匹配 rack = self.mapping.get(host) if rack: return rack # 如果未找到,尝试通过域名匹配(支持通配符) for pattern, rack_name in self.mapping.items(): if '*' in pattern: # 简单的通配符匹配:*.example.com if pattern.startswith('*.'): domain = pattern[2:] if host.endswith(domain): return rack_name # 最后尝试通过IP段匹配(例如 192.168.1.*) for pattern, rack_name in self.mapping.items(): if '*' in pattern and '.' in host: # 简单的IP段匹配 pattern_parts = pattern.split('.') host_parts = host.split('.') if len(pattern_parts) == len(host_parts): match = True for p, h in zip(pattern_parts, host_parts): if p != '*' and p != h: match = False break if match: return rack_name return "default" def get_rack_path(self, host: str) -> str: """获取完整的机架路径(以 / 开头)""" rack = self.resolve_rack(host) return f"/{rack}" def main(): """主函数:解析命令行参数并输出机架路径""" parser = argparse.ArgumentParser( description='Hadoop 机架感知脚本 - 动态配置版本', epilog='示例: python RackAware.py --config /path/to/config.yaml bs022.zx.nicx.cn' ) parser.add_argument( 'host', help='要查询的主机名或IP地址' ) parser.add_argument( '--config', '-c', help='配置文件路径(支持 JSON/YAML/文本格式)', default=None ) parser.add_argument( '--verbose', '-v', action='store_true', help='显示详细日志信息' ) args = parser.parse_args() 创建解析器实例 resolver = RackAwarenessResolver(args.config) 解析机架路径 rack_path = resolver.get_rack_path(args.host) 输出结果(Hadoop 期望的格式) print(rack_path) 详细模式输出调试信息 if args.verbose: print(f"[DEBUG] 主机: {args.host}", file=sys.stderr) print(f"[DEBUG] 机架路径: {rack_path}", file=sys.stderr) print(f"[DEBUG] 总映射规则数: {len(resolver.mapping)}", file=sys.stderr) if name == "main": main()3. 验证配置
配置完成后,重启 Hadoop 服务,然后执行以下命令验证机架感知是否生效:
bin/hdfs dfsadmin -printTopology预期输出如下:
Rack: /rack1 192.168.1.22:50010 (bs022.zx.nicx.cn) Rack: /rack2 192.168.1.35:50010 (bs035.zx.nicx.cn) 192.168.1.38:50010 (bs038.zx.nicx.cn) Rack: /rack3 192.168.1.42:50010 (bs042.zx.nicx.cn)4. 注意事项
- 脚本兼容性:机架感知脚本需要同时支持主机名和 IP 地址,确保集群中所有节点都能正确映射。
- 脚本权限:确保
RackAware.py具有可执行权限:chmod +x RackAware.py - 日志验证:检查 NameNode 日志,确认机架信息已正确识别:
2016-07-04 14:42:22,198 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /rack0/218.241.108.38:50010 2016-07-04 14:42:22,232 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /rack0/218.241.108.35:50010 2016-07-04 14:42:22,263 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /rack0/218.241.108.42:50010 2016-07-04 14:42:22,295 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /rack0/218.241.108.22:50010 2016-07-04 14:42:52,503 INFO org.apache.hadoop.hdfs.StateChange: STATE* Network topology has 1 racks and 4 datanodes5. 总结
机架感知配置完成后,Hadoop 能够根据网络拓扑优化数据副本的放置策略,提高数据的可靠性和读取效率。配置时需注意脚本的兼容性和权限设置,并通过日志和命令验证配置是否生效。