最近再写一个网络仿真器,里面参考了Max-MinFairness算法,这是一种比较理想、公平的带宽分配算法。其思路主要如下:首先是算法的准备,考察某一时刻的网络中所有的flow,由于每条flow都有其各个link,因此可以得到各个link上所有流经的flow,然后开始迭代,各个link都把capacity平均分给所有流经的flow,接着每条flow的速度就等于其最小link分配的带宽,然后每条link的剩余带宽就等于link的capacity减去所有流经的flow的速度的总和,再然后把link的剩余带宽作为capacity重新进行上面的迭代,直至所有flow在迭代中获得的带宽都小于一个阈值时,算法结束,带宽分配完成。
让我们来分析这个算法并考虑如何加速该算法的执行速度。首先,对于一些bottleneck的link,流经其的flow早早就不能分配带宽了,因此如果发现在某个迭代中某条link能够分配的带宽已经小于阈值,那么在下一轮迭代,所有流经其的flow都不再考察,即使某些flow并不是以该link为bottleneck,因此,算法结束的条件可以改为当所有flow都不再考察的时候。这样对不对呢,让我们分析一下。以该link为bottleneck的flow自然不用说了,所谓的bottleneck就是能够获取的带宽最小的link,那么最小的link已经不能分配带宽了,该flow自然不再考察。但不是以该link作为bottleneck的flow呢,它们有更小带宽的link,但是如果该link不是你的bottleneck,已经不能分配带宽了,那就刚不用说更小带宽的link了,所以这些flow也应该不再考察。好,算法的讲解和分析就到这儿了,下面就是算法的实现,笔者采用的Java语言。
public Map<Integer, List<TrafficState>> run() { Map<Integer, List<TrafficState>> resultMap = new HashMap<Integer, List<TrafficState>>(); int current = 0; // PrintWriter resultWriter = new PrintWriter(resultFileName); while (current < runtime) { List<Integer> runningFlowList = new ArrayList<Integer>(); // the first traverse,add the new flows and remove the shopped flow for (int i = 0; i < graph.traffics.size(); i++) { Traffic currentTraffic = graph.traffics.get(i); int starttime = currentTraffic.start; if (starttime <= current && !currentTraffic.isStopped) { List<Integer> linksList = currentTraffic.links; if (currentTraffic.totlesize == 0) { // start a new flow currentTraffic.totlesize = currentTraffic.flowsize; currentTraffic.leftsize = currentTraffic.totlesize; for (Integer linkno : linksList) { graph.links.get(linkno).trafficList .add(currentTraffic); } } // calculate the transfer bytes in a epoch currentTraffic.epochsize = currentTraffic.speed * ((float) period / 1000); currentTraffic.leftsize -= currentTraffic.epochsize; if (currentTraffic.leftsize <= 0 || currentTraffic.end == current) { // no more flowsize or time is up,stop it currentTraffic.isStopped = true; for (Integer linkno : linksList) { graph.links.get(linkno).trafficList .remove(currentTraffic); } } else runningFlowList.add(i); } } // print the measurement if (printTimeSet.contains(current)) { List<TrafficState> stateList = new ArrayList<TrafficState>(); for (Traffic traffic : graph.traffics) { //not the stop flows and the start ones just now if (!traffic.isStopped && traffic.totlesize != 0 && traffic.speed != 0) { TrafficState state = new TrafficState(); state.setBytes(traffic.epochsize); state.setDestination(traffic.destination); state.setSource(traffic.source); state.setThruput(traffic.speed); String pathString = traffic.source; int lastNode = Integer.parseInt(traffic.source); for (Integer linkno : traffic.links) { if (lastNode == graph.links.get(linkno).source) { pathString += "," + graph.links.get(linkno).target; lastNode = graph.links.get(linkno).target; } else { pathString += "," + graph.links.get(linkno).source; lastNode = graph.links.get(linkno).source; } // pathString += "," + // graph.links.get(linkno).target; } state.setPathString(pathString); state.setStarttime(traffic.start); state.setFlowsize(traffic.flowsize); state.setEndtime(traffic.end); stateList.add(state); } } resultMap.put(current, stateList); } // initialize all the links and traffics for (Link link : graph.links) { link.leftCapacity = link.capacity; } for (Traffic traffic : graph.traffics) { traffic.speed = 0; } Set<Integer> finishedTrafficSet = new HashSet<Integer>(); // the second traverse,set the throughput of each flow in next // iteration while (finishedTrafficSet.size() < runningFlowList.size()) { for (int i = 0; i < runningFlowList.size(); i++) { if (!finishedTrafficSet.contains(runningFlowList.get(i))) { Traffic currentTraffic = graph.traffics .get(runningFlowList.get(i)); currentTraffic.increSpeed = Float.MAX_VALUE; Link minLink = null; for (Integer linkno : currentTraffic.links) { Link currentLink = graph.links.get(linkno); int existFlowNum = 0;// the number of exist flows for (Traffic traffic : currentLink.trafficList) { if (traffic.increSpeed != 0 || traffic.speed == 0) { existFlowNum++; } } float currentLinkSpeed = (float) currentLink.leftCapacity / (float) existFlowNum; if (currentLinkSpeed < currentTraffic.increSpeed) { currentTraffic.increSpeed = currentLinkSpeed; minLink = currentLink; } } if (currentTraffic.increSpeed > 5) currentTraffic.speed += currentTraffic.increSpeed; else { currentTraffic.increSpeed = 0; if (minLink != null) { for (Traffic traffic : minLink.trafficList) { traffic.increSpeed = 0; finishedTrafficSet.add(graph.traffics .indexOf(traffic)); } } else finishedTrafficSet.add(runningFlowList.get(i)); } } } // link left capacity decrease the traffic increase throughput for (Link link : graph.links) { for (Traffic traffic : link.trafficList) { link.leftCapacity -= traffic.increSpeed; } } } current += period; } // resultWriter.close(); return resultMap; }
Max-Min Fairness带宽分配算法