| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- using molilian.core;
- using dodohold.core;
- using Microsoft.AspNetCore.Mvc;
- using System.Text;
- using System.Text.Json;
- using System.Collections.Concurrent;
- using System.Diagnostics;
- namespace molilian.api.Controllers
- {
- [ApiController]
- [Route("[controller]/[action]")]
- public class FeatureController : ControllerBase
- {
- protected IHttpContextAccessor _accessor;
- public FeatureController(IHttpContextAccessor accessor)
- {
- _accessor = accessor;
- }
- [HttpGet]
- public async Task<ActionResult> CSRedis(int thread, int durationSeconds = 30)
- {
- var watch = System.Diagnostics.Stopwatch.StartNew();
- var cts = new CancellationTokenSource();
- var performanceLogger = new RedisPerformanceLogger();
- long totalRequests = 0;
- long successCount = 0;
- long failureCount = 0;
- var metricsQueue = new ConcurrentQueue<RedisOperationMetrics>();
- var tasks = new List<Task>();
- for (int i = 0; i < thread; i++)
- {
- tasks.Add(Task.Run(() =>
- {
- while (!cts.Token.IsCancellationRequested)
- {
- var metrics = new RedisOperationMetrics();
- try
- {
- // 写入操作
- var sw = Stopwatch.StartNew();
- var testValue = "test value";
- var key = $"test:csredis:{Guid.NewGuid()}";
- RedisHelper.Set(key, testValue, 60);
- sw.Stop();
- metrics.WriteTimeMs = sw.ElapsedMilliseconds;
- metrics.KeySize = Encoding.UTF8.GetByteCount(key);
- metrics.ValueSize = Encoding.UTF8.GetByteCount(testValue);
- // IncrBy操作
- sw.Restart();
- RedisHelper.IncrBy("counter:csredis", 1);
- sw.Stop();
- metrics.IncrByTimeMs = sw.ElapsedMilliseconds;
- // 读取操作
- sw.Restart();
- var value = RedisHelper.Get("counter:csredis");
- sw.Stop();
- metrics.ReadTimeMs = sw.ElapsedMilliseconds;
- metrics.IsSuccess = true;
- Interlocked.Increment(ref successCount);
- }
- catch (Exception ex)
- {
- metrics.IsSuccess = false;
- metrics.ErrorMessage = ex.Message;
- Interlocked.Increment(ref failureCount);
- string message = $"{ex.Message}\n{ex.StackTrace}";
- NotifyCore.Notify(new NifyMessage
- {
- message = message,
- priority = NifyMessagePriority.high,
- tags = ["red_circle"]
- });
- new LoggerLibrary("Feature").Info(message).SaveAsync();
- }
- finally
- {
- metricsQueue.Enqueue(metrics);
- Interlocked.Increment(ref totalRequests);
- }
- }
- }, cts.Token));
- }
- await Task.Delay(TimeSpan.FromSeconds(durationSeconds));
- cts.Cancel();
- try
- {
- await Task.WhenAll(tasks);
- }
- catch (OperationCanceledException)
- {
- // 预期的取消异常
- }
- watch.Stop();
- var elapsedMs = watch.ElapsedMilliseconds;
- var qps = totalRequests * 1000.0 / elapsedMs;
- var metrics = metricsQueue.ToList();
- var writeStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.WriteTimeMs);
- var incrByStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.IncrByTimeMs);
- var readStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.ReadTimeMs);
- var resultData = new Dictionary<string, object>
- {
- ["ConcurrentThreads"] = thread,
- ["DurationSeconds"] = durationSeconds,
- ["TotalTimeMs"] = elapsedMs,
- ["TotalRequests"] = totalRequests,
- ["SuccessCount"] = successCount,
- ["FailureCount"] = failureCount,
- ["QPS"] = Math.Round(qps, 2),
- ["SuccessRate"] = Math.Round((double)successCount / totalRequests * 100, 2),
- ["RedisMetrics"] = new
- {
- Write = writeStats,
- IncrBy = incrByStats,
- Read = readStats
- }
- };
- await performanceLogger.LogPerformanceResult("CSRedis", resultData);
- return new APIResult(resultData);
- }
- [HttpGet]
- public async Task<ActionResult> FreeRedis(int thread, int durationSeconds = 30)
- {
- var watch = System.Diagnostics.Stopwatch.StartNew();
- var cts = new CancellationTokenSource();
- var performanceLogger = new RedisPerformanceLogger();
- long totalRequests = 0;
- long successCount = 0;
- long failureCount = 0;
- var metricsQueue = new ConcurrentQueue<RedisOperationMetrics>();
- var redis = YunhuiKit.RedisKit.Instance;
- var tasks = new List<Task>();
- for (int i = 0; i < thread; i++)
- {
- tasks.Add(Task.Run(() =>
- {
- while (!cts.Token.IsCancellationRequested)
- {
- var metrics = new RedisOperationMetrics();
- try
- {
- // 写入操作
- var sw = Stopwatch.StartNew();
- var testValue = "test value";
- var key = $"test:freeredis:{Guid.NewGuid()}";
- redis.Set(key, testValue, 60);
- sw.Stop();
- metrics.WriteTimeMs = sw.ElapsedMilliseconds;
- metrics.KeySize = Encoding.UTF8.GetByteCount(key);
- metrics.ValueSize = Encoding.UTF8.GetByteCount(testValue);
- // IncrBy操作
- sw.Restart();
- redis.IncrBy("counter:freeredis", 1);
- sw.Stop();
- metrics.IncrByTimeMs = sw.ElapsedMilliseconds;
- // 读取操作
- sw.Restart();
- var value = redis.Get("counter:freeredis");
- sw.Stop();
- metrics.ReadTimeMs = sw.ElapsedMilliseconds;
- metrics.IsSuccess = true;
- Interlocked.Increment(ref successCount);
- }
- catch (Exception ex)
- {
- metrics.IsSuccess = false;
- metrics.ErrorMessage = ex.Message;
- Interlocked.Increment(ref failureCount);
- string message = $"{ex.Message}\n{ex.StackTrace}";
- NotifyCore.Notify(new NifyMessage
- {
- message = message,
- priority = NifyMessagePriority.high,
- tags = ["red_circle"]
- });
- new LoggerLibrary("Feature").Info(message).SaveAsync();
- }
- finally
- {
- metricsQueue.Enqueue(metrics);
- Interlocked.Increment(ref totalRequests);
- }
- }
- }, cts.Token));
- }
- await Task.Delay(TimeSpan.FromSeconds(durationSeconds));
- cts.Cancel();
- try
- {
- await Task.WhenAll(tasks);
- }
- catch (OperationCanceledException)
- {
- // 预期的取消异常
- }
- watch.Stop();
- var elapsedMs = watch.ElapsedMilliseconds;
- var qps = totalRequests * 1000.0 / elapsedMs;
- var metrics = metricsQueue.ToList();
- var writeStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.WriteTimeMs);
- var incrByStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.IncrByTimeMs);
- var readStats = RedisOperationMetrics.CalculateStatistics(metrics, m => m.ReadTimeMs);
- var resultData = new Dictionary<string, object>
- {
- ["ConcurrentThreads"] = thread,
- ["DurationSeconds"] = durationSeconds,
- ["TotalTimeMs"] = elapsedMs,
- ["TotalRequests"] = totalRequests,
- ["SuccessCount"] = successCount,
- ["FailureCount"] = failureCount,
- ["QPS"] = Math.Round(qps, 2),
- ["SuccessRate"] = Math.Round((double)successCount / totalRequests * 100, 2),
- ["RedisMetrics"] = new
- {
- Write = writeStats,
- IncrBy = incrByStats,
- Read = readStats
- }
- };
- await performanceLogger.LogPerformanceResult("FreeRedis", resultData);
- return new APIResult(resultData);
- }
- }
- public class RedisPerformanceLogger
- {
- private readonly LoggerLibrary _logger;
- private const string LoggerName = "RedisPerformance";
- public RedisPerformanceLogger()
- {
- _logger = new LoggerLibrary(LoggerName);
- }
- public async Task LogPerformanceResult(string clientType, Dictionary<string, object> metrics)
- {
- var logMessage = new StringBuilder();
- logMessage.AppendLine($"Redis Performance Test Result - {clientType}");
- logMessage.AppendLine($"DateTime: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
- foreach (var kvp in metrics)
- {
- logMessage.AppendLine($"{kvp.Key}: {JsonSerializer.Serialize(kvp.Value, new JsonSerializerOptions
- {
- WriteIndented = true
- })}");
- }
- await _logger.Info(logMessage.ToString()).SaveAsync();
- }
- }
- public class RedisOperationMetrics
- {
- public long WriteTimeMs { get; set; }
- public long IncrByTimeMs { get; set; }
- public long ReadTimeMs { get; set; }
- public DateTime OperationTime { get; set; } = DateTime.Now;
- public string OperationType { get; set; }
- public bool IsSuccess { get; set; }
- public string ErrorMessage { get; set; }
- public int RetryCount { get; set; }
- public long KeySize { get; set; }
- public long ValueSize { get; set; }
- public static double CalculatePercentile(List<long> times, double percentile)
- {
- if (times == null || times.Count == 0) return 0;
- var sortedTimes = times.OrderBy(t => t).ToList();
- var index = (int)Math.Ceiling(percentile / 100.0 * sortedTimes.Count) - 1;
- return sortedTimes[Math.Max(0, index)];
- }
- public static OperationStatistics CalculateStatistics(IEnumerable<RedisOperationMetrics> metrics, Func<RedisOperationMetrics, long> timeSelector)
- {
- var times = metrics.Select(timeSelector).ToList();
- return new OperationStatistics
- {
- Average = times.Any() ? Math.Round(times.Average(), 2) : 0,
- Median = CalculatePercentile(times, 50),
- P95 = CalculatePercentile(times, 95),
- P99 = CalculatePercentile(times, 99),
- Max = times.Any() ? times.Max() : 0,
- Min = times.Any() ? times.Min() : 0,
- Count = times.Count,
- TotalTime = times.Sum()
- };
- }
- }
- public class OperationStatistics
- {
- public double Average { get; set; }
- public double Median { get; set; }
- public double P95 { get; set; }
- public double P99 { get; set; }
- public long Max { get; set; }
- public long Min { get; set; }
- public int Count { get; set; }
- public long TotalTime { get; set; }
- }
- }
|