Load Balancer Pool Distribution Analyzer

.calc-header { margin-bottom: 30px; padding: 25px; background: linear-gradient(135deg, #FF6B6B 0%, #C92A2A 100%); border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); color: white; } .calc-header h2 { margin-top: 0; color: white; font-size: 28px; margin-bottom: 10px; } .calc-header p { margin: 10px 0 20px 0; opacity: 0.95; font-size: 15px; } .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 20px; } .form-grid-3 { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 15px; margin-top: 15px; } .form-group { display: flex; flex-direction: column; gap: 8px; } .form-group label { font-weight: 600; font-size: 14px; color: white; } .form-group input, .form-group select { padding: 12px; font-size: 15px; border: 2px solid rgba(255,255,255,0.3); border-radius: 6px; background: rgba(255,255,255,0.95); transition: all 0.3s ease; font-family: 'Courier New', monospace; } .form-group input:focus, .form-group select:focus { outline: none; border-color: #4CAF50; background: white; box-shadow: 0 0 0 3px rgba(76, 175, 80, 0.15); } .form-group select { cursor: pointer; font-family: inherit; } .submit-btn { padding: 14px 35px; font-size: 16px; background: #4CAF50; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold; transition: all 0.3s ease; box-shadow: 0 2px 4px rgba(0,0,0,0.2); margin-top: 15px; width: 100%; } .submit-btn:hover { background: #45a049; transform: translateY(-1px); box-shadow: 0 4px 8px rgba(0,0,0,0.3); } .submit-btn:active { background: #3d8b40; transform: translateY(0); } .secondary-btn { padding: 10px 20px; font-size: 14px; background: rgba(255,255,255,0.2); color: white; border: 2px solid rgba(255,255,255,0.5); border-radius: 6px; cursor: pointer; font-weight: bold; transition: all 0.3s ease; } .secondary-btn:hover { background: rgba(255,255,255,0.35); border-color: white; } .danger-btn { padding: 8px 14px; font-size: 13px; background: #e53935; color: white; border: none; border-radius: 4px; cursor: pointer; font-weight: bold; transition: all 0.2s ease; } .danger-btn:hover { background: #c62828; } .result-section { background: white; border: 1px solid #e0e0e0; border-radius: 8px; margin-top: 20px; overflow: hidden; box-shadow: 0 2px 4px rgba(0,0,0,0.05); transition: all 0.3s ease; display: none; } .result-section.show { display: block; } .result-section:hover { box-shadow: 0 4px 8px rgba(0,0,0,0.1); } .section-header { background: linear-gradient(135deg, #4CAF50 0%, #45a049 100%); color: white; padding: 15px 20px; } .section-header h3 { margin: 0; font-size: 18px; display: flex; align-items: center; gap: 10px; } .section-content { padding: 20px; background: #fafafa; } .data-row { display: flex; margin: 12px 0; padding: 10px; background: white; border-radius: 4px; border-left: 3px solid #4CAF50; align-items: center; } .data-label { font-weight: bold; color: #555; min-width: 220px; flex-shrink: 0; font-size: 14px; } .data-value { color: #333; font-family: 'Courier New', monospace; word-break: break-word; font-size: 18px; } .data-value.highlight { color: #4CAF50; font-weight: bold; font-size: 22px; } .data-value.warning { color: #FF6B6B; font-weight: bold; font-size: 22px; } .help-text { margin-top: 15px; font-size: 14px; color: rgba(255,255,255,0.9); background: rgba(0,0,0,0.1); padding: 10px 15px; border-radius: 4px; } .help-text strong { color: white; } /* Member list table */ .member-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 14px; } .member-table th { background: #f0f0f0; padding: 10px 12px; text-align: left; font-weight: 600; color: #444; border-bottom: 2px solid #ddd; } .member-table td { padding: 10px 12px; border-bottom: 1px solid #eee; vertical-align: middle; } .member-table tr:last-child td { border-bottom: none; } .member-table tr:hover td { background: #f9f9f9; } /* Status badge */ .status-badge { display: inline-block; padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: bold; text-transform: uppercase; letter-spacing: 0.5px; } .status-badge.up { background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7; } .status-badge.down { background: #ffebee; color: #c62828; border: 1px solid #ef9a9a; } /* Balance score ring */ .balance-score-container { display: flex; align-items: center; gap: 20px; padding: 15px; background: white; border-radius: 8px; border: 1px solid #e0e0e0; margin-bottom: 15px; } .balance-score-ring { width: 80px; height: 80px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 22px; font-weight: bold; color: white; flex-shrink: 0; box-shadow: 0 2px 8px rgba(0,0,0,0.2); } .balance-score-ring.excellent { background: linear-gradient(135deg, #43a047, #1b5e20); } .balance-score-ring.good { background: linear-gradient(135deg, #7cb342, #558b2f); } .balance-score-ring.fair { background: linear-gradient(135deg, #fb8c00, #e65100); } .balance-score-ring.poor { background: linear-gradient(135deg, #e53935, #b71c1c); } .balance-score-info { flex: 1; } .balance-score-info h4 { margin: 0 0 5px 0; font-size: 18px; color: #333; } .balance-score-info p { margin: 0; font-size: 13px; color: #666; line-height: 1.5; } /* Metrics grid */ .metrics-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px; } .metric-card { background: white; border: 1px solid #e0e0e0; border-radius: 8px; padding: 15px; text-align: center; border-top: 3px solid #4CAF50; } .metric-card .metric-value { font-size: 22px; font-weight: bold; color: #333; font-family: 'Courier New', monospace; } .metric-card .metric-label { font-size: 12px; color: #888; margin-top: 4px; } /* Chart container */ .chart-wrapper { background: white; border: 1px solid #e0e0e0; border-radius: 8px; padding: 20px; margin-bottom: 20px; } .chart-wrapper h4 { margin: 0 0 15px 0; color: #444; font-size: 15px; font-weight: 600; } /* Algorithm explanation */ .algo-explanation { background: #fff8e1; border: 1px solid #ffe082; border-radius: 6px; padding: 12px 15px; font-size: 13px; color: #5d4037; line-height: 1.6; margin-top: 10px; } .algo-explanation strong { color: #3e2723; } /* Hash ring visualization */ .ring-wrapper { display: flex; align-items: flex-start; gap: 20px; } #hashRingCanvas { border: 1px solid #e0e0e0; border-radius: 50%; display: block; flex-shrink: 0; } .ring-legend { flex: 1; } .ring-legend-item { display: flex; align-items: center; gap: 10px; padding: 6px 0; font-size: 13px; border-bottom: 1px solid #f0f0f0; } .ring-legend-dot { width: 14px; height: 14px; border-radius: 50%; flex-shrink: 0; } /* Redistribution info */ .redistribution-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; background: white; border-radius: 4px; border-left: 3px solid #FF6B6B; margin-bottom: 6px; font-size: 14px; } .redistribution-row .arrow { color: #FF6B6B; font-size: 18px; flex-shrink: 0; } .redistribution-row .move-label { color: #555; flex: 1; } .redistribution-row .move-count { font-family: 'Courier New', monospace; font-weight: bold; color: #333; } /* Slider styling */ .slider-group { display: flex; flex-direction: column; gap: 8px; margin-top: 5px; } .slider-group label { font-weight: 600; font-size: 14px; color: white; display: flex; justify-content: space-between; } .slider-group label span { font-family: 'Courier New', monospace; background: rgba(0,0,0,0.2); padding: 2px 8px; border-radius: 4px; font-size: 13px; } input[type="range"] { width: 100%; accent-color: #4CAF50; height: 6px; cursor: pointer; } /* Controls area inside header */ .header-controls { margin-top: 20px; } .control-group-label { font-weight: 600; font-size: 13px; color: rgba(255,255,255,0.8); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; margin-top: 18px; } .add-member-row { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; } .add-member-row .form-group { flex: 1; min-width: 120px; } /* Failure simulation section */ .failure-section { background: rgba(0,0,0,0.1); border-radius: 8px; padding: 15px; margin-top: 18px; } .failure-section .control-group-label { margin-top: 0; } .failure-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; } .failure-row .form-group { flex: 1; min-width: 140px; } .failure-btn-group { display: flex; gap: 8px; } /* Responsive design */ @media (max-width: 768px) { .form-grid, .form-grid-3 { grid-template-columns: 1fr; } .metrics-grid { grid-template-columns: 1fr 1fr; } .data-row { flex-direction: column; align-items: flex-start; } .data-label { margin-bottom: 4px; min-width: auto; } .ring-wrapper { flex-direction: column; } #hashRingCanvas { width: 220px !important; height: 220px !important; align-self: center; } .balance-score-container { flex-direction: column; text-align: center; } .add-member-row { flex-direction: column; } .add-member-row .form-group { min-width: auto; width: 100%; } .failure-row { flex-direction: column; } } @media (max-width: 480px) { .calc-header h2 { font-size: 22px; } .metrics-grid { grid-template-columns: 1fr; } } Chart.js CDN
========== OVERSKRIFT/KONTROLLER ===========

Load Balancer Pool Distribution Analyzer

Simuler, hvordan forskellige belastningsbalanceringsalgoritmer fordeler trafik på tværs af puljemedlemmer. Model fejlscenarier og sammenlign omfordelingseffektivitet.

Algoritme og antal sessioner
Skyder for antal sessioner
Trafikmængde
Ledelse af puljemedlemmer
Pool medlemmer
Fejlsimulering
Fejlscenariesimulering
Sådan fungerer det:Klient-IP'er er samplet fra et /16-undernet (10.0.0.0/16). Til kildebaseret hashing er hver unik klient-IP deterministisk kortlagt til et medlem. Round robin ignorerer klient-IP og distribuerer sekventielt. Vægtet anvendelser proportional tilfældig opgave. Konsekvent hashing placerer både klienter og medlemmer i en virtuel ring.
========== MEDLEMSTABEL ===========

Pool medlemmer

befolket af JS
ID IP:Port Vægt Status Handlinger
========== DISTRIBUTIONSRESULTATER ===========

Distributionsresultater

Balancescore + algoritmeforklaring
Metrik gitter
Søjlediagram

Sessionsfordeling pr. medlem

Medlemsdetaljerækker
========== FEJL-OMDISTRIBUTION ==========

Omfordelingsanalyse af fejl

========== VISUALISERING AF HASHRING ==========

Konsekvent Hash Ring

Læser ringen:Hvert medlem er placeret på flere punkter rundt om ringen (virtuelle noder). En klient-IP hashes til en position på ringen, hvorefter anmodningen sendes til nærmeste medlem med uret. Tilføjelse eller fjernelse af et medlem påvirker kun buen af ring det ejede - minimere sessionsforstyrrelser.
========== HJÆLP / KONCEPTER ===========

Algoritme reference

Round Robin
Sessioner tildeles sekventielt: medlem 1, 2, 3, ..., N, 1, 2, ... Hvert medlem modtager præcis 1/N af alle anmodninger. Ignorerer serverkapacitet og klienttilhørsforhold. Enkel og forudsigelig, men fejler hårdt på heterogen hardware.
Kilde IP Hash
En hash af klientens IP modulo medlemsantallet vælger backend. Samme klient når altid det samme medlem - nyttigt til stateful applikationer. Tilføjelse eller fjernelse et medlem blander sigalleklientkortlægninger (N ændres til (N-1)/N af alle sessioner).
Vægtet
Hvert medlem modtager en andel, der er proportional med dens vægt i forhold til den samlede vægt pool. Et medlem med vægt=4 får 4 gange så mange sessioner som et vægt=1 medlem. Brugt til at modellere heterogen backend-kapacitet (f.eks. en VM vs en bare-metal-server).
Konsekvent hashing
Medlemmer og klienter er begge kortlagt på en cirkulær ring via hashing. Hver klient går til nærmeste medlem med uret på ringen. Virtuelle noder (replikaer pr. medlem) forbedre ensartet fordeling. Når et medlem fejler, flytter kun dets sessioner til næste medlem på ringen — 1/N sessioner forstyrret vs. 100 % for modulo hashing.