void ZoneGroupManager::outputLoadValue() throw(Error) { //------------------------------------------------------------------ // ZoneGroup load //------------------------------------------------------------------ ofstream file("loadBalance.txt", ios::app); VSDateTime current = VSDateTime::currentDateTime(); file << current.toString() << endl; map< ZoneGroupID_t , ZoneGroup* >::const_iterator itr; for (itr = m_ZoneGroups.begin() ; itr != m_ZoneGroups.end() ; itr ++) { ZoneGroup* pZoneGroup = itr->second; file << "[" << (int)pZoneGroup->getZoneGroupID() << "] "; const map< ZoneID_t, Zone* >& zones = pZoneGroup->getZones(); map< ZoneID_t, Zone* >::const_iterator iZone; // 각 Zone의 loadValue를 구한다. int totalLoad = 0; for (iZone=zones.begin(); iZone!=zones.end(); iZone++) { Zone* pZone = iZone->second; int load = pZone->getLoadValue(); int playerLoad = pZone->getPCCount(); file << (int)pZone->getZoneID() << "(" << load << ", " << playerLoad << ") "; totalLoad += load; } file << " = " << totalLoad << endl; } file << endl; file.close(); }
//--------------------------------------------------------------------------- // make Balanced LoadInfo //--------------------------------------------------------------------------- // // bForce : balacing할 필요가 없다고 판단되는 경우에도 // 강제로 ZoneGroup을 balancing할 경우에 사용된다. // // Zone마다의 10초간의 loop 처리 회수를 load값으로 한다. // 계산에 편의를 위해서 실제 load는 다음과 같의 정의한다. // // load = (loadLimit - load)*loadMultiplier; // //--------------------------------------------------------------------------- bool ZoneGroupManager::makeBalancedLoadInfo(LOAD_INFOS& loadInfos, bool bForce) throw(Error) { const int maxGroup = m_ZoneGroups.size(); // zoneGroup 수 //const int loadMultiplier = 5; // load 가중치 - 느린 애들을 더 느리다...라고 하기 위한 것. const int loadLimit = 500; // load 값 제한 - sleep에 의해서 제한돼서 루프 처리회수 500이 최고다. const int stableLoad = 120; // 안정적인 load - 이 정도면 balancing이 필요없다고 생각되는 수준 //const int minLoadGap = 20 * loadMultiplier; // load balancing을 하기 위한 load 차이 - 최고~최저의 차이가 일정 값 이상이어야지 balancing이 의미있다. const int minLoadGap = 20; // load balancing을 하기 위한 load 차이 - 최고~최저의 차이가 일정 값 이상이어야지 balancing이 의미있다. const int averageLoadPercent = 90; // 한 group의 load % 제한. 100으로 해도 되겠지만 90정도가 괜찮은거 같다. int i; //LOAD_INFOS loadInfos; GROUPS groups; map< ZoneGroupID_t , ZoneGroup* >::const_iterator itr; // 전체 load int totalLoad = 0; //------------------------------------------------------------------ // ZoneGroup마다 loadValue 조사 //------------------------------------------------------------------ int maxLoadValue = 0; int minLoadValue = loadLimit; for (itr = m_ZoneGroups.begin() ; itr != m_ZoneGroups.end() ; itr ++) { ZoneGroup* pZoneGroup = itr->second; const map< ZoneID_t, Zone* >& zones = pZoneGroup->getZones(); map< ZoneID_t, Zone* >::const_iterator iZone; // 각 Zone의 loadValue를 구한다. for (iZone=zones.begin(); iZone!=zones.end(); iZone++) { Zone* pZone = iZone->second; int load = pZone->getLoadValue(); load = min(load, loadLimit); // 10~500 maxLoadValue = max(maxLoadValue, load); minLoadValue = min(minLoadValue, load); // 숫자 적은게 느린 거다. // 계산의 편의를 위해서 숫자를 뒤집?는다. --> 큰 숫자 부하가 큰 걸로 바꾼다. // player숫자를 부하가중치로 사용한다. // playerLoad = 1 ~ 20정도? int playerLoad = pZone->getPCCount()/10; playerLoad = max(1, playerLoad); //load = (loadLimit - load)*loadMultiplier; // 부하 가중치 load = (loadLimit - load)*playerLoad; // 부하 가중치 LoadInfo* pInfo = new LoadInfo; pInfo->id = pZone->getZoneID(); pInfo->oldGroupID = itr->first; pInfo->groupID = -1; pInfo->load = load; // 부하와 zoneID로 이루어진 key DWORD key = (load << 8) | pInfo->id; loadInfos[key] = pInfo; totalLoad += load; } } //------------------------------------------------------------------ // // balancing이 필요한지 확인 // //------------------------------------------------------------------ if (!bForce) { int loadBoundary = stableLoad; //int loadBoundary = (loadLimit - stableLoad ) * loadMultiplier; // 부하 한계 수치보다 작거나 // min~max 부하 수치 차이가 일정수치 이하이면 // load balancing할 필요가 없다. //if (maxLoad <= loadBoundary if (minLoadValue >= loadBoundary || maxLoadValue-minLoadValue <= minLoadGap) { // load를 다시 조사해야 한다. for (itr = m_ZoneGroups.begin() ; itr != m_ZoneGroups.end() ; itr ++) { ZoneGroup* pZoneGroup = itr->second; // loadValue를 초기화 시켜준다. const map< ZoneID_t, Zone* >& zones = pZoneGroup->getZones(); map< ZoneID_t, Zone* >::const_iterator iZone; // 각 Zone의 loadValue를 구한다. for (iZone=zones.begin(); iZone!=zones.end(); iZone++) { Zone* pZone = iZone->second; pZone->initLoadValue(); } } return false; } } // 평균 load //int avgLoad = totalLoad / maxGroups; // average를 90%로 잡은 경우 int avgLoad = totalLoad * averageLoadPercent / maxGroup / 100; // 새로운 그룹의 load를 계산하기 위해서 groups.reserve(maxGroup); for (i=0; i<maxGroup; i++) { groups[i] = 0; } // balancing하기 전의 상태 출력 //outputLoadValue(); //------------------------------------------------------------------ // // load balancing // // 약간의 변화를 준? FirstFit 사용. //------------------------------------------------------------------ LOAD_INFOS::const_iterator iInfo = loadInfos.begin(); int index = 0; for (; iInfo!=loadInfos.end(); iInfo++) { LoadInfo* pInfo = iInfo->second; // 들어갈 새 group을 찾는다. int newGroupID = -1; for (int k=0; k<maxGroup; k++) { int groupLoad = groups[index]; if (groupLoad+pInfo->load <= avgLoad) { newGroupID = index; if (++index>=maxGroup) index = 0; break; } if (++index>=maxGroup) index = 0; } // 적절한 group을 못 찾았으면 젤 값이 적은 group에 넣는다. if (newGroupID==-1) { newGroupID = 0; for (int k=1; k<maxGroup; k++) { if (groups[k] < groups[newGroupID]) { newGroupID = k; } } } // newGroupID에다가 Info를 추가한다. pInfo->groupID = newGroupID + 1; // 1을 증가시켜줘야 한다. -_-; groups[newGroupID] += pInfo->load; } return true; }