using StackExchange.Redis;
using System.Collections.Concurrent;
using System.Configuration;
namespace Client.Utils
{
/// <summary>
/// 对于Redis集群,由于节点分布在不同的服务器上,查询数据需要遍历所有主节点。
/// </summary>
internal class RedisHelper : IDisposable
{
private readonly ConnectionMultiplexer _redis;
private readonly IDatabase _db;
private readonly IServer _server;
private bool _disposed = false;
private static readonly string connectionString = ConfigurationManager.AppSettings["RedisConnect"] ?? throw new InvalidOperationException("RedisConnect is not configured.");
public RedisHelper()
{
try
{
_redis = ConnectionMultiplexer.Connect(connectionString);
_db = _redis.GetDatabase();
_server = _redis.GetServer(_redis.GetEndPoints()[0]);
}
catch (Exception ex)
{
Logger.Error($"Redis连接异常:{ex.Message}");
}
}
/// <summary>
/// 集群读取所有节点key:使用 SCAN 命令安全地获取所有键
/// </summary>
public List<string> GetAllKeys(string zones, int pageSize = 500)
{
var allKeys = new HashSet<string>();
var endpoints = _redis.GetEndPoints();
foreach (var endpoint in endpoints)
{
var server = _redis.GetServer(endpoint);
if (server.IsConnected)
{
// 只处理主节点
if (server.ServerType == ServerType.Cluster)
{
foreach (var item in zones.Split(","))
{
foreach (var key in server.Keys(pattern: $"{item}*:AlarmData", pageSize: pageSize))
{
//去重
allKeys.Add(key);
}
}
}
}
}
return allKeys.ToList();
}
/// <summary>
/// 批量获取 Hash 数据(性能优化)
/// </summary>
public async Task<ConcurrentDictionary<string, HashData>> GetHashesBatchAsync(IEnumerable<string> keys)
{
var result = new ConcurrentDictionary<string, HashData>();
try
{
var tasks = new List<Task>();
foreach (var key in keys)
{
tasks.Add(Task.Run(async () =>
{
var hashEntries = await _db.HashGetAllAsync(key);
var hashDict = new ConcurrentDictionary<string, string>();
foreach (var entry in hashEntries)
{
hashDict[entry.Name] = entry.Value;
}
result[key] = new HashData
{
Key = key,
Fields = hashDict,
FieldCount = hashDict.Count
};
}));
}
await Task.WhenAll(tasks);
return result;
}
catch (Exception ex)
{
Logger.Error($"Redis报警数据读取异常:{ex.Message}");
return result;
}
}
public void Dispose()
{
if (!_disposed)
{
_redis?.Close();
_redis?.Dispose();
_disposed = true;
}
}
}
public class HashData
{
public RedisKey Key { get; set; }
public ConcurrentDictionary<string, string> Fields { get; set; }
public int FieldCount { get; set; }
public TimeSpan? TTL { get; set; }
}
}
注意对于集群Redis,数据分布在不同的主节点下,因此单一读取某个节点会导致数据读取不全的情况;
&spm=1001.2101.3001.5002&articleId=151558557&d=1&t=3&u=b5d3bdba4e0744c08b29b591b44885e3)
1767

被折叠的 条评论
为什么被折叠?



