詳細教你如何部署ICE服務(一)

這系列文章將會一步步教你如何部署一個ICE服務,如果你正在讀這篇博客,我想你已經瞭解了什麼是ICE(Internet Communications Engine)以及如何去實現ICE服務,並且瞭解什麼是ICE對象、ICE對象標識符、ICE對象適配器、ICE服務實現servant、ICE通信器等概念,當然如果你連什麼是ICE都不知道,我不建議你繼續讀下去。

先說一下ICE的基本組件:

(1) Slice工具:將Slice語言定義的接口編譯成各種特定語言實現的代碼,這屬於開發環境的一部分

(2) ICE容器:IceBox、Ice Node、Ice Registry、Ice Grid、Ice Admin等組件,這些是用於部署和管理Ice服務,你可以在你的服務中選擇其中的幾項使用。

(3)ICE運行庫:由ICE實現平臺提供的一套API,不同的語言有不同的實現,如java使用的是jar包,c++使用的是.so文件,這套API需要被ICE服務的客戶端和服務端調用

以實現底層通信。


我在寫這系列博客時使用的開發環境如下:

eclipse 

Ice-3.3.1

jdk-1.6

CentOS release 5.11 (Final)


我們這裏實現一個查詢僱員信息的服務,用於演示Ice服務的部署方式。


(一)我們先在eclipse中創建一個java項目,並在項目下創建一個名爲slice的文件夾,然後使用Ice 的Slice語言定義Ice服務接口 並將文件命名爲query.ice,並將文件放入項目中的slice文件夾中

[["java:package:com.yujie.ice"]]
module info{

struct EmployeeInfo{
string name;
int age;
bool isLeave;
double salary;
string remark;
};
	interface QueryEmployee{
	EmployeeInfo query(EmployeeInfo msg);
	};

};

query.ice文件中定義了報名com.yujie.ice並用info進行包隔離最後生成的包名就是com.yujie.ice.info。

文件中定了一個EmployeeInfo結構體作爲員工的信息結構體,定義了一個接口QueryEmployee,我們需要在自己的服務端代碼中實現這個接口。

(二) 使用Slice工具將query.ice定義的接口 生成java實現的具體代碼,我的eclipse已經安裝了ICE 編譯插件,直接編譯這個java項目就可以生成相應的接口客戶端和服務端的stub代碼。如果你沒有安裝Slice2java 編譯插件你可以使用類似slice2java --output-dir ../src/main/java/  query.ice這樣的命令生成代碼,前提是你已經設置了ICE相應的環境變量。

編譯之後的項目目錄如下所示:



(三)實現ice服務端代碼。

 /**
  * 繼承服務端stub代碼_QueryEmployeeDisp類 並實現query接口
  * @author yujie.wang
  *
  */
public class QueryEmployeeImpl extends _QueryEmployeeDisp{

	@Override
	public EmployeeInfo query(EmployeeInfo msg, Current __current) {
		// TODO Auto-generated method stub
		EmployeeInfo ei = new EmployeeInfo();
		ei.age = 23;
		ei.name = msg.name;
		ei.isLeave = false;
		ei.salary = 2000.0;
		ei.remark = "he is a good employee";
		return ei;
	}
}

我們這裏要實現一個查詢僱員信息的服務,返回一個僱員的的信息。

之後我們實現啓動ICE服務端的代碼,代碼如下所示:

/**
 * 實現啓動ICE服務端代碼
 * @author yujie.wang
 *
 */
public class QueryEmployeeServer {
	public static void main(String [] args){
		int state = 0;
		Ice.Communicator communicator = null;
		try {
			//初始化ice通信器communicator,可以使用args傳入一下ice初始化的參數如超時時間,線程池大小等
			communicator = Ice.Util.initialize(args);
			//創建一個名爲queryEmployeeAdapter的適配器並且默認使用tcp協議  服務部署在10.4.30.81機器上 服務開啓10006監聽端口
			Ice.ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("queryEmployeeAdapter","default -p 10006");
			// 創建服務端代碼實現servant
			QueryEmployeeImpl servant = new QueryEmployeeImpl();
			// 將servant與ice對象標識符建立映射關係,並添加到ice對象適配器中
			adapter.add(servant, Ice.Util.stringToIdentity("queryServer"));
			// 激活對象適配器
			adapter.activate();
			System.out.println("QueryEmployeeServer adapter activate");
			// 服務在退出之前一直保持監聽狀態
			communicator.waitForShutdown();
		} catch (Exception e) {
			// TODO: handle exception
			state = 1;
			System.out.println(e);
		} finally{
			if(communicator != null){
				communicator.destroy();
			}
		}
		System.out.println("state: "+ state);
	}
}

