GoCollaborate: 用一百行代碼寫一個基于 Golang 的實時分布式計算應(yīng)用

為什么我要寫這篇文章

作為一枚技術(shù) Doge,每天總免不了和不懂技術(shù)的老板 探(si) 討(bi) 業(yè)務(wù)的實現(xiàn)可能性;

前一段日子,老板在深(bi) 入(jiao) 調(diào)(jia) 研(ge) 之后決定引入一個第三方 IOT 平臺,通過 RESTful API 實時反饋設(shè)備的監(jiān)測數(shù)據(jù),而因為公司業(yè)務(wù)的特殊性,所獲得的原始監(jiān)測數(shù)據(jù)我們無法直接使用,而是必須經(jīng)過一番計算。以為每位登錄后臺的用戶顯示過去一周的實時能源消耗為例,我們需要在十五秒內(nèi)完成大約 60 MB (120 萬條記錄) 數(shù)據(jù)的提取、清洗及計算,而這顯然超出了瀏覽器和單次 HTTP 請求所能承受的極限。這個需求讓我想起了之前自己學(xué)習(xí) Golang 練手時寫過的一個分布式計算模型,于是趁此機(jī)會把它擴(kuò)展了一下,寫成框架發(fā)布到社區(qū)里,有興趣的童鞋可以 star 回去試驗一下哦。

為什么要用 Go 重新造輪子

Golang 是 Google 在2007年發(fā)布的一門開源的靜態(tài)編譯型編程語言,在垃圾回收、結(jié)構(gòu)類型以及并發(fā)編程的處理上擁有自己的獨(dú)到之處,近年來更是成為使用頻率上升速度最快的編程語言之一。 可以參考這篇文章,Go 在打包編譯后的性能與 Java 或 C++相似。在我們的使用中,Go 一般比 Python 要快 30 倍。同時,其天然支持的 CSP 模型在很多情況下可以免去了消息隊列的使用,對高并發(fā)場景獨(dú)到的處理優(yōu)勢,更是能夠大大縮短程序員的開發(fā)時間哦。

GoCollaborate 是什么?

很多同學(xué)看到這里可能會問了,這個框架什么?我又能用它來做什么呢?

簡而言之,

GoCollaborate 是一個提供分布式服務(wù)管理搭建的輕量級通用框架,您可以輕松地用它進(jìn)行編程,構(gòu)建擴(kuò)展,以及創(chuàng)建自己的高性能分布式服務(wù)。

有相關(guān)從業(yè)經(jīng)驗的同學(xué)可能聽說過 Apache Hadoop,Spark,Lightbend 的 Akka, 阿里的 Dubbo 以及 Facebook 的 Thrift 等等,一套工具集下來是不是感覺暈頭轉(zhuǎn)向呢?不要緊,我們在這姑且暫時把它當(dāng)成一個輕量級的 Hadoop 好了,隨著教程展開,讓我們一起來體驗 Golang 的神奇魅力。

下面我們用一個簡單的應(yīng)用展示框架的基本用法和原理,更多應(yīng)用請參考官方例庫,或者直接提交 issue,我覺得有價值的會后續(xù)補(bǔ)充上去。

正文

首先是安裝:

go get -u github.com/GoCollaborate/src

然后為你的項目創(chuàng)建基本結(jié)構(gòu),創(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
    }
}

這里有幾個參數(shù),caseid是集群的自定義id,id不同的集群之間將無法通信;而cards里面則囊括了當(dāng)前網(wǎng)絡(luò)上已知的主機(jī)地址,local作為本機(jī)地址,你可以修改為自己喜歡的端口,更多內(nèi)容請參見我寫的官方文檔,(目前只完成了英文文檔,后續(xù)會陸續(xù)補(bǔ)充中文部分,著急的同學(xué)可以先用谷歌翻譯哈!)。

然后打開剛才創(chuàng)建的example.go,給我們的計算任務(wù)寫幾個函數(shù):

package core

import (
    "fmt"
    "github.com/GoCollaborate/src/artifacts/task"
    "github.com/GoCollaborate/src/wrappers/taskHelper"
    "net/http"
)

