Go-Micro微服务框架使用

本文暂不介绍GRPC,只介绍通过HTTP方式进行服务间的API调用。且所有示例均采用Go Mod方式管理依赖包。

1.Go-Micro微服务框架简介

Go-Micro类似Java中的SpringCloud,虽然生态上有一些区别,但是可以类比比较。官当Github地址为 https://github.com/micro/go-micro,下载安装依赖命令:

go get -u github.com/micro/go-micro

2.创建Web服务

Golang本身提供了丰富的http包,并且Gin等Web框架实现一个Web服务,但是为了贴合Go-Micro框架的统一规范,所以需要通过使用Go-Micro的github.com/micro/go-micro/web包来创建一个Web服务。

第一种方式:

直接通过web包创建一个服务,参数可选,也比较简单易懂,请自行Ctrl+左键查看源码。创建服务后可以直接像原生的http包一样使用。

func main() {
	service := web.NewService(
		web.Name("cas"),
		web.Address(":8001"),
	)
	service.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
		// handler
	})
	service.Run()
}

第二种方式:
原生的http包在很多情况下处理并不是非常高效,只是提供了一些基础功能,所以Go-Micro提供集成第三方Web框架如:Gin。首先下载安装:

go get -u "github.com/gin-gonic/gin"

Go-Micro整合Gin示例:

func main() {
	engine := gin.Default()
	engine.GET("/hello", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello,world",
		})
	})
	service := web.NewService(
		web.Name("cas"),
		web.Address(":8001"),
		web.Handler(engine),
	)
	service.Run()
}

除了上述的方式直接指定Web服务的相关参数,我们也可以通过命令行参数启动Web服务,这样我们可以在命令行通过指定不同的服务名和端口,快速的多开同一个服务。虽然实际开发部署环境很少用这种方式,但在我们自己调试服务注册与发现时,会非常有用。
 
示例如下,只需要调用Init()方法即可,可自行查看源码,源码中可查看有关的命令函参数名:

func main() {
	engine := gin.Default()
	engine.GET("/hello", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello,world",
		})
	})
	service := web.NewService(
		//web.Name("cas"),
		//web.Address(":80"),
		web.Handler(engine),
	)
	service.Init()
	service.Run()
}

启动命令:

go run main.go -server_name cas -server_address :8001

3.服务注册

3.1 Consul

以Consul作为注册中心,官方下载地址:https://www.consul.io/downloads.html

Windows环境安装:

  1. 直接下载后将consul.exe解压出来;
  2. 将其所解压到的目录文件名添加到path环境变量;
  3. 在 cmd 命令窗口中执行:consul agent -dev命令即可启动Consul服务
  4. Consul 自带 UI 管理界面,访问地址:http://localhost:8500 ,可以看到当前注册的服务:
    在这里插入图片描述

Linux环境安装:

  1. 直接通过官网Linux版本Download处对应的地址下载:wget https://releases.hashicorp.com/consul/1.9.0/consul_1.9.0_linux_amd64.zip
  2. 解压:unzip consul_1.9.0_linux_amd64.zip
  3. 修改权限:chmod 777 consul
  4. 整理一下,将consul文件夹复制到/usr/local/bin/目录下:cp consul /usr/local/bin/
  5. 输入consul命令查看安装是否成功:consul version
  6. 启动consul,并通过-client配置外网主机可访问:consul agent -dev -client=0.0.0.0

当然其实最方便的就是直接通过docker拉个镜像,直接映射端口跑起来就可以了~

服务注册到Consul:

在安装好Consul并启动好服务后,下载Go-Micro提供的插件包go-plugins

go get -u github.com/micro/go-plugins

该包包含了Consul和其他的众多插件(如:eureka等),基本的使用方法是使用consul.NewRegistry()接口创建注册中心对象,然后将其集成到Go-Micro提供的Web服务配置中:

package main

import (
	"github.com/gin-gonic/gin"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-micro/web"
	"github.com/micro/go-plugins/registry/consul"
	"net/http"
)

func main() {
	consulReg := consul.NewRegistry(registry.Addrs(":8500"))
	engine := gin.Default()
	engine.GET("/hello", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello,world",
		})
	})
	service := web.NewService(
		web.Name("cas"),
		web.Address(":8001"),
		web.Registry(consulReg),
		web.Handler(engine),
	)
	service.Init()
	service.Run()
}

可以在Consul管理UI看到服务已经注册成功~
在这里插入图片描述

3.2 etcd

4 服务发现

从注册中心拿服务的方法也比较简单,简单几步即可拿到服务信息:

  1. 同服务注册一样,首先创建Consul注册中心对象:consul.NewRegistry()
  2. 通过Consul对象调用GetService("cas")方法拿到服务节点切片,参数为注册的服务名,所以在上文注册服务时指定的服务名很关键;
  3. 通过Go-Micro提供的selector包拿到具体的服务节点,该包提供2种常见的负载均衡算法,RoundRobin(轮询)Random(随机)。对应方法返回的是一个Next方法,Next方法调用后才返回具体的服务节点,可以自行查看源码;
  4. 拿到具体的服务节点结构体对象后,则可以通过服务的IP等信息,发起HTTP的API调用。

