redis不能使用大容量的value
我做的是代码优化,结果优化出了问题,小米钱包有个业务,获取卡片信息,原来的逻辑接口进来会查询差不多100次数据库,然后组装主库备库的数据组装好返回,我优化了下,改成了一次性查询好数据库所有数据,然后组装好放在redis中。
1、众测灰度阶段上线时候晚高峰,引入两省两市流量后(灰度就是生产前的最后一步,两省就是广东省,江苏省,深圳市,南京市的流量从生产引到灰度上,真实流量看是否有问题),然后cpu发生跳变(一会高,一会低),告警后运维联系了让分析。
2、当天晚上分析看netstat -na查看数据库连接池,发现50个连接数有,我们配置最大连接数就是50,那原因可能是数据库连接池耗尽。初步判断是FullGC导致线程阻塞,cpu使用率下降,FullGC过后,一大波外面等待的请求又同时执行,导致cpu使用率上升,发生跳变。
解决:马上修改连接数据=65,然后临时扩容了灰度12台机器(原来就4台灰度,猜测也有可能是两省流量变高了,也确实比之前高了一些)。到第二题早高峰,cpu还算稳点。
3、第二题晚高峰,cpu又跳变了,说明之前定位不是真正原因。
查看了程序内存使用情况:jmap查看内存使用情况,发现有几百个linkedHashMap对象内存,每个map大约有4M,总共占了1g多内存。那原因才真正清楚了。
是优化代码时候一次性查询了所有数据放入redis中,你数据要使用的,所以项目中反序列化出来Map一次性4M,高峰时候大量并发请求接口进来优先从redis中拿到数据反序列生成map临时对象,4M的内存对象直接从新生代到了老年代,导致JVm内存使用过多,直接触发FullGC,而待回收的对象较大,耗时长,阻塞了就。
解决:当天晚上出了新设计:这种大对象不能缓存在redis中,要使用进程级缓存,并且定时任务刷新,采用主,备缓存刷新机制,保证一个时间只保存一份数据
4、为什么之前没有发现
之前有做性能测试,但是只是模拟了2k的,生产回家有20k的,so
5、为什么第一次分析错了
分析的不全面,然后流量确实大了很多误导导致任务是流量增多导致数据库连接池耗尽
稍微说点jvm回收的:
youngGC,回收新生代的
FullGc,整个堆都可能回收的
新生代在逃过15次GC之后,就会移到老年代,同样的对象,在老年代比在新生代占的内存多,新生代和老年代内存比例:1:2。
youngGC也不是直接就开始,会先去检查老年代的可用连续内存是否能放得下新生代的所有对象内存,放得下就youngGC,放不下可能先oldGC。