由于项目中的数据量已经上百万,相对于互联网行业项目来说这个数量级并不是很大,但是对我们保险行业来说数量已经很大了,原有的一些功能达到了瓶颈,而且压测环境要求在现有的基础上扩大十倍,对业务的影响不能太大,因此压测环境问题也越来越多;性能优化的工作也由我来负责,并不是由我一个人来实现,而是由我来提出解决方案,然后再开会讨论,通过后再具体实施,或者交付你他人来实现改造。
先描述下业务场景团单被保险人超过百万,被保险人的数据包就有90M左右,第一、把文件上传到Mongodb,上传成功给前端响应上传成功,第二再进行解析,由于数据没有校验所以不能进行批量保存,现有的方案是一条保存一次到mongodb临时表,全部导入成功后,再从临时表保存到mongodb和数据库,结果可想而知,花了半个小时导入了100分之一左右失败!
第一、先把数据量减小,三万条数据,同时监控JVM、Mongodb、以及数据库;发现MongoDB的CPU占比竟然达到500%,这很明显不对呀!这才2M左右的数据,CPU占比这么高?而且在没有导入的情况下还是没有降下来,肯定是Mongo有问题,检查Mongo发现有一台mongo宕机了,主节点一直在想从节点发送连接请求,由于只是开发环境所以并没有搭建集群而是采用了主从复制。重启之后,mongo恢复正常,三万条数据,从文件上传到解析入库总共花费了25分钟。
第二、三万条数据从文件上传到解析入库总共花费25分钟,明显太慢了这才只有20tps。理想要求500tps,也就是说百万数据需要在半小时左右解析入库。如下图为改造前模式,从一下流程中可以看出对mongo的操作有点多而且临时表的查询和再次写入mongo、数据库。增加了IO次数。使得导入变得异常缓慢。
性能优化总结
然后我改造整体上传到解析的流程,如下图所示:
性能优化总结
然后开会讨论我提出的这个方案可行性,方案最终得到通过,但还是要改造完看压测的结果。改造完成后,再次使用三万条数据做这个操作,用了将近8分钟性能明显有所提升,但是别高兴的太早,这才达到62.5tps,想要达到理想的500tps还有很大的差距。通过监控Jprofile监控可以看出所有的性能消耗都在网络请求上,从业务逻辑上看到有个调用外系统的,通过使用Jprofile监控看到,导入有个校验被保险人是否在黑名单中,也就是说这三万条数据又要去ecif系统校验,还是一条数据发一个请求去掉ecif系统数据库查询是否存在黑名单中。
关于黑名单的校验避免不了要去ecif数据库查询,这样的查询,无疑是效率很低的。翻看以前的学习笔记时看到了redis的三个经典问题,缓存穿透、缓存击穿、缓存雪崩的问题,而缓存穿透的解决方案不就是缓存空对象和布隆过滤器嘛!可以使用bloomfilter来实现黑名单校验,但是布隆过滤器市面上的实现都是基于google的实现而且不支持分布式;而redis中有个数据类型是bitmap刚好可以用来解决黑名单校验的问题。
简单说下什么是布隆过滤器:布隆过滤器是由布隆在1970年的时候提出来的,它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误判率和删除困难。不过用来校验黑名单不影响;说动手就动手。下图来源与网络:
性能优化总结
布隆过滤器的大小计算:
性能优化总结

性能优化总结
性能优化总结
以上计算公式的图片来源于网络
具体实现过程会整理出来上传到gitHub,今天先把解决问题的方案和具体过程整理出来,明天整理代码后再上传。
通过以上图片可以看出bloomfilter的数据量大小和误判率以及哈希算法的个数是相关的,误判率的设定与数据量大小计算。
通过bloomfilter解决了黑名单校验的问题,再次导入3万条数据,从文件上传到解析入库总共花费70秒左右,达到了400多tps基本上已经满足条件,但是现在还没有经过百万级别的压测;项目经理问我,你这个优化后能达到10倍以上的压测嘛?还有别的瓶颈嘛?我~~~~~

相关文章: