構建第一個Go微服務

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

第二部分: Go微服務 - 構建我們的第一個服務

第二部分包含:

  • 設定我們的Go工作空間。
  • 構建我們第一個微服務。
  • 通過HTTP使用Gorilla Web Toolkit來提供一些JSON服務。

介紹

雖然通過HTTP提供JSON服務不是內部服務和外部服務的唯一選擇,但本文聚焦的是HTTP和JSON. 使用RPC機制和二進位訊息格式(例如Protocol Buffer)也用於內部通訊或外部通訊也是非常有趣的,特別是當外部消費者屬於另外一個系統的時候。Go語言有內建的RPC支援,並且gRPC也是完全值得看看的。 然而,我們現在只聚焦基於由http包和Gorilla Web Toolkit提供的HTTP。

另外一個需要考慮的方面是很多有用的架構(安全、跟蹤等等), 依賴於HTTP頭來傳輸參與者進行中的請求狀態。我們在本文中將看到的例子是我們如何在頭中傳遞相關ID和OAuth票據。雖然其他協議當然也支援類似的機制, 很多架構都是以HTTP構建的,我更願意儘可能的保持我們的整合更加直接。

設定Go工作空間

如果你是一個經驗豐富的Go開發人員,你可以隨意跳過本節內容。 以我拙見,Go語言工作空間結構需要一些時間來適應。一般來說我習慣使用項目根作為工作空間的根,Go語言約定了如何恰當的構造工作空間,因此go編譯器可以尋找原始碼和依賴,有點不正統, 將原始碼放在子目錄下源碼控制路徑後以src命名的目錄中.我強烈推薦讀下官方指南和本文,然後再開始。 我希望我就是這樣的。

安裝SDK

在開始寫我們第一行代碼之前(或check out完整代碼之前), 我們需要安裝Go語言SDK。建議按照官方指導來操作,直接操作就足夠了。

設定開發環境

在這些部落格系列中,我們將使用我們安裝的內建的Go SDK工具來構建和運行我們的代碼,以及按照慣用方式來設定Go的工作空間。

1. 建立工作空間的根目錄

所有命令都基於OS X或Linux開發環境。 如果你啟動並執行是Windows, 請採用必要的指令。

mkdir ~/goworkspacecd goworkspaceexport GOPATH=`pwd`

這裡我們建立了一個根目錄,然後將GOPATH環境變數賦於那個目錄。這就是我們的工作空間的根目錄,我們所寫的所有Go語言代碼和第三方類庫都在它下面。我推薦添加這個GOPATH到.bash_profile檔案或類似的設定檔中,這樣不需要每次都為每個控制台視窗重設它。

2. 為我們第一個項目建立檔案夾和檔案

鑒於我們已經在工作空間的根目錄(例如,和在GOPATH環境變數中指定相同的目錄), 執行下面的語句:

mkdir -p src/github.com/callistaenterprise

如果你希望遵循自己的編碼,可以執行下面的命令:

cd src/github.com/callistaenterprisemkdir -p goblog/accountservicecd goblog/accountservicetouch main.gomkdir service

或者你可以clone這個git倉庫,包含相同代碼,並切換到P2分支。 從上面你建立的src/github.com/callistaenterprise/goblog.git目錄, 執行下面的命令。

git clone https://github.com/callistaenterprise/goblog.gitcd gobloggit checkout P2

記住: $GOPATH/src/github.com/callistaenterprise/goblog是我們項目的根目錄,並且實際是儲存在github上面的。

那麼我們結構已經足夠可以很方便開始了。 用你喜歡的IDE開啟main.go檔案。

建立服務 - main.go

Go語言中的main函數就是你具體做事的地方 - Go語言應用程式的進入點。 下面我們看看它的具體代碼:

package mainimport (    "fmt")var appName = "accountservice"func main() {    fmt.Printf("Starting %v\n", appName)}

然後運行該程式:

> go run path/to/main.goStarting accountservice

就是這樣的,程式只列印了一個字串,然後就退出了。是時候添加第一個HTTP端點了。

構建HTTP web伺服器

注意: 這些HTTP樣本的基礎是從一個優秀的部落格文章派生出來的, 見參考連結。

為了保持代碼整潔,我們把所有HTTP服務相關的檔案放到service目錄下面。

啟動HTTP伺服器

在service目錄中建立webservice.go檔案。

