為什么我要寫這篇文章
作為一枚技術 Doge携狭,每天總免不了和不懂技術的老板 探(si) 討(bi) 業(yè)務的實現可能性友存;
前一段日子缤剧,老板在深(bi) 入(jiao) 調(jia) 研(ge) 之后決定引入一個第三方 IOT 平臺学辱,通過 RESTful API 實時反饋設備的監(jiān)測數據核畴,而因為公司業(yè)務的特殊性膝但,所獲得的原始監(jiān)測數據我們無法直接使用,而是必須經過一番計算谤草。以為每位登錄后臺的用戶顯示過去一周的實時能源消耗為例跟束,我們需要在十五秒內完成大約 60 MB (120 萬條記錄) 數據的提取、清洗及計算丑孩,而這顯然超出了瀏覽器和單次 HTTP 請求所能承受的極限冀宴。這個需求讓我想起了之前自己學習 Golang 練手時寫過的一個分布式計算模型,于是趁此機會把它擴展了一下温学,寫成框架發(fā)布到社區(qū)里略贮,有興趣的童鞋可以 star 回去試驗一下哦。
為什么要用 Go 重新造輪子
Golang 是 Google 在2007年發(fā)布的一門開源的靜態(tài)編譯型編程語言仗岖,在垃圾回收逃延、結構類型以及并發(fā)編程的處理上擁有自己的獨到之處,近年來更是成為使用頻率上升速度最快的編程語言之一轧拄。 可以參考這篇文章揽祥,Go 在打包編譯后的性能與 Java 或 C++相似。在我們的使用中檩电,Go 一般比 Python 要快 30 倍拄丰。同時府树,其天然支持的 CSP 模型在很多情況下可以免去了消息隊列的使用,對高并發(fā)場景獨到的處理優(yōu)勢愈案,更是能夠大大縮短程序員的開發(fā)時間哦挺尾。
GoCollaborate 是什么?
很多同學看到這里可能會問了,這個框架什么站绪?我又能用它來做什么呢遭铺?
簡而言之,
GoCollaborate 是一個提供分布式服務管理搭建的輕量級通用框架恢准,您可以輕松地用它進行編程魂挂,構建擴展,以及創(chuàng)建自己的高性能分布式服務馁筐。
有相關從業(yè)經驗的同學可能聽說過 Apache Hadoop涂召,Spark,Lightbend 的 Akka敏沉, 阿里的 Dubbo 以及 Facebook 的 Thrift 等等果正,一套工具集下來是不是感覺暈頭轉向呢?不要緊盟迟,我們在這姑且暫時把它當成一個輕量級的 Hadoop 好了秋泳,隨著教程展開,讓我們一起來體驗 Golang 的神奇魅力攒菠。
下面我們用一個簡單的應用展示框架的基本用法和原理迫皱,更多應用請參考官方例庫,或者直接提交 issue辖众,我覺得有價值的會后續(xù)補充上去卓起。
正文
首先是安裝:
go get -u github.com/GoCollaborate/src
然后為你的項目創(chuàng)建基本結構,創(chuàng)建好之后看起來像這樣
[Your_Project_Name]
┬
├ [core]
┬
└ example.go
├ case.json
└ main.go
然后是集群的配置,修改case.json
為:
{
"caseid": "GoCollaborateStandardCase",
"cards": {
"localhost:57851": {
"ip": "localhost",
"port": 57851,
"alive": false,
"seed": false
},
"localhost:57852": {
"ip": "localhost",
"port": 57852,
"alive": true,
"seed": true
}
},
"timestamp": 1508619931,
"local": {
"ip": "localhost",
"port": 57852,
"alive": true,
"seed": true
},
"coordinator": {
"ip": "localhost",
"port": 0,
"alive": true,
"seed": false
}
}
這里有幾個參數凹炸,caseid
是集群的自定義id戏阅,id不同的集群之間將無法通信;而cards
里面則囊括了當前網絡上已知的主機地址还惠,local
作為本機地址饲握,你可以修改為自己喜歡的端口,更多內容請參見我寫的官方文檔蚕键,(目前只完成了英文文檔救欧,后續(xù)會陸續(xù)補充中文部分,著急的同學可以先用谷歌翻譯哈锣光!)笆怠。
然后打開剛才創(chuàng)建的example.go,給我們的計算任務寫幾個函數:
package core
import (
"fmt"
"github.com/GoCollaborate/src/artifacts/task"
"github.com/GoCollaborate/src/wrappers/taskHelper"
"net/http"
)
// 任務處理器
func ExampleJobHandler(w http.ResponseWriter, r *http.Request) *task.Job {
// 創(chuàng)建一個 Job 實例
job := task.MakeJob()
// 將任務輸入 Job 的隊列
job.Tasks(&task.Task{task.SHORT,
task.BASE, "exampleFunc",
task.Collection{1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4},
task.Collection{0},
task.NewTaskContext(struct{}{}), 0})
// 為當前階段指定執(zhí)行器誊爹,這里我們簡單做一次 Map-Reduce
job.Stacks("core.ExampleTask.Mapper", "core.ExampleTask.Reducer")
// 這里大家可以根據需要為 HTTP 請求返回內容
// ...
return job
}
// 任務調用的處理函數
func ExampleFunc(source *task.Collection,
result *task.Collection,
context *task.TaskContext) bool {
fmt.Println("Example Task Executed...")
var total int
// 計算數據集內數據的總和
for _, n := range *source {
total += n.(int)
}
// 將總和寫入結果集
result.Append(total)
return true
}
type SimpleMapper int
func (m *SimpleMapper) Map(inmaps map[int]*task.Task) (map[int]*task.Task, error) {
// 將任務平均映射成三個子任務
return taskHelper.Slice(inmaps, 3), nil
}
type SimpleReducer int
func (r *SimpleReducer) Reduce(maps map[int]*task.Task) (map[int]*task.Task, error) {
var sum int
// 根據返回結果計算總和
for _, s := range maps {
for _, r := range (*s).Result {
sum += r.(int)
}
}
fmt.Printf("The sum of numbers is: %v \n", sum)
fmt.Printf("The task set is: %v", maps)
return maps, nil
}
然后在我們的入口文件main.go
里蹬刷,把剛才寫的函數都注冊到框架里:
package main
import (
"./core"
"github.com/GoCollaborate/src"
)
func main() {
mp := new(core.SimpleMapper)
rd := new(core.SimpleReducer)
collaborate.Set("Function", core.ExampleFunc, "exampleFunc")
collaborate.Set("Mapper", mp, "core.ExampleTask.Mapper")
collaborate.Set("Reducer", rd, "core.ExampleTask.Reducer")
collaborate.Set("Shared", []string{"GET", "POST"}, core.ExampleJobHandler)
collaborate.Run()
}
跑一下瓢捉,看能運行嗎?
go run main.go -mode=clbt
剛才創(chuàng)建的任務函數將被映射到
http://localhost:8080/core/ExampleJobHandler
退出程序办成,我們把剛才創(chuàng)建的項目文件夾復制一份泡态,開始真正的分布式計算:
cp Your_Project_Name Your_Project_Name_Copy
在配置文件case.json
內部修改本地端口ip:
{
"caseid": "GoCollaborateStandardCase",
"cards": {
"localhost:57852": {
"ip": "localhost",
"port": 57852,
"alive": true,
"seed": true
}
},
"timestamp": 1508619931,
"local": {
"ip": "localhost",
"port": 57851,
"alive": true,
"seed": false
},
"coordinator": {
"ip": "localhost",
"port": 0,
"alive": true,
"seed": false
}
}
保存,退出迂卢,然后依次進入不同目錄下啟動兩個項目某弦,這里如果大家在本地運行的話記得加個參數,記得把第二個應用的端口設為8081以免沖突哦:
go run main.go -mode=clbt -port=8081
go run main.go -mode=clbt
現在可以訪問:
http://localhost:8080/core/ExampleJobHandler
// and
http://localhost:8081/core/ExampleJobHandler
執(zhí)行剛才注冊的任務啦而克,看看控制臺靶壮,是不是輸出了什么?
然后還有一個做了一半的 UI员萍,提供一點基本統(tǒng)計分析:
http://localhost:8080
因為是個人項目腾降,肯定還有很多不足,最后再附上 github 鏈接 GoCollaborate 碎绎,歡迎大家提交 issue 或者拍磚螃壤,當然愿意貢獻代碼的大蝦就更歡迎了,謝謝閱讀!