大數據框架hadoop的IPC機制實例

    Hadoop IPC(Inter-Process Communication,進程間通信)這是一種簡潔,低消耗的通信機制,可以精確控制進程間通信中如連接、超時、緩存等細節。Hadoop IPC機制的實現使用了Java動態代理,Java NIO等技術。

如下是一個使用Hadoop IPC實現客戶端調用服務器端方法的示例功能是返回服務器端的一個文件信息

1 文件信息類IPCFileStatus

    代碼如下所示:

package org.seandeng.hadoop.ipc;

 

import java.io.DataInput;

import java.io.DataOutput;

import java.io.IOException;

import java.util.Date;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.io.Writable;

 

public class IPCFileStatus implements Writable {

    private String filename;

    private long time;

    public IPCFileStatus() {

    }

    public IPCFileStatus(String filename) {

        this.filename=filename;

        this.time=(new Date()).getTime();

    }

    public String getFilename() {

        return filename;

    }

    public void setFilename(String filename) {

        this.filename = filename;

    }

    public long getTime() {

        return time;

    }

    public void setTime(long time) {

        this.time = time;

    }

    public String toString() {

        return "File: "+filename+" Create at "+(new Date(time));

    }

    public void readFields(DataInput inthrows IOException {

        this.filename = Text.readString(in);

        this.time = in.readLong();

    }

    public void write(DataOutput outthrows IOException {

        Text.writeString(outfilename);

        out.writeLong(time);

    }

}

由於IPCFileStatus類的對象需要從服務器端傳到客戶端,所以就需要進行序列化,Writable接口就是Hadoop定義的一個序列化接口。 
    由於客戶端要調用服務器的方法,所以客戶端需要知道服務器有哪些方法可以調用,在IPC中使用的是定義接口的方法,如定義一個IPC接口,客戶端和服務器端都知道這個接口,客戶端通過IPC獲取到一個服務器端這個實現了接口的引用,待要調用服務器的方法時,直接使用這個引用來調用方法,這樣就可以調用服務器的方法了。

2 接口IPCQueryStatus

    定義一個服務器端和客戶端接口IPCQueryStatus如下所示:

package org.seandeng.hadoop.ipc;

 

import org.apache.hadoop.ipc.VersionedProtocol;

 

public interface IPCQueryStatus extends VersionedProtocol {

    IPCFileStatus getFileStatus(String filename);

}

    在接口IPCQueryStatus中,定義了一個getFileStatus(String filename)方法根據文件名得到一個IPCFileStatus對象,注意到IPCQueryStatus接口繼承自接口 org.apache.hadoop.ipc.VersionedProtocol接口,VersionedProtocol接口是Hadoop IPC接口必須繼承的一個接口,它定義了一個方法getProtocolVersion(),用於返回服務器端的接口實現的版本號,有兩個參數,分別是協議接口對應的接口名稱protocol和客戶端期望服務器的版本號clientVersion,主要作用是檢查通信雙方的接口是否一致,VersionedProtocol的代碼如下:

package org.apache.hadoop.ipc;

 

import java.io.IOException;

/**

 * Superclass of all protocols that use Hadoop RPC.

 * Subclasses of this interface are also supposed to have

 * a static final long versionID field.

 */

public interface VersionedProtocol {

  /**

   * Return protocol version corresponding to protocol interface.

   * @param protocol The classname of the protocol interface

   * @param clientVersion The version of the protocol that the client speaks

   * @return the version that the server will speak

   */

  public long getProtocolVersion(String protocol

                                 long clientVersionthrows IOException;

}

3 實現類IPCQueryStatusImpl

    定義好了接口,那麼在服務器端就需要有一個接口的實現類,用於實現具體的業務邏輯,下面的IPCQueryStatusImpl類實現了IPCQueryStatus接口,僅僅簡單實現了IPCQueryStatus規定兩個方法

package org.seandeng.hadoop.ipc;

 

import java.io.IOException;

 

public class IPCQueryStatusImpl implements IPCQueryStatus {

    public IPCQueryStatusImpl() {}

 

    public IPCFileStatus getFileStatus(String filename) {

        IPCFileStatus status=new IPCFileStatus(filename);

        System.out.println("Method getFileStatus Called, return: "+status);

        return status;

    }

    /**

     * 用於服務器與客戶端,進行IPC接口版本檢查,再服務器返回給客戶端時調用,如果服務器端的IPC版本與客戶端不一致

     * 那麼就會拋出版本不一致的異常

     */

    public long getProtocolVersion(String protocollong clientVersionthrows IOException {

        System.out.println("protocol: "+protocol);

        System.out.println("clientVersion: "+clientVersion);

        return IPCQueryServer.IPC_VER;

    }

}

getFileStatus()方法根據參數filename創建了一個IPCFileStatus對象,getProtocolVersion()方法返回服務器端使用的接口版本。接口和實現類都完成之後就可以用客戶端和服務器進行通信了。

4 IPCQueryServer

    服務器端進行一些成員變量的初始化,然後使用Socket綁定IP,然後在某個端口上監聽客戶端的請求IPCQueryServer類相關代碼如下所示:

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.ipc.RPC;

import org.apache.hadoop.ipc.Server;

 

public class IPCQueryServer {

    public static final int IPC_PORT = 32121;

    public static final long IPC_VER = 5473L;

 

    public static void main(String[] args) {

        try {

            Configuration conf = new Configuration();

            IPCQueryStatusImpl queryService=new IPCQueryStatusImpl();

            System.out.println(conf);

            Server server = RPC.getServer(queryService, "127.0.0.1", IPC_PORT, 1, false, conf);

            server.start();

 

            System.out.println("Server ready, press any key to stop");

            System.in.read();

 

            server.stop();

            System.out.println("Server stopped");

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

    在服務器端先創建一個IPCQueryStatusImpl的對象,傳遞到RPC.getServer()方法中。服務器端使用RPC.getServer()方法穿給創建服務器端對象server,代碼中RPC.getServer()方法的幾個參數說明如下:

· 第一個參數queryService標識該服務器對象對外提供的服務對象實例,即客戶端所要調用的具體對象,下面客戶端的代碼調用的接口如此對應;

· 第二個參數"127.0.0.1"表示監綁定所有的IP地址;

· 第三個參數IPC_PORT表示監聽的端口;

· 第四個參數1表示Server端的Handler實例(線程)的個數爲1

· 第五個參數false表示打開調用方法日誌;

· 第六個參數是Configuration對象,用於定製Server端的配置

創建Server對象之後,調用Server.start()方法開始監聽客戶端的請求,並根據客戶端的請求提供服務。

5 請求類IPCQueryClient

客戶端需要先獲取到一個代理對象,然後才能進行方法調用,在IPC中,使用RPC.getProxy()方法獲取代理對象。客戶端的代碼如下: 

package org.seandeng.hadoop.ipc;

 

import java.net.InetSocketAddress;

 

import org.apache.hadoop.conf.Configuration;

import org.apache.hadoop.ipc.RPC;

 

public class IPCQueryClient {

    public static void main(String[] args) {

        try {

            System.out.println("Interface name: "+IPCQueryStatus.class.getName());

            System.out.println("Interface name: "+IPCQueryStatus.class.getMethod("getFileStatus", String.class).getName());

            InetSocketAddress addr=new InetSocketAddress("localhost", IPCQueryServer.IPC_PORT);

            IPCQueryStatus query=(IPCQueryStatus) RPC.getProxy(IPCQueryStatus.class, IPCQueryServer.IPC_VER, addr,new Configuration());

            IPCFileStatus status=query.getFileStatus("Z:\\temp\\7c64984cf5c3410fbe28037865d010a3.pdf");

            System.out.println(status);

            RPC.stopProxy(query);

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

}

    客戶端的代碼很簡單,首先構造一個要請求服務器的網絡地址(IP和端口),然後通過RPC.getProxy()方法獲取到一個IPCQueryStatus對象,然後進行相應的方法調用。其中客戶端代碼中RPC.getProxy()方法的參數說明如下:

· 第一個參數是IPC接口對象,可以通過IPC接口的靜態成員class直接獲得。接口的靜態成員class保存了該接口的java.lang.Class實例,它表示正在運行的Java應用程序中的類和接口,提供一系列與Java反射相關的重要功能;

· 第二個參數是接口版本,由於接口會根據需求不斷地進行升級,形成多個版本的IPC接口,如果客戶端和服務器端使用的IPC接口版本不一致,結果將是災難性的,所以在建立IPC時,需要對IPC的雙方進行版本檢查;

· 第三個參數是服務器的Socket地址,用於建立IPC的底層TCP連接;

· 第四個參數是Configuration對象,用於定製IPC客戶端參數

6 執行結果

客戶端的代碼編寫完成之後就可以運行程序了,先啓動服務器端,再運行一個客戶端,就完成了一次客戶端調用服務器的過程,客戶端調用了服務器端 IPCQueryStatusImpl對象的getFileStatus()方法,服務器端返回了方法調用結果即IPCFileStatus對象。服務器端和客戶端執行日誌如下所示:

服務器端:

2014-11-26 13:00:49,147 WARN  conf.Configuration (Configuration.java:<clinit>(191)) - DEPRECATED: hadoop-site.xml found in the classpath. Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, mapred-site.xml and hdfs-site.xml to override properties of core-default.xml, mapred-default.xml and hdfs-default.xml respectively

Configuration: core-default.xml, core-site.xml

2014-11-26 13:00:50,124 INFO  ipc.Server (Server.java:run(328)) - Starting SocketReader

2014-11-26 13:00:50,222 INFO  ipc.Server (Server.java:run(598)) - IPC Server Responder: starting

2014-11-26 13:00:50,223 INFO  ipc.Server (Server.java:run(434)) - IPC Server listener on 32121: starting

Server ready, press any key to stop

2014-11-26 13:00:50,224 INFO  ipc.Server (Server.java:run(1358)) - IPC Server handler 0 on 32121: starting

protocol: org.seandeng.hadoop.ipc.IPCQueryStatus

clientVersion: 5473

Method getFileStatus Called, return: File: Z:\temp\7c64984cf5c3410fbe28037865d010a3.pdf Create at Wed Nov 26 13:01:02 CST 2014

客戶端:

Interface name: org.seandeng.hadoop.ipc.IPCQueryStatus

Interface name: getFileStatus

2014-11-26 13:00:59,790 WARN  conf.Configuration (Configuration.java:<clinit>(191)) - DEPRECATED: hadoop-site.xml found in the classpath. Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, mapred-site.xml and hdfs-site.xml to override properties of core-default.xml, mapred-default.xml and hdfs-default.xml respectively

File: Z:\temp\7c64984cf5c3410fbe28037865d010a3.pdf Create at Wed Nov 26 13:01:02 CST 2014

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章