項目小結

前言:準備了大半年的東西,在上一個星期準備交付給客戶使用。怎麼交付給他們使用呢?就是把咱們程序員寫的的代碼發佈到客戶那邊的服務器環境中去。固然對於項目的功能咱們已經測試屢次了,本覺得很簡單的事情卻苦苦折磨了咱們一個星期多才算有個頭緒,並且還把以前一些功能屏蔽了。下面就把我這個星期的bug簡單記錄一下,這其中有我本身代碼的問題也有客戶環境那邊致使的問題。html

零:開發環境

     測試環境 java

             第一階段  LINUX服務器  + tomcat     war項目直接部署測試程序員

             第二階段   k8s + docker  web

     生產環境正則表達式

             騰訊雲平臺    docker + tsf平臺spring

一:虛驚一場

      其中我有個項目是用spring boot開發的,並且仍是個war項目,其餘的都是jar。恰恰就是這個項目在部署到客戶那邊常常出現異常重啓的現象。當時仍是測試階段,數據量還很小,天天就會重啓個8-10+次。這一現象可驚呆了鄙人(由於我第一感受就是死循環,內存泄漏致使的<嚴重並且低級>,由於這會嚴重影響個人聲譽^_^),故要急需解決。由於有一塊我用到了設計模式中的思想(單例+枚舉),來實現模板消息的發送。及恐慌是這一塊致使的。後通過排查雖然有些地方能夠優化。但不至於把項目搞死。無奈只好把問題拋出來,你們一塊兒想辦法解決,雖都提出了不少想法但都沒有最終解決問題,後讓客戶那邊幫咱們查看容器重啓的緣由,他告訴咱們cup佔用率太高。後來咱們把項目的啓動參數增長到2核+內存2014M(以前1核+512M),問題解決。docker

嘗試過程

  1.檢測是否因內存泄漏致使設計模式

     工具  postman  +  jvisualvm.exe     經過postman連續發送5000次請求,而且經過查看 jvisualvm 界面查看內存使用狀況(好像是512M會自動觸發java的回收GC機制)tomcat

    postman 設置連續發送屢次請求服務器

      

     jvisualvm( 目錄 **\jdk1.8.0_121\bin ) 查看內存佔用狀況

備註:可經過此工具來查看內存泄漏,cup佔用等狀況。512M觸發java回收機制

備註:由於垃圾回收機制的影響,若是若是給項目分配了較少的資源,就會頻繁調用GC,反而影響性能。而若是分配的核數較少更會影響項目的穩健型

  2.單例的思考

     單例對象應該是做爲工具對象,即該對象的屬性不該該所有能修改(要否則就失去的單例的意義),然對於不常常修改的屬性不該該影響其餘其餘人(其餘線程)使用。故我總結一下幾點設計單例的規則(已個人消息模板爲例)

     * >  可選屬性(參數)   ——  消息的內容,好比你中的那個獎品。可選屬性應該是每次使用都會被從新賦值,即對於一個可選屬性都應該有一個默認值。

     *>   不可選屬性(參數 ) ——  消息發送的URL,和消息發送的應用APPID(必須有否則就失去單例的意義)

  兩類屬性應該分來建立

有人說設計單例時應該考慮內存泄漏,我認爲是有道理的,應爲單例對象是用static關鍵字修飾,故其不會被垃圾回收機制GC回收到。若是其單例對象的屬性引用了大量的資源如一個map。就會致使該map也不會被回收到

 二:圖片下載

     因爲涉及IO流問題,就少不了編碼方式,即常出現的中文亂碼問題。針對這一塊,其實有出現多個問題,但總結起來就兩類問題,一類就是中文亂碼,另外一類就是客戶端那邊的網絡限制。真對問題的出現緣由,一方面就是編寫代碼的時候我欠思考,固然這是很難避免的,對於IO流的這一塊的複雜程度你們也是有目共睹的^_^。另外一方便就是咱們設計的時候沒有想打客戶那邊的網絡限制,固然就算想到了估計也要這麼作^_^。下面對該問題的詳細描述。

客戶網絡限制

    無論需求先給介紹一下發生場景,我作了一個編輯器(uedit百度的),客戶能夠利用該編輯器編輯文章,並生成HTML頁面。其中該編輯器中的大部分圖片可能都來自網絡,而我須要把網絡圖片下載到本地,下次顯示的時候就是咱們本身資源庫中的圖片。步驟以下

    步驟一》一個正則表達式獲取該文章中的全部圖片地址         

public static List<String> searchPicUrlInString(String html) {
        List<String> urlList = new ArrayList<String>();
        // 圖片網址正則
        String reg = "(http:|https:){1}[\\//]{2}[A-Za-z0-9.\\/\\-\\_\\%]+(bmp|jpeg|gif|png|jpg)";
        Pattern pattern = Pattern.compile(reg);
        Matcher matcher = null;
        matcher = pattern.matcher(html);
        while (matcher.find()) {
            String imageUrl = matcher.group(0);
            // 若是圖片已在chinatopfine,不返回
            if (imageUrl.contains("chinatopfine")) {
                continue;
            }
            // 若是圖片tobacco,不返回
            if (imageUrl.contains("tobacco")) {
                continue;
            }
            // mmbiz.qpic.cn"服務器不返回
            if (imageUrl.contains("mmbiz.qpic.cn")) {
                continue;
            }
            urlList.add(imageUrl);
        }
        return urlList;
    }
View Code

    步驟二》經過網絡圖片URL下載圖片,並返回咱們圖片地址(咱們本身的)

