赞
踩
在开发项目过程中,遇到一个问题就是,一个系统与上百个系统对接,有大量的请求和有可能数据是重复发送,但是在数据必须保证数据不能重复消费。
刚才开始设计思路,按照往常写代码,编写controller,service,dao层,一气呵成。但是在使用过程出现,大量的请求导致服务器不可以,直接宕机。出现这个问题,那没有办法得优化。
设计思路:
1、将所有的请求,放到队列里面。
2、异步消费队列里面的数据。
1、controller层代码
- @RequestMapping("/api")
- @RestController
- @Api(value = "账号监控平台系统相关接口", tags = {"账号监控平台系统相关接口"})
- @Slf4j
- public class UserDepartmentController {
-
- private static LinkedBlockingDeque<List<UserLogin>> deque = new LinkedBlockingDeque<>();
- @Autowired
- private UserLoginManagementService userLoginManagementService;
-
- @Autowired
- private UserLoginService userLoginService;
- @Autowired
- private Sid sid;
-
-
- @ApiOperation(value = "推送用户登录日志接口",notes = "推送用户登录日志接口", httpMethod = "POST")
- @PostMapping("/userLog/add")
- public R addUserLogQueue(@Validated @RequestBody List< @Valid UserLogin> list) {
- if (list == null || list.isEmpty()) {
- return R.errorMsg("传数据不能为空");
- }
- try {
- List<DataMsg> resultList = new ArrayList<>(); //返回给调用接口集合
- List<UserLogin> saveList = new ArrayList<>(); // 保存数据的list
- // 判断参数不能为空,
- for(UserLogin userLogin : list){
- R result = ParameterUtil.userParameter(userLogin);
- if(result.getCode().equals(RStatus.fail.getCode())){
- DataMsg dataMsg = new DataMsg();
- BeanUtils.copyProperties(userLogin,dataMsg);
- dataMsg.setMessage(result.getMsg());
- log.error("【UserDepartmentController -- addUserLog】传入的登录信息数据有空,入参的参数数据:{},消息的提醒:{}",userLogin.toString(),result.getMsg());
- resultList.add(dataMsg);
- }else {
- userLogin.setUserId(userLogin.getSystemName()+"-"+userLogin.getUserId());
- saveList.add(userLogin);
- }
- }
- if(saveList != null && saveList.size() > 0 ){
- // String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
- //log.info("【UserDepartmentController -- addUserLog】传入的登录信息数据,入参的时间:{},入参的数据:{} ",time, saveList.toString());
- if(deque.remainingCapacity() > 0){
- deque.put(saveList);
- }else {
- return R.errorMsg("队列已经满了,请稍后重试");
- }
- SaveUserLogQueueRunnable saveUserLogQueueRunnable = new SaveUserLogQueueRunnable(deque,userLoginService,userLoginManagementService,sid);
- //刚开始使用多线程,但是如果相同的数据发送多次请求,会导致数据会重复。后面修改上面的方式,单线程去处理。
- ThreadPoolExecutor cupInstance = ThreadPoolUtils.getCUPInstance();
- cupInstance.execute(saveUserLogQueueRunnable);
-
- }
- if(resultList != null && resultList.size() >0){
- return R.build(500,"失败",resultList);
- }else{
- return R.ok();
- }
- }catch (Exception e){
- e.printStackTrace();
- return R.errorMsg("请求接口异常");
- }
-
- }
- }

- @Slf4j
- public class SaveUserLogQueueRunnable implements Runnable {
-
- private UserLoginService userLoginService;
- private UserLoginManagementService userLoginManagementService;
- private Sid sid;
- private LinkedBlockingDeque<List<UserLogin>> deque;
-
- public SaveUserLogQueueRunnable(LinkedBlockingDeque<List<UserLogin>> deque, UserLoginService userLoginService, UserLoginManagementService userLoginManagementService, Sid sid){
- this.deque = deque;
- this.userLoginService = userLoginService;
- this.userLoginManagementService = userLoginManagementService;
- this.sid = sid;
- }
-
-
- @Override
- public void run() {
- try {
- //开始处理请求队列中的请求,按照队列的FIFO的规则,先处理先放入到队列中的请求
- while (deque != null && deque.size() > 0){
- List<UserLogin> take = deque.take(); //取出队列中的请求
- addLog(take); //处理请求
- }
- }catch (Exception e){
- log.error("【SaveUserLogQueueRunnable 】处理队列出现错误如下:");
- e.printStackTrace();
- }
-
- }
-
- public synchronized void addLog( List<UserLogin> list) {
- String time1 = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
- System.out.println("list的大小: "+list.size()+"----时间为: "+ time1);
- for (UserLogin userLogin :list){
- // 这是自己写业务处理的代码。
- }
- }
- }

public class Constants { // 消费者,单一线程, 进行处理业务逻辑 public static final ScheduledExecutorService SCHEDULED_EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); }
代码写完了用jmeter 工具测试,,20个并发。
请求参数:
测试结果:预期结果,数据库里面的数据和入参的数据一致。但是出现有重复的数据。有出现问题,还得解决。
解决办法:使用 newSingleThreadScheduledExecutor 单线程去执行,从队列里面拿一条数据消费一条数据
再次测试:还是 jmeter 工具测试,,20个并发。发现不会出现重复的数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。