3.3 重大发现!可用性测试竟然还能这样玩?
在构建高可用系统时,仅仅设计出高可用架构是不够的,还需要通过系统的测试和演练来验证架构的有效性。可用性测试和容灾演练是确保系统在真实故障场景下依然能够稳定运行的关键手段。本节将深入探讨如何设计和实施有效的可用性测试和容灾演练方案。
可用性测试概述
可用性测试是验证系统在各种故障场景下是否能够保持正常运行的过程。它包括以下几个方面:
- 功能测试:验证系统在正常情况下的功能是否正确
- 性能测试:验证系统在高负载情况下的性能表现
- 故障注入测试:模拟各种故障场景,验证系统的容错能力
- 恢复测试:验证系统在故障发生后能否自动恢复
故障注入测试框架
故障注入测试是可用性测试的核心,通过主动注入故障来验证系统的容错能力。
// FaultInjector 故障注入器接口
type FaultInjector interface {
// Inject 注入故障
Inject(fault *Fault) error
// Recover 恢复故障
Recover(fault *Fault) error
}
// Fault 故障定义
type Fault struct {
// 故障ID
ID string `json:"id"`
// 故障类型
Type FaultType `json:"type"`
// 故障目标
Target FaultTarget `json:"target"`
// 故障参数
Parameters map[string]interface{} `json:"parameters"`
// 持续时间
Duration time.Duration `json:"duration"`
// 创建时间
CreatedAt time.Time `json:"created_at"`
// 状态
Status FaultStatus `json:"status"`
}
// FaultType 故障类型
type FaultType string
const (
// FaultTypeNetwork 网络故障
FaultTypeNetwork FaultType = "network"
// FaultTypeService 服务故障
FaultTypeService FaultType = "service"
// FaultTypeDatabase 数据库故障
FaultTypeDatabase FaultType = "database"
// FaultTypeDisk 磁盘故障
FaultTypeDisk FaultType = "disk"
// FaultTypeCPU CPU故障
FaultTypeCPU FaultType = "cpu"
// FaultTypeMemory 内存故障
FaultTypeMemory FaultType = "memory"
)
// FaultTarget 故障目标
type FaultTarget struct {
// 目标类型
Type TargetType `json:"type"`
// 目标标识
Identifier string `json:"identifier"`
// 目标地址
Address string `json:"address,omitempty"`
}
// TargetType 目标类型
type TargetType string
const (
// TargetTypeService 服务
TargetTypeService TargetType = "service"
// TargetTypeHost 主机
TargetTypeHost TargetType = "host"
// TargetTypeContainer 容器
TargetTypeContainer TargetType = "container"
// TargetTypePod Pod
TargetTypePod TargetType = "pod"
)
// FaultStatus 故障状态
type FaultStatus string
const (
// FaultStatusPending 待执行
FaultStatusPending FaultStatus = "pending"
// FaultStatusInjecting 注入中
FaultStatusInjecting FaultStatus = "injecting"
// FaultStatusInjected 已注入
FaultStatusInjected FaultStatus = "injected"
// FaultStatusRecovering 恢复中
FaultStatusRecovering FaultStatus = "recovering"
// FaultStatusRecovered 已恢复
FaultStatusRecovered FaultStatus = "recovered"
// FaultStatusFailed 失败
FaultStatusFailed FaultStatus = "failed"
)
// ChaosFaultInjector 混沌故障注入器
type ChaosFaultInjector struct {
// 故障存储
faultStore FaultStore
// 通知器
notifier Notifier
// 活动管理器
activityManager ActivityManager
}
// FaultStore 故障存储接口
type FaultStore interface {
// SaveFault 保存故障
SaveFault(fault *Fault) error
// GetFaultByID 根据ID获取故障
GetFaultByID(id string) (*Fault, error)
// ListFaults 列出故障
ListFaults() ([]*Fault, error)
// UpdateFault 更新故障
UpdateFault(fault *Fault) error
}
// Notifier 通知器接口
type Notifier interface {
// Notify 发送通知
Notify(message string, level NotificationLevel) error
}
// NotificationLevel 通知级别
type NotificationLevel string
const (
// NotificationLevelInfo 信息
NotificationLevelInfo NotificationLevel = "info"
// NotificationLevelWarning 警告
NotificationLevelWarning NotificationLevel = "warning"
// NotificationLevelError 错误
NotificationLevelError NotificationLevel = "error"
// NotificationLevelCritical 严重
NotificationLevelCritical NotificationLevel = "critical"
)
// ActivityManager 活动管理器接口
type ActivityManager interface {
// RecordActivity 记录活动
RecordActivity(activity *Activity) error
}
// Activity 活动记录
type Activity struct {
// 活动ID
ID string `json:"id"`
// 活动类型
Type string `json:"type"`
// 活动描述
Description string `json:"description"`
// 相关实体
EntityID string `json:"entity_id"`
// 时间戳
Timestamp time.Time `json:"timestamp"`
// 详情
Details map[string]interface{} `json:"details"`
}
// NewChaosFaultInjector 创建混沌故障注入器
func NewChaosFaultInjector(faultStore FaultStore, notifier Notifier, activityManager ActivityManager) *ChaosFaultInjector {
return &ChaosFaultInjector{
faultStore: faultStore,
notifier: notifier,
activityManager: activityManager,
}
}
// Inject 注入故障
func (cfi *ChaosFaultInjector) Inject(fault *Fault) error {
// 更新故障状态
fault.Status = FaultStatusInjecting
fault.CreatedAt = time.Now()
if err := cfi.faultStore.SaveFault(fault); err != nil {
return fmt.Errorf("failed to save fault: %w", err)
}
// 记录活动
cfi.recordActivity("fault_injection_started", fmt.Sprintf("开始注入故障: %s", fault.ID), fault.ID, map[string]interface{}{
"fault_type": fault.Type,
"target": fault.Target,
})
// 发送通知
cfi.notifier.Notify(fmt.Sprintf("开始注入故障: %s", fault.ID), NotificationLevelInfo)
// 根据故障类型执行注入
var err error
switch fault.Type {
case FaultTypeNetwork:
err = cfi.injectNetworkFault(fault)
case FaultTypeService:
err = cfi.injectServiceFault(fault)
case FaultTypeDatabase:
err = cfi.injectDatabaseFault(fault)
case FaultTypeDisk:
err = cfi.injectDiskFault(fault)
case FaultTypeCPU:
err = cfi.injectCPUFault(fault)
case FaultTypeMemory:
err = cfi.injectMemoryFault(fault)
default:
err = fmt.Errorf("unsupported fault type: %s", fault.Type)
}
if err != nil {
fault.Status = FaultStatusFailed
cfi.faultStore.UpdateFault(fault)
cfi.recordActivity("fault_injection_failed", fmt.Sprintf("故障注入失败: %s, 错误: %v", fault.ID, err), fault.ID, nil)
cfi.notifier.Notify(fmt.Sprintf("故障注入失败: %s", fault.ID), NotificationLevelError)
return fmt.Errorf("failed to inject fault: %w", err)
}
// 更新故障状态
fault.Status = FaultStatusInjected
if err := cfi.faultStore.UpdateFault(fault); err != nil {
log.Printf("failed to update fault status: %v", err)
}
cfi.recordActivity("fault_injected", fmt.Sprintf("故障已注入: %s", fault.ID), fault.ID, nil)
cfi.notifier.Notify(fmt.Sprintf("故障已注入: %s", fault.ID), NotificationLevelInfo)
// 如果指定了持续时间,启动自动恢复
if fault.Duration > 0 {
go func() {
time.Sleep(fault.Duration)
if err := cfi.Recover(fault); err != nil {
log.Printf("failed to auto recover fault: %v", err)
}
}()
}
return nil
}
// Recover 恢复故障
func (cfi *ChaosFaultInjector) Recover(fault *Fault) error {
// 获取最新的故障信息
latestFault, err := cfi.faultStore.GetFaultByID(fault.ID)
if err != nil {
return fmt.Errorf("failed to get fault: %w", err)
}
// 检查故障状态
if latestFault.Status != FaultStatusInjected {
return fmt.Errorf("fault is not in injected state")
}
// 更新故障状态
latestFault.Status = FaultStatusRecovering
if err := cfi.faultStore.UpdateFault(latestFault); err != nil {
return fmt.Errorf("failed to update fault status: %w", err)
}
cfi.recordActivity("fault_recovery_started", fmt.Sprintf("开始恢复故障: %s", fault.ID), fault.ID, nil)
cfi.notifier.Notify(fmt.Sprintf("开始恢复故障: %s", fault.ID), NotificationLevelInfo)
// 根据故障类型执行恢复
var recoverErr error
switch fault.Type {
case FaultTypeNetwork:
recoverErr = cfi.recoverNetworkFault(fault)
case FaultTypeService:
recoverErr = cfi.recoverServiceFault(fault)
case FaultTypeDatabase:
recoverErr = cfi.recoverDatabaseFault(fault)
case FaultTypeDisk:
recoverErr = cfi.recoverDiskFault(fault)
case FaultTypeCPU:
recoverErr = cfi.recoverCPUFault(fault)
case FaultTypeMemory:
recoverErr = cfi.recoverMemoryFault(fault)
default:
recoverErr = fmt.Errorf("unsupported fault type: %s", fault.Type)
}
if recoverErr != nil {
latestFault.Status = FaultStatusFailed
cfi.faultStore.UpdateFault(latestFault)
cfi.recordActivity("fault_recovery_failed", fmt.Sprintf("故障恢复失败: %s, 错误: %v", fault.ID, recoverErr), fault.ID, nil)
cfi.notifier.Notify(fmt.Sprintf("故障恢复失败: %s", fault.ID), NotificationLevelError)
return fmt.Errorf("failed to recover fault: %w", recoverErr)
}
// 更新故障状态
latestFault.Status = FaultStatusRecovered
if err := cfi.faultStore.UpdateFault(latestFault); err != nil {
log.Printf("failed to update fault status: %v", err)
}
cfi.recordActivity("fault_recovered", fmt.Sprintf("故障已恢复: %s", fault.ID), fault.ID, nil)
cfi.notifier.Notify(fmt.Sprintf("故障已恢复: %s", fault.ID), NotificationLevelInfo)
return nil
}
// 各种故障注入实现
func (cfi *ChaosFaultInjector) injectNetworkFault(fault *Fault) error {
// 模拟网络故障注入
// 这里可以使用iptables、tc等工具模拟网络延迟、丢包等
log.Printf("Injecting network fault to target: %s", fault.Target.Identifier)
// 示例:使用系统命令模拟网络故障
cmd := exec.Command("iptables", "-A", "INPUT", "-s", fault.Target.Address, "-j", "DROP")
return cmd.Run()
}
func (cfi *ChaosFaultInjector) recoverNetworkFault(fault *Fault) error {
// 恢复网络故障
log.Printf("Recovering network fault from target: %s", fault.Target.Identifier)
// 示例:使用系统命令恢复网络
cmd := exec.Command("iptables", "-D", "INPUT", "-s", fault.Target.Address, "-j", "DROP")
return cmd.Run()
}
func (cfi *ChaosFaultInjector) injectServiceFault(fault *Fault) error {
// 模拟服务故障
log.Printf("Injecting service fault to target: %s", fault.Target.Identifier)
// 这里可以停止服务进程、杀死容器等
return nil
}
func (cfi *ChaosFaultInjector) recoverServiceFault(fault *Fault) error {
// 恢复服务故障
log.Printf("Recovering service fault from target: %s", fault.Target.Identifier)
// 这里可以启动服务进程、重启容器等
return nil
}
func (cfi *ChaosFaultInjector) injectDatabaseFault(fault *Fault) error {
// 模拟数据库故障
log.Printf("Injecting database fault to target: %s", fault.Target.Identifier)
// 这里可以停止数据库服务、模拟连接失败等
return nil
}
func (cfi *ChaosFaultInjector) recoverDatabaseFault(fault *Fault) error {
// 恢复数据库故障
log.Printf("Recovering database fault from target: %s", fault.Target.Identifier)
// 这里可以启动数据库服务、恢复连接等
return nil
}
func (cfi *ChaosFaultInjector) injectDiskFault(fault *Fault) error {
// 模拟磁盘故障
log.Printf("Injecting disk fault to target: %s", fault.Target.Identifier)
// 这里可以填充磁盘空间、模拟IO错误等
return nil
}
func (cfi *ChaosFaultInjector) recoverDiskFault(fault *Fault) error {
// 恢复磁盘故障
log.Printf("Recovering disk fault from target: %s", fault.Target.Identifier)
// 这里可以清理磁盘空间、恢复IO等
return nil
}
func (cfi *ChaosFaultInjector) injectCPUFault(fault *Fault) error {
// 模拟CPU故障
log.Printf("Injecting CPU fault to target: %s", fault.Target.Identifier)
// 这里可以创建高CPU负载进程等
return nil
}
func (cfi *ChaosFaultInjector) recoverCPUFault(fault *Fault) error {
// 恢复CPU故障
log.Printf("Recovering CPU fault from target: %s", fault.Target.Identifier)
// 这里可以终止高CPU负载进程等
return nil
}
func (cfi *ChaosFaultInjector) injectMemoryFault(fault *Fault) error {
// 模拟内存故障
log.Printf("Injecting memory fault to target: %s", fault.Target.Identifier)
// 这里可以创建高内存占用进程等
return nil
}
func (cfi *ChaosFaultInjector) recoverMemoryFault(fault *Fault) error {
// 恢复内存故障
log.Printf("Recovering memory fault from target: %s", fault.Target.Identifier)
// 这里可以终止高内存占用进程等
return nil
}
// recordActivity 记录活动
func (cfi *ChaosFaultInjector) recordActivity(activityType, description, entityID string, details map[string]interface{}) {
activity := &Activity{
ID: generateUUID(),
Type: activityType,
Description: description,
EntityID: entityID,
Timestamp: time.Now(),
Details: details,
}
if err := cfi.activityManager.RecordActivity(activity); err != nil {
log.Printf("failed to record activity: %v", err)
}
}
可用性测试场景设计
1. 网络分区测试
// NetworkPartitionTest 网络分区测试
type NetworkPartitionTest struct {
// 故障注入器
faultInjector FaultInjector
// 测试配置
config *NetworkPartitionTestConfig
}
// NetworkPartitionTestConfig 网络分区测试配置
type NetworkPartitionTestConfig struct {
// 分区持续时间
Duration time.Duration
// 参与分区的主机列表
Hosts []string
// 预期结果
ExpectedResult TestResult
}
// TestResult 测试结果
type TestResult struct {
// 是否通过
Passed bool `json:"passed"`
// 详细信息
Details string `json:"details"`
// 性能指标
Metrics map[string]float64 `json:"metrics"`
}
// NewNetworkPartitionTest 创建网络分区测试
func NewNetworkPartitionTest(faultInjector FaultInjector, config *NetworkPartitionTestConfig) *NetworkPartitionTest {
return &NetworkPartitionTest{
faultInjector: faultInjector,
config: config,
}
}
// Run 运行测试
func (npt *NetworkPartitionTest) Run() (*TestResult, error) {
log.Println("开始网络分区测试")
// 创建网络故障
var faults []*Fault
for _, host := range npt.config.Hosts {
fault := &Fault{
ID: fmt.Sprintf("network_partition_%s_%d", host, time.Now().Unix()),
Type: FaultTypeNetwork,
Target: FaultTarget{Type: TargetTypeHost, Identifier: host},
Duration: npt.config.Duration,
Parameters: map[string]interface{}{
"action": "isolate",
},
}
faults = append(faults, fault)
}
// 注入故障
for _, fault := range faults {
if err := npt.faultInjector.Inject(fault); err != nil {
return nil, fmt.Errorf("failed to inject network fault: %w", err)
}
}
// 等待测试完成
time.Sleep(npt.config.Duration)
// 恢复故障
for _, fault := range faults {
if err := npt.faultInjector.Recover(fault); err != nil {
log.Printf("failed to recover network fault: %v", err)
}
}
// 验证结果
result := &TestResult{
Passed: true,
Details: "网络分区测试完成",
Metrics: map[string]float64{
"duration_seconds": npt.config.Duration.Seconds(),
"hosts_affected": float64(len(npt.config.Hosts)),
},
}
log.Println("网络分区测试完成")
return result, nil
}
2. 服务崩溃测试
// ServiceCrashTest 服务崩溃测试
type ServiceCrashTest struct {
// 故障注入器
faultInjector FaultInjector
// 测试配置
config *ServiceCrashTestConfig
}
// ServiceCrashTestConfig 服务崩溃测试配置
type ServiceCrashTestConfig struct {
// 服务名称
ServiceName string
// 崩溃持续时间
CrashDuration time.Duration
// 恢复检查间隔
CheckInterval time.Duration
// 最大恢复时间
MaxRecoveryTime time.Duration
}
// NewServiceCrashTest 创建服务崩溃测试
func NewServiceCrashTest(faultInjector FaultInjector, config *ServiceCrashTestConfig) *ServiceCrashTest {
return &ServiceCrashTest{
faultInjector: faultInjector,
config: config,
}
}
// Run 运行测试
func (sct *ServiceCrashTest) Run() (*TestResult, error) {
log.Printf("开始服务崩溃测试: %s", sct.config.ServiceName)
// 创建服务故障
fault := &Fault{
ID: fmt.Sprintf("service_crash_%s_%d", sct.config.ServiceName, time.Now().Unix()),
Type: FaultTypeService,
Target: FaultTarget{Type: TargetTypeService, Identifier: sct.config.ServiceName},
Duration: sct.config.CrashDuration,
Parameters: map[string]interface{}{
"action": "kill",
},
}
// 注入故障
if err := sct.faultInjector.Inject(fault); err != nil {
return nil, fmt.Errorf("failed to inject service fault: %w", err)
}
// 等待崩溃持续时间
time.Sleep(sct.config.CrashDuration)
// 恢复故障
if err := sct.faultInjector.Recover(fault); err != nil {
return nil, fmt.Errorf("failed to recover service fault: %w", err)
}
// 验证服务是否恢复
recoveryStart := time.Now()
recovered := false
for time.Since(recoveryStart) < sct.config.MaxRecoveryTime {
if sct.isServiceHealthy(sct.config.ServiceName) {
recovered = true
break
}
time.Sleep(sct.config.CheckInterval)
}
// 构造测试结果
result := &TestResult{
Passed: recovered,
Details: func() string {
if recovered {
return fmt.Sprintf("服务 %s 成功恢复", sct.config.ServiceName)
}
return fmt.Sprintf("服务 %s 未能在 %v 内恢复", sct.config.ServiceName, sct.config.MaxRecoveryTime)
}(),
Metrics: map[string]float64{
"crash_duration_seconds": sct.config.CrashDuration.Seconds(),
"recovery_time_seconds": time.Since(recoveryStart).Seconds(),
},
}
log.Printf("服务崩溃测试完成: %s, 结果: %v", sct.config.ServiceName, result.Passed)
return result, nil
}
// isServiceHealthy 检查服务是否健康
func (sct *ServiceCrashTest) isServiceHealthy(serviceName string) bool {
// 这里应该实现实际的服务健康检查逻辑
// 例如调用服务的健康检查接口
return true // 简化示例
}
自动化测试框架
// AvailabilityTestSuite 可用性测试套件
type AvailabilityTestSuite struct {
// 测试名称
Name string
// 测试列表
Tests []AvailabilityTest
// 测试报告
Report *TestReport
}
// AvailabilityTest 可用性测试接口
type AvailabilityTest interface {
// GetName 获取测试名称
GetName() string
// Run 运行测试
Run() (*TestResult, error)
}
// TestReport 测试报告
type TestReport struct {
// 报告ID
ID string `json:"id"`
// 测试套件名称
SuiteName string `json:"suite_name"`
// 开始时间
StartTime time.Time `json:"start_time"`
// 结束时间
EndTime time.Time `json:"end_time"`
// 测试结果列表
Results []*TestResultDetail `json:"results"`
// 总结
Summary TestSummary `json:"summary"`
}
// TestResultDetail 测试结果详情
type TestResultDetail struct {
// 测试名称
TestName string `json:"test_name"`
// 结果
Result *TestResult `json:"result"`
// 开始时间
StartTime time.Time `json:"start_time"`
// 结束时间
EndTime time.Time `json:"end_time"`
}
// TestSummary 测试总结
type TestSummary struct {
// 总测试数
Total int `json:"total"`
// 通过数
Passed int `json:"passed"`
// 失败数
Failed int `json:"failed"`
// 通过率
PassRate float64 `json:"pass_rate"`
}
// NewAvailabilityTestSuite 创建可用性测试套件
func NewAvailabilityTestSuite(name string, tests []AvailabilityTest) *AvailabilityTestSuite {
return &AvailabilityTestSuite{
Name: name,
Tests: tests,
Report: &TestReport{
ID: generateUUID(),
SuiteName: name,
StartTime: time.Now(),
Results: make([]*TestResultDetail, 0),
},
}
}
// Run 运行测试套件
func (ats *AvailabilityTestSuite) Run() (*TestReport, error) {
log.Printf("开始运行可用性测试套件: %s", ats.Name)
var passed, failed int
// 依次运行每个测试
for _, test := range ats.Tests {
log.Printf("运行测试: %s", test.GetName())
startTime := time.Now()
result, err := test.Run()
endTime := time.Now()
// 记录测试结果
detail := &TestResultDetail{
TestName: test.GetName(),
Result: result,
StartTime: startTime,
EndTime: endTime,
}
ats.Report.Results = append(ats.Report.Results, detail)
if err != nil {
log.Printf("测试 %s 执行失败: %v", test.GetName(), err)
failed++
continue
}
if result.Passed {
log.Printf("测试 %s 通过", test.GetName())
passed++
} else {
log.Printf("测试 %s 失败: %s", test.GetName(), result.Details)
failed++
}
}
// 更新报告
ats.Report.EndTime = time.Now()
ats.Report.Summary = TestSummary{
Total: len(ats.Tests),
Passed: passed,
Failed: failed,
PassRate: float64(passed) / float64(len(ats.Tests)),
}
log.Printf("可用性测试套件 %s 运行完成,通过率: %.2f%%",
ats.Name, ats.Report.Summary.PassRate*100)
return ats.Report, nil
}
// SaveReport 保存测试报告
func (ats *AvailabilityTestSuite) SaveReport(filePath string) error {
data, err := json.MarshalIndent(ats.Report, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal report: %w", err)
}
return ioutil.WriteFile(filePath, data, 0644)
}
使用示例
// 初始化测试环境
func main() {
// 创建故障存储(简化实现)
faultStore := &InMemoryFaultStore{
faults: make(map[string]*Fault),
}
// 创建通知器
notifier := &ConsoleNotifier{}
// 创建活动管理器
activityManager := &InMemoryActivityManager{
activities: make(map[string]*Activity),
}
// 创建故障注入器
faultInjector := NewChaosFaultInjector(faultStore, notifier, activityManager)
// 创建测试配置
networkTestConfig := &NetworkPartitionTestConfig{
Duration: 30 * time.Second,
Hosts: []string{"host1", "host2"},
ExpectedResult: TestResult{
Passed: true,
},
}
serviceTestConfig := &ServiceCrashTestConfig{
ServiceName: "notification-service",
CrashDuration: 10 * time.Second,
CheckInterval: 2 * time.Second,
MaxRecoveryTime: 30 * time.Second,
}
// 创建测试实例
networkTest := NewNetworkPartitionTest(faultInjector, networkTestConfig)
serviceTest := NewServiceCrashTest(faultInjector, serviceTestConfig)
// 创建测试套件
testSuite := NewAvailabilityTestSuite("高可用性测试套件", []AvailabilityTest{
&TestWrapper{"网络分区测试", networkTest},
&TestWrapper{"服务崩溃测试", serviceTest},
})
// 运行测试套件
report, err := testSuite.Run()
if err != nil {
log.Fatalf("测试套件运行失败: %v", err)
}
// 保存测试报告
if err := testSuite.SaveReport("availability_test_report.json"); err != nil {
log.Printf("保存测试报告失败: %v", err)
}
// 打印测试总结
fmt.Printf("测试总结:\n")
fmt.Printf(" 总测试数: %d\n", report.Summary.Total)
fmt.Printf(" 通过数: %d\n", report.Summary.Passed)
fmt.Printf(" 失败数: %d\n", report.Summary.Failed)
fmt.Printf(" 通过率: %.2f%%\n", report.Summary.PassRate*100)
}
// 辅助结构体和接口实现
type InMemoryFaultStore struct {
faults map[string]*Fault
mutex sync.RWMutex
}
func (ims *InMemoryFaultStore) SaveFault(fault *Fault) error {
ims.mutex.Lock()
defer ims.mutex.Unlock()
ims.faults[fault.ID] = fault
return nil
}
func (ims *InMemoryFaultStore) GetFaultByID(id string) (*Fault, error) {
ims.mutex.RLock()
defer ims.mutex.RUnlock()
if fault, exists := ims.faults[id]; exists {
return fault, nil
}
return nil, fmt.Errorf("fault not found")
}
func (ims *InMemoryFaultStore) ListFaults() ([]*Fault, error) {
ims.mutex.RLock()
defer ims.mutex.RUnlock()
var faults []*Fault
for _, fault := range ims.faults {
faults = append(faults, fault)
}
return faults, nil
}
func (ims *InMemoryFaultStore) UpdateFault(fault *Fault) error {
ims.mutex.Lock()
defer ims.mutex.Unlock()
ims.faults[fault.ID] = fault
return nil
}
type ConsoleNotifier struct{}
func (cn *ConsoleNotifier) Notify(message string, level NotificationLevel) error {
fmt.Printf("[%s] %s\n", level, message)
return nil
}
type InMemoryActivityManager struct {
activities map[string]*Activity
mutex sync.RWMutex
}
func (iam *InMemoryActivityManager) RecordActivity(activity *Activity) error {
iam.mutex.Lock()
defer iam.mutex.Unlock()
iam.activities[activity.ID] = activity
return nil
}
type TestWrapper struct {
name string
test interface{}
}
func (tw *TestWrapper) GetName() string {
return tw.name
}
func (tw *TestWrapper) Run() (*TestResult, error) {
switch t := tw.test.(type) {
case *NetworkPartitionTest:
return t.Run()
case *ServiceCrashTest:
return t.Run()
default:
return nil, fmt.Errorf("unsupported test type")
}
}
// 工具函数
func generateUUID() string {
return fmt.Sprintf("%x-%x-%x-%x-%x",
make([]byte, 4), make([]byte, 2), make([]byte, 2), make([]byte, 2), make([]byte, 6))
}
总结
通过以上实现,我们构建了一个完整的可用性测试和容灾演练框架,具有以下特点:
- 多种故障注入能力:支持网络、服务、数据库、磁盘、CPU、内存等多种故障类型
- 自动化测试套件:可以组合多个测试用例形成测试套件
- 详细的测试报告:提供完整的测试结果和性能指标
- 灵活的扩展性:易于添加新的故障类型和测试场景
在实际应用中,还需要考虑以下几点:
- 安全控制:确保故障注入不会对生产环境造成严重影响
- 权限管理:控制谁可以执行故障注入测试
- 监控告警:在测试过程中实时监控系统状态
- 回滚机制:确保在测试失败时能够快速恢复系统
通过定期进行可用性测试和容灾演练,我们可以及时发现系统中的薄弱环节,验证高可用架构的有效性,确保系统在真实故障场景下能够稳定运行。