go-micro框架
0.micro框架
在了解go-micro之前,我们先来了解一下什么是micro。
Micro是一个专注于简化分布式系统开发的微服务生态系统。由开源库和工具组成。主要包含以下几种库:
go-micro用于编写微服务的可插入Go-RPC框架; 服务发现,客户端/服务器rpc,pub/sub等,是整个Micro的核心。
默认使用mdns做服务发现,可以在插件中替换成consul,etcd,k8s等
go-pluginsgo-micro的插件,包括etcd,kubernetes(k8s),nats,rabbitmq,grpc等
micro一个包含传统入口点的微服务工具包; API网关,CLI,Slack Bot,Sidecar和Web UI。
其他各种库和服务可以在github.com/micro找到。
我们先来了解一下服务发现是个什么东西?有什么作用?
1.服务发现
我们在做微服务开发的时候,客户端的一个接口可能需要调用N个服务,客户端必须知道所有服务的网络位置(ip+port),如下图所示
以往的做法是把服务的地址放在配置文件活数据库中,这样就有以下几个问题:
- 需要配置N个服务的网络位置,加大配置的复杂性
- 服务的网络位置变化,需要改变每个调用者的配置
- 集群的情况下,难以做负载(反向代理的方式除外)
总结起来一句话:服务多了,配置很麻烦,问题一大堆
所以现在就选择服务发现来解决这些问题。我们来看一下,服务发现如何解决这个问题,具体设计如下:
与之前解决方法不同的是,加了个服务发现模块。服务端把当前自己的网络位置注册到服务发现模块(这里注册的意思就是告诉),服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问的了(这就是健康检查)。客户端在调用服务A-N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样的方式是不是就可以解决上面的问题了呢?客户端完全不需要记录这些服务的网络位置,客户端和服务端完全解耦!
常见的服务发现框架有:Etcd、Eureka、Consul、Zookeeper
这里我们选择go-micro默认的服务发现框架consul来做一个详细介绍。
2.了解consul并使用
Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。包含多个组件,但是作为一个整体,为你的基础设施提供服务发现和服务配置的工具.他提供以下关键特性:
服务发现:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
健康检查:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。(心跳机制)
键/值存储:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
多数据中心:无需复杂的配置,即可支持任意数量的区域。
官方建议:最好是三台或者三台以上的consul在运行,同名服务最好是三台或三台以上,默认可以搭建集群
2.1consul安装
Consul用Golang实现,因此具有天然可移植性 (支持 Linux、windows和macOS)。安装包仅包含一个可执行文件。 Consul安装非常简单,只需要下载对应系统的软件包并解压后就可使用。
安装步骤如下:
# 这里以 ubuntu系统为例:
$ wget https://releases.hashicorp.com/consul/1.5.2/consul_1.5.2_linux_amd64.zip
$ unzip consul_1.5.2_linux_amd64.zip
$ sudo mv consul /usr/local/bin/
也可用离线包进行解压安装
链接:https://pan.baidu.com/s/1OQoAdn2_IrWbYbQUCg3_zQ
提取码:a4rd
安装验证:
安装 Consul后,通过执行 consul命令,你可以看到命令列表的输出
~ consul
无报错即为成功
2.2 consul的命令行
consul安装好之后,我们来使用一下吧。首先我们来看一下consul都有哪些命令。使用命令consul -h
可以查看consul支持的所有参数,而且每个参数里面还支持其他参数,下面我们来具体看看。
agent指令是consul的核心,它运行agent来维护成员的重要信息、运行检查、服务宣布、查询处理等等。
-bind=0.0.0.0 指定 consul所在机器的 IP地址。 默认值:0.0.0.0
-http-port=8500 consul 自带一个web访问的默认端口:8500
-client=127.0.0.1 表明哪些机器可以访问consul 。 默认本机。0.0.0.0 所有机器均可访问。
-config-dir=foo 所有主动注册服务的 描述信息
-data-dir=path 储存所有注册过来的srv机器的详细信息。
-dev 开发者模式,直接以默认配置启动 consul
-node=hostname 服务发现的名字。
-rejoin consul 启动的时候,加入到的 consul集群
-server 以服务方式开启consul, 允许其他的consul 连接到开启的 consul上 (形成集群)。如果不加 -server, 表示以 “客户端” 的方式开启。不能被连接。
-ui 可以使用 web 页面 来查看服务发现的详情
测试上述命令:
# 在终端中,键入:
consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.6.108 -ui -rejoin -config-dir=/etc/consul.d/ -client 0.0.0.0#看到提示:
==> Consul agent running!
需要先在/etc/下面创建consul.d目录
-server
: 定义agent运行在server模式-bootstrap-expect
:在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap共用-bind
:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0-node
:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名-ui
: 启动web界面 :8500-rejoin
:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。-config-dir
:配置文件目录,里面所有以.json结尾的文件都会被加载-client
:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0data-dir
:提供一个目录用来存放agent的状态,所有的agent允许都需要该目录,该目录必须是稳定的,系统重启后都继续存在
启动 Google 浏览器, 测试:
2.2.1停止consul
你可以使用Ctrl-C 不优雅的关闭Agent. 中断Agent之后你可以看到他离开了集群并关闭.
在退出中,Consul提醒其他集群成员,这个节点离开了.如果你强行杀掉进程.集群的其他成员应该能检测到这个节点失效了.当一个成员离开,他的服务和检测也会从目录中移除.当一个成员失效了,他的健康状况被简单的标记为危险,但是不会从目录中移除.Consul会自动尝试对失效的节点进行重连.允许他从某些网络条件下恢复过来.离开的节点则不会再继续联系.
此外,如果一个agent作为一个服务器,一个优雅的离开是很重要的,可以避免引起潜在的可用性故障影响达成一致性协议.
consul优雅的退出:
$ consul leave
2.2.2注册服务
搭建好conusl集群后,用户或者程序就能到consul中去查询或者注册服务。可以通过提供服务定义文件或者调用HTTP API来注册一个服务.
这里我们使用定义服务文件来注册一个服务:
{"service": {"name": "Faceid","tags": ["rails"],"port": 9000}
}
服务定义文件在我们的配置目录下面,
/etc/consul.d/
,文件都是以.json结尾。
注册完服务之后,我们重启consul。
2.2.3查询服务
一旦agent启动并且服务同步了.我们可以通过DNS或者HTTP的API来查询服务.这里我们通过HTTP来查询服务:
$ curl -s 127.0.0.1:8500/v1/catalog/service/faceid
可以得到一串json数据,可拿去进行json格式解析,还可以打开web页面,查看注册的服务。默认consul对应的端口是8500,在浏览器输入地址`localhost:8500,也可以看到注册的服务
2.2.4健康检查
健康检查是服务发现的关键组件.预防使用到不健康的服务.和服务注册类似,一个检查可以通过检查定义或HTTP API请求来注册.我们将使用和检查定义来注册检查.和服务类似,因为这是建立检查最常用的方式.
在/etc/consul.d/目录下面创建文件web2.json,内容如下:
{"service": {"name": "web","tags": ["extract", "verify", "compare", "idcard"],"address": "192.168.137.130","port": 9000,"check": {"id": "api","name": "HTTP API on port 9000","http": "http://localhost:9000","interval": "10s","timeout": "1s"}}
}
如果我们没有开启服务,那么健康检查一定会报错
consul做健康检查的必须是Script、HTTP、TCP、TTL中的一种。
Script类型需要提供Script脚本和interval变量。**具体配置如下:
{ "check": { "id": "mem-util", "name": "Memory utilization", "script": "/usr/local/bin/check_mem.py", "interval": "10s", "timeout": "1s" }
}
通过执行外部应用进行健康检查:这种外部程序具有退出代码,并可能产生一些输出;脚本按照指预置时间间隔来调用(比如,每30秒调用一次),类似于Nagios插件系统,脚本输出限制在4K以内,输出大于4K将截断。默认情况下,脚本超时时间为30秒——可通过timeout来配置。
HTTP类型必须提供http和Interval字段。具体代码如下:
{ "check": { "id": "api", "name": "HTTP API on port 5000", "http": "http://localhost:5000/health", "interval": "10s", "timeout": "1s" }
}
这种检查将按照预设的时间间隔创建一个HTTP “get”请求。HTTP响应代码来标示服务所处状态:任何2xx代码视为正常,429表示警告——有很多请求;其他值表示失败。
这种类型的检查应使用curl或外部程序来处理HTTP操作。默认情况下,HTTP Checks中,请求超时时间等于调用请求的间隔时间,最大10秒。有可能使用客制的HTTP check,可以自由配置timeout时间,输出限制在4K以内,输出大于4K将截断。
TCP类型需要提供tcp和Interval字段。具体代码如下:
{ "check": { "id": "ssh", "name": "SSH TCP on port 22", "tcp": "localhost:22", "interval": "10s", "timeout": "1s" }
}
这种检查将按照预设的时间间隔与指定的IP/Hostname和端口创建一个TCP连接。服务的状态依赖于TCP连接是否成功——如果连接成功,则状态是“success”;否则状态是“critical”。如果一个Hostname解析为一个IPv4和一个IPv6,将尝试连接这两个地址,第一次连接成功则服务状态是“success”。默认情况下,TCP checks中,请求超时时间等于调用请求的间隔时间,最大10秒。也是可以自由配置的。
TTL(Timeto Live生存时间)类型只需提供ttl,具体配置如下:
{ "check": { "id": "web-app", "name": "Web App Status", "notes": "Web app does a curl internally every 10 seconds", "ttl": "30s" }
}
这种checks为给定TTL保留了最后一种状态,checks的状态必须通过HTTP接口周期性更新,如果外部接口没有更新状态,那么状态就会被认定为不正常。 TTL checks同时会将其最后已知状态更新至磁盘,这允许Agent通过重启后恢复到已知的状态。通过TTL端上一次check来维持健康状态的有效性。
其他更多consul功能,我们可以参考http://www.liangxiansen.cn/2017/04/06/consul/
2.3consul和grpc结合使用
先从GitHub下载consul包
$ go get -u -v github.com/hashicorp/consul
将grpc服务注册到consul上
- 创建 proto文件, 指定 rpc 服务
- 启动 consul 服务发现
- 启动server
- 获取consul 对象。
- 使用 consul对象,将 server 信息,注册给 consul
- 启动服务
- 启动client
- 获取consul 对象。
- 使用consul对象,从consul 上获取健康的 服务。
- 再访问服务 (grpc远程调用)
代码示例:
proto文件:
syntax = "proto3";package pb;message Person {string name = 1;int32 age = 2;
}// 添加 rpc服务
service hello {rpc sayHello (Person) returns (Person);
}
服务端:
package mainimport ("google.golang.org/grpc""day02/pb""context""net""fmt""github.com/hashicorp/consul/api"
)// 定义类
type Children struct {
}// 绑定类方法, 实现借口
func (this *Children)SayHello(ctx context.Context, p *pb.Person) (*pb.Person, error) {p.Name = "hello " + p.Namereturn p, nil
}func main() {// 把grpc服务,注册到consul上.// 1. 初始化consul 配置consulConfig := api.DefaultConfig()// 2. 创建 consul 对象consulClient, err := api.NewClient(consulConfig)if err != nil {fmt.Println("api.NewClient err:", err)return}// 3. 告诉consul, 即将注册的服务的配置信息reg := api.AgentServiceRegistration {ID:"bj38",Tags:[]string{"grcp", "consul"},Name:"grpc And Consul",Address:"127.0.0.1",Port:8800,Check:&api.AgentServiceCheck{CheckID:"consul grpc test",TCP:"127.0.0.1:8800",Timeout:"1s",Interval:"5s",},}// 4. 注册 grpc 服务到 consul 上consulClient.Agent().ServiceRegister(®)//以下为 grpc 服务远程调用// 1.初始化 grpc 对象,grpcServer := grpc.NewServer()// 2.注册服务pb.RegisterHelloServer(grpcServer, new(Children))// 3.设置监听, 指定 IP/portlistener, err := net.Listen("tcp", "127.0.0.1:8800")if err != nil {fmt.Println("Listen err:", err)return}defer listener.Close()fmt.Println("服务启动... ")// 4. 启动服务grpcServer.Serve(listener)}
客户端:
package mainimport ("google.golang.org/grpc""day02/pb""context""fmt""github.com/hashicorp/consul/api""strconv"
)func main() {// 初始化 consul 配置consulConfig := api.DefaultConfig()// 创建consul对象 -- (可以重新指定 consul 属性: IP/Port , 也可以使用默认)consulClient, err := api.NewClient(consulConfig)// 服务发现. 从consuL上, 获取健康的服务services, _, err := consulClient.Health().Service("grpc And Consul", "grcp", true, nil)// 简单的负载均衡.addr := services[0].Service.Address + ":" + strconv.Itoa(services[0].Service.Port)//以下为 grpc 服务远程调用///// 1. 链接服务//grpcConn, _ := grpc.Dial("127.0.0.1:8800", grpc.WithInsecure())// 使用 服务发现consul 上的 IP/port 来与服务建立链接grpcConn, _ := grpc.Dial(addr, grpc.WithInsecure())// 2. 初始化 grpc 客户端grpcClient := pb.NewHelloClient(grpcConn)var person pb.Personperson.Name = "Andy"person.Age = 18// 3. 调用远程函数p, err := grpcClient.SayHello(context.TODO(), &person)fmt.Println(p, err)
}
3go-micro框架
做了这么久的铺垫,接着让我们来进入主题,go-micro的学习。
3.1go-micro安装
首先我们先来安装一下go-micro开发环境。安装步骤如下:
#安装go-micro
go get -u -v github.com/micro/go-micro
#安装工具集
go get -u -v github.com/micro/micro
#安装protobuf插件
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/micro/protoc-gen-micro
或者通过docker镜像安装:
$ docker pull microhq/micro
安装之后输入micro命令,显示如下就证明安装成功
3.2go-micro使用
首先我们先来创建一个go micro框架的项目,创建项目我们使用micro命令,micro类似于beego框架中的beego,可以创建微服务,web项目等,具体用法如下:
new Create a new Micro service by specifying a directory path relative to your $GOPATH
#创建 通过指定相对于$GOPATH的目录路径,创建一个新的微服务。USAGE:
#用法
micro new [command options][arguments...]
#指定服务的命名空间
--namespace "go.micro" Namespace for the service e.g com.example
#服务类型,可以是微服务src,或者web项目web,或者是api等
--type "srv" Type of service e.g api, fnc, srv, web
#服务的正式定义全面
--fqdn FQDN of service e.g com.example.srv.service (defaults to namespace.type.alias)
#别名是在指定时作为组合名的一部分使用的短名称 别名
--alias Alias is the short name used as part of combined name if specified
创建一个web项目
micro new --type "web" micro/rpc/web
Creating service go.micro.web.web in /home/itcast/go/src/micro/rpc/web
.
#主函数
├── main.go
#插件文件
├── plugin.go
#被调用处理函数
├── handler
│ └── handler.go
#前端页面
├── html
│ └── index.html
#docker生成文件
├── Dockerfile
├── Makefile
└── README.md#编译后将web端呼叫srv端的客户端连接内容修改为srv的内容
#需要进行调通
创建微服务
$micro new --type "srv" t1/t1
#"srv" 是表示当前创建的微服务类型
#micro是相对于go/src下的文件夹名称 可以根据项目进行设置
#srv是当前创建的微服务的文件名
Creating service go.micro.srv.srv in /home/itcast/go/src/t1/t1.
#主函数存放位置
├── main.go
#插件
├── plugin.go
#服务提供函数的实现
├── handler
│ └── example.go
#订阅服务
├── subscriber
│ └── example.go
#proto协议
├── proto/example
│ └── example.proto
#docker生成文件
├── Dockerfile
#编译文件
├── Makefile
└── README.md#插件提示,已安装,可忽略
download protobuf for micro:brew install protobuf
go get -u github.com/golang/protobuf/{proto,protoc-gen-go}
go get -u github.com/micro/protoc-gen-microcompile the proto file example.proto:cd /home/itcast/go/src/micro/rpc/srv
protoc --proto_path=. --go_out=. --micro_out=. proto/example/example.proto
go-micro框架创建完成后即可对其文件中的代码进行相应修改,实现自己的项目需求。
go-micro框架相关推荐
- 牌类游戏使用微服务重构笔记(四): micro框架使用经验
项目依赖 推荐使用go module, 我选择go module的最主要原因是足够简单,可以脱离gopath,就跟写nodejs一样,随便在一个地方新建一个文件夹就可以撸代码了,clone下来的源码也 ...
- C# WPF Caliburn.Micro框架下利用Mef加载其它项目界面
01 - 前言 MEF是微软自家的托管可扩展框架,在这里我把它用成了ioc容器.在Caliburn.Micro框架下,view和viewmodel被注入到CompositionContainer容器中 ...
- C# WPF MVVM模式Caliburn.Micro框架下事件发布与订阅
01 - 前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Caliburn提供了一种事件机制,可以在应用程序中低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订阅者之间 ...
- f12控制台如何查看consul_基于 Consul 的 Go Micro 客户端服务发现是如何实现的
基于 Consul 的 Go Micro 客户端服务发现是如何实现的 由 学院君 创建于1年前, 最后更新于 1年前 版本号 #1 上篇分享我们介绍了基于 Consul 作为注册中心的 Go Micr ...
- C# WPF MVVM模式Prism框架下事件发布与订阅
01 - 前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Prism提供了一种事件机制,可以在应用程序中低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订阅者之间通过事 ...
- C# WPF MVVM模式Prism框架从零搭建(经典)
01 - 前言 目前最新的PRISM的版本是8.1.97,本节以6.3.0.0 讲解,可以在Github上获取PRISM的源码. Prism Github地址:https://github.com/P ...
- 找不到服务器micro,Go Micro服务发现
服务发现,就是通过什么办法可以找到需要调用的服务的地址(ip和端口),因为只有拿到服务的地址,我们才可以连接服务,发送接口调用请求. 上一个章节,我们没说明两个服务直接是如何找到对方的,只是使用服务名 ...
- go-micro框架介绍
go-micro介绍及环境搭建 一.micro框架介绍 1.1.概述 Micro是一个简化分布式开发的微服务生态系统,该系统为开发分布式应用程序提供了高效,便捷的模块构建.主要目的是简化分布式系统的开 ...
- MICRO和GO-MICRO
createdtime 20211124 updatedtime 20211126 author venki.chen 一.是什么 1. 定义,是做什么用的? go micro是什么? go-micr ...
- micro、M3O微服务系列(一)
本系列以go,micro3为主 文章目录 软件开发的预测 什么是微服务 为什么使用微服务 什么是micro 理清微服务的关键字 微服务必然涉及的服务发现 使用go和micro构建全球服务网络 隧道 路 ...
最新文章
- VmWare 与 宿主主机通信 STEP BY STEP (适用于刚開始学习的人)
- 引导类、扩展类、系统类加载器的使用及演示
- Go语言字符串和正则表达式
- 服务器启动时Webapp的web.xml中配置的加载顺序
- 音视频中的CBR,VBR,ABR
- Java 面向对象的设计原则
- kafka基础之核心概念
- mac eclipse 安装lombok_别再写getter,setter方法了,用Lombok来简化你的代码吧
- 如何在Ubuntu上安装MariaDB
- linux的vmstat命令,vmstat命令参数详解
- 计算机芯片级维修包括哪些,电脑芯片级维修教程
- mpa和pis_压力单位MPa/psi/bar之间的换算?
- R语言中常用的生物多样性指数的计算(Alpha,Beta,Gamma,功能多样性,系统发育多样性)
- 资源变现小程序添加折扣充值和折扣影票插件
- 1190 -- 找x
- element实现form表单动态添加email效果
- V_rep与vs2019开发环境配置
- 大类资产配置(三)市场择时能力模型T-M
- fMRI与MRI区别+名词解释+MRI中T1和T2的含义与区分
- 安全多方计算之六:秘密共享