示例代码和运行结果:

package main

import (
	"github.com/micro/go-micro/client/selector"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/consul"
	"log"
)

func main() {
	consulReg := consul.NewRegistry(registry.Addrs(":8500"))
	service, err := consulReg.GetService("cas")
	if err != nil {
		log.Fatal("get service from consul err :",err)
	}
	node, err := selector.RoundRobin(service)()
	if err != nil {
		log.Fatal("get service node err :",err)
	}
	log.Printf("service node : %+v", node)
}
//运行打印的log内容
2020-12-09 10:50:46.501937 I | service node : &{Id:ec20b3c9-7531-4921-89bc-73ee7e233525 Address:192.168.152.1:8002 Metadata:map[]}

如果启动时发生依赖报错,请参考我的另一篇博文对该问题的解决:Go-Micro启动依赖报错解决方法 。如要查看轮询或随机效果,可以自己写一个for循环间隔获取节点,查看节点信息的变化情况~

5.服务调用

5.1 HTTP基本调用方式

最基础的就是通过Golang官方提供的http包发起HTTP请求。直接在上文服务发现示例代码的基础上,在拿到服务节点信息后,发情API请求。

package main

import (
	"fmt"
	"github.com/micro/go-micro/client/selector"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/registry/consul"
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)

func main() {
	consulReg := consul.NewRegistry(registry.Addrs(":8500"))
	// 服务发现
	service, err := consulReg.GetService("cas")
	if err != nil {
		log.Fatalf("get service from consul err : %+v",err)
	}
	node, err := selector.RoundRobin(service)()
	if err != nil {
		log.Fatalf("get service node err : %+v",err)
	}
	log.Printf("service node : %+v", node)
	// 服务调用
	url := fmt.Sprintf("http://%s/hello", node.Address)
	reqBody := strings.NewReader("")
	request, err := http.NewRequest(http.MethodGet, url, reqBody)
	if err != nil {
		log.Fatalf("create request err : %+v",err)
	}
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		log.Fatalf("send request err : %+v",err)
	}
	defer response.Body.Close()
	rspBody, err := ioutil.ReadAll(response.Body)
	if err != nil {
		log.Fatalf("read  response body err : %+v",err)
	}
	log.Printf("rsp body : %+v", string(rspBody))
}

//运行结果:
//2020-12-09 11:45:16.422562 I | service node : &{Id:bda22dae-9bc2-46db-b325-bcc9ab2b6778 Address:192.168.152.1:8001 Metadata:map[]}
//2020-12-09 11:45:16.436525 I | rsp body : {"msg":"hello,world"}

5.1 Go-Micro中的HTTP调用方式(推荐)

这种方式也是使用http包,但和上述Golang官方提供的不同,这种方式使用的是Go-Micro的插件包go-plugins,具体为:"github.com/micro/go-plugins/client/http"包,go-plugins包除了有http client的基本功能,还支持Selector参数,自动选取服务,并支持json、protobuf等数据格式。

上述的基础调用方式可以明显发现调用过程其实还是比较繁琐的,而这种方法流程上简化了很多,插件对一些步骤进行了封装和自动化处理,步骤主要为将注册中心放到Selector选择器中,然后基于选择器创建httpClient,通过该客户端来发起请求,调用服务。需要注意的是,插件默认认为服务调用都是通过POST请求的方式,所以指定的接口一定要为POST:

package main

import (
	"context"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/client/selector"
	"github.com/micro/go-micro/registry"
	"github.com/micro/go-plugins/client/http"
	"github.com/micro/go-plugins/registry/consul"
	"log"
)

func main() {
	consulReg := consul.NewRegistry(registry.Addrs(":8500"))
	selector := selector.NewSelector(
		selector.Registry(consulReg),
		selector.SetStrategy(selector.RoundRobin),
	)
	httpClient := http.NewClient(
		// 选择器
		client.Selector(selector),
		// 响应格式默认格式protobuf,设置为json
		client.ContentType("application/json"),
		)
	req := map[string]string{}
	request := httpClient.NewRequest("cas", "/hello", req)
	rsp := map[string]interface{}{}
	err := httpClient.Call(context.Background(), request, &rsp)
	if err != nil {
		log.Fatalf("request err: %+v", err)
	}
	log.Printf("%+v",rsp)
}

注意:如果出现运行报错:{"id":"go.micro.client","code":500,"detail":"none available","status":"Internal Server Error"},可以查看我的另一篇博文:Go-Micro客户端请求报500错误的解决方法,对该问题有详细的分析和解决。

