micro / plugins

Go Micro plugins
Apache License 2.0
96 stars 92 forks source link

micro service reg consul by extranet ip #64

Open hzxgo opened 2 years ago

hzxgo commented 2 years ago

I have two micro services deployed on different pc, the two services reg the same consul by extranet ip. However, the second service can't access to first service by rpc.

consul start-up: consul agent -server -ui -bootstrap-expect=1 -data-dir=/data/consul -node=hostname -bind=0.0.0.0 -advertise=49.234.57.x -client=0.0.0.0

first service(go-micro-v3):

func main() {
    service := micro.NewService(
        micro.Name("first"),
        micro.Registry(consul.NewRegistry(registry.Addrs("49.234.57.x:8500"))),
    )
    service.Init()
    pb.RegisterFirstHandler(service.Server(), new(handler.First))
    service.Run()
}

second service(go-micro-v3):

func main() {
    service := micro.NewService(
        micro.Name("second"),
        micro.Registry(consul.NewRegistry(registry.Addrs("49.234.57.x:8500"))),
    )
    service.Init()
    firstCli := pb.NewFirstService("first", service.Client())
    go func() {
        time.Sleep(1*time.Second)
        obj := &pb.Response{}
        data, err := firstCli.Hello(context.Background(), &pb.Request{})
        if err != nil {
             fmt.Println(err)
        } else {
            types.UnmarshalAny(data.GetData(), obj)
            fmt.Println(obj)
        }
    }
    service.Run()
}

Test:

  1. If the first/second server deployed on the same cloud pc, the second server can get data from the first server by rpc.
  2. If the first/second server deployed on different cloud pc(Both pc have access to all ports), I will get error: {"id":"go.micro.client","code":408,"detail":"call timeout: context deadline exceeded","status":"Request Timeout"}","time":"x"}

the second service(ip: 52.81.x.x) can get data from the first server(ip: 49.234.57.x) by extranet ip reg consul?

lhqbalabala commented 2 years ago

I also encountered this problem.

My reason is that the server opens an intranet port

And go micro registers the intranet port to etcd

This makes the two servers unable to connect through the intranet

In grpc, I registered the public IP to etcd. The local server opens the intranet IP so that other servers can perform RPC through the public IP

However, in go micro, the registry and the open port seem to be integrated, so I did not find a solution

lhqbalabala commented 2 years ago

In the source code micro web service I found gensrv(), which is used to return the IP registered in the registry If advertise is set, advertise will be registered instead of address

func (s *service) genSrv() *registry.Service {
    var host string
    var port string
    var err error

    // default host:port
    if len(s.opts.Address) > 0 {
        host, port, err = net.SplitHostPort(s.opts.Address)
        if err != nil {
            logger.Fatal(err)
        }
    }

    // check the advertise address first
    // if it exists then use it, otherwise
    // use the address
    if len(s.opts.Advertise) > 0 {
        host, port, err = net.SplitHostPort(s.opts.Advertise)
        if err != nil {
            logger.Fatal(err)
        }
    }

    addr, err := maddr.Extract(host)
    if err != nil {
        logger.Fatal(err)
    }

    if strings.Count(addr, ":") > 0 {
        addr = "[" + addr + "]"
    }

    return &registry.Service{
        Name:    s.opts.Name,
        Version: s.opts.Version,
        Nodes: []*registry.Node{{
            Id:       s.opts.Id,
            Address:  net.JoinHostPort(addr, port),
            Metadata: s.opts.Metadata,
        }},
    }
}

Therefore, web services only need the following settings:

http := web.NewService(
        web.Name("xxx"),
        web.Address("Your intranet IP"),
        web.Registry(Reg),
        web.Handler(engine),
        web.Advertise("Your Internet IP"),
)

Similarly, if it is an RPC service, you can set the server's advertise

app := micro.NewService(
        micro.Name(""),
        micro.Address(""),
        micro.Registry(Reg),
        func(o *micro.Options) {
            o.Server.Init(server.Advertise(""))
        },
    )