2025-11-20 17:37:12 +08:00
|
|
|
|
// Package main implement redis test data injection
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"log"
|
|
|
|
|
|
"math/rand"
|
2025-11-21 17:02:07 +08:00
|
|
|
|
"os"
|
|
|
|
|
|
"os/signal"
|
|
|
|
|
|
"strconv"
|
|
|
|
|
|
"syscall"
|
2025-11-20 17:37:12 +08:00
|
|
|
|
"time"
|
|
|
|
|
|
|
2025-11-28 17:17:58 +08:00
|
|
|
|
"modelRT/deploy/redis-test-data/util"
|
2025-11-20 17:37:12 +08:00
|
|
|
|
"modelRT/orm"
|
|
|
|
|
|
|
|
|
|
|
|
redis "github.com/redis/go-redis/v9"
|
|
|
|
|
|
"gorm.io/driver/postgres"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// Redis配置
|
|
|
|
|
|
const (
|
2025-12-01 11:27:38 +08:00
|
|
|
|
redisAddr = "localhost:6379"
|
2025-11-20 17:37:12 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-11-21 17:02:07 +08:00
|
|
|
|
var globalRedisClient *redis.Client
|
|
|
|
|
|
|
|
|
|
|
|
// outlierConfig 异常段配置
|
|
|
|
|
|
type outlierConfig struct {
|
2025-11-20 17:37:12 +08:00
|
|
|
|
Enabled bool // 是否启用异常段
|
|
|
|
|
|
Count int // 异常段数量 (0=随机, 1-5=指定数量)
|
|
|
|
|
|
MinLength int // 异常段最小长度
|
|
|
|
|
|
MaxLength int // 异常段最大长度
|
|
|
|
|
|
Intensity float64 // 异常强度系数 (1.0=轻微超出, 2.0=显著超出)
|
|
|
|
|
|
Distribution string // 分布类型 "both"-上下都有, "upper"-只向上, "lower"-只向下
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GenerateFloatSliceWithOutliers 生成包含连续异常段的数据
|
|
|
|
|
|
// baseValue: 基准值
|
|
|
|
|
|
// changes: 变化范围,每2个元素为一组 [minChange1, maxChange1, minChange2, maxChange2, ...]
|
|
|
|
|
|
// size: 生成的切片长度
|
|
|
|
|
|
// variationType: 变化类型
|
|
|
|
|
|
// outlierConfig: 异常段配置
|
2025-11-21 17:02:07 +08:00
|
|
|
|
func generateFloatSliceWithOutliers(baseValue float64, changes []float64, size int, variationType string, outlierConfig outlierConfig) ([]float64, error) {
|
2025-11-20 17:37:12 +08:00
|
|
|
|
// 先生成正常数据
|
|
|
|
|
|
data, err := generateFloatSlice(baseValue, changes, size, variationType)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 插入异常段
|
|
|
|
|
|
if outlierConfig.Enabled {
|
|
|
|
|
|
data = insertOutliers(data, baseValue, changes, outlierConfig)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return data, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 插入异常段
|
2025-11-21 17:02:07 +08:00
|
|
|
|
func insertOutliers(data []float64, baseValue float64, changes []float64, config outlierConfig) []float64 {
|
2025-11-20 17:37:12 +08:00
|
|
|
|
if len(data) == 0 || !config.Enabled {
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取变化范围的边界
|
|
|
|
|
|
minBound, maxBound := getChangeBounds(baseValue, changes)
|
|
|
|
|
|
// TODO delete
|
2025-11-21 17:02:07 +08:00
|
|
|
|
log.Printf("获取变化范围的边界,min:%.4f,max:%.4f\n", minBound, maxBound)
|
2025-11-20 17:37:12 +08:00
|
|
|
|
|
|
|
|
|
|
// 确定异常段数量
|
|
|
|
|
|
outlierCount := config.Count
|
|
|
|
|
|
if outlierCount == 0 {
|
|
|
|
|
|
// 随机生成1-3个异常段
|
|
|
|
|
|
outlierCount = rand.Intn(3) + 1
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算最大可能的异常段数量
|
|
|
|
|
|
maxPossibleOutliers := len(data) / (config.MinLength + 10)
|
|
|
|
|
|
if outlierCount > maxPossibleOutliers {
|
|
|
|
|
|
outlierCount = maxPossibleOutliers
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成异常段位置
|
|
|
|
|
|
segments := generateOutlierSegments(len(data), config.MinLength, config.MaxLength, outlierCount, config.Distribution)
|
|
|
|
|
|
// TODO 调试信息待删除
|
2025-11-21 17:02:07 +08:00
|
|
|
|
log.Printf("生成异常段位置:%+v\n", segments)
|
2025-11-20 17:37:12 +08:00
|
|
|
|
// 插入异常数据
|
|
|
|
|
|
for _, segment := range segments {
|
|
|
|
|
|
data = insertOutlierSegment(data, segment, minBound, maxBound, config)
|
|
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取变化范围的边界
|
|
|
|
|
|
func getChangeBounds(baseValue float64, changes []float64) (minBound, maxBound float64) {
|
|
|
|
|
|
if len(changes) == 0 {
|
|
|
|
|
|
return baseValue - 10, baseValue + 10
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ranges := normalizeRanges(changes)
|
|
|
|
|
|
minBound, maxBound = baseValue+ranges[0][0], baseValue+ranges[0][1]
|
|
|
|
|
|
|
|
|
|
|
|
for _, r := range ranges {
|
|
|
|
|
|
if baseValue+r[0] < minBound {
|
|
|
|
|
|
minBound = baseValue + r[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
if baseValue+r[1] > maxBound {
|
|
|
|
|
|
maxBound = baseValue + r[1]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return minBound, maxBound
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// OutlierSegment 异常段定义
|
|
|
|
|
|
type OutlierSegment struct {
|
|
|
|
|
|
Start int
|
|
|
|
|
|
Length int
|
|
|
|
|
|
Type string // "upper"-向上异常, "lower"-向下异常
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func generateOutlierSegments(totalSize, minLength, maxLength, count int, distribution string) []OutlierSegment {
|
|
|
|
|
|
if count == 0 {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
segments := make([]OutlierSegment, 0, count)
|
|
|
|
|
|
usedPositions := make(map[int]bool)
|
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < count; i++ {
|
|
|
|
|
|
// 尝试多次寻找合适的位置
|
|
|
|
|
|
for attempt := 0; attempt < 10; attempt++ {
|
|
|
|
|
|
length := rand.Intn(maxLength-minLength+1) + minLength
|
|
|
|
|
|
start := rand.Intn(totalSize - length)
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否与已有段重叠
|
|
|
|
|
|
overlap := false
|
|
|
|
|
|
for pos := start; pos < start+length; pos++ {
|
|
|
|
|
|
if usedPositions[pos] {
|
|
|
|
|
|
overlap = true
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if !overlap {
|
|
|
|
|
|
// 标记已使用的位置
|
|
|
|
|
|
for pos := start; pos < start+length; pos++ {
|
|
|
|
|
|
usedPositions[pos] = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据 distribution 配置决定异常类型
|
|
|
|
|
|
var outlierType string
|
|
|
|
|
|
switch distribution {
|
|
|
|
|
|
case "upper":
|
|
|
|
|
|
outlierType = "upper"
|
|
|
|
|
|
case "lower":
|
|
|
|
|
|
outlierType = "lower"
|
|
|
|
|
|
case "both":
|
|
|
|
|
|
fallthrough
|
|
|
|
|
|
default:
|
|
|
|
|
|
if rand.Float64() < 0.5 {
|
|
|
|
|
|
outlierType = "upper"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
outlierType = "lower"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
segments = append(segments, OutlierSegment{
|
|
|
|
|
|
Start: start,
|
|
|
|
|
|
Length: length,
|
|
|
|
|
|
Type: outlierType,
|
|
|
|
|
|
})
|
|
|
|
|
|
break
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return segments
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-21 17:02:07 +08:00
|
|
|
|
func insertOutlierSegment(data []float64, segment OutlierSegment, minBound, maxBound float64, config outlierConfig) []float64 {
|
2025-11-20 17:37:12 +08:00
|
|
|
|
rangeWidth := maxBound - minBound
|
|
|
|
|
|
|
|
|
|
|
|
// 确定整个异常段的方向
|
|
|
|
|
|
outlierType := segment.Type
|
|
|
|
|
|
if outlierType == "" {
|
|
|
|
|
|
switch config.Distribution {
|
|
|
|
|
|
case "upper":
|
|
|
|
|
|
outlierType = "upper"
|
|
|
|
|
|
case "lower":
|
|
|
|
|
|
outlierType = "lower"
|
|
|
|
|
|
default:
|
|
|
|
|
|
if rand.Float64() < 0.5 {
|
|
|
|
|
|
outlierType = "upper"
|
|
|
|
|
|
} else {
|
|
|
|
|
|
outlierType = "lower"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 为整个段生成同方向异常值
|
|
|
|
|
|
for i := segment.Start; i < segment.Start+segment.Length && i < len(data); i++ {
|
|
|
|
|
|
excess := rangeWidth * (0.3 + rand.Float64()*config.Intensity)
|
|
|
|
|
|
|
|
|
|
|
|
if outlierType == "upper" {
|
|
|
|
|
|
data[i] = maxBound + excess
|
|
|
|
|
|
} else {
|
|
|
|
|
|
data[i] = minBound - excess
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func detectOutlierSegments(data []float64, baseValue float64, changes []float64, minSegmentLength int) []OutlierSegment {
|
|
|
|
|
|
if len(data) == 0 {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
minBound, maxBound := getChangeBounds(baseValue, changes)
|
|
|
|
|
|
var segments []OutlierSegment
|
|
|
|
|
|
currentStart := -1
|
|
|
|
|
|
currentType := ""
|
|
|
|
|
|
|
|
|
|
|
|
for i, value := range data {
|
|
|
|
|
|
isOutlier := value > maxBound || value < minBound
|
|
|
|
|
|
|
|
|
|
|
|
if isOutlier {
|
|
|
|
|
|
outlierType := "upper"
|
|
|
|
|
|
if value < minBound {
|
|
|
|
|
|
outlierType = "lower"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if currentStart == -1 {
|
|
|
|
|
|
// 开始新的异常段
|
|
|
|
|
|
currentStart = i
|
|
|
|
|
|
currentType = outlierType
|
|
|
|
|
|
} else if currentType != outlierType {
|
|
|
|
|
|
// 类型变化,结束当前段
|
|
|
|
|
|
if i-currentStart >= minSegmentLength {
|
|
|
|
|
|
segments = append(segments, OutlierSegment{
|
|
|
|
|
|
Start: currentStart,
|
|
|
|
|
|
Length: i - currentStart,
|
|
|
|
|
|
Type: currentType,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
currentStart = i
|
|
|
|
|
|
currentType = outlierType
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
if currentStart != -1 {
|
|
|
|
|
|
// 结束当前异常段
|
|
|
|
|
|
if i-currentStart >= minSegmentLength {
|
|
|
|
|
|
segments = append(segments, OutlierSegment{
|
|
|
|
|
|
Start: currentStart,
|
|
|
|
|
|
Length: i - currentStart,
|
|
|
|
|
|
Type: currentType,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
currentStart = -1
|
|
|
|
|
|
currentType = ""
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理最后的异常段
|
|
|
|
|
|
if currentStart != -1 && len(data)-currentStart >= minSegmentLength {
|
|
|
|
|
|
segments = append(segments, OutlierSegment{
|
|
|
|
|
|
Start: currentStart,
|
|
|
|
|
|
Length: len(data) - currentStart,
|
|
|
|
|
|
Type: currentType,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return segments
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func generateFloatSlice(baseValue float64, changes []float64, size int, variationType string) ([]float64, error) {
|
|
|
|
|
|
return generateRandomData(baseValue, changes, size), nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func normalizeRanges(changes []float64) [][2]float64 {
|
|
|
|
|
|
ranges := make([][2]float64, len(changes)/2)
|
|
|
|
|
|
for i := 0; i < len(changes); i += 2 {
|
|
|
|
|
|
min, max := changes[i], changes[i+1]
|
|
|
|
|
|
if min > max {
|
|
|
|
|
|
min, max = max, min
|
|
|
|
|
|
}
|
|
|
|
|
|
ranges[i/2] = [2]float64{min, max}
|
|
|
|
|
|
}
|
|
|
|
|
|
return ranges
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func generateRandomData(baseValue float64, changes []float64, size int) []float64 {
|
|
|
|
|
|
data := make([]float64, size)
|
|
|
|
|
|
ranges := normalizeRanges(changes)
|
|
|
|
|
|
for i := range data {
|
|
|
|
|
|
rangeIdx := rand.Intn(len(ranges))
|
|
|
|
|
|
minChange := ranges[rangeIdx][0]
|
|
|
|
|
|
maxChange := ranges[rangeIdx][1]
|
|
|
|
|
|
change := minChange + rand.Float64()*(maxChange-minChange)
|
|
|
|
|
|
data[i] = baseValue + change
|
|
|
|
|
|
}
|
|
|
|
|
|
return data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-21 17:02:07 +08:00
|
|
|
|
// simulateDataWrite 定时生成并写入模拟数据到 Redis ZSet
|
2025-11-28 17:17:58 +08:00
|
|
|
|
func simulateDataWrite(ctx context.Context, rdb *redis.Client, redisKey string, config outlierConfig, measInfo util.CalculationResult) {
|
2025-11-21 17:02:07 +08:00
|
|
|
|
log.Printf("启动数据写入程序, Redis Key: %s, 基准值: %.4f, 变化范围: %+v\n", redisKey, measInfo.BaseValue, measInfo.Changes)
|
2025-11-26 17:49:24 +08:00
|
|
|
|
ticker := time.NewTicker(3 * time.Second)
|
2025-11-21 17:02:07 +08:00
|
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
|
|
|
|
pipe := rdb.Pipeline()
|
|
|
|
|
|
for {
|
|
|
|
|
|
select {
|
|
|
|
|
|
case <-ctx.Done():
|
|
|
|
|
|
log.Printf("\n[%s] 写入程序已停止\n", redisKey)
|
|
|
|
|
|
return
|
|
|
|
|
|
case <-ticker.C:
|
|
|
|
|
|
minBound, maxBound := getChangeBounds(measInfo.BaseValue, measInfo.Changes)
|
|
|
|
|
|
log.Printf("计算边界: [%.4f, %.4f]\n", minBound, maxBound)
|
|
|
|
|
|
|
|
|
|
|
|
// 根据基准值类型决定如何处理
|
|
|
|
|
|
switch measInfo.BaseType {
|
|
|
|
|
|
case "TI":
|
|
|
|
|
|
// 边沿触发类型,生成特殊处理的数据
|
|
|
|
|
|
log.Printf("边沿触发类型,跳过异常数据生成\n")
|
|
|
|
|
|
return
|
|
|
|
|
|
case "TE":
|
|
|
|
|
|
// 正常上下限类型,生成包含异常的数据
|
|
|
|
|
|
if len(measInfo.Changes) == 0 {
|
|
|
|
|
|
log.Printf("无变化范围数据,跳过\n")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 根据变化范围数量调整异常配置
|
|
|
|
|
|
if len(measInfo.Changes) == 2 {
|
|
|
|
|
|
// 只有上下限
|
|
|
|
|
|
config.Distribution = "both"
|
|
|
|
|
|
} else if len(measInfo.Changes) == 4 {
|
|
|
|
|
|
// 有上下限和预警上下限
|
|
|
|
|
|
config.Distribution = "both"
|
|
|
|
|
|
config.Intensity = 2.0 // 增强异常强度
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成包含异常的数据
|
|
|
|
|
|
data, err := generateFloatSliceWithOutliers(
|
|
|
|
|
|
measInfo.BaseValue,
|
|
|
|
|
|
measInfo.Changes,
|
|
|
|
|
|
measInfo.Size,
|
|
|
|
|
|
"random",
|
|
|
|
|
|
config,
|
|
|
|
|
|
)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Printf("生成异常数据失败:%v\n", err)
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
segments := detectOutlierSegments(data, measInfo.BaseValue, measInfo.Changes, config.MinLength)
|
|
|
|
|
|
log.Printf("检测到异常段数量:%d\n", len(segments))
|
|
|
|
|
|
for i, segment := range segments {
|
|
|
|
|
|
log.Printf("异常段%d: 位置[%d-%d], 长度=%d, 类型=%s\n",
|
|
|
|
|
|
i+1, segment.Start, segment.Start+segment.Length-1, segment.Length, segment.Type)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
redisZs := make([]redis.Z, 0, len(data))
|
|
|
|
|
|
for i := range len(data) {
|
|
|
|
|
|
z := redis.Z{
|
|
|
|
|
|
Score: data[i],
|
|
|
|
|
|
Member: strconv.FormatInt(time.Now().UnixNano(), 10),
|
|
|
|
|
|
}
|
|
|
|
|
|
redisZs = append(redisZs, z)
|
|
|
|
|
|
}
|
|
|
|
|
|
pipe.ZAdd(ctx, redisKey, redisZs...)
|
|
|
|
|
|
_, err = pipe.Exec(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
log.Printf("redis pipeline execution failed: %v", err)
|
|
|
|
|
|
}
|
2025-11-25 16:13:55 +08:00
|
|
|
|
log.Printf("生成 redis 实时数据成功\n")
|
2025-11-21 17:02:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func gracefulShutdown() {
|
|
|
|
|
|
if globalRedisClient != nil {
|
|
|
|
|
|
if err := globalRedisClient.Close(); err != nil {
|
|
|
|
|
|
log.Printf("关闭 Redis 客户端失败:%v", err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
log.Println("关闭 Redis 客户端成功")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-20 17:37:12 +08:00
|
|
|
|
func main() {
|
2025-11-21 17:02:07 +08:00
|
|
|
|
rootCtx := context.Background()
|
2025-11-20 17:37:12 +08:00
|
|
|
|
|
|
|
|
|
|
pgURI := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s", "192.168.1.101", 5432, "postgres", "coslight", "demo")
|
|
|
|
|
|
|
2025-11-21 17:02:07 +08:00
|
|
|
|
postgresDBClient, err := gorm.Open(postgres.Open(pgURI))
|
2025-11-20 17:37:12 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
}
|
2025-11-21 17:02:07 +08:00
|
|
|
|
defer func() {
|
|
|
|
|
|
sqlDB, err := postgresDBClient.DB()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
sqlDB.Close()
|
|
|
|
|
|
}()
|
2025-11-20 17:37:12 +08:00
|
|
|
|
|
2025-11-21 17:02:07 +08:00
|
|
|
|
cancelCtx, cancel := context.WithTimeout(rootCtx, 5*time.Second)
|
2025-11-20 17:37:12 +08:00
|
|
|
|
defer cancel()
|
|
|
|
|
|
var measurements []orm.Measurement
|
2025-11-21 17:02:07 +08:00
|
|
|
|
result := postgresDBClient.WithContext(cancelCtx).Find(&measurements)
|
2025-11-20 17:37:12 +08:00
|
|
|
|
if result.Error != nil {
|
|
|
|
|
|
panic(result.Error)
|
|
|
|
|
|
}
|
2025-11-21 17:02:07 +08:00
|
|
|
|
log.Println("总共读取到测量点数量:", len(measurements))
|
2025-11-28 17:17:58 +08:00
|
|
|
|
measInfos := util.ProcessMeasurements(measurements)
|
2025-11-20 17:37:12 +08:00
|
|
|
|
|
|
|
|
|
|
// 测量点数据生成(包含异常数据)
|
|
|
|
|
|
// 配置异常段参数
|
2025-11-21 17:02:07 +08:00
|
|
|
|
outlierConfig := outlierConfig{
|
2025-11-20 17:37:12 +08:00
|
|
|
|
Enabled: true, // 是否产生异常段数据
|
|
|
|
|
|
Count: 2, // 异常段数量
|
|
|
|
|
|
MinLength: 10, // 异常段最小连续长度
|
|
|
|
|
|
MaxLength: 15, // 异常段最大连续长度
|
|
|
|
|
|
Intensity: 1.5, // 异常强度
|
|
|
|
|
|
Distribution: "both", // 分布类型
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-01 11:27:38 +08:00
|
|
|
|
globalRedisClient = util.InitRedisClient(redisAddr)
|
2025-11-21 17:02:07 +08:00
|
|
|
|
rCancelCtx, cancel := context.WithCancel(rootCtx)
|
|
|
|
|
|
defer cancel()
|
2025-11-20 17:37:12 +08:00
|
|
|
|
|
|
|
|
|
|
for key, measInfo := range measInfos {
|
2025-11-21 17:02:07 +08:00
|
|
|
|
go simulateDataWrite(rCancelCtx, globalRedisClient, key, outlierConfig, measInfo)
|
2025-11-20 17:37:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-21 17:02:07 +08:00
|
|
|
|
sigChan := make(chan os.Signal, 1)
|
|
|
|
|
|
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
|
|
|
|
|
<-sigChan
|
|
|
|
|
|
gracefulShutdown()
|
2025-11-20 17:37:12 +08:00
|
|
|
|
}
|