【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等等)

news2025/3/6 15:19:33

【后端开发】go-zero微服务框架实践(goland框架对比,go-zero开发实践,文件上传问题优化等)

文章目录

    • 1、go框架对比介绍
    • 2、go-zero 微服务开发实践
    • 3、go-zero 文件上传问题优化

1、go框架对比介绍

国内开源goland框架对比 1

  • go-zero,2020开源,30kstar:
    整体上做为一个稍重的微服务框架,提供了微服务框架需要具备的通用能力,同时也只带一部分的强约束,例如针对web和rpc服务需要按照其定义的DSL的协议格式进行定义,日志配置、服务配置、apm配置等都要按照框架定义的最佳实践来走。
  • go-kratos,2019开源,23kstar:
    整体上做为一个轻量级的微服务框架,B站开源项目; web和rpc服务的 DSL协议直接采用protobuf和grpc进行定义,采用wire做依赖注入、自动生成代码。 框架定位于解决微服务的核心诉求。
  • tarsgo,2018开源,3kstar:
    做为tars这个大的C++重量级微服务框架下的go语言服务框架,腾讯开源项目; 对于有个好爹的这个事情,总是喜忧参半的;好处在于很多能力不用从头开始做起,直接依托母体;劣势就是独立性相对较差,要选用这个tarsgo的前提,就是要先选用tars这个大的框架。
  • dubbo go,2019开源,4kstar
    做为dubbo这个大的Java重量级微服务框架下的go语言服务框架,阿里开源项目;优劣基本跟tarsgo一样
  • jupiter,2020开源,4kstar
    重量级的微服务框架,斗鱼开源项目;整体思路上跟tars和dubbo力图提供一个大一统的框架,更确切的说是一个微服务平台,也带类似tars和dubbo那样的管理控制台,提供各种控制和metric的继承,这也无形中给选用此框架带来了不少代价。
  • go-mirco,2015开源,22kstar
    一个轻量级的微服务框架,做为一个在2015年就开源的项目,在当时那个市面上开源的微服务框架稀少的年代,它是为数不多的选择。
  • go-kit,2015开源,26kstar
    从严格意义上来说,并不能做为一个微服务框架,而应该是一个微服务的工具集,其官方定义上也是这么说,提供各种选项让你自由选择。做为一个在2015年就开源的项目,也是当时很多go项目为数不多的选择之一。
  • 综上所属,选型时选择go-zero

go-zero介绍 1, 2 云原生go-zero微服务框架设计思考

  • go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。
    go-zero 包含极简的 API 定义和生成工具 goctl,可以根据定义的 api 文件一键生成 Go, iOS, Android, Kotlin, Dart, TypeScript, JavaScript 代码,并可直接运行。
  • 框架设计​
    轻松获得支撑千万日活服务的稳定性,内建级联超时控制、限流、自适应熔断、自适应降载等微服务治理能力,无需配置和额外代码,微服务治理中间件可无缝集成到其它现有框架使用,极简的 API 描述,一键生成各端代码,自动校验客户端请求参数合法性,大量微服务治理和并发工具包。
  • 框架特点​
    强大的工具支持,尽可能少的代码编写,极简的接口,完全兼容 net/http,支持中间件,方便扩展,高性能,面向故障编程,弹性设计,内建服务发现、负载均衡,内建限流、熔断、降载,且自动触发,自动恢复,API 参数自动校验,超时级联控制,自动缓存控制,链路跟踪、统计报警等,高并发支撑,稳定保障了疫情期间每天的流量洪峰。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

2、go-zero 微服务开发实践

1、数据库和数据表设计

  • 微服务进行服务拆分一个最好理解并且最基本的原则就是:每个服务对应一个单独的数据库。做到服务与服务之间的解耦,划清边界。 1
  • 这就要求我们明确项目(服务)需求之后,做好表结构设计。
  • 我们后续项目中用到的model、proto、甚至api层的结构体都可以通过工具根据数据库生成,所以数据库的设计至关重要
  • 这部分所有微服务都是一样的,在这里就不再赘述
  • 部分设计规范可参考 1, 2, 3
  • 最佳实践
    范式设计:遵循数据库范式原则,最少达到第三范式,以减少数据冗余。
    分区考虑:对大数据量表采取分区设计,以提高查询效率。
    索引:为常用查询字段添加索引,以加速数据库查询。
    规范命名:使用统一的命名规范(如小写字母加下划线)来提高可读性。
    外键约束:适当设置外键以确保数据的完整性与关联性。

