中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

怎樣做自己的小說網(wǎng)站外貿(mào)營銷型網(wǎng)站建設(shè)公司

怎樣做自己的小說網(wǎng)站,外貿(mào)營銷型網(wǎng)站建設(shè)公司,app網(wǎng)站建設(shè)哪家好,貴陽平面設(shè)計公司W(wǎng)ebRTC 中的帶寬估計是其擁塞控制機制的核心組成部分,基于延遲的帶寬估計是其中的一種策略,它主要基于延遲變化推斷出可用的網(wǎng)絡(luò)帶寬。 1. 總體架構(gòu) 1.1. 靜態(tài)結(jié)構(gòu) 1)DelayBasedBwe 受 GoogCcNetworkController 控制,接收其輸入…

WebRTC 中的帶寬估計是其擁塞控制機制的核心組成部分,基于延遲的帶寬估計是其中的一種策略,它主要基于延遲變化推斷出可用的網(wǎng)絡(luò)帶寬。

1. 總體架構(gòu)

1.1. 靜態(tài)結(jié)構(gòu)

1)DelayBasedBwe 受 GoogCcNetworkController 控制,接收其輸入并返回帶寬估計值。

2)DelayBasedBwe 內(nèi)部使用 InterArrivalDelta、TrendlineEstimator 和 AimdRateControl 來完成帶寬估計。

3)InterArrivalDelta 用來計算到達時間延遲。

4)TrendlineEstimator 根據(jù)到達時間延遲判斷帶寬使用是否過載。

5)AimdRateControl 內(nèi)部運行一個狀態(tài)機,根據(jù)狀態(tài)機不斷調(diào)整帶寬估計值。

1.2. 調(diào)用流程

1)GoogCcNetworkController 收到 TransportFeedback,調(diào)用 DelayBasedBwe::IncomingPacketFeedbackVector 來計算基于延遲的帶寬估計值。

2)DelaybasedBwe 調(diào)用 InterArralDelta::ComputeDeltas 計算延遲差值。

3)DelaybasedBwe 調(diào)用 TrendlineEstimator::Update 傳入延遲差值計算得到帶寬過載情況。

4)DelaybasedBwe 調(diào)用 AimdRateControl::Udpate 傳入帶寬過載情況計算得到延遲帶寬估計值。

5)GoogCcNetworkController 調(diào)用 SendSideBandwidthEstimation::UpdateDelayBasedEstimate 傳入延遲帶寬估計值,融合基于丟包的帶寬估計值,獲得最終的帶寬估計值。

1.3. 邏輯架構(gòu)

1)DelayBaseBWE 接收一坨輸入,經(jīng)過計算輸出DelayBasedBwe::Result(見 DelayBasedBwe 數(shù)據(jù)結(jié)構(gòu))。

2)InterArrivalDlata 基于 TransportFeedback 計算延遲差。

3)TrendLineEstimator 基于延遲差計算 BandwidthUsage。

4)LinkCapacityEstimator 基于過載狀態(tài)下的 ACK 碼率估算鏈路容量并計算 3sigma 上下界。當AIMD 升碼率時,基于鏈路容量估計值來決定是采用加性增還是乘性增。當 AIMD 降碼率時,下降之后的碼率不能高于鏈路容量估計值。3sigma 上下界用來判斷當前鏈路容量估計值的有效性,如果新的 ACK 碼率超出 3sigma 范圍,則鏈路容量估計值要重置并重新進行估算。

5)DelayBaseBWE 設(shè)置 ALR 狀態(tài)到 AimdRateControl,當根據(jù)帶寬使用情況決策應(yīng)該要升碼率時,如果此時進入了 ALR 狀態(tài),不允許升碼率,和之前碼率保持一致。

6)網(wǎng)絡(luò)非過載狀態(tài)下,DelayBaseBWE 設(shè)置 Probe bitrate 到 AimdRateControl,用探測帶寬更新估計值。此時探測帶寬很可能是鏈路的真實帶寬,這樣更新是合理的。

7)AimdRateControl 使用 TrendLineEstimator 輸出的 BandwidthUsage 更來狀態(tài)機狀態(tài),然后根據(jù)新的控制狀態(tài)來更新帶寬估計值,如果是 kRcHold 則保持估計值不變,如果是 kRcIncrease 則采用加性增或乘性增來增加帶寬估計值,如果是 kRcDecrease 則降低估計值。

DelayBaseBWE 在調(diào)用 AimdRateControl 之前,會根據(jù) BandwidthUsage 進行前處理:

1)如果鏈路處于 overusing 狀態(tài),且沒有可用的 ACK 碼率,則估計值砍半,這個頻率(間隔)由 RTT 決定。

2)如果鏈路處于normal/underusing 狀態(tài),且有可用的探測帶寬,則使用探測帶寬更新估計值。

其他情況,才會更新 AimdRateControl 狀態(tài)機,由 AimdRateControl 給出帶寬估計值。

2. DelayBasedBwe

2.1. 重要屬性

1)video_inter_arrival_

用來計算報文到達延遲差。

2)video_delay_detector_

TrendLineEstimator,用來檢測鏈路過載狀態(tài)。

3)rate_control_

根據(jù)鏈路過載狀態(tài)及其變化來對帶寬進行估計。

2.2. 重要方法

1)IncomingPacketFeedbackVector

傳入 TransportFeedback 以計算報文到達延遲差,同時還會傳入 ACK 碼率、探測碼率和 ALR 狀態(tài)。

2)OnRttUpdate

更新鏈路 RTT,AimdRateControl 使用。

3)LatestEstimate

從 AimdRateControl 獲取最近延遲帶寬估計值。

4)SetStartBitrate

設(shè)置 AimdRateControl 的起始碼率。

5)SetMinBitrate

設(shè)置 AimdRateControl 的最小碼率。

2.3. 數(shù)據(jù)結(jié)構(gòu)

帶寬使用有正常、欠載和過載三種狀態(tài)。

enum class BandwidthUsage {kBwNormal = 0,kBwUnderusing = 1,kBwOverusing = 2,kLast
};

延遲帶寬估計器返回值。

struct DelayBasedBwe::Result {// 帶寬估計值是否有更新bool updated = false;// 是否是使用探測值進行的更新bool probe = false;// 更新后的目標碼率估計值DataRate target_bitrate = DataRate::Zero();// 是否是從過載恢復(fù)bool recovered_from_overuse = false;// 根據(jù)算法計算得到的帶寬使用情況BandwidthUsage delay_detector_state = BandwidthUsage::kBwNormal;
};

2.4. 源碼分析

2.4.1. IncomingPacketFeedbackVector

收到 TransportFeedback 后,使用延遲差值更新趨勢線估計器,更新 ALR 狀態(tài),然后調(diào)用 MaybeUpdateEstimate 獲取估計結(jié)果。

DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(const TransportPacketsFeedback& msg,absl::optional<DataRate> acked_bitrate,absl::optional<DataRate> probe_bitrate,absl::optional<NetworkStateEstimate> network_estimate,bool in_alr) {// 按時間進行排序auto packet_feedback_vector = msg.SortedByReceiveTime();...// 逐個處理feedbackfor (const auto& packet_feedback : packet_feedback_vector) {delayed_feedback = false;// 計算時延delta,并更新detector狀態(tài)IncomingPacketFeedback(packet_feedback, msg.feedback_time);// 網(wǎng)絡(luò)狀態(tài)從欠載狀態(tài)到正常狀態(tài),說明已經(jīng)恢復(fù)if (prev_detector_state == BandwidthUsage::kBwUnderusing &&active_delay_detector_->State() == BandwidthUsage::kBwNormal) {recovered_from_overuse = true;}prev_detector_state = active_delay_detector_->State();}// 更新ALR狀態(tài)rate_control_.SetInApplicationLimitedRegion(in_alr);// 從AIMD獲取目標碼率return MaybeUpdateEstimate(acked_bitrate, probe_bitrate,std::move(network_estimate),recovered_from_overuse, in_alr, msg.feedback_time);
}

2.4.2. MaybeUpdateEstimate

1)在沒有獲取到 ACK 碼率的情況下,如果網(wǎng)絡(luò)過載,算法簡單粗暴,每 200ms 下降 50%。在未獲得測量值的前提下,保守處理比較好。

2)在獲得探測碼率的情況下,如果網(wǎng)絡(luò)不過載,則使用探測碼率更新估計值。這是因為探測碼率是通過主動探測獲得的,它能更快、更真實地反映網(wǎng)絡(luò)當前的實際承載能力。

DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(absl::optional<DataRate> acked_bitrate,absl::optional<DataRate> probe_bitrate,absl::optional<NetworkStateEstimate> state_estimate,bool recovered_from_overuse,bool in_alr,Timestamp at_time) {Result result;// 網(wǎng)絡(luò)過載,需要降碼率if (active_delay_detector_->State() == BandwidthUsage::kBwOverusing) {if (acked_bitrate && rate_control_.TimeToReduceFurther(at_time, *acked_bitrate)) {// 已經(jīng)獲取ACK碼率,且符合調(diào)整頻率限制,基于 ACK 碼率更新估計碼率result.updated = UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);} else if (!acked_bitrate && rate_control_.ValidEstimate() &&rate_control_.InitialTimeToReduceFurther(at_time)) {// 未獲得 ACK 碼率,碼率下降 50%rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, at_time);result.updated = true;result.probe = false;result.target_bitrate = rate_control_.LatestEstimate();}// 網(wǎng)絡(luò)欠載或正常} else {// 已經(jīng)獲得了探測碼率,則使用探測碼率更新AIMD的估計值if (probe_bitrate) {result.probe = true;result.updated = true;rate_control_.SetEstimate(*probe_bitrate, at_time);result.target_bitrate = rate_control_.LatestEstimate();} else {// 沒有探測碼率,則由AIMD基于ACK碼率計算估計碼率result.updated =UpdateEstimate(at_time, acked_bitrate, &result.target_bitrate);result.recovered_from_overuse = recovered_from_overuse;}}BandwidthUsage detector_state = active_delay_detector_->State();// 更新內(nèi)部狀態(tài)if ((result.updated && prev_bitrate_ != result.target_bitrate) ||detector_state != prev_state_) {DataRate bitrate = result.updated ? result.target_bitrate : prev_bitrate_;prev_bitrate_ = bitrate;prev_state_ = detector_state;}result.delay_detector_state = detector_state;return result;
}

3. InterArrivalDelta

3.1. 重要屬性

1)send_time_group_length_

約束一個分組的長度不能 send_time_group_length_,用來協(xié)助劃分時間戳分組。

2)current_timestamp_group_

當前時間戳分組。

3)prev_timestamp_group_

上一個時間戳分組。

4)num_consecutive_reordered_packets_

連續(xù)亂序報文數(shù)量,亂序定義為分組間的到達時間差為負數(shù)。

3.2. 重要方法

1)ComputeDeltas

返回 true 表示達到計算條件,返回發(fā)送時間差和接收時間差。返回false,繼續(xù)更新當前分組數(shù)據(jù)。

3.3. 報文分組

計算相鄰兩個報文的到達時間差的噪聲太大,計算兩個報文分組的到達時間差會更可靠。這就涉及到如何對報文進行分組。

3.3.1. 數(shù)據(jù)結(jié)構(gòu)

struct SendTimeGroup {// 第一個報文bool IsFirstPacket() const { return complete_time.IsInfinite(); }// 所有報文大小之和size_t size;// 第一個報文的發(fā)送時間Timestamp first_send_time;// 不斷更新的發(fā)送時間,但須保持單調(diào)遞增Timestamp send_time;// 第一個報文的接收時間Timestamp first_arrival;// 不斷更新的接收時間Timestamp complete_time;// 每次更新時當前系統(tǒng)時間(發(fā)送端收到反饋時的本地系統(tǒng)時間)Timestamp last_system_time;
};

