接口日志异步入库

问题

  在高并发场景下,接口日志同步入库会增加数据库压力,降低接口效率,对此,可以使用异步入库提高接口效率。

思路

  使用阻塞队列保存日志对象,定时任务定时批量入库。

具体实现

  •  创建日志Bean对象,具体字段根据实际情况来
    
    	public class InterfaceLog implements Serializable {
    	
        private static final long serialVersionUID = 3281809955687842194L;
        
        //日志编码
        private String logId;
      
        //请求地址IP
        private String ipAddress;
        
        //入参
        private String req;
        
    	//出参
        private String resp;
        
    	...//省略
        }
    
  •  新建队列缓存服务,封装并对外提供入队,出队,队列判空三个方法
    
    public interface ILogService {
    
    	void pollLog();
    	
        void putLog(InterfaceLog InterfaceLog );
    
    }
    
    public class LogServiceImpl implements ILogService {
    
        private BlockingQueue<InterfaceLogBean> logqueue= new LinkedBlockingQueue<InterfaceLogBean>(100000);
    
        @Override
        public void pollLog() {
            logqueue.poll();
        }
    
        @Override
        public void putLog(Object log) {
            logqueue.put(log);
        }
    
        @Override
        public boolean isQueueEmpty() {
            return logqueue.isEmpty();
        }
        
    }
    
  •  创建消费者程序,每0.5s从队列拿出n个对象,批量入库一次
    
    @EnableScheduling
    @Component
    public class ProccessLog {
        
        @Autowired
        private ILogService logQueueService;
        
        //0.5s跑一次
        @Scheduled(fixedDelay = 500)
        public void run()
        {
            processLog();
        }
    
        /**
         * 消费者程序
         */
        private void processLog()
        {
            try
            {
                int num = 0;
                List list = new ArrayList();
                // 每次取走不超过200条记录进行数据库插入 根据实际情况调整
                while ((!logQueueService.isQueueEmpty()) && (num < 200))
                {
                    list.add(logQueueService.pollLog());
                    num++;
                }
                if ( (list!=null) && (!list.isEmpty())){
                    //将list 批量入库
                    //....
                }
            }
            catch (Exception e)
            {
                //log.error("async job is failed !error msg is {}",e.getMessage());
                e.printStackTrace();
            }
        }
    
    }
    
  •  批量入库
    
    根据实际orm框架进行编写
    

使用方式

	@Controller
			class {
				@Autowired
			    private ILogService logQueueService;
			    
				@RequestMapping("xxx")
				public xxxInterface(){
					logQueueService.putLog(LogBean);
				}
		    }

总结

 利用LinkedBlockingQueue put方法阻塞特性,保证日志不丢失。LinkedBlockingQueue 读写锁分离,保证了高吞吐。

你可能感兴趣的:(工作记录)