主機狀態一直顯示有問題,去向動態連接庫請求數據時,除了第一臺主機訪問成功外,之後的每一臺主機返回的結果都是9(HOST_NOT_FOUND)
。java
研究了好久也沒研究明白,最後求助潘老師。安全
潘老師指出是指針有問題,主機的指針是咱們構造出來的,雖然該指針指向對象的name
和context
與動態連接庫服務那邊的都同樣,可是他那裏多是按地址處理的,不是同一個地址,就報主機找不到了。服務器
通過測試,確實是這樣。併發
不能直接構造指針,須要使用同步計算機數據時返回的指針進行操做。測試
因此,獲取計算機狀態,操做計算機都須要從新同步一下計算機,將指針同步過來。this
假設用戶操做很頻繁的話,對動態連接庫的壓力就很大。指不定啥時候就炸了。spa
雖然我想到了這點,但也沒想到好的解決方案。線程
潘老師最終的設計方案很是好,採用定時任務,當有計算機的操做時,不實時進行操做,而是先存起來,每隔一段時間統一進行操做,從而減輕服務器壓力。debug
對主機進行關機或重啓時,不當即執行,而是將其添加到一個要執行的任務列表中,當定時任務觸發後,再統一執行。設計
定時任務很簡單,以前在計量中寫過一個天天晚上定時統計數據的定時任務,此次寫這個沒什麼難度,都不須要看文檔了。
註釋很詳盡,相信聰明的你徹底能夠理解。
這裏的存儲計算機狀態設置了一個主機名到計算機狀態映射的HashMap
,這裏沒有用ConcurrentHashMap
,由於只有定時任務一個線程進行put
,其餘接口調用該Map
只負責查詢,不會出現衝突。
@Async @Scheduled(fixedRate = 10000) // 每隔10s執行 public void hostHandle() { logger.info("--- 開始執行定時任務 ---"); logger.debug("獲取關機重啓的訂閱者"); Set<String> shutdownSubscribers = this.cloneStringSetAndClear(hostService.getShutdownSubscribers()); Set<String> rebootSubscribers = this.cloneStringSetAndClear(hostService.getRebootSubscribers()); logger.debug("獲取主機結構體指針Map"); List<HostStruct.ByReference> byReferenceList = baseService.getHostStructReferenceList(); Map<String, HostStruct.ByReference> byReferenceMap = baseService.getHostStructReferenceMap(byReferenceList); if (!shutdownSubscribers.isEmpty()) { logger.info("存在關機訂閱,執行關機操做"); for (String name : shutdownSubscribers) { logger.debug("獲取結構體指針並關機"); HostStruct.ByReference byReference = byReferenceMap.get(name); baseService.shutdown(byReference); } } if (!rebootSubscribers.isEmpty()) { logger.info("存在重啓訂閱,執行重啓操做"); for (String name : rebootSubscribers) { logger.debug("獲取結構體指針並重啓"); HostStruct.ByReference byReference = byReferenceMap.get(name); baseService.reboot(byReference); } } logger.debug("查詢主機列表"); for (HostStruct.ByReference byReference : byReferenceList) { logger.debug("查詢主機指針,同時獲取主機信息"); Integer status = baseService.getHostStatus(byReference); logger.debug("添加到Map中"); hostService.getHostStatusMap().put(Native.toString(byReference.name), status); } logger.info("--- 定時任務執行完畢 ---"); } /** * 克隆字符串集合並清空原集合 * @param primarySet 原集合 * @return 克隆的字符串集合 */ private Set<String> cloneStringSetAndClear(Set<String> primarySet) { logger.debug("新建集合"); Set<String> set = new HashSet<>(primarySet); logger.debug("清空原集合"); primarySet.clear(); logger.debug("返回"); return set; }
目前是用Set
存儲要操做的主機,可是通過查詢,HashSet
、LinkedHashSet
、TreeSet
都是線程不安全的。
這裏就怕執行定時任務的時候,忽然來了一個關機的指令,兩個線程同時訪問Set
,定時任務要克隆一個Set
而後把這個清空,關機須要在Set
中添加元素,兩個線程若是交替執行,結果就很難說了。
去concurrent
包下找,也沒找到合適的。看了看,有第三方庫實現的線程安全的Set
,之後引入進來。
這裏不知道是否是我用的有問題,是併發場景下不推薦用Set
嗎?爲何concurrent
包下沒有相關的實現類?
感嘆一句:C++
仍是難啊!
C++
老師對個人評價是字寫得還不錯,哈哈哈。佩服C++
工程師!