17年8月,我们组开始考拉项目的开发,先说下情况,公司是.net平台为主的(我是做Java的,误打误撞进来了),但这个项目是要用java写,基本上环境、框架、mysql什么都没,我们组一共7个人(5个应届生+一个做了几年安卓的大佬+我)硬着头皮上了。
首先,是框架,我们这里用的是springboot+mybatis,刚好之前从github上找了一个不错的种子框架(https://github.com/lihengming/spring-boot-api-project-seed),包含了基本的代码生成器、拦截、接口封装等,我们又在此基础上加了统一异常日志记录、swagger接口文档、feign网络请求工具、javamelody监控等(后期又改了几次,作为公司内部的种子项目框架),然后项目开始。
一期项目由两部分组成:微信公众号、管理后台。公众号用的是angular,需要特别提的是微信支付比较坑,当时花了两三天。管理后台管理的就是下单(包括公众号下的单)、预检、审核、维修(开始、完成)、取消、支付等功能。
二期项目主要是进销存,在一期的订单上面加入了选择材料、派工、质检、托外等,对应到进销存则是商品订货、领料、出入库、调拨、盘点的状态的管理和流转。总体上线时间在五月底,中间开发、上线遇到过很多的问题,以下会一一列出。
问题:
1.如何进行友好的提示:
在接口发生异常时,我们这里屏蔽了异常信息,封装了一个异常状态码,后期会把状态码发送到ELK,进行异常的查看。
2.大数据量传输,如城市、车型车系等信息
在有一次帮业务导完6000+的维修项配置记录后,线上的pinpoint(我们用的主要监控)疯狂报红,一查,发现全是接口超时,后来发现是因为有几个维修分类对应的维修项数据量太大,最大的有4000条,在http传输的时候报超时,同时页面for循环渲染的时候很慢,我们这里的暂时方案是让业务整理相关分类,每个分类最多在800左右(没有想到好的解决方案),后来,我们又商量了下,接口出最多100条数据,如果没有,页面使用模糊搜索功能。这里不清楚各位大佬有没有好的方案,有的话望分享告知^_^。
3.update case when 是否会影响性能
一期第一次上线的时候,第一天没问题,第二天线上疯狂报错。看了下日志,有lock产生,看了下数据库,产生了很多锁,一看出错的代码,用了事务,而且用了for循环update,赶紧修复,后期各种优化,恢复正常了。但是这里,我们用了很多case when的语法,不清楚是否会影响性能,不清楚有没有大佬知道(欢迎各种意见和建议),至少目前从druid的监控上没有发现问题。
泪点:
1.运维收回权限,非root用户启动报错
由于我们这里对权限限制的比较厉害,我们开发只有dev环境权限,demo、testing、预发布在QA,运维则有线上的权限,好多次因为权限的问题加了半天班。有次限制了资源站点的ip(后来说机器被攻击了),导致整个门店操作有问题等等。
2.发布时,配置文件忘记修改等
由于环境过多,每次发布总是忘了配置文件,后期会接入携程的阿波罗(https://github.com/ctripcorp/apollo)来解决。
优化:
1.后台:业务逻辑优化,移除大部分Transactional,移除for循环insert、update
2.数据库:explain sql,增加索引、联合索引;建立字典表;sql增加逻辑限制(如:isChoiced、isDeleted等),减少update数据量;优化sql,区分度大的索引优先放在where之后,减少函数的使用,优化like的用法('xxx%')等
3.前端:使用sessionStorage,缓存大部分字典表配置信息(如城市、状态等);上传图片需要压缩处理等
建表规范:
符合阿里Java开发文档要求,增加字典表的使用
推荐eclipse建表工具:ermaster,可以直接导出doc文档
一期时候数据库先是用的sqlserver,druid这里报个错,select next value for OrderId,它不支持for这个序列里面的关键词,随即提了个issue,然后修复了。同时,我们拦截了druid,记录所有的update操作的前后值:
@Around(value = "execution(* com.alibaba.druid.filter.FilterEventAdapter.preparedStatement_execute(..))")
后续的话,我们会加入redis的使用,然后对系统做进一步的优化,也欢迎各位大佬补充下相关项目的整合、优化措施,无论大小、前后端,感激不尽,^ _ ^。