package serviceimport (    "log"    "net/http")func StartWebServer(port string) {    log.Println("Starting HTTP service at " + port)    err := http.ListenAndServe(":"+port, nil) // Goroutine will block here    if err != nil {        log.Println("An error occured starting HTTP listener at port " + port)        log.Println("Error: " + err.Error())    }}

上面我們使用內建net/http包執行ListenAndServe, 在指定的連接埠號碼啟動一個HTTP伺服器。

然後我們更新下main.go代碼:

package mainimport (    "fmt"    "github.com/callistaenterprise/goblog/accountservice/service" // 新增代碼)var appName = "accountservice"func main() {    fmt.Printf("Starting %v\n", appName)    service.StartWebServer("6767") // 新增代碼}

然後再次運行這個程式,得到下面的輸出:

> go run *.goStarting accountservice2017/01/30 19:36:00 Starting HTTP service at 6767

那麼現在我們就有一個HTTP伺服器,它監聽localhost的6767連接埠。然後curl它:

> curl http://localhost:6767404 page not found

得到404完全是意料之中的,因為我們還沒有添加任何路由呢。

Ctrl+C停止這個web伺服器。

添加第一個路由

是時候讓我們的伺服器提供一些真正的服務了。我們首先用Go語言結構聲明我們的第一個路由,我們將使用它來填充Gorilla路由器。 在service目錄中,建立一個routes.go檔案。

package serviceimport (    "net/http")// Define a single route, e.g. a human readable name, HTTP method and the pattern the function that will execute when the route is called.type Route struct {    Name        string    Method      string    Pattern     string    HandlerFunc http.HandlerFunc}// Defines the type Routes which is just an array (slice) of Route structs.type Routes []Routevar routes = Routes{    Route{        "GetAccount", // Name        "GET",        // HTTP method        "/accounts/{accountId}", // Route pattern        func(w http.ResponseWriter, r *http.Request) {            w.Header().Set("Content-Type", "application/json; charset=UTF-8")            w.Write([]byte("{\"result\":\"OK\"}"))        },    },}

上面程式碼片段,我們聲明了一個路徑/accounts/{accountId}, 我們後面會用curl來訪問它。Gorilla也支援使用正則模式比對、schemes, methods, queries, headers值等等的複雜路由。因此不限於路徑和路徑參數。

我們在響應的時候,寫入程式碼了一個小的JSON訊息:

{    "result": "OK"}

我們還需要一些模式化的程式碼片段,將我們聲明的路由掛鈎到實際的Gorilla Router上。 在service目錄,我們建立router.go檔案:

package serviceimport (    "github.com/gorilla/mux")// Function that returns a pointer to a mux.Router we can use as a handler.func NewRouter() *mux.Router {    // Create an instance of the Gorilla router    router := mux.NewRouter().StrictSlash(true)    // Iterator over the routes we declared in routes.go and attach them to the router instance    for _, route := range routes {        // Attach each route, uses a Builder-like pattern to set each route up.        router.Methods(route.Method).            Path(route.Pattern).            Name(route.Name).            Handler(route.HandlerFunc)    }    return router}

匯入依賴包

在router.go中的import地區, 我們聲明了依賴github.com/gorilla/mux包。 我們可以通過go get來擷取依賴包的原始碼。

WRAPPING UP

我們可以再回到webserver.go檔案,在函數StartWebServer開始位置加入下面兩行代碼。

func StartWebServer(port string) {    r := NewRouter()    http.Handle("/", r)}

這就將我們剛建立的Router綁定到http.Handle對/路徑的處理。然後重新編譯並運行修改後的代碼:

> go run *.goStarting accountservice2017/01/31 15:15:57 Starting HTTP service at 6767

然後另開一個視窗,curl如下:

> curl http://localhost:6767/accounts/10000{"result":"OK"}

很好,我們現在有了我們第一個HTTP服務。

資訊及效能(FOOTPRINT AND PERFORMANCE)

鑒於我們正在探索基於Go的微服務,由於驚人的記憶體佔用和良好的效能,我們最好能快速進行基準測試來看看它們如何執行的。
我已經開發了一個簡單的Gatling測試, 可以使用GET請求對/accounts/{accountId}進行捶打。 如果之前你是直接從https://github.com/callistaen...,那麼你的原始碼中就包含有負載測試代碼goblog/loadtest。或者可以直接查看https://github.com/callistaen...。

你自己運行一下負載測試

如果你需要自己運行負載測試工具,確保accountservice服務已啟動,並且運行在localhost的6767連接埠上。並且你已經checkout我們的P2分支的代碼。你還需要Java的運行環境以及需要安裝Apache Maven。

改變目錄到goblog/loadtest目錄下面,在命令列中執行下面的命令。

mvn gatling:execute -Dusers=1000 -Dduration=30 -DbaseUrl=http://localhost:6767

這樣就會啟動並運行測試。參數如下:

  • users: 類比測試的並發使用者數.
  • duration: 測試要啟動並執行秒數.
  • baseUrl: 我們要測試的服務的基礎路徑。當我們把它遷移到Docker Swarm後,baseUrl修改修改為Swarm的公用IP. 在第5部分會介紹。

首次運行,mvn會自動安裝一大堆東西。安裝完後,測試完成之後,它會將結果寫到控制台視窗,同時也會產生一個報告到target/gatling/results中的html中。

結果

注意: 稍後,當我們的服務運行到Docker Swarm模式的Docker容器中時, 我們會在那裡做所有基準測試並捕獲度量。

在開始負載測試之前,我們的基於Go的accountservice記憶體消耗可以從macbook的工作管理員中查看到,大概如下:

1.8MB, 不是特別壞。讓我們使用Gatling測試,運行每秒1000個請求。需要記住一點,我們使用了非常幼稚的實現,我們僅僅響應一個硬式編碼JSON響應。

服務每秒1000個請求,佔用的記憶體也只是增加到28MB。 依然是Spring Boot應用程式啟動時候使用記憶體的1/10. 當我們給它添加一些真正的功能時,看這些數字變化會更加有意思。

效能和CPU使用率

提供每秒1000個請求,每個核大概使用8%。

注意,Gatling一回合子微秒延遲如何, 但是平均延遲報告值為每個請求0ms, 花費龐大的11毫秒。 在這點上來看,我們的accountservice執行還是表現出色的,在子毫秒範圍內大概每秒服務745個請求。

下一章

在下一部分, 我們將真正的讓accountservice做一些有意義的事情。 我們會添加一個簡單的嵌入資料庫到Account對象,然後提供HTTP服務。我們也會看看JSON的序列化,並檢查這些增加對於足跡和效能的影響。

參考連結

  • http://callistaenterprise.se/...
  • http://thenewstack.io/make-a-...
  • https://github.com/gorilla/
  • 專題首頁
  • 下一節
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.