使用客户端TTL;

可用率使用最近10次扫描结果来统计;
This commit is contained in:
陈国伟 2021-06-17 13:18:45 +08:00
parent 4ad3323314
commit 3c2a4a0dfb
10 changed files with 64 additions and 105 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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;
}
}
}

View File

@ -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();
}
}
}
}

View File

@ -1,6 +1,7 @@
{
"Dns": {
"UpStream": "114.114.114.114"
"UpStream": "114.114.114.114",
"GithubTTL": "00.10.00"
},
"Github": {
"ScanAllInterval": "02:00:00", //

View File

@ -4,7 +4,7 @@ github定制版的dns服务解析访问github最快的ip
### 加速原理
* 使用github公开的ip范围扫描所有可用的ip
* 轮询检测并统计可用ip的访问成功率与访问耗时
* 拦截dns访问github时服务端模拟TTL返回最优ip
* 拦截dns访问github时返回最优ip
### 使用说明
在局域网服务器(没有就使用本机)运行本程序将网络连接的dns设置为程序运行的机器的ip。