zoukankan      html  css  js  c++  java
  • 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!

  • 相关阅读:
    转载:SqlServer数据库性能优化详解
    复杂事件处理技术概览(一)
    Netty : writeAndFlush的线程安全及并发问题
    如何在RCP程序中添加一个banner栏
    AChecker + Selenium2对需要登录的页面进行自动化可访问性测试
    5分钟开启Esper之旅
    使SWT/JFace支持跨平台
    Ubuntu上Docker安装Trouble Shooting
    使Docker Container支持运行SWT程序
    Xcode5中如何切换Storyboards为xib
  • 原文地址:https://www.cnblogs.com/bener/p/10683404.html
Copyright © 2011-2022 走看看