Main.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package me.yoqi.servermanager;
  2. import java.io.BufferedReader;
  3. import java.io.BufferedWriter;
  4. import java.io.ByteArrayInputStream;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.FileReader;
  8. import java.io.FileWriter;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.io.InputStreamReader;
  12. import java.util.ArrayList;
  13. import java.util.HashMap;
  14. import java.util.LinkedHashMap;
  15. import java.util.List;
  16. import java.util.Map;
  17. import com.google.common.base.Charsets;
  18. /**
  19. * b数据优化空间很大,所以修改toMachine()函数,依据CPU最优进行分配 。 Created by liuyuqi.gov@msn.cn on
  20. * 2018/07/02.
  21. */
  22. public class Main {
  23. // 参数
  24. public static final double alpha = 10.;
  25. public static final double beta = 0.5;
  26. public static final int T = 98;
  27. public static final int EXEC_LIMIT = 100000;
  28. // 静态数据
  29. private int num_app; // app数 9338
  30. private int num_inst; // inst数 68219
  31. private int num_mac; // machine数 6000
  32. private int num_k; // 资源种类 200
  33. private List<Integer> cpuIter; // [0, 1, 2, ... 97]
  34. private Map<String, Integer> appIndex; // app_1,app_2字符串用0,1等数字替换,{app_1=0,
  35. // app_2=1,...,app_4=3}
  36. private Map<String, Integer> machineIndex;// {machine_1=0, machine_2=1,
  37. private List<Integer> machinePriorIndex = new ArrayList<Integer>();
  38. private String[] apps; // [app_1, app_2, app_3, app_4,
  39. private String[] machines;// [machine_1, machine_2, machine_3, machine_4,
  40. private Map<String, Integer> inst2AppIndex;// {inst_157=49}
  41. private double[][] appResources;// app 9338*200
  42. private LinkedHashMap<String, Double> appCPU = new LinkedHashMap<String, Double>();
  43. private double[][] machineResources;// 主机 6000*200
  44. private Map<Integer, Integer>[] appInterference;// 9338 限制条件[{}, {},
  45. // {3517=2}, {}, {5600=1,
  46. // 6747=2, 7707=2, 4830=2},
  47. // 动态数据
  48. private Map<String, Integer> inst2Machine;// 部署 {inst_33717=5456,
  49. // 这个数据类型和Map<String, Integer>有点区别,加上list会保存顺序
  50. private List<String> deployResult = new ArrayList<String>(); // [inst_33717,5456
  51. private List<String> instUnDelpoy = new ArrayList<String>();// 未部署的实例
  52. private List<String> instSortByDisk = new ArrayList<String>();// 未部署的实例
  53. private Map<String, Integer> inst2MachineDefaultConflict = new HashMap<String, Integer>();;// 记录初始部署冲突的实例和主机
  54. private double[][] machineResourcesUsed;// 6000*200
  55. private Map<Integer, Integer>[] machineHasApp;// 6000 [{}, {},{6004=1,
  56. /**
  57. * 先对disk排序,然后first fit
  58. *
  59. * @throws IOException
  60. * 读,写文件异常
  61. */
  62. private void run() throws IOException {
  63. // 1、对instance实例按照cpu使用率(98个点的均值)降序排列。
  64. int count = 0;
  65. File file = new File("resb/app_cpu.csv");
  66. BufferedReader br = new BufferedReader(new FileReader(file));
  67. // while((len = br.readLine()) != null){ }
  68. for (int i = 0; i < num_inst; i++) {
  69. String line = br.readLine();
  70. String[] parts = line.split(",", -1);
  71. appCPU.put(parts[0], Double.valueOf(parts[1]));
  72. }
  73. br.close();
  74. // 2、为每个machine主机预留一定CPU空间
  75. // 3、first fit策略将inst放到machine中
  76. String tmp_Res;
  77. String inst_tmp = null;
  78. int time_count = 0;
  79. long startTime = System.currentTimeMillis();
  80. long cost_time = 0;
  81. boolean flag = false;
  82. for (Map.Entry<String, Double> entry : appCPU.entrySet()) {
  83. // 判断是否部署过,如果部署过则重新部署
  84. flag = false;
  85. inst_tmp = entry.getKey();
  86. if (inst2Machine.containsKey(inst_tmp)) {
  87. pickInstance(inst_tmp);
  88. }
  89. for (int i = num_mac - 1; i >= 0; i--) {
  90. tmp_Res = toMachine(inst_tmp, i);
  91. if (tmp_Res == "success") {
  92. deployResult.add(inst_tmp + "," + "machine_" + (i + 1));
  93. flag = true;
  94. break;
  95. }
  96. }
  97. if (flag == false) {
  98. System.out.println(time_count);
  99. }
  100. time_count++;
  101. if (time_count % 5000 == 0) {
  102. cost_time = System.currentTimeMillis() - startTime;
  103. System.out.println("已经部署:" + time_count + " 剩余部署:" + (num_inst - time_count));
  104. System.out.println("预估剩余时间:" + ((cost_time / 1000) * (num_inst - time_count) / time_count) + "s");
  105. }
  106. }
  107. saveResult(deployResult);
  108. }
  109. // 读取数据
  110. protected void init(BufferedReader bufferedReader) throws IOException {
  111. cpuIter = new ArrayList<Integer>();
  112. for (int i = 0; i < T; i++)
  113. cpuIter.add(i);
  114. /** Read app_resources */
  115. num_app = Integer.parseInt(bufferedReader.readLine());// 9338
  116. apps = new String[num_app];
  117. for (int i = 0; i < num_app; i++) {// 循环app表每一行
  118. // appId,resources
  119. String line = bufferedReader.readLine();
  120. String[] parts = line.split(",", -1);
  121. List<Double> resources = new ArrayList<Double>();
  122. for (String x : parts[1].split("\\|", -1))// cpu
  123. resources.add(Double.parseDouble(x));
  124. for (String x : parts[2].split("\\|", -1))// mem
  125. resources.add(Double.parseDouble(x));
  126. for (int j = 3; j < parts.length; j++) // disk/P/M/PM
  127. resources.add(Double.parseDouble(parts[j]));
  128. if (i == 0) {
  129. num_k = resources.size();
  130. appIndex = new HashMap<String, Integer>();
  131. appResources = new double[num_app][num_k];
  132. }
  133. if (num_k != resources.size())
  134. throw new IOException("[DEBUG 2]Invaild problem");
  135. if (appIndex.containsKey(parts[0]))
  136. throw new IOException("[DEBUG 3]Invaild problem");
  137. appIndex.put(parts[0], i);
  138. apps[i] = parts[0];// [app_1, app_2, app_3, app_4]
  139. for (int j = 0; j < num_k; j++)
  140. appResources[i][j] = resources.get(j);
  141. }
  142. /** Read machine_resources */
  143. num_mac = Integer.parseInt(bufferedReader.readLine());// 6000
  144. machineResources = new double[num_mac][num_k];
  145. machineResourcesUsed = new double[num_mac][num_k];
  146. machineIndex = new HashMap<String, Integer>();// {machine_3791=3790,
  147. machineHasApp = new Map[num_mac];
  148. machines = new String[num_mac];
  149. for (int i = 0; i < num_mac; i++) {
  150. // machineId,resources
  151. String line = bufferedReader.readLine();
  152. String[] parts = line.split(",", -1);
  153. if (machineIndex.containsKey(parts[0]))
  154. throw new IOException("[DEBUG 4]Invaild problem");
  155. machineIndex.put(parts[0], i);
  156. machines[i] = parts[0];
  157. machineHasApp[i] = new HashMap<Integer, Integer>();
  158. double cpu = Double.parseDouble(parts[1]);
  159. double mem = Double.parseDouble(parts[2]);
  160. for (int j = 0; j < T; j++) {
  161. machineResources[i][j] = cpu;
  162. machineResources[i][T + j] = mem;
  163. }
  164. for (int j = 3; j < parts.length; j++)
  165. machineResources[i][2 * T + j - 3] = Double.parseDouble(parts[j]);
  166. for (int j = 0; j < num_k; j++)
  167. machineResourcesUsed[i][j] = 0.;
  168. }
  169. /** Read app_interference */
  170. int icnt = Integer.parseInt(bufferedReader.readLine());// 35242
  171. appInterference = new Map[num_app];
  172. for (int i = 0; i < num_app; i++)
  173. appInterference[i] = new HashMap<Integer, Integer>();
  174. for (int i = 0; i < icnt; i++) {
  175. String line = bufferedReader.readLine();
  176. String[] parts = line.split(",", -1);
  177. if (!appIndex.containsKey(parts[0]) || !appIndex.containsKey(parts[1]))
  178. throw new IOException("[DEBUG 8]Invaild problem");
  179. int app1 = appIndex.get(parts[0]);
  180. int app2 = appIndex.get(parts[1]);
  181. int limit = Integer.parseInt(parts[2]);
  182. Map<Integer, Integer> inter = appInterference[app1];
  183. if (inter.containsKey(app2))
  184. throw new IOException("[DEBUG 9]Invaild problem");
  185. if (app1 == app2)
  186. limit += 1; // self-interference +1 here
  187. inter.put(app2, limit);
  188. }
  189. /** Read instance_deploy */
  190. num_inst = Integer.parseInt(bufferedReader.readLine());// 68219
  191. inst2AppIndex = new HashMap<String, Integer>();// 68219*2
  192. // {inst_33717=8766,
  193. // inst_33718=2956}
  194. inst2Machine = new HashMap<String, Integer>();// {inst_33717=5456,
  195. for (int i = 0; i < num_inst; i++) {
  196. String line = bufferedReader.readLine();
  197. String[] parts = line.split(",", -1);
  198. if (inst2AppIndex.containsKey(parts[0]))
  199. throw new IOException("[DEBUG 5]Invaild problem");
  200. if (!appIndex.containsKey(parts[1]))
  201. throw new IOException("[DEBUG 6]Invaild problem");
  202. inst2AppIndex.put(parts[0], appIndex.get(parts[1]));
  203. if (!"".equals(parts[2])) {
  204. if (!machineIndex.containsKey(parts[2]))
  205. throw new IOException("[DEBUG 7]Invaild problem");
  206. toMachineDefault(parts[0], machineIndex.get(parts[2]));
  207. } else {
  208. instUnDelpoy.add(parts[0]);
  209. }
  210. }
  211. System.out.println("finish init");
  212. }
  213. private String toMachineDefault(String inst, int machineIt) {
  214. int appIt = inst2AppIndex.get(inst);
  215. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  216. String res_tmp = doCheck(inst, machineIt);
  217. if (res_tmp != "success") {
  218. inst2MachineDefaultConflict.put(inst, machineIt);
  219. }
  220. // 将inst放入新的machine
  221. inst2Machine.put(inst, machineIt);
  222. if (!hasApp.containsKey(appIt))
  223. hasApp.put(appIt, 0);
  224. hasApp.put(appIt, hasApp.get(appIt) + 1);
  225. for (int i = 0; i < num_k; i++)
  226. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  227. return "success";
  228. }
  229. private String toMachine(String inst, int machineIt) {
  230. return toMachine(inst, machineIt, true);
  231. }
  232. private String doCheck(String inst, int machineIt) {
  233. int appIt = inst2AppIndex.get(inst);
  234. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  235. // 检查互斥规则,初始数据这里有冲突
  236. int nowHas = 0;
  237. if (hasApp.containsKey(appIt))
  238. nowHas = hasApp.get(appIt);
  239. for (Integer conditionalApp : hasApp.keySet()) {
  240. if (hasApp.get(conditionalApp) <= 0)
  241. continue;
  242. if (!appInterference[conditionalApp].containsKey(appIt))
  243. continue;
  244. if (nowHas + 1 > appInterference[conditionalApp].get(appIt)) {
  245. return "App Interference, inst: " + inst + ", " + apps[conditionalApp] + " -> " + apps[appIt] + ", "
  246. + (nowHas + 1) + " > " + appInterference[conditionalApp].get(appIt);
  247. }
  248. }
  249. // 初始数据这里有冲突
  250. for (Integer checkApp : hasApp.keySet()) {
  251. if (!appInterference[appIt].containsKey(checkApp))
  252. continue;
  253. if (hasApp.get(checkApp) > appInterference[appIt].get(checkApp)) {
  254. return "App Interference, inst: " + inst + ", " + apps[appIt] + " -> " + apps[checkApp] + ", "
  255. + (nowHas + 1) + " > " + appInterference[appIt].get(checkApp);
  256. }
  257. }
  258. // 检查资源限制,初始数据这里没有冲突
  259. for (int i = 0; i < num_k; i++)
  260. if (dcmp(
  261. machineResourcesUsed[machineIt][i] + appResources[appIt][i] - machineResources[machineIt][i]) > 0) {
  262. String res = "Resource Limit: inst: " + inst + ", " + "machine: " + machines[machineIt] + ", app: "
  263. + apps[appIt] + ", resIter: " + i + ", " + machineResourcesUsed[machineIt][i] + " + "
  264. + appResources[appIt][i] + " > " + machineResources[machineIt][i];
  265. // System.out.println(res);
  266. return res;
  267. }
  268. return "success";
  269. }
  270. private String deployByCPU(String inst, int machineIt) {
  271. int appIt = inst2AppIndex.get(inst);
  272. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  273. String res_tmp = doCheck(inst, machineIt);
  274. if (res_tmp != "success") {
  275. return res_tmp;
  276. }
  277. // 将inst放入新的machine
  278. inst2Machine.put(inst, machineIt);
  279. if (!hasApp.containsKey(appIt))
  280. hasApp.put(appIt, 0);
  281. hasApp.put(appIt, hasApp.get(appIt) + 1);
  282. for (int i = 0; i < num_k; i++)
  283. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  284. return "success";
  285. }
  286. private String toMachine(String inst, int machineIt, boolean doCheck) {
  287. int appIt = inst2AppIndex.get(inst);
  288. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  289. if (doCheck) {
  290. String res_tmp = doCheck(inst, machineIt);
  291. if (res_tmp != "success") {
  292. return res_tmp;
  293. }
  294. }
  295. // 将inst放入新的machine
  296. inst2Machine.put(inst, machineIt);
  297. if (!hasApp.containsKey(appIt))
  298. hasApp.put(appIt, 0);
  299. hasApp.put(appIt, hasApp.get(appIt) + 1);
  300. for (int i = 0; i < num_k; i++)
  301. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  302. return "success";
  303. }
  304. /**
  305. * 把实例inst 移除主机,撤销消耗资源
  306. *
  307. * @param inst
  308. * 实例id
  309. */
  310. private void pickInstance(String inst) {
  311. if (!inst2Machine.containsKey(inst))
  312. return;
  313. int appIt = inst2AppIndex.get(inst);
  314. int fromMachine = inst2Machine.get(inst);
  315. // 更新machineHasApp
  316. Map<Integer, Integer> fromHasApp = machineHasApp[fromMachine];
  317. fromHasApp.put(appIt, fromHasApp.get(appIt) - 1);
  318. if (fromHasApp.get(appIt) <= 0)
  319. fromHasApp.remove(appIt);
  320. // 更新machineResourcesUsed
  321. for (int i = 0; i < num_k; i++)
  322. machineResourcesUsed[fromMachine][i] -= appResources[appIt][i];
  323. // 更新inst2Machine
  324. inst2Machine.remove(inst);
  325. }
  326. private int dcmp(double x) {
  327. if (Math.abs(x) < 1e-9)
  328. return 0;
  329. return x < 0. ? -1 : 1;
  330. }
  331. private void saveResult(List<String> res) throws IOException {
  332. String res_path = "result.csv";
  333. File file = new File(res_path);
  334. if (!file.exists()) {
  335. file.createNewFile();
  336. }
  337. BufferedWriter writer = new BufferedWriter(new FileWriter(file));
  338. for (int i = 0; i < res.size(); i++) {
  339. writer.write(res.get(i));
  340. writer.newLine();
  341. }
  342. writer.close();
  343. }
  344. public static void main(String[] args) throws Exception {
  345. if (args.length != 4 && args.length != 2) {
  346. System.err.println(
  347. "传入参数有误,使用方式为:java -cp xxx.jar app_resources.csv machine_resources.csv instance_deploy.csv app_interference.csv");
  348. return;
  349. }
  350. System.out.println("-------开始部署啦--------");
  351. long startTime = System.currentTimeMillis(); // 获取开始时间
  352. InputStream problem;
  353. // app_resources.csv
  354. // machine_resources.csv
  355. // instance_deploy.csv
  356. // app_interference.csv
  357. if (args.length == 4) {
  358. // 将赛题拼成评测数据
  359. StringBuffer sb = new StringBuffer();
  360. for (int i = 0; i < 4; i++) {
  361. List<String> lines = new ArrayList<String>();
  362. BufferedReader bs = new BufferedReader(new FileReader(new File(args[i])));
  363. for (String line = bs.readLine(); line != null; line = bs.readLine())
  364. lines.add(line);
  365. sb.append("" + lines.size()).append("\n");
  366. for (String line : lines)
  367. sb.append(line).append("\n");
  368. }
  369. String alldata = sb.toString();
  370. problem = new ByteArrayInputStream(alldata.getBytes());
  371. } else {
  372. problem = new FileInputStream(args[0]);
  373. }
  374. // 评测
  375. Main evaluator = new Main();
  376. evaluator.init(new BufferedReader(new InputStreamReader(problem, Charsets.UTF_8)));
  377. System.out.println("默认已经部署了:" + evaluator.inst2Machine.size());
  378. evaluator.run();
  379. long endTime = System.currentTimeMillis(); // 获取结束时间
  380. System.out.println("程序运行时间:" + (endTime - startTime) / 1000 + "s"); // 输出程序运行时间
  381. System.out.println("-------部署结束啦--------");
  382. }
  383. }