在这里插入图片描述
在这里插入图片描述

2、使用工具生成model

  • 使用goctl中的model命令生成,1
  • 为了进一步提高效率,我们对此进行了封装,方便我们更快更好的生成model
    比如在model文件夹里保留建表的sql文件,用后缀_gen,_script等补充更多功能性的查询函数。
  • 注意事项:
    生成代码后,手动检查是否符合业务逻辑,尤其是验证函数。
    定期更新模型代码,保持与数据库的同步。
    自定义字段类型:如果有特殊数据类型,考虑自定义字段类型以保证数据正确性。

3、开发api层

  • 先定义xxx.api文件,可以参考 api demo
  • 使用goctl生成代码:goctl api go -api main.api -dir …/ --style=goZero
  • 配置生成代码中的config目录以及yaml文件,弄清它们两者之间的联系
  • 配置生成代码svc目录中的文件(比如jwt之类的中间件)
  • 最佳实践
    RESTful 设计原则:遵循 RESTful API 设计规范,确保接口的可理解性和一致性。
    参数验证:对输入参数进行严格验证,使用中间件处理错误和异常。
    使用 Swagger:集成 Swagger 将 API 接口文档化,便于开发和调试。
  • 注意事项:
    设计清晰的错误返回结构,方便前端处理。
    避免过于复杂的路由,保持路由设计的简洁性。

4、开发rpc层

  • 使用goctl生成pb.go文件:goctl rpc protoc lottery.proto --go_out=…/ --go-grpc_out=…/ --zrpc_out=…/ --style=goZero
  • 配置svc,注册model
  • 编写logic,调用model,写业务代码
  • 最佳实践:
    Protocol Buffers:使用 Protocol Buffers 作为序列化方式,以提高传输效率。
    接口隔离原则:为不同的服务定义清晰且独立的接口,减少各服务间的耦合。
  • 注意事项:
    在开发过程中使用本地模拟服务进行测试,确保 RPC 调用的稳定性。
    定义通用的错误处理机制,以便各个服务能够统一处理错误。

5、在api层注册rpc服务,调用rpc方法,对外提供接口

  • api层配置svc,注册rpc客户端
  • 调用rpc方法
  • 返回restful api
  • 最佳实践:
    API与RPC解耦:保证 API 层与 RPC 层之间的解耦,便于后期修改和扩展。
    服务发现:在微服务架构中,使用服务注册和发现机制(如 Consul 或 Nacos)来管理服务地址。
  • 注意事项:
    在服务注册时确保服务的健康检查设置,及时发现并替换故障服务。
    关注 RPC 服务的性能监控,避免因服务调用导致的性能瓶颈。

6、生成接口文档

  • 虽然goctl不直接支持生成swagger,但是goctl的插件支持。- goctl-swagger 通过 api 文件生成 swagger 文档
  • 安装好goctl-swagger插件之后,我们就可以在api层的xxx.api同级目录下生成swagger了
  • 参考命令如下:其中main.api是我在api层的desc目录中定义的,我们也在同级目录执行goctl命令即可:
  • goctl api plugin -plugin goctl-swagger=“swagger -filename main.json” -api main.api -dir .
  • 执行之后,就会出现如下图所示的main.json,这就是swagger文件
  • 你可以直接使用swagger进行测试,也可以导入到其他工具中
  • 注意事项:
    定期审查和维护接口文档,确保其准确性与时效性。
    对于较复杂的业务逻辑,提供详细的说明和使用场景,增强文档的可读性。

更多微服务开发最佳实践

  • 项目结构管理-分层架构
    规范目录结构,遵循行业最佳实践,提供可预见的目录结构,方便团队协作,保持代码的清晰和可维护性
    避免将所有代码放在同一目录中,防止代码杂乱无章。注重模块之间的低耦合、高内聚设计。
    apis, etc, catch, gen, pkg, config, handle, logic, middleware, rpchelper, svc, types, pkg, convert, etcd, constvalue, util, test等等

  • 错误处理与日志记录
    统一错误处理机制:定义通用的错误类型和处理函数,提高错误处理的可维护性。
    结构化日志:使用结构化日志工具(如 Logrus 或 Zap)来记录 API 调用和服务事件,便于后续分析。
    定期审查和分析日志,寻找潜在的性能瓶颈和异常。
    避免在生产环境记录敏感信息,确保日志安全。

  • 安全性
    身份认证与授权:使用 JWT 或 OAuth 2.0 实现用户身份认证与授权,增强 API 的安全性。
    数据加密:保护敏感数据,包括数据库存储的敏感信息和 API 请求的传输安全。
    定期更新认证和授权机制,以适应新的安全威胁。
    关注服务间通讯的安全性,尤其是在多服务间的 RPC 调用中。

  • 性能优化
    缓存策略:利用 Redis 等缓存机制来减轻数据库负担,提高数据访问速度。
    异步处理:使用消息队列(如 Kafka 或 RabbitMQ)处理不需要实时响应的任务,实现异步化。
    进行性能测试,确定程序瓶颈点并进行针对性优化。
    定期评估 Cache 的失效策略和更新机制,以避免缓存污染。

  • 服务监控与运维
    监控和报警:使用 Prometheus 和 Grafana 等工具监控微服务的性能指标,并设置报警规则,以便实时响应。
    健康检查:实现定期健康检查,确保服务的可用性。
    监控数据的采集和存储应考虑存储成本和数据的清理策略。
    对于重要的服务,建议引入熔断和重试机制,以提升系统的鲁棒性。

  • 持续集成与持续交付 (CI/CD)
    自动化测试:为 API 和 RPC 层编写单元测试和集成测试,确保代码质量。
    CI/CD 工具:使用 Jenkins、GitLab CI 或 GitHub Actions 等工具,实现代码的自动构建、测试和部署。
    保持 CI/CD 流程的可用性和高效性,定期审查构建和部署的效率。
    确保每次代码提交都能触发 CI 流程,及时反馈问题。

  • 文档与知识共享
    维护开发文档:记录开发过程中遇到的问题及解决方案,形成知识库。
    代码评审:开展代码评审活动,促进团队成员间的学习和知识共享。
    定期更新文档,确保其与实际开发保持一致。
    鼓励团队成员共享经验与最佳实践,共同提升团队的整体水平

3、go-zero 文件上传问题优化

背景与问题

  • 使用go-zero框架,在定义请求消息的时候默认没有支持file类型的types,1 2
  • 项目实现不方便换成gin框架(成本高)
  • request中body请求信息有一个参数需要file类型,用于支持上传文件的场景, 上传代码 1

在这里插入图片描述

api

type (
UploadFileReq {	}
UploadFileRes {
	Code int64 `json:"code"`
	Msg  string `json:"msg"`
	Data string `json:"data"`
}
service file-upload {
	@handler uploadFile
	post /uploadFile (UploadFileReq) returns (UploadFileRes)
}

handler

func UploadFileHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 解析表单
		fileData, handler, err := r.FormFile("file")
		if err != nil {
			httpx.Error(w, err)
			return
		}
		// 关闭文件数据
		defer fileData.Close()
		// 文件上传
		filename := handler.Filename
		l := file.NewUploadFileLogic(r.Context(), svcCtx)
		resp, err := l.UploadFile(&fileData, filename)
	}
}

service

package file

import (
	"encoding/csv"
	"fmt"
	"github.com/xuri/excelize/v2"
	"io"
	"log"
	"mime/multipart"
	"strings"
)

func (l *UploadFileLogic) UploadFile(data *multipart.File, fileName string) (resp *types.UploadFileResp, err error) {
	// 上传对象存储
	ossConfig := l.svcCtx.Config.OssConfig
	filePath := fmt.Sprintf("uploads/%s", fileName)

	err = file.UploadFile(*data, filePath, file.OssConfig{
		AccessKeyId:     ossConfig.AccessKeyId,
		AccessKeySecret: ossConfig.AccessKeySecret,
		BucketName:      ossConfig.BucketName,
		Endpoint:        ossConfig.Endpoint,
		BucketDoMan:     ossConfig.BucketDoMan,
	})
	if err != nil {
		l.Logger.Errorf("上传文件失败, err:%s", err.Error())
		return nil, err
	}

	// 解析文件内容
	fileType := strings.ToLower(fileName[strings.LastIndex(fileName, ".")+1:])
	switch fileType {
	case "csv":
		// 解析 CSV 文件
		csvData, err := l.parseCSVFile(*data)
		if err != nil {
			l.Logger.Errorf("解析 CSV 文件失败, err:%s", err.Error())
			return nil, err
		}
		l.Logger.Infof("解析到的 CSV 数据: %v", csvData)
	case "xlsx", "xls":
		// 解析 Excel 文件
		excelData, err := l.parseExcelFile(*data)
		if err != nil {
			l.Logger.Errorf("解析 Excel 文件失败, err:%s", err.Error())
			return nil, err
		}
		l.Logger.Infof("解析到的 Excel 数据: %v", excelData)
	default:
		return nil, fmt.Errorf("不支持的文件类型: %s", fileType)
	}

	// 构造返回值
	resp = &types.UploadFileResp{
		FilePath: filePath,
		FileName: fileName,
	}

	return resp, nil
}

