tonglin0325的个人主页

go学习笔记——gin限流

如果想在Gin Web服务中实现限流功能,可以使用ulule/limiteruber-go/ratelimit

1.ulule/limiter

ulule/limiter是一款支持分布式限流的框架,其可以在Redis中存储和共享限流状态,从而在分布式环境中实现一致的限流逻辑。

ulule/limiter基于令牌桶(Token Bucket)算法,因为允许累积令牌,若桶中有令牌,短时间可处理大量请求,所以可能会短时超限。令牌桶算法允许突发流量的业务,适用场景如 API 请求、流媒体加载。

其他基于令牌桶算法的限流框架还有 golang.org/x/time/rate

1.引用依赖

1
2
go get github.com/ulule/limiter/v3@v3.11.2

ulule/limiter可以和gin web框架集成,实现服务接收外部请求场景下的限流,或者服务请求外部API场景下的限流

2.使用Gin限流中间件实现服务接收外部请求场景下的限流

参考:https://github.com/ulule/limiter-examples/blob/master/gin/main.go

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package middleware

import (
"github.com/gin-gonic/gin"
"github.com/redis/go-redis/v9"
"github.com/ulule/limiter/v3"
mgin "github.com/ulule/limiter/v3/drivers/middleware/gin"
redisstore "github.com/ulule/limiter/v3/drivers/store/redis"
"time"
)

// 在中间件中对接收的请求进行限流
func RateLimitMiddleWare(rdb *redis.Client) gin.HandlerFunc {
// 定义限流规则:1 请求/10秒
rate := limiter.Rate{
Period: 10 * time.Second,
Limit: 1,
}
// 创建限流存储
store, err := redisstore.NewStoreWithOptions(rdb, limiter.StoreOptions{
Prefix: "rate_limiter", // Redis 键的前缀
})
if err != nil {
panic(err)
}
// 创建限流实例
instance := limiter.New(store, rate)
middleware := mgin.NewMiddleware(instance)
return middleware
}

在router中使用限流中间件

1
2
3
4
// ratelimit
rateLimitMiddleWare := middleware.RateLimitMiddleWare(redisClient)
authGroup.Use(rateLimitMiddleWare)

全文 >>

golang学习笔记——gorm

gen是gorm官方推出的一个GORM代码生成工具

官方文档:https://gorm.io/zh_CN/gen/

1.使用gen框架生成model和dao

安装gorm gen

1
2
go get -u gorm.io/gen

假设有如下用户表

1
2
3
4
5
6
7
8
CREATE TABLE user
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`username` varchar(128) NOT NULL COMMENT '用户名',
`email` varchar(128) NOT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

在cmd目录下创建gen/generate.go文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package main

import (
"fmt"

"gorm.io/driver/mysql"
"gorm.io/gen"
"gorm.io/gorm"
)

const MySQLDSN = "root:123456@tcp(127.0.0.1:55000)/default?charset=utf8mb4&parseTime=True"

func connectDB(dsn string) *gorm.DB {
db, err := gorm.Open(mysql.Open(dsn))
if err != nil {
panic(fmt.Errorf("connect mysql fail: %w", err))
}
return db
}

func main() {
// 指定生成代码的具体相对目录(相对当前文件),默认为:./query
// 默认生成需要使用WithContext之后才可以查询的代码,但可以通过设置gen.WithoutContext禁用该模式
g := gen.NewGenerator(gen.Config{
// 默认会在 OutPath 目录生成CRUD代码,并且同目录下生成 model 包
// 所以OutPath最终package不能设置为model,在有数据库表同步的情况下会产生冲突
// 若一定要使用可以通过ModelPkgPath单独指定model package的名称
OutPath: "./internal/dao",
ModelPkgPath: "./internal/model",

// gen.WithoutContext:禁用WithContext模式
// gen.WithDefaultQuery:生成一个全局Query对象Q
// gen.WithQueryInterface:生成Query接口
Mode: gen.WithoutContext | gen.WithDefaultQuery | gen.WithQueryInterface,
})

// 通常复用项目中已有的SQL连接配置db(*gorm.DB)
// 非必需,但如果需要复用连接时的gorm.Config或需要连接数据库同步表信息则必须设置
g.UseDB(connectDB(MySQLDSN))

// 从连接的数据库为所有表生成Model结构体和CRUD代码
//g.ApplyBasic(g.GenerateAllTable()...)

// 也可以手动指定需要生成代码的数据表
//g.ApplyBasic(g.GenerateModel("user"), g.GenerateModel("role"))

// 还可以指定只生成model
var models = [...]string{"user"}
for _, tableName := range models {
// 只生成model
g.GenerateModel(tableName)
// 生成model和query
//tableModel := g.GenerateModel(tableName)
//g.ApplyBasic(tableModel)
}

//g.ApplyInterface(func(model.Filter) {}, g.GenerateModel("user"))
// 执行并生成代码
g.Execute()
}

