golang实现故障注入的中间件插件库go-fault的使用

Golang实现故障注入的中间件插件库go-fault的使用

go-fault是一个Golang HTTP中间件库,可以方便地在服务中注入故障。使用该库可以拒绝传入请求、响应HTTP错误、延迟部分请求或注入自定义故障。

主要特性

go-fault通过标准的Go HTTP中间件工作。首先创建一个Injector(包含要运行的注入代码的中间件),然后用Fault包装该Injector,后者控制何时运行Injector

目前有三种类型的注入器:

  • SlowInjector:注入延迟
  • ErrorInjector:注入错误
  • RejectInjector:拒绝请求

示例代码

// main.go
package main

import (
    "net/http"
    "time"

    "github.com/lingrino/go-fault"
)

// 主处理函数
var mainHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    http.Error(w, http.StatusText(http.StatusOK), http.StatusOK)
})

func main() {
    // 创建延迟注入器,延迟2秒
    slowInjector, _ := fault.NewSlowInjector(time.Second * 2)
    
    // 创建故障配置:
    // - 启用故障注入
    // - 25%的请求受影响
    // - 排除/ping和/health路径
    slowFault, _ := fault.NewFault(slowInjector,
        fault.WithEnabled(true),
        fault.WithParticipation(0.25),
        fault.WithPathBlocklist([]string{"/ping", "/health"}),
    )

    // 将故障注入器添加到处理链中
    handlerChain := slowFault.Handler(mainHandler)

    // 启动HTTP服务器
    http.ListenAndServe("127.0.0.1:3000", handlerChain)
}

使用说明

  1. 延迟注入:使用NewSlowInjector创建延迟注入器
  2. 错误注入:使用NewErrorInjector创建错误注入器
  3. 拒绝请求:使用NewRejectInjector创建拒绝请求注入器

配置选项:

  • WithEnabled:启用/禁用故障注入
  • WithParticipation:设置受影响请求的百分比
  • WithPathBlocklist:设置排除路径列表
  • WithPathAllowlist:设置仅影响指定路径

局限性

该库无法完美模拟请求被丢弃的场景(请求无响应的情况)。建议使用长时间延迟的SlowInjector配合RejectInjector来模拟这种情况。

性能

当故障注入禁用时,性能影响可以忽略不计。启用时会有轻微性能差异,但仅在注入故障时才会出现。

测试

该库有完善的测试覆盖,包括:

$ go test -v -cover -race ./...
[...]
PASS
coverage: 100.0% of statements
ok      github.com/lingrino/go-fault      0.575s

基准测试

$ go test -run=XXX -bench=.
goos: darwin
goarch: amd64
pkg: github.com/lingrino/go-fault
BenchmarkNoFault-8                        684826              1734 ns/op
BenchmarkFaultDisabled-8                  675291              1771 ns/op
BenchmarkFaultErrorZeroPercent-8          667903              1823 ns/op
BenchmarkFaultError100Percent-8           663661              1833 ns/op
PASS
ok      github.com/lingrino/go-fault      8.814s

更多关于golang实现故障注入的中间件插件库go-fault的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现故障注入的中间件插件库go-fault的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go-Fault: Golang故障注入中间件库使用指南

go-fault 是一个用于Golang的故障注入中间件库,允许开发者在服务中模拟各种故障场景,如延迟、错误响应等,以测试系统的弹性和容错能力。

安装

go get github.com/lingrino/go-fault

基本使用

1. 注入延迟

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/lingrino/go-fault"
)

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Hello, World!")
}

func main() {
	// 创建故障注入器 - 50%概率注入500ms延迟
	injector := fault.NewFault(
		fault.WithProbability(0.5),
		fault.WithDelay(time.Millisecond * 500),
	)

	// 包装原始handler
	http.Handle("/", injector.Handler(http.HandlerFunc(handler)))
	http.ListenAndServe(":8080", nil)
}

2. 注入错误响应

package main

import (
	"net/http"

	"github.com/lingrino/go-fault"
)

func handler(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("Normal response"))
}

func main() {
	// 创建故障注入器 - 30%概率返回500错误
	injector := fault.NewFault(
		fault.WithProbability(0.3),
		fault.WithError(http.StatusInternalServerError, []byte("Injected error")),
	)

	http.Handle("/", injector.Handler(http.HandlerFunc(handler)))
	http.ListenAndServe(":8080", nil)
}

高级功能

1. 组合多种故障

injector := fault.NewFault(
	fault.WithProbability(0.2),
	fault.WithDelay(time.Second),
	fault.WithError(http.StatusServiceUnavailable, []byte("Service unavailable")),
	fault.WithCallback(func(w http.ResponseWriter, r *http.Request) {
		// 自定义回调逻辑
		w.Header().Set("X-Fault-Injected", "true")
	}),
)

2. 条件触发

injector := fault.NewFault(
	fault.WithCondition(func(r *http.Request) bool {
		// 只对特定路径注入故障
		return r.URL.Path == "/api/v1/payments"
	}),
	fault.WithError(http.StatusPaymentRequired, []byte("Payment required")),
)

3. 自定义故障逻辑

injector := fault.NewFault(
	fault.WithCallback(func(w http.ResponseWriter, r *http.Request) {
		// 50%概率返回错误,50%概率注入延迟
		if rand.Float32() < 0.5 {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("Custom error"))
		} else {
			time.Sleep(2 * time.Second)
		}
	}),
)

实际应用示例

微服务中的故障注入

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/lingrino/go-fault"
)

func paymentHandler(w http.ResponseWriter, r *http.Request) {
	// 模拟支付处理
	time.Sleep(100 * time.Millisecond)
	w.Write([]byte("Payment processed"))
}

func main() {
	// 为支付服务创建故障注入
	paymentInjector := fault.NewFault(
		fault.WithProbability(0.1), // 10%故障率
		fault.WithError(http.StatusInternalServerError, []byte("Payment service unavailable")),
		fault.WithDelay(time.Second * 3), // 3秒延迟
	)

	mux := http.NewServeMux()
	mux.Handle("/pay", paymentInjector.Handler(http.HandlerFunc(paymentHandler)))

	log.Println("Server started on :8080")
	log.Fatal(http.ListenAndServe(":8080", mux))
}

最佳实践

  1. 生产环境谨慎使用:确保只在测试环境启用故障注入
  2. 动态配置:考虑通过环境变量或配置中心控制故障注入参数
  3. 监控:记录所有注入的故障以便分析
  4. 渐进式实施:从低故障率开始,逐步增加

替代方案

如果 go-fault 不能满足需求,还可以考虑:

  • Chaos Mesh (Kubernetes环境)
  • Gremlin (企业级混沌工程平台)
  • 自定义中间件实现

go-fault 是一个轻量级的解决方案,特别适合HTTP服务的故障注入测试,能有效帮助开发者验证系统的容错能力。

回到顶部