fix(link): ride out short path blackouts: 30s handshake, 180s idle limit, 90s keepalive, faster probe reconnect [CI]
This commit is contained in:
1 parent
be04045c8c
commit
0873acf66a
3 files changed
+20
-9
No files matched your search
@@ -78,8 +78,9 @@ public sealed class PeerHub
|
||||
{
|
||||
private const int DedupeWindow = 1024;
|
||||
|
||||
/// <summary>超过这么久没有收到 Probe 的任何帧就认为会话已死(Probe 每 30 秒至少发一次时钟同步)。</summary>
|
||||
private static readonly TimeSpan IdleLimit = TimeSpan.FromSeconds(75);
|
||||
/// <summary>超过这么久没有收到 Probe 的任何帧就认为会话已死(Probe 每 30 秒至少发一次时钟同步)。
|
||||
/// 要比线路可能的中断长得多:差的线路上几十秒甚至一两分钟的黑洞时有发生(TCP RTT 能到 30 秒),75 秒就关会话会把一次中断变成几分钟的数据空白(要重新握手,而握手在差线路上也慢)。</summary>
|
||||
private static readonly TimeSpan IdleLimit = TimeSpan.FromSeconds(180);
|
||||
|
||||
private readonly RpcRouter<PeerContext> _router;
|
||||
private readonly SessionRegistry _sessions;
|
||||
|
||||
@@ -29,7 +29,8 @@ public sealed class PeerListenerOptions
|
||||
|
||||
public int MaxSessions { get; init; } = 8;
|
||||
|
||||
public TimeSpan HandshakeTimeout { get; init; } = TimeSpan.FromSeconds(10);
|
||||
/// <summary>敲门、TLS、挑战应答整个握手的上限。线路差的时候(RTT 好几秒、还丢包)握手本来就要很久,10 秒做不完就会一直连不上;敲门已经挡住了不认识的连接,放宽不会放大被占连接的风险。</summary>
|
||||
public TimeSpan HandshakeTimeout { get; init; } = PeerTimings.Handshake;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -209,7 +210,8 @@ public sealed class PeerListener
|
||||
}
|
||||
|
||||
/// <summary>发起点对点会话(Probe 一侧):按 SPKI 指纹固定对端证书,用身份私钥签名,派生同样的数据面凭据。</summary>
|
||||
/// <summary>点对点会话的套接字:开启 TCP keepalive(空闲 15 秒后每 5 秒探测,连续 3 次无响应就断开,约 30 秒),主机丢失或路径被切断时连接不会一直挂着。</summary>
|
||||
/// <summary>点对点会话的套接字:开启 TCP keepalive(空闲 30 秒后每 10 秒探测,连续 6 次无响应才断开,约 90 秒),主机真的没了的时候连接不会一直挂着;
|
||||
/// 但线路短暂中断(几十秒的黑洞)不能把会话杀掉——线路中断本来就是要测的东西,会话得扛过去,恢复之后接着测。</summary>
|
||||
internal static class PeerSockets
|
||||
{
|
||||
public static void EnableKeepAlive(Socket socket)
|
||||
@@ -217,9 +219,9 @@ internal static class PeerSockets
|
||||
try
|
||||
{
|
||||
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 15);
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 5);
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 3);
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 30);
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 10);
|
||||
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, 6);
|
||||
}
|
||||
catch (Exception ex) when (ex is SocketException or ArgumentException or PlatformNotSupportedException)
|
||||
{
|
||||
@@ -228,6 +230,13 @@ internal static class PeerSockets
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>点对点会话的时间常数,Probe 和 Agent 两侧共用。</summary>
|
||||
public static class PeerTimings
|
||||
{
|
||||
/// <summary>建立会话(连接、敲门、TLS、挑战应答)的总时限。</summary>
|
||||
public static readonly TimeSpan Handshake = TimeSpan.FromSeconds(30);
|
||||
}
|
||||
|
||||
public static class PeerConnector
|
||||
{
|
||||
public static async Task<(PeerSessionInfo Info, TlsFrameTransport Transport)> ConnectAsync(
|
||||
@@ -240,7 +249,7 @@ public static class PeerConnector
|
||||
PeerSockets.EnableKeepAlive(client.Client);
|
||||
try
|
||||
{
|
||||
using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(10), time);
|
||||
using var timeout = new CancellationTokenSource(PeerTimings.Handshake, time);
|
||||
using CancellationTokenSource linked = CancellationTokenSource.CreateLinkedTokenSource(ct, timeout.Token);
|
||||
await client.ConnectAsync(host, port, linked.Token);
|
||||
Stream stream = client.GetStream();
|
||||
|
||||
@@ -47,7 +47,8 @@ public sealed class AgentConnection
|
||||
|
||||
public async Task RunAsync(CancellationToken ct)
|
||||
{
|
||||
var backoff = new Backoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(20));
|
||||
// 重连的间隔别拉太长:每次尝试本来就要等好几秒(握手上限 30 秒),线路一恢复要尽快接上;带抖动,不会和别的节点撞在一起
|
||||
var backoff = new Backoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(8));
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
|
||||
Reference in new issue
Block a user