[业界方案] 智能运维AIOps-学习笔记
[业界方案] 智能运维-学习笔记
0x00 摘要
本文为本人的学习笔记,非商用。
目的是对于所学习的技术,大致知道其应用领域,技术特点和未来方向,看看目前工作中是否可以用到,或者以后选型时能够做到心里有数,顺便也可以梳理清楚自己的知识体系。
文章或涉及多方引用,如有纰漏忘记列举,请多指正与包涵。
0x01 AIOps 背景
1.1 AIOps概述
智能运维的理想状态就是把运维工作的三大部分:监控、管理和故障定位,利用一些机器学习算法的方法把它们有机结合起来。
- AIOps 平台包括数据湖,即存储采集数据,还有自动化系统、记录系统、交互系统、监控生态圈。
- AIOps平台主要通过整合分析IT基础设施、APM、NPM、日志、数字化体验监测数据,来提升IT运维流程的效率。
- AIOps平台能力的ROI多是基于平均故障接手时间(MTTA)和平均故障修复(MTTR)时间这两个指标的降低进行评估的。
1.2 AIOps场景
AIOPS场景很多,诸如异常检测、根因分析、故障自愈、容量预测等方面。根据平台的实际场景和业界AIOPS的实践经验,360将AIOPS划分为三个场景:成本、效率和稳定性。针对成本来说,利用AI算法节省资源、智能调度,提高资源利用率的手段来节省资源;针对效率方面来说,利用AI算法主动发现问题、分析问题和解决问题,真正节省人力,提高效率。
1.3 AIOps能力
AIOps智能运维平台需要提供如下能力:
- 提供独立、开放的历史/实时数据采集、算法分析平台,整合IT数据和业务指标数据;
- 提供告警消噪(包括告警抑制、告警收敛等),消除误报或冗余事件;
- 提供跨系统追踪和关联分析,有效进行故障的根因分析;
- 设定动态基线捕获超出静态阈值的异常,实现单/多指标异常检测;
- 根据机器学习结果,预测未来事件,防止潜在的故障;
- 直接或通过集成启动解决问题的动作;
1.4 AIOps的基础
只有当工程(自动化、标准化)的水平达到一定高度后,才有望向智能化方向发展。以下给出的几种简单方法和技术,既能在异构系统中建立某种关联,为智能化提供一定的支持,又不要求开发人员改变技术栈或开发框架。
- 日志标准化:日志包含所约定的内容、格式,能标识自己的业务线、服务层级等。
- 全链路追踪:TraceID或者RequestID应该能从发起方透传到后端,标识唯一请求。
- SLA规范化:采用统一的SLA约定,比如都用“响应时间”来约定性能指标,用“慢速比”来衡量系统健康度。
0x02 一些值得借鉴的方案
2.1 容量预估
2.1.1 360
监控项的样本就是时间序列,通过分析监控项的序列,得到未来一段时间的预测值。根据波动剧烈程度,监控项可以分为波动不太剧烈和剧烈的,根据周期性,可以分为具有周期性和不具有周期性等等,当然还有很多划分的标准。可见,不同时间的序列,360需要使用不同的模型去预测。
在对时间序列进行预测的过程中,360先后使用了下面几种模型,总结出了一些经验:
模型 | 时间开销 | 准确率 | 开源包 |
---|---|---|---|
LR(线性回归) | 少 | 低 | sklearn |
ARIMA | 少 | 低 | statsmodels |
浅层神经网络,回归树等 | 中等 | 中 | pybrain, sklearn |
LSTM | 大,需要GPU | 高 | tensorflow |
2.1.2 京东物流
预测大体上分为故障预测、容量预测和性能预测。我们之前尝试了业界基于 RSTM 的一个算法,该算法是基于时序数据预测的一个经典算法。
2.2 主机分类
360会根据监控项的特征,来判断该机器属于的类型(cpu、磁盘、内存密集型)。机器学习中有很多分类算法,比如SVM、决策树、分类树等都可以完成分类任务。
2.3 负样本不足
在AIOPS中,经常用遇到负样本不足的问题,一个原因是异常的场景比较少,一个原因是用户标注的成本比较高。在主机分类的过程中,360使用了两种手段来生成样本,一种是人工标注,一种是用户标注,解决了负样本不足的问题。
比如为了将不同类型的机器和不同类型的实例进行合理搭配,需要将实例和机器进行分类。在该项目中,实例分类采用了BP神经网络,其中输入是7个重要的实例指标,输出是4个类别(低消耗、计算型、存储型、综合型)。机器分类采用决策树模型,输入是5个机器指标,输出和实例的输出类型一样。样本全部采用人工标注的方式,生成了1000左右的样本。
2.4 异常检测
2.4.1 360公司
异常检测是AIOPS最常见的场景,算法也有很多,业界比较流行的比如普通的统计学习方法--3σ原则,它利用检测点偏移量来检测出异常。比如普通的回归方法,用曲线拟合方法来检测新的节点和拟合曲线的偏离程度,甚至有人将CNN和RNN模型应用到异常点的检测。
360使用lvs比较多,为了应对流量突增和突减的情况,需要一个异常检测算法。通过对lvs流量的时间序列图的分析,发现有的曲线有周期性,有的没有,有的毛刺比较多,有的比较平稳,所以需要有一个普适检测算法,能够处理各种复杂的场景。
现实场景中,负样本比较少,360采用了无监督模型,除此之外,还借鉴投票机制来解决单纯的方法有时候具有偏差这样的问题。在该项目中,360采用了五种以上的检测算法,有统计学中同比环比的情况、曲线拟合算法以及周志华老师的隔离森林模型。通过这些模型来一起对一个时间序列进行检测。如果这些算法中有超过一半的算法认为该检测点为异常点,360就认为这个点为异常点。
2.4.2 美团外卖订单量预测异常报警模型
同比环比预测器
同比环比是比较常用的异常检测方式,它是将当前时刻数据和前一时刻数据(环比)或者前一天同一时刻数据(同比)比较,超过一定阈值即认为该点异常。
基线预测器
同比环比使用历史上的单点数据来预测当前数据,误差比较大。t时刻的监控数据,与 t-1,t-2,…时刻的监控数据存在相关性。同时,与t-k,t-2k,…时刻的数据也存在相关性(k为周期),如果能利用上这些相关数据对t时刻进行预测,预测结果的误差将会更小。
比较常用的方式是对历史数据求平均,然后过滤噪声,可以得到一个平滑的曲线(基线),使用基线数据来预测当前时刻的数据。
Holt-Winters预测器
同比环比预测到基线数据预测,使用的相关数据变多,预测的效果也较好。但是基线数据预测器只使用了周期相关的历史数据,没有使用上同周期相邻时刻的历史数据,相邻时刻的历史数据对于当前时刻的预测影响是比较大的。
美团使用了Holt-Winters来实现这一目标。Holt-Winters是三次指数滑动平均算法,它将时间序列数据分为三部分:残差数据a(t),趋势性数据b(t),季节性数据s(t)。使用Holt-Winters预测t时刻数据,需要t时刻前包含多个周期的历史数据。相关链接:Exponential smoothing、Holt-Winters seasonal method。
外卖报警模型中的预测器
在外卖订单量异常检测中,使用Holt-Winters预测器实时预测下一分钟订单量,每次需要至少5天以上的订单量数据才能有较好的预测效果,数据量要求比较大。在实际的异常检测模型中,我们对Holt-Winters预测器进行了简化。预测器的趋势数据表示的是时间序列的总体变化趋势,如果以天为周期看待外卖的订单量时间序列,是没有明显的趋势性的,因此,我们可以去掉其中的趋势数据部分。
计算序列的周期性数据
时间序列的周期性数据不需要实时计算,按周期性更新即可,如外卖订单大盘监控,s(t)只需要每天更新一次即可。对于s(t)的计算,可以有多种方法,可以使用上面提到的Holt-Winters按公式计算出时间序列的周期性数据,或直接使用前一天的监控数据作为当天的周期数据(这两种方式都需要对输入序列进行预处理,保证算法的输入序列不含有异常数据)。也可以将历史数据做平均求出基线作为序列的周期性数据。
目前外卖订单中心报警模型采用的是Holt-Winters计算周期数据的方式。在将该模型推广到外卖其他业务线监控时,使用了计算基线数据作为周期数据的方式。
残差数据实时预测
计算出周期数据后,下一个目标就是对残差数据的预测。实际监控数据与周期数据相减得到残差数据,对残差数据做一次滑动平均,预测出下一刻的残差,将该时刻的残差、周期数据相加即可得到该时刻的预测数据。残差序列的长度设为60,即可以得到比较准确的预测效果。
预测器预测出当前时刻订单量的预测值后,还需要与真实值比较来判断当前时刻订单量是否异常。一般的比较器都是通过阈值法,比如实际值超过预测值的一定比例就认为该点出现异常,进行报警。这种方式错误率比较大。在订单模型的报警检测中没有使用这种方式,而是使用了两个串联的Filter,只有当两个Fliter都认为该点异常时,才进行报警,下面简单介绍一下两个Filter的实现。
- 离散度Filter:根据预测误差曲线离散程度过滤出可能的异常点。一个序列的方差表示该序列离散的程度,方差越大,表明该序列波动越大。如果一个预测误差序列方差比较大,那么我们认为预测误差的报警阈值相对大一些才比较合理。
- 阈值Filter:根据误差绝对值是否超过某个阈值过滤出可能的异常点。阈值Filter设计了一个分段阈值函数y=f(x),对于实际值x和预测值p,只有当|x-p|>f(x)时报警。实际使用中,可以寻找一个对数函数替换分段阈值函数,更易于参数调优。
2.4.3 微众银行
微众银行目标是使用机器学习算法实现无阈值KPI曲线异常识别。
“微众银行智能监控系统识图模块”是针对业务四大黄金指标而设计的智能曲线异常检测系统。四大黄金指标包括交易量(业务实时产生的交易量)、业务成功率(业务成功量/交易量)、系统成功率(系统成功量/交易量, 业务成功量和系统成功量的区别在于是否明确捕捉到系统异常)、平均时延(交易的平均耗时)。这四大黄金指标都是分钟级数据,这四个指标统计维度不同,波动规律也有所差别,因此需要用不同的算法检测。
检测方法主要有三种:
- 基于LSTM与高斯分布的检测,这个算法主要用于交易量和时延的检测。大部分的曲线突变都能准确检测到,但算法的死角在于小幅度长时间的缓慢变化容易被漏掉。
- 基于k-means算法的特征检测,主要用于填补第一种算法的盲区,在交易量缓慢变化的案例效果较好。
- 基于概率密度的检测,主要用于业务成功率和系统成功率的曲线,因为成功率曲线的背后隐藏着无数的可能,需要用一个更接近本质的量来衡量异常的程度。
而以上三种方法都有一个共同的判断原则——少见即异常。在我们确立了无监督为主的大前提下,异常检测的问题转换成了如何衡量当前的情况是否“少见”的问题。
2.4.3 华为
首先是数据源的异常检测。
Z-score算法
Z-score算法,就是每个点减去均价再除方差,衡量计算这个点与整体情况的偏离度,达到一定程度就标记为极度异常数据(不纳入指标统计)。
用最简单的方法先过滤掉,在正常情况下,z-score能够帮助我们过滤掉更多的异常,而在真正出现故障时,可以减少对合理异常数据的过滤。
但是这个z-score算法,优点的计算简单,计算成本低,但是缺点是后期人工成本高;比如对于数据滑窗参数要手工调整,同时阈值也需要手工判断,成本较高。同时,算法本身对于异常点突出效果不明显的话,阈值难以取舍。接下来就是来了基于Boxplot箱线图的改良算法。
Boxplot算法
该算法核心是基于箱线图算法来改良的,在这个思想里,默认异常数据百分比是比较低且相对稳定的,不过,指标数据一般不是完美的正态分布,比如时延指标是有右偏(偏大)情况,会往高的时延方向偏移,因此,我们在原有的箱线图算法中加了一个重心偏移。同时,我们还发现时延数据不仅有重心偏移,还存在长尾效应,因此我们还加入了长尾修正参数,即:99分位数据减去中间值除上75分位与中间值来衡量这个长尾效应,这样,算法很好地解决了存在重心偏移以及长尾效应的异常数据过滤。
时间序列分解算法
数据源的异常检测解决好后,指标的异常检测就有了基础。
大家经常用到异常检测方法的时间序列分解法,周期项、趋势项、残差项的计算都在其中。从算法表现图上来看,通过周期学习,趋势计算后,原始数据减去周期再减去趋势,就变成了白噪声。通过置信空间的计算,叠加原来计算的周期与趋势,就得到了指标的上下阈值。
因为用户少,少量用户的异常失败就会导致整个指标下降30%甚至更多,而且每天发生这种下降的随机性很强。
多工况检测算法
上面时间序列分解算法所不能适应的场景,就是多工况检测(MRCheck)算法的由来,这个算法外部用的很少,在此分享下,我们通过历史数据的特征进行贡献度识别,其实数据的波动和请求量还有时间是有关系的。因此,如图所示流程,会根据特征(请求量和时间),建立不同的工况(本质是聚类算法),如3~20种工况,然后通过各个点与聚类中心点的距离进行工况划分的评估,确定工况划分的合理性。
可以这么理解,以前时间序列是只有一种工况的特例,而现在我们通过变成多种工况,重新评估置信空间,异常检测阈值线根据工况变化随之发生变化,很好的解决了原来时间序列分解算法的问题。
2.5 报警收敛
2.5.1 360
360对历史报警进行分析,发现其中有很多规律。如果360利用算法分析出这些报警项之间的关系,再加上人工经验,将很大程度减少报警的数目。
下面介绍一下如何通过算法去分析出报警项之间的潜在关系。360采用机器学习中关联分析常用的算法Apriori来分析历史报警,该模型利用频繁项集分析出A—>B这种关系。将这种规则应用到报警中,如果A报警发出,则B报警就不需要发出,这样就能够成倍减少报警次数。下图是360对过去30天的报警数据分析,得到20+的关联规则。
360线上维护着一个规则库,这个规则库来源于两部分:算法分析规则、人工总结规则。在利用这些规则同时,360还结合了业务的评级来对业务报警进行一定程度的合并处理。
2.5.2 美团
以下是美团的一种算法落地实施。
异常报警根因分析的设计大致分为四个部分:收集报警信息、提取报警信息的关键特征、聚类处理、展示报警摘要。
聚类算法采用论文“Clustering Intrusion Detection Alarms to Support Root Cause Analysis [KLAUS JULISCH, 2002]”中描述的根因分析算法。该算法基于一个假设:将报警日志集群经过泛化,得到的泛化报警能够表示报警集群的主要特征。可以将报警抽象为各种层次,抽象层次越高,细节越少,但是它能包含的范围就越大;反之,抽象层次越低,则可能无用信息越多,包含的范围就越小。这种抽象的层次关系可以用一些有向无环图(DAG)来表达。
算法描述
- 算法假设所有的泛化层次结构Gi都是树,这样每个报警集群都有一个唯一的、最顶层的泛化结果。
- 将L定义为一个原始的报警日志集合,算法选择一个属性Ai,将L中所有报警的Ai值替换为Gi中Ai的父值,通过这一操作不断对报警进行泛化。
- 持续步骤2的操作,直到找到一个覆盖报警数量大于min_size的泛化报警为止。
- 输出步骤3中找到的报警。
2.6 根因分析
2.6.1 360 模型
360推出一种模型,能够帮助运维人员缩小报警排查范围,快速定位到问题。该项目中要分析两个维度数据:
一个是事件维度,关注的是六大类报警事件;
一个是指标维度,关注机器维度的监控项(大约有200左右个监控项)。
那如何在事件发生后,找到跟它相关的指标呢?实现的方法如下:
- 针对每个事件,使用在2014年SIGKDD会议上发表的论文《Correlating Events with Time Series for Incident Diagnosis》中提到的方法,看哪些指标跟这个事件发生有关系。
这样的目的能够对指标进行初筛,达到降维的目的。
- 针对第一步选出来的指标,求出这些指标的信息增益比,选择前k个(360取得值是5)特征作为最后的影响指标;
- 最后使用xgboost对影响指标进行分类,验证效果。
2.6.2 微众银行专家系统
微众银行先采用专家系统的技术来实现,主要有以下原因:
- 首先,“业务异常”的数据是“小数据”。在“小数据”的基础上,机器学习在根因分析方面的应用相对有限。
- 其次,“根因分析”是需要有较强的解释性的,每次业务异常后,运维工程师都会有完整的异常事件分析报告,机器学习在可解释性上相对较弱,而专家系统能更好的解释根因是如何分析出来的,更符合人类的思考逻辑。
- 最后,利用人类专家“举一反三”的能力,可以短期内构建出根因分析系统。
因此我们先选择了专家系统的解决方案,将IT专家的经验总结起来形成推导规则。
2.6.3 微众银行知识图谱
传统根因推导过程是运维工程师通过对软件架构和调用关系的理解将异常发生时的告警、日志等信息联系在一起,应用运维知识经验来排查推导异常根因,相当于在大脑中存储和训练了一个知识图谱。其中最大的挑战在于,运维工程师的知识经验存在差异而且往往仅精通本领域知识,同时人脑存储的信息量也相对有限。
图形数据库(图形数据库是一种非关系型数据库,应用图形理论存储实体之间的关系信息)可以针对每个异常事件创建一个覆盖多应用域及基础架构的全专业图谱,沉淀运维知识进行因果推导。相比于专家规则引擎系统,基于图数据库的知识图谱更利于开发维护,并且具备结合机器学习实现复杂推理和新知识发现的扩展性,可视化的推导链路也具有较好的可解释性易于复盘和优化。
针对异常事件建立的知识图谱包含每笔异常交易的路径信息、CMDB 关联的数据库等基础架构信息、相关性分析得出的告警 / 日志 / 变更信息,针对这些数据基于基础组件影响上层应用等运维知识进行因果推导得出根因,如果存在多种结论则依据加权评分进行可能性排名。
异常事件的知识图谱是结合“动”态和“静”态数据来设计,“动”态数据包括业务流水相关的日志、证据数据,“静”态数据则来自于CMDB等配置系统。两类数据共同构建起一个完整的异常事件图谱。一般来说,知识图谱设计及根因分析一般包括信息收集、根因定位、根因补充三个阶段。
2.6.4 京东物流
在做根因分析的时候,我们首先要做的就是要把指标和应用的一些关联拓扑构建出来。指标和应用的拓扑依赖关系应该如何去构建呢?这主要依赖于分布式跟踪系统进行自动探测应用拓扑。
但在实际应用中,通常我们探测的拓扑关系比较复杂需要结合人工标注的方式为拓扑增加相应的权重作为拓扑依赖关系的一个修正。有了应用拓扑之间的依赖关系之后,基于大量历史告警数据进行自学习,分析每个故障时间点应用和指标之间的关联关系汇总为知识库数据,并存储到知识库系统。
这个不断完善的知识库系统可以作为研发定位问题的依据,也可以作为故障自动处理的依据,还可以作为运维机器人的知识来源。同时,知识库也支持人工添加一些常见的故障以及故障原因并给予较高的分析权重。基于不断修正的业务拓扑关系,系统就可以自动找出一个或几个故障的根因。
2.7 平台
2.7.1 京东
京东物流的运维体系规划。最下层是资源层,包括物理资源、虚拟资源、应用、中间件以及数据库。上层是平台层。
- 在平台层,我们建立了维护基础数据的 CMDB 系统,在 ITSM 管理方面,集成了事件管理、问题管理、值班管理等运维流程化管理模块。在 CMDB 系统基础上我们建设了大规模资源监控平台、网络监控平台以及多个运维平台。
- 再往上,是数据化层。在这一层,我们期望通过对监控和运维平台产生的大量数据进行分析,做趋势性的预测和智能分析,提供一些比较有价值的统计报表,来指导业务运营和决策。
- 最上层是 AIOps 层,我们是从三个方面去实现的:发现问题,解决问题,规避问题。基于 AIOps,我们可以在异常检测、根因分析、故障预测、智能故障处理、智能运维机器人等方面继续发力探索。在解决问题方面,可以借助 KPI 聚类分析进行告警知识库自学习和故障自动处理等。
如何从架构方面落地实现的呢?我们将整体系统架构拆分为底层数据处理架构和业务架构,底层数据处理架构负责监控数据的采集、数据清洗、校验、告警和通知操作。业务架构负责监控数据统计分析、展现。
- 首先我们采用被动监控的方式,通过部署监控 Agent,把监控数据收集到 Kafka 消息队列里。消费模块从 Kafka 拿到数据后转存到 jimdb(京东内部的内存数据库中间件)中,jimdb 实际是一个内存的分布式消息队列。
- 这里加了一层 jimdb 的队列。为什么要加这层呢?因为我们如果直接消费 Kafka,Kafka 有分区的概念,不同的分区之间可以并发生产消息,但是 Kafka 的分区是消耗磁盘 IO 的,如果我们建的分区太多,这个磁盘 IO 可能就会是一个瓶颈,而且意味着我们要需要更多的硬件资源。
- 考虑到这一点,我们增加了 jimdb 层,它是一个生产者消费者模型的分布式消息队列,理论上可以有无数个 Consumer,这些 Consumer 之间并发消费数据,从而实现并发数据处理。
我们把所有的监控平台的监控数据整合在一起,接入了京东目前所有的监控系统,包括 log 监控、Docker 监控,MDC 的监控,DBS 的数据库监控,还有调用链监控等,把数据收集起来做统一的报警和分析。在 2.0 版本,我们会把所有监控平台的指标收集上来之后,在应用维度做统一的整合。这样在一个应用页面,就可以看到这个应用相关的所有监控信息,比如操作系统维度的指标,数据库相关指标、应用性能相关指标以及日志相关的指标等。
此外,我们还加入了日志分析的相关功能,使用的是业界比较成熟的方案:通过 agent 将日志发送到 Kafka,Kafka 里面做一些 Cluster,Filter,最后存储和索引。
2.8 APM
2.8.1 京东物流
关于 APM,Google Dapper 可以说是所有 APM 产品的鼻祖。基于 Dapper,近年来也出现了非常多优秀的 APM 产品。除了商业化的 APM 厂商,还有一些比较优秀的开源项目:Pinpoint / Zipkin / Cat / EagleEye / OpenTracing / SkyWalking 等。各种 APM 产品各有优劣,结合自身业务需求并充分对比分析后我们选择基于 Pinpoint 进行二次开发实现 APM。
它的缺点在于性能方面比 Zipkin、SkyWalking 要差一点,但是 Pinpoint 也有其他项目不具备的优势,比如接入简单无需修改代码,再比如可以跟踪到代码级别等等。
目前有很多国内外的厂商都在做 APM 的产品,如果企业计划做 AIOps 的话我们不推荐直接使用厂商的产品,因为厂商的 APM 底层数据对客户是不透明的。而自主研发 APM 平台最大的意义在于 APM 里面有大量的数据是我们可以使用的,通过对这些基础数据进行大数据分析以及数据挖掘之后,可以为 AIOps 提供很多数据来源。如果使用厂商的产品,在很多方面底层数据的使用就不是那么自由了。
下面介绍一下我们在 APM 方面的进展,我们基于 Pinpoint 开发的 Jtrace 分布式跟踪系统拥有 7 大能力:
- 分布式事务跟踪;
- 自动检测应用拓扑;
- 水平扩展支持大规模服务集群;
- 代码级别的可见性,这是相对于其他产品最大的不同,它可以跟踪方法堆栈,特别清晰;
- 使用字节码增强;
- 集成了 SQLAdvisor,在抓到 SQL 之后,我们会分析到哪些是比较慢的 SQL,慢的 SQL 到底慢在哪里,我们可以通过这个给出一些优化建议;
- 智能化采样率,基于业务访问量自动调整采样率,大大降低了业务性能方面的开销。
关于性能方面,我们从以下几个方面进行了优化:
- 使用二进制格式(thrift 协议),高压缩比,在网络传输上可以减轻很多开销;
- 使用变长编码和格式优化数据记录(thrift CompactProtocol);
- 用常量表替换重复的 API 信息,SQL 语句和字符串;
- 智能采样率;
- 使用异步数据传输来最小化应用线程中止;
- 使用 UDP 协议传输数据。
优化后性能损失与目前流行的 Zipkin 相近。相对于我们获取的数据精度来说,这个是可以接受的结果。
0xFF 参考
微众银行智能运维AIOps系列| 浅析智能异常检测:“慧识图”核心算法(三)
https://tech.meituan.com/2017/04/21/order-holtwinter.html
https://github.com/Microsoft/TagAnomaly
https://github.com/baidu/Curve
https://github.com/Tencent/Metis
https://github.com/yahoo/egads
https://github.com/Netflix/Surus
https://github.com/rob-med/awesome-TS-anomaly-detection
https://github.com/yzhao062/anomaly-detection-resources
https://github.com/dsmi-lab-ntust/AnomalyDetectionToolbox
https://github.com/jeroenjanssens/phd-thesis
https://www.xenonstack.com/blog/time-series-analysis/
https://github.com/NetManAIOps/donut