(四) 實現客戶端代碼

/**
 * 實現客戶端調用接口代碼
 * @author yujie.wang
 *
 */
public class QueryEmployeeClient {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Ice.Communicator communicator = null;
		try {
			//初始化ice通信器communicator,可以使用args傳入一下ice初始化的參數如超時時間,線程池大小等
			communicator = Ice.Util.initialize(args);
			// 傳入遠程服務單元的 ice對象標識符  協議默認tcp 主機 已經服務監聽端口
			Ice.ObjectPrx op = communicator.stringToProxy("queryServer:default -h 10.4.30.81 -p 10006");
			// 檢查通用客戶端代理op 是不是queryServer對象標識符所關聯的ice對象的代理
			QueryEmployeePrx qp = QueryEmployeePrxHelper.checkedCast(op);
			if(qp == null){
				throw new Exception("qp == null");
			}
			// 構造傳入參數
			EmployeeInfo ei = new EmployeeInfo();
			ei.name = "yujie.wang";
			// 調用接口
			EmployeeInfo result = qp.query(ei);
			if(result == null){
				throw new Exception("result == null");
			}
			// 輸出服務端返回結果
			System.out.println(result.remark);
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println(e);
		}
	}

}

(五) 服務部署

當然你可以直接在eclipse裏運行服務端啓動ice服務的main方法,但是爲了延續後面的服務部署思路,我這裏打算將代碼打成jar包,通過一個簡單的shell腳本來運行這個main方法。

接下來 我們將java項目進行編譯,之後將編譯後的class代碼通過jar -cvf  yujie-ice-test1.jar ./* 命令打成yujie-ice-test1.jar包。

我在服務器上寫了一個非常簡單的容器IceServer用於啓動這個ice服務,該容器的目錄結構如下所示:


bin目錄下面有如下兩個文件:

env.sh

#!/bin/sh
if [ -z "$JAVA_HOME" ]; then
        JAVA_HOME="/data/web/jdk"
fi
echo "JAVA_HOME:$JAVA_HOME"
if [ -z "$SERVER_HOME" ]; then
        BIN_DIR=`readlink -f "$0"`
        echo "BIN_DIR:$BIN_DIR"
        BASE_DIR=`dirname "$BIN_DIR"`
        echo "BASE_DIR:$BASE_DIR"
        SERVER_HOME="`cd $BASE_DIR/.. && pwd`"
else 
        echo "SERVER_HOME IS NOT EMPTY"
fi

echo "SERVER_HOME:$SERVER_HOME"

startIceServer.sh

#!/bin/sh
. ./env.sh

APP_HOME=$SERVER_HOME/lib
APP_MAINCLASS=com.yujie.ice.server.QueryEmployeeServer

CLASSPATH=$APP_HOME
echo $CLASSPATH
for i in "$APP_HOME"/*.jar;do CLASSPATH="$CLASSPATH":"$i";done
echo $CLASSPATH
$JAVA_HOME/bin/java -Xms1000M -Xmx1000M -Xmn500M -XX:PermSize=128m -XX:MaxPermSize=256m -cp  $CLASSPATH  $APP_MAINCLASS 


lib目錄下面分別是ICE  平臺API jar包和我們自己服務的jar包。


現在我們用startIceServer.sh腳本來啓動服務端代碼

sh startIceserver.sh &



最後我們在本地運行客戶端調用代碼輸出如下:





(六)該部署方式總結

優點:直接使用服務端main函數啓動,沒有引入ice其他容器組件,客戶端和服務端直接通過tcp建立連接,是一個十分輕量級的服務。

確定:客戶端直接寫死了服務的Endpoint信息,及其不靈活;服務端部署方式簡單粗暴 不易運維,無法實現負載均衡、故障恢復


這種部署方式只是簡單粗暴的演示,完全不能作爲工業級的部署方案。

下一節我們將實現另一種部署方案,該方案會解決該種部署方式的一些問題。










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