文章目录
1. 场景描述
每天有一次定时任务,需要向300w用户推送支付宝模板消息,单台服务器初次尝试30w个消息推送时,耗时4.6个小时,使用的是并行流推送的方式。
2. 原因猜测
通过监控观察到,推送模板消息时,服务器CPU的利用率只在 10% 左右,并没有高效利用起CPU,并行流的优点是将CPU资源调动起来,实现并行处理,一般情况CPU资源应该是被占用得挺多的,假设服务器有四个核,默认并行流会将四个核都同时调用起来,实现真正的并行处理,而不像线程是伪实时,可以将四个核心下的并行流处理单成四个队列,30w任务平均分配在四个队列中,只有前面的任务执行完了,下一个任务才会继续,此时就会面临一个问题了,推送模板消息是发送http请求,涉及到了网络调用,此时每个任务执行过程中是有一个I/O阻塞时间的,下一个任务只能等待前一个完成才会执行,这段I/O阻塞便停滞了CPU资源。
可以通过提高并行流的核心数或者换成线程处理的方式来验证猜测。
3. 测试
@Service
public class ConsumMsg {
@Autowired
StreamOpt streamOpt;
/**
* 初始化任务队列
* @param count
* @return
*/
public List<Integer> initMsg(int count) {
List<Integer> list = Lists.newArrayList();
for (int i = 0; i < count; i++) {
list.add(i);
}
return list;
}
/**
* 并行流处理
* @param count
*/
public void parallel(int count) {
List<Integer> list = initMsg(count);
int successSize = list.parallelStream().mapToInt(streamOpt::sendMsg).sum();
System.out.println("并行流成功个数:"