运行generate.go,将会生成model和dao文件

全文 >>

go学习笔记——分布式事务框架DTM

DTM是一款开源的GO语言分布式事务管理器,解决跨数据库、跨服务、跨语言栈更新数据的一致性问题。

DTM可适合多语言栈的公司使用。方便go、python、php、nodejs、ruby、c# 各类语言使用。

支持的分布式事务协议包括:SAGA,TCC,XA和二阶段消息这几种模式。

官方网站:https://dtm.pub/

1.启动DTM服务

参考:https://dtm.pub/guide/install.html#%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%8C%85%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85

项目

1
2
https://github.com/dtm-labs/dtm

git dtm项目

1
2
git clone https://github.com/dtm-labs/dtm && cd dtm

启动dtm

全文 >>

golang项目引用GitHub私有仓库module

1.创建go module项目

module的名字假设为go-test

module项目创建成功后,将go.mod文件中的 module “go-test” 修改成

1
2
module "github.com/tonglin0325/go-test"

避免引用的时候go get报错,如下

1
2
3
4
5
go get github.com/tonglin0325/go-test@latest
go: github.com/tonglin0325/go-test@latest (v1.0.0) requires github.com/tonglin0325/go-test@v1.0.0: parsing go.mod:
module declares its path as: go-test
but was required as: github.com/tonglin0325/go-test

在module中写好代码后上传到github上,并在github上给项目打上tag

如果GitHub repository设置成public的话,此时就可以使用如下命令引用这个module了

全文 >>

k8s学习笔记——Istio和Kong

服务网格(Service Mesh)是一种用于处理微服务架构中服务间通信的基础设施层。它的主要作用是提供可靠的服务发现、负载均衡、故障恢复、指标监控和安全性,通常无需对服务代码进行大量修改。服务网格通过在每个服务实例旁边部署一个轻量级代理(sidecar)来实现这些功能。

1.Istio#

Istio 是一个开源的服务网格(Service Mesh),透明地层叠到现有的分布式应用程序之上。Istio 强大的功能提供了一种统一且更高效的方式来保护、连接和监控服务。Istio 是实现负载均衡、服务间身份验证和监控的途径——几乎无需修改服务代码。它为你提供:

  • 集群中服务间的安全通信,采用双向 TLS 加密,基于强身份的身份验证和授权
  • HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡
  • 通过丰富的路由规则、重试、故障切换和故障注入对流量行为进行细粒度控制
  • 支持访问控制、速率限制和配额的可插拔策略层和配置 API
  • 集群内所有流量(包括集群入口和出口)的自动化指标、日志和跟踪

参考:https://istio.io/latest/docs/overview/what-is-istio/

Istio 的流量管理模型源于和服务一起部署的 Envoy 代理。 网格内服务发送和接收的所有 data plane 流量都经由 Envoy 代理, 这让控制网格内的流量变得异常简单,而且不需要对服务做任何的更改。

Envoy 是在 Istio 里使用的高性能代理,用于为所有服务网格里的服务调度进出的流量。

参考:https://istio.io/latest/zh/docs/concepts/traffic-management/

2.Kong#

Kong 提供了两个主要产品:Kong Gateway 和 Kuma。

