go微服務系列(一) go micro入門

寶樹吶 發表於 2020-08-09

1. 什麼是go micro

1.1 go micro作用

它是一個可插入的RPC框架,用於在Go中編寫微服務。開箱即用,您將收到:

  • 服務發現: 應用程式自動註冊到服務發現系統
  • 負載平衡: 客戶端負載平衡,用於平衡服務例項之間的請求
  • 同步通訊: 提供請求 / 響應傳輸層。
  • 非同步通訊: 內建釋出 / 訂閱功能。
  • 訊息編碼: 基於訊息的內容型別頭的編碼 / 解碼。
  • RPC 客戶機/伺服器包: 利用上述功能並公開介面來構建微服務

1.2 go micro架構組成

Go 微體系結構可以描述為三層堆疊

go微服務系列(一) go micro入門

頂層由客戶端-伺服器模型和服務抽象組成。

  • 伺服器: 用於編寫服務的構建塊
  • 客戶端: 提供了向服務請求的介面。

底層由以下型別的外掛組成:

  • 代理: 為非同步釋出/訂閱通訊提供訊息代理的介面。
  • 編解碼器: 用於編碼/解碼訊息。支援的格式包括 json,bson,protobuf,msgpack 等。
  • 登錄檔: 提供服務發現機制(預設為 Consul)
  • 選擇器: 建立在登錄檔上的負載平衡抽象。它允許使用諸如隨機,輪循,最小康等演算法來 “選擇” 服務。
    傳輸 - 服務之間同步請求 / 響應通訊的介面。
  • Go Micro還提供了Sidecar等功能。這使您可以使用Go以外的語言編寫的服務

Sidecar提供服務註冊,gRPC編碼/解碼和HTTP處理程式。它支援多種語言。

2. go micro入門

最簡單的用法大概如下,結合net/http標準庫監聽路由

package main

import (
	"github.com/micro/go-micro/web"
	"net/http"
)

func main() {

	server := web.NewService(web.Address(":8081")) // 路由
	server.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("hello go micro"))
	})
	_ = server.Run()
}

也可以整合第三方web框架作為路由

  • 比如gin
package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/micro/go-micro/web"
)

func main() {
    // 使用gin作為路由
	r := gin.Default()
	r.GET("/user", func(c *gin.Context) {
		c.String(http.StatusOK, "user api")
	})

	server := web.NewService(
		web.Address(":8081"),                                // 埠
		web.Metadata(map[string]string{"protocol": "http"}), // 元資訊
		web.Handler(r)) // 路由
		
	_ = server.Run()
}

3. 結合consul進行服務註冊/發現

微服務裡最重要的關鍵一步就是服務註冊

常用的有consul、etcd、zookeeper、eureka

我們這裡使用consul

3.1 consul的安裝

這裡直接使用docker安裝

docker run -d --name=cs -p 8500:8500 consul agent -server -bootstrap -ui -client 0.0.0.0

然後再訪問埠8500,如下現實安裝成功

go微服務系列(一) go micro入門

3.2 服務註冊程式碼示例

github.com/micro/go-micro/registry/consul
上面這個在1.14.0版本之後刪除了,要用這個github.com/micro/go-plugins/registry/consul,或者換成etcd作為註冊中心

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/web"
	"github.com/micro/go-plugins/registry/consul"
)

func main() {
    // 新增consul地址
	cr := consul.NewRegistry(
		registry.Addrs("127.0.0.1:8500"))
    
    // 使用gin作為router
	router := gin.Default()
	router.GET("/user", func(c *gin.Context) {
		c.String(http.StatusOK, "user api")
	})
    
    // 初始化go micro
	server := web.NewService(
		web.Name("productService"),                          // 當前微服務服務名
		web.Registry(cr),                                    // 註冊到consul
		web.Address(":8081"),                                // 埠
		web.Metadata(map[string]string{"protocol": "http"}), // 元資訊
		web.Handler(router)) // 路由

	_ = server.Run()
}

把上述程式碼執行起來,再去consul介面檢視,發現productService服務新增成功

go微服務系列(一) go micro入門

然後把程式碼停掉,再去consul介面檢視,productService就沒了,非常方便

3.2 服務發現程式碼示例

package main

import (
	"fmt"
	"log"

	"github.com/micro/go-micro/client/selector"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/consul"
)

func main() {
	// 1.連線到consul
	cr := consul.NewRegistry(registry.Addrs("127.0.0.1:8500"))

	// 2.根據service name獲取對應的微服務列表
	services, err := cr.GetService("productService")
	if err != nil {
		log.Fatal("cannot get service list")
	}

	// 3.使用random隨機獲取其中一個例項
	next := selector.Random(services)
	svc, err := next()
	if err != nil {
		log.Fatal("cannot get service")
	}

	fmt.Println("[測試輸出]:", svc.Id, svc.Address, svc.Metadata)
}

然後使用goland先啟動服務註冊中的productService的微服務,再啟動服務發現中的程式碼。

服務發現將會輸出如下,服務發現成功:

go微服務系列(一) go micro入門