// 任務(wù)處理器
func ExampleJobHandler(w http.ResponseWriter, r *http.Request) *task.Job {
    // 創(chuàng)建一個 Job 實例
    job := task.MakeJob()
    // 將任務(wù)輸入 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})
    // 為當(dāng)前階段指定執(zhí)行器,這里我們簡單做一次 Map-Reduce
    job.Stacks("core.ExampleTask.Mapper", "core.ExampleTask.Reducer")
    
    // 這里大家可以根據(jù)需要為 HTTP 請求返回內(nèi)容
    // ...
    
    return job
}

// 任務(wù)調(diào)用的處理函數(shù)
func ExampleFunc(source *task.Collection,
    result *task.Collection,
    context *task.TaskContext) bool {

    fmt.Println("Example Task Executed...")
    
    var total int
    // 計算數(shù)據(jù)集內(nèi)數(shù)據(jù)的總和
    for _, n := range *source {
        total += n.(int)
    }
    
    // 將總和寫入結(jié)果集
    result.Append(total)
    return true
}

type SimpleMapper int

func (m *SimpleMapper) Map(inmaps map[int]*task.Task) (map[int]*task.Task, error) {
    // 將任務(wù)平均映射成三個子任務(wù)
    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
    
    // 根據(jù)返回結(jié)果計算總和
    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里,把剛才寫的函數(shù)都注冊到框架里:

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()
}

跑一下,看能運(yùn)行嗎?

go run main.go -mode=clbt

剛才創(chuàng)建的任務(wù)函數(shù)將被映射到

http://localhost:8080/core/ExampleJobHandler
image

退出程序,我們把剛才創(chuàng)建的項目文件夾復(fù)制一份,開始真正的分布式計算:

cp Your_Project_Name Your_Project_Name_Copy

在配置文件case.json內(nèi)部修改本地端口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
    }
}

保存,退出,然后依次進(jìn)入不同目錄下啟動兩個項目,這里如果大家在本地運(yùn)行的話記得加個參數(shù),記得把第二個應(yīng)用的端口設(shè)為8081以免沖突哦:

go run main.go -mode=clbt -port=8081
go run main.go -mode=clbt

現(xiàn)在可以訪問:

http://localhost:8080/core/ExampleJobHandler
// and 
http://localhost:8081/core/ExampleJobHandler

執(zhí)行剛才注冊的任務(wù)啦,看看控制臺,是不是輸出了什么?

image

然后還有一個做了一半的 UI,提供一點基本統(tǒng)計分析:

http://localhost:8080


因為是個人項目,肯定還有很多不足,最后再附上 github 鏈接 GoCollaborate ,歡迎大家提交 issue 或者拍磚,當(dāng)然愿意貢獻(xiàn)代碼的大蝦就更歡迎了,謝謝閱讀!

P.S. 框架的全文文檔都在這里,本文的例子在這里。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,724評論 19 139
  • 承載量是分布式系統(tǒng)存在的原因 當(dāng)一個互聯(lián)網(wǎng)業(yè)務(wù)獲得大眾歡迎的時候,最顯著碰到的技術(shù)問題,就是服務(wù)器非常繁忙。當(dāng)每天...
    XYLY閱讀 1,526評論 1 48
  • 本文轉(zhuǎn)載自http://geek.csdn.net/news/detail/112672 WeTest導(dǎo)讀 我們常...
    shineegirl閱讀 1,618評論 0 26
  • 聽說 大自然正在孕育一場風(fēng)暴 于是我來到這片灘涂 逢一個叫“瑪娃”的孩子 看不見移動的浮萍 河流平靜成了湖泊 水天...
    詩姬閱讀 187評論 2 5
  • 研磨 居住地:湖北利川 身 高:168cm 職 業(yè):經(jīng) 商 初始體重:162 斤 目前體重:133 斤 初始腰圍:...
    瘦朵朵教練閱讀 465評論 0 0

友情鏈接更多精彩內(nèi)容