Eureka-Client(Golang實現)


Eureka-Client

Golang實現eureka-client

原理

根據Java版本的源碼,可以看出client主要是通過REST請求來與server進行通信。

Java版本的核心實現:com.netflix.discovery.DiscoveryClient

其中主要邏輯如下:

  • client啟動時注冊信息到server
  • 定時心跳、刷新服務列表,主要是兩個線程池:heartbeatExecutorcacheRefreshExecutor
  • client關閉時刪除注冊信息

實現

這里不限制語言,主要是發送REST請求到server。

注冊信息

通過POST請求,將服務信息注冊到server。

請求地址:POST /eureka/apps/{APP_NAME}

信息如下:(不是完整的信息)

{
    "instance":{
        "instanceId":"192.168.1.107:golang-example:10000",
        "hostName":"192.168.1.107",
        "ipAddr":"192.168.1.107",
        "app":"golang-example",
        "port":{
            "@enabled":"true",
            "$":10000
        },
        "securePort":{
            "@enabled":"true",
            "$":443
        },
        "status":"UP",
        "overriddenStatus":"UNKNOWN",
        "dataCenterInfo":{
            "name":"MyOwn",
            "@class":"com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo"
        }
    }
}

定時心跳、刷新服務列表

服務啟動后,接下來就是維持client與server之間的心跳等。

定時心跳

默認情況下是30秒發送心跳信息到server。

請求地址:PUT /eureka/apps/{APP_NAME}/{INSTANCE_ID}?status=UP&lastDirtyTimestamp={TIMESTAMP}

定時刷新服務列表

默認情況下是30秒刷新服務列表。

刷新服務列表有全量和增量兩種方式:

  • 全量:GET /eureka/apps
  • 增量(delta):GET /eureka/apps/delta

其中,全量就是每次都拉取到所有服務信息;而增量拉取變化的服務信息,然后本地去做更新。

為了方便我只實現了全量拉取,沒有實現delta。

刪除注冊信息

在服務停止時,刪除注冊的信息即可。

請求地址:DELETE /eureka/apps/{APP_NAME}/{INSTANCE_ID}

Golang核心實現

有2個定時器:

  • refreshTicker來刷新服務列表
  • heartbeatTicker進行心跳
func (c *Client) Start() {
	c.mutex.Lock()
	c.Running = true
	c.mutex.Unlock()

	refreshTicker := time.NewTicker(c.EurekaClientConfig.RefreshIntervalSeconds)
	heartbeatTicker := time.NewTicker(c.EurekaClientConfig.HeartbeatIntervalSeconds)

	go func() {
		for range refreshTicker.C {
			if c.Running {
				if err := c.doRefresh(); err != nil {
					fmt.Println(err)
				}
			} else {
				break
			}
		}
	}()

	go func() {
		if err := c.doRegister(); err != nil {
			fmt.Println(err)
		}
		for range heartbeatTicker.C {
			if c.Running {
				if err := c.doHeartbeat(); err != nil {
					fmt.Println(err)
				}
			} else {
				break
			}
		}
	}()
}

例子

下面是使用的例子,為了在client停止時刪除注冊信息,這里用到了signal

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"os/signal"
	"syscall"

	client "github.com/xuanbo/eureka-client"
)

func main() {
	// 1.創建客戶端
	c := client.NewClient(&client.EurekaClientConfig{
		DefaultZone: "http://127.0.0.1:8080/eureka/",
		App:         "golang-example",
		Port:        10000,
	})
	// 2.啟動client,注冊到server。並定心跳、刷新服務列表
	c.Start()

	sigs := make(chan os.Signal)
	exit := make(chan bool, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)

	// 隨便弄一個請求
	http.HandleFunc("/services", func(writer http.ResponseWriter, request *http.Request) {
		// 3.獲取所有服務(status均為UP)
		services := c.Services
		
		b, _ := json.Marshal(services)
		_, _ = writer.Write(b)
	})
	server := &http.Server{
		Addr:    ":10000",
		Handler: http.DefaultServeMux,
	}

	// 啟動http服務
	go func() {
		if err := server.ListenAndServe(); err != nil {
			fmt.Println(err)
		}
	}()

	// 關閉
	go func() {
		fmt.Println(<-sigs)

		// 停止http服務
		if err := server.Close(); err != nil {
			panic(err)
		}

		// 4.停止客戶端,並刪除注冊信息
		c.Shutdown()

		exit <- true
	}()

	<-exit
}

主要是4步,用起來比較簡單。

Github地址

Github

說明

未在生產中使用,只是想把Golang的服務與Java的Spring Cloud結合起來玩耍。

Just for fun!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM