第二章 实习任务与完成情况
2.1 本人承担的主要工作
在实习中,本人负责的工作主要有以下几个方面:
1) CRM系统的XSS攻击防护:
2) CRM的需求分析及需求开发;
3) 对用户上传的账单图片及pdf进行设别,提取出账单信息
4) 使用定时任务对满足条件的客户进行迁移;
5) Open API联调平台的系统架构设计及开发、部署:
2.2 完成实习任务的技术方案与步骤
2.2.1 相关技术
1) XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。要对XSS攻击进行防护需要对用户输入的数据进行HTML Encode处理。 将其中的"中括号", “单引号”,“引号” 之类的特殊字符进行编码。
2) OCR (Optical Character Recognition,光学字符识别)是指电子设备检查纸上打印的字符,通过检测暗、亮的模式确定其形状,然后用字符识别方法将形状翻译成计算机文字的过程;即,针对印刷体字符,采用光学的方式将纸质文档中的文字转换成为黑白点阵的图像文件,并通过识别软件将图像中的文字转换成文本格式,供文字处理软件进一步编辑加工的技术。项目中主要使用了百度商用OCR及开源OCR Tesseract。
3) 分布式定时任务elastic-job 是由当当网基于quartz 二次开发之后的分布式调度解决方案 , 由两个相对独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成 。
elastic-job主要的设计理念是无中心化的分布式定时调度框架,思路来源于Quartz的基于数据库的高可用方案。但数据库没有分布式协调功能,所以在高可用方案的基础上增加了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。
4) Spring的 及AOP 技术。Spring里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在AOP中,拦截器用于在某个方法或者字段被访问之前,进行拦截
然后再之前或者之后加入某些操作。
开发环境:客户端环境要求,操作系统:Linux Ubuntu 10.04或Windows或Mac OS 10.6等操作系统;
主要开发语言:Java、JavaScript、XML。
2.2.2 系统需求分析
系统设计特点
Open API 即开放 API,也称开放平台。 所谓的开放 API(OpenAPI)是服务型网站常见的一种应用,网站的服务商将自己的网站服务封装成一系列API(Application Programming Interface,应用编程接口)开放出去,供第三方开发者(用户、平台、合作ERP)通过HTTP调用的开发资源,这种行为就叫做开放网站的 API,所开放的 API 就被称作 OpenAPI(开放 API )。Open API调用流程如图(1)所示:
图(1)
2.2.3 系统概要设计
系统业务流程
用户在通过权限系统检查后,通过okhttp向Open API服务器发送HTTPS请求然后通过系统获得HTTPS响应。对应架构如图(2)所示:
图(2)
用户通过系统调用Open API的时序如图(3)所示:
图(3)
开发者根据各自管理资源模式的不同分为以下三类:
用户开发者:IMC、宝视佳等卖家,用户开发者可以申请开发者并获取master_token,通过master_token来访问所有用户资源;
第三方应用开发者:赛盒、店小秘等ERP,应用开发者需要向连连申请开发访问得资源权限域(如:用户有5个资源1~5,然后应用开发者向连连申请要开发1~3资源,可参考图三),并通过用户授权获取access_token,来代理用户访问用户资源;
平台开发者:SellerBench、小米有品、京东印尼、自建站等合作平台,由于合作需要,Open API这边会单独给平台开发一部分接口,平台开发者在申请开发者的时候需要指定对接的资源,申请成功连连会为其发放master_token,平台开发者可以根据master_token访问对应的平台资源。
三种开发者管理模式如图(4)所示:
图(4)
系统数据库设计
不同的用户所拥有的接口权限是不同的,我们将接口和接口模式抽象成资源,并且将拥有资源的对象抽象成为一个角色。每个用户都有对应的角色,这样就做到了接口与用户的松耦合。数据库设计如图(5): 图(5)
2.2.4 系统详细设计
系统功能模块详细设计
请求拦截分为三种场景:请求菜单、请求group资源、请求调用Open API,拦截器需要对三种场景分别进行拦截过滤,未登录用户权限控制时序如图(6)所示: 图(6)
系统关键技术
实习过程中,因为需求的不同,主要使用了以下关键技术:
1)XSS攻击防护
XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的"中括号", “单引号”,“引号” 之类的特殊字符进行编码。
2)图片及pdf文件的文字识别与提取
本次需求是需要对用户上传的pdf或图片文件进行识别,然后从文件中提取我们需要的部分。因为pdf文件的模板都是类似的,所以我们需要对pdf的内容进行拆分,然后一行一行的识别。这里使用了PDFTextStripper工具,这是一个java自带的pdf解析器,能够将pdf解析成String对象,然后通过对STring数组的解析,提取出我们想要的信息。提取信息的过程主要是对关键字进行识别,如果识别出关键字,就对接下去的内容进行提取。
对于图片的文字提取,我使用了百度的OCR工具。通过百度OCR对图片进行识别,准确率达到了98%,但是因为项目资金原因,需要使用开源的OCR识别工具,因此我通过tesseract来对图像进行识别,Tesseract(识别引擎),一款由HP实验室开发由Google维护的开源OCR(Optical Character Recognition , 光学字符识别)引擎,与Microsoft Office Document Imaging(MODI)相比,我们可以不断的训练的库,使图像转换文本的能力不断增强;如果团队深度需要,还可以以它为模板,开发出符合自身需求的OCR引擎。
Tesseract-ocr安装很容易,在网上找到下载地址直接下载安装就可以,安装完成之后需要配置环境变量,配置完环境变量之后可以在cmd命令行中输入tesseract验证Tesseract-ocr能否使用。除了需要配置Tesseract-ocr文件的环境变量外,还需要配置Tesseract-ocr文件下的tessdata(语言包)的环境变量。
3)Elastic Job
elastic-job 是由当当网基于quartz 二次开发之后的分布式调度解决方案,主要的设计理念是无中心化的分布式定时调度框架,思路来源于Quartz的基于数据库的高可用方案。但数据库没有分布式协调功能,所以在高可用方案的基础上增加了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。
在项目中使用elastic job时,需要继承SimpleJob接口,并且实现接口的execute()方法。在方法中,需要查询出需要迁移的客户。这里我对sql进行了一次优化,使sql的执行效率提升了10倍,这一条sql分为三个步骤,正常情况下这三个步骤分开来查询都没有问题,但是合并之后查询速度很慢,原因在于自动将视图合并了,造成了两个loop循环,而没有把里面的过滤条件(子查询)先执行。因此使用了no_merge的hint,让oracle不对视图进行合并,这样就会先进行里面的子查询进行条件的过滤,再进行关联,减少关联的成本。
通过配置作业与spring容器配合作业,把bean依赖注入,就可以使用分布式定时任务了,分布式作业执行流程如图(7)所示:
图(7)
2.3 实习中的问题及解决方法
问题1:查询需要迁移的客户时,sql执行的非常慢,达到10s+,非常影响效率。
解决方案:首先查看sql的执行计划,如图(8)所示
图(8)
发现使用了两个LOOP循环导致sql执行的非常慢,对子查询加上“/*+ no_merge */”的hint后,防止视图合并,让sql先对立面的视图进行查询作为条件再执行外面的视图。这样就能避免两次的LOOP循环而采用反哈希join,优化后的执行计划如图(9)所示:
图(9)
可以看出优化过的sql没有了两次LOOP循环,sql执行速度大大增加。
问题2:缓存雪崩。在redis中储存了用户的登录信息,我们会给缓存设置一个失效时间,但是如果所有的缓存的失效时间相同,那么在同一时间失效时,所有系统的请求都会发送到数据库层,db可能无法承受如此大的压力导致系统崩溃。
解决方案:
线程互斥:只让一个线程构建缓存,其他线程等待构建缓存的线程执行完,重新从缓存获取数据才可以,每个时刻只有一个线程在执行请求,减轻了db的压力,但缺点也很明显,降低了系统的qps。
交错失效时间:这种方法时间比较简单粗暴,既然在同一时间失效会造成请求过多雪崩,那我们错开不同的失效时间即可从一定长度上避免这种问题,在缓存进行失效时间设置的时候,从某个适当的值域中随机一个时间作为失效时间即可。
问题3:线上频繁接到JVM的Full GC的报警,在日志里,看到了一个“Metadata GC Threshold”的字样,类似于如下日志:
【Full GC(Metadata GC Threshold)xxxxx, xxxxx】
解决方案:首先查看Metaspace区域的内存占用情况,通过jstat来观察, Metaspace区域的内存呈现一个波动的状态,他总是会先不断增加,达到一个顶点之后,就会把Metaspace区域给占满,然后自然就会触发一次Full GC,Full GC会带着Metaspace区域的垃圾回收,所以接下来Metaspace区域的内存占用又变得很小了。原因是使用Java中的反射时加载的,解决方案很简单。在有大量反射代码的场景下,只要把
-XX:SoftRefLRUPolicyMSPerMB=0
这个参数设置大一些即可,提高这个数值,就是让反射过程中JVM自动创建的软引用的一些类的Class对象不要被随便回收,当时我们优化这个参数之后,就可以看到系统稳定运行了。
2.4 实习任务的完成情况
有效并有效率的完成了各项任务。
第三章 实习总结
3.1 实习的收获与体会
3.1.1 实习的收获
1) 在公司接触到了很多新的知识,学习到了很多新的框架,例如Mybatis、Spring boot、dubbo、redis、kafka等等。同时也学习到了很多编码的规范,例如类和方法的命名规范、工程的结构、代码中如何抛异常等等。对java的使用更加的熟练,并且能够处理一些有难度的问题。同时公司的也会举办一些技术分享,在技术分享中,学习到了数据库的死锁及解决方案、数据库中的隔离级别及不同隔离级别造成的问题、多线程的使用及多线程时如何保证系统的安全。对今后的技术之路打下了坚实的基础。
2) 学习到了开发中使用的各种工具,例如maven,SVN、git、Linux。学会了如何利用maven命令进行项目的打包,以及在公司的服务器上通过脚本命令来部署项目;如何拉取分支,更新代码、提交代码等版本控制操作;学会了如何在公司服务器下查看服务器的性能,查看项目的日志来排查项目中出现的bug。
3) 学习到了如何对需求进行分析及设计,需求是需要和业务相结合的,只有更好的了解到业务,才能保证需求设计的正确。同时确认需求要和很多的人员进行沟通,在这一过程中,学习到了如何与同事进行交流与对接,更好的融入到团队当中。
3.1.2 实习的体会
在实习的过程中,学习到了很多课堂上没有的东西。平时在学校学习到的基本上都是理论知识,很少有实践的机会。而在实习的过程中,我对专业课的知识有了更多深刻的理解。之前学习到的一些自以为没有用处的知识,发现在实习过程中是多么的重要。同时在实习的过程中也提高了我对实际问题的解决能力,加深了我对程序开发的理解。
总之,理论+实践=知识。程序设计过程中,以理论为指导,以实践为主体,将理论与实践紧密结合起来,亲身体会到只有将理论与实践有效的结合起来,才能使理论指导实践,又反过来丰富理论,二者相得益彰,使学习效率大大提高。