Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 35 additions & 53 deletions core/src/SSRAG/Datory/DistributedCache.Public.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,42 +39,33 @@ public async Task<T> GetOrCreateAsync<T>(string key, Func<Task<T>> factory)

// 2. 获取或创建锁,防止缓存击穿
var lockKey = $"lock:{key}";
var semaphore = _locks.GetOrAdd(lockKey, _ => new SemaphoreSlim(1, 1));
using var _ = await _locks.LockAsync(lockKey).ConfigureAwait(false);

await semaphore.WaitAsync();
try
// 3. 再次检查本地缓存(可能在等待期间已被其他线程填充)
if (_memoryCache.TryGetValue(key, out value))
{
// 3. 再次检查本地缓存(可能在等待期间已被其他线程填充)
if (_memoryCache.TryGetValue(key, out value))
{
return value;
}

// 4. 从Redis获取

var redisValue = await StringGetAsync(key);
if (!string.IsNullOrEmpty(redisValue))
{
value = TranslateUtils.JsonDeserialize<T>(redisValue);
_memoryCache.Set(key, value, TimeSpan.FromMinutes(Constants.DefaultMemoryExpireMinutes));
return value;
}

// 5. 如果Redis中也没有,则调用工厂方法生成数据
value = await factory();
if (value == null) return default;

// 6. 同时写入本地缓存和Redis
_memoryCache.Set(key, value, TimeSpan.FromMinutes(Constants.DefaultMemoryExpireMinutes));
await StringSetAsync(key, TranslateUtils.JsonSerialize(value));

return value;
}
finally

// 4. 从Redis获取

var redisValue = await StringGetAsync(key);
if (!string.IsNullOrEmpty(redisValue))
{
semaphore.Release();
_locks.TryRemove(lockKey, out _);
value = TranslateUtils.JsonDeserialize<T>(redisValue);
_memoryCache.Set(key, value, TimeSpan.FromMinutes(Constants.DefaultMemoryExpireMinutes));
return value;
}

// 5. 如果Redis中也没有,则调用工厂方法生成数据
value = await factory();
if (value == null) return default;

// 6. 同时写入本地缓存和Redis
_memoryCache.Set(key, value, TimeSpan.FromMinutes(Constants.DefaultMemoryExpireMinutes));
await StringSetAsync(key, TranslateUtils.JsonSerialize(value));

return value;
}

public async Task RemoveAsync(string key)
Expand Down Expand Up @@ -103,33 +94,24 @@ public async Task<string> GetStringAsync(string key)

// 2. 获取或创建锁,防止缓存击穿
var lockKey = $"lock:{key}";
var semaphore = _locks.GetOrAdd(lockKey, _ => new SemaphoreSlim(1, 1));
using var _ = await _locks.LockAsync(lockKey).ConfigureAwait(false);

await semaphore.WaitAsync();
try
// 3. 再次检查本地缓存(可能在等待期间已被其他线程填充)
if (_memoryCache.TryGetValue(key, out value))
{
// 3. 再次检查本地缓存(可能在等待期间已被其他线程填充)
if (_memoryCache.TryGetValue(key, out value))
{
return value;
}

// 4. 从Redis获取
var redisValue = await StringGetAsync(key);
if (!string.IsNullOrEmpty(redisValue))
{
value = redisValue;
_memoryCache.Set(key, value, TimeSpan.FromMinutes(Constants.DefaultMemoryExpireMinutes));
return value;
}

return string.Empty;
return value;
}
finally

// 4. 从Redis获取
var redisValue = await StringGetAsync(key);
if (!string.IsNullOrEmpty(redisValue))
{
semaphore.Release();
_locks.TryRemove(lockKey, out _);
value = redisValue;
_memoryCache.Set(key, value, TimeSpan.FromMinutes(Constants.DefaultMemoryExpireMinutes));
return value;
}

return string.Empty;
}

public async Task<bool> SetStringAsync(string key, string value, int minutes = 0)
Expand Down Expand Up @@ -232,4 +214,4 @@ public async Task ClearAsync()
ClearKeys();
}
}
}
}
5 changes: 3 additions & 2 deletions core/src/SSRAG/Datory/DistributedCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Concurrent;
using System.Threading;
using System.Collections.Generic;
using AsyncKeyedLock;
using SSRAG.Datory.Utils;

namespace SSRAG.Datory
Expand All @@ -13,7 +14,7 @@ public partial class DistributedCache : IDistributedCache
private readonly string _prefix;
private readonly MemoryCache _memoryCache;
private readonly Lazy<ConnectionMultiplexer> _lazyConnection;
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new();
private static readonly AsyncKeyedLocker<string> _locks = new();

public DistributedCache(string connectionString)
{
Expand Down Expand Up @@ -41,4 +42,4 @@ public DistributedCache(string connectionString)

private ConnectionMultiplexer GetConnection() => _lazyConnection.Value;
}
}
}
1 change: 1 addition & 0 deletions core/src/SSRAG/SSRAG.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="AsyncKeyedLock" Version="8.0.0" />
<PackageReference Include="StackExchange.Redis" Version="2.8.41" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.115.5" />
<PackageReference Include="Dapper" Version="2.0.123" />
Expand Down