3.3.2. 分組規(guī)則

1)收到的報文是當前分組第一個報文,則表示分組開始。

2)收到的報文和當前分組屬于同一個 burst,則報文歸屬于當前分組。

3)收到的報文的發(fā)送時間與當前分組中第一個報文的發(fā)送時間之差小于等于 5ms,則報文歸屬當前分組。

4)否則,報文屬于新的分組。

bool InterArrivalDelta::NewTimestampGroup(Timestamp arrival_time, Timestamp send_time) {if (current_timestamp_group_.IsFirstPacket()) {// 當前Group還未收到報文return false;} else if (BelongsToBurst(arrival_time, send_time)) {// 與當前Group同屬于一個burstreturn false;} else { // 根據(jù)發(fā)送時間跨度來劃分分組// send_time_group_length_ = TimeDelta::Millis(5)return send_time - current_timestamp_group_.first_send_time >send_time_group_length_;}
}

3.3.3. Burst 規(guī)則

1)發(fā)送時間相同,肯定屬于同一個 burst。

2)由于鏈路擁塞,導(dǎo)致不同發(fā)送時間的報文也可能形成一個 burst,具體規(guī)則見注釋。

bool InterArrivalDelta::BelongsToBurst(Timestamp arrival_time,Timestamp send_time) {// 計算數(shù)據(jù)包到達時間和當前時間組完成時間(最近報文的 arrival_time)之間的時間差TimeDelta arrival_time_delta =arrival_time - current_timestamp_group_.complete_time;// 計算數(shù)據(jù)包發(fā)送時間和當前時間組發(fā)送時間(分組當前最大的 send_time)之間的時間差TimeDelta send_time_delta = send_time - current_timestamp_group_.send_time;// send_time一樣,屬于同一個burst發(fā)出來if (send_time_delta.IsZero())return true;// 計算傳播時間差,即到達時間差減去發(fā)送時間差,表示在網(wǎng)絡(luò)中的傳播時間TimeDelta propagation_delta = arrival_time_delta - send_time_delta;// 即使send_time不一樣,如果同時滿足以下條件,也認為屬于同一個burst:// 1)傳播時間差為負,說明與當前分組最后一個報文是積壓在鏈路然后一起發(fā)送過來// 2)到達時間差小于等于5ms// 3)報文到達時間與當前分組第一個包的到達時間之差小于100msif (propagation_delta < TimeDelta::Zero() &&arrival_time_delta <= kBurstDeltaThreshold &&arrival_time - current_timestamp_group_.first_arrival < kMaxBurstDuration)return true;return false;
}

3.4. Delta 計算

Delta 的計算方式比較簡單,兩組報文的 send_time 相減和 complete_time 相減分別得到 send_time_delta 和 arrival_time_delta。但還需要處理亂序、系統(tǒng)時間漂移等異常情況,以防異常數(shù)據(jù)污染,使得計算結(jié)果變得不可靠。

1)系統(tǒng)時間漂移

system_time 是收到反饋的本地系統(tǒng)時間,通過比較前后兩次系統(tǒng)時間的差值,如果超出正常范圍,則認為系統(tǒng)時間可以被人為修改,數(shù)據(jù)需要重置,重新進行統(tǒng)計。

2)亂序

連續(xù)出現(xiàn) 3 次 arrival_time_delta 為負,說明網(wǎng)絡(luò)亂序情況非常嚴重,基于當前數(shù)據(jù)計算結(jié)果不可靠,需要進行重置。

bool InterArrivalDelta::ComputeDeltas(Timestamp send_time, Timestamp arrival_time,Timestamp system_time, size_t packet_size, TimeDelta* send_time_delta,TimeDelta* arrival_time_delta, int* packet_size_delta) {bool calculated_deltas = false;if (current_timestamp_group_.IsFirstPacket()) {// 如果是第一個數(shù)據(jù)包,則僅存儲發(fā)送和到達時間,因為需要至少兩幀數(shù)據(jù)來計算差異。current_timestamp_group_.send_time = send_time;current_timestamp_group_.first_send_time = send_time;current_timestamp_group_.first_arrival = arrival_time;} else if (current_timestamp_group_.first_send_time > send_time) {// 如果當前數(shù)據(jù)包的發(fā)送時間早于第一個發(fā)送時間,表明是亂序包,直接返回return false;} else if (NewTimestampGroup(arrival_time, send_time)) {// First packet of a later send burst, the previous packets sample is ready.if (prev_timestamp_group_.complete_time.IsFinite()) {// 兩組報文的發(fā)送時間差*send_time_delta =current_timestamp_group_.send_time - prev_timestamp_group_.send_time;// 兩組報文的接收時間差*arrival_time_delta = current_timestamp_group_.complete_time -prev_timestamp_group_.complete_time;TimeDelta system_time_delta = current_timestamp_group_.last_system_time -prev_timestamp_group_.last_system_time;// 發(fā)現(xiàn)系統(tǒng)時間偏移,重置if (*arrival_time_delta - system_time_delta >= kArrivalTimeOffsetThreshold) {Reset();return false;}// 兩組報文亂序到達,超過3個亂序報文,重置if (*arrival_time_delta < TimeDelta::Zero()) {++num_consecutive_reordered_packets_;if (num_consecutive_reordered_packets_ >= kReorderedResetThreshold) {Reset();}return false;} else {num_consecutive_reordered_packets_ = 0;}// 兩組報文大小差*packet_size_delta = static_cast<int>(current_timestamp_group_.size) -static_cast<int>(prev_timestamp_group_.size);// 完成差異計算calculated_deltas = true;}// current -> prevprev_timestamp_group_ = current_timestamp_group_;// The new timestamp is now the current frame.current_timestamp_group_.first_send_time = send_time;current_timestamp_group_.send_time = send_time;current_timestamp_group_.first_arrival = arrival_time;current_timestamp_group_.size = 0;} else {// 屬于當前 group 的正常報文,更新 send_timecurrent_timestamp_group_.send_time =std::max(current_timestamp_group_.send_time, send_time);}// Accumulate the frame size.current_timestamp_group_.size += packet_size;current_timestamp_group_.complete_time = arrival_time;current_timestamp_group_.last_system_time = system_time;return calculated_deltas;
}

4. TrendLineEstimator

4.1. 重要屬性

1)delay_hist_

