using CSRedis; using dodohold.core; using ICSharpCode.SharpZipLib.Zip; using Microsoft.AspNetCore.Mvc; using System.Diagnostics; using System.Text; using System.Text.Json.Serialization; namespace molilian.api.Controllers { [ApiController] [Route("api/[controller]")] public class StressTestController : ControllerBase { private static readonly StressTestService _stressTestService = new(); [HttpPost("start")] public IActionResult StartTest([FromBody] StressTestConfig config) { _stressTestService.StartTest(config); return Ok(new { message = "压力测试已启动" }); } [HttpPost("stop")] public IActionResult StopTest() { _stressTestService.StopTest(); return Ok(new { message = "压力测试已停止" }); } [HttpGet("status")] public IActionResult GetStatus() { return Ok(_stressTestService.GetStatus()); } // StressTestController.cs 中 GetMetrics 方法的修改 [HttpGet("metrics")] public IActionResult GetMetrics() { var status = _stressTestService.GetStatus(); return Ok(new { 每秒总操作数 = status.LastSecondOperations, 每秒读操作数 = status.LastSecondReads, 每秒写操作数 = status.LastSecondWrites, 数据吞吐量 = status.FormattedThroughput, 平均响应时间 = status.AverageResponseTime }); } } // StressTestService.cs public class StressTestService { private CancellationTokenSource _cancellationTokenSource; private TestStatus _status = new TestStatus(); private readonly object _lockObject = new object(); private volatile int _currentConcurrentTasks; // 当前并发数 private List _runningTasks; // 正在运行的任务列表 // 计数器字段 private int _timeoutCount; private int _errorCount; private int _completedRequests; private long _totalResponseTime; private int _readCount; // 添加读操作计数 private int _writeCount; // 添加写操作计数 private string _testValue; // 缓存生成的测试数据 private readonly Random _random = new Random(); private int _lastSecondReads; private int _lastSecondWrites; private DateTime _lastCounterReset = DateTime.Now; private volatile StressTestConfig _currentConfig; // 添加当前配置字段 private async Task ManageTasks(CancellationToken cancellationToken) { _runningTasks = new List(); while (!cancellationToken.IsCancellationRequested) { try { // 移除已完成的任务 _runningTasks.RemoveAll(t => t.IsCompleted || t.IsFaulted || t.IsCanceled); // 获取当前配置的目标并发数 int targetConcurrency = _currentConfig.ConcurrentTasks; // 增加任务 while (_runningTasks.Count < targetConcurrency) { var taskId = _runningTasks.Count; var task = RunSingleTask(taskId, cancellationToken); _runningTasks.Add(task); Console.WriteLine($"添加新任务,当前任务数:{_runningTasks.Count}"); } // 减少任务 while (_runningTasks.Count > targetConcurrency) { int removeCount = _runningTasks.Count - targetConcurrency; Console.WriteLine($"移除{removeCount}个任务"); // 移除多余的任务 _runningTasks.RemoveRange(targetConcurrency, removeCount); } await Task.Delay(1000, cancellationToken); // 每秒检查一次任务状态 } catch (OperationCanceledException) { // 正常的取消操作 break; } catch (Exception ex) { Console.WriteLine($"任务管理异常:{ex.Message}"); // 继续运行,不要因为单次异常而停止整个测试 } } } public void StartTest(StressTestConfig config) { lock (_lockObject) { // 更新配置 _currentConfig = config; if (_status.IsRunning) { Console.WriteLine($"更新配置 - 并发数: {config.ConcurrentTasks}, 读写比: {config.ReadsPerWrite}, 数据大小: {config.ValueSizeKB}KB"); _status.CurrentConfig = config; return; } // 首次启动 Console.WriteLine($"启动测试 - 并发数: {config.ConcurrentTasks}, 读写比: {config.ReadsPerWrite}, 数据大小: {config.ValueSizeKB}KB"); _timeoutCount = 0; _errorCount = 0; _completedRequests = 0; _totalResponseTime = 0; _readCount = 0; _writeCount = 0; _totalDataSize = 0; _cancellationTokenSource = new CancellationTokenSource(); _status = new TestStatus { IsRunning = true, StartTime = DateTime.Now, CurrentConfig = config, EndTime = DateTime.Now.AddHours(1) }; // 启动任务管理器 Task.Run(() => ManageTasks(_cancellationTokenSource.Token)); } } private async Task RunSingleTask(int taskId, CancellationToken cancellationToken) { var endTime = DateTime.Now.AddHours(1); int requestId = 0; while (DateTime.Now < endTime && !cancellationToken.IsCancellationRequested) { try { // 获取最新配置 var config = _currentConfig; var testValue = GenerateTestValue(config.ValueSizeKB); var key = $"test:key:{taskId}:{requestId++}"; // 构造包含大小信息的值 var value = new { id = $"{taskId}_{requestId}", timestamp = DateTime.Now.Ticks, data = testValue }; // 写入操作 try { var requestSw = Stopwatch.StartNew(); var setTask = RedisHelper.SetAsync(key, value, 3600); var timeoutTask = Task.Delay(config.TimeoutMs); var completedTask = await Task.WhenAny(setTask, timeoutTask); if (completedTask == timeoutTask) { Interlocked.Increment(ref _timeoutCount); continue; } requestSw.Stop(); Interlocked.Increment(ref _writeCount); Interlocked.Increment(ref _lastSecondWrites); Interlocked.Add(ref _totalResponseTime, requestSw.ElapsedMilliseconds); Interlocked.Add(ref _totalDataSize, config.ValueSizeKB * 1024); UpdateStatus(); } catch (Exception) { Interlocked.Increment(ref _errorCount); continue; } // 执行多次读取操作,使用最新的配置 for (int i = 0; i < config.ReadsPerWrite && !cancellationToken.IsCancellationRequested; i++) { try { var requestSw = Stopwatch.StartNew(); var getTask = Task.Run(() => { try { RedisHelper.Get(key); } catch (Exception) { Interlocked.Increment(ref _errorCount); } }); var timeoutTask = Task.Delay(config.TimeoutMs); var completedTask = await Task.WhenAny(getTask, timeoutTask); if (completedTask == timeoutTask) { Interlocked.Increment(ref _timeoutCount); continue; } requestSw.Stop(); Interlocked.Increment(ref _readCount); Interlocked.Increment(ref _lastSecondReads); Interlocked.Add(ref _totalResponseTime, requestSw.ElapsedMilliseconds); Interlocked.Add(ref _totalDataSize, config.ValueSizeKB * 1024); UpdateStatus(); if (config.OperationIntervalMs > 0) { await Task.Delay(config.OperationIntervalMs, cancellationToken); } } catch (Exception) { Interlocked.Increment(ref _errorCount); } } } catch (Exception ex) { Console.WriteLine($"任务 {taskId} 异常:{ex.Message}"); Interlocked.Increment(ref _errorCount); // 添加短暂延迟,避免出错时立即重试 await Task.Delay(100, cancellationToken); } } } // 生成指定大小的随机字符串 private string GenerateTestValue(int sizeKB) { if (_testValue != null && _testValue.Length == sizeKB * 1024) // 如果已有相同大小的数据,直接返回 return _testValue; const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; var stringBuilder = new StringBuilder(sizeKB * 1024); for (int i = 0; i < sizeKB * 1024; i++) { stringBuilder.Append(chars[_random.Next(chars.Length)]); } _testValue = stringBuilder.ToString(); return _testValue; } private long _totalDataSize; // 添加数据大小统计 private void UpdateStatus() { lock (_lockObject) { var now = DateTime.Now; if ((now - _lastCounterReset).TotalSeconds >= 1) { _status.LastSecondReads = _lastSecondReads; _status.LastSecondWrites = _lastSecondWrites; _status.LastSecondOperations = _lastSecondReads + _lastSecondWrites; _lastSecondReads = 0; _lastSecondWrites = 0; _lastCounterReset = now; } _status.TimeoutCount = _timeoutCount; _status.ErrorCount = _errorCount; _status.CompletedRequests = _completedRequests; _status.ReadCount = _readCount; _status.WriteCount = _writeCount; _status.AverageResponseTime = (double)_totalResponseTime / (_readCount + _writeCount); _status.TotalDataSize = _totalDataSize; _status.DataThroughput = _status.TotalDataSize / (DateTime.Now - _status.StartTime.Value).TotalSeconds; } } public void StopTest() { lock (_lockObject) { if (_status.IsRunning) { _cancellationTokenSource?.Cancel(); _status.IsRunning = false; } } } public TestStatus GetStatus() { return _status; } } // TestStatus.cs 的修改部分 public class TestStatus { [JsonPropertyName("运行状态")] public bool IsRunning { get; set; } [JsonPropertyName("计划总请求数")] public int TotalRequests { get; set; } [JsonPropertyName("已完成请求数")] public int CompletedRequests { get; set; } [JsonPropertyName("超时次数")] public int TimeoutCount { get; set; } [JsonPropertyName("错误次数")] public int ErrorCount { get; set; } [JsonPropertyName("平均响应时间(ms)")] public double AverageResponseTime { get; set; } [JsonPropertyName("开始时间")] public DateTime? StartTime { get; set; } [JsonPropertyName("当前配置")] public StressTestConfig CurrentConfig { get; set; } [JsonPropertyName("进度百分比")] public double ProgressPercentage => TotalRequests == 0 ? 0 : (CompletedRequests * 100.0 / TotalRequests); [JsonPropertyName("读操作总数")] public int ReadCount { get; set; } [JsonPropertyName("写操作总数")] public int WriteCount { get; set; } [JsonPropertyName("读写比例")] public double ReadWriteRatio => WriteCount == 0 ? 0 : (double)ReadCount / WriteCount; [JsonPropertyName("每秒平均操作数")] public double OperationsPerSecond => StartTime.HasValue ? (ReadCount + WriteCount) / (DateTime.Now - StartTime.Value).TotalSeconds : 0; [JsonPropertyName("结束时间")] public DateTime? EndTime { get; set; } [JsonPropertyName("剩余时间(分钟)")] public double RemainingMinutes => EndTime.HasValue ? Math.Max(0, (EndTime.Value - DateTime.Now).TotalMinutes) : 0; [JsonPropertyName("总数据量(字节)")] public long TotalDataSize { get; set; } [JsonPropertyName("数据吞吐量(字节/秒)")] public double DataThroughput { get; set; } [JsonPropertyName("数据吞吐量")] public string FormattedThroughput { get { if (DataThroughput < 1024) return $"{DataThroughput:F2} B/s"; if (DataThroughput < 1024 * 1024) return $"{DataThroughput / 1024:F2} KB/s"; if (DataThroughput < 1024 * 1024 * 1024) return $"{DataThroughput / (1024 * 1024):F2} MB/s"; return $"{DataThroughput / (1024 * 1024 * 1024):F2} GB/s"; } } [JsonPropertyName("最近每秒操作数")] public int LastSecondOperations { get; set; } [JsonPropertyName("最近每秒读操作数")] public int LastSecondReads { get; set; } [JsonPropertyName("最近每秒写操作数")] public int LastSecondWrites { get; set; } } // StressTestConfig.cs 的修改部分 public class StressTestConfig { [JsonPropertyName("并发任务数")] public int ConcurrentTasks { get; set; } = 100; [JsonPropertyName("超时时间(ms)")] public int TimeoutMs { get; set; } = 1000; [JsonPropertyName("读写比例")] public int ReadsPerWrite { get; set; } = 10; [JsonPropertyName("操作间隔(ms)")] public int OperationIntervalMs { get; set; } = 0; [JsonPropertyName("数据大小(KB)")] public int ValueSizeKB { get; set; } = 10; } }