前言:准备了大半年的东西,在上一个星期准备交付给客户使用。怎么交付给他们使用呢?就是把咱们程序员写的的代码发布到客户那边的服务器环境中去。固然对于项目的功能咱们已经测试屡次了,本觉得很简单的事情却苦苦折磨了咱们一个星期多才算有个头绪,并且还把以前一些功能屏蔽了。下面就把我这个星期的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; }
步骤二》经过网络图片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; }
但因为客户那边限制的访问外网的能力,最终这个功能被咱们舍弃了
中文乱码
其实中文乱码发生在两处,第一处就是前面说的编辑器中的文章不免会有中文,当时就是中文乱码。当时我用的是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; }
另外一处就是上传带有中文名的图片(固然能够直接修改图片名称把中文名替换,但由于某种业务缘由须要使用原图片的名称),我直接把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,常常会把测试环境的代码链接到本身的本地项目。虽然在当时时时段段会有点影响,但我图方便就临时启动一下本地项目,也就问题解决了(当时就两套环境),本身感受还挺方便。因此就侥幸一直这样。但此次上真正环境,出现了一个问题惊动了咱们的小团队,须要快熟解决..................不说了,浪费了不少时间也无从下手,以前侥幸获取的方便也一会儿全还了回去。