mirror of
https://github.com/netbirdio/docs.git
synced 2026-08-25 09:11:26 +02:00
docs: add a Performance troubleshooting page (#930)
Add a decision-flow guide for "NetBird feels slow" that helps a reader find whether the tunnel, their own connection, a routing peer, or the app is the real cause, instead of assuming NetBird is at fault. The page leads with the path traffic takes, a one-minute Quick test that resolves the two most common causes (a relayed peer, or the local network), then a Start here checklist that links down to detail sections: checking the connection with netbird status -d, setting a baseline with iperf3 in both directions, isolating the slow hop, ruling out packet size and inspecting firewalls, and separating startup delays from throughput. Add a reusable PathFlow component that draws the hop-by-hop path as a labelled icon flow, used for the overview, the routing-peer example, and the recap. Wire the page into the docs sidebar and the troubleshooting hub. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
a9b5c3f99b
commit
451a5af235
@@ -1062,6 +1062,10 @@ export const docsNavigation = [
|
||||
title: 'Resource Connectivity',
|
||||
href: '/help/troubleshooting-resource-connectivity',
|
||||
},
|
||||
{
|
||||
title: 'Performance',
|
||||
href: '/help/troubleshooting-performance',
|
||||
},
|
||||
{
|
||||
title: 'Reverse Proxy',
|
||||
href: '/manage/reverse-proxy/troubleshooting',
|
||||
|
||||
161
src/components/PathFlow.jsx
Normal file
161
src/components/PathFlow.jsx
Normal file
@@ -0,0 +1,161 @@
|
||||
// A horizontal "stepper" that draws the path traffic takes from one peer to a
|
||||
// resource, hop by hop. Each hop is an icon card on a connecting line, with the
|
||||
// last hop optionally marked as the destination. Static and SSR-friendly (no
|
||||
// hooks), responsive, and horizontally scrollable on narrow screens.
|
||||
//
|
||||
// Monochrome inline SVG icons use `currentColor` so they inherit the card's
|
||||
// text color and work in both light and dark mode, matching TroubleshootingTiles.
|
||||
|
||||
const icons = {
|
||||
laptop: (
|
||||
<>
|
||||
<rect x="4" y="5" width="16" height="11" rx="1.5" />
|
||||
<path d="M2 20h20" />
|
||||
</>
|
||||
),
|
||||
router: (
|
||||
<>
|
||||
<rect x="4" y="13" width="16" height="7" rx="1.5" />
|
||||
<path d="M7.5 16.5h.01" />
|
||||
<path d="M11 16.5h5.5" />
|
||||
<path d="M12 13V9" />
|
||||
<path d="M9 9a4.2 4.2 0 0 1 6 0" />
|
||||
</>
|
||||
),
|
||||
cloud: <path d="M7 18a4 4 0 0 1 0-8 5 5 0 0 1 9.6-1.5A3.5 3.5 0 0 1 17 18H7Z" />,
|
||||
firewall: (
|
||||
<>
|
||||
<rect x="3" y="5" width="18" height="14" rx="1" />
|
||||
<path d="M3 10h18M3 14h18M9 5v5M15 5v5M6 10v4M12 10v4M18 10v4M9 14v5M15 14v5" />
|
||||
</>
|
||||
),
|
||||
routingPeer: (
|
||||
<>
|
||||
<path d="M6 6l6 6-6 6" />
|
||||
<path d="M13 6l6 6-6 6" />
|
||||
</>
|
||||
),
|
||||
server: (
|
||||
<>
|
||||
<rect x="4" y="4" width="16" height="6" rx="1.5" />
|
||||
<rect x="4" y="14" width="16" height="6" rx="1.5" />
|
||||
<path d="M8 7h.01M8 17h.01" />
|
||||
</>
|
||||
),
|
||||
resource: (
|
||||
<>
|
||||
<path d="M7 5a11 11 0 0 1 0 14" />
|
||||
<path d="M11 8a6.5 6.5 0 0 1 0 8" />
|
||||
<path d="M15 10.5a2.8 2.8 0 0 1 0 3" />
|
||||
</>
|
||||
),
|
||||
database: (
|
||||
<>
|
||||
<ellipse cx="12" cy="6" rx="7" ry="3" />
|
||||
<path d="M5 6v12c0 1.7 3.1 3 7 3s7-1.3 7-3V6" />
|
||||
<path d="M5 12c0 1.7 3.1 3 7 3s7-1.3 7-3" />
|
||||
</>
|
||||
),
|
||||
}
|
||||
|
||||
function StepIcon({ name, className }) {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth={1.5}
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className={className}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{icons[name] ?? icons.resource}
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A left-to-right path of hops, each a labelled icon card on a connecting line.
|
||||
*
|
||||
* @param {Array<{
|
||||
* icon: string, // key into the inline icon set
|
||||
* title: string,
|
||||
* label?: string, // defaults to "Step N", or "Destination" when destination is true
|
||||
* description?: string, // hidden in compact mode
|
||||
* destination?: boolean // orange ring + orange label for the final hop
|
||||
* }>} steps
|
||||
* @param {string} [caption] - Optional caption under the flow
|
||||
* @param {boolean} [compact] - Smaller cards, titles only (used in the recap)
|
||||
*/
|
||||
export function PathFlow({ steps = [], caption, compact = false }) {
|
||||
const n = steps.length
|
||||
const iconBox = compact ? 'h-11 w-11 rounded-xl' : 'h-14 w-14 rounded-2xl'
|
||||
const iconSize = compact ? 'h-5 w-5' : 'h-6 w-6'
|
||||
const minW = compact ? 'min-w-[84px]' : 'min-w-[108px]'
|
||||
|
||||
return (
|
||||
<figure className="not-prose my-8">
|
||||
<div className="overflow-x-auto pb-2">
|
||||
<ol className="flex min-w-full items-start">
|
||||
{steps.map((step, i) => {
|
||||
const isDest = !!step.destination
|
||||
return (
|
||||
<li
|
||||
key={i}
|
||||
className={`relative flex flex-1 flex-col items-center px-1.5 text-center ${minW}`}
|
||||
>
|
||||
<div className="relative flex h-14 w-full items-center justify-center">
|
||||
{i > 0 && (
|
||||
<span
|
||||
className="absolute left-0 top-1/2 h-px w-1/2 -translate-y-1/2 bg-netbird/40"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
{i < n - 1 && (
|
||||
<span
|
||||
className="absolute right-0 top-1/2 h-px w-1/2 -translate-y-1/2 bg-netbird/40"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={`relative z-10 flex items-center justify-center bg-zinc-50 text-netbird ring-1 ring-inset dark:bg-white/5 ${iconBox} ${
|
||||
isDest
|
||||
? 'ring-netbird/60 dark:ring-netbird/60'
|
||||
: 'ring-zinc-900/10 dark:ring-white/10'
|
||||
}`}
|
||||
>
|
||||
<StepIcon name={step.icon} className={iconSize} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<span
|
||||
className={`mt-3 text-[0.65rem] font-semibold uppercase tracking-wider ${
|
||||
isDest
|
||||
? 'text-netbird'
|
||||
: 'text-zinc-400 dark:text-zinc-500'
|
||||
}`}
|
||||
>
|
||||
{step.label ?? (isDest ? 'Destination' : `Step ${i + 1}`)}
|
||||
</span>
|
||||
<span className="mt-1 text-sm font-semibold text-zinc-900 dark:text-white">
|
||||
{step.title}
|
||||
</span>
|
||||
{!compact && step.description && (
|
||||
<span className="mt-1 text-xs leading-5 text-zinc-600 dark:text-zinc-400">
|
||||
{step.description}
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ol>
|
||||
</div>
|
||||
{caption && (
|
||||
<figcaption className="mt-2 text-center text-xs text-zinc-500 dark:text-zinc-400">
|
||||
{caption}
|
||||
</figcaption>
|
||||
)}
|
||||
</figure>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user