hadoop2.7.3源码解析之hadoop RPC使用
来源:互联网 发布:海宁淘宝摄影 编辑:程序博客网 时间:2024/06/06 00:16
- 概述
- namenode提供服务
- 客户端获取代理
- 客户端具体的发送数据流程
- ClientNamenodeProtocolPB序列化相应的方法
- 发送序列化之后的数据
- 服务端反序列化
概述
在以前的博客中,我简单的介绍了一下hadoop rpc框架的实现流程(http://blog.csdn.net/zhangjun5965/article/details/59653549),这一小节主要介绍一下在hdfs中,是如何运用这个rpc框架进行通讯的。
首先回顾一下使用hadoop rpc的主要流程
- 首先定义client和server交互的接口(如client和namenode的ClientProtocol)
- 服务器端实现接口(如namenode提供服务的NameNodeRpcServer类)
- 服务器端启动服务。(通过RPC.Builder(conf).build())
- 客户端获取接口的代理,执行相关的方法。
下面我们简单讲解一下rpc框架在hadoop的具体使用
namenode提供服务
namenode用于对外提供rpc服务的是NameNodeRpcServe类,这个类实现了NamenodeProtocols接口,NamenodeProtocols定义了NamenodeProtocols需要实现的所有的接口。
比如客户端和namenode交互的ClientProtocol、datanode和namenode交互的DatanodeProtocol,用于提供ha服务的HAServiceProtocol等。
/** The full set of RPC methods implemented by the Namenode. */@InterfaceAudience.Privatepublic interface NamenodeProtocols extends ClientProtocol, DatanodeProtocol, NamenodeProtocol, RefreshAuthorizationPolicyProtocol, RefreshUserMappingsProtocol, RefreshCallQueueProtocol, GenericRefreshProtocol, GetUserMappingsProtocol, HAServiceProtocol, TraceAdminProtocol {}
此外,我们在这个类中看到他的内部定义了两个rpc服务,一个是针对客户端的,一个是针对namenode的
/** The RPC server that listens to requests from DataNodes */ private final RPC.Server serviceRpcServer; private final InetSocketAddress serviceRPCAddress; /** The RPC server that listens to requests from clients */ protected final RPC.Server clientRpcServer; protected final InetSocketAddress clientRpcAddress;
在构造方法中,实例化了这两个变量
this.serviceRpcServer = new RPC.Builder(conf) .setProtocol( org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolPB.class) .setInstance(clientNNPbService) .setBindAddress(bindHost) .setPort(serviceRpcAddr.getPort()).setNumHandlers(serviceHandlerCount) .setVerbose(false) .setSecretManager(namesystem.getDelegationTokenSecretManager()) .build();............................clientNNPbService).setBindAddress(bindHost) .setPort(rpcAddr.getPort()).setNumHandlers(handlerCount) .setVerbose(false) .setSecretManager(namesystem.getDelegationTokenSecretManager()).build();
在start方法中启动了这两个服务。根据代码,发现是在namenode和BackupNode在启动的时候调用了start方法,也就是说这两个服务是在namenode启动的时候初始化的。
客户端获取代理
不管是创建文件,还是删除,都是先通过FileSystem.get(conf)来首先获取具体的的文件系统,FileSystem会根据传入的conf来进行适配,比如hdfs://开头的就实例化DistributedFileSystem,最终通过FileSystem.createFileSystem(URI, Configuration)来初始化具体的文件系统。
private static FileSystem createFileSystem(URI uri, Configuration conf ) throws IOException { Class<?> clazz = getFileSystemClass(uri.getScheme(), conf); FileSystem fs = (FileSystem)ReflectionUtils.newInstance(clazz, conf); fs.initialize(uri, conf); return fs; }
对于DistributedFileSystem来说, fs.initialize(uri, conf);当然就是调用了
DistributedFileSystem.initialize(URI, Configuration)方法,在这里构造了一个DFSClient对象,客户端所有的操作都是通过它来完成的。
@Override public void initialize(URI uri, Configuration conf) throws IOException { super.initialize(uri, conf); setConf(conf); String host = uri.getHost(); if (host == null) { throw new IOException("Incomplete HDFS URI, no host: "+ uri); } homeDirPrefix = conf.get( DFSConfigKeys.DFS_USER_HOME_DIR_PREFIX_KEY, DFSConfigKeys.DFS_USER_HOME_DIR_PREFIX_DEFAULT); this.dfs = new DFSClient(uri, conf, statistics); this.uri = URI.create(uri.getScheme()+"://"+uri.getAuthority()); this.workingDir = getHomeDirectory(); }
在DFSClient的构造方法里,获取了namenode的代理对象,用于和namenode进行交互。
Preconditions.checkArgument(nameNodeUri != null, "null URI"); proxyInfo = NameNodeProxies.createProxy(conf, nameNodeUri, ClientProtocol.class, nnFallbackToSimpleAuth); this.dtService = proxyInfo.getDelegationTokenService(); this.namenode = proxyInfo.getProxy();
在createProxy方法里,通过查询配置文件获取是否配置了HA,来分别获取不同的代理,为了简单理解,我们现在只说一下非HA的情况。非HA的情况是调用了NameNodeProxies.createNonHAProxy(Configuration, InetSocketAddress, Class, UserGroupInformation, boolean, AtomicBoolean)来获取相应的代理。
在这,主要是针对不同的协议来分别获取不同的代理,
public static <T> ProxyAndInfo<T> createNonHAProxy( Configuration conf, InetSocketAddress nnAddr, Class<T> xface, UserGroupInformation ugi, boolean withRetries, AtomicBoolean fallbackToSimpleAuth) throws IOException { Text dtService = SecurityUtil.buildTokenService(nnAddr); T proxy; if (xface == ClientProtocol.class) { proxy = (T) createNNProxyWithClientProtocol(nnAddr, conf, ugi, withRetries, fallbackToSimpleAuth); } else if (xface == JournalProtocol.class) { proxy = (T) createNNProxyWithJournalProtocol(nnAddr, conf, ugi); } else if (xface == NamenodeProtocol.class) { proxy = (T) createNNProxyWithNamenodeProtocol(nnAddr, conf, ugi, withRetries); } else if (xface == GetUserMappingsProtocol.class) { proxy = (T) createNNProxyWithGetUserMappingsProtocol(nnAddr, conf, ugi); } else if (xface == RefreshUserMappingsProtocol.class) { proxy = (T) createNNProxyWithRefreshUserMappingsProtocol(nnAddr, conf, ugi); } else if (xface == RefreshAuthorizationPolicyProtocol.class) { proxy = (T) createNNProxyWithRefreshAuthorizationPolicyProtocol(nnAddr, conf, ugi); } else if (xface == RefreshCallQueueProtocol.class) { proxy = (T) createNNProxyWithRefreshCallQueueProtocol(nnAddr, conf, ugi); } else { String message = "Unsupported protocol found when creating the proxy " + "connection to NameNode: " + ((xface != null) ? xface.getClass().getName() : "null"); LOG.error(message); throw new IllegalStateException(message); } return new ProxyAndInfo<T>(proxy, dtService, nnAddr); }
对于ClientProtocol接口来说,通过createNNProxyWithClientProtocol方法来获取,进入这个方法。
private static ClientProtocol createNNProxyWithClientProtocol( InetSocketAddress address, Configuration conf, UserGroupInformation ugi, boolean withRetries, AtomicBoolean fallbackToSimpleAuth) throws IOException { RPC.setProtocolEngine(conf, ClientNamenodeProtocolPB.class, ProtobufRpcEngine.class); final RetryPolicy defaultPolicy = RetryUtils.getDefaultRetryPolicy( conf, DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_ENABLED_KEY, DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_ENABLED_DEFAULT, DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_SPEC_KEY, DFSConfigKeys.DFS_CLIENT_RETRY_POLICY_SPEC_DEFAULT, SafeModeException.class); final long version = RPC.getProtocolVersion(ClientNamenodeProtocolPB.class); //首先获取了一个ClientNamenodeProtocolPB代理。 ClientNamenodeProtocolPB proxy = RPC.getProtocolProxy( ClientNamenodeProtocolPB.class, version, address, ugi, conf, NetUtils.getDefaultSocketFactory(conf), org.apache.hadoop.ipc.Client.getTimeout(conf), defaultPolicy, fallbackToSimpleAuth).getProxy(); //是否有重试机制 if (withRetries) { // create the proxy with retries Map<String, RetryPolicy> methodNameToPolicyMap = new HashMap<String, RetryPolicy>(); ClientProtocol translatorProxy = new ClientNamenodeProtocolTranslatorPB(proxy); return (ClientProtocol) RetryProxy.create( ClientProtocol.class, new DefaultFailoverProxyProvider<ClientProtocol>( ClientProtocol.class, translatorProxy), methodNameToPolicyMap, defaultPolicy); } else { return new ClientNamenodeProtocolTranslatorPB(proxy); } }
我们看到最后都是通过传入ClientNamenodeProtocolPB类型的参数proxy构造了一个ClientNamenodeProtocolTranslatorPB类型的接口代理。
client和namenode交互应该是ClientProtocol,可是为什么要中间再来一个ClientNamenodeProtocolPB接口呢,这就是下面我们要讲的东西了
客户端具体的发送数据流程
ClientNamenodeProtocolPB序列化相应的方法
client和namenode交互使用的是ClientProtocol接口,但是这个接口里面的方法的参数是java的类型,是无法在网络上传输的,所以需要进行序列化操作。所以就有了在客户端序列化操作的ClientNamenodeProtocolPB接口,ClientNamenodeProtocolPB采用了适配器模式对ClientProtocol对应的方法进行了一一的适配,将方法转换成可以在网络上传输的序列化之后的格式。
我们以delete方法为例,当调用了ClientProtocol的方法进行删除文件操作的时候,是先进入了oClientNamenodeProtocolTranslatorPB.delete(String, boolean)方法,用传进来的参数构造了一个DeleteRequestProto用于网络传输的对象。然后通过ClientNamenodeProtocolPB的delete方法来执行相应的操作。
发送序列化之后的数据
然后会在ClientNamenodeProtocolPB相应的代理的invoke方法里,通过client的call方法往服务器发送数据。
服务端反序列化
同样在服务器端也有一个用于反序列化的ClientNamenodeProtocolServerSideTranslatorPB类,用于将server接收的数据进行反序列化,然后在调用NameNodeRpcServer相应的方法执行相应的方法。
- hadoop2.7.3源码解析之hadoop RPC使用
- Hadoop源码解析之RPC协议
- hadoop源码解析之RPC分析
- Hadoop RPC 源码解析
- Hadoop 源码解析-rpc扩展
- Hadoop源码之RPC机制
- Hadoop RPC源码解析——RPC框架详解
- [jjzhu学hadoop]之hadoop2.7.3源码编译eclipse项目
- Hadoop RPC源码分析之Client
- Hadoop RPC源码分析之Server
- hadoop2.7.3源码解析之datanode注册和心跳机制
- hadoop2.7.3源码解析之HA架构分析
- spark源码解析 spark-core之rpc
- Hadoop DFS源码研究之---Hadoop RPC机制
- Hadoop RPC源码解析——Client类
- Hadoop RPC源码解析——Server类(一)
- Hadoop RPC源码解析——Server类(二)
- Hadoop RPC远程过程调用源码解析及实例
- 一步步深入Java底层原理(四)
- nginx出现413 request entity too large错误解决方法
- Android Activity生命周期
- 盒子模型
- spfa+vector
- hadoop2.7.3源码解析之hadoop RPC使用
- 每天一个linux命令(27):linux chmod命令
- POJ 1905 Expanding Rods(二分搜索)
- Codeforces Educational Codeforces Round 27
- 灰度发布
- 常用 Git 命令清单
- 【干货】Nginx高并发配置 + Linux服务器优化配置
- 程序员的Epic Fail [0]
- Fragement切换