Tài liệu

Timing Wheel

Thời gian đọc 3 phút Gói: Nalix.Network
Trên trang này

Namespace: Nalix.Network.Internal.Time
Assembly: Nalix.Network

TimingWheel ([Injectable] internal sealed class TimingWheel : IActivatable) là một Hashed Wheel Timer rất nhẹ, theo dõi các instance IConnection đã đăng ký và ngắt những kết nối có thời gian nhàn rỗi (Clock.UnixMillisecondsNow() - conn.LastPingTime) đạt tới conn.IdleTimeoutMs (mặc định TimingWheelOptions.IdleTimeoutMs = 60,000 ms).

Nguồn mã

  • src/Nalix.Network/Internal/Time/TimingWheel.cs
  • src/Nalix.Network/Internal/Time/TimingWheelMetrics.cs
  • src/Nalix.Network/Options/TimingWheelOptions.cs

Kiến trúc Hashed Wheel

Architecture Diagram
flowchart TD
    subgraph Wheel["TimingWheelBucket[] (BucketCount = 512)"]
        B0["Bucket 0 (Doubly-Linked List + Lock)"]
        B1["Bucket 1 (Doubly-Linked List + Lock)"]
        BN["Bucket N - 1"]
    end

    subgraph Worker["Background PeriodicTimer Loop (TickDuration = 1000ms)"]
        Tick["Advance Tick & Catch-up Missed Ticks"]
        Drain["Process Current Bucket"]
        CheckVer{"task.Version == conn.TimeoutVersion?"}
        CheckRounds{"task.Rounds > 0?"}
        CheckIdle{"idleMs >= conn.IdleTimeoutMs?"}
        Disc["conn.Disconnect() + Return TimeoutTask"]
        Resched["Recompute Remaining Ticks & Re-enqueue"]
    end

    Tick --> Drain --> CheckVer
    CheckVer -->|No (Stale)| Pool["Return TimeoutTask to ObjectPool"]
    CheckVer -->|Yes| CheckRounds
    CheckRounds -->|Yes| Dec["task.Rounds-- (Stay in Bucket)"]
    CheckRounds -->|No| CheckIdle
    CheckIdle -->|Yes| Disc
    CheckIdle -->|No| Resched --> Wheel

Cơ chế chính

1. Bucket liên kết đôi (TimingWheelBucket) và khóa striped theo kết nối

  • Wheel cấp phát BucketCount (512) slot TimingWheelBucket. Khi BucketCount là lũy thừa của hai, chỉ số bucket được tính bằng bitmask ((int)(targetTick & _mask)).
  • Mỗi bucket duy trì một danh sách liên kết đôi các nút TimeoutTask lấy từ pool, được bảo vệ bởi khóa monitor theo bucket (lock (bucket)), hỗ trợ thêm và xóa với độ phức tạp $O(1)$.
  • Việc đăng ký và hủy đăng ký kết nối được đồng bộ theo từng kết nối bằng một mảng khóa striped có kích thước lũy thừa của hai (_connectionLocks), cùng với các thuộc tính ITimeoutTrackedConnection.TimeoutVersion và TimeoutTask trực tiếp trên Connection / WebSocketConnection / PassthroughConnection.

2. Phá tham chiếu ngay khi hủy

Khi một Connection bị dispose, PerformDestructiveCleanup() lập tức phá tham chiếu từ TimeoutTask.Conn (task.Conn = null), cho phép bộ thu gom rác thu hồi Connection ngay mà không phải chờ con trỏ wheel quay tới bucket đó.

3. Kích hoạt theo đếm tham chiếu (Activate / Deactivate)

Nhiều listener (TcpListenerBase, WebSocketListenerBase, UdpPassthroughListener) dùng chung TimingWheel singleton. Activate tăng _activeListeners và khởi động worker nền của TaskManager cho listener đầu tiên; Deactivate giảm _activeListeners và dừng/xả wheel khi listener cuối cùng tắt (chờ tối đa TimingWheelOptions.WheelDrainTimeoutMs = 5000 ms).

Cấu hình (TimingWheelOptions)

Thuộc tínhMặc địnhKiểm traMô tả
BucketCount512[ValueRange(1, int.MaxValue)]Số slot của wheel (giá trị lũy thừa của hai cho phép chỉ số bitmask).
TickDuration1000[ValueRange(1, int.MaxValue)]Khoảng tick tính bằng mili-giây cho vòng PeriodicTimer.
IdleTimeoutMs60_000[ValueRange(1, int.MaxValue)]Timeout nhàn rỗi mặc định của kết nối tính bằng mili-giây trước khi tự động ngắt.
WheelDrainTimeoutMs5000[ValueRange(0, 60000)]Thời gian chờ xả tối đa khi tắt máy, tính bằng mili-giây.

API liên quan