我为Hadoop(2.7.1)名称节点和数据节点分别设置了Docker(1.9.1)映像。我可以从这些容器中创建容器,并使它们通过用户定义的Docker网络进行通信。但是,datanode似乎报告自己具有网络网关的IP地址,而不是其自己的IP地址。虽然这不会对单个数据节点造成任何问题,但是在添加其他数据节点时,仍然会引起混乱。它们都使用相同的IP地址注册,并且名称节点在它们之间翻转,仅报告单个数据节点处于活动状态。
在用户定义的Docker网络上运行时,为什么服务器(名称节点)从客户端(数据节点)套接字连接中读取错误的IP地址,我该如何解决?
更新:此问题似乎在Docker方面
运行两个容器--net=bridge
并执行一个netcat服务器:
nc -v -l 9000
在一个容器中,在另一个容器中,一个netcat客户端:
nc 172.17.0.2 9000
使第一个容器正确打印:
接受来自 **172.17.0.3** 端口9000 [tcp / 9000]的连接
但是创建一个用户定义的网络:
sudo docker network create --driver bridge test
并在以--net=test
错误开头的容器中执行相同的命令会错误打印网关/用户定义的网络接口的IP地址:
接受来自 **172.18.0.1** 端口9000 [tcp / 9000]的连接
HDFS / Docker详细信息
dfs.datanode.address
每个数据节点hdfs-site.xml
文件中的属性均设置为其主机名(例如hdfs- datanode-1
)。
网络是这样创建的:
sudo docker network create --driver bridge hadoop-network
namenode像这样开始:
sudo docker run -d \
--name hdfs-namenode \
-v /hdfs/name:/hdfs-name \
--net=hadoop-network \
--hostname hdfs-namenode \
-p 50070:50070 \
hadoop:namenode
并且datanode像这样开始:
sudo docker run -d \
--name hdfs-datanode-1 \
-v /hdfs/data_1:/hdfs-data \
--net=hadoop-network \
--hostname=hdfs-datanode-1 \
--restart=always \
hadoop:datanode
两个节点连接良好,当查询(使用sudo docker exec hdfs-namenode hdfs dfsadmin -report
)时,连接性报告为:
...
实时数据节点(1):
名称: **172.18.0.1** :50010(172.18.0.1)
主机名: **hdfs-datanode-1**
...
但是,正在运行的输出:
sudo docker exec hdfs-namenode cat /etc/hosts
表示namenode认为它正在运行,172.18.0.2
而datanode在以下运行172.18.0.3
:
**172.18.0.2 hdfs-namenode**
127.0.0.1本地主机
:: 1 localhost ip6-localhost ip6-loopback
fe00 :: 0 ip6-localnet
ff00 :: 0 ip6-mcastprefix
ff02 :: 1 ip6-allnodes
ff02 :: 2 ip6-allrouters
**172.18.0.3 hdfs-datanode-1**
172.18.0.3 hdfs-datanode-1.hadoop-network
并且datanode上的等效项显示相同:
**172.18.0.3 hdfs-datanode-1**
127.0.0.1本地主机
:: 1 localhost ip6-localhost ip6-loopback
fe00 :: 0 ip6-localnet
ff00 :: 0 ip6-mcastprefix
ff02 :: 1 ip6-allnodes
ff02 :: 2 ip6-allrouters
**172.18.0.2 hdfs-namenode**
172.18.0.2 hdfs-namenode.hadoop-network
ip route
两者都运行可以确认:
sudo docker exec hdfs-namenode ip route
默认通过172.18.0.1 dev eth0
172.18.0.0/16 dev eth0原始内核作用域链接 **src 172.18.0.2**
sudo docker exec hdfs-datanode-1 ip route
默认通过172.18.0.1 dev eth0
172.18.0.0/16 dev eth0原始内核作用域链接src **172.18.0.3**
然而,当数据节点启动时,名称节点将数据节点的IP地址报告为172.18.0.1
:
... INFO hdfs.StateChange:BLOCK * registerDatanode:来自DatanodeRegistration( **172.18.0.1:50010,datanodeUuid** = 3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3,infoPort = 50075,infoSecurePort = 0,ipcPort = 50020,storageInfo = lv =- 56; cid = CID-60401abd-4793-4acf-94dc-e8db02b27d59; nsid = 1824008146; c = 0)存储3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3
... INFO blockmanagement.DatanodeDescriptor:失败的存储数量从0更改为0
... INFO net.NetworkTopology:添加新节点:/默认机架/ **172.18.0.1** :50010
... INFO blockmanagement.DatanodeDescriptor:失败的存储数量从0更改为0
... INFO blockmanagement.DatanodeDescriptor:为DN **172.18.0.1:50010** 添加新的存储ID DS-4ba1a710-a4ca-4cad-8222- cc5f16c213fb
... INFO BlockStateChange:BLOCK *过程报告:来自存储DS-4ba1a710-a4ca-4cad-8222-cc5f16c213fb节点DatanodeRegistration( **172.18.0.1:50010,datanodeUuid** = 3abaf40c-4ce6-47e7-be2b-fbb4a7eba0e3,infoPort = 50075,infoSecurePort 0,ipcPort = 50020,storageInfo = lv = -56; cid = CID-60401abd-4793-4acf-94dc-e8db02b27d59; nsid = 1824008146; c = 0),块:1,hasStaleStorage:false,处理时间:3毫秒
并且使用tcpdump
捕获两者之间的流量(在连接到主机网络的Docker容器中运行-使用docker run --net=host
)似乎表明发生了错误(br-b59d498905c5
是Docker为Docker创建的网络接口的名称hadoop- network
):
tcpdump -nnvvXS -s0 -i br-b59d498905c5 \
"(src host 172.18.0.3 or src host 172.18.0.2) and \
(dst host 172.18.0.3 or dst host 172.18.0.2)"
IP地址似乎在registerDatanode
呼叫中正确发送:
...
172.18.0.3.33987> 172.18.0.2.9000:...
...
0x0050:f828 004d 0a10 7265 6769 7374 6572 4461。(。M..registerDa
0x0060:7461 6e6f 6465 1237 6f72 672e 6170 6163 tanode.7org.apac
0x0070:6865 2e68 6164 6f6f 702e 6864 6673 2e73 he.hadoop.hdfs.s
0x0080:6572 7665 722e 7072 6f74 6f63 6f6c 2e44 erver.protocol.D
0x0090:6174 616e 6f64 6550 726f 746f 636f 6c18 atanode协议。
0x00a0:01a7 010a a401 0a51 0a0a 3137 322e 3138 ....... Q .. **172.18**
0x00b0:2e30 2e33 120f 6864 6673 2d64 6174 616e **.0.3** .. **hdfs-**
datan 0x00c0:6f64 652d 311a 2433 6162 **6ode** 3430 **1。** $ 3abaf40c-
...
但是在随后的通话中这是不正确的。例如,在sendHeartbeat
通话之后一秒钟的时间:
...
172.18.0.3.33987> 172.18.0.2.9000:...
...
0x0050:f828 004a 0a0d 7365 6e64 4865 6172 7462 .... sendHeartb
0x0060:6561 7412 376f 7267 2e61 7061 6368 652e eat.7org.apache。
0x0070:6861 646f 6f70 2e68 6466 732e 7365 7276 hadoop.hdfs.serv
0x0080:6572 2e70 726f 746f 636f 6c2e 4461 7461 er.protocol.Data
0x0090:6e6f 6465 5072 6f74 6f63 6f6c 1801 9d02 nodeProtocol ....
0x00a0:0aa4 010a 510a 0a31 3732 2e31 382e 302e .... Q .. **172.18.0。**
0x00b0:3112 0f68 6466 732d 6461 7461 6e6f 6465 **1** .. **hdfs-datanode**
0x00c0:2d31 1a24 3361 6261 6634 3063 2d34 6365 **-1** 。$ 3abaf40c-4ce
...
通过datanode代码进行的调试清楚地显示了根据namenode返回的信息更新datanode注册详细信息BPServiceActor.register()
时发生的错误:
bpRegistration = bpNamenode.registerDatanode(bpRegistration);
调试namenode 表示它从datanode套接字连接中读取了
错误的 IP地址,并更新了datanode注册详细信息。
补充笔记
我可以在用户定义的Docker网络上运行以下代码来重现该问题:
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
// 9000 is the namenode port
ServerSocket server = new ServerSocket(9000);
Socket socket = server.accept();
System.out.println(socket.getInetAddress().getHostAddress());
}
}
和
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception {
// 172.18.0.2 is the namenode IP address
Socket socket = new Socket("172.18.0.2", 9000);
}
}
与这两个Server
和Client
运行在172.18.0.2
这个正确的输出172.18.0.2
,但与Client
上运行172.18.0.3
它错误地输出172.18.0.1
。
在不使用用户定义的网络的情况下运行相同的代码(在默认的bridge
网络/ docker0
接口上并公开port 9000
)可以提供正确的输出。
我在namenode的文件中将dfs.namenode.datanode.registration.ip-hostname- check
属性设置为false
,hdfs- site.xml
以防止反向DNS查找错误。如果我可以使用DNS,那么将来可能不需要这样做,但是现在,由于数据节点报告了错误的IP地址,我怀疑使用DNS会有所帮助。
我相信相关的有线协议registerDatanode
,sendHeartbeat
并且blockReport
都是RegisterDatanodeRequestProto
,HeartbeatRequestProto
而且BlockReportRequestProto
和他们的定义可以在这里找到。这些都包含DatanodeRegistrationProto
为其第一个数据成员。此消息在此处定义,如下所示:
/**
* Identifies a Datanode
*/
message DatanodeIDProto {
required string ipAddr = 1; // IP address
required string hostName = 2; // hostname
...
}
这是由一个已知的docker问题引起的(我也提出了并关闭了此重复描述了问题中所述步骤的副本)。
有一个合并的拉取请求可以解决此问题,并已计划将其包含在Docker
1.10.0中。但是与此同时,可以使用以下解决方法:
sudo docker network rm
sudo service docker stop
sudo iptables -F && sudo iptables -F -t nat
sudo service docker start
使用运行两个容器并执行netcat服务器: 在一个容器中,而在另一个容器中是netcat客户端: 使第一个容器正确打印: 数据阳极是这样开始的: 这两个节点连接良好,当查询时(使用),连接情况报告为: 但是,运行的输出: 但是,当datanode启动时,namenode报告datanode的IP地址为: 并且使用捕获两者之间的通信量(运行在连接到主机网络的Docker容器中-使用)似乎显示发生了错
这是错误: 照明\数据库\查询异常SQLSTATE[42S22]:找不到列: 1054未知列"在'where子句'(SQL:选择计数(*)作为聚合从在哪里"=user@email.com) 我的Resgister控制器: }我的用户表迁移:
当我的网卡连接到网络A时,我正在启动我的RMI服务器。运行我的客户端按预期成功并打印“Hello World”。一旦我将网络连接更改为网络B(无需重新启动RMI服务器!)我无法再连接到服务器。服务器和客户端总是在同一台主机上运行,所以使用localhost地址就足够了。 服务器: 客户: 例外是: 它指的是在连接到网络A时分配给我的IP地址。注册表查找按预期工作,只有对的调用失败,但有上述异常。
问题内容: 节点程序员通常使用这样的范例: 为什么不简化该函数以仅接受一个参数(错误或响应)呢? 似乎更简单。我唯一看到的缺点是函数不能将错误返回为它们的实际预期返回值-但我认为这是一个非常微不足道的用例。 为什么错误优先模式被认为是标准的? 编辑:的实现: 另一个编辑:是否有可能我的替代方法比节点约定更方便,因为仅接受一个参数的回调也更有可能在非回调用例中重用? 问题答案: (有关使用该问题的回
问题内容: 尝试这样做并遇到很多两种类型的错误: 第一:500 当我在浏览器中访问这些URL时,收到以下消息: 内部路由错误 抱歉,我们无法连接到目标服务器。 我们刚刚收到有关此问题的通知。我们将尽快更正。 如有任何疑问,请随时与我们联系:support@iriscouch.com 第二名:503 当我在浏览器中访问这些URL时,收到以下消息: 错误503后端读取错误 后端读取错误 大师冥想: X
有一个非常有趣的错误,我不知道如何解决。在我注册为新用户并单击submit按钮后,我得到以下错误块: 注意:在第153行的public_html/mystore/系统/库/mail.php中遇到非格式良好的数值注意:在第153行的public_html/mystore/系统/库/mail.php中遇到非格式良好的数值警告:无法修改标头信息-标头已发送由(输出开始于public_html/mysto