analysis: split TCP retransmissions into forward and return, and show both on the line cards
tcp.retrans.up counts retransmitted segments sent by the dialing side, tcp.retrans.down those sent by the listening side. The cards show RTT as a round trip (⇄) with forward (→) and return (←) rows for QUIC loss and TCP retransmission.
This commit is contained in:
1 parent
48ffa56285
commit
9f5a6cf77a
9 files changed
+104
-37
No files matched your search
@@ -29,11 +29,11 @@ interface Props {
|
||||
m: Record<string, number | null | undefined>
|
||||
}
|
||||
|
||||
/** 一条线路的 QUIC/TCP 双行摘要,各自显示时延、质量点阵和丢包/重传率。 */
|
||||
/** 一条线路的 QUIC/TCP 摘要:RTT 是往返(⇄);去程是拨号方到监听方(→),回程反过来(←);QUIC 看各方向丢包,TCP 看各方向重传,都配质量点阵。 */
|
||||
export function LineStrips({ lineId, range, m }: Props) {
|
||||
const info = OVERVIEW_RANGES.find((r) => r.value === range) ?? OVERVIEW_RANGES[0]
|
||||
const series = useQuery(
|
||||
() => api.get<SeriesDto>(`/api/public/lines/${encodeURIComponent(lineId)}/series`, { range: info.value, anchor: 'now', step: info.step, preset: 'quic,tcp', metrics: 'loss.up,loss.down,loss.total,rtt.p50,rtt.p95,rtt.p99,tcp.retrans,tcp.rtt.p50' }),
|
||||
() => api.get<SeriesDto>(`/api/public/lines/${encodeURIComponent(lineId)}/series`, { range: info.value, anchor: 'now', step: info.step, preset: 'quic,tcp', metrics: 'loss.up,loss.down,loss.total,rtt.p50,rtt.p95,rtt.p99,tcp.retrans.up,tcp.retrans.down,tcp.rtt.p50' }),
|
||||
[lineId, info.value],
|
||||
30_000,
|
||||
)
|
||||
@@ -57,24 +57,25 @@ export function LineStrips({ lineId, range, m }: Props) {
|
||||
const at = shown !== null && t[shown] !== undefined ? shown : null
|
||||
const lossUp = col('loss.up')
|
||||
const lossDown = col('loss.down')
|
||||
const retrans = col('tcp.retrans')
|
||||
const retransUp = col('tcp.retrans.up')
|
||||
const retransDown = col('tcp.retrans.down')
|
||||
const up = m['loss.up']
|
||||
const down = m['loss.down']
|
||||
const upText = up === null || up === undefined ? '丢包 —' : `${fmtPct(up)} 丢包`
|
||||
const downText = down === null || down === undefined ? '丢包 —' : `${fmtPct(down)} 丢包`
|
||||
const retransValue = m['tcp.retrans']
|
||||
const retransTone = levelOf(retransValue)
|
||||
const retransText = retransValue === null || retransValue === undefined ? '重传 —' : `${fmtPct(retransValue)} 重传`
|
||||
const retransUpValue = m['tcp.retrans.up']
|
||||
const retransDownValue = m['tcp.retrans.down']
|
||||
const retransText = (v: number | null | undefined) => (v === null || v === undefined ? '重传 —' : `${fmtPct(v)} 重传`)
|
||||
return (
|
||||
<div className="strips" ref={box} onMouseMove={onMove} onMouseLeave={() => setHover(null)}>
|
||||
<div className="line-mini-stack">
|
||||
<div className="line-mini-quic-head" title={`QUIC RTT p50 ${fmtMs(m['rtt.p50'])} · p95 ${fmtMs(m['rtt.p95'])} · p99 ${fmtMs(m['rtt.p99'])}`}>
|
||||
<span>QUIC</span><strong className="num">{fmtMs(m['rtt.p50'])}</strong><small>悬停看 p95 / p99</small>
|
||||
<span>QUIC RTT ⇄</span><strong className="num">{fmtMs(m['rtt.p50'])}</strong><small>悬停看 p95 / p99</small>
|
||||
{series.error ? <span className="line-mini-badge bad" title={`上一次取数失败:${series.error.message}`}>数据未更新</span> : null}
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`去程 拨号方 → 监听方 丢包 ${fmtPct(up)}`}>
|
||||
<span>去程</span>
|
||||
<span>去程 →</span>
|
||||
<span className={`line-mini-badge ${levelOf(up)}`}>{upText}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的去程丢包`}>
|
||||
@@ -85,7 +86,7 @@ export function LineStrips({ lineId, range, m }: Props) {
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`回程 监听方 → 拨号方 丢包 ${fmtPct(down)}`}>
|
||||
<span>回程</span>
|
||||
<span>回程 ←</span>
|
||||
<span className={`line-mini-badge ${levelOf(down)}`}>{downText}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的回程丢包`}>
|
||||
@@ -96,12 +97,28 @@ export function LineStrips({ lineId, range, m }: Props) {
|
||||
</div>
|
||||
<div className="line-mini-tcp">
|
||||
<div className="line-mini-tcp-head" title={`TCP RTT p50 ${fmtMs(m['tcp.rtt.p50'])}`}>
|
||||
<span>TCP</span><strong className="num">{fmtMs(m['tcp.rtt.p50'])}</strong>
|
||||
<span className={`line-mini-badge ${retransTone}`}>{retransText}</span>
|
||||
<span>TCP RTT ⇄</span><strong className="num">{fmtMs(m['tcp.rtt.p50'])}</strong>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的 TCP 重传`}>
|
||||
{(s ? retrans : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`retrans-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`TCP 去程 拨号方 → 监听方 重传 ${fmtPct(retransUpValue)}`}>
|
||||
<span>去程 →</span>
|
||||
<span className={`line-mini-badge ${levelOf(retransUpValue)}`}>{retransText(retransUpValue)}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的 TCP 去程重传`}>
|
||||
{(s ? retransUp : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`retrans-up-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`TCP 回程 监听方 → 拨号方 重传 ${fmtPct(retransDownValue)}`}>
|
||||
<span>回程 ←</span>
|
||||
<span className={`line-mini-badge ${levelOf(retransDownValue)}`}>{retransText(retransDownValue)}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的 TCP 回程重传`}>
|
||||
{(s ? retransDown : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`retrans-down-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -127,7 +144,10 @@ export function LineStrips({ lineId, range, m }: Props) {
|
||||
<div className="pop-group">
|
||||
<span className="pop-name">TCP</span>
|
||||
<span>
|
||||
重传 <em className={levelOf(col('tcp.retrans')[at])}>{fmtPct(col('tcp.retrans')[at])}</em>
|
||||
去程重传 <em className={levelOf(col('tcp.retrans.up')[at])}>{fmtPct(col('tcp.retrans.up')[at])}</em>
|
||||
</span>
|
||||
<span>
|
||||
回程重传 <em className={levelOf(col('tcp.retrans.down')[at])}>{fmtPct(col('tcp.retrans.down')[at])}</em>
|
||||
</span>
|
||||
<span>
|
||||
RTT p50 <em>{fmtMs(col('tcp.rtt.p50')[at])}</em>
|
||||
|
||||
Reference in new issue
Block a user