服务的注册发现对于微服务来说是一个非常重要的环节,在单一架构应用中,service 之间的互相调用,通过一个固定的 host 和 port 来发起 REST 或者 RPC 来调用,但是在微服务架构中,各个服务往往是动态变化的,所以需要一个服务发现机制来发送客户端的请求到动态的 service 实例中去。

在利用 go micro 来实现服务发现便利很多,micro 中默认支持使用 Consul 来做服务发现,当然它使用插件机制(go-plugins)还支持 Etcd, Gossip, NATS 等其他的第三方服务注册发现工具。在每个服务启动的时候,都将自己注册到 registry 上,退出时也自动解注册,具体实现我们可以来看一下go-micro/service.go的相关代码片段:

......

func (s *service) run(exit chan bool) {
	if s.opts.RegisterInterval <= time.Duration(0) {
		return
	}

    //定时注册自己
	t := time.NewTicker(s.opts.RegisterInterval)

	for {
		select {
		case <-t.C:
			err := s.opts.Server.Register()
			if err != nil {
				log.Log("service run Server.Register error: ", err)
			}
		case <-exit:
			t.Stop()
			return
		}
	}
}

......

func (s *service) Start() error {
	for _, fn := range s.opts.BeforeStart {
		if err := fn(); err != nil {
			return err
		}
	}

	if err := s.opts.Server.Start(); err != nil {
		return err
	}
    // Run() 调用中也会结果run来调到这里来注册
	if err := s.opts.Server.Register(); err != nil {
		return err
	}

	for _, fn := range s.opts.AfterStart {
		if err := fn(); err != nil {
			return err
		}
	}

	return nil
}

func (s *service) Stop() error {
	var gerr error

	for _, fn := range s.opts.BeforeStop {
		if err := fn(); err != nil {
			gerr = err
		}
	}
   // 退出时自动解除注册
	if err := s.opts.Server.Deregister(); err != nil {
		return err
	}

	if err := s.opts.Server.Stop(); err != nil {
		return err
	}

	for _, fn := range s.opts.AfterStop {
		if err := fn(); err != nil {
			gerr = err
		}
	}

	return gerr
}
......

关于 Consul 的相关使用可以参考 《Consul 简介和快速入门》,下面主要来利用一个酒店预订的示例来看下 Go Micro 如何使用 Consul 的集群来做服务发现。

示例中会使用到一个 Micro API,它是 Micro 组件中的一个微服务 API 网关的实现,API 网关模式可以为服务提供一个入口,该 HTTP 入口动态路由到合适的后端 service,利用它进行服务发现,负载平衡,编码和基于 RPC 的通信。

api

Micro API 提供的 HTTP API 如下 :

- /[service]/[method]    # HTTP路径动态映射到services
- /rpc # 通过名称和方法显示调用后端service

在示例中使用 Micro API 的 RPC Handler,它是 go-micro 客户端将请求主体转发为 RPC 请求的默认处理程序的替代方案,具体 Micro API 的使用和 REST 映射规则可以查看文档https://micro.mu/docs/api.html

该酒店预定服务利用了官方 micro/examples中的 booking 示例改写, 具体代码 => https://github.com/yuansir/go-micro-consul-cluster

.
├── README.md
├── api
│   └── hotel   # booking service
├── data    # data
│   ├── bindata.go
│   ├── customers.json
│   ├── locations.json
│   ├── profiles.json
│   └── rates.json
├── docker-compose.yml # docker compose file
└── srv # services
    ├── auth    # auth token servce
    ├── geo     # geo service
    ├── profile # profile service
    └── rate    # rate service

docker-compose.yml

version: '3'

services:
    consul-agent-1: &consul-agent
        image: consul:latest
        networks:
            - consul-cluster
        command: 'agent -retry-join consul-server-bootstrap -client 0.0.0.0'

    consul-agent-2:
        <<: *consul-agent

    consul-agent-3:
        <<: *consul-agent

    consul-server-1: &consul-server
        <<: *consul-agent
        command: 'agent -server -retry-join consul-server-bootstrap -client 0.0.0.0'

    consul-server-2:
        <<: *consul-server

    consul-server-bootstrap:
        <<: *consul-agent
        ports:
            - '8400:8400'
            - '8500:8500'
            - '8600:8600'
            - '8600:8600/udp'
        command: 'agent -server -bootstrap-expect 3 -ui -client 0.0.0.0'

    auth:
        build: ./srv/auth
        networks:
            - consul-cluster
        command: --registry_address=consul-server-bootstrap:8500
        links:
            - consul-server-bootstrap
    geo:
        build: ./srv/geo
        networks:
            - consul-cluster
        command: --registry_address=consul-server-bootstrap:8500
        links:
            - consul-server-bootstrap
    profile:
        build: ./srv/profile
        networks:
            - consul-cluster
        command: --registry_address=consul-server-bootstrap:8500
        links:
            - consul-server-bootstrap
    rate:
        build: ./srv/rate
        networks:
            - consul-cluster
        command: --registry_address=consul-server-bootstrap:8500
        links:
            - consul-server-bootstrap
    api:
        build: ./api/hotel
        networks:
            - consul-cluster
        command: --registry_address=consul-server-bootstrap:8500
        links:
            - consul-server-bootstrap
            - auth
            - geo
            - profile
            - rate
    micro:
        networks:
            - consul-cluster
        command: --registry_address=consul-server-bootstrap:8500  api --handler=rpc
        image: microhq/micro:latest
        links:
            - consul-server-bootstrap
            - api
        ports:
            - '8080:8080'

networks: consul-cluster:

consul 每个数据中心至少必须拥有一台 server,建议在一个集群中有 3 或者 5 个 server.部署单一的 server,在出现失败时会不可避免的造成数据丢失.-bootstrap-expect 选项提示 Consul 我们期待加入的 server 节点的数量。每一个服务的--registry_address就是设置注册到的服务发现注册表地址。

docker-compose up 后可以通过 consul 的 web ui 来查看 Service 的状态。 1531203571067

转载请注明: 转载自Ryan 是菜鸟 | LNMP 技术栈笔记

如果觉得本篇文章对您十分有益,何不 打赏一下

谢谢打赏

本文链接地址: Go 实践微服务 – 服务发现

知识共享许可协议 本作品采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可