Kong Gateway 是一个云原生 API 网关,专注于管理、配置和路由 API 请求。它提供了强大的插件系统,可以扩展其功能以实现身份验证、速率限制、日志记录等功能。Kong Gateway 主要用于处理进出 API 的流量,但它不具备完整的服务网格功能。

Kuma 是 Kong 开发的一个服务网格,旨在简化服务间通信的管理。Kuma 提供了服务网格的所有核心功能,包括服务发现、负载均衡、故障恢复、可观察性和安全性。Kuma 可以部署在多个环境中,包括 Kubernetes 和虚拟机。

k8s学习笔记——ingress

Ingress 提供从集群外部到集群内服务(service)的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源所定义的规则来控制。

下面是 Ingress 的一个简单示例,可将所有流量都发送到同一 Service:

ingress-diagram

通过配置,Ingress 可为 Service 提供外部可访问的 URL、对其流量作负载均衡、 终止 SSL/TLS,以及基于名称的虚拟托管等能力。 Ingress 控制器 负责完成 Ingress 的工作,具体实现上通常会使用某个负载均衡器, 不过也可以配置边缘路由器或其他前端来帮助处理流量。

参考:https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/

典型的Ingress 控制器有 ingress-nginxIstio Ingress(一个基于 Istio 的 Ingress 控制器),用于 Kubernetes 的 Kong Ingress 控制器(一个用来驱动 Kong Gateway 的 Ingress 控制器)

参考:https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress-controllers/

Presto学习笔记——Go客户端连接Presto

1.查询PrestoDB(facebook版本)

1.创建PrestoDB环境

使用docker创建presto测试环境

1
2
https://hub.docker.com/r/prestodb/presto/tags

拉取镜像

1
2
docker pull prestodb/presto:0.284

启动

1
2
docker run -p 8080:8080 -ti -v /Users/lintong/Downloads/config.properties:/opt/presto-server/etc/config.properties -v /Users/lintong/Downloads/jvm.config:/opt/presto-server/etc/jvm.config prestodb/presto:0.284

其中config.properties配置文件

1
2
3
4
5
6
7
8
coordinator=true
node-scheduler.include-coordinator=true
http-server.http.port=8080
query.max-memory=5GB
query.max-memory-per-node=1GB
discovery-server.enabled=true
discovery.uri=http://localhost:8080

jvm.config

1
2
3
4
5
6
7
8
9
10
-server
-Xmx4G
-XX:+UseG1GC
-XX:G1HeapRegionSize=32M
-XX:+UseGCOverheadLimit
-XX:+ExplicitGCInvokesConcurrent
-XX:+HeapDumpOnOutOfMemoryError
-XX:+ExitOnOutOfMemoryError
-Djdk.attach.allowAttachSelf=true

全文 >>

screen使用教程

在terminal上使用跳板机远程登录其他机器的时候,经常会因为和跳板机的连接断开而丢失会话,如下

这时候可以使用screen命令来创建和恢复会话

1.创建会话

1
2
3
4
screen 
或者
screen -S session_name

这时我们就进到了一个screen会话中,比如我们进到/tmp目录下

2.查看现有的会话

这时候我们把这个terminal窗口直接关闭掉,另外开启一个terminal,输入如下命令来查看现有的会话

1
2
screen -ls

全文 >>

go学习笔记——常用命令

1.查找go依赖

go依赖可以去下面网站查找package

1
2
https://pkg.go.dev/

比如

1
2
https://pkg.go.dev/github.com/confluentinc/confluent-kafka-go#section-readme

2.go切换源

1
2
3
4
5
6
7
# 启用 Go Modules 功能
go env -w GO111MODULE=on
# 切换源
go env -w GOPROXY=https://goproxy.io,direct
# 确认是否生效
go env

3.安装指定依赖

1
2
3
go get -u github.com/confluentinc/confluent-kafka-go/kafka
go get: added github.com/confluentinc/confluent-kafka-go v1.9.2

如果想安装特定版本的依赖

1
2
go get github.com/confluentinc/confluent-kafka-go/kafka@v1.9.2

4.下载依赖

1
2
go mod download

5.清理无用的依赖

下载缺失依赖,并清理无用的依赖(包括清理 go.mod 中的记录)

全文 >>