如何解决xxl-job 5分钟调用service service调用阻塞问题?
一、xxl-job和Spring Cloud的问题
在使用xxl-job调用Spring Cloud微服务时,可能会出现阻塞的情况。这是因为xxl-job的调用方式是http请求,而Spring Cloud使用了ribbon负载均衡和Hystrix熔断器,如果在超时时间内没有响应,则会触发Hystrix的短路机制,导致服务阻塞。
解决方法是可以设置超时时间,如下:
@Bean
public RestTemplate restTemplate() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(5000);
requestFactory.setReadTimeout(5000);
return new RestTemplate(requestFactory);
}
二、调整xxl-job的线程池
在使用xxl-job的过程中,可能会出现调用服务阻塞的情况。可以通过调整xxl-job的线程池大小来缓解此问题。线程池大小越大,可以同时处理的请求数就越多,从而减少阻塞的情况。
可以通过在配置文件中配置以下属性来调整线程池大小:
xxl.job.executor.threadpool.core-size=100
xxl.job.executor.threadpool.max-size=200
三、使用异步调用方式
使用异步调用方式是解决这个问题的常用方法。可以在service中使用CompletableFuture异步调用xxl-job任务。
例如,如下是一个调用xxl-job任务的示例:
@Service
public class JobService {
@Autowired
private JobClient jobClient;
public CompletableFuture<JobResult> runJobAsync(long jobId, String param) {
return CompletableFuture.supplyAsync(() -> jobClient.run(jobId, param));
}
}
然后,在controller中就可以使用异步调用方式调用service:
@RestController
@RequestMapping("/job")
public class JobController {
@Autowired
private JobService jobService;
@PostMapping("/runAsync")
public CompletableFuture<JobResult> runJobAsync(@RequestParam long jobId, @RequestParam String param) {
return jobService.runJobAsync(jobId, param);
}
}
四、增加日志输出
增加日志输出可以帮助我们更好地定位问题,了解程序运行的情况。在xxl-job的调用过程中,可以增加日志输出来查看调用情况、参数、返回值等信息。
例如,在jobHandler中可以增加日志输出,如下:
@XxlJob("MyJobHandler")
public ReturnT<String> execute(String param) throws Exception {
log.info("start MyJobHandler...param:{}", param);
// do something
log.info("end MyJobHandler...result:{}", result);
return ReturnT.SUCCESS;
}
五、使用分布式事务
如果xxl-job的任务需要对数据库进行操作,需要使用分布式事务来保证数据的一致性。使用分布式事务可以避免数据操作不一致、服务阻塞等问题。
常见的分布式事务解决方案有TCC、XA、Seata等。
例如,使用Seata可以在服务中增加@GlobalTransactional注解,实现分布式事务的管理,如下所示:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private AccountClient accountClient;
@Override
@GlobalTransactional
public void transfer(String userId, String targetUserId, BigDecimal amount) {
// 扣除用户余额
accountClient.reduceBalance(userId, amount);
// 增加目标用户的余额
accountClient.addBalance(targetUserId, amount);
// 更新用户的交易记录
userMapper.updateUser(userId, targetUserId, amount);
}
}