/**
     * 
     * @param picUrl
     *            網絡圖片地址
     * @param savePath
     *            保存路徑
     * @return 返回圖片名稱
     */
    public static String savePictureByUrl(String picUrl, String savePath) {
        // 生成圖片名
            String imgType = picUrl.substring(picUrl.lastIndexOf("."));
            String imgName = UUID.randomUUID().toString().replaceAll("-", "")
                    .toString()
                    + imgType;
            File f = new File(savePath);
            if (!f.exists()) {
                f.mkdirs();
            }
            String imgPath = savePath + File.separator + imgName;
            File file = new File(imgPath);
            URL url = null;
            try {
                url = new URL(picUrl);
                DataInputStream dataInputStream = new DataInputStream(
                        url.openStream());
                FileOutputStream fileOutputStream = new FileOutputStream(file);
                ByteArrayOutputStream output = new ByteArrayOutputStream();
                byte[] buffer = new byte[1024];
                int length;
    
                while ((length = dataInputStream.read(buffer)) > 0) {
                    output.write(buffer, 0, length);
                }
                fileOutputStream.write(output.toByteArray());
                dataInputStream.close();
                fileOutputStream.close();
    
            } catch (IOException e) {
                e.printStackTrace();
                log.info("本地備份圖片失敗:" + picUrl);
        }
        // 返回圖片名
        return imgName;

    }
View Code

但因爲客戶那邊限制的訪問外網的能力,最終這個功能被咱們捨棄了

中文亂碼

      其實中文亂碼發生在兩處,第一處就是前面說的編輯器中的文章不免會有中文,當時就是中文亂碼。當時我用的是FileOutputStream,簡單查看了一下該類不能指定編碼格式,但其的包裝類PrintStream能夠指定,這兩個問題也就很快解決了

    代碼以下    new PrintStream(new FileOutputStream(file),false, "UTF-8");

public static String saveHtmlByString2(String htmlName,String htmlDir, String content,
            File templateHtml) throws IOException {    
        // 生成html名和地址
        htmlName = htmlName
                + ".html";
        String htmlPath = htmlDir + htmlName;

        Document doc;
        try {
            doc = Jsoup.parse(templateHtml, "UTF-8");
        } catch (IOException e) {
            log.info("Html 模板解析錯誤:" + templateHtml.getAbsolutePath());
            throw e;
        }
        // 獲取模板中要 替換的標籤
        Element div = doc.getElementById("isme");
        // content替換爲content
        div.html(content);
        // 建立文件
        File filedir = new File(htmlDir);
        if (!filedir.exists()) {
            filedir.mkdirs();
        }
        // 建立文件
        File file = new File(htmlPath);
        file.createNewFile();
        PrintStream ps = new PrintStream(new FileOutputStream(file),false, "UTF-8");
        ps.println(doc.html());
        ps.flush();
        ps.close();
        return htmlName;
    }
View Code

    另外一處就是上傳帶有中文名的圖片(固然能夠直接修改圖片名稱把中文名替換,但由於某種業務緣由須要使用原圖片的名稱),我直接把war包發佈到咱們的測試環境即linix服務器是能夠上傳中文名圖片的爲何放到客戶的環境就很差用了呢?

   方法一   首先想到的方法就是和上面的解決思路同樣,經過包裝流指定編碼方式(很差用)

   方法二   指定服務器編碼格式(echo  $LANG查看),固然也是很差用(其實關鍵點,就是這)

   方法三   網上有人說文件的內容和System.getProperty(「file.encoding」)這個屬性有關而文件名和System.getProperty(「sun.jnu.encoding」)有關,固然測試結果仍是很差用。

   方法四   修改docker容器內的編碼格式,有這個想法時,我首先是進入了咱們本身的容器經過(echo  $LANG)命令發現沒有輸出,固然容器內的中文名圖片也是亂碼。感受一會兒問題就找到了根源。即個人項目的真正運行環境是容器。而後就從新修改建立鏡像的DockerFile以下問題解決^_^

WORKDIR /home

ADD wxcms.war /home/tomcat/webapps/
ADD myhosts /home/
ADD startup.sh /home/tomcat/bin/startup.sh

# 安裝必要的工具

RUN chmod -R 777 /home/tomcat/bin && \
        mkdir -p /qyhupload/wxkf && \
        mkdir -p /qyhupload/cyxx && \
        mkdir -p /qyhupload/information && \
        mkdir -p /qyhupload/company/ && \
        mkdir -p /qyhupload/cigarette/ && \
        mkdir -p /qyhupload/article && \
        mkdir -p /qyhupload/tuwenmessage && \
        ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai > /etc/timezone
RUN locale
 RUN localedef -i zh_CN -c -f UTF-8 zh_CN.UTF-8

RUN echo "export LC_ALL=zh_CN.UTF-8" >> /etc/profile && source /etc/profile
ENV LANG zh_CN.UTF-8

ENV LC_CTYPE zh_CN.UTF-8

三:入坑屢次,屢教不改,哀傷

     這塊內容纔是我最想總結的對本身的教訓, 有時候我爲了圖一時之便,把本來設計的規則棄置無論,也許當時本身還能夠控制但時間久了,或遇到本身沒法把控的問題出現。就會焦頭爛額,沒法下手。這一次有一個問題就狠狠的敲擊了我。

    長哎一聲,以致我當時的哀傷。事情簡單介紹一下,以前爲了方便本身查看bug,常常會把測試環境的代碼鏈接到本身的本地項目。雖然在當時時時段段會有點影響,但我圖方便就臨時啓動一下本地項目,也就問題解決了(當時就兩套環境),本身感受還挺方便。因此就僥倖一直這樣。但此次上真正環境,出現了一個問題驚動了咱們的小團隊,須要快熟解決..................不說了,浪費了不少時間也無從下手,以前僥倖獲取的方便也一會兒全還了回去。

相關文章
相關標籤/搜索