其他需要注意的是服务调用这边只支持json形式传参,所以如Gin中请使用Bind()的方式获取请求参数:

engine := gin.Default()
	engine.POST("/hello", func(c *gin.Context) {
		req := struct {
			Name string `json:"name"`
		}{}
		c.BindJSON(&req)
		c.JSON(http.StatusOK, gin.H{
			"msg": "hello,world",
			"name": req.Name,
		})
	})
<think>好的,我现在需要处理用户关于TensorFlow Lite Micro框架的查询。首先,用户想了解框架的介绍、文档、下载以及示例教程。我需要根据提供的引用内容来组织回答,并确保符合之前的系统级指令,比如正确使用LaTeX格式和添加引用标识。 首先,查看用户提供的引用内容。引用[1]、[3]、[4]、[5]都提到了TensorFlow Lite Micro的项目结构、教程、案例和转换方法。引用[2]提到在Arduino开发板上的应用。这些信息可以用来构建回答的不同部分,比如框架概述、核心功能、应用场景等。 接下来,我需要确保回答结构清晰,分点说明。按照用户的请求,应该包括框架介绍、文档资源、下载方式、示例教程这几个部分。每个部分需要引用对应的引用来源,比如介绍部分引用[5],文档和下载引用[1][3][5],示例教程引用[3][5],应用场景引用[2][3]。 然后,生成相关问题。根据用户的问题,可能涉及与其他框架的比较、模型转换步骤、硬件兼容性、调试工具、性能优化、实际案例等。需要确保问题与用户的需求相关,并且能够引导进一步的学习。 最后,检查LaTeX格式是否正确。例如,如果有数学表达式,需要用$...$,但在这个回答中可能不需要,所以重点放在代码块的格式和引用标识的正确添加上。代码示例需要正确使用三个反引号包裹,并注明语言类型,如python或C++。同时,每个引用标识要自然添加在相关段落的末尾。 现在,整合这些信息,确保每个部分都有对应的引用支持,结构清晰,语言通顺,并且符合用户的要求。例如,在介绍框架时,引用[5]的项目介绍;在文档部分,引用[1]和[5]的教程信息;在示例教程中,提到HaaS EDU K1案例引用[3]和Arduino的案例引用[2]。最后生成的相关问题需要覆盖用户可能感兴趣的扩展方向,如与其他框架对比、模型转换、硬件支持等。 可能需要注意,用户提供的引用中有一些是关于具体案例和代码转换的内容,需要正确引用到相应的部分。同时,确保回答中的每个引用标识对应正确的来源,例如引用[1]是关于目录结构和配置文件的介绍,引用[3]是案例下载,引用[5]是项目地址和介绍等。 在组织语言时,尽量使用简洁明了的中文,分点列出,便于用户快速获取信息。同时,生成的示例代码块需要正确无误,如果有的话,但根据引用内容,可能主要是项目结构和配置,而不是具体代码,所以可能不需要插入代码块,但用户提供的示例中有Python代码,可能需要根据情况调整。 总结,回答的结构大致如下: 1. 框架概述(引用[5]) 2. 核心功能(引用[5][4]) 3. 文档资源(引用[1][5]) 4. 下载方式(引用[5]) 5. 示例教程(引用[3][2][5]) 6. 应用场景(引用[2][3][5]) 然后生成相关问题,确保覆盖用户可能关心的其他方面,如模型转换、性能优化、硬件兼容性等。</think>### TensorFlow Lite Micro框架介绍 #### 1. 框架概述 TensorFlow Lite Micro(TFLite Micro)是专为**低功耗、资源受限的嵌入式设备**设计的机器学习框架,支持微控制器(MCU)和数字信号处理器(DSP)等目标平台。其核心目标是将轻量级ML模型部署到边缘设备,实现离线推理[^5]。 #### 2. 核心功能 - **模型优化**:通过量化、剪枝等技术减少模型体积,例如使用`tf.lite.TFLiteConverter`转换具体函数[^4]。 - **跨平台支持**:兼容Arduino、HaaS EDU K1等开发板[^2][^3]。 - **低内存占用**:运行时内存需求可低至数十KB,适用于MCU环境。 #### 3. 文档资源 - **官方教程**:涵盖项目结构、启动文件配置等基础知识[^1]。 - **API文档**:提供C/C++接口说明,便于嵌入式开发集成[^3][^5]。 #### 4. 下载方式 项目代码托管在GitCode镜像仓库,可直接克隆或下载: ```bash git clone https://gitcode.com/gh_mirrors/tf/tflite-micro.git ``` [^5] #### 5. 示例教程 - **离线语音唤醒案例**:通过HaaS EDU K1开发板实现快捷词检测(C/C++代码)。 - **Arduino BLE 33 Nano Sense应用**:运行预训练模型实现传感器数据处理。 #### 6. 应用场景 - **智能家居**:本地语音指令识别。 - **工业物联网**:设备状态实时监测与异常检测。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值