项目小结

前言:准备了大半年的东西,在上一个星期准备交付给客户使用。怎么交付给他们使用呢?就是把咱们程序员写的的代码发布到客户那边的服务器环境中去。固然对于项目的功能咱们已经测试屡次了,本觉得很简单的事情却苦苦折磨了咱们一个星期多才算有个头绪,并且还把以前一些功能屏蔽了。下面就把我这个星期的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,常常会把测试环境的代码链接到本身的本地项目。虽然在当时时时段段会有点影响,但我图方便就临时启动一下本地项目,也就问题解决了(当时就两套环境),本身感受还挺方便。因此就侥幸一直这样。但此次上真正环境,出现了一个问题惊动了咱们的小团队,须要快熟解决..................不说了,浪费了不少时间也无从下手,以前侥幸获取的方便也一会儿全还了回去。

相关文章
相关标签/搜索