1 / 54

LB simulator by Jonathan Ledlie

LB simulator by Jonathan Ledlie. Model. Running the experiments. ./lb -l pareto.60min.4096n.3hours -H 3600 -c gnutella.4096n -C 100 -w 10 -k Z/1.2/4096 -O zipf.v1.i1.ak -f 100 -v 1 -i 1 -s 1000. char *usage = &quot;Usage: lb, Distributions<br>&quot;

Télécharger la présentation

LB simulator by Jonathan Ledlie

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. LB simulatorby Jonathan Ledlie

  2. Model

  3. Running the experiments ./lb -l pareto.60min.4096n.3hours -H 3600 -c gnutella.4096n -C 100 -w 10 -k Z/1.2/4096 -O zipf.v1.i1.ak -f 100 -v 1 -i 1 -s 1000

  4. char *usage = \ • "Usage: lb, Distributions\n" \ • " -l physical server lifetime and deathtime file\n" \ • " -H average physical server lifetime\n" \ • " -c physical server capacity file (requests/round/server)\n" \ • " -C average physical server capacity\n" \ • " -w queries per round per alive node\n" \ • " -k routing key distribution\n\n" \ • " Other parameters\n" • " -i number of ID choices when joining (default is 1, i.e., off). Zero is opt\n" \ • " -a [t|p|k] active load balancing method\n" \ • " t: virtual server transfer:\n" \ • " (1) If overloaded and have exactly one virtual server,\n" \ • " split virtual server into two.\n" \ • " (2) If overloaded and have more than one virtual server,\n" \ • " attempt to transfer a virtual servers.\n" \ • " Never delete or merge virtual servers.\n" \ • " p: pure virtual servers:\n" \ • " If overloaded this round and have more than one virtual server,\n" \ • " choose the least loaded virtual server that will make us unloaded\n" \ • " and delete it.\n" \ • " If underloaded and adding an average virtual server workload\n" \ • " will not put us over capacity,\n" \ • " create a virtual server\n" \ • " k: continue to use k-choices by actively rechoosing ids\n" \ • " based on perceived workload\n" \ • " g: use Ganesan's Threshold algorithm\n" \ • " -U upper slack pct above which we are overloaded (default .90) \n" \ • " -L lower slack pct below which we are underloaded (default .10)\n" \ • " -s random seed\n" \ • " -e epsilon difference between k-choice keys to make shift\n" \

  5. " -o oracle mode\n" \ " - node VSs match object distribution\n" \ " - all nodes are up at continuously\n" \ " -d debug\n" \ " -f frequency of runtime summary output (once every 1000 rounds is default)\n" \ " -v initial virtual servers per node (1 is default)\n" \ " -S shift workload to new distribution halfway through run\n" \ " -O output file prefix\n" \ " -p k-choices active dampening method\n" \ " 1: limit ids\n" \ " 2: limit create and delete\n" \ " 3: limit both\n" \ " -m kchoices (active) min capacity, below which rechoosing is dampened\n\n" \ "Distributions:\n" \ " Pareto P/scale/shape\n" \ " Normal N/mean/stddev\n" \ " Zipf Z/alpha/num-elements\n" \ " Poisson F/mean\n" \ " Uniform U [0..1)\n" \ " Constant C/value\n";

  6. Main program • int main (int argc, char **argv) { • while (!finished) { • DEBUG_P (("ROUND %d\n", cRound)); • Node Birth & Death •  time: pareto distribution •  capacity: trace driven • VS Creation, Deletion, Splitting, and Transfer • four protocols t/p/k/g • Finger Table Update • Queries •  Zipf distribution • } • }

  7. class PhysicalServer { • private: • int id; • double capacity; • int rechooseAttempts; • set<VirtualServer*> localVs; • void setNextLBactionTime (); • vector<double> keys; • set<double> usedKeys; • public: • void setNode (int id, double capacity); • double getRandomKey (); • bool sendMsg (int senderId, bool isQuery); • bool sendMaintMsg (double dstKey); • bool createVs (int vsCreateCount, double desiredWork, double &predictedWork); • bool splitVs (); • bool transferVs (int &vsDelta); • double chooseKey (vector<double> keyList, double desiredWork, • double &predictedWork, double skipKey, double &cost, • double &distanceFromCenter); • VirtualServer* addVs (double key); • };

  8. class VirtualServer { private: double key; double previousKey; public: PhysicalServer *rootPs; Fingers* fingers; bool sendMsg (int senderId, bool isQuery); bool sendMsg (VirtualServer *sender, bool isQuery); bool route (double dstKey, vector<double> &hops, vector<int> &fingersUsed, bool isQuery); bool route (double dstKey, vector<double> &hops, vector<int> &fingersUsed, bool isQuery, double dstVsKeyCache); bool findHopDistance (double dstKey, vector<double> &hops, vector<int> &fingersUsed, double dstVsKeyCache); void merge (VirtualServer *oldGuy); double getArcLength (); };

  9. 0 b 0 0 b 1 0 b 10 0 b 100 0 b 1000 0 b 1002 … 0 b 999 2 b 406 2 d 1730 3 d 2677 4 d 3006 5 b 1391 5 d 1950 5 d 3587 7 b 494 Node actions • birth/death (churn) • According to Pareto distribution • From file pareto.60min.4096n.3hours • Capacity (heterogeneous) • According to gnutella trace • From file gnutella.4096n 0 10 1 106 2 10 3 10 4 106 … 4090 10 4091 10 4092 106 4093 10 4094 1 4095 106

  10. gnutella.4096n 0 10 1 106 2 10 3 10 4 106 5 10 6 106 7 10 8 106 9 1 10 106 Node creation result 0 b 0 0 b 1 0 b 10 0 b 100 0 b 1000 0 b 1002 0 b 1006 //Non-oracle mode code R 0 Action: b node 0 R 0 PS 0 starting birth PS 0 create Vs key 0.894653 R 0 PS 0 finished birth arc 0.000000 psUp 1 cap 10.000000 (l 0.100000 u 9.900000) lvsSize 1 sysCap 9.900000 R 0 Action: b node 1 R 0 PS 1 starting birth PS 1 create Vs key 0.128510 R 0 PS 1 finished birth arc 0.233856 psUp 2 cap 106.000000 (l 1.060000 u 104.940000) lvsSize 1 sysCap 114.840000 R 0 Action: b node 10 R 0 PS 10 starting birth PS 10 create Vs key 0.885590 R 0 PS 10 finished birth arc 0.757080 psUp 3 cap 106.000000 (l 1.060000 u 104.940000) lvsSize 1 sysCap 219.780000 R 0 Action: b node 100

  11. Node creation result 0 b 997 0 b 999 2 b 406 2 d 1730 3 d 2677 4 d 3006 5 b 1391 ROUND 2 R 2 PS 406 starting birth PS 406 create Vs key 0.394836 R 2 PS 406 finished birth arc 0.000488 psUp 2018 cap 106.000000 (l 1.060000 u 104.940000) lvsSize 1 sysCap 198304.920000 PS 1730 death now 2 psUp 2018 vsSize 1 PS 1730 removing key 0.127899 PS 1730 remove Vs 0.127899

  12. Node creation psCount = initNodes (capacityFile, ps, initialVsPerNode); if (oracle) { //oracle mode } While (1){ //Non-oracle mode code } int initNodes (char *filename, PhysicalServer *&ps, int &initialVsPerNode) { int psCount = 0; vector<int> capacity; filename="gnutella.4096n" ; // by goophy fp = fopen(filename, "r"); // node-id capacity int id, cap; while (fscanf (fp, "%d %d\n", &id, &cap) > 0) { capacity[id] = cap; psCount++; } ps = new PhysicalServer[psCount]; for (int i = 0; i < psCount; i++) { ps[i].setNode (i, (double)(capacity[i])); } initStep (psCount/2 * initialVsPerNode); return psCount; }

  13. Node creation/oracle mode psCount = initNodes (capacityFile, ps, initialVsPerNode); if (oracle) { psCount /= 2; if (keyDist->getName() == 'z') { oracleAllocateVsZipf (keyDist,ps); } else if (keyDist->getName() == 'u') { oracleAllocateVsUniform (keyDist,ps); } for (int i = 0; i < psCount; i++) { ps[i].birth (0); } psUp = psCount; }

  14. Node creation/nonoracle mode while (!finished && ((action = nextEvent (nodeId)) != ' ')) { int vsAct = 0; int myInitialVsCount = initialVsPerNode; switch (action) { case 'b': if (activeLBmethod == 'p') { //k-choices active dampening method myInitialVsCount = (int)(ceil (ps[nodeId].getUpperTarget()/10.)); vsAct = ps[nodeId].birth (myInitialVsCount); break; case 'd': vsAct = ps[nodeId].death (); break; case 'r': recordingStats = true; break; case 'w': printf ("shifting workload\n"); delete keyDist; keyDist = distFactory->newDistribution (keyDistStr); break; case 'q': finished = true; break; } } if (!oracle && cRound == 0) { mergeVServers (); }

  15. int PhysicalServer::birth (int initialVsPerNode) { birthTime = cRound; deathTime = -1; util = 0.; usedKeys.clear (); haveDeletedVS = false; rechooseAttempts = 0; thresholdLevel = 0; thresholdShift = false; setNextLBactionTime (); currentTargetCapacity += (double)(upperTarget); systemTargetCapacity += capacity; double VsDesiredWork = 0.; double VsPredictedWork = 0.; if (idChoice == 1) { //number of ID choices when joining, default for (int i = 0; i < initialVsPerNode; i++) { if (createVs (initialVsPerNode, VsDesiredWork, VsPredictedWork)) { createCount++; } } } else { int maxToCreate = 3; if (maxToCreate > idChoice) maxToCreate = idChoice / 2; if (cRound < earliestLBround) maxToCreate = 1; bool createOK = true; VsDesiredWork = (upperTarget - lowerTarget) / 2. + lowerTarget; for (int i = 0; createCount == 0 || … maxToCreate > i); i++) { VsPredictedWork = 0.; createOK = createVs (initialVsPerNode, VsDesiredWork, VsPredictedWork); VsDesiredWork -= VsPredictedWork; } } psUp++; return createCount; }

  16. gnutella.4096n 0 10 1 106 2 10 3 10 4 106 5 10 6 106 7 10 8 106 9 1 10 106 VS creation result 0 b 0 0 b 1 0 b 10 0 b 100 0 b 1000 0 b 1002 0 b 1006 //Non-oracle mode code R 0 Action: b node 0 R 0 PS 0 starting birth PS 0 create Vs key 0.894653 R 0 PS 0 finished birth arc 0.000000 psUp 1 cap 10.000000 (l 0.100000 u 9.900000) lvsSize 1 sysCap 9.900000 R 0 Action: b node 1 R 0 PS 1 starting birth PS 1 create Vs key 0.128510 R 0 PS 1 finished birth arc 0.233856 psUp 2 cap 106.000000 (l 1.060000 u 104.940000) lvsSize 1 sysCap 114.840000 R 0 Action: b node 10 R 0 PS 10 starting birth PS 10 create Vs key 0.885590 R 0 PS 10 finished birth arc 0.757080 psUp 3 cap 106.000000 (l 1.060000 u 104.940000) lvsSize 1 sysCap 219.780000 R 0 Action: b node 100

  17. bool PhysicalServer::createVs (int vsCreateCount, double desiredWork, double &predictedWork) { ASSERT (alive); setNextLBactionTime (); double key; vector<double> keyList; if (idChoice != 1) { if (idChoice > 1) { if (localVs.size() >= idChoice) { return false; } keyList = getSampleKeys(); } statKeyListSize.push_back ((double)(keyList.size())); double cost, gap; key = chooseKey (keyList, desiredWork, predictedWork, -1., cost, gap); } else { key = getRandomKey (); } allKeys.insert (key); bool createdOK = true; … PhysicalServer::createVs

  18. bool PhysicalServer::createVs (int vsCreateCount, double desiredWork, • double &predictedWork) { • … • if (cRound == 0) {// Do not merge VSs right at beginning • addVs (key); DEBUG_P (("PS %d create Vs key %f\n", id, key)); • } else { • map<double,VirtualServer*>::iterator succ, pred; • succ = vServers.upper_bound (key); • if (succ == vServers.end()) succ = vServers.begin(); • if (succ->second->getRootPs() != this) {// merge, if we own our predecessor • pred = succ; • if (pred == vServers.begin()) {pred = vServers.end(); } • pred--; DEBUG_P (("PS %d create Vs key %f\n", id, key)); • VirtualServer* newVs = addVs (key); • if (pred->second->getRootPs() == this) { • DEBUG_P (("PS %d merging %f into %f\n", id, pred->first,key)); • newVs->merge (pred->second); • int vsCount = 0; deleteLocalVs (pred, vsCount); createdOK = false; • } • } else { • DEBUG_P (("PS %d aborting creation of %f because we are successor\n", • id, key)); createdOK = false; • } • } • return createdOK; } PhysicalServer::createVs

  19. VirtualServer* PhysicalServer::addVs (double key) { VirtualServer *vs = new VirtualServer (key, this); ASSERT (vs); vServers.insert(pair<double,VirtualServer*>(key,vs)); localVs.insert(vs); return vs; }

  20. setNextLBactionTime void PhysicalServer::setNextLBactionTime () { if (usingThreshold) nextLBactionTime = cRound + 60; nextLBactionTime = cRound + (int)(poisson ((double)lbActionInterval)); }

  21. Main program • int main (int argc, char **argv) { • while (!finished) { • DEBUG_P (("ROUND %d\n", cRound)); • Node Birth & Death •  time: pareto distribution •  capacity: trace driven • VS Creation, Deletion, Splitting, and Transfer • four protocols t/p/k/g • Finger Table Update • Queries •  Zipf distribution • } • }

  22. VS actions for (int i = 0; activeLBmethod != '-' && !oracle && cRound > earliestLBround && i < psCount; i++) { int vsCurrentSize = vServers.size(); if (activeLBmethod == 't') { //transfer } else if (activeLBmethod == 'p') { //proportion } else if (activeLBmethod == 'k') { } else if (activeLBmethod == 'g') { } }

  23. VS actions: transfer • if (ps[i].isOverloaded ()) { • if (ps[i].getVsCount () == 1) { • // split can fail if we are adjacent to our neighbor • if (ps[i].splitVs ()) { • ASSERT (vServers.size() == vsCurrentSize+1); • interimStats->splitVs(); • } • } else { • int vsDelta = 0; • if (ps[i].transferVs (vsDelta)) DEBUG_P (("successful transfer\n")); • } • } // if isOverloaded

  24. VS actions: proportion if (ps[i].isOverloaded () && ps[i].getVsCount () > 1) { int vsDelta = 0; ps[i].deleteVs(vsDelta); ASSERT (vServers.size() == vsCurrentSize+vsDelta); interimStats->deleteVs(); } else if (ps[i].isUnderloaded() && ps[i].canAddVs(maxVsPerNode)) { DEBUG_P (("PS %d about to createVs\n", i)); double targetWork = ps[i].getExtraCapacity(); double predictedWork = 0.; if (ps[i].createVs (1,targetWork,predictedWork)) { ASSERT (vServers.size() == vsCurrentSize+1); } // increment for any kind of activity interimStats->createVs(); }

  25. VS actions: K-choices if (ps[i].isOverloaded () || ps[i].isUnderloaded()) { int vsDelta = 0; int actionCode = ps[i].rechooseVs (vsDelta); switch (actionCode) { case 0: break; case 1: interimStats->createVs(); break; case 2: interimStats->deleteVs(); break; case 3: interimStats->deleteVs(); interimStats->createVs(); break; default: ASSERT (0); } }

  26. VS actions: g int vsDelta = 0; int actionCode = ps[i].thresholdVs (vsDelta); switch (actionCode) { case 0: break; case 1: // did neighbor adjust break; case 2: // did reorder interimStats->deleteVs(); interimStats->createVs(); break; default: ASSERT (0); }

  27. Main program • int main (int argc, char **argv) { • while (!finished) { • DEBUG_P (("ROUND %d\n", cRound)); • Node Birth & Death •  time: pareto distribution •  capacity: trace driven • VS Creation, Deletion, Splitting, and Transfer • four protocols t/p/k/g • Finger Table Update • Queries •  Zipf distribution • } • }

  28. R 0 Start of finger updates VS 0.000061 fixing fingers R 0 PS 2108 sendMsg work 0 R 0 VS 0.000061 set finger-1 for 0.000549 is 0.000641 R 0 PS 2998 sendMsg work 0 R 0 VS 0.000061 set finger-2 for 0.001038 is 0.002472 R 0 PS 2998 sendMsg work 1 R 0 VS 0.000061 set finger-3 for 0.002014 is 0.002472 R 0 PS 3031 sendMsg work 0 R 0 VS 0.000061 set finger-4 for 0.003967 is 0.004272 R 0 PS 931 sendMsg work 0 R 0 VS 0.000061 set finger-5 for 0.007874 is 0.009308 R 0 PS 3871 sendMsg work 0 R 0 VS 0.000061 set finger-6 for 0.015686 is 0.016144 R 0 PS 3537 sendMsg work 0 R 0 VS 0.000061 set finger-7 for 0.031311 is 0.031586 R 0 PS 87 sendMsg work 0 R 0 VS 0.000061 set finger-8 for 0.062561 is 0.063019 R 0 PS 2230 sendMsg work 0 R 0 VS 0.000061 set finger-9 for 0.125061 is 0.125153 R 0 PS 730 sendMsg work 0 R 0 VS 0.000061 set finger-10 for 0.250061 is 0.250641 R 0 PS 1029 sendMsg work 0 R 0 VS 0.000061 set finger-11 for 0.500061 is 0.500214 After round 0 0 b 996 0 b 997 0 b 999 2 b 406 2 d 1730 3 d 2677 4 d 3006 5 b 1391

  29. Finger updating DEBUG_P (("R %d Start of finger updates\n", cRound)); /* * UPDATE FINGER POINTERS */ deadVServersCountVector.push_back ((double)(deadVServers.size())); gracefulVServersCountVector.push_back ((double)(gracefulRelocateVServers.size())); if (!oracle || (oracle && cRound == 0)) { for (map<double,VirtualServer*>::iterator p = vServers.begin(); p != vServers.end(); p++) { int msgCount = p->second->fixFingers (); interimStats->maintMsg (msgCount); } deadVServers.clear (); gracefulRelocateVServers.clear (); } DEBUG_P (("R %d End of finger updates\n", cRound));

  30. Main program • int main (int argc, char **argv) { • while (!finished) { • DEBUG_P (("ROUND %d\n", cRound)); • Node Birth & Death •  time: pareto distribution •  capacity: trace driven • VS Creation, Deletion, Splitting, and Transfer • four protocols t/p/k/g • Finger Table Update • Queries •  Zipf distribution • } • }

  31. QUERIES 1/2 Query generation DEBUG_P (("QUERIES\n")); int queryCount = (int)(ceil(psUp * queriesPerRound)); map<double,VirtualServer*>::iterator p = vServers.lower_bound (randPct()); vector<double> dstKeys; dstKeys.reserve (queryCount); for (int i = 0; i < queryCount; i++) { double dstKey = keyDist->next(); //Zipf or Uniform dstKeys.push_back (dstKey); } int queryIndex = -1; int querySuccessCount = 0; deque<bool> previousQuerySuccess; initializePreviousQuerySuccess (previousQuerySuccess);

More Related