/// HTTP2 Ping usage /// /// hyper uses HTTP2 pings for two purposes: /// /// 1. Adaptive flow control using BDP /// 2. Connection keep-alive /// /// Both cases are optional. /// /// # BDP Algorithm /// /// 1. When receiving a DATA frame, if a BDP ping isn't outstanding: /// 1a. Record current time. /// 1b. Send a BDP ping. /// 2. Increment the number of received bytes. /// 3. When the BDP ping ack is received: /// 3a. Record duration from sent time. /// 3b. Merge RTT with a running average. /// 3c. Calculate bdp as bytes/rtt. /// 3d. If bdp is over 2/3 max, set new max to bdp and update windows.
#[cfg(feature = "runtime")] use std::fmt; #[cfg(feature = "runtime")] use std::future::Future; #[cfg(feature = "runtime")] use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::task::{self, Poll}; use std::time::Duration; #[cfg(not(feature = "runtime"))] use std::time::Instant;
use h2::{Ping, PingPong}; #[cfg(feature = "runtime")] use tokio::time::{Instant, Sleep}; use tracing::{debug, trace};
#[derive(Clone)] pub(super) struct Config { pub(super) bdp_initial_window: Option<WindowSize>, /// If no frames are received in this amount of time, a PING frame is sent. #[cfg(feature = "runtime")] pub(super) keep_alive_interval: Option<Duration>, /// After sending a keepalive PING, the connection will be closed if /// a pong is not received in this amount of time. #[cfg(feature = "runtime")] pub(super) keep_alive_timeout: Duration, /// If true, sends pings even when there are no active streams. #[cfg(feature = "runtime")] pub(super) keep_alive_while_idle: bool,
}
// bdp /// If `Some`, bdp is enabled, and this tracks how many bytes have been /// read during the current sample.
bytes: Option<usize>, /// We delay a variable amount of time between BDP pings. This allows us /// to send less pings as the bandwidth stabilizes.
next_bdp_at: Option<Instant>,
// keep-alive /// If `Some`, keep-alive is enabled, and the Instant is how long ago /// the connection read the last frame. #[cfg(feature = "runtime")]
last_read_at: Option<Instant>,
struct Bdp { /// Current BDP in bytes
bdp: u32, /// Largest bandwidth we've seen so far.
max_bandwidth: f64, /// Round trip time in seconds
rtt: f64, /// Delay the next ping by this amount. /// /// This will change depending on how stable the current bandwidth is.
ping_delay: Duration, /// The count of ping round trips where BDP has stayed the same.
stable_count: u32,
}
#[cfg(feature = "runtime")] struct KeepAlive { /// If no frames are received in this amount of time, a PING frame is sent.
interval: Duration, /// After sending a keepalive PING, the connection will be closed if /// a pong is not received in this amount of time.
timeout: Duration, /// If true, sends pings even when there are no active streams.
while_idle: bool,
/// Any higher than this likely will be hitting the TCP flow control. const BDP_LIMIT: usize = 1024 * 1024 * 16;
impl Bdp { fn calculate(&mutself, bytes: usize, rtt: Duration) -> Option<WindowSize> { // No need to do any math if we're at the limit. ifself.bdp as usize == BDP_LIMIT { self.stabilize_delay(); return None;
}
// average the rtt let rtt = seconds(rtt); ifself.rtt == 0.0 { // First sample means rtt is first rtt. self.rtt = rtt;
} else { // Weigh this rtt as 1/8 for a moving average. self.rtt += (rtt - self.rtt) * 0.125;
}
// calculate the current bandwidth let bw = (bytes as f64) / (self.rtt * 1.5);
trace!("current bandwidth = {:.1}B/s", bw);
if bw < self.max_bandwidth { // not a faster bandwidth, so don't update self.stabilize_delay(); return None;
} else { self.max_bandwidth = bw;
}
// if the current `bytes` sample is at least 2/3 the previous // bdp, increase to double the current sample. if bytes >= self.bdp as usize * 2 / 3 { self.bdp = (bytes * 2).min(BDP_LIMIT) as WindowSize;
trace!("BDP increased to {}", self.bdp);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.