接手了同事一个高并发的场景问题,理论上峰值一秒要处理500次请求,
之前他和领导是讨论开发了这么一个方案:用redis做消息队列存储初始请求,然后写了一个定时任务定时扫描线程池里队列空闲的数量,如果队列有空闲值,从redis消息队列里消费数据,压到线程池里执行业务操作,以此循环。
大概代码过程
定时任务A {
1.判断线程池是否有空闲队列
2.从redis中获取消息
3. 线程池操作调用方法B
executor.execute(() -> {
方法B(xxx);
});
}
方法B进行了一些业务操作,然后调用了一个查询表数据的方法
方法B(xxx):{
long time1 = System.currentTimeMillis();
log.info("业务【" + xxx + "】time1 " + time1);
Data = 方法C(xxx);
long time5 = System.currentTimeMillis();
log.info("业务【" + xxx + "】 time5 " + time5);
long endTime = System.currentTimeMillis();
log.info("工单【" + relId + "】查询耗时"+(endTime-time1)+"ms");
}
方法C查询了一条表数据并返回
方法C(xxx){
long time2 = System.currentTimeMillis();
log.info("业务【" + xxx + "】 time2 " + time2);
StringBuffer sb = new StringBuffer("select * from 表名 where id=?");
List<Map<String, Object>> list = jdbcTemplate.queryForList(sb.toString(), xxx);
long time3 = System.currentTimeMillis();
log.info("业务【" + xxx + "】 time3 " + time3);
Map<String, Object> data = new HashMap<>;
if(list!=null&&list.size()>0){
data = list.get(0);
}
long time4 = System.currentTimeMillis();
log.info("业务【" + xxx + "】 time4 " + time4);
return data;
}
之前同事线程池设置核心线程数设置100,最大线程数200,池队列200,定时任务A每12秒执行一次,一次取100条数据,看了看日志,在执行的中间会有这种场景
2025-01-21 11:39:50.626 INFO 1077868 --- [ool-6-thread-17] .i.c.m.b.c. : 业务【xxx】time1 1737430790626
2025-01-21 11:40:05.240 INFO 1077868 --- [ool-6-thread-17] c.i.c.e.i.s.i. : 业务【xxx】 time2 1737430805240
2025-01-21 11:40:05.242 INFO 1077868 --- [ool-6-thread-17] c.i.c.e.i.s.i. : 业务【xxx】 time3 1737430805242
2025-01-21 11:40:05.242 INFO 1077868 --- [ool-6-thread-17] c.i.c.e.i.s.i. : 业务【xxx】 time4 1737430805242
2025-01-21 11:40:05.243 INFO 1077868 --- [ool-6-thread-17] .i.c.m.b.c. : 业务【xxx】time5 1737430805243
2025-01-21 11:40:05.243 INFO 1077868 --- [ool-6-thread-17] .i.c.m.b.c. : 业务【xxx】查询耗时14617ms
time1和time2之间会相差15秒
其他设置和尝试:
- 减小了线程池的大小和定时任务间隔,线程池核心线程数改成16(服务器16核),队列大小改成了32;定时任务A改成1秒执行一次。
结果是:总时间差不多还是五六分钟处理500条,但是time2和time3间隔差的短了点,在4s左右,还是不满足。 - 服务的数据库链接数设置了 200,定时服务运行时,数据库连接数没有超过数据库上限,且工具里查询同样的sql很快,应该不是数据库瓶颈
- 定时任务运行的时候看了下服务器top指令,cpu占用率最高每个核心30%,没有跑满;服务占用内存设置了最大2G;不知道有没有影响,看top里也没有占满只有1.7G左右
- 把方法C 抽出来直接放在方法B里实现查询,呈现出来就是jdbcTemplate执行的前后两个时间差距变大。
目前没定位到这个time2和1之间为什么会有这么久的间隔,有没有佬给分析一下,感谢!