[TOC]
一、RPC基本概念
1、RPC是什么
所谓的RPC其实是为了不同主机的两个进程间通信而产生的,通常不同的主机之间的进程通信,那么程序编写则需要考虑到网络通信的功能,这样程序的编写将会变得复杂。而RPC就是报文交换的一种机制,一台主机上的进程对另外一台主机的进程发起请求时,内核会将请求转交给RPC client,RPC client经过报文的封装转交给目标主机的RPC server,RPC server就将报文进行解析,还原成正常的请求,转交给目标主机上的目标进程。所以在两台主机的两个进程看来,就像是在同一台主机上的两个进程通信一样,完全没有意识到是在不同的主机上。所以说RPC其实也是一种协议或者是编程框架,简化了分布式程序的编写。
而hadoop作为一个典型的分布式项目,跨主机调用服务的情况很常见(并非http服务)。我们要清楚一点,通过http这些restfulapi的方式暴露的服务,调用者是明显知道被调用者是在不同的主机上。而通过RPC调用的话,在调用者看来,他以为被调用者是在同一台主机上的,但是实际上是在不同主机上的。
2、RPC基本流程
1、首先调用方需要有个RPCclient,被调用方需要有 RCPServer,这两个服务用于RPC通信。
2、调用者通过RPCClient调用指定方法,RPCClient则将请求封装后(将方法参数值进行二进制序列化),传递给server
3、server收到请求后,反序列化参数,恢复成请求原本的形式,然后找到对应的方法进行本地调用。将方法的返回值通过RPC返回给client
4、client收到结果后,将结果返回给调用者作为返回值。
二、hadoop的RPC
1、hdfs的RPC基本流程
hdfs的rpc流程基本如上,其中的关键就是获得NameNode代理对象。
2、java中的代理方式
(1)静态代理
先定义一个公共接口,里面包括了可以通过RPC调用的方法列表。而且被代理对象以及对象本身都需要实现该接口
(2)动态代理
先定义一个公共接口,里面包括了可以通过RPC调用的方法列表。被代理对象以及对象本身都不需要实现该接口。而是通过匿名内部类+反射的机制实现。hadoop就是使用这种方式
3、hadoop rpc框架的例子
例子结构:
Server
MyImpl.java server本地执行的方法的具体实现代码
MyInterface.java 可以rpc执行的方法列表
MyRpcServer.java rpc server端
Client
MyRpcClient.java rpc client端
Server:
/*
MyInterface.java
*/
package Server;
import org.apache.hadoop.ipc.VersionedProtocol;
public interface MyInterface extends VersionedProtocol {
public static long versionID = 1001; //这个是标记RPC的client和server对应的标记
public String helloWorld(String name);
}
/*
MyImpl.java
*/
package Server;
import org.apache.hadoop.ipc.ProtocolSignature;
import java.io.IOException;
public class MyImpl implements MyInterface{
/*这是实际目标*/
//重写我们在上面接口自定义的方法
@Override
public String helloWorld(String name) {
return "hello," + name;
}
//返回版本号
@Override
public long getProtocolVersion(String s, long l) throws IOException {
return MyInterface.versionID;
}
//返回签名信息
@Override
public ProtocolSignature getProtocolSignature(String s, long l, int i) throws IOException {
return new ProtocolSignature(MyInterface.versionID, null);
}
}
/*
MyRpcServer.java
*/
package Server;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import java.io.IOException;
public class MyRpcServer {
public static void main(String[] args) {
//建立rpc通道对象
RPC.Builder builder = new RPC.Builder(new Configuration());
//设置RPC server参数
builder.setBindAddress("localhost");
builder.setPort(7788);
//部署程序,传入实现server业务代码的接口定义,这里面包括了该rpcserver 可以提供的方法,也就是给client调用的方法列表,通过反射的方式引入类对象
builder.setProtocol(MyInterface.class);
//部署接口的实现类对象
builder.setInstance(new MyImpl());
//开启server
try {
RPC.Server server = builder.build();
server.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
client:
/*
MyRpcClient.java
*/
package Client;
import Server.MyInterface;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import java.io.IOException;
import java.net.InetSocketAddress;
public class MyRpcClient {
public static void main(String[] args) {
try {
//获取代理对象,设置接口类对象、RPC通信的versionID,rpcserver地址、configuration对象
MyInterface proxy = RPC.getProxy(
MyInterface.class,
MyInterface.versionID,
new InetSocketAddress("localhost", 7788),
new Configuration());
//获得代理对象之后,就可以通过proxy调用接口类中的方法,这里就调用上面定义的 helloWorld对象
System.out.println(proxy.helloWorld("king"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
下面启动server端和client端,执行结果为:
//server:可以看到显示监听端口 7788
[main] INFO org.apache.hadoop.ipc.CallQueueManager - Using callQueue: class java.util.concurrent.LinkedBlockingQueue queueCapacity: 100 scheduler: class org.apache.hadoop.ipc.DefaultRpcScheduler
[Socket Reader #1 for port 7788] INFO org.apache.hadoop.ipc.Server - Starting Socket Reader #1 for port 7788
[IPC Server Responder] INFO org.apache.hadoop.ipc.Server - IPC Server Responder: starting
[IPC Server listener on 7788] INFO org.apache.hadoop.ipc.Server - IPC Server listener on 7788: starting
//client: 我们传入“King”作为参数,能够争取执行
hello,king
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/192180.html