go-kratos使用备忘

我搭建的一个kratos项目模板,欢迎使用,仓库地址 需要特别注意的一些建议 API路由覆盖的问题 比如有两个接口 A get /v1/user/{user_id}和 B get /v1/user/profile如果A定义在B之前,那么B可能会被A覆盖路由。需要将A放到B之前。 JWT使用的建议 摘自极客时间课程《高并发系统实战课》 通讯过程必须使用 HTTPS 协议,这样才可以降低被拦截的可能。 要注意限制 token 的更换次数,并定期刷新 token,比如用户的 access_token 每天只能更换 50 次,超过了就要求用户重新登陆,同时 token 每隔 15 分钟更换一次。这样可以降低 token 被盗取后给用户带来的影响。 Web 用户的 token 保存在 cookie 中时,建议加上 httponly、SameSite=Strict 限制,以防止 cookie 被一些特殊脚本偷走。 配置文件 配置文件校验 配合buf的validate可以方便地进行配置文件的校验,在程序启动之前就对配置文件进行一次校验。下面是一个简单的proto配置定义 syntax = "proto3"; package conf; import "buf/validate/validate.proto"; import "google/protobuf/duration.proto"; option go_package = "github.com/tpl-x/kratos/internal/conf;conf"; message Bootstrap { Server server = 1; Data data = 2; Log log = 3; } message Server { message HTTP { string network = 1; string addr = 2; google....

使用go编写一个简单的人脸识别服务

需要下载相关的模型 https://github.com/Kagami/go-face-testdata 下面的models 代码实现 代码如下 package main import ( "encoding/base64" "encoding/json" "errors" "fmt" "io" "log" "math" "net/http" "os" "path/filepath" "strconv" "sync" "time" "unsafe" "github.com/Kagami/go-face" "github.com/gorilla/mux" ) // Config 配置结构 type Config struct { Port string `json:"port"` ModelsDir string `json:"models_dir"` UploadsDir string `json:"uploads_dir"` TempDir string `json:"temp_dir"` DataFile string `json:"data_file"` MaxFileSize int64 `json:"max_file_size"` DefaultThreshold float32 `json:"default_threshold"` LogLevel string `json:"log_level"` } // Person 人员结构(支持多样本) type Person struct { ID int `json:"id"` Name string `json:"name"` Samples []FaceSample `json:"samples"` Created time....

Go语言中的指数加权移动平均

Tailscale中有很多实用的代码,下面是EWMA的一个实现,源码 // Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause // Package maths contains additional mathematical functions or structures not // found in the standard library. package maths import ( "math" "time" ) // EWMA is an exponentially weighted moving average supporting updates at // irregular intervals with at most nanosecond resolution. // The zero value will compute a half-life of 1 second. // It is not safe for concurrent use....

在go中使用Semaphoregroup

在netbird中看到一个semaphore-group函数 package semaphoregroup import ( "context" "sync" ) // SemaphoreGroup is a custom type that combines sync.WaitGroup and a semaphore. type SemaphoreGroup struct { waitGroup sync.WaitGroup semaphore chan struct{} } // NewSemaphoreGroup creates a new SemaphoreGroup with the specified semaphore limit. func NewSemaphoreGroup(limit int) *SemaphoreGroup { return &SemaphoreGroup{ semaphore: make(chan struct{}, limit), } } // Add increments the internal WaitGroup counter and acquires a semaphore slot. func (sg *SemaphoreGroup) Add(ctx context....

在 Go 中构建可扩展的多租户应用程序【译】

原文链接 https://atlasgo.io/blog/2025/05/26/gophercon-scalable-multi-tenant-apps-in-go 为 GopherCon Israel 2025 准备并呈现。 引言 在本篇博客中,我们将基于我们在构建 Atlas Cloud 后端(作为我们商业产品的一部分)的经验,探讨在 Go 中构建可扩展多租户应用程序的不同策略。 但首先,让我们明确一下我们所说的多租户应用是什么。 多租户是一个系统的特性,即单个实例为多个客户(租户)提供服务。 作为一家商业企业,你的目标当然是有很多客户!但你想要服务许多客户,他们期望有一个流畅无缝的体验,就好像只有他们在使用你的服务一样。 你向客户隐含做出的两个重要承诺是: 数据隔离:每个租户的数据都是隔离和安全的,确保一个租户无法访问另一个租户的数据。 性能:无论租户数量如何,应用程序都应表现良好,确保一个租户的使用不会降低其他租户的体验。 让我们探讨一些可能实现这些承诺的方法。 物理隔离 确保数据和性能隔离最直接的方法是为每个租户运行一个独立的应用实例。这种方法通常被称为“物理隔离”或“专用实例”。 为每个租户运行独立实例,可以确保: 每个租户的数据存储在独立的数据库中,从而保证完全隔离。如有需要,租户可以在不同的 VPC 中运行,甚至可以在不同的云账户中运行。 租户独立消费资源,因此一个租户的使用不会影响其他租户,从而消除了“吵闹邻居”问题。 然而,大多数公司不会选择这条路,原因有几点: 运营开销:将应用程序部署到数百或数千个生产环境,每个环境都有自己的数据库和配置,管理起来可能非常复杂。 成本:如果您的公司需要为每个租户的资源支付云服务提供商的费用,成本可能会迅速变得难以承受。 可扩展性:如果添加新租户需要部署新实例,那么扩展应用程序以支持许多租户可能会成为瓶颈。 可见性:跨多个实例监控和调试问题可能具有挑战性,因为您需要从所有实例中聚合日志和指标。 逻辑隔离 另一种方法是运行单个应用程序实例来服务多个租户,通常称为“逻辑隔离”。在此模型中,租户共享相同的应用程序代码和数据库,但它们的数据在逻辑上是隔离的。逻辑隔离可以总结为: 共享基础设施,作用域请求 让我们看看在 Go 应用程序中实际如何使用这个示例,从一个简单的 GORM 示例开始: package main type Tenant struct { ID uint `gorm:"primaryKey" json:"id"` Name string `json:"name"` } type Customer struct { ID uint `gorm:"primaryKey" json:"id"` Name string `json:"name"` TenantID uint `json:"tenant_id"` } 在这个示例中,我们有两个模型: Tenant 和 Customer 。每个 Customer 属于一个 Tenant , Customer 模型中的 TenantID 字段用于将每个客户与特定的租户关联起来。...

Sherpa Go语言实战

简介 sherpa 是 Next-gen Kaldi 项目的部署框架。 使用 VAD 语音活动检测(Voice Activity Detection,简称VAD)是一种技术,用于检测音频信号中是否存在语音或其他声音活动。它在语音处理、语音识别、音频压缩等领域有广泛的应用。 VAD的主要功能 语音识别系统:通过VAD,系统可以在检测到语音时启动识别过程,提高效率。 音频压缩:在语音通信中,VAD可以帮助压缩算法仅对有效语音信号进行压缩,减少传输数据量。 噪声抑制系统:通过检测语音活动,系统可以在静默时段增强噪声抑制效果。 在GO中使用 todo KWS 关键词唤醒(Keyword Spotting,简称KWS)是一种技术,用于检测音频信号中特定的关键词或短语。它广泛应用于语音助手、智能家居设备、车载系统等领域,通过识别特定关键词来激活设备或执行特定命令。 主要功能 关键词检测:识别音频信号中是否包含预定义的关键词或短语。 唤醒设备:当检测到关键词时,激活设备或应用程序。 提高用户体验:通过语音命令简化操作流程,增强用户体验。 自定义keywords 通过官方的工具sherpa-onnx-cli,可以实现自定义关键字,下面是简单的介绍 原文 # Note: You need to run pip install sherpa-onnx to get the commandline tool: sherpa-onnx-cli sherpa-onnx-cli text2token --help Usage: sherpa-onnx-cli text2token [OPTIONS] INPUT OUTPUT Options: --text TEXT Path to the input texts. Each line in the texts contains the original phrase, it might also contain some extra items, for example, the boosting score (startting with :), the triggering threshold (startting with #, only used in keyword spotting task) and the original phrase (startting with @)....

在Go程序中使用Vosk进行语音识别STT

Vosk 介绍 Vosk是一款基于深度学习的开源语音识别工具,能够在没有云连接的情况下进行高效的离线语音识别。它通过对语音信号进行预处理、特征提取和模型推断,将语音转换成文本。Vosk不仅支持多种主流编程语言,还覆盖了20多种语言和方言,包括英语、中文、法语、德语等,为跨语言应用提供了强大的支持。 工作原理 Vosk的语音识别过程可以分为以下几个关键步骤: 语音信号预处理:对输入的语音信号进行去噪、增强等处理,以提高识别准确性。 特征提取:从处理后的语音信号中提取出能够表征语音特性的关键特征。 模型推断:利用预训练的深度学习模型对提取的特征进行识别,输出对应的文本。 优势解析 隐私保护:Vosk的离线特性意味着用户的语音数据不会离开设备,有效保护了用户的隐私。 实时性:在设备端进行语音识别,减少了网络传输时间和延迟,使得识别过程更加实时。 跨平台:支持Windows、Linux、macOS以及嵌入式设备等多种平台,便于在不同场景下的应用。 可扩展性:作为开源项目,Vosk允许开发者根据自己的需求进行定制和优化,以适应不同的应用场景。 多语言支持:提供对多种语言和方言的识别能力,为跨国应用提供了便利。 官方 https://alphacephei.com/vosk/ 模型下载 https://alphacephei.com/vosk/models GO项目搭建 本文基于Linux,Windows请参考官方仓库的说明 创建go程序 创建go程序内容如下: package main import ( "encoding/json" "flag" "fmt" "io" "log" "os" vosk "github.com/alphacep/vosk-api/go" ) func main() { var filename string flag.StringVar(&filename, "f", "", "file to transcribe") flag.Parse() model, err := vosk.NewModel("model") if err != nil { log.Fatal(err) } // we can check if word is in the vocabulary // fmt....

Go程序自动升级的方案探究

前导 2024年的最后一天看见v站的这个帖子,故整理下,备忘。 常用的库 cloudflare tableflip 仓库为 https://github.com/cloudflare/tableflip 官方示例 package tableflip_test import ( "context" "flag" "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" "github.com/cloudflare/tableflip" ) // This shows how to use the upgrader // with the graceful shutdown facilities of net/http. func Example_httpShutdown() { var ( listenAddr = flag.String("listen", "localhost:8080", "`Address` to listen on") pidFile = flag.String("pid-file", "", "`Path` to pid file") ) flag.Parse() log.SetPrefix(fmt.Sprintf("%d ", os.Getpid())) upg, err := tableflip.New(tableflip.Options{ PIDFile: *pidFile, }) if err !...

对称和反向gRPC连接【译】

原文链接为 https://tilde.town/~hut8/post/grpc-connections/ 使用kimi进行翻译 背景 gRPC是一项出色的现代技术,用于远程过程调用。它允许你在客户端创建一个“存根”对象,该对象的目的是调用服务器上的方法。它是许多情况下REST或GraphQL的绝佳替代品,通常值得学习这项技术。更多信息可以在官方文档中找到。 网络 概念上,我们对客户端和服务器有两种不同的想法。 TCP服务器和客户端 - gRPC在HTTP/2之上运行,HTTP/2在TCP之上运行,所以我将讨论TCP中“服务器”和“客户端”的含义。在TCP连接中,客户端是连接的发起者,服务器是连接的接收者。然而,一旦建立了连接,连接就是对称的;客户端和服务器都可以发送和接收消息,直到一方通过shutdown(2)关闭,或通过close(2)关闭连接。 gRPC服务器和客户端 - gRPC客户端通过存根调用在服务器上运行的方法。这不是对称的。服务器不能在客户端上调用方法。 服务器/客户端类型耦合问题 如果你有一个gRPC客户端,它也是TCP客户端(它调用connect(2))。如果你有一个gRPC服务器,它也是TCP服务器(它调用listen(2)和accept(2))。 因此,如果你想让两台机器可以相互调用gRPC,那么每台机器都是客户端和服务器(在TCP和gRPC两种意义上),现在你有了两个与彼此无关的TCP连接。在有两朵云实例的场景中,这种架构通常并不复杂。但TCP通常很混乱。防火墙、NAT和动态分配的IP地址可能会使客户端到服务器的单向连接变得复杂。 这里有一个这样的情况的例子:假设你的“服务器”是一个在家庭路由器后面的笔记本电脑上运行的程序,它必须接收命令(例如,远程控制)来自“客户端”(例如,云计算实例)。根据gRPC,客户端必须是云计算实例(这很容易被称为“服务器”),因为那是创建远程过程调用的一方。服务器是笔记本电脑,因为那是实际发生过程调用的地方。 当你在客户端(即云计算实例)上创建一个“存根”时,你必须创建一个TCP连接并连接到服务器(即笔记本电脑)。现在你遇到了几个可能的问题: 你不知道笔记本电脑的IP地址,所以你现在需要一个反向服务,让笔记本电脑告诉云它的IP地址。 笔记本电脑可能在NAT后面,所以一旦你找到了IP地址,笔记本电脑将不得不配置端口转发。这在企业环境中很可能是不可能的。 笔记本电脑可能在防火墙后面,这将禁止传入连接。这可能是本地机器上的,也可能是在网关路由器上的。 这些问题中的一些可能是无法解决的,所以我们需要另一种方法。 gRPC独有的解决方案 服务器不能在客户端gRPC上调用方法。也许你可以让客户端在服务器上调用一个方法,其唯一目的是接收描述服务器希望客户端运行的方法的消息。这可以通过流式响应来完成。但这很复杂,需要大量的代码来绕过gRPC的设计。我在其他地方看到过这个建议,但我认为这是一个丑陋的临时解决方案,它制造的问题比它解决的还要多。考虑一下,你将如何在静态类型的方式中实际调用这些“客户端方法”。 基于隧道的解决方案 将TCP客户端/服务器从gRPC客户端/服务器中解耦的一个好方法是实现某种隧道。在上面的例子中,笔记本电脑可以向云计算实例发起一个TCP连接,然后通过实现特定于语言的接口,“拨号”操作让云计算实例(gRPC客户端)连接到笔记本电脑(gRPC服务器)可以简单地使用现有的TCP连接。 SSH是一个不可思议的协议,它的用途比大多数用户知道的还要多。在我们的情况下,它是将我们的TCP连接从gRPC连接中解耦的完美方式。它还有其他好处:尽管gRPC提供认证和加密,但如果更方便,你可以使用SSH提供的。 这些例子是Go语言特有的,但你可以在任何语言中做类似的事情。gRPC服务器不需要监听端口;你可以传入任何实现了Go的net.Listener的类型。所以我们可以做一个net.Listener,它将接受SSH连接,任何时候请求我们的自定义类型的新SSH通道,我们将接受它并返回一个新的net.Conn,这是我们将实现的另一个类型,它只是通过我们的隧道传输数据。 让我们从SSHDataTunnel开始,它是我们的net.Conn。 import ( "net" "time" "golang.org/x/crypto/ssh" ) // SSHDataTunnel实现了net.Conn type SSHDataTunnel struct { Chan ssh.Channel Conn net.Conn } func NewSSHDataTunnel(sshChan ssh.Channel, carrier net.Conn) *SSHDataTunnel { return &SSHDataTunnel{ Chan: sshChan, Conn: carrier, } } func (c *SSHDataTunnel) Read(b []byte) (n int, err error) { return c....

在Go语言中使用Arrow、Flight和Duckdb

从duckdb开始 DuckDB 是一个嵌入式分析型数据库,专为 OLAP(在线分析处理)工作负载设计。本文将基于 go-duckdb 项目的示例,详细介绍 DuckDB 在 Go 语言中的各种使用场景。 基础使用 简单查询 package main import ( "database/sql" _ "github.com/marcboeker/go-duckdb" ) func main() { db, err := sql.Open("duckdb", ":memory:") if err != nil { panic(err) } defer db.Close() // 执行查询 rows, err := db.Query("SELECT 42") if err != nil { panic(err) } defer rows.Close() } 高级特性 Copy COPY 函数可以用于导入导出数据: package main import ( "database/sql" "fmt" _ "github.com/marcboeker/go-duckdb" ) func main() { db, err := sql....