使用客户端TTL;
可用率使用最近10次扫描结果来统计;
This commit is contained in:
parent
4ad3323314
commit
3c2a4a0dfb
@ -1,4 +1,5 @@
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace FastGithub.Dns
|
||||
{
|
||||
@ -6,5 +7,7 @@ namespace FastGithub.Dns
|
||||
sealed class DnsOptions
|
||||
{
|
||||
public IPAddress UpStream { get; set; } = IPAddress.Parse("114.114.114.114");
|
||||
|
||||
public TimeSpan GithubTTL { get; set; } = TimeSpan.FromMinutes(10d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,8 +18,7 @@ namespace FastGithub
|
||||
public static IServiceCollection AddGithubDns(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var assembly = typeof(DnsServiceCollectionExtensions).Assembly;
|
||||
return services
|
||||
.AddMemoryCache()
|
||||
return services
|
||||
.AddServiceAndOptions(assembly, configuration)
|
||||
.AddHostedService<DnsHostedService>()
|
||||
.AddGithubScanner(configuration);
|
||||
|
||||
@ -6,8 +6,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DNS" Version="6.1.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="5.0.0" />
|
||||
<PackageReference Include="DNS" Version="6.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@ -2,12 +2,11 @@
|
||||
using DNS.Protocol;
|
||||
using DNS.Protocol.ResourceRecords;
|
||||
using FastGithub.Scanner;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -17,17 +16,16 @@ namespace FastGithub.Dns
|
||||
sealed class GithubRequestResolver : IRequestResolver
|
||||
{
|
||||
private readonly IGithubScanResults githubScanResults;
|
||||
private readonly IMemoryCache memoryCache;
|
||||
private readonly ILogger<GithubRequestResolver> logger;
|
||||
private readonly TimeSpan TTL = TimeSpan.FromMinutes(10d);
|
||||
private readonly IOptionsMonitor<DnsOptions> options;
|
||||
private readonly ILogger<GithubRequestResolver> logger;
|
||||
|
||||
public GithubRequestResolver(
|
||||
IGithubScanResults githubScanResults,
|
||||
IMemoryCache memoryCache,
|
||||
IOptionsMonitor<DnsOptions> options,
|
||||
ILogger<GithubRequestResolver> logger)
|
||||
{
|
||||
this.githubScanResults = githubScanResults;
|
||||
this.memoryCache = memoryCache;
|
||||
this.options = options;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@ -39,11 +37,12 @@ namespace FastGithub.Dns
|
||||
if (question != null && question.Type == RecordType.A)
|
||||
{
|
||||
var domain = question.Name.ToString();
|
||||
var address = this.GetGithubAddress(domain, TTL);
|
||||
var address = this.githubScanResults.FindBestAddress(domain);
|
||||
|
||||
if (address != null)
|
||||
{
|
||||
var record = new IPAddressResourceRecord(question.Name, address);
|
||||
var ttl = this.options.CurrentValue.GithubTTL;
|
||||
var record = new IPAddressResourceRecord(question.Name, address, ttl);
|
||||
response.AnswerRecords.Add(record);
|
||||
this.logger.LogInformation(record.ToString());
|
||||
}
|
||||
@ -51,37 +50,5 @@ namespace FastGithub.Dns
|
||||
|
||||
return Task.FromResult<IResponse>(response);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模拟TTL
|
||||
/// 如果ip可用,则10分钟内返回缓存的ip,防止客户端ip频繁切换
|
||||
/// </summary>
|
||||
/// <param name="domain"></param>
|
||||
/// <param name="ttl"></param>
|
||||
/// <returns></returns>
|
||||
private IPAddress? GetGithubAddress(string domain, TimeSpan ttl)
|
||||
{
|
||||
if (domain.Contains("github", StringComparison.OrdinalIgnoreCase) == false)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var key = $"ttl:{domain}";
|
||||
if (this.memoryCache.TryGetValue<IPAddress>(key, out var address))
|
||||
{
|
||||
if (this.githubScanResults.IsAvailable(domain, address))
|
||||
{
|
||||
return address;
|
||||
}
|
||||
this.memoryCache.Remove(key);
|
||||
}
|
||||
|
||||
address = this.githubScanResults.FindBestAddress(domain);
|
||||
if (address != null)
|
||||
{
|
||||
this.memoryCache.Set(key, address, ttl);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,7 +8,8 @@ namespace FastGithub.Scanner
|
||||
private record Github(
|
||||
string Domain,
|
||||
IPAddress Address,
|
||||
double SuccessRate,
|
||||
bool Available,
|
||||
double AvailableRate,
|
||||
TimeSpan AvgElapsed);
|
||||
|
||||
/// <summary>
|
||||
@ -58,8 +59,9 @@ namespace FastGithub.Scanner
|
||||
return new Github(
|
||||
this.Domain,
|
||||
this.Address,
|
||||
this.History.GetSuccessRate(),
|
||||
this.History.GetAvgElapsed()
|
||||
this.Available,
|
||||
this.History.AvailableRate,
|
||||
this.History.AvgElapsed
|
||||
).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ namespace FastGithub.Scanner
|
||||
lock (this.syncRoot)
|
||||
{
|
||||
return this.contextList
|
||||
.Where(item => item.Available && item.Domain == domain)
|
||||
.OrderByDescending(item => item.History.GetSuccessRate())
|
||||
.ThenBy(item => item.History.GetAvgElapsed())
|
||||
.Where(item => item.Domain == domain && item.History.AvailableRate > 0d)
|
||||
.OrderByDescending(item => item.History.AvailableRate)
|
||||
.ThenBy(item => item.History.AvgElapsed)
|
||||
.Select(item => item.Address)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
@ -1,74 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace FastGithub.Scanner
|
||||
{
|
||||
sealed class GithubContextHistory
|
||||
{
|
||||
private record ScanLog(DateTime ScanTime, TimeSpan Elapsed);
|
||||
private const int MAX_LOG_COUNT = 10;
|
||||
private record ScanLog(bool Available, TimeSpan Elapsed);
|
||||
|
||||
private readonly Queue<ScanLog> successLogs = new();
|
||||
private readonly Queue<ScanLog> scanLogs = new();
|
||||
|
||||
private readonly Queue<ScanLog> failureLogs = new();
|
||||
|
||||
private static readonly TimeSpan keepLogsTimeSpan = TimeSpan.FromHours(2d);
|
||||
|
||||
|
||||
public void AddSuccess(TimeSpan elapsed)
|
||||
/// <summary>
|
||||
/// 获取可用率
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double AvailableRate
|
||||
{
|
||||
ClearStaleData(this.successLogs, keepLogsTimeSpan);
|
||||
this.successLogs.Enqueue(new ScanLog(DateTime.Now, elapsed));
|
||||
}
|
||||
|
||||
public void AddFailure()
|
||||
{
|
||||
ClearStaleData(this.failureLogs, keepLogsTimeSpan);
|
||||
this.failureLogs.Enqueue(new ScanLog(DateTime.Now, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
static void ClearStaleData(Queue<ScanLog> logs, TimeSpan timeSpan)
|
||||
{
|
||||
var time = DateTime.Now.Subtract(timeSpan);
|
||||
while (logs.TryPeek(out var log))
|
||||
get
|
||||
{
|
||||
if (log.ScanTime < time)
|
||||
if (this.scanLogs.Count == 0)
|
||||
{
|
||||
logs.TryDequeue(out _);
|
||||
return 0d;
|
||||
}
|
||||
break;
|
||||
|
||||
var availableCount = this.scanLogs.Count(item => item.Available);
|
||||
return (double)availableCount / this.scanLogs.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取成功率
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public double GetSuccessRate()
|
||||
{
|
||||
var successCount = this.successLogs.Count;
|
||||
var totalScanCount = successCount + this.failureLogs.Count;
|
||||
return totalScanCount == 0 ? 0d : (double)successCount / totalScanCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取平均耗时
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TimeSpan GetAvgElapsed()
|
||||
public TimeSpan AvgElapsed
|
||||
{
|
||||
var totalScanCount = this.successLogs.Count + this.failureLogs.Count;
|
||||
if (totalScanCount == 0)
|
||||
get
|
||||
{
|
||||
return TimeSpan.MaxValue;
|
||||
}
|
||||
var availableCount = 0;
|
||||
var availableElapsed = TimeSpan.Zero;
|
||||
|
||||
var totalSuccessElapsed = TimeSpan.Zero;
|
||||
foreach (var item in this.successLogs)
|
||||
foreach (var item in this.scanLogs)
|
||||
{
|
||||
if (item.Available == true)
|
||||
{
|
||||
availableCount += 1;
|
||||
availableElapsed = availableElapsed.Add(item.Elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
return availableCount == 0 ? TimeSpan.MaxValue : availableElapsed / availableCount;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(bool available, TimeSpan elapsed)
|
||||
{
|
||||
this.scanLogs.Enqueue(new ScanLog(available, elapsed));
|
||||
while (this.scanLogs.Count > MAX_LOG_COUNT)
|
||||
{
|
||||
totalSuccessElapsed = totalSuccessElapsed.Add(item.Elapsed);
|
||||
this.scanLogs.Dequeue();
|
||||
}
|
||||
|
||||
return totalSuccessElapsed / totalScanCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,16 +28,12 @@ namespace FastGithub.Scanner.Middlewares
|
||||
finally
|
||||
{
|
||||
stopwatch.Stop();
|
||||
context.History.Add(context.Available, stopwatch.Elapsed);
|
||||
|
||||
if (context.Available)
|
||||
if (context.History.AvailableRate > 0d)
|
||||
{
|
||||
context.History.AddSuccess(stopwatch.Elapsed);
|
||||
this.logger.LogInformation(context.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
context.History.AddFailure();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"Dns": {
|
||||
"UpStream": "114.114.114.114"
|
||||
"UpStream": "114.114.114.114",
|
||||
"GithubTTL": "00.10.00"
|
||||
},
|
||||
"Github": {
|
||||
"ScanAllInterval": "02:00:00", // 完整扫描时间间隔
|
||||
|
||||
Loading…
Reference in New Issue
Block a user