在構(gòu)建微服務(wù)時窒篱,使用服務(wù)發(fā)現(xiàn)可以減少配置的復(fù)雜性,本文以go-micro為微服務(wù)框架配并,使用consul作為服務(wù)發(fā)現(xiàn)服務(wù)高镐,使用gin開發(fā)golang服務(wù)嫉髓。
使用gin 的原因是gin能夠很好的和go-micro進行集成邑闲。
本文主要介紹服務(wù)注冊和發(fā)現(xiàn)的實現(xiàn)
關(guān)于如何搭建consul服務(wù)可以移步:http://www.reibang.com/p/271d490929a5
本文默認以搭建好了consul服務(wù)苫耸,服務(wù)的地址是:192.168.109.131:8500
如果你搭建好了自己的consul服務(wù)儡陨,可以在瀏覽器內(nèi)輸入192.168.109.131:8500(地址根據(jù)自己的consul服務(wù)做調(diào)整),會看到如下界面:
這里我的consul服務(wù)啟用了 3個節(jié)點褐筛。
填坑
在開始寫代碼前渔扎,先給大家避一避坑信轿,目前go-micro已經(jīng)更新到v2版本财忽,此版本去除了對consul 的支持,但支持etcd即彪、mdns作為服務(wù)發(fā)現(xiàn)隶校,但是老版本的go-micro仍支持consul,但是有些地方做了調(diào)整绰疤。
首先舞终,需要go 1.13的支持敛劝,所以小伙伴們需要升級下golang
然后,在獲取go-micro庫時蛾方,不能使用這個指令了 go get -u github.com/micro/go-micro
改為:go get -u github.com/micro/go-micro/v2
原來go-micro consul的支持已經(jīng)遷移到了go-plugins里面
我們的代碼里在導(dǎo)入consul庫時,也變?yōu)榱耍?"github.com/micro/go-plugins/registry/consul"
這個在下面的代碼里可以看到
然后,沒有安裝gin的同學(xué)唆垃,需要使用如下指令獲取下:
go get -u github.com/gin-gonic/gin
這些小編折騰了很久才搞明白辕万,這里先給大家提醒下,避免走我的老路
開擼
服務(wù)注冊
我們預(yù)設(shè)兩個server醉途,userserver和orderserver
下面開始上代碼:
userserver程序結(jié)果如下:
有兩個文件router.go和main.go
main.go代碼如下
main.go實現(xiàn)初始化路由隘擎,服務(wù)注冊
package main
import (
"github.com/micro/go-micro/registry"http://注意這些地址變了
"github.com/micro/go-micro/web"http://注意這些地址變了
"github.com/micro/go-plugins/registry/consul"http://注意這些地址變了
"userserver/routers"
)
var consulReg registry.Registry
func init() {
//新建一個consul注冊的地址凉夯,也就是我們consul服務(wù)啟動的機器ip+端口
consulReg = consul.NewRegistry(
registry.Addrs("192.168.109.131:8500"),
)
}
func main() {
//初始化路由
ginRouter := routers.InitRouters()
//注冊服務(wù)
microService:= web.NewService(
web.Name("userserver"),
//web.RegisterTTL(time.Second*30),//設(shè)置注冊服務(wù)的過期時間
//web.RegisterInterval(time.Second*20),//設(shè)置間隔多久再次注冊服務(wù)
web.Address(":18001"),
web.Handler(ginRouter),
web.Registry(consulReg),
)
microService.Run()
}
router.go代碼如下
router.go主要用來定義程序的api接口,使用gin開發(fā)
package routers
import "github.com/gin-gonic/gin"
func InitRouters() *gin.Engine {
ginRouter := gin.Default()
ginRouter.POST("/users/", func(context *gin.Context) {
context.String(200, "get userinfos")
})
return ginRouter
}
注冊的代碼就寫好了震桶,啟動userserver蹲姐,我們在consul服務(wù)界面人柿,可以看到如下效果:
說明我們注冊成功了
服務(wù)發(fā)現(xiàn)
服務(wù)發(fā)現(xiàn)凫岖,就是從consul中獲取到我們注冊進去的服務(wù),這樣在調(diào)用別的服務(wù)時扎阶,就不用從配置文件獲取婶芭,直接查詢consul即可。
orderserver我們除了實現(xiàn)服務(wù)注冊外惰赋,也實現(xiàn)服務(wù)發(fā)現(xiàn)的功能
orderserver代碼結(jié)構(gòu)如下:
上代碼
main.go代碼如下
package main
import (
"bytes"
"fmt"
"github.com/micro/go-micro/client/selector"
"github.com/micro/go-micro/registry"
"github.com/micro/go-micro/web"
"github.com/micro/go-plugins/registry/consul"
"net/http"
"orderserver/routers"
"time"
)
var consulReg registry.Registry
func init(){
//新建一個consul注冊的地址赁濒,也就是我們consul服務(wù)啟動的機器ip+端口
consulReg = consul.NewRegistry(
registry.Addrs("192.168.109.131:8500"),
)
}
func main() {
//初始化路由
ginRouter := routers.InitRouters()
//注冊服務(wù)
microService:= web.NewService(
web.Name("orderserver"),
//web.RegisterTTL(time.Second*30),//設(shè)置注冊服務(wù)的過期時間
//web.RegisterInterval(time.Second*20),//設(shè)置間隔多久再次注冊服務(wù)
web.Address(":18002"),
web.Handler(ginRouter),
web.Registry(consulReg),
)
//獲取服務(wù)地址
hostAddress := GetServiceAddr("userserver")
if len(hostAddress) <= 0{
fmt.Println("hostAddress is null")
}else{
url := "http://"+ hostAddress + "/users"
response, _ := http.Post(url, "application/json;charset=utf-8",bytes.NewBuffer([]byte("")))
fmt.Println(response)
}
microService.Run()
}
func GetServiceAddr(serviceName string)(address string){
var retryCount int
for{
servers,err :=consulReg.GetService(serviceName)
if err !=nil {
fmt.Println(err.Error())
}
var services []*registry.Service
for _,value := range servers{
fmt.Println(value.Name, ":", value.Version)
services = append(services, value)
}
next := selector.RoundRobin(services)
if node , err := next();err == nil{
address = node.Address
}
if len(address) > 0{
return
}
//重試次數(shù)++
retryCount++
time.Sleep(time.Second * 1)
//重試5次為獲取返回空
if retryCount >= 5{
return
}
}
}
GetServiceAddr就是服務(wù)發(fā)現(xiàn)的代碼
首先挪拟,使用servers,err :=consulReg.GetService(serviceName)獲取注冊的服務(wù)
返回的servers是個slice
然后击你,使用next := selector.RoundRobin(services)獲取其中一個服務(wù)的信息
這里注意:
在老版本中可以直接使用selector.RoundRobin(services)丁侄,但是在v2版本中需要做個轉(zhuǎn)換處理:
var services []*registry.Service
for _,value := range servers{
fmt.Println(value.Name, ":", value.Version)
services = append(services, value)
}
因為使用的數(shù)據(jù)結(jié)構(gòu)不同,感興趣的可以細看下區(qū)別石景。
router.go代碼如下
package routers
import "github.com/gin-gonic/gin"
func InitRouters() *gin.Engine {
ginRouter := gin.Default()
ginRouter.POST("/orders/", func(context *gin.Context) {
context.String(200, "get orderinfos")
})
return ginRouter
}
啟動oerderserver 我們就能獲取到userserver的地址拙吉,各位可以調(diào)試看下效果庐镐。
今天go-micro+gin+consul微服務(wù)實戰(zhàn)就介紹完了,是不是很簡單