特性
服务发现
自动服务注册和发现。默认使用consul作为服务发现和注册中心,可通过插件化修改为其他的注册中心,比如etcd,zookeeper等。
负载均衡
基于服务发现的客户端负载平衡。
消息编码
基于内容类型的动态消息编码。 客户端和服务器将根据内容类型使用对应的编解码器。
同步流
基于RPC的请求/响应,支持双向流。提供了同步通讯的抽象。向服务发出的请求将被自动解析、负载平衡、拨号和流处理。 默认值启用tls时,transport为http / 1.1或http2。
异步消息
PubSub是作为异步通信和事件驱动架构的一等公民而构建的。事件通知是微服务开发的核心模式。启用tls时,默认消息传递是点对点http1.1或http2。
可插拔接口
Go Micro为每个分布式系统抽象出Go接口。这些接口是可插拔的,并且允许Go Micro不依赖于运行时。您可以插入任何底层技术。
micro toolkit
micro是一个工具包。提供了一些工具方便在go-micro微服务架构中使用。
|
|
问题
使用micro toolkit,安装其他插件,第一次build缺少相关包,go get 下来,build成功之后运行命令,报如下错误:
|
|
解决方法参考该链接:https://github.com/etcd-io/etcd/issues/9357#issuecomment-377560659
使用
手动取消注册
1micro deregister service '{"name":"<service.name>","version":"<service.version>","nodes":[{"id":"<node.id>"}]}'
如何使用
安装服务注册发现中心
本地使用docker安装consul:
- 本地安装docker
- 运行
docker pull consul
命令从docker hub上拉取最新官方consul镜像 - 运行
docker run -d --name=local-consul -e CONSUL_BIND_INTERFACE=eth0 -p 8500:8500 consul
命令启动docker容器,需要暴露8500端口,否则本地服务无法注册到consul
服务端
|
|
客户端
|
|
踩过的坑
go-micro框架客户端连接池大小配置不是只建这么多的连接,源码中的处理机制是每次发起客户端请求首先检查池中有没有连接,如果没有连接会直接新建一个连接发起请求,连接用完释放连接的时候会检查池中的连接数是达到配置的连接数,如果达到配置的连接数直接关闭该连接,如果未达到才将该连接放到池中。这就会导致一个问题,如果请求量过大会导致连接一直在创建,最终会报 too many open files 错误。
下面是go-micro框架中client端获取连接和释放连接的源码:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859// 获取连接func (p *pool) getConn(addr string, tr transport.Transport, opts ...transport.DialOption) (*poolConn, error) {p.Lock()conns := p.conns[addr]now := time.Now().Unix()// while we have conns check age and then return one// otherwise we'll create a new conn// 1. 首先检查池中可用连接数是否大于1for len(conns) > 0 {conn := conns[len(conns)-1]conns = conns[:len(conns)-1]p.conns[addr] = conns// if conn is old kill it and move onif d := now - conn.created; d > p.ttl {conn.Client.Close()continue}// we got a good conn, lets unlock and return itp.Unlock()// 2. 直接返回池中连接return conn, nil}p.Unlock()// create new conn// 3. 如果池中没有连接了,这时新建一个连接并返回c, err := tr.Dial(addr, opts...)if err != nil {return nil, err}return &poolConn{c, time.Now().Unix()}, nil}// 释放连接func (p *pool) release(addr string, conn *poolConn, err error) {// don't store the conn if it has erroredif err != nil {conn.Client.Close()return}// otherwise put it back for reusep.Lock()conns := p.conns[addr]// 1. 检查池中连接数是否已达到最大,如果达到最大直接关闭连接if len(conns) >= p.size {p.Unlock()conn.Client.Close()return}// 2. 未达到池中最大连接数将该连接放入池中p.conns[addr] = append(conns, conn)p.Unlock()}客户端配置register直接放到main方法获取测试用例中都可以调用到服务端,但是本地同样启个服务端然后在服务里面配置客户端register发现未生效,一直使用默认的consul。本地测试代码如下:
12345678910111213141516171819202122232425// 这种方式在测试用例中是可以调用成功的// 但是如果和server一起启动,就会初始化失败,使用的register始终都是默认的consulfunc TestClient(t *testing.T) {var c client.Clientr := etcdv3.NewRegistry(registry.Addrs("127.0.0.1:2379"))c = client.NewClient()c.Init(client.Selector(selector.NewSelector(selector.Registry(r))),client.PoolSize(100), //连接池大小client.PoolTTL(5*time.Minute), //长连接缓存时间client.Retries(3), //重试次数client.RequestTimeout(30*time.Second), //请求超时client.DialTimeout(2*time.Second), //客户端连接超时client.Transport(tcp.NewTransport()),)Client = service.NewDemoService("demo.service", c)rsp, err := Client.Do(context.TODO(), &Request{Say: "hello",})if err != nil {t.Errorf("err %v\n", err)}}
这篇博客只是关于go-micro的一个简单介绍以及入门使用,笔者也在学习阶段,随着研究的深入也会分享更多关于go-micro的只是给大家。
参考文档
Micro Documentation[go-micro]
Micro Documentation[function]
Micro examples repository
go-micro 框架介绍
Micro-Api文档