// 解析 CSV 文件
func (l *UploadFileLogic) parseCSVFile(file multipart.File) ([][]string, error) {
	reader := csv.NewReader(file)
	records, err := reader.ReadAll()
	if err != nil {
		return nil, fmt.Errorf("读取 CSV 文件失败: %w", err)
	}
	return records, nil
}

// 解析 Excel 文件
func (l *UploadFileLogic) parseExcelFile(file multipart.File) ([][]map[string]string, error) {
	excel := excelize.NewFile()
	defer func() {
		if err := excel.Close(); err != nil {
			log.Printf("关闭 Excel 文件失败: %s", err.Error())
		}
	}()
	// 读取 Excel 文件内容
	err := excel.ImportFromReader(file)
	if err != nil {
		return nil, fmt.Errorf("导入 Excel 文件失败: %w", err)
	return parsedData, nil
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2310583.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#—csv文件格式操作实例【在winform表格中操作csv】

C#—csv文件格式操作实例【在winform表格中操作csv】 实例一 实例效果 当在winform界面中点击读取按钮时 将csv中的所有数据读取出来放置在datagridview控件,可以在datagridview控件中编辑数据,当点击保存按钮时 将datagridview控件中的所有数据存储在…

一周学会Flask3 Python Web开发-WTForms表单验证

锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们可以通过WTForms表单类属性的validators属性来实现表单验证。 常用的WTForms验证器 验证器说明DataRequired(messageNo…

23种设计模式一览【设计模式】

文章目录 前言一、创建型模式(Creational Patterns)二、结构型模式(Structural Patterns)三、行为型模式(Behavioral Patterns) 前言 设计模式是软件工程中用来解决特定问题的一组解决方案。它们是经过验证…

GPIO及其应用

GPIO及其应用 文章目录 GPIO及其应用1.GPIO概括2.GPIO工作基本结构3.GPIO寄存器3.1寄存器总览3.2寄存器功能3.3BIT简写的代表 4.GPIO的电气特性4.1拉电流与灌电流4.2驱动大功率负载4.3电平逻辑兼容性 5.LED闪烁(实操)6.LED交替闪烁(实操)7.开关控制LED灯…

NO1.C++语言基础|四种智能指针|内存分配情况|指针传擦和引用传参|const和static|c和c++的区别

1. 说⼀下你理解的 C 中的四种智能指针 智能指针的作用是管理指针,可以避免内存泄漏的发生。 智能指针就是一个类,当超出了类的作用域时,就会调用析构函数,这时就会自动释放资源。 所以智能指针作用的原理就是在函数结束时自动释…

Vue 关于如何在vue中实现跨域请求问题

📚首先,让我们了解一下什么是跨域。当一个请求的URL的协议、域名、端口三者中任意一个与当前页面的URL不同,就称为跨域请求。 🔒为什么会出现跨域问题呢?这是因为浏览器的同源策略限制。同源策略是浏览器最核心的安全…

毕业项目推荐:基于yolov8/yolov5/yolo11的暴力行为检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示:功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出(xls格式)功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

torch.einsum 的 10 个常见用法详解以及多头注意力实现

torch.einsum 是 PyTorch 提供的一个高效的张量运算函数,能够用紧凑的 Einstein Summation 约定(Einstein Summation Convention, Einsum)描述复杂的张量操作,例如矩阵乘法、转置、内积、外积、批量矩阵乘法等。 1. 基本语法 tor…

【DeepSeek】一文详解GRPO算法——为什么能减少大模型训练资源?

GRPO,一种新的强化学习方法,是DeepSeek R1使用到的训练方法。 今天的这篇博客文章,笔者会从零开始,层层递进地为各位介绍一种在强化学习中极具实用价值的技术——GRPO(Group Relative Policy Optimization&#xff09…

Ollama 框架本地部署教程:开源定制,为AI 项目打造专属解决方案!

Ollama 是一款开源的本地大语言模型(LLM)运行框架,用于管理和运行语言模型。具有以下核心特点: 开源可定制:采用 MIT 开源协议,开发者能自由使用、阅读源码并定制,可根据自身需求进行功能扩展和…

开发环境搭建-03.后端环境搭建-使用Git进行版本控制

一.Git进行版本控制 我们对项目开发就会产生很多代码,我们需要有效的将这些代码管理起来,因此我们真正开发代码前需要把我们的Git环境搭建好。通过Git来管理我们项目的版本,进而实现版本控制。 首先我们使用Git创建本地仓库,然后…

[Lc(2)滑动窗口_1] 长度最小的数组 | 无重复字符的最长子串 | 最大连续1的个数 III | 将 x 减到 0 的最小操作数

目录 1. 长度最小的字数组 题解 代码 ⭕2.无重复字符的最长子串 题解 代码 3.最大连续1的个数 III 题解 代码 4.将 x 减到 0 的最小操作数 题解 代码 1. 长度最小的字数组 题目链接:209.长度最小的字数组 题目分析: 给定一个含有 n 个 正整数 的数组…

【最大半连通子图——tarjan求最大连通分量,拓扑排序,树形DP】

题目 分析 最大连通分量肯定是满足半连通分量的要求,因此tarjan。 同时为了简化图,我们进行缩点,图一定变为拓扑图。 我们很容易看出,只要是一条不分叉的链,是满足条件的。 于是我们按照拓扑序不断树形DP 建边注意…

一周学会Flask3 Python Web开发-在模板中渲染WTForms表单视图函数里获取表单数据

锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 为了能够在模板中渲染表单,我们需要把表单类实例传入模板。首先在视图函数里实例化表单类LoginForm,然…

DeepSeek R1助力,腾讯AI代码助手解锁音乐创作新

目录 1. DeepSeekR1模型简介2. 歌词创作流程2.1 准备工作2.2 歌词生成技巧 3. 音乐制作环节3.1 主流AI音乐生成平台 4. 歌曲欣赏5. 总结展望 1. DeepSeekR1模型简介 腾讯AI代码助手最新推出的DeepSeekR1模型不仅在代码生成方面表现出色,其强大的自然语言处理能力也…

【微信小程序】每日心情笔记

个人团队的比赛项目,仅供学习交流使用 一、项目基本介绍 1. 项目简介 一款基于微信小程序的轻量化笔记工具,旨在帮助用户通过记录每日心情和事件,更好地管理情绪和生活。用户可以根据日期和心情分类(如开心、平静、难过等&#…

前端基础之组件

组件&#xff1a;实现应用中局部功能代码和资源的集合 非单文件组件 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"…

spring boot整合flyway实现数据的动态维护

1、简单介绍一下flyway Flyway 是一款开源的数据库版本控制工具&#xff0c;主要用于管理数据库结构的变更&#xff08;如创建表、修改字段、插入数据等&#xff09;。它通过跟踪和执行版本化的迁移脚本&#xff0c;帮助团队实现数据库变更的自动化。接下来简单介绍一下flyway…

数据结构知识学习小结

一、动态内存分配基本步骤 1、内存分配简单示例&#xff1a; 个人对于示例的理解&#xff1a; 定义一个整型的指针变量p&#xff08;着重认为它是一个“变量”我觉得可能会更好理解&#xff09;&#xff0c;这个变量用来存地址的&#xff0c;而不是“值”&#xff0c;malloc函…

【Spring AOP】_切点类的切点表达式

目录 1. 根据方法签名匹配编写切点表达式 1.1 具体语法 1.2 通配符表达规范 2. 根据注解匹配编写切点表达式 2.1 实现步骤 2.2 元注解及其常用取值含义 2.3 使用自定义注解 2.3.1 编写自定义注解MyAspect 2.3.2 编写切面类MyAspectDemo 2.3.3 编写测试类及测试方法 在…