准备使用 .NET 8 引入的 Frozen Collections,查找速度比 HashSet 还要快,相关链接:
再结合 AlternateLookup<ReadOnlySpan<char>>
,参考博文 Alternate Lookup for Dictionary and HashSet in .NET 9
采用 FrozenSet + AlternateLookup 的方法实现并上线了
实现一个 HostedService,在应用启动时与定时周期内从 redis 读取 IP 黑名单数据,创建新的 FrozenSet 实例
public async Task<FrozenSet<string>> GetBlockedIpSetAsync(string appName)
{
string key = CacheKeyManager.IpBlockList(appName);
return [.. (await redisDatabase.Database.SortedSetRangeByRankAsync(key)).Select(x => x.ToString())];
}
并基于这个 FrozenSet 实例创建 AlternateLookup
internal static FrozenSet<string>.AlternateLookup<ReadOnlySpan<char>>? BlockedIpLookup { get; private set; }
public static void BuildBlacklists(FrozenSet<string> blockbedIpSet)
{
BlockedIpLookup = blockbedIpSet.GetAlternateLookup<ReadOnlySpan<char>>();
}
然后通过 AlternateLookup 的 Contains 检查黑名单中是否存在对应的 IP
public static bool IsIpBlocked(string appName, string ip)
{
return appName switch
{
BlogList.Name => BlogList.BlockedIpLookup?.Contains(ip) == true,
BlogPostDetail.Name => BlogPostDetail.BlockedIpLookup?.Contains(ip) == true,
_ => throw new Exception($"The app name '{appName}' is not supported ")
};
}
我觉得用字典存应该不错
ConcurrentDictionary
需求是给定一个ip,判断其是否在黑名单中吗?
– 会长 1周前@会长: 是的
– dudu 1周前@会长: 准备用 FrozenSet + AlternateLookup
– dudu 1周前@dudu: 哦,刚才去查了下,这个结构说是比HashSet<T>查找更快,但是实例化之后不能往里添加新的元素。那如果需要把新的ip添加到黑名单还需要重新实例化吗?
– 会长 1周前@会长: 是的,通过定时任务从 redis 中读取黑名单创建新的实例
– dudu 1周前