<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
近期,Apache SkyWalking 修復了一個隱藏了近4年的Bug - TTL timer 可能失效問題,這個 bug 在 SkyWalking <=9.2.0 版本中存在。 關於這個 bug 的詳細資訊可以看郵寄清單 lists.apache.org/thread/ztp4… 具體如下
首先說下這個 Bug 導致的現象:
The selected first getAddress is xxx.xxx.xx.xx:port. The remove stage is skipped.
no-init
模式啟動的 OAP 節點,重啟的時候會一直列印類似紀錄檔 table:xxx does not exist. OAP is running in 'no-init' mode, waiting... retry 3s later.
如果 SkyWalking OAP 出現上面的兩個問題,很可能就是這個 Bug 導致的。
下面我們先了解一下 SkyWalking OAP 叢集方面的設計
SkyWalking OAP 可選的角色有 Mixed、Receiver、Aggregator
預設角色是 Mixed,可以通過修改 application.yml 進行設定
core: selector: ${SW_CORE:default} default: # Mixed: Receive agent data, Level 1 aggregate, Level 2 aggregate # Receiver: Receive agent data, Level 1 aggregate # Aggregator: Level 2 aggregate role: ${SW_CORE_ROLE:Mixed} # Mixed/Receiver/Aggregator restHost: ${SW_CORE_REST_HOST:0.0.0.0} restPort: ${SW_CORE_REST_PORT:12800} # 省略部分設定...
L1聚合:為了減少記憶體及網路負載,對於接收到的 metrics 資料進行當前 OAP 節點內的聚合,具體實現參考 MetricsAggregateWorker#onWork()
方法的實現;
L2聚合:又稱分散式聚合,OAP 節點將L1聚合後的資料,根據一定的路由規則,傳送給叢集中的其他OAP節點,進行二次聚合,併入庫。具體實現見 MetricsPersistentWorker
類。
OAP 支援叢集部署,目前支援的註冊中心有
預設是 standalone,可以通過修改 application.yml 進行設定
cluster: selector: ${SW_CLUSTER:standalone} standalone: # Please check your ZooKeeper is 3.5+, However, it is also compatible with ZooKeeper 3.4.x. Replace the ZooKeeper 3.5+ # library the oap-libs folder with your ZooKeeper 3.4.x library. zookeeper: namespace: ${SW_NAMESPACE:""} hostPort: ${SW_CLUSTER_ZK_HOST_PORT:localhost:2181} # Retry Policy baseSleepTimeMs: ${SW_CLUSTER_ZK_SLEEP_TIME:1000} # initial amount of time to wait between retries maxRetries: ${SW_CLUSTER_ZK_MAX_RETRIES:3} # max number of times to retry # Enable ACL enableACL: ${SW_ZK_ENABLE_ACL:false} # disable ACL in default schema: ${SW_ZK_SCHEMA:digest} # only support digest schema expression: ${SW_ZK_EXPRESSION:skywalking:skywalking} internalComHost: ${SW_CLUSTER_INTERNAL_COM_HOST:""} internalComPort: ${SW_CLUSTER_INTERNAL_COM_PORT:-1} kubernetes: namespace: ${SW_CLUSTER_K8S_NAMESPACE:default} # 省略部分設定...
OAP 啟動的時候,如果當前角色是 Mixed 或 Aggregator,則會將自己註冊到叢集註冊中心,standalone 模式下也有一個記憶體級叢集管理器,參見 StandaloneManager
類的實現 。
application.yml 中的設定
core: selector: ${SW_CORE:default} default: # Mixed: Receive agent data, Level 1 aggregate, Level 2 aggregate # Receiver: Receive agent data, Level 1 aggregate # Aggregator: Level 2 aggregate role: ${SW_CORE_ROLE:Mixed} # Mixed/Receiver/Aggregator restHost: ${SW_CORE_REST_HOST:0.0.0.0} restPort: ${SW_CORE_REST_PORT:12800} # 省略部分設定... # Set a timeout on metrics data. After the timeout has expired, the metrics data will automatically be deleted. enableDataKeeperExecutor: ${SW_CORE_ENABLE_DATA_KEEPER_EXECUTOR:true} # Turn it off then automatically metrics data delete will be close. dataKeeperExecutePeriod: ${SW_CORE_DATA_KEEPER_EXECUTE_PERIOD:5} # How often the data keeper executor runs periodically, unit is minute recordDataTTL: ${SW_CORE_RECORD_DATA_TTL:3} # Unit is day metricsDataTTL: ${SW_CORE_METRICS_DATA_TTL:7} # Unit is day # 省略部分設定...
DataTTLKeeperTimer 負責刪除過期的資料,SkyWalking OAP 在啟動的時候會根據 enableDataKeeperExecutor
設定決定是否開啟 DataTTLKeeperTimer,也就是是否執行 DataTTLKeeperTimer#start()
方法。 DataTTLKeeperTimer#start()
方法的執行邏輯主要是通過 JDK 內建的 Executors.newSingleThreadScheduledExecutor()
建立一個單執行緒的定時任務,執行 DataTTLKeeperTimer#delete()
方法刪除過期的資料, 執行週期是dataKeeperExecutePeriod
設定值,預設5分鐘執行一次。
DataTTLKeeperTimer#start()
方法會在所有 OAP 節點啟動一個定時任務,那如果所有節點都去執行資料刪除操作可能會有問題,那麼如何保證只有一個節點執行呢?
如果讓我們設計的話,可能會引入一個分散式任務排程框架或者實現分散式鎖,這樣的話 SkyWalking 就要強依賴某個中介軟體了,SkyWalking 可能是考慮到了這些也沒有選擇這麼實現。
那我們看下 SkyWalking 是如何解決這個問題的呢,我們前面提到 OAP 在啟動的時候,如果當前角色是 Mixed 或 Aggregator,則會將自己註冊到叢集註冊中心,SkyWalking OAP 呼叫 clusterNodesQuery#queryRemoteNodes()
方法,從註冊中心獲取這些節點的註冊資訊(host:port)集合, 然後判斷集合中的第一個節點是否就是當前節點,如果是那麼當前節點執行過期資料刪除操作,如下圖所示
節點A和節點集合中的第一個元素相等,則節點A負責執行過期資料刪除操作。
這就要求 queryRemoteNodes
返回的節點集合是有序的,為什麼這麼說呢, 試想一下,如果每個 OAP 節點呼叫 queryRemoteNodes
方法返回的註冊資訊順序不一致的話,就可能出現所有節點都不和集合中的第一個節點相等,這種情況下就沒有 OAP 節點能執行過期資料刪除操作了,而 queryRemoteNodes
方法恰恰無法保證返回的註冊資訊順序一致。
我們既然知道了 bug 產生的原因,解決起來就比較簡單了,只需要對獲取到的節點集合呼叫 Collections.sort()
方法對 RemoteInstance
(實現了java.lang.Comparable 介面)做排序,保證所有OAP節點做比較時都是一致的順序,程式碼如下
相關程式碼如下:
/** * TTL = Time To Live * * DataTTLKeeperTimer is an internal timer, it drives the {@link IHistoryDeleteDAO} to remove the expired data. TTL * configurations are provided in {@link CoreModuleConfig}, some storage implementations, such as ES6/ES7, provides an * override TTL, which could be more suitable for the implementation. No matter which TTL configurations are set, they * are all driven by this timer. */ @Slf4j public enum DataTTLKeeperTimer { INSTANCE; private ModuleManager moduleManager; private ClusterNodesQuery clusterNodesQuery; private CoreModuleConfig moduleConfig; public void start(ModuleManager moduleManager, CoreModuleConfig moduleConfig) { this.moduleManager = moduleManager; this.clusterNodesQuery = moduleManager.find(ClusterModule.NAME).provider().getService(ClusterNodesQuery.class); this.moduleConfig = moduleConfig; // 建立定時任務 Executors.newSingleThreadScheduledExecutor() .scheduleAtFixedRate( new RunnableWithExceptionProtection( this::delete, // 刪除過期的資料 t -> log.error("Remove data in background failure.", t) ), moduleConfig .getDataKeeperExecutePeriod(), moduleConfig.getDataKeeperExecutePeriod(), TimeUnit.MINUTES); } /** * DataTTLKeeperTimer starts in every OAP node, but the deletion only work when it is as the first node in the OAP * node list from {@link ClusterNodesQuery}. */ private void delete() { IModelManager modelGetter = moduleManager.find(CoreModule.NAME).provider().getService(IModelManager.class); List<Model> models = modelGetter.allModels(); try { // 查詢服務節點 List<RemoteInstance> remoteInstances = clusterNodesQuery.queryRemoteNodes(); if (CollectionUtils.isNotEmpty(remoteInstances) && !remoteInstances.get(0).getAddress().isSelf()) { log.info( "The selected first getAddress is {}. The remove stage is skipped.", remoteInstances.get(0).toString() ); return; } // 返回的第一個節點是自己,則執行刪除操作 log.info("Beginning to remove expired metrics from the storage."); models.forEach(this::execute); } finally { log.info("Beginning to inspect data boundaries."); this.inspect(models); } } private void execute(Model model) { try { if (!model.isTimeSeries()) { return; } if (log.isDebugEnabled()) { log.debug( "Is record? {}. RecordDataTTL {}, MetricsDataTTL {}", model.isRecord(), moduleConfig.getRecordDataTTL(), moduleConfig.getMetricsDataTTL()); } // 獲取 IHistoryDeleteDAO 介面的具體實現 moduleManager.find(StorageModule.NAME) .provider() .getService(IHistoryDeleteDAO.class) .deleteHistory(model, Metrics.TIME_BUCKET, model.isRecord() ? moduleConfig.getRecordDataTTL() : moduleConfig.getMetricsDataTTL() ); } catch (IOException e) { log.warn("History of {} delete failure", model.getName()); log.error(e.getMessage(), e); } } private void inspect(List<Model> models) { try { moduleManager.find(StorageModule.NAME) .provider() .getService(IHistoryDeleteDAO.class) .inspect(models, Metrics.TIME_BUCKET); } catch (IOException e) { log.error(e.getMessage(), e); } } }
更多技術細節大家可以參考下面的連結
相關連結
以上就是Apache SkyWalking 修復TTL timer 失效bug詳解的詳細內容,更多關於Apache SkyWalking 修復bug的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45