Files

584 lines
42 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Sizing Calculator — Mek-Tech</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
<link rel="stylesheet" href="/css/dynamic.css">
<link rel="icon" href="/img/favicon.svg" type="image/svg+xml">
<style>
:root{--sb-w:200px;--hdr-h:48px}
html,body{height:100%;margin:0;padding:0}
body{background:var(--bg);font-family:'Inter',-apple-system,sans-serif}
.app-layout{display:flex;min-height:100vh;padding-top:var(--hdr-h)}
.sidebar{position:fixed;top:var(--hdr-h);left:0;width:var(--sb-w);height:calc(100vh - var(--hdr-h));background:var(--bg-nav);border-right:1px solid var(--border);display:flex;flex-direction:column;z-index:50;overflow-y:auto}
.sb-brand{padding:.75rem 1rem;border-bottom:1px solid var(--border)}
.sb-brand h2{font-size:.8rem;font-weight:600;color:var(--text)}
.sb-brand p{font-size:.6rem;color:var(--text-dim)}
.sb-nav{flex:1;padding:.35rem 0}
.sb-item{display:flex;align-items:center;gap:.5rem;padding:.45rem .85rem;margin:1px .4rem;border-radius:var(--radius);cursor:pointer;font-size:.78rem;color:var(--text-muted);transition:all .12s;border:none;background:none;width:calc(100% - .8rem);text-align:left;font-family:inherit}
.sb-item:hover{color:var(--text);background:var(--border-light)}
.sb-item.active{color:var(--accent);background:rgba(88,166,255,.08);font-weight:600}
.sb-item .sb-icon{width:20px;text-align:center;font-size:.85rem;flex-shrink:0}
.main-area{flex:1;margin-left:var(--sb-w);padding:1.25rem 1.5rem 3rem;max-width:1200px}
.page-hdr{margin-bottom:1.25rem}
.page-hdr h1{font-size:1.4rem;color:var(--text);font-weight:600}
.page-hdr p{font-size:.8rem;color:var(--text-muted);margin-top:.1rem}
.sel-bar{display:flex;gap:.5rem;margin-bottom:1.25rem;flex-wrap:wrap}
.sel-bar select{padding:.45rem .7rem;font-size:.8rem;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);color:var(--text);cursor:pointer;min-width:200px}
.sel-bar select:focus{outline:none;border-color:var(--accent)}
.calc-grid{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
@media(max-width:768px){.calc-grid{grid-template-columns:1fr}}
.calc-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:1.25rem}
.calc-card h3{font-size:.75rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.3px;margin-bottom:1rem}
.calc-card h4{font-size:.85rem;color:var(--text);margin-bottom:.35rem}
.calc-input{margin-bottom:.75rem}
.calc-input label{display:block;font-size:.72rem;color:var(--text-muted);margin-bottom:.2rem}
.calc-input input,.calc-input select{width:100%;padding:.4rem .6rem;font-size:.8rem;background:var(--bg);border:1px solid var(--border);border-radius:var(--radius);color:var(--text)}
.calc-input input:focus{outline:none;border-color:var(--accent)}
.result-card{background:var(--bg-nav);border:1px solid var(--border);border-radius:var(--radius);padding:1rem;margin-top:.5rem}
.result-card .r-row{display:flex;justify-content:space-between;align-items:center;padding:.35rem 0;border-bottom:1px solid var(--border-light)}
.result-card .r-row:last-child{border-bottom:none}
.result-card .r-label{font-size:.75rem;color:var(--text-muted)}
.result-card .r-val{font-size:.85rem;color:var(--text);font-weight:600}
.result-card .r-val.accent{color:var(--accent)}
.result-card .r-val.green{color:var(--green)}
.result-card .r-val.orange{color:var(--orange)}
.result-card .r-val.purple{color:var(--purple)}
.r-highlight{background:rgba(88,166,255,.06);border-radius:var(--radius);padding:.6rem .75rem;margin-top:.5rem}
.r-highlight .rh-title{font-size:.65rem;color:var(--text-muted);text-transform:uppercase;letter-spacing:.3px}
.r-highlight .rh-val{font-size:1.1rem;font-weight:700;color:var(--accent);margin-top:.1rem}
.r-recommendation{background:var(--green-bg);border:1px solid var(--green);border-radius:var(--radius);padding:.75rem;margin-top:.75rem}
.r-recommendation .rr-title{font-size:.65rem;color:var(--green);text-transform:uppercase;letter-spacing:.3px;margin-bottom:.25rem}
.r-recommendation .rr-text{font-size:.78rem;color:var(--text)}
.desc-text{font-size:.78rem;color:var(--text-muted);line-height:1.5;margin-bottom:.75rem}
</style>
<script src="https://unpkg.com/lucide@latest"></script></head>
<body>
<nav class="navbar"><div class="nav-inner"><a href="/" class="nav-brand"><img src="/img/logo.svg" class="nav-logo" alt="Mek-Tech"></a><div style="display:flex;align-items:center;gap:.4rem"><a href="/" class="nav-icon-btn" title="Dashboard"><i data-lucide="layout-dashboard" style="width:15px;height:15px"></i> Dashboard</a><button class="theme-toggle" id="themeToggle" onclick="toggleTheme()"></button><a href="/auth/logout" class="nav-icon-btn" style="color:var(--red)"><i data-lucide="log-out" style="width:15px;height:15px"></i> Uitloggen</a></div></div></nav>
<div class="app-layout">
<aside class="sidebar">
<div class="sb-brand"><h2>Mek-Tech Sizing</h2><p>Data Architecture Calculator</p></div>
<nav class="sb-nav">
<button class="sb-item active" data-platform="kafka"><span class="sb-icon">📨</span> Apache Kafka</button>
<button class="sb-item" data-platform="spark"><span class="sb-icon">⚡</span> Apache Spark</button>
<button class="sb-item" data-platform="minio"><span class="sb-icon">💾</span> MinIO / S3</button>
<button class="sb-item" data-platform="sap-hana"><span class="sb-icon">🔷</span> SAP HANA</button>
<button class="sb-item" data-platform="warehouse"><span class="sb-icon">🏛</span> Data Warehouse</button>
<button class="sb-item" data-platform="vector"><span class="sb-icon">🧠</span> Vector Store</button>
<button class="sb-item" data-platform="k8s"><span class="sb-icon">⎈</span> Kubernetes</button>
<button class="sb-item" data-platform="hadoop"><span class="sb-icon">📊</span> Hadoop HDFS</button>
<button class="theme-toggle" id="themeToggle" onclick="toggleTheme()"></button></nav>
</aside>
<div class="main-area">
<div class="page-hdr">
<h1>Data Architecture Sizing Calculator</h1>
<p>Best-practice dimensionering voor enterprise data platforms — gebaseerd op 15+ jaar ervaring</p>
</div>
<div class="sel-bar">
<select id="platformSelect" onchange="switchPlatform(this.value)">
<option value="kafka">Apache Kafka / Event Streaming</option>
<option value="spark">Apache Spark / Flink</option>
<option value="minio">MinIO / S3 Object Storage</option>
<option value="sap-hana">SAP HANA Platform</option>
<option value="warehouse">Data Warehouse / Iceberg</option>
<option value="vector">Vector Store / Embeddings</option>
<option value="k8s">Kubernetes Cluster</option>
<option value="hadoop">Hadoop HDFS / Data Lake</option>
</select>
</div>
<!-- KAFKA -->
<div class="calc-panel" id="panel-kafka">
<div class="desc-text">Bereken de optimale Kafka cluster configuratie op basis van throughput, retentie en replicatie. Geschikt voor Confluent, Red Hat AMQ Streams, en Apache Kafka.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Berichten per seconde (msg/s)</label><input type="number" id="k-msgs" value="500000" oninput="calcKafka()"></div>
<div class="calc-input"><label>Gem. berichtgrootte (KB)</label><input type="number" id="k-msgSize" value="5" step="0.5" oninput="calcKafka()"></div>
<div class="calc-input"><label>Retentie (dagen)</label><input type="number" id="k-retention" value="7" oninput="calcKafka()"></div>
<div class="calc-input"><label>Replicatie factor</label><select id="k-replicas" onchange="calcKafka()"><option value="2">2 (Standard)</option><option value="3" selected>3 (Enterprise)</option><option value="4">4 (Mission Critical)</option></select></div>
<div class="calc-input"><label>Disk snelheid (MB/s per disk)</label><select id="k-diskSpeed" onchange="calcKafka()"><option value="200">HDD 7200rpm (~200 MB/s)</option><option value="550" selected>SSD SATA (~550 MB/s)</option><option value="3500">NVMe (~3500 MB/s)</option><option value="7000">Optane (~7000 MB/s)</option></select></div>
<div class="calc-input"><label>Compressie</label><select id="k-compress" onchange="calcKafka()"><option value="1">Geen (1:1)</option><option value="0.4" selected>Snappy / LZ4 (0.4x)</option><option value="0.25">ZSTD (0.25x)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Doorvoer (bruto)</span><span class="r-val accent" id="k-throughput">—</span></div>
<div class="r-row"><span class="r-label">Doorvoer (netto na compressie)</span><span class="r-val" id="k-throughputNet">—</span></div>
<div class="r-row"><span class="r-label">Opslag per dag</span><span class="r-val" id="k-daily">—</span></div>
<div class="r-row"><span class="r-label">Totale opslag (retentie)</span><span class="r-val" id="k-total">—</span></div>
<div class="r-row"><span class="r-label">Totaal met replicatie</span><span class="r-val orange" id="k-totalRep">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen partitions</span><span class="r-val" id="k-partitions">—</span></div>
<div class="r-row"><span class="r-label">Min. brokers (performance)</span><span class="r-val" id="k-brokers">—</span></div>
</div>
<div class="r-highlight">
<div class="rh-title">Aanbevolen Cluster Configuratie</div>
<div class="rh-val" id="k-clusterRec">—</div>
</div>
<div class="r-recommendation" id="k-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Voor enterprise Kafka deployments raden wij 3 replication factor aan met minstens 3 brokers. Gebruik NVMe storage voor critical workloads, SSD voor standard. Partition count = max(3 × brokers, throughput / 10MB).</div>
</div>
</div>
</div>
</div>
<!-- SPARK -->
<div class="calc-panel" id="panel-spark" style="display:none">
<div class="desc-text">Dimensionering voor Apache Spark en Flink workloads. Optimaliseer executors, cores, memory en dynamic allocation voor batch en streaming.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Data volume per dag (GB)</label><input type="number" id="s-data" value="500" oninput="calcSpark()"></div>
<div class="calc-input"><label>Processing type</label><select id="s-type" onchange="calcSpark()"><option value="batch">Batch (dagelijks)</option><option value="stream" selected>Streaming (real-time)</option><option value="ml">ML Training</option></select></div>
<div class="calc-input"><label>Gewenste processing time (min)</label><input type="number" id="s-time" value="30" oninput="calcSpark()"></div>
<div class="calc-input"><label>Beschikbaar geheugen per node (GB)</label><select id="s-ram" onchange="calcSpark()"><option value="64">64 GB</option><option value="128">128 GB</option><option value="256" selected>256 GB</option><option value="512">512 GB</option><option value="1024">1024 GB</option></select></div>
<div class="calc-input"><label>CPU cores per node</label><select id="s-cores" onchange="calcSpark()"><option value="16">16 cores</option><option value="32" selected>32 cores</option><option value="64">64 cores</option><option value="96">96 cores</option></select></div>
<div class="calc-input"><label>Dynamic allocation</label><select id="s-dynamic" onchange="calcSpark()"><option value="0">Uit</option><option value="1" selected>Aan (min-max)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Aanbevolen executors</span><span class="r-val accent" id="s-executors">—</span></div>
<div class="r-row"><span class="r-label">Cores per executor</span><span class="r-val" id="s-coresPerExec">—</span></div>
<div class="r-row"><span class="r-label">Memory per executor (GB)</span><span class="r-val" id="s-memPerExec">—</span></div>
<div class="r-row"><span class="r-label">Totale cluster RAM (GB)</span><span class="r-val purple" id="s-totalRam">—</span></div>
<div class="r-row"><span class="r-label">Totale vCores</span><span class="r-val" id="s-totalCores">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen worker nodes</span><span class="r-val green" id="s-workers">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Totale cluster capaciteit</div><div class="rh-val" id="s-clusterRec">—</div></div>
<div class="r-recommendation" id="s-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Standaard Spark config: 5 cores per executor, 4-8 GB overhead per executor. Voor streaming gebruik 2-3 cores per executor. Altijd dynamic allocation inschakelen voor fluctuaties.</div>
</div>
</div>
</div>
</div>
<!-- MINIO -->
<div class="calc-panel" id="panel-minio" style="display:none">
<div class="desc-text">Sizing voor MinIO object storage clusters. Berekent erasure coding, drive configuratie en totale bruikbare capaciteit. Geschikt voor S3-compatible storage.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Bruto opslag capaciteit (TB)</label><input type="number" id="m-capacity" value="500" oninput="calcMinio()"></div>
<div class="calc-input"><label>Drive grootte (TB)</label><select id="m-driveSize" onchange="calcMinio()"><option value="4">4 TB</option><option value="8">8 TB</option><option value="14">14 TB</option><option value="18">18 TB</option><option value="22" selected>22 TB</option><option value="30">30 TB</option></select></div>
<div class="calc-input"><label>Erasure Code (EC)</label><select id="m-ec" onchange="calcMinio()"><option value="4:2">4 data + 2 parity (1.5x)</option><option value="8:4" selected>8 data + 4 parity (1.5x)</option><option value="12:4">12 data + 4 parity (1.33x)</option><option value="10:6">10 data + 6 parity (1.6x)</option><option value="16:8">16 data + 8 parity (1.5x)</option></select></div>
<div class="calc-input"><label>Redundantie</label><select id="m-redundancy" onchange="calcMinio()"><option value="no">Geen (single node)</option><option value="rack" selected>Rack-aware (3 racks)</option><option value="region">Region-aware (2 regio's)</option></select></div>
<div class="calc-input"><label>Compressie (avg)</label><select id="m-compress" onchange="calcMinio()"><option value="1">Geen</option><option value="0.6" selected>Gemiddeld (0.6x)</option><option value="0.3">Hoog (0.3x)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Aantal drives</span><span class="r-val" id="m-drives">—</span></div>
<div class="r-row"><span class="r-label">Aantal nodes</span><span class="r-val" id="m-nodes">—</span></div>
<div class="r-row"><span class="r-label">Bruto capaciteit</span><span class="r-val" id="m-gross">—</span></div>
<div class="r-row"><span class="r-label">EC overhead factor</span><span class="r-val" id="m-ecFactor">—</span></div>
<div class="r-row"><span class="r-label">Bruikbaar na EC</span><span class="r-val accent" id="m-usable">—</span></div>
<div class="r-row"><span class="r-label">Effectief na compressie</span><span class="r-val green" id="m-effective">—</span></div>
<div class="r-row"><span class="r-label">Min. nodes aanbevolen</span><span class="r-val purple" id="m-minNodes">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Configuratie</div><div class="rh-val" id="m-clusterRec">—</div></div>
<div class="r-recommendation" id="m-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Minio EC:8+4 is de sweet spot voor enterprise — 1.5x overhead met 4 parity failures tolerantie. Gebruik minimaal 12 nodes (24 drives) voor productie. Rack-aware deployment voor datacenter resiliency.</div>
</div>
</div>
</div>
</div>
<!-- SAP HANA -->
<div class="calc-panel" id="panel-sap-hana" style="display:none">
<div class="desc-text">SAP HANA memory en platform sizing. Berekent vereist geheugen, CPU en opslag op basis van SAP best practices en ervaringscijfers.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>SAP module / workload</label><select id="h-module" onchange="calcHana()"><option value="s4hana" selected>S/4HANA</option><option value="bw">BW/4HANA</option><option value="bpc">BPC</option><option value="slt">SLT</option><option value="mix">Mixed workload</option></select></div>
<div class="calc-input"><label>Actieve gebruikers</label><input type="number" id="h-users" value="500" oninput="calcHana()"></div>
<div class="calc-input"><label>Data volume (GB, huidig)</label><input type="number" id="h-data" value="500" oninput="calcHana()"></div>
<div class="calc-input"><label>Groei per jaar (%)</label><input type="number" id="h-growth" value="20" oninput="calcHana()"></div>
<div class="calc-input"><label>HA (High Availability)</label><select id="h-ha" onchange="calcHana()"><option value="1">Scale-up (standby)</option><option value="0">Geen HA</option></select></div>
<div class="calc-input"><label>DR (Disaster Recovery)</label><select id="h-dr" onchange="calcHana()"><option value="1">Async replicatie</option><option value="0" selected>Geen DR</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Berekend geheugen (RAM)</span><span class="r-val accent" id="h-ram">—</span></div>
<div class="r-row"><span class="r-label">waarvan data footprint</span><span class="r-val" id="h-dataFP">—</span></div>
<div class="r-row"><span class="r-label">waarvan overhead / growth</span><span class="r-val" id="h-overhead">—</span></div>
<div class="r-row"><span class="r-label">CPU cores aanbevolen</span><span class="r-val" id="h-cpu">—</span></div>
<div class="r-row"><span class="r-label">Opslag (data + logs)</span><span class="r-val orange" id="h-storage">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen node type</span><span class="r-val purple" id="h-nodeType">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Totale HANA Platform Sizing</div><div class="rh-val" id="h-clusterRec">—</div></div>
<div class="r-recommendation" id="h-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">SAP HANA geheugen: 1GB RAM per 50GB data (S/4HANA) of 1:4 (BW/4HANA). Tel 20-30% overhead voor growth en workloads. Scale-up voor performance, scale-out voor capaciteit. Gebruik minimaal 2x data voor opslag (logs + backups).</div>
</div>
</div>
</div>
</div>
<!-- DATA WAREHOUSE -->
<div class="calc-panel" id="panel-warehouse" style="display:none">
<div class="desc-text">Dimensionering voor Data Warehouse en Lakehouse architecturen (Iceberg, Snowflake, Redshift, BigQuery). Berekent compute/storage verhouding.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Bruto data volume (TB)</label><input type="number" id="w-volume" value="100" oninput="calcWarehouse()"></div>
<div class="calc-input"><label>Daily change (ingest/CDC)</label><input type="number" id="w-ingest" value="500" oninput="calcWarehouse()"><span style="font-size:.6rem;color:var(--text-dim)">GB per dag</span></div>
<div class="calc-input"><label>Concurrent queries</label><select id="w-queries" onchange="calcWarehouse()"><option value="5">5 (Small)</option><option value="20" selected>20 (Medium)</option><option value="50">50 (Large)</option><option value="100">100 (Enterprise)</option></select></div>
<div class="calc-input"><label>Query complexiteit</label><select id="w-complexity" onchange="calcWarehouse()"><option value="simple">Simpel (SELECT/WHERE)</option><option value="moderate" selected>Gemiddeld (JOINs, aggregaties)</option><option value="complex">Complex (multi-JOIN, window)</option></select></div>
<div class="calc-input"><label>Architectuur</label><select id="w-arch" onchange="calcWarehouse()"><option value="lakehouse" selected>Lakehouse (Iceberg + Trino)</option><option value="cloud">Cloud DW (Snowflake)</option><option value="mpp">MPP (Redshift)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Gecomprimeerde data (Snappy)</span><span class="r-val" id="w-compressed">—</span></div>
<div class="r-row"><span class="r-label">Effectieve opslag (incl. replicatie)</span><span class="r-val" id="w-total">—</span></div>
<div class="r-row"><span class="r-label">Compute eenheden</span><span class="r-val accent" id="w-compute">—</span></div>
<div class="r-row"><span class="r-label">Geheugen (GB)</span><span class="r-val" id="w-ram">—</span></div>
<div class="r-row"><span class="r-label">vCores</span><span class="r-val" id="w-vcores">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen nodes</span><span class="r-val green" id="w-nodes">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Platform Configuratie</div><div class="rh-val" id="w-clusterRec">—</div></div>
<div class="r-recommendation" id="w-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Lakehouse: Iceberg tables + Trino/Presto query engine. Reken op 5-8x compressie op Parquet. Compute/storage scheiding geeft flexibiliteit. Voor 100TB data: 4-8 worker nodes met 64GB RAM + 16 cores.</div>
</div>
</div>
</div>
</div>
<!-- VECTOR STORE -->
<div class="calc-panel" id="panel-vector" style="display:none">
<div class="desc-text">Sizing voor vector databases en embedding stores (Pinecone, Weaviate, Qdrant, Milvus). Berekent geheugen, dimensies en index grootte.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Aantal vectors (miljoenen)</label><input type="number" id="v-vectors" value="50" oninput="calcVector()"></div>
<div class="calc-input"><label>Vector dimensies</label><select id="v-dims" onchange="calcVector()"><option value="384">384 (all-MiniLM)</option><option value="768" selected>768 (gte-small)</option><option value="1024">1024 (ADA-002)</option><option value="1536">1536 (text-embedding-3)</option></select></div>
<div class="calc-input"><label>Index type</label><select id="v-index" onchange="calcVector()"><option value="flat">Flat (exact, brute force)</option><option value="hnsw" selected>HNSW (approximate, aanbevolen)</option><option value="ivf">IVF (inverted file)</option></select></div>
<div class="calc-input"><label>Replicatie factor</label><select id="v-replicas" onchange="calcVector()"><option value="1">Geen</option><option value="2" selected>2x (HA)</option><option value="3">3x (Enterprise)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Ruwe vector grootte (GB)</span><span class="r-val" id="v-raw">—</span></div>
<div class="r-row"><span class="r-label">Index overhead</span><span class="r-val" id="v-indexOverhead">—</span></div>
<div class="r-row"><span class="r-label">Totaal geheugen (RAM)</span><span class="r-val accent" id="v-ram">—</span></div>
<div class="r-row"><span class="r-label">Totaal met replicatie</span><span class="r-val orange" id="v-total">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen nodes</span><span class="r-val green" id="v-nodes">—</span></div>
<div class="r-row"><span class="r-label">Node type</span><span class="r-val purple" id="v-nodeType">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Vector Store</div><div class="rh-val" id="v-clusterRec">—</div></div>
<div class="r-recommendation" id="v-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">HNSW index met 768 dims is de sweet spot voor enterprise. Reken op 2-3x ruwe data voor index overhead. Houd minimaal 2x RAM vrij naast de vector index voor query processing. Gebruik replica's voor HA.</div>
</div>
</div>
</div>
</div>
<!-- KUBERNETES -->
<div class="calc-panel" id="panel-k8s" style="display:none">
<div class="desc-text">Kubernetes cluster sizing voor data workloads. Berekent node pools, resource quotas, pod density en cluster capaciteit.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Totaal aantal pods</label><input type="number" id="k8-pods" value="200" oninput="calcK8s()"></div>
<div class="calc-input"><label>CPU request per pod (cores)</label><input type="number" id="k8-cpu" value="1" step="0.5" oninput="calcK8s()"></div>
<div class="calc-input"><label>Memory request per pod (GB)</label><input type="number" id="k8-mem" value="4" oninput="calcK8s()"></div>
<div class="calc-input"><label>Node type</label><select id="k8-nodeType" onchange="calcK8s()"><option value="small" selected>Small (16 cores, 64GB)</option><option value="medium">Medium (32 cores, 128GB)</option><option value="large">Large (64 cores, 256GB)</option><option value="gpu">GPU (32 cores, 256GB + NVIDIA A100)</option></select></div>
<div class="calc-input"><label>Overcommit ratio</label><select id="k8-overcommit" onchange="calcK8s()"><option value="1">Geen (1:1, critical)</option><option value="1.5" selected>Gemiddeld (1.5x)</option><option value="2">Hoog (2x, burstable)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Totale CPU request</span><span class="r-val" id="k8-totalCpu">—</span></div>
<div class="r-row"><span class="r-label">Totaal geheugen request</span><span class="r-val" id="k8-totalMem">—</span></div>
<div class="r-row"><span class="r-label">Node capaciteit (pods)</span><span class="r-val" id="k8-nodeCap">—</span></div>
<div class="r-row"><span class="r-label">Aanbevolen nodes</span><span class="r-val accent" id="k8-nodes">—</span></div>
<div class="r-row"><span class="r-label">Gebruikte capaciteit</span><span class="r-val" id="k8-usage">—</span></div>
<div class="r-row"><span class="r-label">N+1 redundantie</span><span class="r-val green" id="k8-nodesHA">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Cluster</div><div class="rh-val" id="k8-clusterRec">—</div></div>
<div class="r-recommendation" id="k8-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">Gebruik medium nodes (32c/128GB) voor data workloads. Reken 110 pods max per node. Reserveer 20% capaciteit voor cluster overhead (system daemons, DNS, monitoring). Overcommit 1.5x voor batch jobs.</div>
</div>
</div>
</div>
</div>
<!-- HADOOP -->
<div class="calc-panel" id="panel-hadoop" style="display:none">
<div class="desc-text">Hadoop HDFS en data lake sizing. Berekent storage, replication, block size, en cluster configuratie voor big data workloads.</div>
<div class="calc-grid">
<div class="calc-card">
<h3>Input Parameters</h3>
<div class="calc-input"><label>Bruto data volume (TB)</label><input type="number" id="hd-volume" value="1000" oninput="calcHadoop()"></div>
<div class="calc-input"><label>Replicatie factor</label><select id="hd-replicas" onchange="calcHadoop()"><option value="1">1 (dev/test)</option><option value="2">2 (standard)</option><option value="3" selected>3 (enterprise)</option></select></div>
<div class="calc-input"><label>Block size</label><select id="hd-block" onchange="calcHadoop()"><option value="128">128 MB</option><option value="256" selected>256 MB</option><option value="512">512 MB</option></select></div>
<div class="calc-input"><label>Disk (TB per node)</label><select id="hd-disk" onchange="calcHadoop()"><option value="4">4 TB HDD</option><option value="8">8 TB HDD</option><option value="12">12 TB HDD</option><option value="16" selected>16 TB HDD</option><option value="30">30 TB SSD</option></select></div>
<div class="calc-input"><label>Compressie</label><select id="hd-compress" onchange="calcHadoop()"><option value="1">Geen</option><option value="0.5" selected>Snappy/LZO (0.5x)</option><option value="0.35">ZSTD (0.35x)</option></select></div>
</div>
<div class="calc-card">
<h3>Resultaten</h3>
<div class="result-card">
<div class="r-row"><span class="r-label">Effectieve opslag (na compressie)</span><span class="r-val" id="hd-effective">—</span></div>
<div class="r-row"><span class="r-label">Totaal met replicatie</span><span class="r-val orange" id="hd-totalRep">—</span></div>
<div class="r-row"><span class="r-label">Bruto capacity per node</span><span class="r-val" id="hd-perNode">—</span></div>
<div class="r-row"><span class="r-label">Aantal data nodes</span><span class="r-val accent" id="hd-nodes">—</span></div>
<div class="r-row"><span class="r-label">Aantal blokken in cluster</span><span class="r-val" id="hd-blocks">—</span></div>
<div class="r-row"><span class="r-label">MapReduce capacity</span><span class="r-val purple" id="hd-mr">—</span></div>
</div>
<div class="r-highlight"><div class="rh-title">Aanbevolen Hadoop Cluster</div><div class="rh-val" id="hd-clusterRec">—</div></div>
<div class="r-recommendation" id="hd-rec">
<div class="rr-title">Mek-Tech Best Practice</div>
<div class="rr-text">HDFS replicatie 3x is enterprise standaard. Gebruik 256MB block size voor data lake workloads. Reken 70-80% disk utilization na OS overhead. Snappy compressie voor balance tussen ratio en speed. Namenode heeft 1GB RAM per 1M blokken.</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function fmt(v){if(v>=1e6)return (v/1e6).toFixed(1)+' PB';if(v>=1e3)return (v/1e3).toFixed(1)+' TB';return Math.round(v)+' GB'}
function fmtBytes(v){return fmt(v)}
function fmtNum(v){if(v>=1e6)return (v/1e6).toFixed(1)+'M';if(v>=1e3)return (v/1e3).toFixed(1)+'K';return Math.round(v).toString()}
function tbToGb(t){return t*1000}
function gbToTb(g){return g/1000}
function calcKafka(){
var msgs=+document.getElementById('k-msgs').value||0
var msgKB=+document.getElementById('k-msgSize').value||0
var retention=+document.getElementById('k-retention').value||0
var replicas=+document.getElementById('k-replicas').value||3
var diskSpeed=+document.getElementById('k-diskSpeed').value||550
var compress=+document.getElementById('k-compress').value||0.4
var mbps=msgs*msgKB/1024
var mbpsNet=mbps*compress
var dailyGB=mbpsNet*86400/1024
var totalGB=dailyGB*retention
var totalRepGB=totalGB*replicas
var partitions=Math.max(msgs/100000,3*replicas)
var brokersPerf=Math.ceil(mbps/diskSpeed)
var brokers=max(3,brokersPerf,Math.ceil(totalRepGB/5000))
document.getElementById('k-throughput').textContent=mbps.toFixed(1)+' MB/s'
document.getElementById('k-throughputNet').textContent=mbpsNet.toFixed(1)+' MB/s'
document.getElementById('k-daily').textContent=dailyGB<1000?Math.round(dailyGB)+' GB':(dailyGB/1000).toFixed(2)+' TB'
document.getElementById('k-total').textContent=fmt(totalGB)
document.getElementById('k-totalRep').textContent=fmt(totalRepGB)
document.getElementById('k-partitions').textContent=Math.ceil(partitions)
document.getElementById('k-brokers').textContent=brokers
var nodeRec=''
if(brokers<=3)nodeRec=brokers+' nodes × 4TB NVMe'
else if(brokers<=6)nodeRec=brokers+' nodes × 8TB SSD'
else if(brokers<=10)nodeRec=brokers+' nodes × 16TB SSD'
else nodeRec=brokers+' nodes × 32TB SSD'
document.getElementById('k-clusterRec').textContent=nodeRec+' (total ~'+fmt(totalRepGB)+')'
var recEl=document.getElementById('k-rec').querySelector('.rr-text')
if(compress<0.3)recEl.textContent='ZSTD compressie geeft ~75% reductie. Overweeg tiered storage voor data >14 dagen oud. Gebruik JBOD configuratie (geen RAID) voor max throughput.'
else recEl.textContent='Voor '+msgs.toLocaleString()+' msg/s met '+msgKB+'KB berichten: '+brokers+' brokers '+nodeRec+'. Partities: '+Math.ceil(partitions)+'. Monitor follower fetch latency en under-replicated partitions.'
}
function calcSpark(){
var data=+document.getElementById('s-data').value||0
var type=document.getElementById('s-type').value
var time=+document.getElementById('s-time').value||30
var nodeRam=+document.getElementById('s-ram').value||256
var nodeCores=+document.getElementById('s-cores').value||32
var dynamic=document.getElementById('s-dynamic').value==='1'
var execOverhead=type==='ml'?8:4
var coresPerExec=type==='stream'?2:5
if(type==='ml')coresPerExec=4
var execsPerNode=Math.floor((nodeRam-execOverhead)/(coresPerExec*4+execOverhead))||1
var totalExecs=execsPerNode
var totalRam=totalExecs*(coresPerExec*4+execOverhead)
var totalVCores=totalExecs*coresPerExec
var workers=Math.ceil(totalExecs/execsPerNode)
if(dynamic)workers=Math.ceil(workers*1.3)
document.getElementById('s-executors').textContent=totalExecs
document.getElementById('s-coresPerExec').textContent=coresPerExec
document.getElementById('s-memPerExec').textContent=coresPerExec*4+execOverhead+' GB'
document.getElementById('s-totalRam').textContent=totalRam+' GB'
document.getElementById('s-totalCores').textContent=totalVCores
document.getElementById('s-workers').textContent=workers
document.getElementById('s-clusterRec').textContent=workers+' nodes × '+nodeRam+'GB RAM / '+nodeCores+' cores'
document.getElementById('s-rec').querySelector('.rr-text').textContent='Voor '+type+' workloads met '+data+'GB data: '+workers+' worker nodes. '+(dynamic?'Dynamic allocation actief — efficiënt voor fluctuerende loads.':'Static allocation — consistent maar minder flexibel.')+' Gebruik RDD persistance voor iterative ML workloads.'
}
function max(){return Math.max.apply(null,arguments)}
function calcMinio(){
var capTB=+document.getElementById('m-capacity').value||0
var driveTB=+document.getElementById('m-driveSize').value||22
var ecStr=document.getElementById('m-ec').value
var ecParts=ecStr.split(':')
var ecData=+ecParts[0],ecParity=+ecParts[1]
var ecFactor=1+ecParity/ecData
var redundancy=document.getElementById('m-redundancy').value
var compress=+document.getElementById('m-compress').value||0.6
var grossTB=capTB*ecFactor
var drives=Math.ceil(grossTB/driveTB)
var nodes=Math.ceil(drives/2)
var usableTB=grossTB/ecFactor
var effectiveTB=usableTB/compress
var minNodes=ecData+ecParity
if(redundancy==='rack')nodes=Math.max(nodes,Math.ceil(minNodes/3)*3)
if(redundancy==='region')nodes=Math.max(nodes,minNodes*2)
document.getElementById('m-drives').textContent=drives
document.getElementById('m-nodes').textContent=nodes
document.getElementById('m-gross').textContent=grossTB.toFixed(1)+' TB'
document.getElementById('m-ecFactor').textContent=ecFactor.toFixed(2)+'x'
document.getElementById('m-usable').textContent=usableTB.toFixed(1)+' TB'
document.getElementById('m-effective').textContent=effectiveTB.toFixed(1)+' TB'
document.getElementById('m-minNodes').textContent=minNodes+' (EC:'+ecData+'+'+ecParity+')'
document.getElementById('m-clusterRec').textContent=nodes+' nodes × '+Math.ceil(drives/nodes)+' drives × '+driveTB+'TB ('+Math.round(grossTB)+'TB gross)'
}
function calcHana(){
var module=document.getElementById('h-module').value
var users=+document.getElementById('h-users').value||0
var dataGB=+document.getElementById('h-data').value||0
var growth=+document.getElementById('h-growth').value||0
var ha=document.getElementById('h-ha').value==='1'
var dr=document.getElementById('h-dr').value==='1'
var ratio=module==='bw'?0.25:module==='bpc'?0.15:module==='slt'?0.05:0.02
var dataFP=Math.round(dataGB*ratio*100)/100
var ram=dataFP*(1+growth/100)+users*0.25
var overhead=ram-dataFP
var cpu=Math.max(8,Math.round(ram/32))
var storage=(dataGB+ram*2)*1.2
var nodeType=ram<=256?'1x HPE ProLiant DL380 (256GB)':'2x HPE ProLiant DL380 (512GB)'
if(ram>1024)nodeType='4x HPE ProLiant DL380 (1TB+) — Scale-out'
if(ha)ram*=1.5
document.getElementById('h-ram').textContent=Math.round(ram)+' GB'
document.getElementById('h-dataFP').textContent=Math.round(dataFP)+' GB'
document.getElementById('h-overhead').textContent=Math.round(overhead)+' GB'
document.getElementById('h-cpu').textContent=cpu+' cores'
document.getElementById('h-storage').textContent=Math.round(storage)+' GB'
document.getElementById('h-nodeType').textContent=nodeType
document.getElementById('h-clusterRec').textContent=Math.round(ram)+'GB RAM, '+cpu+' cores, '+(ha?'+ standby (HA) ':'')+(dr?'+ async replicatie (DR)':'')+' — totaal ~'+Math.round(storage/1000)+'TB opslag'
}
function calcWarehouse(){
var vol=+document.getElementById('w-volume').value||0
var ingest=+document.getElementById('w-ingest').value||0
var queries=+document.getElementById('w-queries').value||20
var complexity=document.getElementById('w-complexity').value
var arch=document.getElementById('w-arch').value
var compressRatio=5
var compressed=vol/compressRatio
var totalTB=compressed*1.5
var complexityFactor=complexity==='simple'?0.5:complexity==='complex'?2:1
var computeUnits=Math.ceil(queries*complexityFactor*0.5)
var ram=computeUnits*32
var vcores=computeUnits*8
var nodes=Math.max(2,Math.ceil(computeUnits/4))
document.getElementById('w-compressed').textContent=compressed.toFixed(1)+' TB'
document.getElementById('w-total').textContent=totalTB.toFixed(1)+' TB'
document.getElementById('w-compute').textContent=computeUnits
document.getElementById('w-ram').textContent=ram+' GB'
document.getElementById('w-vcores').textContent=vcores
document.getElementById('w-nodes').textContent=nodes
document.getElementById('w-clusterRec').textContent=nodes+' nodes, '+ram+'GB RAM, '+vcores+' vCores, '+arch+' — '+(arch==='lakehouse'?'Trino + Iceberg':'Snowflake')+' voor '+queries+' concurrent queries'
}
function calcVector(){
var vecM=+document.getElementById('v-vectors').value||0
var dims=+document.getElementById('v-dims').value||768
var idx=document.getElementById('v-index').value
var replicas=+document.getElementById('v-replicas').value||2
var rawGB=vecM*dims*4/1e9
var idxOverhead=idx==='flat'?rawGB*0.5:idx==='ivf'?rawGB*0.8:rawGB*1.3
var totalRam=rawGB+idxOverhead
var totalRep=totalRam*replicas
var nodes=Math.ceil(totalRep/128)
var nodeType=totalRep<=128?'64GB':totalRep<=256?'128GB':totalRep<=512?'256GB':'512GB+ cluster'
document.getElementById('v-raw').textContent=rawGB.toFixed(1)+' GB'
document.getElementById('v-indexOverhead').textContent=idxOverhead.toFixed(1)+' GB'
document.getElementById('v-ram').textContent=totalRam.toFixed(1)+' GB'
document.getElementById('v-total').textContent=totalRep.toFixed(1)+' GB'
document.getElementById('v-nodes').textContent=nodes
document.getElementById('v-nodeType').textContent=nodeType
document.getElementById('v-clusterRec').textContent=nodes+' nodes × '+nodeType+' (HNSW, '+(vecM*replicas).toFixed(1)+'M vectors)'
}
function calcK8s(){
var pods=+document.getElementById('k8-pods').value||0
var cpuReq=+document.getElementById('k8-cpu').value||1
var memReq=+document.getElementById('k8-mem').value||4
var nodeSel=document.getElementById('k8-nodeType').value
var overcommit=+document.getElementById('k8-overcommit').value||1.5
var nodeSpecs={small:{cores:16,ram:64},medium:{cores:32,ram:128},large:{cores:64,ram:256},gpu:{cores:32,ram:256}}
var ns=nodeSpecs[nodeSel]
var totalCpu=Math.ceil(pods*cpuReq/overcommit)
var totalMem=Math.ceil(pods*memReq/overcommit)
var maxPodsPerNode=110
var podCpuCap=Math.floor(ns.cores/cpuReq*overcommit)
var podMemCap=Math.floor(ns.ram/memReq*overcommit)
var nodeCap=Math.min(maxPodsPerNode,podCpuCap,podMemCap)
var nodes=Math.ceil(pods/nodeCap)
var usage=Math.round(pods/(nodes*nodeCap)*100)
var nodesHA=nodes+1
document.getElementById('k8-totalCpu').textContent=totalCpu+' cores ('+(pods*cpuReq)+' actual)'
document.getElementById('k8-totalMem').textContent=totalMem+' GB ('+(pods*memReq)+' actual)'
document.getElementById('k8-nodeCap').textContent=nodeCap+' pods'
document.getElementById('k8-nodes').textContent=nodes
document.getElementById('k8-usage').textContent=usage+'%'
document.getElementById('k8-nodesHA').textContent=nodesHA+' (N+1)'
document.getElementById('k8-clusterRec').textContent=nodes+'× '+nodeSel+' ('+ns.cores+'c/'+ns.ram+'GB) — '+(nodes*ns.ram)+'GB RAM, '+(nodes*ns.cores)+' cores — capacity: '+usage+'%'
}
function calcHadoop(){
var vol=+document.getElementById('hd-volume').value||0
var replicas=+document.getElementById('hd-replicas').value||3
var block=+document.getElementById('hd-block').value||256
var disk=+document.getElementById('hd-disk').value||16
var compress=+document.getElementById('hd-compress').value||0.5
var effectiveTB=vol*compress
var totalRepTB=effectiveTB*replicas
var perNodeTB=disk*0.85
var nodes=Math.ceil(totalRepTB/perNodeTB)
var blocks=Math.ceil(effectiveTB*1024*1024/block)
var mrCap=nodes*Math.floor(disk*0.1)
document.getElementById('hd-effective').textContent=effectiveTB.toFixed(1)+' TB'
document.getElementById('hd-totalRep').textContent=totalRepTB.toFixed(1)+' TB'
document.getElementById('hd-perNode').textContent=Math.round(perNodeTB*100)/100+' TB'
document.getElementById('hd-nodes').textContent=nodes
document.getElementById('hd-blocks').textContent=blocks.toLocaleString()
document.getElementById('hd-mr').textContent=mrCap+' GB input slot'
document.getElementById('hd-clusterRec').textContent=nodes+' nodes × '+disk+'TB ('+Math.round(nodes*disk*0.85)+'TB usable) — replicatie '+replicas+'x — '+block+'MB blocks'
}
function switchPlatform(p){
document.querySelectorAll('.sb-item').forEach(function(b){b.classList.remove('active')})
document.querySelectorAll('.calc-panel').forEach(function(p2){p2.style.display='none'})
var btn=document.querySelector('.sb-item[data-platform="'+p+'"]')
if(btn)btn.classList.add('active')
var panel=document.getElementById('panel-'+p)
if(panel)panel.style.display='block'
document.getElementById('platformSelect').value=p
var fns={kafka:calcKafka,spark:calcSpark,minio:calcMinio,'sap-hana':calcHana,warehouse:calcWarehouse,vector:calcVector,k8s:calcK8s,hadoop:calcHadoop}
if(fns[p])setTimeout(fns[p],50)
}
document.querySelectorAll('.sb-item').forEach(function(btn){
btn.addEventListener('click',function(){switchPlatform(this.dataset.platform)})
})
calcKafka()
</script>
<script src="/js/theme.js"></script><script>lucide.createIcons()</script></body>
</html>