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;
}
}
CDN Chart.js
========== HEADER / KONTROL ==========
========== TABEL ANGGOTA ==========
========== HASIL DISTRIBUSI ==========
========== KEGAGALAN REDISTRIBUSI ==========
========== VISUALISASI HASH RING ==========
========== BANTUAN / KONSEP ==========
Penganalisis Distribusi Kumpulan Penyeimbang Beban
Simulasikan bagaimana algoritma penyeimbangan beban yang berbeda mendistribusikan lalu lintas ke seluruh anggota kumpulan. Modelkan skenario kegagalan dan bandingkan efisiensi redistribusi.
Algoritma & Jumlah Sesi
Penggeser jumlah sesi
Simulasi kegagalan
Volume Lalu Lintas
Manajemen anggota kumpulan
Anggota Pangkalan
Simulasi Skenario Kegagalan
Cara kerjanya:IP klien diambil sampelnya dari subnet /16 (10.0.0.0/16).
Untuk hashing berbasis sumber, setiap IP klien unik dipetakan secara deterministik ke anggota.
Round robin mengabaikan IP klien dan mendistribusikan secara berurutan. Tertimbang menggunakan proporsional
tugas acak. Hashing yang konsisten menempatkan klien dan anggota pada ring virtual.
Anggota Pangkalan
| PENGENAL | IP:Pelabuhan | Berat | Status | Tindakan |
|---|
Hasil Distribusi
Skor keseimbangan + penjelasan algoritma
Kisi metrik
Bagan batang
Baris detail anggota
Distribusi Sesi per Anggota
Analisis Redistribusi Kegagalan
Cincin Hash yang Konsisten
Membaca cincin:Setiap anggota ditempatkan di beberapa titik di sekitar ring
(node virtual). IP klien di-hash ke posisi di ring, lalu permintaan dikirim
ke anggota terdekat searah jarum jam. Menambah atau menghapus anggota hanya mempengaruhi alurnya
dering yang dimilikinya — meminimalkan gangguan sesi.
Referensi Algoritma
Usul
Sesi ditugaskan secara berurutan: anggota 1, 2, 3, ..., N, 1, 2, ... Setiap anggota
menerima tepat 1/N dari semua permintaan. Mengabaikan kapasitas server dan afinitas klien.
Sederhana dan dapat diprediksi tetapi gagal pada perangkat keras yang heterogen.
Sumber IP Hash
Hash dari modul IP klien, jumlah anggota memilih backend. Klien yang sama
selalu menjangkau anggota yang sama — berguna untuk aplikasi stateful. Menambah atau menghapus
ada perombakan anggotasemuapemetaan klien (N perubahan menjadi (N-1)/N semua sesi).
Tertimbang
Setiap anggota menerima bagian yang sebanding dengan beratnya relatif terhadap berat totalnya
kolam renang. Seorang anggota dengan bobot=4 mendapat 4x sesi dari anggota berbobot=1. Digunakan untuk memodelkan
kapasitas backend heterogen (misalnya, VM vs server bare-metal).
Hashing yang Konsisten
Anggota dan klien keduanya dipetakan ke dalam lingkaran melingkar melalui hashing. Setiap klien pergi
ke anggota terdekat searah jarum jam di atas ring. Node virtual (replika per anggota)
meningkatkan keseragaman distribusi. Ketika seorang anggota gagal, hanya sesinya yang berpindah ke
anggota berikutnya di ring — 1/N sesi terganggu vs. 100% untuk hashing modulo.