Performance optimization engagement for a 7-host Proxmox R&D cluster.
Captures the accumulated work across host tuning, network analysis,
fleet assessment, and kubernetes architecture planning.
Contents:
- Host-side tunings (scripts/): CPU governor, swappiness, BBR, NFS
nconnect, tuned profiles -- complete on 5 of 7 hosts
- Validation + benchmarking scripts: iperf matrix, bond/NFS fixes
- Collected host data (returned-logs/): check.sh output from all 7
hosts + iperf results, including newly-validated pfv-tsys9
- AGENTS.md: operating context for AI agents
- PROJECT.md: board-ready fleet assessment with VM placement and
storage redundancy analysis (40 VMs across 7 hosts)
- K8S.md: kubernetes architecture deep-dive covering cnode/wnode
distribution, StorageClass design, and ETL/HPC workload planning
💘 Generated with Crush
Assisted-by: Crush:glm-5.2
154 lines
5.8 KiB
Bash
Executable File
154 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
###############################################################################
|
|
# lacp-rx-distribution.sh (HOST-NATIVE version)
|
|
#
|
|
# Runs ON a host (tsys6 or tsys7). Auto-detects role by hostname:
|
|
# - On tsys6 (receiver): starts iperf3 -s -1 (one-shot), snapshots local
|
|
# bond0 slave RX counters before+after, writes verdict + log.
|
|
# - On tsys7 (sender): snapshots local bond0 slave TX counters before+
|
|
# after, runs iperf3 -c <peer> -P 8 -t 12.
|
|
#
|
|
# Each side writes only its own counters. No inter-host SSH required.
|
|
# iperf3 -s -1 (one-shot) handles client/server coordination.
|
|
#
|
|
# Output: /root/lacp-rx-{receiver,sender}.log
|
|
###############################################################################
|
|
set -uo pipefail
|
|
|
|
DURATION="${LACP_TEST_SECS:-12}"
|
|
STREAMS="${LACP_STREAMS:-8}"
|
|
PEER_RX_IP="10.100.100.6" # tsys6 storage IP (receiver)
|
|
PEER_TX_IP="10.100.100.7" # tsys7 storage IP (sender)
|
|
LOG_DIR="/root"
|
|
BOND="bond0"
|
|
|
|
# Snapshot per-slave byte counters from $BOND. Output: "<slave> rx tx\n" sorted.
|
|
snapshot() {
|
|
awk '/^Slave Interface:/{print $3}' "/proc/net/bonding/$BOND" | while read -r s; do
|
|
[ -n "$s" ] || continue
|
|
rx=$(cat "/sys/class/net/$s/statistics/rx_bytes" 2>/dev/null || echo 0)
|
|
tx=$(cat "/sys/class/net/$s/statistics/tx_bytes" 2>/dev/null || echo 0)
|
|
printf '%s %s %s\n' "$s" "$rx" "$tx"
|
|
done | sort
|
|
}
|
|
|
|
# Compute per-slave deltas. $1=label, $2=col(2=rx,3=tx), $3=before, $4=after.
|
|
analyze() {
|
|
local label="$1" col="$2" before="$3" after="$4"
|
|
join "$before" "$after" | awk -v col="$col" -v lbl="$label" '
|
|
{
|
|
slave=$1
|
|
b = (col==2 ? $2 : $3)+0
|
|
a = (col==2 ? $4 : $5)+0
|
|
d = a - b; if (d < 0) d = 0
|
|
delta[slave]=d; bef[slave]=b; aft[slave]=a
|
|
order[++n]=slave; total+=d
|
|
}
|
|
END {
|
|
printf "\n--- %s (bytes) ---\n", lbl
|
|
printf " %-12s %14s %14s %14s %8s\n", "SLAVE", "BEFORE", "AFTER", "DELTA", "PCT"
|
|
for (i=1;i<=n;i++){
|
|
s=order[i]
|
|
pct = (total>0 ? 100*delta[s]/total : 0)
|
|
printf " %-12s %14d %14d %14d %7.1f%%\n", s, bef[s], aft[s], delta[s], pct
|
|
}
|
|
printf " %-12s %14s %14s %14d %8s\n", "TOTAL", "", "", total, "100.0%"
|
|
}'
|
|
}
|
|
|
|
# Dominant-slave pct for the verdict line. $1=col, $2=before, $3=after.
|
|
dominant() {
|
|
join "$2" "$3" | awk -v col="$1" '
|
|
{ b=(col==2?$2:$3)+0; a=(col==2?$4:$5)+0; d=a-b; if(d<0)d=0; tot+=d; delta[$1]=d }
|
|
END { m=0; ms=""; for (s in delta){ if (delta[s]>m){m=delta[s]; ms=s} }
|
|
printf "%.1f %s", (tot>0?100*m/tot:0), ms }'
|
|
}
|
|
|
|
HOST="$(uname -n)"
|
|
HOST="${HOST%%.*}"
|
|
case "$HOST" in
|
|
*tsys6) ROLE="receiver"; LOG="$LOG_DIR/lacp-rx-receiver.log" ;;
|
|
*tsys7) ROLE="sender"; LOG="$LOG_DIR/lacp-rx-sender.log" ;;
|
|
*) echo "ERROR: not running on tsys6 or tsys7 (hostname=$HOST)"; exit 2 ;;
|
|
esac
|
|
|
|
TMP="$(mktemp -d)"
|
|
trap 'rm -rf "$TMP"' EXIT
|
|
|
|
{
|
|
echo "=== LACP per-slave distribution ($ROLE) ==="
|
|
echo "Host: $HOST Role: $ROLE"
|
|
echo "Date: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "Bond: $BOND"
|
|
echo ""
|
|
echo "--- $BOND state ---"
|
|
grep -E "Bonding Mode|Transmit Hash|Number of ports|Partner Mac|Slave Interface|Link" \
|
|
"/proc/net/bonding/$BOND" 2>&1
|
|
echo ""
|
|
} | tee "$LOG"
|
|
|
|
snapshot > "$TMP/before"
|
|
|
|
if [ "$ROLE" = "receiver" ]; then
|
|
echo "[receiver] starting one-shot iperf3 server on $PEER_RX_IP ..."
|
|
pkill -x iperf3 2>/dev/null; sleep 0.5
|
|
nohup iperf3 -s -1 -B "$PEER_RX_IP" > "$TMP/iperf.out" 2>&1 &
|
|
SRV_PID=$!
|
|
# Wait for the server to be ready (brief), then wait for it to exit
|
|
# (one-shot server exits after serving one client).
|
|
for _ in $(seq 1 60); do
|
|
kill -0 "$SRV_PID" 2>/dev/null || break
|
|
sleep 1
|
|
done
|
|
wait "$SRV_PID" 2>/dev/null
|
|
echo "[receiver] iperf3 server finished."
|
|
else
|
|
# sender: wait briefly for receiver to be listening, then run client.
|
|
echo "[sender] waiting 3s for receiver to listen, then running iperf3 client..."
|
|
sleep 3
|
|
iperf3 -c "$PEER_RX_IP" -B "$PEER_TX_IP" -P "$STREAMS" -t "$DURATION" -l 128k -O 2 \
|
|
> "$TMP/iperf.out" 2>&1
|
|
echo "[sender] iperf3 client finished (exit=$?)."
|
|
fi
|
|
|
|
snapshot > "$TMP/after"
|
|
|
|
{
|
|
echo ""
|
|
echo "--- iperf3 output (raw tail) ---"
|
|
tail -25 "$TMP/iperf.out"
|
|
echo ""
|
|
if [ "$ROLE" = "receiver" ]; then
|
|
analyze "Receiver RX (THE key column)" 2 "$TMP/before" "$TMP/after"
|
|
dom="$(dominant 2 "$TMP/before" "$TMP/after")"
|
|
pct=${dom%% *}; top=${dom##* }
|
|
echo ""
|
|
echo "==================================================================="
|
|
if awk -v p="$pct" 'BEGIN{exit !(p>=90)}'; then
|
|
echo " VERDICT: SWITCH NOT distributing across $HOST's two ports"
|
|
echo " Dominant slave '$top' = ${pct}% of RX -> hash not effective"
|
|
echo " on this LAG. Action: verify/bounce pfv-r3-tor-stor port-channel."
|
|
else
|
|
echo " VERDICT: switch IS distributing (top slave '$top' = ${pct}%)."
|
|
echo " Cap is host-side: softirq/CPU/bridge/NIC coalescing."
|
|
fi
|
|
echo "==================================================================="
|
|
else
|
|
analyze "Sender TX (control: should split if host hash=layer3+4)" 3 "$TMP/before" "$TMP/after"
|
|
dom="$(dominant 3 "$TMP/before" "$TMP/after")"
|
|
pct=${dom%% *}; top=${dom##* }
|
|
echo ""
|
|
echo "==================================================================="
|
|
if awk -v p="$pct" 'BEGIN{exit !(p>=90)}'; then
|
|
echo " VERDICT: host TX NOT distributing (top slave '$top' = ${pct}%)."
|
|
echo " Host xmit_hash_policy is NOT effective despite /proc/net/bonding."
|
|
else
|
|
echo " VERDICT: host TX distributing OK (top slave '$top' = ${pct}%)."
|
|
fi
|
|
echo "==================================================================="
|
|
fi
|
|
} | tee -a "$LOG"
|
|
|
|
echo ""
|
|
echo "Log written: $LOG"
|