Browse Source

fix: 原 Redis 框架存在超时问题,查询资料发现改框架在高并发情况下表现不佳,更改使用 FreeRedis 框架

master
fajiao 2 years ago
parent
commit
4ba4fd2d03
  1. 29
      Cis.Application/Cis.Application.xml
  2. 4
      Cis.Application/Cm/Service/CmMarkLabelService.cs
  3. 65
      Cis.Application/Core/Center/CameraDataCenter.cs
  4. 36
      Cis.Application/Core/Component/CameraSDK/CameraSdkServer.cs
  5. 29
      Cis.Application/Core/Component/CameraSDK/ICameraSdkServer.cs
  6. 21
      Cis.Application/Core/Component/MarkSeacher/MarkSearcherServer.cs
  7. 7
      Cis.Core/Cache/CacheSetup.cs
  8. 2
      Cis.Core/Cache/SqlSugarCache.cs
  9. 4
      Cis.Core/Cis.Core.csproj
  10. 2
      Cis.Core/CoreConfig.json

29
Cis.Application/Cis.Application.xml

@ -416,19 +416,40 @@
<param name="ip"></param>
<returns></returns>
</member>
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.GetPtzInfoById(System.String,EC.Helper.CameraSDK.PtzInfo@)">
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.GetPtzInfoByIp(System.String)">
<summary>
获取 ptz
</summary>
<param name="cameraId"></param>
<param name="ptzInfo"></param>
<param name="ip"></param>
<returns></returns>
</member>
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.GetPtzInfoByIp(System.String,EC.Helper.CameraSDK.PtzInfo@)">
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.GetPtzInfoByIpAsync(System.String)">
<summary>
获取 ptz
</summary>
<param name="ip"></param>
<returns></returns>
</member>
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.TryGetPtzInfoByIp(System.String,EC.Helper.CameraSDK.PtzInfo@)">
<summary>
获取 ptz
</summary>
<param name="ip"></param>
<param name="ptzInfo"></param>
<returns></returns>
</member>
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.GetPtzInfoByIdAsync(System.String)">
<summary>
获取 ptz
</summary>
<param name="cameraId"></param>
<returns></returns>
</member>
<member name="M:Cis.Application.Core.Component.PtzServer.ICameraSdkServer.TryGetPtzInfoById(System.String,EC.Helper.CameraSDK.PtzInfo@)">
<summary>
获取 ptz
</summary>
<param name="cameraId"></param>
<param name="ptzInfo"></param>
<returns></returns>
</member>

4
Cis.Application/Cm/Service/CmMarkLabelService.cs

