1、異步計算
散布式計算聽起來有點高大上,如果說異步計算,估計了解的人多了。我們在平常的工作和生活中,1般都能遇到或用到異步計算。
比如年底要做很多的報表,領導把需要的報表安排下來,我和我的團隊去做統計。為了不耽誤領導的時間,不需要領導站在我們屁股后面親身督戰。對領導來講,這個就是1個簡單的異步計算模型了。
我們的團隊在統計的時候,數據量很多,系統要運行很久,我們也沒必要1直看進度條轉圈圈,可以去做1下別的工作,或吃點零食,這個也是異步計算。
負責統計的系統,也沒有必要1直轉圈圈,把任務在后臺運行,前端還可以履行其他的查詢,這個也是異步計算。
1個事情,就牽出來1大堆異步計算,看來生活中,真的是滿常見的。:)
異步計算實現了事務的計算的轉移,但是其實不能下降事務本身的計算時間。
2、異步計算工具:Gearman
注:Gearman強悍的地方就是它可以支持不同語言直接的交互,client端是1種語言,worker端可以是另外1種語言!中間的交互具體轉化細節都封裝在jobserver中處理。
Gearman是1個用來把工作委派給其他機器、散布式的調用更合適做某項工作的機器、并發的做某項工作在多個調用間做負載均衡、或用來在調用其它語言的函數的系統。
1個Gearman要求的處理進程觸及3個角色:Client -> Job -> Worker。
Client:要求的發起者,可以是 C,PHP,Perl,MySQL UDF 等等。
Job:要求的調度者,用來負責調和把 Client 發出的要求轉發給適合的 Work。
Worker:要求的處理者,可以是 C,PHP,Perl 等等。
由于 Client,Worker 其實不限制用1樣的語言,所以有益于多語言多系統之間的集成。
乃至我們通過增加更多的 Worker,可以很方便的實現利用程序的異步計算。
3、Gearman樣例
下面是例子是官網上面的字符串反轉,供需要用的時候參考。
worker.php + client.java或worker.java +client.php
1. 環境:JDK1.7.0_25
所需jar包:java-gearman-service-0.6.6.jar, slf4j-api⑴.6.4.jar,slf4j-simple⑴.6.4.jar。可以直接到網上去下載。
2.代碼:
Java語言
client端代碼:
package com.gearman.demo;
import org.gearman.Gearman;
import org.gearman.GearmanClient;
import org.gearman.GearmanJobEvent;
import org.gearman.GearmanJobReturn;
import org.gearman.GearmanServer;
public class EchoClient {
public static void main(String... args) throws InterruptedException {
// 創建1個Gearman實例
Gearman gearman = Gearman.createGearman();
// 創建1個Gearman client
GearmanClient client = gearman.createGearmanClient();
/*
* 創建1個jobserver
*
* Parameter 1: job server的IP地址 Parameter 2: job server監聽的端口
*
* job server收到client的job,并將其分發給注冊worker
*/
GearmanServer server = gearman.createGearmanServer(
EchoWorker.ECHO_HOST, EchoWorker.ECHO_PORT);
// 告知客戶端,提交工作時它可以連接到該服務器
client.addServer(server);
/*
* 向job server提交工作
*
* Parameter 1: gearman function名字 Parameter 2: 傳送給job server和worker的數據
*
* GearmanJobReturn返回job發熱結果
*/
GearmanJobReturn jobReturn = client.submitJob(
EchoWorker.ECHO_FUNCTION_NAME, ("Hello World!").getBytes());
// 遍歷作業事件,直到我們打到最后文件
while (!jobReturn.isEOF()) {
// 下1個作業事件
GearmanJobEvent event = jobReturn.poll();
switch (event.getEventType()) {
case GEARMAN_JOB_SUCCESS: // job履行成功
System.out.println(new String(event.getData()));
break;
case GEARMAN_SUBMIT_FAIL: // job提交失敗
case GEARMAN_JOB_FAIL: // job履行失敗
System.err.println(event.getEventType() + ": "
+ new String(event.getData()));
default:
}
}
// 關閉
gearman.shutdown();
}
}
worker端代碼:
package com.gearman.demo;
import org.gearman.Gearman;
import org.gearman.GearmanFunction;
import org.gearman.GearmanFunctionCallback;
import org.gearman.GearmanServer;
import org.gearman.GearmanWorker;
public class EchoWorker implements GearmanFunction {
// function name
public static final String ECHO_FUNCTION_NAME = "reverse";
// job server地址
public static final String ECHO_HOST = "10.10.115.23";
// job server監聽的端口
public static final int ECHO_PORT = 4730;
public static void main(String... args) {
// 創建1個Gearman實例
Gearman gearman = Gearman.createGearman();
/*
* 創建1個jobserver
*
* Parameter 1: job server的IP地址 Parameter 2: job server監聽的端口
*
* job server收到client的job,并將其分發給注冊worker
*/
GearmanServer server = gearman.createGearmanServer(
EchoWorker.ECHO_HOST, EchoWorker.ECHO_PORT);
// 創建1個Gearman的worker
GearmanWorker worker = gearman.createGearmanWorker();
// 告知工人如何履行工作(主要實現了GearmanFunction接口)
worker.addFunction(EchoWorker.ECHO_FUNCTION_NAME, new EchoWorker());
// worker連接服務器
worker.addServer(server);
}
@Override
public byte[] work(String function, byte[] data,
GearmanFunctionCallback callback) throws Exception {
// work方法實現了GearmanFunction接口中的work方法,本實例中進行了字符串的反寫
if (data != null) {
String str = new String(data);
StringBuffer sb = new StringBuffer(str);
return sb.reverse().toString().getBytes();
} else {
return "未接收到data".getBytes();
}
}
}
*ECHO_HOST = "192.168.1.12"為安裝了Gearman并開啟geramand服務的主機地址
*int ECHO_PORT = 4730默許端口為4730
例如log4j.properties文件內容以下:
log4j.rootLogger=debug, stdout, R
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p - %m%n
log4j.appender.R=org.apache.log4j.RollingFileAppender
log4j.appender.R.File=firestorm.log
log4j.appender.R.MaxFileSize=100KB
log4j.appender.R.MaxBackupIndex=1
log4j.appender.R.layout=org.apache.log4j.PatternLayout
log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n
log4j.logger.com.codefutures=DEBUG
PHP語言
client端:
<?php
$client = new GearmanClient();
$client->addServer();
print $client->do("reverse","Hello World!");
print " ";
?>
worker端:
<?php
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction("reverse","my_reverse_function");
echo "Starting worker ...";
while($worker->work());
function my_reverse_function($job)
{
return strrev($job->workload());
}
?>
3.測試
注:這里我將php文件放在:/home/user/projects/ 文件夾下,另外,*.java的文件在eclipse中新建的工程里面。
測試1:worker.php + EchoClient.java
$php worker.php
然后,再在eclipse中運行:EchoClient.java
eclipse console輸出結果:
INFO - [10.10.115.23:4730] :Connected
INFO - [10.10.115.23:4730] : OUT :SUBMIT_JOB
INFO - [10.10.115.23:4730] : IN :JOB_CREATED
INFO - [10.10.115.23:4730] : IN :WORK_COMPLETE
!dlroW olleH
INFO - [10.10.115.23:4730] : Disconnected
運行成功!!
測試2:EchoWorker.java + client.php
先在eclipse中運行,EchoWorker.java
然后,再在命令行下輸入:php client.php
命令行下輸出結果:
!dlroW olleH
運行成功!!
下一篇 Mysql 下創建root用戶