保存用來計算延遲斜率的元素,元素定義如下:

struct PacketTiming {// 相對隊列第一組報文到達的相對時間,即 X 坐標double arrival_time_ms;// 平滑后的累積延遲差,即 Y 坐標double smoothed_delay_ms;// 平滑前的累積延遲差double raw_delay_ms;
};

2)threshold_

計算的延遲斜率通過與 threshold_ 比較來判斷網(wǎng)絡(luò)使用狀態(tài)。

4.2. 重要方法

1)Update

內(nèi)部調(diào)用 UpdateTrendLine。

2)UdpateTrendline

傳入新的時間差值,更新網(wǎng)絡(luò)使用狀態(tài)。

3)State

獲取當前網(wǎng)絡(luò)使用狀態(tài)。

4.3. 源碼分析

4.3.1. UpdateTrendline

這是 TrendLineEstimator 的主函數(shù),延遲差值累積到一定數(shù)量后,計算一個擬合后的斜率,然后基于斜率判斷帶寬使用情況,邏輯比較清晰,處理流程如下圖所示:

void TrendlineEstimator::UpdateTrendline(double recv_delta_ms,double send_delta_ms,int64_t send_time_ms,int64_t arrival_time_ms,size_t packet_size) {// 計算延遲差const double delta_ms = recv_delta_ms - send_delta_ms;// 累加次數(shù)++num_of_deltas_;// 最大值約束num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax);if (first_arrival_time_ms_ == -1)first_arrival_time_ms_ = arrival_time_ms;// 平滑前延遲累積accumulated_delay_ += delta_ms;// 平滑后延遲累積,使用指數(shù)加權(quán)平均算法:smoothing_coef_ = 0.9smoothed_delay_ = smoothing_coef_ * smoothed_delay_ +(1 - smoothing_coef_) * accumulated_delay_;// 插入新元素delay_hist_.emplace_back(static_cast<double>(arrival_time_ms - first_arrival_time_ms_),smoothed_delay_, accumulated_delay_);// 確保按照 arrival_time_ms 升序排列if (settings_.enable_sort) {for (size_t i = delay_hist_.size() - 1;i > 0 &&delay_hist_[i].arrival_time_ms < delay_hist_[i - 1].arrival_time_ms;--i) {std::swap(delay_hist_[i], delay_hist_[i - 1]);}}// 維持窗口大小if (delay_hist_.size() > settings_.window_size)delay_hist_.pop_front();// Simple linear regression.double trend = prev_trend_;// 當累積的數(shù)據(jù)量達到這個大小時,觸發(fā)趨勢線的更新if (delay_hist_.size() == settings_.window_size) {trend = LinearFitSlope(delay_hist_).value_or(trend);if (settings_.enable_cap) {absl::optional<double> cap = ComputeSlopeCap(delay_hist_, settings_);if (trend >= 0 && cap.has_value() && trend > cap.value()) {trend = cap.value();}}}// 基于趨勢線計算,檢測網(wǎng)絡(luò)使用狀態(tài)Detect(trend, send_delta_ms, arrival_time_ms);
}

4.3.2. ComputeSlopeCap

考慮到最小二乘法對異常值比較敏感,需要對通過最小二乘法計算的斜率進行約束,約束值的計算方法是:取歷史數(shù)據(jù)中前七個數(shù)據(jù)中最小原始延遲數(shù)據(jù),取歷史數(shù)據(jù)中后七個數(shù)據(jù)中最小延遲數(shù)據(jù),一前一后兩個數(shù)據(jù)計算一個斜率,用這個斜率來約束通過最小二乘法計算的斜率。

absl::optional<double> ComputeSlopeCap(const std::deque<TrendlineEstimator::PacketTiming>& packets,const TrendlineEstimatorSettings& settings) {// 從前數(shù)7個數(shù)據(jù),尋找最小原始延遲數(shù)據(jù)點TrendlineEstimator::PacketTiming early = packets[0];for (size_t i = 1; i < settings.beginning_packets; ++i) {if (packets[i].raw_delay_ms < early.raw_delay_ms)early = packets[i];}// 從后數(shù)7個數(shù)據(jù),尋找最小原始延遲數(shù)據(jù)點size_t late_start = packets.size() - settings.end_packets;TrendlineEstimator::PacketTiming late = packets[late_start];for (size_t i = late_start + 1; i < packets.size(); ++i) {if (packets[i].raw_delay_ms < late.raw_delay_ms)late = packets[i];}// 檢查late和early兩個數(shù)據(jù)點之間的時間跨度,如果小于1ms,// 則認為時間跨度太小,不足以進行有效計算if (late.arrival_time_ms - early.arrival_time_ms < 1) {return absl::nullopt;}// 使用找到的兩個數(shù)據(jù)點計算斜率return (late.raw_delay_ms - early.raw_delay_ms) /(late.arrival_time_ms - early.arrival_time_ms) +settings.cap_uncertainty;
}

4.3.3. Detect

使用調(diào)整后斜率與 threshold_ 進行比較,判斷網(wǎng)絡(luò)使用情況,租后還需要更新閾值,以適應(yīng)網(wǎng)絡(luò)變化。

1)斜率小于 -threshold_,標識網(wǎng)絡(luò)為 kBwUnderusing;

2)斜率處于 [-threshold, threshold] 范圍內(nèi),標識網(wǎng)絡(luò)為 kBwNormal;

3)斜率大于 threshold_ 且滿足以下三個條件則標識網(wǎng)絡(luò)為 kBwOverusing:

