0%

Jenkins 本地配置

背景

编写 Jenkinsfile时,原来每次调试需要修改 Jenkinsfile后推送到 gitlab,然后 Jenkins Job run时,拉取远程 gitlab仓库,读取仓库下的
Jenkinsfile,开发调试效率低.

Read more »

go 项目中多人代码格式化和import package 格式不一致,使用githooks统一代码风格.

配置 .githooks目录

1
2
3
4
5
.PHONY: init
init:
@git config core.hooksPath .githooks
@go get golang.org/x/tools/cmd/goimports@v0.1.5
@echo "githooks 配置成功"

配置 pre-commit.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
branch="$(git rev-parse --abbrev-ref HEAD)"

if [ $branch = master ] || [ $branch = dev ];then
echo "当前分支 $branch 不支持提交操作"
exit 1
fi

for file in $(git diff --cached --name-only --diff-filter=ACMRTUXB | grep "\.go")
do
echo "(gofmt) $file"
gofmt -w $file
goimports -w $file
git add "$file"
done

相比于令牌桶,漏桶更严格,调用方只能严格按照预定的间隔顺序进行消费调用.
uber 在 Github 上开源了一套用于服务限流的 go 语言库 ratelimit, 该组件基于 Leaky Bucket(漏桶) 实现。

ratelimit使用

官方 example

1
2
3
4
5
6
7
8
rl := ratelimit.New(100) // per second

prev := time.Now()
for i := 0; i < 10; i++ {
now := rl.Take()
fmt.Println(i, now.Sub(prev))
prev = now
}

ratelimit 实现

根据传入的limit参数,计算每个请求的间隔
limiter.perRequest = time.Second / time.Duration(rate)
根据最近的 limiter.last最近获取时间,当前时间 now - last = interval 为两次请求的间隔,如果间隔小于 perRequest,那么sleep
perRequest - interval 时间即可.

1
2
3
4
5
6
7
8
newState.sleepFor += t.perRequest - now.Sub(oldState.last)
sleepFor = t.perRequest - now.Sub(t.last)
if sleepFor > 0 {
t.clock.Sleep(sleepFor)
t.last = now.Add(sleepFor)
} else {
t.last = now
}

最大松弛量

在 uber-go 实现的 ratelimit 中,可以把之前间隔比较长的请求的时间,匀给后面的使用,保证每秒请求数 (RPS) 即可。

1
2
3
4
5
6
7
8
9
// 为了防止无限等待达不到限流的效果,引入 maxSlack
if newState.sleepFor < t.maxSlack {
newState.sleepFor = t.maxSlack
}
// 将多余的时间给后面的请求使用
if newState.sleepFor > 0 {
newState.last = newState.last.Add(newState.sleepFor)
interval, newState.sleepFor = newState.sleepFor, 0
}

对于需要严格限制请求间隔的情况,ratelimit 提供 WithoutSlack option function,不允许最大松弛量

对于需要使用自定义时钟的情况,提供 WithClock option function,只要实现以下接口即可.

1
2
3
4
type Clock interface {
Now() time.Time
Sleep(time.Duration)
}

参考资料