@ -26,7 +26,7 @@ public class CmMarkLabelService : IDynamicApiController, ITransient
[HttpPost]
public async Task<bool> Add([FromForm] CmMarkLabel entity)
{
bool ret = _cameraSdk.GetPtzInfoById(entity.CbCameraId.ToString(), out PtzInfo ptzInfo);
bool ret = _cameraSdk.TryGetPtzInfoById(entity.CbCameraId.ToString(), out PtzInfo ptzInfo);
if (!ret) return false;
entity.PanPosition = ptzInfo.Pan;
entity.TiltPosition = ptzInfo.Tilt;
@ -37,7 +37,7 @@ public class CmMarkLabelService : IDynamicApiController, ITransient
[HttpPost]
public async Task<long> AddReturnId([FromForm] CmMarkLabel entity)
{
bool ret = _cameraSdk.GetPtzInfoById(entity.CbCameraId.ToString(), out PtzInfo ptzInfo);
bool ret = _cameraSdk.TryGetPtzInfoById(entity.CbCameraId.ToString(), out PtzInfo ptzInfo);
if (!ret) return 0;
entity.PanPosition = ptzInfo.Pan;
entity.TiltPosition = ptzInfo.Tilt;

65
Cis.Application/Core/Center/CameraDataCenter.cs

@ -1,8 +1,8 @@
using Cis.Application.Core.Component.MarkSeacher;
using Cis.Application.Core.Component.PtzServer;
using EC.Helper.CameraSDK;
using FreeRedis;
using StackExchange.Profiling.Internal;
using StackExchange.Redis;
using System.Collections.Concurrent;
namespace Cis.Application.Core;
@ -11,7 +11,7 @@ public class CameraDataCenter : ISingleton
{
#region Attr
private readonly IDatabase _cache;
private readonly RedisClient _cache;
private readonly CameraDataOptions _options;
private readonly ICameraSdkServer _cameraSdkServer;
private readonly IMarkSearcherServer _markSearcherServer;
@ -25,7 +25,7 @@ public class CameraDataCenter : ISingleton
#endregion Attr
public CameraDataCenter(
IDatabase cache,
RedisClient cache,
ICameraSdkServer cameraSdkServer,
IMarkSearcherServer markSearcherServer
)
@ -49,11 +49,11 @@ public class CameraDataCenter : ISingleton
private void InitThread()
{
// 初始化 CameraPtzThread
RefreshCameraPtzThread = new Thread(() =>
RefreshCameraPtzThread = new Thread(async () =>
{
while (true)
{
RefreshCameraPtzInfos();
await RefreshCameraPtzInfos();
Thread.Sleep(_options.CameraPtz.LoopInterval);
}
})
@ -63,20 +63,20 @@ public class CameraDataCenter : ISingleton
// 启动 CameraPtzThread
RefreshCameraPtzThread.Start();
// 初始化 MarkSearcherThread
RefreshMarkSearcherThread = new Thread(() =>
{
while (true)
{
RefreshMarkSearchers();
Thread.Sleep(_options.MarkSearcher.LoopInterval);
}
})
{
IsBackground = true// 设置后台线程
};
// 启动 MarkSearcherThread
RefreshMarkSearcherThread.Start();
//// 初始化 MarkSearcherThread
//RefreshMarkSearcherThread = new Thread(async () =>
//{
// while (true)
// {
// await RefreshMarkSearchers();
// Thread.Sleep(_options.MarkSearcher.LoopInterval);
// }
//})
//{
// IsBackground = true// 设置后台线程
//};
//// 启动 MarkSearcherThread
//RefreshMarkSearcherThread.Start();
}
/// <summary>
@ -84,13 +84,12 @@ public class CameraDataCenter : ISingleton
/// 有待改善,应设置超时计数机制
/// https://blog.csdn.net/qq_28368039/article/details/118597396
/// </summary>
private async void RefreshCameraPtzInfos()
private async Task RefreshCameraPtzInfos()
{
HashEntry[] entries = _cache.HashGetAll(CacheInfo.CameraIpCounts);
string[] cameraIpList = await _cache.HKeysAsync(CacheInfo.CameraIpCounts);
List<Task> tasks = new();
foreach (HashEntry entry in entries)
foreach (string cameraIp in cameraIpList)
{
string cameraIp = entry.Name;
tasks.Add(RefreshCameraPtzInfo(cameraIp));
}
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(_options.CameraPtz.Timeout));
@ -103,21 +102,20 @@ public class CameraDataCenter : ISingleton
/// <returns></returns>
private async Task RefreshCameraPtzInfo(string cameraIp)
{
bool ret = _cameraSdkServer.GetPtzInfoByIp(cameraIp, out PtzInfo ptzInfo);
bool ret = _cameraSdkServer.TryGetPtzInfoByIp(cameraIp, out PtzInfo ptzInfo);
if (!ret) return;
await _cache.HashSetAsync(CacheInfo.CameraPtzInfos, cameraIp, ptzInfo.ToJson());
await _cache.HSetAsync(CacheInfo.CameraPtzInfos, cameraIp, ptzInfo.ToJson());
}
/// <summary>
/// 刷新所有 markSearcher
/// </summary>
private async void RefreshMarkSearchers()
private async Task RefreshMarkSearchers()
{
HashEntry[] entries = _cache.HashGetAll(CacheInfo.CameraId2Ip);
string[] cameraIdList = await _cache.HKeysAsync(CacheInfo.CameraId2Ip);
List<Task> tasks = new();
foreach (HashEntry entry in entries)
foreach (string cameraId in cameraIdList)
{
string cameraId = entry.Name;
tasks.Add(RefreshMarkSearcher(cameraId.ToLong()));
}
await Task.WhenAny(Task.WhenAll(tasks), Task.Delay(_options.CameraPtz.Timeout));
@ -132,10 +130,11 @@ public class CameraDataCenter : ISingleton
{
MarkSearcherBase markSearcher = _markSearcherServer.GetSearcher(cameraId);
if (markSearcher == null) return;
string cameraIp = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId);
RedisValue value = _cache.HashGet(CacheInfo.CameraPtzInfos, cameraIp);
if (!value.HasValue) return;
PtzInfo ptzInfo = value.ToString().FromJson<PtzInfo>();
string cameraIp = await _cache.HGetAsync(CacheInfo.CameraId2Ip, cameraId.ToString());
string ptzInfoStr = await _cache.HGetAsync(CacheInfo.CameraPtzInfos, cameraIp);
if (string.IsNullOrEmpty(ptzInfoStr)) return;
PtzInfo ptzInfo = ptzInfoStr.ToObject<PtzInfo>();
if (ptzInfo == null) return;
markSearcher.UpdateCameraCalcParams(ptzInfo);
List<MarkLabelCalcResult> resultList = await markSearcher.SearchAsync();
SearchResultListDict[cameraId] = resultList;

36
Cis.Application/Core/Component/CameraSDK/CameraSdkServer.cs

@ -1,6 +1,6 @@
using Cis.Application.Core.Component.PtzServer;
using EC.Helper.CameraSDK;
using StackExchange.Redis;
using FreeRedis;
using System.Collections.Concurrent;
namespace Cis.Application.Core.Component.CameraSDK;
@ -12,7 +12,7 @@ public class CameraSdkServer : ICameraSdkServer, ISingleton
{
#region Attr
private readonly IDatabase _cache;
private readonly RedisClient _cache;
/// <summary>
/// {ip, ICameraSDK}
@ -21,7 +21,7 @@ public class CameraSdkServer : ICameraSdkServer, ISingleton
#endregion Attr
public CameraSdkServer(IDatabase cache)
public CameraSdkServer(RedisClient cache)
{
_cache = cache;
}
@ -54,20 +54,38 @@ public class CameraSdkServer : ICameraSdkServer, ISingleton
#region Main Method
public bool GetPtzInfoById(string cameraId, out PtzInfo ptzInfo)
public PtzInfo GetPtzInfoByIp(string ip)
{
RedisValue value = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId);
if (!value.HasValue) { ptzInfo = PtzInfo.Default; return false; }
string ip = value.ToString();
return GetPtzInfoByIp(ip, out ptzInfo);
bool ret = CameraSdkDict.TryGetValue(ip, out ICameraSDK cameraSDK);
if (!ret) return PtzInfo.Default;
return cameraSDK.GetPtzInfo();
}
public bool GetPtzInfoByIp(string ip, out PtzInfo ptzInfo)
public async Task<PtzInfo> GetPtzInfoByIpAsync(string ip)
{
return await Task.Run(() => GetPtzInfoByIp(ip));
}
public bool TryGetPtzInfoByIp(string ip, out PtzInfo ptzInfo)
{
bool ret = CameraSdkDict.TryGetValue(ip, out ICameraSDK cameraSDK);
if (!ret) { ptzInfo = PtzInfo.Default; return false; }
return cameraSDK.TryGetPtzInfo(out ptzInfo);
}
public async Task<PtzInfo> GetPtzInfoByIdAsync(string cameraId)
{
string ip = await _cache.HGetAsync(CacheInfo.CameraId2Ip, cameraId);
if (string.IsNullOrEmpty(ip)) return PtzInfo.Default;
return GetPtzInfoByIp(ip);
}
public bool TryGetPtzInfoById(string cameraId, out PtzInfo ptzInfo)
{
string ip = _cache.HGet(CacheInfo.CameraId2Ip, cameraId);
if (string.IsNullOrEmpty(ip)) { ptzInfo = PtzInfo.Default; return false; }
return TryGetPtzInfoByIp(ip, out ptzInfo);
}
#endregion Main Method
}

29
Cis.Application/Core/Component/CameraSDK/ICameraSdkServer.cs

@ -37,18 +37,39 @@ public interface ICameraSdkServer
/// <summary>
/// 获取 ptz
/// </summary>
/// <param name="cameraId"></param>
/// <param name="ptzInfo"></param>
/// <param name="ip"></param>
/// <returns></returns>
public bool GetPtzInfoById(string cameraId, out PtzInfo ptzInfo);
public PtzInfo GetPtzInfoByIp(string ip);
/// <summary>
/// 获取 ptz
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public Task<PtzInfo> GetPtzInfoByIpAsync(string ip);
/// <summary>
/// 获取 ptz
/// </summary>
/// <param name="ip"></param>
/// <param name="ptzInfo"></param>
/// <returns></returns>
public bool TryGetPtzInfoByIp(string ip, out PtzInfo ptzInfo);
/// <summary>
/// 获取 ptz
/// </summary>
/// <param name="cameraId"></param>
/// <returns></returns>
public Task<PtzInfo> GetPtzInfoByIdAsync(string cameraId);
/// <summary>
/// 获取 ptz
/// </summary>
/// <param name="cameraId"></param>
/// <param name="ptzInfo"></param>
/// <returns></returns>
public bool GetPtzInfoByIp(string ip, out PtzInfo ptzInfo);
public bool TryGetPtzInfoById(string cameraId, out PtzInfo ptzInfo);
#endregion Main Method
}

21
Cis.Application/Core/Component/MarkSeacher/MarkSearcherServer.cs

@ -2,7 +2,7 @@
using Cis.Application.Cm;
using Cis.Application.Core.Component.PtzServer;
using EC.Helper.CameraSDK;
using StackExchange.Redis;
using FreeRedis;
using System.Collections.Concurrent;
namespace Cis.Application.Core.Component.MarkSeacher;
@ -17,7 +17,7 @@ public class MarkSearcherServer : IMarkSearcherServer, ISingleton
private readonly SqlSugarRepository<CbCamera> _cbCameraRep;
private readonly SqlSugarRepository<CbCameraParams> _cbCameraParamsRep;
private readonly SqlSugarRepository<CmMarkLabel> _cmMarkLableRep;
private readonly IDatabase _cache;
private readonly RedisClient _cache;
private readonly ICameraSdkServer _cameraSdkServer;
@ -34,7 +34,7 @@ public class MarkSearcherServer : IMarkSearcherServer, ISingleton
#endregion Attr
public MarkSearcherServer(
IDatabase cache,
RedisClient cache,
ICameraSdkServer cameraSdkServer
)
{
@ -89,7 +89,7 @@ public class MarkSearcherServer : IMarkSearcherServer, ISingleton
if (!ret) return false;
}
}
ret = _cameraSdkServer.GetPtzInfoByIp(cbCamera.Ip, out PtzInfo ptzInfo);
ret = _cameraSdkServer.TryGetPtzInfoByIp(cbCamera.Ip, out PtzInfo ptzInfo);
if (!ret) return false;
// 创建相机计算参数
@ -117,8 +117,8 @@ public class MarkSearcherServer : IMarkSearcherServer, ISingleton
ret = MarkSearcherDict.TryAdd(cameraId, markSearcher);
if (!ret) return false;
// 记录缓存
_cache.HashSet(CacheInfo.CameraId2Ip, cbCamera.Id, cbCamera.Ip);
_cache.HashIncrement(CacheInfo.CameraIpCounts, cbCamera.Ip);
_cache.HSet(CacheInfo.CameraId2Ip, cbCamera.Id.ToString(), cbCamera.Ip);
_cache.HIncrBy(CacheInfo.CameraIpCounts, cbCamera.Ip, 1);
return true;
}
@ -144,11 +144,10 @@ public class MarkSearcherServer : IMarkSearcherServer, ISingleton
{
bool ret = MarkSearcherDict.TryRemove(cameraId, out _);
if (!ret) return false;
RedisValue value = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId);
if (!value.HasValue) return false;
string cameraIp = (string)value;
_cache.HashDelete(CacheInfo.CameraId2Ip, cameraId);
_cache.HashDecrement(CacheInfo.CameraIpCounts, cameraIp);
string cameraIp = _cache.HGet(CacheInfo.CameraId2Ip, cameraId.ToString());
if (string.IsNullOrEmpty(cameraIp)) return false;
_cache.HDel(CacheInfo.CameraId2Ip, cameraId.ToString());
_cache.HIncrBy(CacheInfo.CameraIpCounts, cameraIp, -1);
//int ipCount = (int)_cache.HashGet(CacheInfo.CameraIpCounts, cameraIp);
//if (ipCount <= 0)
//{

7
Cis.Core/Cache/CacheSetup.cs

@ -1,4 +1,4 @@
using StackExchange.Redis;
using FreeRedis;
namespace Cis.Core;
@ -10,11 +10,10 @@ public static class CacheSetup
/// <param name="services"></param>
public static void AddCache(this IServiceCollection services)
{
services.AddSingleton<IDatabase>(options =>
services.AddSingleton<RedisClient>(options =>
{
var redisOptions = App.GetOptions<RedisOptions>();
ConnectionMultiplexer multiplexer = ConnectionMultiplexer.Connect(redisOptions.ConnectionString);
IDatabase cache = multiplexer.GetDatabase();
RedisClient cache = new(redisOptions.ConnectionString);
return cache;
});
}

2
Cis.Core/Cache/SqlSugarCache.cs

@ -7,7 +7,7 @@ namespace Cis.Core;
/// </summary>
public class SqlSugarCache : ICacheService, ISingleton
{
private static readonly ICache _cache = NewLife.Caching.Cache.Default;
private static readonly ICache _cache = Cache.Default;
public void Add<V>(string key, V value)
{

4
Cis.Core/Cis.Core.csproj

@ -24,16 +24,16 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FreeRedis" Version="1.0.3" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.8.2.2" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.4.9" />
<PackageReference Include="Furion.Pure" Version="4.4.9" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.11" />
<PackageReference Include="NewLife.Core" Version="10.0.2022.1101" />
<PackageReference Include="SqlSugarCore" Version="5.1.3.1" />
<PackageReference Include="StackExchange.Redis" Version="2.6.80" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties coreconfig_1json__JsonSchema="https://download.stackhawk.com/hawk/jsonschema/hawkconfig.json" /></VisualStudio></ProjectExtensions>
<ProjectExtensions><VisualStudio><UserProperties coreconfig_1json__JsonSchema="https://gitee.com/dotnetchina/Furion/raw/v4/schemas/v4/furion-schema.json" /></VisualStudio></ProjectExtensions>
</Project>

2
Cis.Core/CoreConfig.json

@ -9,7 +9,7 @@
//"ConnectionString": "DataSource=./cis.db",
//"DbType": "PostgreSQL",
//"ConnectionString": "HOST=127.0.0.1;PORT=5432;USER ID=pgsql;PASSWORD=123456;DATABASE=cis;",
"EnableInitDb": true //
"EnableInitDb": false //
}
]
},

Loading…
Cancel
Save