go微服务学习 go-micro框架
Posted Demonwuwen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go微服务学习 go-micro框架相关的知识,希望对你有一定的参考价值。
本节简单介绍micro和consul,具体使用放在下一节
1 micro简介
在了解go-micro之前,我们先来了解一下什么是micro。
Micro解决了在云内外构建分布式系统的关键要求。它利用微服务体系结构模式,并提供一组作为平台构建基块的服务. Micro 处理分布式系统的复杂性,并提供更简单的可编程抽象.
Micro是一个专注于简化分布式系统开发的微服务生态系统。由开源库和工具组成。主要包含以下几种库:
-
go-micro用于编写微服务的可插入Go-RPC框架; 服务发现,客户端/服务器rpc,pub/sub等,是整个Micro的核心。
默认使用mdns做服务发现,可以在插件中替换成consul,etcd,k8s等
组播 广播
-
go-plugins:go-micro的插件,包括etcd,kubernetes(k8s),nats,rabbitmq,grpc等
-
micro:一个包含传统入口点的微服务工具包; API网关,CLI,Slack Bot,Sidecar和Web UI。
其他各种库和服务可以在github.com/micro找到。
2 go-micro的主要功能
- 服务发现:自动服务注册和名称解析。服务发现是微服务开发的核心。当服务A需要与服务B通话时,它需要该服务的位置。默认发现机制是多播DNS(mdns),一种零配置系统。您可以选择使用SWIM协议为p2p网络设置八卦,或者为弹性云原生设置设置consul
- 负载均衡:基于服务发现构建的客户端负载均衡。一旦我们获得了服务的任意数量实例的地址,我们现在需要一种方法来决定要路由到哪个节点。我们使用随机散列负载均衡来提供跨服务的均匀分布,并在出现问题时重试不同的节点
- 消息编码:基于内容类型的动态消息编码。客户端和服务器将使用编解码器和内容类型为您无缝编码和解码Go类型。可以编码任何种类的消息并从不同的客户端发送。客户端和服务器默认处理此问题。这包括默认的protobuf和json
- 请求/响应:基于RPC的请求/响应,支持双向流。我们提供了同步通信的抽象。对服务的请求将自动解决,负载平衡,拨号和流式传输。启用tls时,默认传输为http / 1.1或http2
- Async Messaging:PubSub是异步通信和事件驱动架构的一流公民。事件通知是微服务开发的核心模式。启用tls时,默认消息传递是点对点http / 1.1或http2
- 可插拔接口:Go Micro为每个分布式系统抽象使用Go接口,因此,这些接口是可插拔的,并允许Go Micro与运行时无关,可以插入任何基础技术
插件地址:https://github.com/micro/go-plugins
2.1 服务发现
服务发现是微服务开发的核心。当服务A需要与服务B通话时,它需要该服务的位置。
我们在做微服务开发的时候,客户端的一个接口可能需要调用N个服务,客户端必须知道所有服务的网络位置(ip+port),如下图所示
以往的做法是把服务的地址放在配置文件活数据库中,这样就有以下几个问题:
- 需要配置N个服务的网络位置,加大配置的复杂性
- 服务的网络位置变化,需要改变每个调用者的配置
- 集群的情况下,难以做负载(反向代理的方式除外)
总结起来一句话:服务多了,配置很麻烦,问题一大堆
所以现在就选择服务发现来解决这些问题。
服务端把当前自己的网络位置注册到服务发现模块(这里注册的意思就是告诉),服务发现就以K-V的方式记录下,K一般是服务名,V就是IP:PORT。服务发现模块定时的轮询查看这些服务能不能访问的了(这就是健康检查)。客户端在调用服务A-N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务。这样的方式是不是就可以解决上面的问题了呢?客户端完全不需要记录这些服务的网络位置,客户端和服务端完全解耦!
2.2 了解consul并使用
Consul是一种服务网格解决方案,提供具有服务发现、配置和分段功能的全功能控制平面。这些特性可以根据需要单独使用,也可以一起使用以构建完整的服务网格。Consul需要一个数据平面,并支持代理和本地集成模型。Consul附带一个简单的内置代理,这样一切都可以开箱即用,但也支持第三方代理集成,如Envoy。
他提供了以下特性
服务发现:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
健康检查:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。(心跳机制)
键/值存储:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
安全服务通信:领事可以为服务生成和分发TLS证书,以建立相互的TLS连接。意图可用于定义允许哪些服务进行通信。服务细分可以很容易地进行管理,并且意图可以实时更改,而不是使用复杂的网络拓扑和静态防火墙规则。
多数据中心:无需复杂的配置,即可支持任意数量的区域。
官方建议:最好是三台或者三台以上的consul在运行,同名服务最好是三台或三台以上,默认可以搭建集群
2.2.1 consul安装
1、MacOS 安装
此方法安装比较方便:打开终端输入以下两行命令
brew tap hashicorp/tap
brew install hashicorp/tap/consul
注:这种安装方法会自动更新版本
如果需要更新到最新版本:
brew upgrade hashicorp/tap/consul
2、Ubuntu安装
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/
安装完成后终端输入consul确认:
consul
出现如图所示,即安装完毕。
2.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 页面 来查看服务发现的详情
info: 指令提供了各种操作时可以用到的debug信息,对于client和server,info有返回不同的子系统信息,目前有以下几个KV信息:agent(提供agent信息),consul(提供consul库的信息),raft(提供raft库的信息),serf_lan(提供LAN gossip pool),serf_wan(提供WAN gossip pool)
leave:指令触发一个优雅的离开动作并关闭agent,节点离开后不会尝试重新加入集群中。运行在server状态的节点,节点会被优雅的删除,这是很严重的,在某些情况下一个不优雅的离开会影响到集群的可用性。
members:指令输出consul agent目前所知道的所有的成员以及它们的状态,节点的状态只有alive、left、failed三种状态。
-detailed:输出每个节点更详细的信息。
-rpc-addr:一个rpc地址,agent可以链接上来发送命令,如果没有指定,默认是127.0.0.1:8400。
-status:过滤出符合正则规则的节点
reload:指令可以重新加载agent的配置文件。SIGHUP指令在重新加载配置文件时使用,任何重新加载的错误都会写在agent的log文件中,并不会打印到屏幕。
测试上述命令: 'bind的ip设置为你自己的ip'
consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.1.5 -ui -rejoin -d -client 0.0.0.0
此时看到提示:
打开浏览器:localhost:8500可以看到如下界面
如果我们创建自己的web.json文件
{
"service":{
"name": "Faceid",
"tags": ["rails"],
"port": 9000
}
}
命令行输入增加-config-dir=/path 就制定web.json的文件夹路径
consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.1.5 -ui -rejoin -config-dir=/Users/demon/Documents/go学习/consul.d -client 0.0.0.0
打开就看到如下界面。
2.3 注册服务到consul命令
步骤:
- 1 进入配置文件路径
- 2 创建json文件
- 3 按json语法填写服务信息
{
“service”:{
“name”: “Faceid”,
“tags”: [“rails”],
“port”: 9000
}
}- 4 重新启动consul
consul agent -server -bootstrap-expect 1 -data-dir /tmp/consul -node=n1 -bind=192.168.1.5 -ui -rejoin -config-dir=/Users/demon/Documents/go学习/consul.d -client 0.0.0.0
- 5 查询服务
- 1浏览器查看
关闭consul 使用命令 consul leave
2.4 健康检查
- 打开web.json配置文件
- 写入服务配置信息,给web.json文件添加如下信息:
{
"service":{
"name": "Faceid",
"tags": ["rails"],
"port": 9000,
"check":{
"id": "api",
"name": "rails check",
"http": "http:192.168.1.5:8800",
"interval": "5s",
"timeout": "1s"
}
}
}
- 执行consul reload 或者,consul leave关闭consul,重新启动consul
终端可看到如下信息
- 用浏览器输入localhost:8500查看Faceid这个服务情况
此时可以看到不健康,因为我们在json中设置了1ms消息超时检测,没有服务Faceid给consul回复。
除了 http 实现健康检查外,还可以使用 “脚本”、“tcp”、“ttl” 方式进行健康检查。
2.5 consul和grpc结合
安装 consul 源码包:
$ go get -u -v github.com/hashicorp/consul
使用整体流程
- 创建 proto文件 , 指定 rpc 服务
- 启动 consul 服务发现 consul agent -dev
- 启动server
- 获取consul 对象。
- 使用 consul对象,将 server 信息,注册给 consul
- 启动服务
- 启动client
- 获取consul 对象。
- 使用consul对象,从consul 上获取健康的 服务。
- 再访问服务 (grpc远程调用)
1. 创建proto文件,指定rpc服务
创建person.proto文件
syntax = "proto3";
option go_package = "./pb";
message Person {
string name = 1;
int32 age = 2;
}
// 添加 rpc服务
service hello {
rpc sayHello (Person) returns (Person);
}
在当前文件夹终端输入如下命令
protoc --go_out=. *.proto --go-grpc_out=. *.proto
此时会生成一个pb文件夹,里面就是通过person.proto
文件生成的go文件
person.pb.go
和person_grpc.pb.go
2. 启动 consul 服务发现
通过命令
consul agent -dev
此时可以通过打开localhost:8500查看
3. 启动server
服务端代码编写。
创建server文件夹,在里面创建server.go
package main
import (
"context"
"fmt"
"github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"grpcPrac/consul_grpc/pb"
"net"
)
type Children struct {
pb.UnimplementedHelloServer
}
func (this *Children) SayHello(ctx context.Context,p *pb.Person) (*pb.Person, error) {
p.Name = "Hello " + p.Name
return 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: "FaceID",
Tags: []string{"grpc","consul"},
Name: "grpc and consul",
Address: "127.0.0.1",
Port: 12345,
Check: &api.AgentServiceCheck{
CheckID: "consul grpc test",
TCP: "127.0.0.1:12345",
Timeout: "1s",
Interval: "5s",
},
}
//4. 注册grpc到服务发现consul
consulClient.Agent().ServiceRegister(®)
// grpc 服务远程调用
//1 初始化grpc对象
grpcServer := grpc.NewServer()
//2 注册服务
pb.RegisterHelloServer(grpcServer,&Children{})
//3 设置监听,指定IP端口
listener, err := net.Listen("tcp","127.0.0.1:12345")
if err!= nil{
fmt.Println("Listen err:",err)
return
}
defer listener.Close()
fmt.Println("服务启动... ")
//4 启动服务
grpcServer.Serve(listener)
}
启动服务
go run server.go
4. 启动client
package main
import (
"context"
"fmt"
"github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"grpcPrac/consul_grpc/pb"
"strconv"
)
func main() {
//初始化consul配置,客户端服务器需要一致
consultConfig := api.DefaultConfig()
//获取consul操作对象
regisgerClient, err := api.NewClient(consultConfig)
if err!= nil{
fmt.Println("api.NewClient err:",err)
return
}
//获取地址
serviceEntry,_,_:=regisgerClient.Health().Service("grpc and consul","grpc",true,nil)
//简单负载均衡
addr := serviceEntry[0].Service.Address+":"+strconv.Itoa(serviceEntry[0].Service.Port)
//1.连接服务
grpcConn, err := grpc.Dial(addr,grpc.WithInsecure())
if err!= nil{
fmt.Println("grpc.Dial err:",err)
return
}
//2.初始化客户端
grpcClient := pb.NewHelloClient(grpcConn)
var person pb.Person
person.Name = "Huang"
person.Age = 18
//3. 调用远程函数
p,err := grpcClient.SayHello(context.TODO(),&person)
fmt.Println(p, err)
}
启动客户端,可以看到如下结果
我们其实还可以打开localhost:8500查看consul服务
2.6 服务注销
当我们需要注销服务的时候,就可以编写以下程序。
package main
import "github.com/hashicorp/consul/api"
func main() {
//1.初始化consul配置
consulConfig := api.DefaultConfig()
//2.创建consul对象
consulClient,_ := api.NewClient(consulConfig)
//3.注销服务
consulClient.Agent().ServiceDeregister("FaceID")
}
运行程序后,我们查看web端就可以发现,grpc and consul
这一项服务消失了
3 go-micro核心接口
go-micro之所以可以高度订制和他的框架结构是分不开的,go-micro由8个关键的interface组成,每一个interface都可以根据自己的需求重新实现,这8个主要的inteface也构成了go-micro的框架结构
以上是关于go微服务学习 go-micro框架的主要内容,如果未能解决你的问题,请参考以下文章