最近要寫一個拉取其他項目數據的定時任務。
最先寫了一個,首先查詢主表,獲取主數據后,循環去拉取子數據。這種方式在同一個定時任務里,超級慢。
果斷改成多個定時任務,第一個定時任務獲取主數據存表。第二個定時任務查詢本地主表數據,循環去拉取。這種方式比在一個定時任務里快很多。
接下來說說線上出現的問題:
在跟進定時任務時,發現:1,數據沒有同步完全;2,服務器日志里報請求太頻繁。可能是其他項目的防刷機制,后來我想只是一個請求,又是定時的,沒有同時操作。
后來發現是多台服務的問題,定時到某個時間點,多台服務器會在毫秒級內一塊請求,就算是一個請求也會報頻繁。
解決方案:
在定時任務里加鎖機制,等某台服務器獲取權限,其他服務器將不再執行此次定時任務
if(redisTemplate.opsForValue().setIfAbsent("getsnInfo","11")){ //key的值放什么不重要,重要的是key.所以11或者aa都行。多個定時任務,是多個key,不能set一樣的,各管各的定時任務。懂redis的應該都明白 try{ // 業務代碼 }catch(){ redisTemplate.delete("getsnInfo"); } redisTemplate.delete("getsnInfo"); }
注意:
異常里和方法結尾,都要加上刪除key標識。否則當系統異常退出和正常執行退出時,key還在,未來的定時任務將永遠不會被執行。
另外:redistemplate中的setIfAbsent和setnx是一樣的意思,都是不存在則set,返回boolean類型,判斷是否進入方法體。
看你的redis使用版本和引用是哪種類型,一般都會有這兩種。