分布式环境中Apache Thrift RPC的Java方法实现

时间:2017-02-17 09:39:50

标签: java rpc thrift

我项目的简要说明: 我正在编写一个名为" GreetingsNode"的java类,它在分布式环境中工作,其中有一个" managementNode",它就像服务存储库一样,接收和存储信息(其他节点的主机端口号和服务)以及由已注册服务提供的方法的RPC。如果节点可以应答RPC,则打开thrift套接字并在调用节点和应答节点之间建立连接,并且应答节点返回结果。

我使用Apache thrift作为IDL和RPC的框架。

现在问题。 My GreetingsNodeHandler类实现了一个包含单个方法的简单thrift接口" getHello(user)" (用户是包含节点名称的结构,它是GreetingsNode类的构造函数的参数)。 当连接到管理节点的GreetingsNode X生成该方法的RPC时,另一个注册的GreetingsNode必须回复消息" hello X"。

我没有正确理解如何实现返回结果的处理程序部分,因此我无法理解应该如何编写应该检查方法实现是否正常工作的junit测试。

像一个断言     assertEquals(client.getHello(user).getMessage()," Hello John Doe")

会起作用,但在我的情况下,我不知道如何把客户端部分......

GreetingService thrift服务的代码:

struct Message {
    1: string message   
}  

struct User {
    1: string name
}

service GreetingsService {
    Message getHello(1: User user)
}

必须实现GreetingsService方法的GreetingsServiceHandler代码getHello()

public class GreetingsServiceHandler implements GreetingsService.Iface {

private static Random random = new Random(10);
private ManagementService.Client managementClient;
private GreetingsService.Client helloClient;

@Override
public Message getHello(User user) throws TException {
    Message answer = null;
    // class ServiceProvider is generated by thrift, part of ManagementService thrift service 
    ServiceProvider provider = null; 
    List<ServiceProvider>providers = managementClient.getProvidersForService(user.name);

    if (providers.isEmpty())
        throw new NoProviderAvailableException(); //separate file contains Exception
    else {
        provider = providers.get(random.nextInt(providers.size()));
        //connection between nodes is established here
        TTransport helloTransport = new TSocket(provider.getHostName(), provider.getPort());
        TProtocol helloProtocol = new TBinaryProtocol(helloTransport);
        helloClient = new GreetingsService.Client(helloProtocol);
        helloTransport.open();

        // here lies my problem
        answer = helloClient.getHello(user);
        //if I use this instead, then helloClient variable is clearly not used, but of course I need it to answer the method call
        answer = answer.setMessage("Ciao " + user.getName() + ", welcome among us!");

    }
    return answer;

}

和GreetingsNode代码如下:

public class GreetingsNode implements NodeIface {

private ThriftServer helloServer;
private ManagementService.Client managementClient;
private NodeManifest nodeManifest;
private User user;
private String name;

public GreetingsNode(NodeManifest nodeManifest, String name) {
    this.nodeManifest = nodeManifest;
    this.helloServer = new ThriftServer(GreetingsServiceHandler.class);
    this.name = name;
}

@Override
public void turnOn() throws TException {

    helloServer.start();

    TSocket helloServerTransport = new TSocket("localhost", Constants.SERVER_PORT);
    TBinaryProtocol helloServerProtocol = new TBinaryProtocol(helloServerTransport);
    managementClient = new ManagementService.Client(helloServerProtocol);
    this.setUser(new User(name));
    helloServerTransport.open();

    helloServer = new ThriftServer(GreetingsServiceHandler.class);
    //portNegotiator is a class described in a separate file, that handles the registration of other nodes to the managementNode. NodeManifest is a file generated by thrift, part of managementService thrift file, describing a struct that contains hostname and port number of nodes.
    PortNegotiator negotiator = new PortNegotiator(managementClient);
    negotiator.negotiate(nodeManifest, helloServer);

}

@Override
public void turnOff() {
    helloServer.stop();
}

public User getUser() {
    return user;
}

public void setUser(User user) {
    this.user = user;
}

1 个答案:

答案 0 :(得分:1)

处理程序中的基本方法impl非常简单,类似以下应该做的事(免责声明:未经测试):

@Override
public Message getHello(User user) throws TException {
    Message answer = new Message();
    answer = answer.setMessage("Ciao " + user.getName() + ", welcome among us!");
    return answer;
}
  

如果我改用它,那么显然不会使用helloClient变量,但我当然需要它来回答方法调用

     

当连接到管理节点的GreetingsNode X生成该方法的RPC时,另一个注册的GreetingsNode必须回答“hello X”消息。

如果这意味着我们需要一个像 Client =&gt;这样的通话序列ServerA =&gt;服务器B 然后这也是可能的,只需要稍作修改。从上面的基本示例开始,我们相应地增强了代码:

private Message callTheOtherNode(User user) {
  // class ServiceProvider is generated by Thrift, 
  // part of ManagementService Thrift service 
  ServiceProvider provider = null; 
  List<ServiceProvider>providers = managementClient.getProvidersForService(user.name);

  if (providers.isEmpty())
      throw new NoProviderAvailableException(); //separate file contains Exception

  provider = providers.get(random.nextInt(providers.size()));
  //connection between nodes is established here
  TTransport helloTransport = new TSocket(provider.getHostName(), provider.getPort());
  TProtocol helloProtocol = new TBinaryProtocol(helloTransport);
  helloClient = new GreetingsService.Client(helloProtocol);
  helloTransport.open();
  return helloClient.getHello(user);
}

@Override
public Message getHello(User user) throws TException {
    Message answer = callTheOtherNode(user);
    return answer;
}

当然,被调用的“其他节点”需要实际处理请求,而不是简单地将其再次转发给另一个节点。