Meta hat als Open Source veröffentlicht Rebalancer, eine C++-Bibliothek mit einer Python-Schnittstelle zum Lösen von Zuordnungsproblemen. Sie entscheidet, welche Objekte unter welchen Nebenbedingungen und Zielen in welche Binns kommen. Laut dem Engineering at Meta-Beitragverwaltet Rebalancer seit über 9 Jahren die Ressourcenallokation bei Meta. Die Veröffentlichung steht unter Apache 2.0 und umfasst Dokumentation, ein PyPI-Paket und eine Debugging-UI namens Rebalancer Explorer.
Ist sie einsetzbar? Ja. pip install rebalancer installiert v1.0.4 für Python 3.12+, mit vorgebauten Wheels für Linux x86-64 und macOS 14+ ARM64. .deb-, .rpm- und Homebrew-Pakete existieren ebenfalls. PyPI stuft das Projekt weiterhin als Alpha ein.
Welches Problem löst Rebalancer?
Zuordnungsprobleme treten in Metas gesamtem Stack auf. Racks kommen in Datacenter, Server zu Diensten, Aufgaben zu Servern und Benutzer-Traffic zu Datacentern. Meta nennt 2 Hindernisse: Benutzerfreundlichkeit und Skalierbarkeit. Ingenieure tun sich schwer, Richtlinien in präzise Formeln zu überführen, und viele Probleme sind NP-schwer und zu groß für kommerzielle Solver.
Rebalancers Antwort darauf ist, die Art und Weise, wie ein Problem spezifiziert wird, von der Art und Weise zu trennen, wie es gelöst wird. Das Design wird im OSDI-2024-Paper, Optimizing Resource Allocation in Hyperscale Datacenters.
Wie die Spezifikationsschicht funktioniert
Die Spezifikationssprache hat 3 Schichten:
- Modellierungskonstrukte: Dimensionen (Attribute wie CPU oder Speicher), Partitionen (Gruppen von Objekten), Scopes (Gruppen von Binns) und Auslastung.
- Expression-API: Auslastung mit SUM oder MAX aggregieren oder mit Operationen wie SQUARE transformieren.
- Spec-API: Dutzende vordefinierte Ziele und Nebenbedingungen, aufgelistet in der Dokumentation.
Metas Beispiel modelliert Aufgaben als Objekte, Server als Binns und Racks als Scope. Eine CapacitySpec begrenzt CPU und Speicher pro Server. Eine GroupCountSpec erlaubt 1 Jobtyp pro Rack. Eine BalanceSpec gleicht die Auslastung jedes Servers in beiden Dimensionen aus.
Ein Ausdrucksgraph, zwei Solver
Rebalancer kompiliert die Spezifikation in einen gerichteten azyklischen Ausdrucksgraphen. Blattknoten enthalten Auslastungswerte; Aggregations- und Transformationsknoten liegen darüber. Nutzer geben eine anfängliche Zuweisung und eine Abbruchbedingung vor. Nebenbedingungen, die die anfängliche Zuweisung bereits verletzt, werden zu Zielen mit hoher Priorität.
Optimaler Solver: Der Graph wird in ein gemischt-ganzzahliges Programm für FICO Xpress, Gurobi oder HiGHSübersetzt. Variablenaggregation und Symmetriebrechung verkleinern die Modelle. Die Worst-Case-Modellgröße bleibt O(objects × bins). Metas größte Probleme sind für jeden MIP-Solver zu groß.
Lokale Suche: Dieser Solver arbeitet direkt auf dem Ausdrucksgraphen. Er erkundet Verschiebungen von Objekten in andere Bins, mit einer Worst-Case-Nachbarschaft von O(objects + bins). Anschließend wendet er den besten Kandidaten an, der keine Nebenbedingung verletzt. Die Auswertung ist parallelisiert und erreicht Millionen von Auswertungen pro Sekunde, zudem wird der Suchraum beschnitten.
Meta nutzt lokale Suche für fast alle großen Probleme und MIP für kleine bis mittelgroße, wobei oft zuerst mit MIP prototypisiert wird.
Produktionszahlen bei Meta
- Etwa 40 millionen Zuweisungsprobleme pro Tag gelöst, über 30+ einzigartige Formulierungen.
- P99-Lösungszeit von 12 Sekunden bei 265k Objekten und 3.2k Bins.
- Probleme mit mehr als 1 million Objekten und 5k Bins benötigen im Durchschnitt 171 Sekunden, über 3.4k+ Läufe.
Beste Anwendungsfälle für Rebalancer
- Platzierung von Shards, Tasks oder Containern auf einem Cluster: Arbeit unter CPU- und Speichergrenzen auf Server verteilen und dabei Replikate über Racks verteilen. Metas Shard Manager und RAS betreiben dieses Muster.
- Ausgleich von Traffic und Workloads über Regionen: Nutzer-Traffic oder Jobs an Rechenzentren routen und dabei Latenz gegen Last abwägen. Taiji tut dies für Edge-Traffic, und Meta balanciert ML-Training nach Priorität.
- Operative Zuweisung außerhalb der Infrastruktur: Support-Tickets Ingenieuren zuordnen, Meetings Räumen oder Arbeitsplätze Personen – unter Kapazitätsregeln. Meta hat alle 3 davon umgesetzt.
Debugging mit dem Rebalancer Explorer
Modeler bei Meta verbrachten den Großteil ihrer Zeit mit dem Debugging von Solver-Verhalten. Rebalancer Explorer ist eine Dockerisierte Web-UI, die genau dafür gebaut wurde. Sie zeigt bindende Constraints, Relaxation-Effekte und warum ein Objekt in einem Bin gelandet ist.
Interaktiver Explainer
Run local search</button> <button class="b" id="mtpStep">Step once</button> <button class="b" id="mtpShuf">Random bad start</button> <button class="b" id="mtpReset">Reset</button> </div> <div class="stats"> <div class="st"><div class="k">Schritt</div><div class="v" id="mtpS">0</div></div> <div class="st"><div class="k">Bewertete Züge</div><div class="v" id="mtpE">0</div></div> <div class="st"><div class="k">Kapazitätsüberschreitung</div><div class="v" id="mtpV">0</div></div> <div class="st"><div class="k">Balance-Zielfunktion</div><div class="v" id="mtpO">0</div></div> </div> <div class="racks" id="mtpRacks"></div> <div class="spark"><div class="k">Zielfunktion über Schritte (niedriger ist besser, ideal = 324)</div> <svg id="mtpSpark" viewBox="0 0 800 70" width="100%" height="70" preserveAspectRatio="none"></svg> </div> <div class="log" id="mtpLog">Server S1 startet mit 4 CPU über der Kapazität. Drücken Sie auf Run.</div> </div> <!-- PANE 2 --> <div class="pane" id="mtpP1"> <p class="note">Rebalancer kompiliert Specs in einen <b>gerichteten azyklischen Ausdrucksgraphen</b>. Die Blätter halten die Auslastung jedes Servers; darüber liegen SQUARE-, SUM- und MAX-Knoten. Wenn eine Aufgabe verschoben wird, brauchen nur die Blätter, die sie berührt, und deren Vorfahren neue Werte. Der Graph nutzt denselben Live-Zustand wie Tab 1.</p> <div class="btns"> <button class="b pri" id="mtpGMove">Eine zufällige Aufgabe verschieben</button> <button class="b" id="mtpGBest">Besten Local-Search-Zug anwenden</button> </div> <div class="gwrap"><svg id="mtpGraph" viewBox="0 0 820 300" width="100%"></svg></div> <div class="log" id="mtpGLog">Drücken Sie auf einen Button, um eine Aufgabe zu verschieben.</div> </div> <!-- PANE 3 --> <div class="pane" id="mtpP2"> <p class="note">Das MIP-Modell benötigt etwa eine binäre Variable pro Objekt pro Bin, wächst also mit <b>O(Objekte × Bins)</b>. Eine Local-Search-Nachbarschaft wächst mit <b>O(Objekte + Bins)</b>. Ziehen Sie die Regler oder laden Sie Metas veröffentlichte Größen.</p> <div class="btns"> <button class="b" data-o="500" data-bn="20">Klein: 500 × 20</button> <button class="b" data-o="265000" data-bn="3200">Meta P99: 265k × 3.2k</button> <button class="b" data-o="1000000" data-bn="5000">Meta XL: 1M × 5k</button> </div> <div class="sl"><label>Objekte <b id="mtpOv"></b></label><input type="range" id="mtpOs" min="1" max="6.3" step="0.01" value="2.7"></div> <div class="sl"><label>Bins <b id="mtpBv"></b></label><input type="range" id="mtpBs" min="0.3" max="4" step="0.01" value="1.3"></div> <div class="cmp"> <div class="row"><div class="t">MIP-binäre Variablen, Worst Case <span id="mtpMv"></span></div><div class="track"><i id="mtpMb" style="background:linear-gradient(90deg,#FF8A5A,#FF5A6E)"></i></div></div> <div class="row"><div class="t">Local-Search-Nachbarschaft, Worst Case <span id="mtpLv"></span></div><div class="track"><i id="mtpLb" style="background:linear-gradient(90deg,#0866FF,#38D6FF)"></i></div></div> </div> <div class="verdict" id="mtpVerdict"></div> <p class="note" style="margin-top:10px">Die Balken verwenden eine logarithmische Skala. Die Größenbereiche im Fazit sind illustrativ; Metas angegebene Regel ist Local Search für fast alle großen Probleme und MIP für kleine bis mittelgroße.</p> </div> <!-- PANE 4 --> <div class="pane" id="mtpP3"> <p class="note">Von Meta für Rebalancer veröffentlichte Produktionszahlen (Engineering at Meta, 21. September 2026).</p> <div class="grid" id="mtpCards"> <div class="card"><div class="n"><span data-c="40">0</span><em>M</em></div><div class="d">täglich gelöste Zuordnungsprobleme</div></div> <div class="card"><div class="n"><span data-c="30">0</span><em>+</em></div><div class="d">einzigartige Problemformulierungen</div></div> <div class="card"><div class="n"><span data-c="12">0</span><em>s</em></div><div class="d">P99-Lösungszeit bei 265k Objekten und 3.2k Bins</div></div> <div class="card"><div class="n"><span data-c="171">0</span><em>s</em></div><div class="d">durchschnittliche Lösungszeit für 1M+ Objekte und 5k Bins</div></div> <div class="card"><div class="n"><span data-c="3.4" data-d="1">0</span><em>k+</em></div><div class="d">Läufe in diesem 1M+ Objekt-Umfang</div></div> <div class="card"><div class="n"><span data-c="9">0</span><em>+ yrs</em></div><div class="d">im Einsatz bei Meta vor der Open-Sourcing-Veröffentlichung</div></div> </div> <div class="pills"> <span class="pill">Shard Manager: Shards → Server</span> <span class="pill">RAS: Server → Dienste</span> <span class="pill">Taiji: Edge-Traffic → Rechenzentren</span> <span class="pill">Serverless-Funktionsgruppierung</span> <span class="pill">ML-Training-Ausbalancierung</span> <span class="pill">Meetings → Räume</span> </div> </div> <div class="ft"> <span>Quellen: <a href="https://engineering.fb.com/2026/09/21/open-source/rebalancer-generic-high-performance-library-assignment-problems/" target="_blank" rel="noopener">Engineering at Meta</a> · <a href="https://github.com/facebook/rebalancer" target="_blank" rel="noopener">GitHub</a> · Tabs 1 bis 3 sind vereinfachte Simulationen</span> <span class="brand">Erstellt von Marktechpost</span> </div> </div> <script> (function(){ var R=document.getElementById('mtp-rebal'); function postH(){try{parent.postMessage({mtpRebalH:R.offsetHeight+40},'*');}catch(e){}} var SIZES=[6,5,4,4,3,3,3,2,2,2,1,1], CAP=16, NS=4; var START=[0,0,0,0,1,1,1,2,2,2,0,1]; var asg=START.slice(), step=0, evals=0, hist=[], timer=null, hot=-1; function util(a){var u=[0,0,0,0];for(var i=0;i<a.length;i++)u[a[i]]+=SIZES[i];return u;} function score(a){var u=util(a),v=0,o=0;for(var s=0;s<NS;s++){v+=Math.max(0,u[s]-CAP);o+=u[s]*u[s];}return [v,o];} function better(x,y){return x[0]<y[0]||(x[0]===y[0]&&x[1]<y[1]);} function bestMove(){ var cur=score(asg),best=null,bs=cur,n=0; for(var i=0;i<asg.length;i++){for(var s=0;s<NS;s++){if(s===asg[i])continue;var b=asg.slice();b[i]=s;n++;var sc=score(b);if(better(sc,bs)){bs=sc;best={a:b,txt:'move t'+(i+1)+' S'+(asg[i]+1)+' → S'+(s+1),ids:[i]};}}} for(var i2=0;i2<asg.length;i2++)for(var j=i2+1;j<asg.length;j++){if(asg[i2]===asg[j])continue;var c=asg.slice();c[i2]=asg[j];c[j]=asg[i2];n++;var sc2=score(c);if(better(sc2,bs)){bs=sc2;best={a:c,txt:'swap t'+(i2+1)+' t'+(j+1),ids:[i2,j]};}} return {best:best,n:n,sc:bs}; } var racksEl=document.getElementById('mtpRacks'); function rects(){var m={};racksEl.querySelectorAll('.chip').forEach(function(c){m[c.dataset.id]=c.getBoundingClientRect();});return m;} function render(ids){ var before=rects(),u=util(asg),h=''; for(var r=0;r<2;r++){h+='<div class="rack"><div class="rl">Rack '+(r?'B':'A')+' (Bereich)</div><div class="srvs">'; for(var s=r*2;s<r*2+2;s++){var over=u[s]>CAP; h+='<div class="srv'+(over?' over':'')+'"><div class="sn">S'+(s+1)+'<span>'+u[s]+' / '+CAP+' CPU</span></div><div class="bar"><i style="width:'+Math.min(100,u[s]/24*100)+'%"></i><u style="left:'+(CAP/24*100)+'%"></u></div><div class="chips">'; for(var i=0;i<asg.length;i++)if(asg[i]===s){h+='<div class="chip'+(ids&&ids.indexOf(i)>-1?' hot':'')+'" data-id="'+i+'" style="width:'+(30+SIZES[i]*8)+'px">t'+(i+1)+'·'+SIZES[i]+'</div>';} h+='</div></div>';} h+='</div></div>';} racksEl.innerHTML=h; racksEl.querySelectorAll('.chip').forEach(function(c){var b=before[c.dataset.id];if(!b)return;var a=c.getBoundingClientRect(),dx=b.left-a.left,dy=b.top-a.top;if(dx||dy){c.style.transition='none';c.style.transform='translate('+dx+'px,'+dy+'px)';requestAnimationFrame(function(){requestAnimationFrame(function(){c.style.transition='transform .55s cubic-bezier(.2,.8,.2,1)';c.style.transform='';});});}}); var sc=score(asg); document.getElementById('mtpS').textContent=step; document.getElementById('mtpE').textContent=evals; var V=document.getElementById('mtpV');V.textContent=sc[0];V.className='v '+(sc[0]?'bad':'good'); var O=document.getElementById('mtpO');O.textContent=sc[1];O.className='v'+(sc[1]===324?' good':''); spark();drawGraph(null);postH(); } function spark(){ var s=document.getElementById('mtpSpark'),pts=hist.length?hist:[score(asg)[1]]; var mx=Math.max.apply(null,pts.concat([600])),mn=300,n=Math.max(pts.length-1,12); var p=pts.map(function(v,i){return (i/n*790+5)+','+(65-(v-mn)/(mx-mn)*58);}).join(' '); var ideal=65-(324-mn)/(mx-mn)*58; s.innerHTML='<line x1="0" x2="800" y1="'+ideal+'" y2="'+ideal+'" stroke="#2BD99F" stroke-dasharray="4 4" opacity=".6"/><polyline points="'+p+'" fill="none" stroke="#38D6FF" stroke-width="2.5"/>'+pts.map(function(v,i){return '<circle cx="'+(i/n*790+5)+'" cy="'+(65-(v-mn)/(mx-mn)*58)+'" r="3.5" fill="#0866FF" stroke="#fff" stroke-width="1"/>';}).join(''); } var logEl=document.getElementById('mtpLog'); function doStep(){ var r=bestMove();evals+=r.n; if(!r.best){stop();logEl.textContent='Lokales Optimum: Keine Verschiebung oder kein Tausch verbessert den Score ('+evals+' Auswertungen).';render();return false;} var old=asg;asg=r.best.a;step++;hist.push(score(asg)[1]); var moved=r.best.ids;logEl.textContent='Schritt '+step+': '+r.best.txt+' (geprüfte Kandidaten: '+r.n+')'; render(moved);drawGraph(diff(old,asg));return true; } function diff(a,b){var s={};for(var i=0;i<a.length;i++)if(a[i]!==b[i]){s[a[i]]=1;s[b[i]]=1;}return Object.keys(s).map(Number);} function stop(){if(timer){clearInterval(timer);timer=null;}document.getElementById('mtpRun').textContent=' Lokale Suche ausführen';} document.getElementById('mtpRun').onclick=function(){if(timer){stop();return;}this.textContent='❚❚ Pause';if(!doStep())return;timer=setInterval(function(){if(!doStep())stop();},900);}; document.getElementById('mtpStep').onclick=function(){stop();doStep();}; function resetTo(a,msg){stop();asg=a;step=0;evals=0;hist=[score(asg)[1]];logEl.textContent=msg;render();} document.getElementById('mtpReset').onclick=function(){resetTo(START.slice(),'Server S1 startet mit 4 CPU über Kapazität. Klicke auf Ausführen.');}; document.getElementById('mtpShuf').onclick=function(){var a=[];for(var i=0;i<12;i++)a.push(Math.random()<.55?Math.floor(Math.random()*2):Math.floor(Math.random()*4));resetTo(a,'Neuer zufälliger Start. Klicke auf Ausführen.');}; /* Ausdrucksgraph */ var G=document.getElementById('mtpGraph'),gLog=document.getElementById('mtpGLog'); var LX=[110,300,490,680]; function drawGraph(live){ live=live||[];var u=util(asg),sc=score(asg),h=''; function on(s){return live.indexOf(s)>-1;} var any=live.length>0; for(var s=0;s<4;s++){ h+='<path class="edge'+(on(s)?' live':'')+'" d="M'+LX[s]+',232 L'+LX[s]+',172"/>'; h+='<path class="edge'+(on(s)?' live':'')+'" d="M'+LX[s]+',138 C'+LX[s]+',100 300,110 300,78"/>'; h+='<path class="edge'+(on(s)?' live':'')+'" d="M'+(LX[s]+40)+',233 C'+(LX[s]+60)+',200 650,130 650,78"/>'; } h+='<path class="edge'+(any?' live':'')+'" d="M300,44 L300,22"/><path class="edge'+(any?' live':'')+'" d="M650,44 L650,22"/>'; function node(x,y,w,label,val,l){return '<g class="node'+(l?' live':'')+'"><rect x="'+(x-w/2)+'" y="'+(y-17)+'" width="'+w+'" height="34" rx="8"/><text x="'+x+'" y="'+(y-2)+'">'+label+'</text><text class="val" x="'+x+'" y="'+(y+11)+'">'+val+'</text></g>';} for(var k=0;k<4;k++){h+=node(LX[k],250,96,'U(S'+(k+1)+')','= '+u[k],on(k));h+=node(LX[k],155,96,'SQUARE','= '+u[k]*u[k],on(k));} h+=node(300,61,120,'SUM','= '+sc[1],any);h+=node(650,61,120,'MAX','= '+Math.max.apply(null,u),any); h+='<text x="300" y="14" fill="#4C9BFF" font-size="11" font-weight="700" text-anchor="middle">BalanceSpec-Zielfunktion</text>'; h+='<text x="650" y="14" fill="'+(Math.max.apply(null,u)>CAP?'#FF5A6E':'#2BD99F')+'" font-size="11" font-weight="700" text-anchor="middle">CapacitySpec: MAX ≤ '+CAP+(Math.max.apply(null,u)>CAP?' (verletzt)':' (ok)')+'</text>'; h+='<text x="410" y="292" fill="#93A3BF" font-size="11" text-anchor="middle">Blätter: Auslastung pro Server · in diesem Zug neu berechnete Knoten: '+(any?(live.length*2+2):0)+' von 10</text>'; G.innerHTML=h; } document.getElementById('mtpGMove').onclick=function(){stop();var i=Math.floor(Math.random()*12),s;do{s=Math.floor(Math.random()*4);}while(s===asg[i]);var old=asg;asg=asg.slice();asg[i]=s;evals++;step++;hist.push(score(asg)[1]);render([i]);var d=diff(old,asg);drawGraph(d);gLog.textContent='Verschoben: t'+(i+1)+' S'+(old[i]+1)+' → S'+(s+1)+'. Nur '+(d.length*2+2)+' von 10 Knoten benötigten neue Werte.';}; document.getElementById('mtpGBest').onclick=function(){stop();var r=bestMove();evals+=r.n;if(!r.best){gLog.textContent='Lokales Optimum erreicht. Versuche zuerst einen zufälligen Zug.';render();return;}var old=asg;asg=r.best.a;step++;hist.push(score(asg)[1]);render(r.best.ids);var d=diff(old,asg);drawGraph(d);gLog.textContent='Beste von '+r.n+' Kandidaten: '+r.best.txt+'. Neu berechnet: '+(d.length*2+2)+' von 10 Knoten.';}; /* Löser-Auswahl */ var Os=document.getElementById('mtpOs'),Bs=document.getElementById('mtpBs'); function fmt(n){if(n>=1e9)return (n/1e9).toFixed(n>=1e10?0:1)+'B';if(n>=1e6)return (n/1e6).toFixed(n>=1e7?0:1)+'M';if(n>=1e3)return (n/1e3).toFixed(n>=1e4?0:1)+'k';return Math.round(n)+'';} function pick(){ var o=exactO||Math.round(Math.pow(10,+Os.value)),b=exactB||Math.round(Math.pow(10,+Bs.value)),m=o*b,l=o+b;exactO=exactB=0; document.getElementById('mtpOv').textContent=fmt(o);document.getElementById('mtpBv').textContent=fmt(b); document.getElementById('mtpMv').textContent='≈ '+fmt(m);document.getElementById('mtpLv').textContent='≈ '+fmt(l); document.getElementById('mtpMb').style.width=Math.min(100,Math.log10(m)/11*100)+'%'; document.getElementById('mtpLb').style.width=Math.min(100,Math.log10(l)/11*100)+'%'; var v=document.getElementById('mtpVerdict'),t; if(m<=1e6){t='<b>Ein optimaler (MIP)-Löser ist ein guter Anfang.</b> Kleines Modell: übergebe es an HiGHS, Gurobi oder FICO Xpress und erhalte eine beweisbar optimale Zuordnung.';v.style.borderColor='#2BD99F';} else if(m<=1e8){t='<b>Mit MIP prototypisieren, dann zu lokaler Suche wechseln.</b> Meta sagt, dass dies ein häufiger Weg ist: finde eine starke Basislinie mit dem optimalen Löser und migriere dann.';v.style.borderColor='#4C9BFF';} else{t='<b>Lokale Suche.</b> Das MIP würde ≈ '+fmt(m)+' Binärvariablen benötigen im worst case, während jede Local-Search-Nachbarschaft nahe '+fmt(l)+' bleibt. Meta rechnet fast alle großen Probleme auf diese Weise.';v.style.borderColor='#38D6FF';} v.innerHTML=t;postH(); } var exactO=0,exactB=0;Os.oninput=pick;Bs.oninput=pick; document.querySelectorAll('#mtpP2 button[data-o]').forEach(function(btn){btn.onclick=function(){exactO=+btn.dataset.o;exactB=+btn.dataset.bn;Os.value=Math.log10(+btn.dataset.o);Bs.value=Math.log10(+btn.dataset.bn);pick();};}); /* stats */ var counted=false; function count(){ var cards=document.querySelectorAll('#mtpCards .card'); cards.forEach(function(c,i){c.classList.remove('in');setTimeout(function(){c.classList.add('in');},90*i);}); document.querySelectorAll('#mtpCards [data-c]').forEach(function(el){var tgt=+el.dataset.c,dp=+(el.dataset.d||0),t0=null; function f(ts){if(!t0)t0=ts;var p=Math.min(1,(ts-t0)/1100),e=1-Math.pow(1-p,3);el.textContent=(tgt*e).toFixed(dp);if(p<1)requestAnimationFrame(f);}requestAnimationFrame(f);}); } /* tabs */ var tabs=R.querySelectorAll('.tab'); tabs.forEach(function(t){t.onclick=function(){tabs.forEach(function(x){x.classList.remove('on');});t.classList.add('on'); R.querySelectorAll('.pane').forEach(function(p){p.classList.remove('on');});document.getElementById('mtpP'+t.dataset.p).classList.add('on'); if(t.dataset.p==='3')count();if(t.dataset.p==='1')drawGraph(null);setTimeout(postH,60);setTimeout(postH,450);};}); hist=[score(asg)[1]];render();pick(); window.addEventListener('load',postH);window.addEventListener('resize',postH);setTimeout(postH,300); })(); </script> </body></html>">Rebalancer im Vergleich zu den engsten Open-Source-Alternativen
| Merkmal | Meta Rebalancer | Google OR-Tools | Timefold Solver (Community) |
|---|---|---|---|
| Lizenz | Apache 2.0 | Apache 2.0 | Apache 2.0 (Die Enterprise-Edition ist kommerziell) |
| Kernsprache | C++ | C++ | Java |
| APIs | C++, Python | C++, Python, Java, C# | Java, Kotlin |
| Fokus | Generische Zuweisung (Objekte zu Bins) | Umfangreiche Suite: CP-SAT, LP- und MIP-Wrapper, Routing, Packing, Zuweisung | Planung: Routing, Dienstpläne, Terminierung, Aufgabenverteilung |
| Lokale Suche | Ja, parallel, auf dem Ausdrucksgraphen | Ja, im Routing-Solver (guided local search, simulated annealing, tabu) | Ja, Kern-Engine (tabu, simulated annealing, late acceptance) |
| MIP-Backends | FICO Xpress, Gurobi, HiGHS | Wrapper für kommerzielle und Open-Source-MIP-Solver | Nicht verwendet |
| Debugging-UI | Rebalancer Explorer (Docker) | Nicht im README aufgeführt | Benchmarker; Score-Analyse in kommerziellen Editionen |
| Installation | pip install rebalancer | pip install ortools | Maven, JDK 21+ |
OR-Tools deckt mehr Problemklassen ab, und Timefold zielt auf JVM-Scheduling und -Routing. Rebalancers Vorteil ist eine Zuordnungsspezifikation, die sowohl auf lokaler Suche als auch auf MIP läuft.
Kernpunkte
- Rebalancer modelliert jedes Zuordnungsproblem als Objekte, Bins, Constraints und Ziele.
- Specs kompilieren zu einem Ausdrucksgraphen, der durch lokale Suche oder einen MIP-Solver gelöst wird.
- MIP-Backends umfassen FICO Xpress, Gurobi und das Open-Source-HiGHS.
- Meta löst etwa 40M Probleme pro Tag; P99 liegt bei 12s bei 265k Objekten und 3.2k Bins.
- Apache 2.0, C++- und Python-APIs, ab heute über PyPI installierbar.
Schauen Sie sich Paper, GitHub Repo und Technische Detailsan. Der gesamte Dank gilt dem Forscher dieses Projekts. Folgen Sie uns außerdem gerne auf Twitter und vergessen Sie nicht, unserem 150k+ML SubReddit beizutreten und unseren Newsletterzu abonnieren. Moment! Sind Sie auf Telegram? jetzt können Sie uns auch auf Telegram beitreten.
Der Beitrag Meta AI Open-Sources Rebalancer: Ein C++-Assignment-Solver, der täglich etwa 40 Million Zuordnungsprobleme löst erschien zuerst auf MarkTechPost.