a)連續(xù)處于 overuse 狀態(tài)超過 10ms

b)連續(xù)處于 overuse 狀態(tài)兩次及以上

c)最后一次計算的斜率比之前的斜率更大。

void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) {// 初始階段,樣本數(shù)不足,假設(shè)網(wǎng)絡(luò)正常if (num_of_deltas_ < 2) {hypothesis_ = BandwidthUsage::kBwNormal;return;}// 調(diào)整原始trend,具體原理未知,kMinNumDeltas=60,threshold_gain_=4.0const double modified_trend =std::min(num_of_deltas_, kMinNumDeltas) * trend * threshold_gain_;// 更新上次調(diào)整后trendprev_modified_trend_ = modified_trend;if (modified_trend > threshold_) {if (time_over_using_ == -1) {// 初始化計時器。假設(shè)自上次采樣以來,有一半時間處于過度使用網(wǎng)絡(luò)的狀態(tài)。time_over_using_ = ts_delta / 2;} else {// 累加 overusing 時長time_over_using_ += ts_delta;}overuse_counter_++; // 累加 overuse 次數(shù)// 處于 overuse 狀態(tài)很長時間,且檢測到 overuse 大于一次if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {if (trend >= prev_trend_) { // trend 還在加強time_over_using_ = 0;overuse_counter_ = 0;hypothesis_ = BandwidthUsage::kBwOverusing;}}} else if (modified_trend < -threshold_) {time_over_using_ = -1;overuse_counter_ = 0;hypothesis_ = BandwidthUsage::kBwUnderusing;} else { // [-threshold, threshold]time_over_using_ = -1;overuse_counter_ = 0;hypothesis_ = BandwidthUsage::kBwNormal;}prev_trend_ = trend; // 更新trend// 動態(tài)更新閾值UpdateThreshold(modified_trend, now_ms);
}

4.3.4. UpdateThreshold

threshold_ 初始值為 12.5,在計算過程中會進行動態(tài)更新,以適應(yīng)網(wǎng)絡(luò)條件變化。

void TrendlineEstimator::UpdateThreshold(double modified_trend, int64_t now_ms) {if (last_update_ms_ == -1)last_update_ms_ = now_ms;// kMaxAdaptOffsetMs = 15.0// 調(diào)整后趨勢與當前閾值的差值超過了kMaxAdaptOffsetMs,則不進行閾值調(diào)整。// 這可以防止因網(wǎng)絡(luò)突發(fā)的大延遲(如路由變化或瞬時擁塞)導(dǎo)致閾值被錯誤地大幅提高或降低。if (fabs(modified_trend) > threshold_ + kMaxAdaptOffsetMs) {last_update_ms_ = now_ms;return;}// k_up_(0.0087), k_down_(0.039), threshold_(12.5)// 選擇閾值調(diào)整系數(shù)const double k = fabs(modified_trend) < threshold_ ? k_down_ : k_up_;// 約束time_delta_ms最大值為100msconst int64_t kMaxTimeDeltaMs = 100;int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);// trend如果在normal區(qū)間內(nèi),則減小threshold_// trend如果在normal區(qū)間外,則增大threshold_threshold_ += k * (fabs(modified_trend) - threshold_) * time_delta_ms;// 約束threshold_在[6, 600]范圍threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);last_update_ms_ = now_ms;
}

5. LinkCapacityEstimator

5.1. 重要屬性

1)estimate_kbps_

估計的鏈路容量。

2)deviation_kbps_

鏈路容量估計值的方差,用來量化估計值的不確定性或波動性,初始值為 0.4。

5.2. 重要方法

1)UpperBound

鏈路容量估計的上界,等于鏈路容量估計值加上 3 倍標準差。

2)LowerBound

鏈路容量估計的下界,等于鏈路容量估計值減去 3 倍標準差。

3)OnOveruseDetected

當 AIMD 檢測到 overuse 時,調(diào)用此接口,傳入 ACK 碼率,LinkCapacityEstimator 對 ACK 碼率使用 0.05 的權(quán)重來更新估計值。網(wǎng)絡(luò)處于 overuse 狀態(tài)時,ACK 碼率能夠真實反映鏈路容量。

void LinkCapacityEstimator::OnOveruseDetected(DataRate acknowledged_rate) {Update(acknowledged_rate, 0.05);
}

4)OnProbeRate

探測碼率具有更好的實時性,LinkCapacityEstimator 對探測碼率賦予更高的權(quán)重(0.5)來更新估計值。

void LinkCapacityEstimator::OnOveruseDetected(DataRate acknowledged_rate) {Update(acknowledged_rate, 0.05);
}

5)estimate

獲取鏈路容量估計值。

5.3. 源碼分析

5.3.1. UpperBound/LowerBound

可以認為鏈路容量估計值符合正態(tài)分布,正態(tài)分布中大約 99.7% 的數(shù)據(jù)位于均值的三倍標準差之內(nèi),可以提供一個相對寬松但合理的上限和下限估計。

UpperBound 取鏈路容量估計值加上 3 倍標準差,LowerBound 取鏈路容量估計值減去 3 倍標準差。

DataRate LinkCapacityEstimator::UpperBound() const {if (estimate_kbps_.has_value())return DataRate::KilobitsPerSec(estimate_kbps_.value() +3 * deviation_estimate_kbps());return DataRate::Infinity();
}DataRate LinkCapacityEstimator::LowerBound() const {if (estimate_kbps_.has_value())return DataRate::KilobitsPerSec(std::max(0.0, estimate_kbps_.value() - 3 * deviation_estimate_kbps()));return DataRate::Zero();
}double LinkCapacityEstimator::deviation_estimate_kbps() const {// 計算標準差之前先恢復(fù)歸一化return sqrt(deviation_kbps_ * estimate_kbps_.value());
}

5.3.2. Update

