微服务示例服务注册和发现

举报
码乐 发表于 2025/11/12 11:48:36 2025/11/12
【摘要】 1 简介在 Go (Golang) 项目中使用 Gin 实现两个服务: 员工账号服务(employee-service) 商品服务(product-service) etcd 服务注册与发现。下面是完整示例代码以及etcd 配置与集成步骤。 2 项目结构示例 go-gin-etcd-demo/ │ ├── employee/ │ ├──...

1 简介

在 Go (Golang) 项目中使用 Gin 实现两个服务:

    员工账号服务(employee-service)

    商品服务(product-service)

      etcd   服务注册与发现。

下面是完整示例代码以及etcd 配置与集成步骤。

2 项目结构示例

    go-gin-etcd-demo/
    │
    ├── employee/
    │   ├── main.go               # 员工服务入口
    │   └── handler.go            # Gin 路由与逻辑
    │
    ├── product/
    │   ├── main.go               # 商品服务入口
    │   └── handler.go
    │
    ├── common/
    │   ├── registry/
    │   │   └── etcd.go           # etcd注册与发现逻辑
    │   └── utils/
    │       └── config.go         # 公共配置
    │
    └── go.mod

3 准备工作

1️⃣ 安装依赖

  go get go.etcd.io/etcd/client/v3
  go get github.com/gin-gonic/gin
  go get github.com/google/uuid

2️⃣ 启动 etcd

本地运行:

    docker run -d --name etcd -p 2379:2379 \
      quay.io/coreos/etcd \
      /usr/local/bin/etcd \
      --advertise-client-urls http://0.0.0.0:2379 \
      --listen-client-urls http://0.0.0.0:2379

测试是否可访问:

    etcdctl --endpoints=http://localhost:2379 put testkey "hello etcd"
    etcdctl --endpoints=http://localhost:2379 get testkey

4 公共部分:etcd 注册中心逻辑

文件:common/registry/etcd.go

      package registry

      import (
          "context"
          "fmt"
          "log"
          "time"

          clientv3 "go.etcd.io/etcd/client/v3"
      )

      type EtcdRegistry struct {
          client *clientv3.Client
          lease  clientv3.Lease
      }

      func NewEtcdRegistry(endpoints []string) (*EtcdRegistry, error) {
          client, err := clientv3.New(clientv3.Config{
              Endpoints:   endpoints,
              DialTimeout: 5 * time.Second,
          })
          if err != nil {
              return nil, err
          }

          return &EtcdRegistry{
              client: client,
              lease:  clientv3.NewLease(client),
          }, nil
      }
  • 注册服务

     func (r *EtcdRegistry) Register(serviceName, addr string, ttl int64) error {
         leaseResp, err := r.lease.Grant(context.Background(), ttl)
         if err != nil {
             return err
         }
    
         key := fmt.Sprintf("/services/%s/%s", serviceName, addr)
         _, err = r.client.Put(context.Background(), key, addr, clientv3.WithLease(leaseResp.ID))
         if err != nil {
             return err
         }
    
         // 续租 keep alive
         ch, err := r.lease.KeepAlive(context.Background(), leaseResp.ID)
         if err != nil {
             return err
         }
    
         go func() {
             for {
                 <-ch
                 // 续租心跳
             }
         }()
    
         log.Printf("✅ 服务注册成功: %s => %s", serviceName, addr)
         return nil
     }
    
  • 发现服务

       func (r *EtcdRegistry) Discover(serviceName string) ([]string, error) {
           keyPrefix := fmt.Sprintf("/services/%s/", serviceName)
           resp, err := r.client.Get(context.Background(), keyPrefix, clientv3.WithPrefix())
           if err != nil {
               return nil, err
           }
    
           var addrs []string
           for _, kv := range resp.Kvs {
               addrs = append(addrs, string(kv.Value))
           }
           return addrs, nil
       }
    

5 服务的实现

  • 员工账号服务

文件:employee/main.go

      package main

      import (
          "fmt"
          "log"

          "github.com/gin-gonic/gin"
          "go-gin-etcd-demo/common/registry"
      )

      func main() {
          r := gin.Default()
          r.GET("/employee/:id", getEmployee)
          r.POST("/employee", createEmployee)

          // 注册到etcd
          etcd, _ := registry.NewEtcdRegistry([]string{"127.0.0.1:2379"})
          addr := "127.0.0.1:8081"
          err := etcd.Register("employee-service", addr, 10)
          if err != nil {
              log.Fatal(err)
          }

          r.Run(addr)
      }

      func getEmployee(c *gin.Context) {
          id := c.Param("id")
          c.JSON(200, gin.H{
              "id":   id,
              "name": "Tom",
          })
      }

      func createEmployee(c *gin.Context) {
          c.JSON(200, gin.H{"msg": "employee created"})
      }
  • 商品服务

文件:product/main.go

      package main

      import (
          "log"
          "net/http"

          "github.com/gin-gonic/gin"
          "go-gin-etcd-demo/common/registry"
      )

      func main() {
          r := gin.Default()
          r.GET("/product/:id", getProduct)
          r.GET("/employee-info/:id", getEmployeeFromDiscovery)

          // 注册服务
          etcd, _ := registry.NewEtcdRegistry([]string{"127.0.0.1:2379"})
          addr := "127.0.0.1:8082"
          err := etcd.Register("product-service", addr, 10)
          if err != nil {
              log.Fatal(err)
          }

          r.Run(addr)
      }

      func getProduct(c *gin.Context) {
          id := c.Param("id")
          c.JSON(200, gin.H{"id": id, "name": "Laptop"})
      }

      func getEmployeeFromDiscovery(c *gin.Context) {
          id := c.Param("id")
          reg, _ := registry.NewEtcdRegistry([]string{"127.0.0.1:2379"})
          addrs, _ := reg.Discover("employee-service")

          if len(addrs) == 0 {
              c.JSON(500, gin.H{"error": "employee-service not found"})
              return
          }

          resp, err := http.Get("http://" + addrs[0] + "/employee/" + id)
          if err != nil {
              c.JSON(500, gin.H{"error": err.Error()})
              return
          }
          defer resp.Body.Close()

          c.JSON(200, gin.H{"msg": "通过etcd发现的employee服务访问成功"})
      }
  • 运行流

1️⃣ 启动 etcd
2️⃣ 启动员工服务:

			go run employee/main.go

3️⃣ 启动商品服务:

		go run product/main.go

4️⃣ 测试:

		curl http://127.0.0.1:8082/employee-info/123

product-service 会通过 etcd 自动发现 employee-service 并转发请求。

6 总结

功能:服务框架,示例点:Gin
功能:注册中心,示例点:etcd
功能:注册机制,示例点:TTL + KeepAlive
功能:服务发现,示例点:通过 /services/{name}/ 前缀查找
功能:交互方式,示例点:HTTP REST

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。