ServiceComb 开发实战(2)—— Service-Center 服务注册发现对接


上一章 ServiceComb 开发实战(1) —— Service-Center 安装部署 中,主要了解了一下 Service-Center(SC)的安装和启动(不太了解的童鞋可以点击链接查看)。在文章末尾我们使用了 curl 命令模拟 provider 与 consumer 服务的注册与发现流程,本章将通过官方的 api 文档,动手构建对接示例。

一. 服务注册发现

为什么使用服务注册发现

在微服务架构中,一个应用由一组职责单一化的服务组成。在分布式系统中,各个服务会被动态的部署到不同的节点,为了高可用性,一些服务亦会出现多实例的情况。面对这样一组服务,加上服务的动态伸缩容,如果仅通过人工配置的形式来管理服务之间的依赖,这将是一件无比艰巨的维护任务。于是诞生了“注册中心”这样的解决方案,它提供了注册机制,让服务将自己的信息登记到中心;提供了发现机制,供服务从中心查找其他的服务信息。

服务注册发现流程

下面是来自 Service-Center 官方的设计原理
为了方便理解,这里将整个流程与现实生活中的“找对象”流程类比:

启动流程:
服务注册发现启动流程
1 待婚者(Provider)向 婚恋机构(Service-Center)提交 个人信息
2 婚恋机构(Service-Center)将 待婚者(Provider)个人信息存储起来(ETCD)
3 求偶者(Consumer)向 婚恋机构(Service-Center)获取符合条件的 待婚者(Provider)信息
4 求偶者(Consumer)将 待婚者(Provider)信息存储到通讯录(cache)
5 求偶者(Consumer)向 婚恋机构(Service-Center)订阅 待婚者(Provider)动态

通讯流程:
服务注册发现通讯流程
1 婚恋机构(Service-Center)制定了契约,要求 待婚者(Provider)每30s向自己报告健康状况(心跳保活),如果未收到报告,信息将会过期并被删除;
2 求偶者(Consumer)向 婚恋机构(Service-Center)订阅了 待婚者(Provider)动态,若有变化,将更新通讯录(cache);
3 求偶者(Consumer)从通讯录(cache)中获取联系方式(endpoints),并进行通讯。

二. Service-Center对接

1.创建项目

创建名为 “helloworld”的项目,以下为参考目录结构:

.
└── rest
    ├── common
    │   ├── config
    │   │   └── config.go
    │   │       // 配置文件解析
    │   │   
    │   ├── restful
    │   │   └── restutil.go
    │   │       // http 请求简单封装
    │   │   
    │   └── servicecenter
    │       └── v3
    │           └── registery.go
    │               // Service-Center v3 接口 client 实现
    ├── consumer
    │   ├── conf
    │   │   └── microservice.yaml
    │   │       // 微服务配置
    │   │
    │   └── helloclient.go
    │       // 消费端入口
    │
    └── provider
        ├── conf
        │   └── microservice.yaml
        │       // 微服务配置
        │
        └── helloserver.go
            // 服务端入口
2. v3 接口 client 实现

Service-Center 的服务注册与发现是基于 RESTful 标准接口实现的,与编程语言无关,以下内容基于 golang 进行实现,仅因本人对 golang 比较熟悉,其他语言可以参考官网 API 文档 进行实现。

文件位置:rest/common/servicecenter/v3/registery.go 文件

var (
    // 接口 API 定义
    microServices = "/registry/v3/microservices"
    svcInstances  = "/registry/v3/microservices/%s/instances"
    discovery     = "/registry/v3/instances"
    existence     = "/registry/v3/existence"
    heartbeats    = "/registry/v3/heartbeats"
    watcher       = "/registry/v3/microservices/%s/watcher"

    microServiceType sourceType = "microservice"
    schemaType       sourceType = "schema"
)

type sourceType string

type Client struct {
   
    rawURL string
    domain string
}

func NewClient(addr string, domain string) *Client {
   
    return &Client{
   rawURL: addr, domain: domain}
}

// 查询微服务是否存在
func (c *Client) existence(params url.Values) (*proto.GetExistenceResponse, error) {
   
    reqURL := c.rawURL + existence + "?" + params.Encode()
    
    // 对http.NewRequest接口的简单封装,详情请见 rest/common/restful/restutil.go
    req, err := restful.NewRequest(http.MethodGet, reqURL, c.DefaultHeaders(), nil)
    if err == nil {
   
        respData := &proto.GetExistenceResponse{
   }
        
        // 对http.Do接口的简单封装,详情请见 rest/common/restful/restutil.go
        err = restful.DoRequest(req, respData)
        if err == nil {
   
            return respData, nil
        }
    }
    return nil, err
}

// 获取微服务服务ID
func (c *Client) GetServiceID(svc *config.ServiceConf) (string, error) {
   
    val := url.Values{
   }
    val.Set("type", string(microServiceType))
    val.Set("appId", svc.AppID)
    val.Set("serviceName", svc.Name)
    val.Set("version", svc.Version)
    respData, err := c.existence(val)
    if err == nil {
   
        return respData.ServiceId, nil
    }
    return "", fmt.Errorf("[GetServiceID]: %s", err)
}

// 注册微服务
func (c *Client) RegisterService(svc *config.ServiceConf) (string, error) {
   
    ms := &proto.CreateServiceRequest{
   
        Service: &proto.MicroService{
   
            AppId:       svc.AppID,
            ServiceName: svc.Name,
            Version:     svc.Version,
        },
    }

    reqURL := c.rawURL + microServices
    req, err := restful.NewRequest(http.MethodPost, reqURL, c.DefaultHeaders(), ms)
    if err == nil {
   
        respData := &proto.CreateServiceResponse{
   }
        err = restful.DoRequest(req, respData)
        if err == nil {
   
            return respData.ServiceId, nil
        }
    }
    return "", fmt.Errorf("[RegisterService]: %s", err)
}

// 注册微服务实例
func (c *Client) RegisterInstance(svcID string, ins *config.InstanceConf) (string, error) {
   
    endpoint := ins.Protocol + "://" + ins.ListenAddress
    ms := &proto.RegisterInstanceRequest{
   
        Instance: &proto.MicroServiceInstance{
   
            HostName:  ins.Hostname,
            Endpoints: []
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值