AimdRateControl 在網(wǎng)絡(luò)處于過載狀態(tài)時,會調(diào)用此接口傳入 ACK 碼率,來更新鏈路容量估計值。只有處于網(wǎng)絡(luò)過載狀態(tài)的 ACK 碼率才能真實反映當前鏈路容量。LinkCapacityEstimator 使用指數(shù)移動平均算法對鏈路容量值進行平滑,并計算歸一化方差。

void LinkCapacityEstimator::Update(DataRate capacity_sample, double alpha) {double sample_kbps = capacity_sample.kbps();if (!estimate_kbps_.has_value()) {estimate_kbps_ = sample_kbps;} else {// 使用指數(shù)移動平均算法來平滑估計值estimate_kbps_ = (1 - alpha) * estimate_kbps_.value() + alpha * sample_kbps;}// 方差歸一化參數(shù)const double norm = std::max(estimate_kbps_.value(), 1.0);// 計算估計值與當前樣本值之間的差,相當于樣本值與平均值的差double error_kbps = estimate_kbps_.value() - sample_kbps;// 計算歸一化方差并進行平滑,注意這里的歸一化并沒有完全歸一,單位是 kbps。// 如果要做完全歸一化,分母應(yīng)該是 norm 的平方。deviation_kbps_ =(1 - alpha) * deviation_kbps_ + alpha * error_kbps * error_kbps / norm;// 對歸一化方差進行約束(這是個經(jīng)驗值)deviation_kbps_ = rtc::SafeClamp(deviation_kbps_, 0.4f, 2.5f);
}

限制 deviation_kbps_ 在 [0.4, 2.5] 范圍,這應(yīng)該是一個經(jīng)驗值。相當于 500Kbps 的估計值,歸一化方差范圍對應(yīng)的估計誤差大約在 14kbps 到 35kbps 之間。

(500-x)^2 / 500 = 0.4
|500-x| = sqrt(500 * 0.4)
|500-x| ~= 14kbps(500-x)^2 / 500 = 2.5
|500-x| = sqrt(500 * 2.5)
|500-x| ~= 35kbps

6. AimdRateControl

6.1. 重要屬性

1)link_capacity_

鏈路容量估計器,用來輔助調(diào)整估計帶寬,具體參考源碼分析。

6.2. 重要方法

1)SetStartBitrate

設(shè)置起始估計值。

2)SetMinBitrate

設(shè)置估計值的下限。

3)LatestEstimate

獲取最近的估計值。

4)SetRtt

更新 RTT,當進行加性提速時,需要使用 RTT 來計算增速。

5)Update

外部周期性調(diào)用,傳入 ACK 碼率,驅(qū)動 AimdRateControl 的狀態(tài)機運轉(zhuǎn)。

6)SetInApplicationLimitedRegion

設(shè)置 ALR 狀態(tài),ALR 狀態(tài)不允許提速(如果有配置的話)。

6.3. 狀態(tài)機

碼率控制狀態(tài)定義如下:

enum class RateControlState { kRcHold, kRcIncrease, kRcDecrease
};

碼率控制狀態(tài)在網(wǎng)絡(luò)過載信號的刺激下會作出相應(yīng)的響應(yīng)和變化,形成一個狀態(tài)機,如下圖所示。

狀態(tài)機狀態(tài)變化規(guī)則說明:

1)狀態(tài)機一開始進入 Incr 狀態(tài)。

【注】Incr 狀態(tài)碼率每次增長系數(shù)見源碼分析

2)檢測到 overuse 信號,不管當前處于什么狀態(tài),都轉(zhuǎn)換到 Decr 狀態(tài)。

【注】Decr 狀態(tài)碼率每次下降系數(shù)為

3)檢測到 underuse 信號,不管當前處于什么狀態(tài),都轉(zhuǎn)換到 Hold 狀態(tài)。

【注】即使之前處于 Incr 狀態(tài),也必須轉(zhuǎn)換到 Hold 狀態(tài)。因為 underuse 信號,說明網(wǎng)絡(luò)正處于排空期,在排空完成前不要提升速率,否則可能會增加延遲。

4)在 Decr 狀態(tài),檢測到 normal 信號,進入 Hold 狀態(tài),降速可以結(jié)束了。

5)在 Hold 狀態(tài),檢測到 normal 信號,進入 Incr 狀態(tài),需要開始提速了。

【注】Hold 是一個暫態(tài),會不停往上瘋狂試探網(wǎng)絡(luò)容量的上界。因此,Hold 的意思,更像是等待網(wǎng)絡(luò)排空的Hold,而不是碼率保持的 Hold。

6)在 Incr 狀態(tài),檢測到 normal 信號,繼續(xù)保持 Incr 狀態(tài),提速還不能停。

【注】說明這是一個相對激進的帶寬評估狀態(tài)機,不會停在剛剛好,而是一定會走到 underuse。

狀態(tài)機運行相關(guān)代碼如下:

void AimdRateControl::ChangeState(const RateControlInput& input, Timestamp at_time) {switch (input.bw_state) {case BandwidthUsage::kBwNormal:// 帶寬使用狀態(tài)正常// 如果之前是保持,現(xiàn)在可以提升估計值了// 如果之前是提升,現(xiàn)在繼續(xù)提升// 如果之前是降低,現(xiàn)在繼續(xù)降低if (rate_control_state_ == RateControlState::kRcHold) {time_last_bitrate_change_ = at_time;rate_control_state_ = RateControlState::kRcIncrease;}break;case BandwidthUsage::kBwOverusing:// 網(wǎng)絡(luò)過載,不管之前是什么控制狀態(tài),現(xiàn)在都要降低估計值if (rate_control_state_ != RateControlState::kRcDecrease) {rate_control_state_ = RateControlState::kRcDecrease;}break;case BandwidthUsage::kBwUnderusing:// 網(wǎng)絡(luò)欠載,不管之前是什么控制狀態(tài),現(xiàn)在都要保持估計值rate_control_state_ = RateControlState::kRcHold;break;default:RTC_DCHECK_NOTREACHED();}
}

6.4. 源碼分析

6.4.1. ChangeBitrate

使用輸入?yún)?shù)中的網(wǎng)絡(luò)使用信號更新狀態(tài)機,然后根據(jù)新的狀態(tài)指示作出相應(yīng)處理。有幾個處理細節(jié)需要注意:

1)ACK 碼率是提速和降速的基礎(chǔ),這是因為 ACK 碼率是一個鏈路容量的一個觀測值,也是當前鏈路容量的可靠估計值。

2)LinkCapacityEstimator 是基于 ACK 碼率的估計,當收到新的 ACK 碼率超出估計值的 3 倍標準差,有理由認為當前的估計值與真實值有較大偏差,需要重置。

void AimdRateControl::ChangeBitrate(const RateControlInput& input,Timestamp at_time) {absl::optional<DataRate> new_bitrate;// ACK 碼率DataRate estimated_throughput =input.estimated_throughput.value_or(latest_estimated_throughput_);// 更新if (input.estimated_throughput)latest_estimated_throughput_ = *input.estimated_throughput;// 未設(shè)置或者未評估,if (!bitrate_is_initialized_ && input.bw_state != BandwidthUsage::kBwOverusing)return;// 狀態(tài)機更新ChangeState(input, at_time);switch (rate_control_state_) {// 保持case RateControlState::kRcHold:break; // 碼率不變// 提速case RateControlState::kRcIncrease: {// ACK 碼率超過估計值的 3*sigma 范圍,需要重置 LinkCapacityEstimatorif (estimated_throughput > link_capacity_.UpperBound())link_capacity_.Reset();// 以 ACK 碼率的 1.5 倍作為提速上限D(zhuǎn)ataRate increase_limit =1.5 * estimated_throughput + DataRate::KilobitsPerSec(10);// 發(fā)送端,設(shè)置了 ALR 狀態(tài)不允許升速if (send_side_ && in_alr_ && no_bitrate_increase_in_alr_) {increase_limit = current_bitrate_;}if (current_bitrate_ < increase_limit) {DataRate increased_bitrate = DataRate::MinusInfinity();if (link_capacity_.has_estimate()) {// 鏈路容量估計值有效,認為目標碼率與鏈路容量較為接近,采用加性增進行調(diào)整。DataRate additive_increase =AdditiveRateIncrease(at_time, time_last_bitrate_change_);increased_bitrate = current_bitrate_ + additive_increase;} else {// 鏈路容量估計值無效,則使用乘性增方式來探索新的鏈路容量。DataRate multiplicative_increase = MultiplicativeRateIncrease(at_time, time_last_bitrate_change_, current_bitrate_);increased_bitrate = current_bitrate_ + multiplicative_increase;}new_bitrate = std::min(increased_bitrate, increase_limit);}time_last_bitrate_change_ = at_time;break;}// 降速case RateControlState::kRcDecrease: {DataRate decreased_bitrate = DataRate::PlusInfinity();// 降速目標設(shè)置為 ACK 碼率的 85%decreased_bitrate = estimated_throughput * beta_;if (decreased_bitrate > DataRate::KilobitsPerSec(5) &&subtract_additional_backoff_term_) {decreased_bitrate -= DataRate::KilobitsPerSec(5);}// 如果降速目標還是比當前碼率高,則嘗試使用鏈路容量估計值的 85%if (decreased_bitrate > current_bitrate_) {if (link_capacity_.has_estimate()) {decreased_bitrate = beta_ * link_capacity_.estimate();}}// 有可能降速目標還是比當前碼率高if (decreased_bitrate < current_bitrate_) {new_bitrate = decreased_bitrate;}// 更新 last_decrease_if (bitrate_is_initialized_ && estimated_throughput < current_bitrate_) {if (!new_bitrate.has_value()) {last_decrease_ = DataRate::Zero();} else {last_decrease_ = current_bitrate_ - *new_bitrate;}}// ACK 碼率超過估計值的 3*sigma 范圍,需要重置 LinkCapacityEstimatorif (estimated_throughput < link_capacity_.LowerBound()) {link_capacity_.Reset();}bitrate_is_initialized_ = true;// 使用 overuse 信號下的 ACK 碼率更新鏈路容量估計link_capacity_.OnOveruseDetected(estimated_throughput);// Stay on hold until the pipes are cleared.rate_control_state_ = RateControlState::kRcHold;time_last_bitrate_change_ = at_time;time_last_bitrate_decrease_ = at_time;break;}default:RTC_DCHECK_NOTREACHED();}// 更新當前估計值current_bitrate_ = ClampBitrate(new_bitrate.value_or(current_bitrate_));
}

6.4.2. AdditiveRateIncrease

加性提速根據(jù) rtt_ 和 current_bitrate_ 來計算增速,相當于每個 rtt 多發(fā)送一個 packet,這樣的增速看上去是比較溫和的。

DataRate AimdRateControl::AdditiveRateIncrease(Timestamp at_time,Timestamp last_time) const {double time_period_seconds = (at_time - last_time).seconds<double>();double data_rate_increase_bps =GetNearMaxIncreaseRateBpsPerSecond() * time_period_seconds;return DataRate::BitsPerSec(data_rate_increase_bps);
}
double AimdRateControl::GetNearMaxIncreaseRateBpsPerSecond() const {RTC_DCHECK(!current_bitrate_.IsZero());// 假定視頻幀率為30FPS,計算每幀的時間間隔 kFrameInterval 為大約33.3毫秒const TimeDelta kFrameInterval = TimeDelta::Seconds(1) / 30;// 根據(jù)當前比特率和幀間隔,計算單幀數(shù)據(jù)的大小,這代表了每幀數(shù)據(jù)傳輸所需的總比特數(shù)DataSize frame_size = current_bitrate_ * kFrameInterval;// 設(shè)定每數(shù)據(jù)包的大小為1200字節(jié)const DataSize kPacketSize = DataSize::Bytes(1200);//  計算每幀數(shù)據(jù)需要多少個這樣的數(shù)據(jù)包,取上界值(因為即使最后一包不滿,也按一整個包計算)double packets_per_frame = std::ceil(frame_size / kPacketSize);// 基于總幀大小和包的數(shù)量,計算平均每個包的大小DataSize avg_packet_size = frame_size / packets_per_frame;// 注:純粹數(shù)學(xué)推導(dǎo),avg_packet_size == kPacketSize// 在真實RTT的基礎(chǔ)上加上100ms再乘以2,使得加性增速更加保守?TimeDelta response_time = rtt_ + TimeDelta::Millis(100);response_time = response_time * 2;// 按照ping-pong模式(收到ack后再發(fā)送下一個報文)一秒鐘可以多發(fā)送多少數(shù)據(jù)。double increase_rate_bps_per_second =(avg_packet_size / response_time).bps<double>();double kMinIncreaseRateBpsPerSecond = 4000;return std::max(kMinIncreaseRateBpsPerSecond, increase_rate_bps_per_second);
}

