The important thing in life is to have a great aim , and the determination

          常用鏈接

          統(tǒng)計(jì)

          IT技術(shù)鏈接

          保險(xiǎn)相關(guān)

          友情鏈接

          基金知識(shí)

          生活相關(guān)

          最新評(píng)論

          2017年8月5日 #

          POI操作Excel

          一、POI概述   Apache POI是Apache軟件基金會(huì)的開(kāi)放源碼函式庫(kù),POI提供API給Java程序?qū)icrosoft Office格式檔案讀和寫的功能。   結(jié)構(gòu): HSSF - 提供讀寫Microsoft Excel格式檔案的功能。 XSSF - 提供讀寫Microsoft Excel OOXML格式檔案的功能。 HWPF - 提供讀寫Microsoft Word格式檔案的功能。 HSLF - 提供讀寫Microsoft PowerPoint格式檔案的功能。 HDGF - 提供讀寫Microsoft Visio格式檔案的功能。  使用必須引入依賴 org.apache.poi poi 3.17 注:3.17版本是支持jdk6的最后版本 二、HSSF概況   HSSF 是Horrible SpreadSheet Format的縮寫,通過(guò)HSSF,你可以用純Java代碼來(lái)讀取、寫入、修改Excel文件。HSSF 為讀取操作提供了兩類API:usermodel和eventusermodel,即“用戶模型”和“事件-用戶模型”。 三、 POI EXCEL文檔結(jié)構(gòu)類 HSSFWorkbook excel文檔對(duì)象 HSSFSheet excel的sheet HSSFRow excel的行 HSSFCell excel的單元格 HSSFFont excel字體 HSSFName 名稱 HSSFDataFormat 日期格式 HSSFHeader sheet頭 HSSFFooter sheet尾 HSSFCellStyle cell樣式 HSSFDateUtil 日期 HSSFPrintSetup 打印 HSSFErrorConstants 錯(cuò)誤信息表 四、EXCEL的讀寫操作 1、讀取“區(qū)域數(shù)據(jù).xls”并儲(chǔ)存于list集合中,“區(qū)域數(shù)據(jù).xls”如下圖 public List importXLS(){ ArrayList list = new ArrayList<>(); try {      //1、獲取文件輸入流      InputStream inputStream = new FileInputStream("/Users/Shared/區(qū)域數(shù)據(jù).xls");      //2、獲取Excel工作簿對(duì)象 HSSFWorkbook workbook = new HSSFWorkbook(inputStream);      //3、得到Excel工作表對(duì)象 HSSFSheet sheetAt = workbook.getSheetAt(0); //4、循環(huán)讀取表格數(shù)據(jù)      for (Row row : sheetAt) {        //首行(即表頭)不讀取 if (row.getRowNum() == 0) { continue; } //讀取當(dāng)前行中單元格數(shù)據(jù),索引從0開(kāi)始        String areaNum = row.getCell(0).getStringCellValue(); String province = row.getCell(1).getStringCellValue(); String city = row.getCell(2).getStringCellValue(); String district = row.getCell(3).getStringCellValue(); String postcode = row.getCell(4).getStringCellValue(); Area area = new Area(); area.setCity(city); area.setDistrict(district); area.setProvince(province);        area.setPostCode(postcode); list.add(area); }      //5、關(guān)閉流 workbook.close(); } catch (IOException e) { e.printStackTrace(); }   return list; } 2、導(dǎo)出數(shù)據(jù)到“區(qū)域數(shù)據(jù).xls”文件中,頁(yè)面數(shù)據(jù)如下圖: public void exportExcel() throws IOException { Page page = areaService.pageQuery(null); List list = page.getContent(); //1.在內(nèi)存中創(chuàng)建一個(gè)excel文件 HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); //2.創(chuàng)建工作簿 HSSFSheet sheet = hssfWorkbook.createSheet(); //3.創(chuàng)建標(biāo)題行 HSSFRow titlerRow = sheet.createRow(0); titlerRow.createCell(0).setCellValue("省"); titlerRow.createCell(1).setCellValue("市"); titlerRow.createCell(2).setCellValue("區(qū)"); titlerRow.createCell(3).setCellValue("郵編"); titlerRow.createCell(4).setCellValue("簡(jiǎn)碼"); titlerRow.createCell(5).setCellValue("城市編碼"); //4.遍歷數(shù)據(jù),創(chuàng)建數(shù)據(jù)行 for (Area area : list) { //獲取最后一行的行號(hào) int lastRowNum = sheet.getLastRowNum(); HSSFRow dataRow = sheet.createRow(lastRowNum + 1); dataRow.createCell(0).setCellValue(area.getProvince()); dataRow.createCell(1).setCellValue(area.getCity()); dataRow.createCell(2).setCellValue(area.getDistrict()); dataRow.createCell(3).setCellValue(area.getPostcode()); dataRow.createCell(4).setCellValue(area.getShortcode()); dataRow.createCell(5).setCellValue(area.getCitycode()); } //5.創(chuàng)建文件名 String fileName = "區(qū)域數(shù)據(jù)統(tǒng)計(jì).xls"; //6.獲取輸出流對(duì)象 HttpServletResponse response = ServletActionContext.getResponse(); ServletOutputStream outputStream = response.getOutputStream(); //7.獲取mimeType ServletContext servletContext = ServletActionContext.getServletContext(); String mimeType = servletContext.getMimeType(fileName); //8.獲取瀏覽器信息,對(duì)文件名進(jìn)行重新編碼 HttpServletRequest request = ServletActionContext.getRequest(); fileName = FileUtils.filenameEncoding(fileName, request); //9.設(shè)置信息頭 response.setContentType(mimeType); response.setHeader("Content-Disposition","attachment;filename="+fileName); //10.寫出文件,關(guān)閉流 hssfWorkbook.write(outputStream); hssfWorkbook.close(); } 工具類 public class FileUtils { public static String filenameEncoding(String filename, HttpServletRequest request) throws IOException { String agent = request.getHeader("User-Agent"); //獲取瀏覽器 if (agent.contains("Firefox")) { BASE64Encoder base64Encoder = new BASE64Encoder(); filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?="; } else if(agent.contains("MSIE")) { filename = URLEncoder.encode(filename, "utf-8"); } else if(agent.contains ("Safari")) { filename = new String (filename.getBytes ("utf-8"),"ISO8859-1"); } else { filename = URLEncoder.encode(filename, "utf-8"); } return filename; } } 寫出xls文件: 五、 EXCEL常用操作方法 1、 得到Excel常用對(duì)象 POIFSFileSystem fs=newPOIFSFileSystem(new FileInputStream("d:/test.xls")); //得到Excel工作簿對(duì)象 HSSFWorkbook wb = new HSSFWorkbook(fs); //得到Excel工作表對(duì)象 HSSFSheet sheet = wb.getSheetAt(0); //得到Excel工作表的行 HSSFRow row = sheet.getRow(i); //得到Excel工作表指定行的單元格 HSSFCell cell = row.getCell((short) j); cellStyle = cell.getCellStyle();//得到單元格樣式 2、建立Excel常用對(duì)象 HSSFWorkbook wb = new HSSFWorkbook();//創(chuàng)建Excel工作簿對(duì)象 HSSFSheet sheet = wb.createSheet("new sheet");//創(chuàng)建Excel工作表對(duì)象 HSSFRow row = sheet.createRow((short)0); //創(chuàng)建Excel工作表的行 cellStyle = wb.createCellStyle();//創(chuàng)建單元格樣式 row.createCell((short)0).setCellStyle(cellStyle); //創(chuàng)建Excel工作表指定行的單元格 row.createCell((short)0).setCellValue(1); //設(shè)置Excel工作表的值 3、設(shè)置sheet名稱和單元格內(nèi)容 wb.setSheetName(1, "第一張工作表",HSSFCell.ENCODING_UTF_16); cell.setEncoding((short) 1); cell.setCellValue("單元格內(nèi)容"); 4、取得sheet的數(shù)目 wb.getNumberOfSheets() 5、 根據(jù)index取得sheet對(duì)象 HSSFSheet sheet = wb.getSheetAt(0); 6、取得有效的行數(shù) int rowcount = sheet.getLastRowNum(); 7、取得一行的有效單元格個(gè)數(shù) row.getLastCellNum(); 8、單元格值類型讀寫 cell.setCellType(HSSFCell.CELL_TYPE_STRING); //設(shè)置單元格為STRING類型 cell.getNumericCellValue();//讀取為數(shù)值類型的單元格內(nèi)容 9、設(shè)置列寬、行高 sheet.setColumnWidth((short)column,(short)width); row.setHeight((short)height); 10、添加區(qū)域,合并單元格 Region region = new Region((short)rowFrom,(short)columnFrom,(short)rowTo ,(short)columnTo);//合并從第rowFrom行columnFrom列 sheet.addMergedRegion(region);// 到rowTo行columnTo的區(qū)域 //得到所有區(qū)域 sheet.getNumMergedRegions() 11、保存Excel文件 FileOutputStream fileOut = new FileOutputStream(path); wb.write(fileOut); 12、根據(jù)單元格不同屬性返回字符串?dāng)?shù)值 public String getCellStringValue(HSSFCell cell) {   String cellValue = "";   switch (cell.getCellType()) {     case HSSFCell.CELL_TYPE_STRING://字符串類型         cellValue = cell.getStringCellValue();         if(cellValue.trim().equals("")||cellValue.trim().length()<=0)           cellValue=" ";         break;     case HSSFCell.CELL_TYPE_NUMERIC: //數(shù)值類型         cellValue = String.valueOf(cell.getNumericCellValue());         break;     case HSSFCell.CELL_TYPE_FORMULA: //公式         cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC);         cellValue = String.valueOf(cell.getNumericCellValue());         break;     case HSSFCell.CELL_TYPE_BLANK:         cellValue=" ";         break;     case HSSFCell.CELL_TYPE_BOOLEAN:         break;     case HSSFCell.CELL_TYPE_ERROR:         break;     default:         break;   }   return cellValue; } 13、常用單元格邊框格式 HSSFCellStyle style = wb.createCellStyle(); style.setBorderBottom(HSSFCellStyle.BORDER_DOTTED);//下邊框 style.setBorderLeft(HSSFCellStyle.BORDER_DOTTED);//左邊框 style.setBorderRight(HSSFCellStyle.BORDER_THIN);//右邊框 style.setBorderTop(HSSFCellStyle.BORDER_THIN);//上邊框 14、設(shè)置字體和內(nèi)容位置 HSSFFont f = wb.createFont(); f.setFontHeightInPoints((short) 11);//字號(hào) f.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);//加粗 style.setFont(f); style.setAlignment(HSSFCellStyle.ALIGN_CENTER);//左右居中 style.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);//上下居中 style.setRotation(short rotation);//單元格內(nèi)容的旋轉(zhuǎn)的角度 HSSFDataFormat df = wb.createDataFormat(); style1.setDataFormat(df.getFormat("0.00%"));//設(shè)置單元格數(shù)據(jù)格式 cell.setCellFormula(string);//給單元格設(shè)公式 style.setRotation(short rotation);//單元格內(nèi)容的旋轉(zhuǎn)的角度 15、插入圖片 //先把讀進(jìn)來(lái)的圖片放到一個(gè)ByteArrayOutputStream中,以便產(chǎn)生ByteArray ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); BufferedImage bufferImg = ImageIO.read(new File("ok.jpg")); ImageIO.write(bufferImg,"jpg",byteArrayOut); //讀進(jìn)一個(gè)excel模版 FileInputStream fos = new FileInputStream(filePathName+"/stencil.xlt"); fs = new POIFSFileSystem(fos); //創(chuàng)建一個(gè)工作薄 HSSFWorkbook wb = new HSSFWorkbook(fs); HSSFSheet sheet = wb.getSheetAt(0); HSSFPatriarch patriarch = sheet.createDrawingPatriarch(); HSSFClientAnchor anchor = new HSSFClientAnchor(0,0,1023,255,(short) 0,0,(short)10,10); patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG)); 16、調(diào)整工作表位置 HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet("format sheet"); HSSFPrintSetup ps = sheet.getPrintSetup(); sheet.setAutobreaks(true); ps.setFitHeight((short)1); ps.setFitWidth((short)1);

          posted @ 2020-03-20 10:13 鴻雁 閱讀(119) | 評(píng)論 (0)編輯 收藏

          python操作文件存在的問(wèn)題解決辦法

          1、在學(xué)習(xí)從文件讀取數(shù)據(jù)中,寫了個(gè)示例代碼,讀取不在同一個(gè)目錄的file.txt,運(yùn)行后報(bào)這個(gè)Python OSError: [Errno 22] Invalid argument:錯(cuò)誤: (1)、首先,在F盤的python_stu中新增了一個(gè)file.txt,同時(shí)在F盤的python_stu文件目錄底下新增一個(gè)file文件夾,里面有個(gè)file_reader.py來(lái)讀取python_stu文件目錄底下的file.txt,代碼分別如下: file.txt: 測(cè)試 測(cè)試2 測(cè)試3 file_reader.py: with open('F:\python_stu\file.txt') as file_obj: contents = file_obj.read(); print(contents.rstrip()); (2)、運(yùn)行后報(bào)錯(cuò): (3)、出現(xiàn)這種錯(cuò)誤的原因是由于讀取不到這個(gè)文件,看Traceback報(bào)的錯(cuò)誤,最后一行,很明顯讀取不到file.txt,前面的F:\\python_stu沒(méi)錯(cuò),后面的名稱怎么變了,還是x0cile.txt。 (4)、解決辦法,可修改上述第一行代碼為: with open('F:\python_stu/file.txt') as file_obj: 或者: with open('F:/python_stu/file.txt') as file_obj: 或者: with open('F://python_stu//file.txt') as file_obj: 又或者: with open('F:\\python_stu\\file.txt') as file_obj: 還有一些我就不附上了,上面第一種方式不統(tǒng)一,最好不要用,用統(tǒng)一的方式,而且有時(shí)候還有注意一些轉(zhuǎn)義字符,比如 \t,\n也會(huì)導(dǎo)致報(bào)錯(cuò)。

          posted @ 2019-05-14 23:04 鴻雁 閱讀(161) | 評(píng)論 (0)編輯 收藏

          Hadoop-2.4.1學(xué)習(xí)之QJM HA的自動(dòng)故障轉(zhuǎn)移

          前面學(xué)習(xí)了使用命令hdfs haadmin -failover手動(dòng)進(jìn)行故障轉(zhuǎn)移,在該模式下,即使現(xiàn)役NameNode已經(jīng)失效,系統(tǒng)也不會(huì)自動(dòng)從現(xiàn)役NameNode轉(zhuǎn)移到待機(jī)NameNode,下面學(xué)習(xí)如何配置部署HA自動(dòng)進(jìn)行故障轉(zhuǎn)移。自動(dòng)故障轉(zhuǎn)移為HDFS部署增加了兩個(gè)新組件:ZooKeeper和ZKFailoverController(ZKFC)進(jìn)程。ZooKeeper是維護(hù)少量協(xié)調(diào)數(shù)據(jù),通知客戶端這些數(shù)據(jù)的改變和監(jiān)視客戶端故障的高可用服務(wù)。HA的自動(dòng)故障轉(zhuǎn)移依賴于ZooKeeper的以下功能:

          • 故障檢測(cè):集群中的每個(gè)NameNode在ZooKeeper中維護(hù)了一個(gè)持久會(huì)話,如果機(jī)器崩潰,ZooKeeper中的會(huì)話將終止,ZooKeeper通知另一個(gè)NameNode需要觸發(fā)故障轉(zhuǎn)移。
          • 現(xiàn)役NameNode選擇:ZooKeeper提供了一個(gè)簡(jiǎn)單的機(jī)制用于唯一的選擇一個(gè)節(jié)點(diǎn)為active狀態(tài)。如果目前現(xiàn)役NameNode崩潰,另一個(gè)節(jié)點(diǎn)可能從ZooKeeper獲得特殊的排外鎖以表明它應(yīng)該成為現(xiàn)役NameNode。

                 ZKFC是自動(dòng)故障轉(zhuǎn)移中的另一個(gè)新組件,是ZooKeeper的客戶端,也監(jiān)視和管理NameNode的狀態(tài)。每個(gè)運(yùn)行NameNode的主機(jī)也運(yùn)行了一個(gè)ZKFC進(jìn)程,ZKFC負(fù)責(zé):

          • 健康監(jiān)測(cè):ZKFC使用一個(gè)健康檢查命令定期地ping與之在相同主機(jī)的NameNode,只要該NameNode及時(shí)地回復(fù)健康狀態(tài),ZKFC認(rèn)為該節(jié)點(diǎn)是健康的。如果該節(jié)點(diǎn)崩潰,凍結(jié)或進(jìn)入不健康狀態(tài),健康監(jiān)測(cè)器標(biāo)識(shí)該節(jié)點(diǎn)為非健康的。
          • ZooKeeper會(huì)話管理:當(dāng)本地NameNode是健康的,ZKFC保持一個(gè)在ZooKeeper中打開(kāi)的會(huì)話。如果本地NameNode處于active狀態(tài),ZKFC也保持一個(gè)特殊的znode鎖,該鎖使用了ZooKeeper對(duì)短暫節(jié)點(diǎn)的支持,如果會(huì)話終止,鎖節(jié)點(diǎn)將自動(dòng)刪除。
          • 基于ZooKeeper的選擇:如果本地NameNode是健康的,且ZKFC發(fā)現(xiàn)沒(méi)有其它的節(jié)點(diǎn)當(dāng)前持有znode鎖,它將為自己獲取該鎖。如果成功,則它已經(jīng)贏得了選擇,并負(fù)責(zé)運(yùn)行故障轉(zhuǎn)移進(jìn)程以使它的本地NameNode為active。故障轉(zhuǎn)移進(jìn)城與前面描述的手動(dòng)故障轉(zhuǎn)移相似,首先如果必要保護(hù)之前的現(xiàn)役NameNode,然后本地NameNode轉(zhuǎn)換為active狀態(tài)。

                 在典型部署中,ZooKeeper守護(hù)進(jìn)程運(yùn)行在三個(gè)或者五個(gè)節(jié)點(diǎn)上,但由于ZooKeeper本身需要較少的資源,所以將ZooKeeper部署在與現(xiàn)役NameNode和待機(jī)NameNode相同的主機(jī)上,還可以將ZooKeeper部署到與YARN的ResourceManager相同的節(jié)點(diǎn)上。建議配置ZooKeeper將數(shù)據(jù)存儲(chǔ)在與HDFS元數(shù)據(jù)不同的硬盤上以得到最好的性能和隔離性。在配置自動(dòng)故障轉(zhuǎn)移之前需要先停掉集群,目前在集群運(yùn)行時(shí)還不可能將手動(dòng)故障轉(zhuǎn)移的安裝轉(zhuǎn)換為自動(dòng)故障轉(zhuǎn)移的安裝。接下來(lái)看看如何配置HA的自動(dòng)故障轉(zhuǎn)移。首先在hdfs-site.xml中添加下面的參數(shù),該參數(shù)的值默認(rèn)為false:

          1. <property>  
          2.    <name>dfs.ha.automatic-failover.enabled</name>  
          3.    <value>true</value>  
          4. </property>  

                 在core-site.xml文件中添加下面的參數(shù),該參數(shù)的值為ZooKeeper服務(wù)器的地址,ZKFC將使用該地址。

          1. <property>  
          2.    <name>ha.zookeeper.quorum</name> <value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>  
          3. </property>  

                 在HA或者HDFS聯(lián)盟中,上面的兩個(gè)參數(shù)還需要以NameServiceID為后綴,比如dfs.ha.automatic-failover.enabled.mycluster。除了上面的兩個(gè)參數(shù)外,還有其它幾個(gè)參數(shù)用于自動(dòng)故障轉(zhuǎn)移,比如ha.zookeeper.session-timeout.ms,但對(duì)于大多數(shù)安裝來(lái)說(shuō)都不是必須的。

                 在添加了上述的配置參數(shù)后,下一步就是在ZooKeeper中初始化要求的狀態(tài),可以在任一NameNode中運(yùn)行下面的命令實(shí)現(xiàn)該目的,該命令將在ZooKeeper中創(chuàng)建znode:

          1. $ hdfs zkfc -formatZK  

                 在啟用自動(dòng)故障轉(zhuǎn)移的集群中,start-dfs.sh腳本將在任何運(yùn)行NameNode的主機(jī)上自動(dòng)啟動(dòng)ZKFC守護(hù)進(jìn)程,一旦ZKFC啟動(dòng)完畢,它們將自動(dòng)選擇一個(gè)NameNode為現(xiàn)役NameNode。如果手動(dòng)管理集群中的服務(wù),需要在每臺(tái)運(yùn)行NameNode的主機(jī)上手動(dòng)啟動(dòng)ZKFC,命令為:

          1. hadoop-daemon.sh start zkfc  
          2. hdfs zkfc  

                 如果正在運(yùn)行一個(gè)安全的集群,可能想確保存儲(chǔ)在ZooKeeper中的信息也是安全的,這將阻止惡意的客戶端修改ZooKeeper中的元數(shù)據(jù)或者潛在地觸發(fā)一個(gè)錯(cuò)誤的故障轉(zhuǎn)移。為了保護(hù)ZooKeeper中的信息,首先在core-site.xml中添加下面的參數(shù):

          1. <property>  
          2.    <name>ha.zookeeper.auth</name>  
          3.    <value>@/path/to/zk-auth.txt</value>  
          4.  </property>  
          5.  <property>  
          6.    <name>ha.zookeeper.acl</name>  
          7.    <value>@/path/to/zk-acl.txt</value>  
          8.  </property>  

                 參數(shù)值中的@字符表示參數(shù)值保存在@后的硬盤文件中。第一個(gè)配置文件指定了ZooKeeper的認(rèn)證列表,其格式與ZK CLI使用的相同,例如:digest:hdfs-zkfcs:mypassword,其中hdfs-zkfcs為ZooKeeper的用戶名,mypassword為密碼。其次使用下面的命令為該認(rèn)證生成一個(gè)ZooKeeper訪問(wèn)控制列表:

          1. $ java -cp $ZK_HOME/lib/*:$ZK_HOME/zookeeper-3.4.2.jar org.apache.zookeeper.server.auth.DigestAuthenticationProvider hdfs-zkfcs:mypassword  
          2. output: hdfs-zkfcs:mypassword->hdfs-zkfcs:P/OQvnYyU/nF/mGYvB/xurX8dYs=   

                 拷貝->之后的字符串并添加digest:前綴,然后粘貼到zk-acls.txt中,例如:digest:hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=:rwcda。要想使ACLs生效,需要再次運(yùn)行zkfc –formatZK。最后可能像下面這樣在ZK CLI中驗(yàn)證ACLs:

          1. [zk: localhost:2181(CONNECTED) 1] getAcl /hadoop-ha  
          2. 'digest,'hdfs-zkfcs:vlUvLnd8MlacsE80rDuu6ONESbM=  
          3. : cdrwa  

                 在安裝完成自動(dòng)故障轉(zhuǎn)移后,或許需要測(cè)試一下。首先定位現(xiàn)役NameNode,可以通過(guò)訪問(wèn)NameNode的web頁(yè)面來(lái)確定哪個(gè)NameNode是active狀態(tài)的。一旦確定了處于active狀態(tài)的NameNode,就需要在該節(jié)點(diǎn)上制造點(diǎn)故障,比如使用命令kill -9 <pid of NN>模擬JVM崩潰,或重啟主機(jī)或拔掉網(wǎng)線來(lái)模擬不同的中斷。一旦觸發(fā)了自動(dòng)故障轉(zhuǎn)移,另一個(gè)NameNode應(yīng)該自動(dòng)在幾秒鐘內(nèi)變?yōu)閍ctive狀態(tài)。檢測(cè)到故障并觸發(fā)故障轉(zhuǎn)移由參數(shù)ha.zookeeper.session-timeout.ms控制,該參數(shù)為與core-site.xml中,默認(rèn)為5秒。如果測(cè)試不成功,可能是配置問(wèn)題,檢查ZKFC和NameNode進(jìn)程的日志以進(jìn)一步診斷問(wèn)題,通常錯(cuò)誤都是很明顯的。

          posted @ 2017-08-13 18:49 鴻雁 閱讀(434) | 評(píng)論 (0)編輯 收藏

          Yarn 調(diào)度器Scheduler詳解

          理想情況下,我們應(yīng)用對(duì)Yarn資源的請(qǐng)求應(yīng)該立刻得到滿足,但現(xiàn)實(shí)情況資源往往是有限的,特別是在一個(gè)很繁忙的集群,一個(gè)應(yīng)用資源的請(qǐng)求經(jīng)常需要等待一段時(shí)間才能的到相應(yīng)的資源。在Yarn中,負(fù)責(zé)給應(yīng)用分配資源的就是Scheduler。其實(shí)調(diào)度本身就是一個(gè)難題,很難找到一個(gè)完美的策略可以解決所有的應(yīng)用場(chǎng)景。為此,Yarn提供了多種調(diào)度器和可配置的策略供我們選擇。

          一、調(diào)度器的選擇

          在Yarn中有三種調(diào)度器可以選擇:FIFO Scheduler ,Capacity SchedulerFairS cheduler

          FIFO Scheduler把應(yīng)用按提交的順序排成一個(gè)隊(duì)列,這是一個(gè)先進(jìn)先出隊(duì)列,在進(jìn)行資源分配的時(shí)候,先給隊(duì)列中最頭上的應(yīng)用進(jìn)行分配資源,待最頭上的應(yīng)用需求滿足后再給下一個(gè)分配,以此類推。

          FIFO Scheduler是最簡(jiǎn)單也是最容易理解的調(diào)度器,也不需要任何配置,但它并不適用于共享集群。大的應(yīng)用可能會(huì)占用所有集群資源,這就導(dǎo)致其它應(yīng)用被阻塞。在共享集群中,更適合采用Capacity SchedulerFair Scheduler,這兩個(gè)調(diào)度器都允許大任務(wù)和小任務(wù)在提交的同時(shí)獲得一定的系統(tǒng)資源。

          下面“Yarn調(diào)度器對(duì)比圖”展示了這幾個(gè)調(diào)度器的區(qū)別,從圖中可以看出,在FIFO 調(diào)度器中,小任務(wù)會(huì)被大任務(wù)阻塞。

          而對(duì)于Capacity調(diào)度器,有一個(gè)專門的隊(duì)列用來(lái)運(yùn)行小任務(wù),但是為小任務(wù)專門設(shè)置一個(gè)隊(duì)列會(huì)預(yù)先占用一定的集群資源,這就導(dǎo)致大任務(wù)的執(zhí)行時(shí)間會(huì)落后于使用FIFO調(diào)度器時(shí)的時(shí)間。

          在Fair調(diào)度器中,我們不需要預(yù)先占用一定的系統(tǒng)資源,F(xiàn)air調(diào)度器會(huì)為所有運(yùn)行的job動(dòng)態(tài)的調(diào)整系統(tǒng)資源。如下圖所示,當(dāng)?shù)谝粋€(gè)大job提交時(shí),只有這一個(gè)job在運(yùn)行,此時(shí)它獲得了所有集群資源;當(dāng)?shù)诙€(gè)小任務(wù)提交后,F(xiàn)air調(diào)度器會(huì)分配一半資源給這個(gè)小任務(wù),讓這兩個(gè)任務(wù)公平的共享集群資源。

          需要注意的是,在下圖Fair調(diào)度器中,從第二個(gè)任務(wù)提交到獲得資源會(huì)有一定的延遲,因?yàn)樗枰却谝粋€(gè)任務(wù)釋放占用的Container。小任務(wù)執(zhí)行完成之后也會(huì)釋放自己占用的資源,大任務(wù)又獲得了全部的系統(tǒng)資源。最終的效果就是Fair調(diào)度器即得到了高的資源利用率又能保證小任務(wù)及時(shí)完成。

          Yarn調(diào)度器對(duì)比圖: 
          技術(shù)分享

          二、Capacity Scheduler(容器調(diào)度器)的配置

          2.1 容器調(diào)度介紹

          Capacity 調(diào)度器允許多個(gè)組織共享整個(gè)集群,每個(gè)組織可以獲得集群的一部分計(jì)算能力。通過(guò)為每個(gè)組織分配專門的隊(duì)列,然后再為每個(gè)隊(duì)列分配一定的集群資源,這樣整個(gè)集群就可以通過(guò)設(shè)置多個(gè)隊(duì)列的方式給多個(gè)組織提供服務(wù)了。除此之外,隊(duì)列內(nèi)部又可以垂直劃分,這樣一個(gè)組織內(nèi)部的多個(gè)成員就可以共享這個(gè)隊(duì)列資源了,在一個(gè)隊(duì)列內(nèi)部,資源的調(diào)度是采用的是先進(jìn)先出(FIFO)策略。

          通過(guò)上面那幅圖,我們已經(jīng)知道一個(gè)job可能使用不了整個(gè)隊(duì)列的資源。然而如果這個(gè)隊(duì)列中運(yùn)行多個(gè)job,如果這個(gè)隊(duì)列的資源夠用,那么就分配給這些job,如果這個(gè)隊(duì)列的資源不夠用了呢?其實(shí)Capacity調(diào)度器仍可能分配額外的資源給這個(gè)隊(duì)列,這就是“彈性隊(duì)列”(queue elasticity)的概念。

          在正常的操作中,Capacity調(diào)度器不會(huì)強(qiáng)制釋放Container,當(dāng)一個(gè)隊(duì)列資源不夠用時(shí),這個(gè)隊(duì)列只能獲得其它隊(duì)列釋放后的Container資源。當(dāng)然,我們可以為隊(duì)列設(shè)置一個(gè)最大資源使用量,以免這個(gè)隊(duì)列過(guò)多的占用空閑資源,導(dǎo)致其它隊(duì)列無(wú)法使用這些空閑資源,這就是”彈性隊(duì)列”需要權(quán)衡的地方。

          2.2 容器調(diào)度的配置

          假設(shè)我們有如下層次的隊(duì)列:

          root ├── prod └── dev     ├── eng     └── science 

          下面是一個(gè)簡(jiǎn)單的Capacity調(diào)度器的配置文件,文件名為capacity-scheduler.xml。在這個(gè)配置中,在root隊(duì)列下面定義了兩個(gè)子隊(duì)列proddev,分別占40%和60%的容量。需要注意,一個(gè)隊(duì)列的配置是通過(guò)屬性yarn.sheduler.capacity.<queue-path>.<sub-property>指定的,<queue-path>代表的是隊(duì)列的繼承樹(shù),如root.prod隊(duì)列,<sub-property>一般指capacitymaximum-capacity

          技術(shù)分享

          我們可以看到,dev隊(duì)列又被分成了engscience兩個(gè)相同容量的子隊(duì)列。devmaximum-capacity屬性被設(shè)置成了75%,所以即使prod隊(duì)列完全空閑dev也不會(huì)占用全部集群資源,也就是說(shuō),prod隊(duì)列仍有25%的可用資源用來(lái)應(yīng)急。我們注意到,engscience兩個(gè)隊(duì)列沒(méi)有設(shè)置maximum-capacity屬性,也就是說(shuō)engscience隊(duì)列中的job可能會(huì)用到整個(gè)dev隊(duì)列的所有資源(最多為集群的75%)。而類似的,prod由于沒(méi)有設(shè)置maximum-capacity屬性,它有可能會(huì)占用集群全部資源。

          Capacity容器除了可以配置隊(duì)列及其容量外,我們還可以配置一個(gè)用戶或應(yīng)用可以分配的最大資源數(shù)量、可以同時(shí)運(yùn)行多少應(yīng)用、隊(duì)列的ACL認(rèn)證等。

          2.3 隊(duì)列的設(shè)置

          關(guān)于隊(duì)列的設(shè)置,這取決于我們具體的應(yīng)用。比如,在MapReduce中,我們可以通過(guò)mapreduce.job.queuename屬性指定要用的隊(duì)列。如果隊(duì)列不存在,我們?cè)谔峤蝗蝿?wù)時(shí)就會(huì)收到錯(cuò)誤。如果我們沒(méi)有定義任何隊(duì)列,所有的應(yīng)用將會(huì)放在一個(gè)default隊(duì)列中。

          注意:對(duì)于Capacity調(diào)度器,我們的隊(duì)列名必須是隊(duì)列樹(shù)中的最后一部分,如果我們使用隊(duì)列樹(shù)則不會(huì)被識(shí)別。比如,在上面配置中,我們使用prodeng作為隊(duì)列名是可以的,但是如果我們用root.dev.eng或者dev.eng是無(wú)效的。

          三、Fair Scheduler(公平調(diào)度器)的配置

          3.1 公平調(diào)度

          Fair調(diào)度器的設(shè)計(jì)目標(biāo)是為所有的應(yīng)用分配公平的資源(對(duì)公平的定義可以通過(guò)參數(shù)來(lái)設(shè)置)。在上面的“Yarn調(diào)度器對(duì)比圖”展示了一個(gè)隊(duì)列中兩個(gè)應(yīng)用的公平調(diào)度;當(dāng)然,公平調(diào)度在也可以在多個(gè)隊(duì)列間工作。舉個(gè)例子,假設(shè)有兩個(gè)用戶A和B,他們分別擁有一個(gè)隊(duì)列。當(dāng)A啟動(dòng)一個(gè)job而B(niǎo)沒(méi)有任務(wù)時(shí),A會(huì)獲得全部集群資源;當(dāng)B啟動(dòng)一個(gè)job后,A的job會(huì)繼續(xù)運(yùn)行,不過(guò)一會(huì)兒之后兩個(gè)任務(wù)會(huì)各自獲得一半的集群資源。如果此時(shí)B再啟動(dòng)第二個(gè)job并且其它job還在運(yùn)行,則它將會(huì)和B的第一個(gè)job共享B這個(gè)隊(duì)列的資源,也就是B的兩個(gè)job會(huì)用于四分之一的集群資源,而A的job仍然用于集群一半的資源,結(jié)果就是資源最終在兩個(gè)用戶之間平等的共享。過(guò)程如下圖所示: 
          技術(shù)分享

          3.2 啟用Fair Scheduler

          調(diào)度器的使用是通過(guò)yarn-site.xml配置文件中的yarn.resourcemanager.scheduler.class參數(shù)進(jìn)行配置的,默認(rèn)采用Capacity Scheduler調(diào)度器。如果我們要使用Fair調(diào)度器,需要在這個(gè)參數(shù)上配置FairScheduler類的全限定名: org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler

          3.3 隊(duì)列的配置

          Fair調(diào)度器的配置文件位于類路徑下的fair-scheduler.xml文件中,這個(gè)路徑可以通過(guò)yarn.scheduler.fair.allocation.file屬性進(jìn)行修改。若沒(méi)有這個(gè)配置文件,F(xiàn)air調(diào)度器采用的分配策略,這個(gè)策略和3.1節(jié)介紹的類似:調(diào)度器會(huì)在用戶提交第一個(gè)應(yīng)用時(shí)為其自動(dòng)創(chuàng)建一個(gè)隊(duì)列,隊(duì)列的名字就是用戶名,所有的應(yīng)用都會(huì)被分配到相應(yīng)的用戶隊(duì)列中。

          我們可以在配置文件中配置每一個(gè)隊(duì)列,并且可以像Capacity 調(diào)度器一樣分層次配置隊(duì)列。比如,參考capacity-scheduler.xml來(lái)配置fair-scheduler: 
          技術(shù)分享

          隊(duì)列的層次是通過(guò)嵌套<queue>元素實(shí)現(xiàn)的。所有的隊(duì)列都是root隊(duì)列的孩子,即使我們沒(méi)有配到<root>元素里。在這個(gè)配置中,我們把dev隊(duì)列有分成了engscience兩個(gè)隊(duì)列。

          Fair調(diào)度器中的隊(duì)列有一個(gè)權(quán)重屬性(這個(gè)權(quán)重就是對(duì)公平的定義),并把這個(gè)屬性作為公平調(diào)度的依據(jù)。在這個(gè)例子中,當(dāng)調(diào)度器分配集群40:60資源給proddev時(shí)便視作公平,engscience隊(duì)列沒(méi)有定義權(quán)重,則會(huì)被平均分配。這里的權(quán)重并不是百分比,我們把上面的40和60分別替換成2和3,效果也是一樣的。注意,對(duì)于在沒(méi)有配置文件時(shí)按用戶自動(dòng)創(chuàng)建的隊(duì)列,它們?nèi)杂袡?quán)重并且權(quán)重值為1。

          每個(gè)隊(duì)列內(nèi)部仍可以有不同的調(diào)度策略。隊(duì)列的默認(rèn)調(diào)度策略可以通過(guò)頂級(jí)元素<defaultQueueSchedulingPolicy>進(jìn)行配置,如果沒(méi)有配置,默認(rèn)采用公平調(diào)度。

          盡管是Fair調(diào)度器,其仍支持在隊(duì)列級(jí)別進(jìn)行FIFO調(diào)度。每個(gè)隊(duì)列的調(diào)度策略可以被其內(nèi)部的<schedulingPolicy> 元素覆蓋,在上面這個(gè)例子中,prod隊(duì)列就被指定采用FIFO進(jìn)行調(diào)度,所以,對(duì)于提交到prod隊(duì)列的任務(wù)就可以按照FIFO規(guī)則順序的執(zhí)行了。需要注意,proddev之間的調(diào)度仍然是公平調(diào)度,同樣engscience也是公平調(diào)度。

          盡管上面的配置中沒(méi)有展示,每個(gè)隊(duì)列仍可配置最大、最小資源占用數(shù)和最大可運(yùn)行的應(yīng)用的數(shù)量。

          3.4 隊(duì)列的設(shè)置

          Fair調(diào)度器采用了一套基于規(guī)則的系統(tǒng)來(lái)確定應(yīng)用應(yīng)該放到哪個(gè)隊(duì)列。在上面的例子中,<queuePlacementPolicy> 元素定義了一個(gè)規(guī)則列表,其中的每個(gè)規(guī)則會(huì)被逐個(gè)嘗試直到匹配成功。例如,上例第一個(gè)規(guī)則specified,則會(huì)把應(yīng)用放到它指定的隊(duì)列中,若這個(gè)應(yīng)用沒(méi)有指定隊(duì)列名或隊(duì)列名不存在,則說(shuō)明不匹配這個(gè)規(guī)則,然后嘗試下一個(gè)規(guī)則。primaryGroup規(guī)則會(huì)嘗試把應(yīng)用放在以用戶所在的Unix組名命名的隊(duì)列中,如果沒(méi)有這個(gè)隊(duì)列,不創(chuàng)建隊(duì)列轉(zhuǎn)而嘗試下一個(gè)規(guī)則。當(dāng)前面所有規(guī)則不滿足時(shí),則觸發(fā)default規(guī)則,把應(yīng)用放在dev.eng隊(duì)列中。

          當(dāng)然,我們可以不配置queuePlacementPolicy規(guī)則,調(diào)度器則默認(rèn)采用如下規(guī)則:

          <queuePlacementPolicy> <rule name="specified" /> <rule name="user" /> </queuePlacementPolicy> 

          上面規(guī)則可以歸結(jié)成一句話,除非隊(duì)列被準(zhǔn)確的定義,否則會(huì)以用戶名為隊(duì)列名創(chuàng)建隊(duì)列。

          還有一個(gè)簡(jiǎn)單的配置策略可以使得所有的應(yīng)用放入同一個(gè)隊(duì)列(default),這樣就可以讓所有應(yīng)用之間平等共享集群而不是在用戶之間。這個(gè)配置的定義如下:

          <queuePlacementPolicy> <rule name="default" /> </queuePlacementPolicy> 

          實(shí)現(xiàn)上面功能我們還可以不使用配置文件,直接設(shè)置yarn.scheduler.fair.user-as-default-queue=false,這樣應(yīng)用便會(huì)被放入default 隊(duì)列,而不是各個(gè)用戶名隊(duì)列。另外,我們還可以設(shè)置yarn.scheduler.fair.allow-undeclared-pools=false,這樣用戶就無(wú)法創(chuàng)建隊(duì)列了。

          3.5 搶占(Preemption)

          當(dāng)一個(gè)job提交到一個(gè)繁忙集群中的空隊(duì)列時(shí),job并不會(huì)馬上執(zhí)行,而是阻塞直到正在運(yùn)行的job釋放系統(tǒng)資源。為了使提交job的執(zhí)行時(shí)間更具預(yù)測(cè)性(可以設(shè)置等待的超時(shí)時(shí)間),F(xiàn)air調(diào)度器支持搶占。

          搶占就是允許調(diào)度器殺掉占用超過(guò)其應(yīng)占份額資源隊(duì)列的containers,這些containers資源便可被分配到應(yīng)該享有這些份額資源的隊(duì)列中。需要注意搶占會(huì)降低集群的執(zhí)行效率,因?yàn)楸唤K止的containers需要被重新執(zhí)行。

          可以通過(guò)設(shè)置一個(gè)全局的參數(shù)yarn.scheduler.fair.preemption=true來(lái)啟用搶占功能。此外,還有兩個(gè)參數(shù)用來(lái)控制搶占的過(guò)期時(shí)間(這兩個(gè)參數(shù)默認(rèn)沒(méi)有配置,需要至少配置一個(gè)來(lái)允許搶占Container):

          - minimum share preemption timeout - fair share preemption timeout 

          如果隊(duì)列在minimum share preemption timeout指定的時(shí)間內(nèi)未獲得最小的資源保障,調(diào)度器就會(huì)搶占containers。我們可以通過(guò)配置文件中的頂級(jí)元素<defaultMinSharePreemptionTimeout>為所有隊(duì)列配置這個(gè)超時(shí)時(shí)間;我們還可以在<queue>元素內(nèi)配置<minSharePreemptionTimeout>元素來(lái)為某個(gè)隊(duì)列指定超時(shí)時(shí)間。

          與之類似,如果隊(duì)列在fair share preemption timeout指定時(shí)間內(nèi)未獲得平等的資源的一半(這個(gè)比例可以配置),調(diào)度器則會(huì)進(jìn)行搶占containers。這個(gè)超時(shí)時(shí)間可以通過(guò)頂級(jí)元素<defaultFairSharePreemptionTimeout>和元素級(jí)元素<fairSharePreemptionTimeout>分別配置所有隊(duì)列和某個(gè)隊(duì)列的超時(shí)時(shí)間。上面提到的比例可以通過(guò)<defaultFairSharePreemptionThreshold>(配置所有隊(duì)列)和<fairSharePreemptionThreshold>(配置某個(gè)隊(duì)列)進(jìn)行配置,默認(rèn)是0.5。

          posted @ 2017-08-05 00:35 鴻雁 閱讀(364) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 东源县| 五河县| 类乌齐县| 灵川县| 丹巴县| 融水| 海城市| 文登市| 青海省| 东乡| 青龙| 巴林右旗| 高邑县| 肃南| 贡觉县| 梁河县| 庄浪县| 璧山县| 江山市| 保亭| 古蔺县| 东港市| 仁布县| 贵溪市| 大姚县| 北宁市| 新龙县| 肃宁县| 京山县| 叶城县| 湘潭市| 新密市| 咸阳市| 香港 | 宁德市| 舞阳县| 台湾省| 邹城市| 阿图什市| 镇沅| 图木舒克市|