GT4 遠程執行客戶機快速入門
您是一位軟件 開發 人員,正在努力地把公司的應用程序移植到一個嶄新的分布式環境中。您的組織已經為網格計算這一令人興奮的新領域提供了一些資源,但是您卻不知道接下來應該做些什么。最終期限很快就要到了,惶恐的氣氛逐漸在您的團隊中蔓延開來。您需要做的
您是一位軟件
開發人員,正在努力地把公司的應用程序移植到一個嶄新的分布式環境中。您的組織已經為網格計算這一令人興奮的新領域提供了一些資源,但是您卻不知道接下來應該做些什么。最終期限很快就要到了,惶恐的氣氛逐漸在您的團隊中蔓延開來。您需要做的事情是制定一個快速路線圖,將組織的應用程序部署或移植到計算或數據網格中。Globus 一直以來都在致力于提供有關 Globus Toolkit V4.0(GT4)的文檔,但您現在需要的是
開發文檔。Globus 正在創建一些
開發文檔
Web 站點來解決這個問題。同時,在本文中,我們給出了一些資源管理領域中的開發技巧,目的在于幫助您使用
Web services Grid Resource Allocation and Management(WS-GRAM)服務快速啟用網格應用程序。
 |
OGSA-GRAM 和 WS-GRAM 之間的可移植性問題
GT4 中的 WS-GRAM 與 GT3(OGSA-MMJFS)中實現的 GRAM 接口并不兼容,不過大部分接口的名字都是相同的:例如 GramJobListener、GramJob 等。實際上,這個自定義 GRAM 客戶機的大部分代碼都與 GT3 的對應部分非常類似,是構建在 GT3 的代碼基礎之上的。GRAM 在 GT4 中作為 Web Services Resource Framework(WSRF)服務實現;而在 GT3 中,它是一個 OGSA 服務。 |
|
全新的 WS-GRAM
Globus GRAM 服務為多種類型的作業調度程序提供了安全提交作業的功能。為支持 XML 加密和簽名,WS-GRAM 徹底重新進行了構建。它使用數字證書在客戶機和服務器之間發送安全的 XML SOAP 消息。實際上,GT4 就是一個安全 Web 服務容器。它與傳統容器之間的區別就是在于可跨多個 SOAP(Simple Object Aclearcase/" target="_blank" >ccess Protocol)消息(也稱為 WSRF)維護狀態。
下面的技巧展示了如何創建一個自定義 Java™ 技術程序向遠程主機提交 WS-GRAM 作業。
技巧 1:監聽作業狀態的變化
要監聽作業狀態的變化,就需要實現 org.globus.exec.client.GramJobListener 接口,它與其 GT3 的對應部分并不兼容(順便提一下,二者的接口名是相同的)。這種技術如下所示。
清單 1. WS-GRAM 客戶機基礎實現
/**
* A Custom GRAM Client for GT4:
* 1) Based on the GlobusRun command from the GT4 WS-GRAM implementation.
* 2) The GT4 WSRF libraries are required to compile this stuff, plus the
* following VM arguments must be used:
* -Daxis.ClientConfigFile=[GLOBUS_LOCATION]/client-config.wsdd
* -DGLOBUS_LOCATION=[GLOBUS_LOCATION]
* @author Vladimir Silva
*
*/
public class GRAMClient
// Listen for job status messages
implements GramJobListener
{
private static Log logger = LogFactory.getLog(GRAMClient.class.getName());
// Amount of time to wait for job status changes
private static final long STATE_CHANGE_BASE_TIMEOUT_MILLIS = 60000;
/**
* Job submission member variables.
*/
private GramJob job;
// completed if Done or Failed
private boolean jobCompleted = false;
// Batch runs will not wait for the job to complete
private boolean batch;
// Delegation
private boolean limitedDelegation = true;
private boolean delegationEnabled = true;
// Don't print messages by default
private boolean quiet = false;
// proxy credential
private String proxyPath = null;
/**
* Application error state.
*/
private boolean noInterruptHandling = false;
private boolean isInterrupted = true;
private boolean normalApplicationEnd = false;
|
WS-GRAM 中的基本對象是 GramJob
。它用來以 XML 格式提交作業描述文件。作業描述中定義了可執行程序、參數、標準輸入/輸出/錯誤、階段文件(staging file)以及其他一些選項。下面是一個簡單的作業描述文件。
清單 2. 簡單的作業描述 XML 文件
<!--
Job to print the remote host environment
For a full set of WS-GRAM options see the WS_GRAM developers page at:
http://www.globus.org/toolkit/docs/4.0/execu-
tion/wsgram/user-index.html#s-wsgram-user-simplejob
-->
<job>
<executable>/usr/bin/env</executable>
<!-- Job stdout/err will be stored in the globus user home directory -->
<stdout>${GLOBUS_USER_HOME}/stdout</stdout>
<stderr>${GLOBUS_USER_HOME}/stderr</stderr>
<!-- Clean up std out/err from user's home -->
<fileCleanUp>
<deletion>
<file>file:///${GLOBUS_USER_HOME}/stdout</file>
</deletion>
<deletion>
<file>file:///${GLOBUS_USER_HOME}/stderr</file>
</deletion>
</fileCleanUp>
</job>
|
清單 2 中的作業文件將輸出遠程主機環境,并將 stdout
/stderr
的內容存儲到用戶的主目錄中(分別使用 stdout
和 stderr
的名字)。如 fileCleanup
段所示,在作業完成之后,這些文件就會被刪除。如果 cleanup 段被注釋掉了,那么對此作業的后續調用就會產生一些副作用:將輸出附加到同名文件之后。因此建議您在每次作業調用之后清除文件。
技巧 2:接收到狀態變化時應該做些什么?
要接收作業狀態的變化,我們必須要實現 stateChanged
回調函數(請參見清單 3)。
清單 3. 接收狀態變化
/**
* Callback as a GramJobListener.
* Will not be called in batch mode.
*/
public void stateChanged(GramJob job) {
StateEnumeration jobState = job.getState();
boolean holding = job.isHolding();
printMessage("========== State Notification ==========");
printJobState(jobState, holding);
printMessage("========================================");
synchronized (this) {
if ( jobState.equals(StateEnumeration.Done)
|| jobState.equals(StateEnumeration.Failed)) {
printMessage("Exit Code: "
+ Integer.toString(job.getExitCode()));
this.jobCompleted = true;
}
notifyAll();
// if we a running an interactive job,
// prevent a hold from hanging the client
if ( holding && !batch) {
logger.debug(
"Automatically releasing hold for interactive job");
try {
job.release();
} catch (Exception e) {
String errorMessage = "Unable to release job from hold";
logger.debug(errorMessage, e);
printError(errorMessage + " - " + e.getMessage());
}
}
}
}
|
接收到 stateChanged
回調時,必須檢查作業狀態,并相應地通知正在等待的線程。上面的子程序會輸出作業狀態,通知正在等待的線程,然后適當地釋放資源。
技巧 3:作業設置
在這個步驟中,我們需要正確設置作業參數。例如,如果指定了一個作業文件,那么就會使用這個文件的內容創建一個 GramJob 對象。還可設置作業超時。另外還必須定義授權和消息保護之類的安全參數。授權可以是用戶、主機(默認)或身份標識。消息保護可以是加密或 XML 簽名。其他選項包括委托、持續時間以及終止時間(請參見清單 4)。設置好這些參數后,即可提交作業了。
清單 4. 作業參數的設置
/**
* Submit a WS-GRAM Job (GT4)
* @param factoryEndpoint Factory endpoint reference
* @param simpleJobCommandLine Executable (null to use a job file)
* @param rslFileJob XML file (null to use a command line)
* @param authorization Authorization: Host, Self, Identity
* @param xmlSecurity XML Sec: Encryption or signature
* @param batchMode Submission mode: batch will not wait for completion
* @param dryRunMode Used to parse RSL
* @param quiet Messages/NO messages
* @param duration Duration date
* @param terminationDate Termination date
* @param timeout Job timeout (ms)
*/
private void submitRSL(EndpointReferenceType factoryEndpoint,
String simpleJobCommandLine,
File rslFile,
Authorization authorization,
Integer xmlSecurity,
boolean batchMode,
boolean dryRunMode,
boolean quiet,
Date duration,
Date terminationDate,
int timeout)
throws Exception
{
this.quiet = quiet;
this.batch = batchMode || dryRunMode; // in single job only.
// In multi-job, -batch is not allowed. Dryrun is.
if (batchMode) {
printMessage("Warning: Will not wait for job completion, "
+ "and will not destroy job service.");
}
// create a job object with the XML spec or a simple command
if (rslFile != null) {
try {
this.job = new GramJob(rslFile);
} catch (Exception e) {
String errorMessage = "Unable to parse RSL from file "
+ rslFile;
logger.debug(errorMessage, e);
throw new IOException (errorMessage + " - " + e.getMessage());
}
}
else {
this.job = new GramJob(RSLHelper
.makeSimpleJob(simpleJobCommandLine));
}
// set job options
job.setTimeOut(timeout);
job.setAuthorization(authorization);
job.setMessageProtectionType(xmlSecurity);
job.setDelegationEnabled(this.delegationEnabled);
job.setDuration(duration);
job.setTerminationTime(terminationDate);
// submit here
this.processJob(job, factoryEndpoint, batch);
}
|
技巧 4:作業處理
創建好對象并設置好其參數后,我們就可以對作業進行處理了。在這個步驟中需要考慮的問題如下:
- 加載一個有效的代理證書 —— 可以使用默認的用戶代理,也可以動態創建一個自定義代理。
- 創建一個惟一的作業標識符 —— Axis 工廠 org.apache.axis.components.uuid.UUIDGenFactory 可用于生成惟一的字符串標識符。
- 如果這個作業是以非批處理模式發送的,那么其父類就應該為作業狀態變化添加一個監聽程序。
- 作業必須提交給工廠端點。
- 如果作業的提交模式為非批處理,那么客戶機必須要等待作業完成,并相應地銷毀作業資源(請參見清單 5)。
清單 5. 作業處理
/**
* Submit the GRAM Job
* @param job Job object (GramJob)
* @param factoryEndpoint Factory end point reference
* @param batch If false will wait for job to complete
* @throws Exception
*/
private void processJob(GramJob job,
EndpointReferenceType factoryEndpoint,
boolean batch)
throws Exception
{
// load custom proxy (if any)
if (proxyPath != null) {
try {
ExtendedGSSManager manager = (ExtendedGSSManager)
ExtendedGSSManager.getInstance();
String handle = "X509_USER_PROXY=" + proxyPath.toString();
GSSCredential proxy = manager.createCredential(handle
.getBytes(),
ExtendedGSSCredential. IMPEXP_MECH_SPECIFIC,
GSSCredential.DEFAULT_LIFETIME, null,
GSSCredential.INITIATE_AND_ACCEPT);
job.setCredentials(proxy);
} catch (Exception e) {
logger.debug("Exception while obtaining user proxy: ", e);
printError("error obtaining user proxy: " + e.getMessage());
// don't exit, but resume using default proxy instead
}
}
// Generate a Job ID
UUIDGen uuidgen = UUIDGenFactory.getUUIDGen();
String submissionID = "uuid:" + uuidgen.nextUUID();
printMessage("Submission ID: " + submissionID);
if (!batch) {
job.addListener(this);
}
boolean submitted = false;
int tries = 0;
while (!submitted) {
tries++;
try {
job.submit(factoryEndpoint, batch, this.limitedDelegation,
submissionID);
submitted = true;
} catch (Exception e) {
logger.debug("Exception while submitting the job request: ", e);
throw new IOException("Job request error: " + e);
}
}
if (batch) {
printMessage("CREATED MANAGED JOB SERVICE WITH HANDLE:");
printMessage(job.getHandle());
}
if (logger.isDebugEnabled()) {
long millis = System.currentTimeMillis();
BigDecimal seconds = new BigDecimal(((double) millis) / 1000);
seconds = seconds.setScale(3, BigDecimal.ROUND_HALF_DOWN);
logger.debug("Submission time (secs) after: " + seconds.toString());
logger.debug("Submission time in milliseconds: " + millis);
}
if (!batch) {
printMessage("WAITING FOR JOB TO FINISH");
waitForJobCompletion(STATE_CHANGE_BASE_TIMEOUT_MILLIS);
try {
this.destroyJob(this.job); // TEST
} catch (Exception e) {
printError("could not destroy");
}
if (this.job.getState().equals(StateEnumeration.Failed)) {
printJobFault(this.job);
}
}
}
|
技巧 5:等待作業完成(非批處理模式)
如果提交模式是非批處理,那么主線程就必須等待作業完成,并將狀態信息返回給客戶機。這是通過檢查作業的狀態并通過循環判斷作業終止原因來實現的。作業終止的原因可能是作業故障(通常是在服務器端產生的錯誤)、客戶機超時或未知錯誤(請參見清單 6)。
清單 6. 等待作業完成
private synchronized void waitForJobCompletion(
long maxWaitPerStateNotificationMillis)
throws Exception
{
long durationToWait = maxWaitPerStateNotificationMillis;
long startTime;
StateEnumeration oldState = job.getState();
// prints one more state initially (Unsubmitted)
// but cost extra remote call for sure. Null test below instead
while (!this.jobCompleted)
{
if (logger.isDebugEnabled()) {
logger.debug("Job not completed - waiting for state change "
+ "(timeout before pulling: " + durationToWait
+ " ms).");
}
startTime = System.currentTimeMillis(); // (re)set start time
try {
wait(durationToWait); // wait for a state change notif
} catch (InterruptedException ie) {
String errorMessage = "interrupted thread waiting for job to finish";
logger.debug(errorMessage, ie);
printError(errorMessage); // no exiting...
}
// now let's determine what stopped the wait():
StateEnumeration currentState = job.getState();
// A) New job state change notification (good!)
if (currentState != null && !currentState.equals(oldState)) {
oldState = currentState; // wait for next state notif
durationToWait = maxWaitPerStateNotificationMillis; // reset
}
else
{
long now = System.currentTimeMillis();
long durationWaited = now - startTime;
// B) Timeout when waiting for a notification (bad)
if (durationWaited >= durationToWait) {
if (logger.isWarnEnabled()) {
logger.warn("Did not receive any new notification of "
+ "job state change after a delay of "
+ durationToWait + " ms.\nPulling job state.");
}
// pull state from remote job and print the
// state only if it is a new state
//refreshJobStatus();
job.refreshStatus();
// binary exponential backoff
durationToWait = 2 * durationToWait;
}
// C) Some other reason
else {
// wait but only for remainder of timeout duration
durationToWait = durationToWait - durationWaited;
}
}
}
}
|
準備好測試了?
最后,我做好了一切準備,可以進行簡單的測試了。按清單 7 設置參數,即可測試這個自定義 WS-GRAM 客戶機。運行輸出結果如清單 8 所示。
清單 7. WS-GRAM 客戶機測試
// remote host
String contact = "rtpmeta";
// Factory type: Fork, Condor, PBS, LSF
String factoryType = ManagedJobFactoryConstants.FACTORY_TYPE.FORK;
// Job XML
File rslFile = new File("/tmp/simple.xml");
// Default Security: Host authorization + XML encryption
Authorization authz = HostAuthorization.getInstance();
Integer xmlSecurity = Constants.ENCRYPTION;
// Submission mode: batch = will not wait
boolean batchMode = false;
// a Simple command executable (if no job file)
String simpleJobCommandLine = null;
// Job timeout values: duration, termination times
Date serviceDuration = null;
Date serviceTermination = null;
int timeout = GramJob.DEFAULT_TIMEOUT;
try {
GRAMClient gram = new GRAMClient();
gram.submitRSL(getFactoryEPR(contact,factoryType)
, simpleJobCommandLine, rslFile
, authz, xmlSecurity
, batchMode, false, false
, serviceDuration, serviceTermination, timeout );
} catch (Exception e) {
e.printStackTrace();
}
|
清單 8. 清單 7 運行的輸出結果
Submission ID: uuid:3eb57530-cfc4-11da-bb0b-dadfac0c5c05
WAITING FOR JOB TO FINISH
========== State Notification ==========
Job State: CleanUp
========================================
========== State Notification ==========
Job State: Active
========================================
========== State Notification ==========
Job State: Done
========================================
Exit Code: 0
DESTROYING JOB RESOURCE
JOB RESOURCE DESTROYED
|


|
回頁首 |
|
故障診斷和調試技巧
下面是用來檢索作業輸出結果、診斷常見錯誤和調試代碼的一些技巧。
技巧 1:檢索作業輸出結果
WS-GRAM Java API 目前不能檢索作業的輸出結果。例如,如果我們在一臺遠程主機上運行 /bin/hostname
命令,就會得到這個作業的一個惟一標識符,但此 API 不能將該命令的輸出結果回顯到控制臺。C-API 可勝任此類任務??紤]下面的命令。
清單 9. C-API 命令
globusrun-ws -submit -s
-factory https://rtpmeta:8443/wsrf/services/ManagedJobFactoryService
-f /tmp/simple.xml
Delegating user credentials...Done.
Submitting job...Done.
Job ID: uuid:272c8c7c-cfcf-11da-9061-00065ba4e6be
Termination time: 04/20/2006 18:05 GMT
Current job state: Active
Current job state: CleanUp-Hold
X509_USER_KEY=
X509_CERT_DIR=/etc/grid-security/certificates
LOGNAME=globus
GLOBUS_LOCATION=/opt/gt-4.0.1
HOME=/opt/home/globus
X509_USER_CERT=
GLOBUS_GRAM_JOB_HANDLE=https://134.67.144.3:8443/wsrf/services/
ManagedExecutableJobService?272c8c7c-cfcf-11da-9061-00065ba4e6be
JAVA_HOME=/usr/java/j2sdk1.4.2_10/jre
X509_USER_PROXY=
Current job state: CleanUp
Current job state: Done
Destroying job...Done.
Cleaning up any delegated credentials...Done.
|
WS-GRAM C-client 提交清單 2 中給出的作業描述文件,并返回或將輸出結果回顯到客戶機控制臺上。WS-GRAM Java API 目前無法處理此類任務。
Globus 尚未在當前版本的工具包中實現將 Java 輸出流回顯到客戶機上的功能的原因不明?;蛟S是由于時間和資源不足。
技巧 2:故障診斷
下面讓我們來看看創建自定義 WS-GRAM 客戶機時遇到的兩個常見錯誤,以及排除這些錯誤的方法。
清單 10. 第一個常見錯誤
No client transport named 'https' found!
at org.apache.axis.client.AxisClient.invoke(AxisClient.java:170)
at org.apache.axis.client.Call.invokeEngine(Call.java:2727)
at org.apache.axis.client.Call.invoke(Call.java:2710)
at org.apache.axis.client.Call.invoke(Call.java:2386)
at org.apache.axis.client.Call.invoke(Call.java:2309)
...
|
這個錯誤是由于 Axis Web 服務客戶機不能找到安全服務 HTTPS 的協議定義而導致的。要排除這個錯誤,在啟動腳本中添加如下 VM 參數即可:
-Daxis.ClientConfigFile=[GLOBUS_LOCATION]/client-config.wsdd
|
清單 11. 第二個常見錯誤
org.apache.axis.ConfigurationException:
Configuration file directory './etc' does not exist or is not
a directory or is not readable.
at org.apache.axis.configuration.DirProvider.{init}(DirProvider.java:73)
at org.globus.wsrf.container.ServiceDispatcher.{init}(ServiceDispatcher.java:80)
at org.globus.wsrf.container.GSIServiceDispatcher.{init}(GSIServiceContainer.java:63)
at org.globus.wsrf.container.GSIServiceContainer.createServiceDispatcher
(GSIServiceContainer.java:49)
at org.globus.wsrf.container.ServiceContainer.start(ServiceContainer.java:226)
...
|
這個錯誤是因 WSRF 代碼無法找到 GT4 配置目錄和其他必需組件的位置而導致的。要排除這個錯誤,添加如下 VM 參數即可:
-DGLOBUS_LOCATION=[GLOBUS_LOCATION]
|
技巧 3:啟用調試
如果您遇到了無法確定的未知錯誤,請在 log4j.properties 文件中啟用調試,如下所示。要使其生效,log4j.properties 文件應該在您的 classpath 目錄中。然后應可看到大量調試消息,幫助您判斷到底發生了什么情況。
清單 12. 在 log4j.properties 中啟用調試
# WS-GRAM client
log4j.category.org.globus.exec.client=DEBUG
log4j.category.org.globus.exec.generated=DEBUG
# Custom WS-GRAM client
log4j.category.gram=DEBUG
|


|
回頁首 |
|
結束語
GRAM 服務為那些有權訪問網格環境中作業宿主資源的用戶提供了將作業安全地提交到多種類型的作業調度程序的功能。有效代理的存在是作業提交的必要條件。所有的 GRAM 作業提交選項都可以通過嵌入請求文檔輸入而透明地進行支持。實際上,作業啟動是通過提交客戶端向 GRAM 服務所提供的作業描述來實現的。
本文是一篇 WS-GRAM 快速入門,旨在幫助您開發可用于 Web 服務、Web 應用程序或您的自定義作業提交程序的客戶機程序。


|
回頁首 |
|
下載
描述 | 名字 | 大小 | 下載方法 |
Source code |
gr-wsgramclient.java |
14KB |
HTTP |
原文轉自:http://www.anti-gravitydesign.com
- 評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
-
国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97
|