[{"data":1,"prerenderedAt":2167},["ShallowReactive",2],{"navigation":3,"pages-product-benchmarks":38},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":37},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,17,22,27,32],{"title":10,"path":6,"stem":7,"icon":11},"Getting started","i-lucide-flag",{"title":13,"path":14,"stem":15,"icon":16},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F2.installation","i-lucide-download",{"title":18,"path":19,"stem":20,"icon":21},"License configuration","\u002Fdocs\u002Fgetting-started\u002Flicense-configuration","1.docs\u002F1.getting-started\u002F3.license-configuration","i-lucide-key-round",{"title":23,"path":24,"stem":25,"icon":26},"Your first app","\u002Fdocs\u002Fgetting-started\u002Ffirst-app","1.docs\u002F1.getting-started\u002F4.first-app","i-lucide-square-play",{"title":28,"path":29,"stem":30,"icon":31},"Architecture","\u002Fdocs\u002Fgetting-started\u002Farchitecture","1.docs\u002F1.getting-started\u002F5.architecture","i-lucide-layers",{"title":33,"path":34,"stem":35,"icon":36},"Migrating from Kafka Streams","\u002Fdocs\u002Fgetting-started\u002Fmigration","1.docs\u002F1.getting-started\u002F6.migration","i-lucide-shuffle",false,{"id":39,"title":40,"body":41,"booktabsTables":2159,"compactToc":2159,"description":2160,"extension":2161,"meta":2162,"monoTables":2159,"navigation":2159,"path":2163,"seo":2164,"stem":2165,"wide":2159,"__hash__":2166},"pages\u002F6.pages\u002Fproduct\u002Fbenchmarks.md","Benchmarks",{"type":42,"value":43,"toc":2105},"minimark",[44,102,105,112,117,122,190,194,246,250,253,268,272,276,297,311,319,323,326,330,333,337,341,348,359,363,424,428,564,569,582,586,706,709,712,716,719,725,751,754,816,819,941,944,947,1068,1070,1074,1077,1083,1086,1122,1125,1128,1186,1189,1311,1314,1317,1436,1438,1442,1445,1451,1475,1478,1544,1547,1666,1669,1672,1791,1793,1796,1799,1802,1808,1859,1862,1884,1888,1975,1978,1982,1996,2000,2003,2007,2028,2032,2039,2043,2056,2060,2067,2081,2084,2088,2091,2095,2098,2102],[45,46,47,55,95],"tldr-panel",{},[48,49,50,54],"p",{},[51,52,53],"strong",{},"Vs Kafka Streams 4.1.1 on the same hardware"," (Hetzner 8-vCPU machine, throughput parity):",[56,57,58,69,77,85],"ul",{},[59,60,61,64,65,68],"li",{},[51,62,63],{},"P99 latency"," — up to ",[51,66,67],{},"13.6× lower"," on stateful workloads",[59,70,71,64,74],{},[51,72,73],{},"CPU",[51,75,76],{},"3.4× less",[59,78,79,64,82],{},[51,80,81],{},"Container memory",[51,83,84],{},"7.8× less",[59,86,87,90,91,94],{},[51,88,89],{},"State restoration"," — ",[51,92,93],{},"1.45–1.65× faster"," cold start",[48,96,97,98,101],{},"Single-machine ceiling: ~",[51,99,100],{},"200–300 MB\u002Fs"," uncompressed network throughput.",[48,103,104],{},"These numbers compare a StoatFlow build (EOS Phase 6b, ALO Phase 8) against a stable Apache Kafka Streams 4.1.1 baseline on identical hardware, identical broker, identical workload. The intent is to be useful, not promotional — full topology, load profile, methodology, and the cases where StoatFlow is only at parity or measurably behind Kafka Streams are all in scope below.",[48,106,107,108,111],{},"All runs originate from the internal benchmark report dated ",[51,109,110],{},"2026-04-22",". The numbers below transcribe that report verbatim.",[113,114,116],"h2",{"id":115},"setup","Setup",[118,119,121],"h3",{"id":120},"hardware","Hardware",[123,124,125,138],"table",{},[126,127,128],"thead",{},[129,130,131,135],"tr",{},[132,133,134],"th",{},"Component",[132,136,137],{},"Value",[139,140,141,154,162,174,182],"tbody",{},[129,142,143,147],{},[144,145,146],"td",{},"Benchmark app node",[144,148,149,150,153],{},"Hetzner ",[51,151,152],{},"ccx33"," — 8 dedicated vCPU, 32 GB RAM",[129,155,156,159],{},[144,157,158],{},"Container limits (app)",[144,160,161],{},"8 CPU, 16 GB memory",[129,163,164,167],{},[144,165,166],{},"Kafka brokers",[144,168,169,170,173],{},"3× Hetzner ",[51,171,172],{},"cpx32"," — 4 shared vCPU, 8 GB RAM, 160 GB SSD each — co-located with the k3s control plane and the monitoring stack (Prometheus, Grafana)",[129,175,176,179],{},[144,177,178],{},"Region",[144,180,181],{},"nbg1 (Nuremberg)",[129,183,184,187],{},[144,185,186],{},"Orchestration",[144,188,189],{},"k3s on Hetzner Cloud",[118,191,193],{"id":192},"kafka-runtime","Kafka & runtime",[123,195,196,204],{},[126,197,198],{},[129,199,200,202],{},[132,201,134],{},[132,203,137],{},[139,205,206,214,222,234],{},[129,207,208,211],{},[144,209,210],{},"Kafka broker",[144,212,213],{},"4.1.1 (Strimzi 0.50.0 operator)",[129,215,216,219],{},[144,217,218],{},"JDK",[144,220,221],{},"25 (preview features enabled; required for StoatFlow's virtual-thread runtime)",[129,223,224,227],{},[144,225,226],{},"StoatFlow EOS commit barrier",[144,228,229,233],{},[230,231,232],"code",{},"commit-barrier.min-interval-ms=130",", adaptive scheduling (post-commit feedback clamps barrier-to-barrier interval between configured min and max)",[129,235,236,239],{},[144,237,238],{},"Kafka Streams EOS commit interval",[144,240,241,242,245],{},"100 ms (default ",[230,243,244],{},"commit.interval.ms",")",[118,247,249],{"id":248},"whats-controlled-whats-varied","What's controlled, what's varied",[48,251,252],{},"Topology, input data, load profile, partition count, broker, hardware, and run duration are identical across the two runtimes for any given comparison. The only variable is the runtime itself (StoatFlow vs Kafka Streams) and the processing mode (EOS vs ALO).",[48,254,255,256,259,260,263,264,267],{},"Each run executes for ",[51,257,258],{},"20 minutes"," total: a ",[51,261,262],{},"10-minute warmup"," (JIT, GC stabilisation, lag catch-up) followed by a ",[51,265,266],{},"10-minute measurement window"," at steady state. Topics are recreated between runs; state is empty at start.",[113,269,271],{"id":270},"methodology","Methodology",[118,273,275],{"id":274},"latency","Latency",[48,277,278,284,285,288,289,292,293,296],{},[51,279,280,283],{},[230,281,282],{},"True E2E P50 \u002F P95 \u002F P99"," is measured from the downstream-consumer's point of view"," — the latency a real service reading the output topic would actually observe. A dedicated ",[230,286,287],{},"latency-consumer"," pod simulates that downstream application: it subscribes to the output topic with ",[230,290,291],{},"isolation.level=read_committed"," (so a record only becomes visible after the producing transaction commits) and, for every consumed record, computes ",[230,294,295],{},"consumption time − record timestamp",". Percentiles are derived over the entire measurement window, not from averages.",[48,298,299,300,303,304,307,308,310],{},"The ",[230,301,302],{},"read_committed"," isolation is deliberate. Under EOS, downstream consumers can't see records before the producing transaction commits — which means the runtime's commit cadence is part of the user-observable latency (StoatFlow's ",[51,305,306],{},"130 ms minimum"," barrier interval — adaptively scheduled — and Kafka Streams' default 100 ms ",[230,309,244],{},"). An internal produce-time measurement would hide that cost.",[48,312,313,314,318],{},"The latency-consumer adds ~10–15 % measurement overhead through the extra consume-and-timestamp cycle. Percentile ",[315,316,317],"em",{},"relative"," comparisons between runtimes hold; absolute latency on a runtime without a latency-consumer would be slightly lower.",[118,320,322],{"id":321},"resource-utilisation","Resource utilisation",[48,324,325],{},"CPU, JVM heap, container working set, GC pause durations, and thread counts are sampled from Prometheus at 10-second resolution and averaged over the measurement window. GC pause is the per-event JVM Stop-the-World duration, not the cumulative GC time.",[118,327,329],{"id":328},"repeatability","Repeatability",[48,331,332],{},"Throughput is defined and controlled by the load generators — produced rec\u002Fs mirrors the configured input rate, predictable and repeatable across runs. Latency, CPU, memory, and GC numbers in the result tables are sampled from each run and should be read as point estimates rather than statistical means.",[113,334,336],{"id":335},"scenario-a-stateless-simple","Scenario A — Stateless (simple)",[118,338,340],{"id":339},"topology","Topology",[48,342,343],{},[344,345],"img",{"alt":346,"src":347},"KSTD topology — Stateless (simple)","\u002Fassets\u002Fproduct\u002Fbenchmarks\u002Fsuite-v1\u002FStoatFlow-vs-KafkaStreams_benchmark-suite-v1_stateless-simple-0.1.0.excalidraw.png",[48,349,350,351,354,355,358],{},"A minimal stateless pipeline: one source topic → ",[230,352,353],{},"mapValues"," (uppercase) → ",[230,356,357],{},"filter"," (length > 5) → one sink topic. No state, no repartitioning, no joins. The simplest possible topology — used to measure pure framework overhead.",[118,360,362],{"id":361},"data-load-profile","Data & load profile",[123,364,365,374],{},[126,366,367],{},[129,368,369,372],{},[132,370,371],{},"Property",[132,373,137],{},[139,375,376,384,392,400,408,416],{},[129,377,378,381],{},[144,379,380],{},"Serdes",[144,382,383],{},"String \u002F String",[129,385,386,389],{},[144,387,388],{},"Record size",[144,390,391],{},"~1,024 bytes (fixed)",[129,393,394,397],{},[144,395,396],{},"Partitions",[144,398,399],{},"12",[129,401,402,405],{},[144,403,404],{},"Distinct keys",[144,406,407],{},"10,000",[129,409,410,413],{},[144,411,412],{},"Load",[144,414,415],{},"20,000 msg\u002Fs",[129,417,418,421],{},[144,419,420],{},"Total records \u002F run",[144,422,423],{},"~12.3M",[118,425,427],{"id":426},"results-eos","Results — EOS",[123,429,430,449],{},[126,431,432],{},[129,433,434,437,440,443,446],{},[132,435,436],{},"Metric",[132,438,439],{},"KS",[132,441,442],{},"StoatFlow",[132,444,445],{},"Δ",[132,447,448],{},"Notes",[139,450,451,468,484,500,516,532,548],{},[129,452,453,456,459,462,465],{},[144,454,455],{},"True E2E P50 (ms)",[144,457,458],{},"100.2",[144,460,461],{},"124.0",[144,463,464],{},"+24%",[144,466,467],{},"KS wins",[129,469,470,473,476,479,482],{},[144,471,472],{},"True E2E P95 (ms)",[144,474,475],{},"163.7",[144,477,478],{},"191.8",[144,480,481],{},"+17%",[144,483,467],{},[129,485,486,489,492,495,498],{},[144,487,488],{},"True E2E P99 (ms)",[144,490,491],{},"180.0",[144,493,494],{},"201.9",[144,496,497],{},"+12%",[144,499,467],{},[129,501,502,505,508,510,513],{},[144,503,504],{},"Avg CPU (cores)",[144,506,507],{},"1.3",[144,509,507],{},[144,511,512],{},"0%",[144,514,515],{},"parity",[129,517,518,521,524,527,530],{},[144,519,520],{},"Avg heap (MB)",[144,522,523],{},"93",[144,525,526],{},"62",[144,528,529],{},"−33%",[144,531],{},[129,533,534,537,540,543,545],{},[144,535,536],{},"Avg container mem (MB)",[144,538,539],{},"432",[144,541,542],{},"504",[144,544,481],{},[144,546,547],{},"KS uses less",[129,549,550,553,556,559,562],{},[144,551,552],{},"Avg GC pause (ms)",[144,554,555],{},"4.3",[144,557,558],{},"3.1",[144,560,561],{},"−28%",[144,563],{},[565,566],"benchmark-snapshot",{"mode":567,"scenario":568},"EOS","Stateless (simple)",[48,570,571,572,574,575,578,579,581],{},"This is the scenario where StoatFlow's EOS commit cadence is most exposed: with no state store cost and trivial per-record work, StoatFlow's ",[51,573,306],{}," barrier interval runs a touch slower than KS's ",[51,576,577],{},"100 ms"," ",[230,580,244],{},". The ~30 ms cadence delta accounts for essentially all of the observed ~24 ms True E2E P50 gap. ALO drops the barrier cadence entirely and the gap inverts (see below).",[118,583,585],{"id":584},"results-alo","Results — ALO",[123,587,588,602],{},[126,589,590],{},[129,591,592,594,596,598,600],{},[132,593,436],{},[132,595,439],{},[132,597,442],{},[132,599,445],{},[132,601,448],{},[139,603,604,619,634,649,662,677,692],{},[129,605,606,608,611,614,617],{},[144,607,455],{},[144,609,610],{},"45.3",[144,612,613],{},"41.9",[144,615,616],{},"−8%",[144,618],{},[129,620,621,623,626,629,632],{},[144,622,472],{},[144,624,625],{},"65.3",[144,627,628],{},"61.5",[144,630,631],{},"−6%",[144,633],{},[129,635,636,638,641,644,647],{},[144,637,488],{},[144,639,640],{},"75.0",[144,642,643],{},"71.6",[144,645,646],{},"−5%",[144,648],{},[129,650,651,653,656,658,660],{},[144,652,504],{},[144,654,655],{},"1.2",[144,657,655],{},[144,659,512],{},[144,661,515],{},[129,663,664,666,669,672,675],{},[144,665,520],{},[144,667,668],{},"97",[144,670,671],{},"197",[144,673,674],{},"+103%",[144,676,547],{},[129,678,679,681,684,687,690],{},[144,680,536],{},[144,682,683],{},"430",[144,685,686],{},"657",[144,688,689],{},"+53%",[144,691,547],{},[129,693,694,696,699,701,704],{},[144,695,552],{},[144,697,698],{},"3.8",[144,700,507],{},[144,702,703],{},"−66%",[144,705],{},[565,707],{"mode":708,"scenario":568},"ALO",[48,710,711],{},"In ALO, StoatFlow recovers a small latency lead but uses substantially more container memory on this scenario — the in-memory buffer and virtual-thread stack overhead dominate when there's no state store to amortise over. The GC pause delta (−66 %) goes the other way.",[113,713,715],{"id":714},"scenario-b-word-count","Scenario B — Word count",[118,717,340],{"id":718},"topology-1",[48,720,721],{},[344,722],{"alt":723,"src":724},"KSTD topology — Word count","\u002Fassets\u002Fproduct\u002Fbenchmarks\u002Fsuite-v1\u002FStoatFlow-vs-KafkaStreams_benchmark-suite-v1_word-count-0.1.0.excalidraw.png",[48,726,727,728,731,732,735,736,739,740,743,744,747,748,750],{},"Canonical stateful aggregation: source → ",[230,729,730],{},"flatMapValues"," (tokenise on whitespace) → ",[230,733,734],{},"groupBy(word)"," → ",[230,737,738],{},"count"," (RocksDB) → ",[230,741,742],{},"toStream"," → output. Implicit repartitioning between ",[230,745,746],{},"groupBy"," and ",[230,749,738],{},": Kafka Streams writes to a Kafka-hosted repartition topic; StoatFlow re-keys in memory.",[118,752,362],{"id":753},"data-load-profile-1",[123,755,756,764],{},[126,757,758],{},[129,759,760,762],{},[132,761,371],{},[132,763,137],{},[139,765,766,773,780,786,794,801,808],{},[129,767,768,770],{},[144,769,380],{},[144,771,772],{},"String \u002F Long",[129,774,775,777],{},[144,776,388],{},[144,778,779],{},"~200 bytes avg (range 50 – 1,000)",[129,781,782,784],{},[144,783,396],{},[144,785,399],{},[129,787,788,791],{},[144,789,790],{},"Distinct word keys",[144,792,793],{},"~1,000",[129,795,796,798],{},[144,797,412],{},[144,799,800],{},"7,500 msg\u002Fs",[129,802,803,805],{},[144,804,420],{},[144,806,807],{},"~4.6M",[129,809,810,813],{},[144,811,812],{},"State",[144,814,815],{},"1 RocksDB store (word counts)",[118,817,427],{"id":818},"results-eos-1",[123,820,821,835],{},[126,822,823],{},[129,824,825,827,829,831,833],{},[132,826,436],{},[132,828,439],{},[132,830,442],{},[132,832,445],{},[132,834,448],{},[139,836,837,852,867,881,896,911,926],{},[129,838,839,841,844,847,850],{},[144,840,455],{},[144,842,843],{},"155.3",[144,845,846],{},"120.7",[144,848,849],{},"−22%",[144,851],{},[129,853,854,856,859,862,865],{},[144,855,472],{},[144,857,858],{},"197.4",[144,860,861],{},"191.9",[144,863,864],{},"−3%",[144,866,515],{},[129,868,869,871,874,877,879],{},[144,870,488],{},[144,872,873],{},"215.0",[144,875,876],{},"201.7",[144,878,631],{},[144,880],{},[129,882,883,885,888,891,894],{},[144,884,504],{},[144,886,887],{},"3.0",[144,889,890],{},"2.2",[144,892,893],{},"−27%",[144,895],{},[129,897,898,900,903,906,909],{},[144,899,520],{},[144,901,902],{},"724",[144,904,905],{},"406",[144,907,908],{},"−44%",[144,910],{},[129,912,913,915,918,921,924],{},[144,914,536],{},[144,916,917],{},"1,769",[144,919,920],{},"1,219",[144,922,923],{},"−31%",[144,925],{},[129,927,928,930,933,936,939],{},[144,929,552],{},[144,931,932],{},"6.4",[144,934,935],{},"1.1",[144,937,938],{},"−83%",[144,940],{},[565,942],{"mode":567,"scenario":943},"Word count",[118,945,585],{"id":946},"results-alo-1",[123,948,949,963],{},[126,950,951],{},[129,952,953,955,957,959,961],{},[132,954,436],{},[132,956,439],{},[132,958,442],{},[132,960,445],{},[132,962,448],{},[139,964,965,980,995,1010,1025,1040,1054],{},[129,966,967,969,972,975,978],{},[144,968,455],{},[144,970,971],{},"39.8",[144,973,974],{},"39.4",[144,976,977],{},"−1%",[144,979,515],{},[129,981,982,984,987,990,993],{},[144,983,472],{},[144,985,986],{},"65.0",[144,988,989],{},"54.3",[144,991,992],{},"−16%",[144,994],{},[129,996,997,999,1002,1005,1008],{},[144,998,488],{},[144,1000,1001],{},"72.4",[144,1003,1004],{},"62.3",[144,1006,1007],{},"−14%",[144,1009],{},[129,1011,1012,1014,1017,1020,1023],{},[144,1013,504],{},[144,1015,1016],{},"3.5",[144,1018,1019],{},"1.8",[144,1021,1022],{},"−49%",[144,1024],{},[129,1026,1027,1029,1032,1035,1038],{},[144,1028,520],{},[144,1030,1031],{},"759",[144,1033,1034],{},"771",[144,1036,1037],{},"+2%",[144,1039,515],{},[129,1041,1042,1044,1047,1050,1052],{},[144,1043,536],{},[144,1045,1046],{},"2,278",[144,1048,1049],{},"2,323",[144,1051,1037],{},[144,1053,515],{},[129,1055,1056,1058,1060,1063,1066],{},[144,1057,552],{},[144,1059,558],{},[144,1061,1062],{},"0.7",[144,1064,1065],{},"−77%",[144,1067],{},[565,1069],{"mode":708,"scenario":943},[113,1071,1073],{"id":1072},"scenario-c-stateless-advanced","Scenario C — Stateless (advanced)",[118,1075,340],{"id":1076},"topology-2",[48,1078,1079],{},[344,1080],{"alt":1081,"src":1082},"KSTD topology — Stateless (advanced)","\u002Fassets\u002Fproduct\u002Fbenchmarks\u002Fsuite-v1\u002FStoatFlow-vs-KafkaStreams_benchmark-suite-v1_stateless-advanced-0.1.0.excalidraw.png",[48,1084,1085],{},"Two independent processing paths over four Protobuf input streams:",[56,1087,1088,1106],{},[59,1089,1090,1093,1094,1097,1098,1101,1102,1105],{},[51,1091,1092],{},"Path A",": ",[230,1095,1096],{},"user-events"," + ",[230,1099,1100],{},"product-updates"," → merge → ",[230,1103,1104],{},"flatMap"," (tag expansion, 1 → N fan-out) → repartition → split by priority → 3 output topics.",[59,1107,1108,1093,1111,1097,1114,1117,1118,1121],{},[51,1109,1110],{},"Path B",[230,1112,1113],{},"orders",[230,1115,1116],{},"click-streams"," → filter\u002Ftransform → merge → repartition by ",[230,1119,1120],{},"customerId"," → 1 output topic.",[48,1123,1124],{},"Two explicit repartitions, four inputs, four outputs, no state.",[118,1126,362],{"id":1127},"data-load-profile-2",[123,1129,1130,1138],{},[126,1131,1132],{},[129,1133,1134,1136],{},[132,1135,371],{},[132,1137,137],{},[139,1139,1140,1147,1165,1172,1179],{},[129,1141,1142,1144],{},[144,1143,380],{},[144,1145,1146],{},"Protobuf (all topics)",[129,1148,1149,1151],{},[144,1150,388],{},[144,1152,1153,1155,1156,1158,1159,1161,1162,1164],{},[230,1154,1096],{}," \u002F ",[230,1157,1100],{}," 2 – 5 KB · ",[230,1160,1113],{}," 8 – 15 KB · ",[230,1163,1116],{}," 15 – 30 KB",[129,1166,1167,1169],{},[144,1168,396],{},[144,1170,1171],{},"12 per topic",[129,1173,1174,1176],{},[144,1175,412],{},[144,1177,1178],{},"2,100 + 1,400 + 700 + 2,800 = 7,000 msg\u002Fs total",[129,1180,1181,1183],{},[144,1182,420],{},[144,1184,1185],{},"~4.3M",[118,1187,427],{"id":1188},"results-eos-2",[123,1190,1191,1205],{},[126,1192,1193],{},[129,1194,1195,1197,1199,1201,1203],{},[132,1196,436],{},[132,1198,439],{},[132,1200,442],{},[132,1202,445],{},[132,1204,448],{},[139,1206,1207,1222,1236,1251,1266,1281,1296],{},[129,1208,1209,1211,1214,1217,1220],{},[144,1210,455],{},[144,1212,1213],{},"217.6",[144,1215,1216],{},"116.4",[144,1218,1219],{},"−47%",[144,1221],{},[129,1223,1224,1226,1229,1232,1234],{},[144,1225,472],{},[144,1227,1228],{},"338.4",[144,1230,1231],{},"181.0",[144,1233,1219],{},[144,1235],{},[129,1237,1238,1240,1243,1246,1249],{},[144,1239,488],{},[144,1241,1242],{},"413.9",[144,1244,1245],{},"196.5",[144,1247,1248],{},"−53%",[144,1250],{},[129,1252,1253,1255,1258,1261,1264],{},[144,1254,504],{},[144,1256,1257],{},"2.3",[144,1259,1260],{},"1.0",[144,1262,1263],{},"−57%",[144,1265],{},[129,1267,1268,1270,1273,1276,1279],{},[144,1269,520],{},[144,1271,1272],{},"480",[144,1274,1275],{},"141",[144,1277,1278],{},"−71%",[144,1280],{},[129,1282,1283,1285,1288,1291,1294],{},[144,1284,536],{},[144,1286,1287],{},"1,252",[144,1289,1290],{},"518",[144,1292,1293],{},"−59%",[144,1295],{},[129,1297,1298,1300,1303,1306,1309],{},[144,1299,552],{},[144,1301,1302],{},"1.7",[144,1304,1305],{},"2.9",[144,1307,1308],{},"+71%",[144,1310,467],{},[565,1312],{"mode":567,"scenario":1313},"Stateless (advanced)",[118,1315,585],{"id":1316},"results-alo-2",[123,1318,1319,1333],{},[126,1320,1321],{},[129,1322,1323,1325,1327,1329,1331],{},[132,1324,436],{},[132,1326,439],{},[132,1328,442],{},[132,1330,445],{},[132,1332,448],{},[139,1334,1335,1350,1365,1379,1393,1408,1423],{},[129,1336,1337,1339,1342,1345,1348],{},[144,1338,455],{},[144,1340,1341],{},"50.3",[144,1343,1344],{},"37.3",[144,1346,1347],{},"−26%",[144,1349],{},[129,1351,1352,1354,1357,1360,1363],{},[144,1353,472],{},[144,1355,1356],{},"79.0",[144,1358,1359],{},"52.0",[144,1361,1362],{},"−34%",[144,1364],{},[129,1366,1367,1369,1372,1375,1377],{},[144,1368,488],{},[144,1370,1371],{},"91.8",[144,1373,1374],{},"60.8",[144,1376,1362],{},[144,1378],{},[129,1380,1381,1383,1386,1388,1391],{},[144,1382,504],{},[144,1384,1385],{},"2.6",[144,1387,935],{},[144,1389,1390],{},"−58%",[144,1392],{},[129,1394,1395,1397,1400,1403,1406],{},[144,1396,520],{},[144,1398,1399],{},"810",[144,1401,1402],{},"128",[144,1404,1405],{},"−84%",[144,1407],{},[129,1409,1410,1412,1415,1418,1421],{},[144,1411,536],{},[144,1413,1414],{},"1,654",[144,1416,1417],{},"506",[144,1419,1420],{},"−69%",[144,1422],{},[129,1424,1425,1427,1429,1431,1434],{},[144,1426,552],{},[144,1428,935],{},[144,1430,1385],{},[144,1432,1433],{},"+136%",[144,1435,467],{},[565,1437],{"mode":708,"scenario":1313},[113,1439,1441],{"id":1440},"scenario-d-stateful-joins","Scenario D — Stateful joins",[118,1443,340],{"id":1444},"topology-3",[48,1446,1447],{},[344,1448],{"alt":1449,"src":1450},"KSTD topology — Stateful joins","\u002Fassets\u002Fproduct\u002Fbenchmarks\u002Fsuite-v1\u002FStoatFlow-vs-KafkaStreams_benchmark-suite-v1_stateful-joins-0.1.0.excalidraw.png",[48,1452,1453,1454,1097,1457,1097,1460,1097,1462,1097,1465,1468,1469,1471,1472,1474],{},"Five-table enrichment chain: ",[230,1455,1456],{},"customers",[230,1458,1459],{},"products",[230,1461,1113],{},[230,1463,1464],{},"shipments",[230,1466,1467],{},"reviews",". One primary-key join (",[230,1470,1113],{}," ⋈ ",[230,1473,1464],{},") plus four foreign-key joins. Output: fully enriched record per order. Ten-plus RocksDB state stores (one per input table plus join intermediates). Avro with Schema Registry.",[118,1476,362],{"id":1477},"data-load-profile-3",[123,1479,1480,1488],{},[126,1481,1482],{},[129,1483,1484,1486],{},[132,1485,371],{},[132,1487,137],{},[139,1489,1490,1497,1516,1523,1530,1537],{},[129,1491,1492,1494],{},[144,1493,380],{},[144,1495,1496],{},"Avro + Confluent Schema Registry",[129,1498,1499,1501],{},[144,1500,388],{},[144,1502,1503,1155,1505,1158,1507,1509,1510,1512,1513,1515],{},[230,1504,1456],{},[230,1506,1459],{},[230,1508,1113],{}," 10 – 50 KB · ",[230,1511,1464],{}," 5.5 – 27 KB · ",[230,1514,1467],{}," 5.5 – 20 KB",[129,1517,1518,1520],{},[144,1519,396],{},[144,1521,1522],{},"12 per input topic",[129,1524,1525,1527],{},[144,1526,412],{},[144,1528,1529],{},"12 + 18 + 120 + 90 + 60 = 300 msg\u002Fs total",[129,1531,1532,1534],{},[144,1533,420],{},[144,1535,1536],{},"~184 K",[129,1538,1539,1541],{},[144,1540,812],{},[144,1542,1543],{},"10+ RocksDB stores",[118,1545,427],{"id":1546},"results-eos-3",[123,1548,1549,1563],{},[126,1550,1551],{},[129,1552,1553,1555,1557,1559,1561],{},[132,1554,436],{},[132,1556,439],{},[132,1558,442],{},[132,1560,445],{},[132,1562,448],{},[139,1564,1565,1580,1595,1609,1621,1636,1651],{},[129,1566,1567,1569,1572,1575,1578],{},[144,1568,455],{},[144,1570,1571],{},"1,594.5",[144,1573,1574],{},"144.4",[144,1576,1577],{},"−91%",[144,1579],{},[129,1581,1582,1584,1587,1590,1593],{},[144,1583,472],{},[144,1585,1586],{},"2,914.9",[144,1588,1589],{},"214.2",[144,1591,1592],{},"−93%",[144,1594],{},[129,1596,1597,1599,1602,1605,1607],{},[144,1598,488],{},[144,1600,1601],{},"3,297.9",[144,1603,1604],{},"242.8",[144,1606,1592],{},[144,1608],{},[129,1610,1611,1613,1615,1617,1619],{},[144,1612,504],{},[144,1614,555],{},[144,1616,1305],{},[144,1618,529],{},[144,1620],{},[129,1622,1623,1625,1628,1631,1634],{},[144,1624,520],{},[144,1626,1627],{},"1,775",[144,1629,1630],{},"194",[144,1632,1633],{},"−89%",[144,1635],{},[129,1637,1638,1640,1643,1646,1649],{},[144,1639,536],{},[144,1641,1642],{},"8,667",[144,1644,1645],{},"1,105",[144,1647,1648],{},"−87%",[144,1650],{},[129,1652,1653,1655,1658,1661,1664],{},[144,1654,552],{},[144,1656,1657],{},"13.7",[144,1659,1660],{},"8.2",[144,1662,1663],{},"−40%",[144,1665],{},[565,1667],{"mode":567,"scenario":1668},"Stateful joins",[118,1670,585],{"id":1671},"results-alo-3",[123,1673,1674,1688],{},[126,1675,1676],{},[129,1677,1678,1680,1682,1684,1686],{},[132,1679,436],{},[132,1681,439],{},[132,1683,442],{},[132,1685,445],{},[132,1687,448],{},[139,1689,1690,1704,1719,1733,1747,1762,1776],{},[129,1691,1692,1694,1697,1699,1702],{},[144,1693,455],{},[144,1695,1696],{},"267.9",[144,1698,971],{},[144,1700,1701],{},"−85%",[144,1703],{},[129,1705,1706,1708,1711,1714,1717],{},[144,1707,472],{},[144,1709,1710],{},"562.9",[144,1712,1713],{},"55.0",[144,1715,1716],{},"−90%",[144,1718],{},[129,1720,1721,1723,1726,1729,1731],{},[144,1722,488],{},[144,1724,1725],{},"703.8",[144,1727,1728],{},"63.0",[144,1730,1577],{},[144,1732],{},[129,1734,1735,1737,1740,1743,1745],{},[144,1736,504],{},[144,1738,1739],{},"6.8",[144,1741,1742],{},"2.0",[144,1744,1278],{},[144,1746],{},[129,1748,1749,1751,1754,1757,1760],{},[144,1750,520],{},[144,1752,1753],{},"1,301",[144,1755,1756],{},"485",[144,1758,1759],{},"−63%",[144,1761],{},[129,1763,1764,1766,1769,1772,1774],{},[144,1765,536],{},[144,1767,1768],{},"7,932",[144,1770,1771],{},"1,802",[144,1773,1065],{},[144,1775],{},[129,1777,1778,1780,1783,1786,1789],{},[144,1779,552],{},[144,1781,1782],{},"14.6",[144,1784,1785],{},"8.0",[144,1787,1788],{},"−45%",[144,1790],{},[565,1792],{"mode":708,"scenario":1668},[113,1794,89],{"id":1795},"state-restoration",[48,1797,1798],{},"Separate benchmark — cold-start recovery from pre-populated changelog topics, no live processing. Measures the wall-clock time and resource cost of materialising a full state set.",[118,1800,116],{"id":1801},"setup-1",[48,1803,1804],{},[344,1805],{"alt":1806,"src":1807},"KSTD topology — State restoration (16 KTables)","\u002Fassets\u002Fproduct\u002Fbenchmarks\u002Fsuite-v1\u002FStoatFlow-vs-KafkaStreams_benchmark-suite-v1_restoration-0.1.0.excalidraw.png",[123,1809,1810,1818],{},[126,1811,1812],{},[129,1813,1814,1816],{},[132,1815,371],{},[132,1817,137],{},[139,1819,1820,1828,1836,1844,1852],{},[129,1821,1822,1825],{},[144,1823,1824],{},"Stores",[144,1826,1827],{},"16 KTable source stores",[129,1829,1830,1833],{},[144,1831,1832],{},"Partitions per store",[144,1834,1835],{},"6",[129,1837,1838,1841],{},[144,1839,1840],{},"Total records",[144,1842,1843],{},"~155.8M",[129,1845,1846,1849],{},[144,1847,1848],{},"Raw data",[144,1850,1851],{},"~16.8 GB",[129,1853,1854,1856],{},[144,1855,380],{},[144,1857,1858],{},"Mixed Avro \u002F String",[48,1860,1861],{},"StoatFlow offers two restoration modes:",[56,1863,1864,1876],{},[59,1865,1866,1871,1872,1875],{},[51,1867,1868],{},[230,1869,1870],{},"WriteBatch HIGH_PERF"," — RocksDB ",[230,1873,1874],{},"WriteBatch"," ingestion. Lower memory overhead, recommended default.",[59,1877,1878,1883],{},[51,1879,1880],{},[230,1881,1882],{},"SST HP buf128"," — direct SST file ingestion with a 128 MB per-worker sort buffer. Lower wall-clock time, substantially higher memory ceiling.",[118,1885,1887],{"id":1886},"results","Results",[123,1889,1890,1904],{},[126,1891,1892],{},[129,1893,1894,1896,1898,1901],{},[132,1895,436],{},[132,1897,439],{},[132,1899,1900],{},"StoatFlow · WriteBatch",[132,1902,1903],{},"StoatFlow · SST",[139,1905,1906,1920,1934,1947,1961],{},[129,1907,1908,1911,1914,1917],{},[144,1909,1910],{},"Total time (s)",[144,1912,1913],{},"183",[144,1915,1916],{},"127 (1.45× faster)",[144,1918,1919],{},"111 (1.65× faster)",[129,1921,1922,1925,1928,1931],{},[144,1923,1924],{},"Aggregate throughput (M rec\u002Fs)",[144,1926,1927],{},"0.87",[144,1929,1930],{},"1.23",[144,1932,1933],{},"1.41",[129,1935,1936,1938,1941,1944],{},[144,1937,504],{},[144,1939,1940],{},"6.88",[144,1942,1943],{},"6.17",[144,1945,1946],{},"7.79",[129,1948,1949,1952,1955,1958],{},[144,1950,1951],{},"Avg container memory (MB)",[144,1953,1954],{},"5,616",[144,1956,1957],{},"4,690",[144,1959,1960],{},"18,105",[129,1962,1963,1966,1969,1972],{},[144,1964,1965],{},"On-disk RocksDB (GB)",[144,1967,1968],{},"16.5",[144,1970,1971],{},"10.8",[144,1973,1974],{},"10.2",[1976,1977],"benchmark-restoration",{},[118,1979,1981],{"id":1980},"when-to-use-which-mode","When to use which mode",[56,1983,1984,1990],{},[59,1985,1986,1989],{},[51,1987,1988],{},"WriteBatch (default)"," — broadly applicable. Wall-clock 1.45× faster than KS, lower memory than KS, smaller on-disk footprint. The right starting point unless restoration time is the binding production constraint.",[59,1991,1992,1995],{},[51,1993,1994],{},"SST ingestion"," — when first-byte-after-restart latency matters and the deployment has memory headroom. ~3.2× the container memory of WriteBatch during the restoration window; the same memory profile during steady-state.",[113,1997,1999],{"id":1998},"where-stoatflow-is-at-parity-or-behind","Where StoatFlow is at parity or behind",[48,2001,2002],{},"A short list of cases where the numbers don't favour StoatFlow — included so the page reads as data, not as advocacy.",[118,2004,2006],{"id":2005},"eos-latency-on-the-simplest-topology","EOS latency on the simplest topology",[48,2008,2009,2010,2012,2013,2016,2017,2019,2020,2023,2024,2027],{},"On ",[230,2011,568],{}," in EOS mode, Kafka Streams beats StoatFlow on every latency percentile: ",[51,2014,2015],{},"P50 by 24 %, P95 by 17 %, P99 by 12 %",". Root cause: StoatFlow's commit pipeline runs at a ",[51,2018,306],{}," barrier interval (",[230,2021,2022],{},"commit-barrier.min-interval-ms","; the adaptive scheduler clamps barrier-to-barrier between the configured min and max via post-commit feedback). KS's default ",[230,2025,2026],{},"commit.interval.ms=100"," produces a slightly tighter cadence on workloads where the commit itself dominates the latency budget. The ~30 ms cadence delta accounts for essentially the entire ~24 ms P50 gap. In ALO mode (no transactions, no barrier cadence) StoatFlow recovers and shows a small latency lead, so the gap is specific to EOS-on-simple-topologies. The minimum barrier interval is a tunable; lowering it further narrows the EOS gap at the cost of commit-pipeline throughput.",[118,2029,2031],{"id":2030},"container-memory-on-stateless-simple-alo","Container memory on Stateless (simple) ALO",[48,2033,2034,2035,2038],{},"In ALO mode on the simplest topology, StoatFlow uses ",[51,2036,2037],{},"+53 % container memory"," (657 MB vs 430 MB). GC pause time is 2.9× lower in the same comparison — a different point on the same trade-off — but the working-set figure is larger, and a memory-constrained deployment should know that. The delta does not appear on more substantial workloads, where state-store memory dominates.",[118,2040,2042],{"id":2041},"gc-pause-on-stateless-advanced","GC pause on Stateless (advanced)",[48,2044,2045,2046,747,2049,2052,2053,2055],{},"GC pause averages run ",[51,2047,2048],{},"+71 % in EOS",[51,2050,2051],{},"+136 % in ALO"," vs Kafka Streams on this scenario (2.9 ms vs 1.7 ms; 2.6 ms vs 1.1 ms). Absolute pause times remain under 3 ms in both runtimes, so the relative figure overstates the practical impact, but it's a genuine regression on this workload shape (high-fanout ",[230,2054,1104],{}," on relatively large records).",[118,2057,2059],{"id":2058},"not-yet-benchmarked","Not yet benchmarked",[48,2061,2062,2063,2066],{},"The following are explicitly ",[51,2064,2065],{},"out of the current measurement set",". Numbers here are not just unfavourable — they are absent.",[56,2068,2069,2075],{},[59,2070,2071,2074],{},[51,2072,2073],{},"Scaling beyond 8 vCPU."," All numbers above are on a single Hetzner ccx33. Larger boxes (16+ vCPU, 64+ GB) are extrapolated from microbenchmarks of the lane dispatcher and have not been validated end-to-end at scale.",[59,2076,2077,2080],{},[51,2078,2079],{},"Custom processor DAGs with deep fan-out."," Only the four scenarios above were measured. Topologies with many sub-topologies (10+) may behave differently.",[48,2082,2083],{},"StoatFlow at the time of these runs is in active development (EOS Phase 6b, ALO Phase 8); Kafka Streams 4.1.1 is a stable production release. Later StoatFlow phases may improve or regress against these numbers.",[113,2085,2087],{"id":2086},"whats-next","What's next",[48,2089,2090],{},"Two benchmark expansions are planned for upcoming runs.",[118,2092,2094],{"id":2093},"higher-load-runs-on-aws-eks","Higher-load runs on AWS EKS",[48,2096,2097],{},"16-core compute-optimized nodes for both the application tier and the Kafka broker tier, with substantially higher network and disk-IO bandwidth than the current Hetzner ccx33 baseline. Goal: stress sustained throughput beyond the single-machine measurements above, validate the vertical-scale assumption past 8 vCPU end-to-end (currently extrapolated from microbenchmarks), and push past the ~380 MB\u002Fs broker-fetch ceiling that bounds State restoration today.",[118,2099,2101],{"id":2100},"additional-benchmark-apps","Additional benchmark apps",[48,2103,2104],{},"Coverage of all window types (tumbling, hopping, sliding, session) and stream-stream joins — neither is exercised today; the current set covers stateless transforms, key changes, aggregations, and primary-key + foreign-key table joins. Plus more complex topologies modelling real-world use cases, driven by production-like test-data workloads — record-size distributions, key cardinality, arrival patterns, and foreign-key relationships that actually resolve at join time (not random keys that mostly miss) — instead of the synthetic load profiles used in the current runs.",{"title":2106,"searchDepth":2107,"depth":2107,"links":2108},"",2,[2109,2115,2120,2126,2132,2138,2144,2149,2155],{"id":115,"depth":2107,"text":116,"children":2110},[2111,2113,2114],{"id":120,"depth":2112,"text":121},3,{"id":192,"depth":2112,"text":193},{"id":248,"depth":2112,"text":249},{"id":270,"depth":2107,"text":271,"children":2116},[2117,2118,2119],{"id":274,"depth":2112,"text":275},{"id":321,"depth":2112,"text":322},{"id":328,"depth":2112,"text":329},{"id":335,"depth":2107,"text":336,"children":2121},[2122,2123,2124,2125],{"id":339,"depth":2112,"text":340},{"id":361,"depth":2112,"text":362},{"id":426,"depth":2112,"text":427},{"id":584,"depth":2112,"text":585},{"id":714,"depth":2107,"text":715,"children":2127},[2128,2129,2130,2131],{"id":718,"depth":2112,"text":340},{"id":753,"depth":2112,"text":362},{"id":818,"depth":2112,"text":427},{"id":946,"depth":2112,"text":585},{"id":1072,"depth":2107,"text":1073,"children":2133},[2134,2135,2136,2137],{"id":1076,"depth":2112,"text":340},{"id":1127,"depth":2112,"text":362},{"id":1188,"depth":2112,"text":427},{"id":1316,"depth":2112,"text":585},{"id":1440,"depth":2107,"text":1441,"children":2139},[2140,2141,2142,2143],{"id":1444,"depth":2112,"text":340},{"id":1477,"depth":2112,"text":362},{"id":1546,"depth":2112,"text":427},{"id":1671,"depth":2112,"text":585},{"id":1795,"depth":2107,"text":89,"children":2145},[2146,2147,2148],{"id":1801,"depth":2112,"text":116},{"id":1886,"depth":2112,"text":1887},{"id":1980,"depth":2112,"text":1981},{"id":1998,"depth":2107,"text":1999,"children":2150},[2151,2152,2153,2154],{"id":2005,"depth":2112,"text":2006},{"id":2030,"depth":2112,"text":2031},{"id":2041,"depth":2112,"text":2042},{"id":2058,"depth":2112,"text":2059},{"id":2086,"depth":2107,"text":2087,"children":2156},[2157,2158],{"id":2093,"depth":2112,"text":2094},{"id":2100,"depth":2112,"text":2101},true,"StoatFlow vs Kafka Streams 4.1 — four representative workloads, EOS and ALO modes, plus state restoration. Run 2026-04-22 on Hetzner ccx33 (8 vCPU \u002F 32 GB RAM).","md",{},"\u002Fpages\u002Fproduct\u002Fbenchmarks",{"title":40,"description":2160},"6.pages\u002Fproduct\u002Fbenchmarks","Kp1I0X_AcXi5F_F6rgxhk9BD-EzHq8dlJ7Ov5Udk4og",1780332011699]