6.4.3. MultiplicativeRateIncrease

乘性提速會計算一個增益值,初始化增益為 8%,會根據(jù)時間頻率來調(diào)整增益系數(shù)。

DataRate AimdRateControl::MultiplicativeRateIncrease(Timestamp at_time,Timestamp last_time,DataRate current_bitrate) const {// 初始化增益系數(shù)double alpha = 1.08;// 如果之前調(diào)整過碼率,距離上次調(diào)整碼率時間過去越久,增益系數(shù)越大if (last_time.IsFinite()) {auto time_since_last_update = at_time - last_time;alpha = pow(alpha, std::min(time_since_last_update.seconds<double>(), 1.0));}// 根據(jù)增益系數(shù)計算增速,限制最低碼率增速為 1KbpsDataRate multiplicative_increase =std::max(current_bitrate * (alpha - 1.0), DataRate::BitsPerSec(1000));return multiplicative_increase;
}

7. 總結(jié)

基于延遲的帶寬估計,以處于非 ALR 狀態(tài)的 ACK 碼率為基礎(chǔ),基于延遲梯度估計鏈路真實帶寬,實現(xiàn)對鏈路帶寬的動態(tài)跟蹤,算法的核心邏輯可以表述為:

1)網(wǎng)絡(luò)過載,說明網(wǎng)絡(luò)產(chǎn)生擁塞,當前發(fā)送碼率過高,需要降低發(fā)送碼率。

2)網(wǎng)絡(luò)欠載,說明網(wǎng)絡(luò)正在排空,不要急著提升發(fā)送碼率,先保持當前發(fā)送碼率一段時間。

3)網(wǎng)絡(luò)正常,可以試著增加發(fā)送碼率,探測下帶寬的上限。

同時,在網(wǎng)絡(luò)非過載狀態(tài)下,使用探測帶寬對估計值進行校正,使估計更加精準。算法在計算延遲梯度、判斷網(wǎng)絡(luò)使用狀況都做了精心的設(shè)計,會盡量排除隨機噪聲的干擾。

http://m.risenshineclean.com/news/64523.html

相關(guān)文章:

  • 全面的網(wǎng)站建設(shè)免費sem工具
  • 慈善系統(tǒng)網(wǎng)站建設(shè)需求網(wǎng)站建設(shè)教程
  • 快速學(xué)制作網(wǎng)站百度小說排行榜第一名
  • wordpress 導(dǎo)航站模板營銷型網(wǎng)站建設(shè)論文
  • 布偶貓網(wǎng)頁設(shè)計教程百度seo入駐
  • 注冊網(wǎng)站頁面跳轉(zhuǎn)錯誤惠州seo排名優(yōu)化
  • 手機網(wǎng)站Com全國十大婚戀網(wǎng)站排名
  • 怎樣建立手機網(wǎng)站廣告營銷策略有哪些
  • 有自己域名如何做網(wǎng)站色盲測試圖第六版及答案大全
  • 微信上瀏覽自己做的網(wǎng)站免費下載app并安裝
  • 做阿里還是網(wǎng)站濰坊百度關(guān)鍵詞優(yōu)化
  • 微商網(wǎng)站制作武漢關(guān)鍵詞排名推廣
  • 哪些網(wǎng)站可以找到做海報的素材鄭州seo網(wǎng)站排名
  • xxx網(wǎng)站策劃書西安網(wǎng)頁設(shè)計
  • 莫名接到網(wǎng)站建設(shè)電話推廣引流工具
  • 溫嶺做網(wǎng)站新冠疫情最新消息今天
  • 營銷型網(wǎng)站建設(shè)實戰(zhàn)》杭州優(yōu)化公司哪家好
  • 中國建設(shè)銀行的業(yè)務(wù)范圍深圳百度網(wǎng)站排名優(yōu)化
  • 日照疫情最新消息今天封城了廣州網(wǎng)絡(luò)seo公司
  • 個人網(wǎng)站備案 淘寶客天氣預(yù)報最新天氣預(yù)報
  • 心理咨詢網(wǎng)站開發(fā)長春網(wǎng)站建設(shè)制作
  • 坪山做網(wǎng)站的公司北京全網(wǎng)營銷推廣
  • 網(wǎng)站建設(shè)分幾模塊黃頁推廣引流網(wǎng)站
  • 哪些網(wǎng)站可以做調(diào)查賺錢優(yōu)化推廣網(wǎng)站seo
  • 網(wǎng)站建設(shè)公司有哪些方面微商怎么引流被加精準粉
  • 怎么注冊英文網(wǎng)站域名互動營銷的案例及分析
  • 免費建立個人文章網(wǎng)站百度游戲風(fēng)云榜
  • c2c商城網(wǎng)站建設(shè)費用b站推廣入口2023年
  • 句容網(wǎng)站建設(shè)制作萬網(wǎng)查詢
  • 網(wǎng)站的鏈接結(jié)構(gòu)怎么做營銷策劃書模板范文