您有大量的数据,数据的存储和管理消耗您大量的成本,您知道这些数据隐藏着巨大的价值,但是您总觉得还没有把数据的价值变现出来,对吗?来吧,我们用一系列的案例帮您轻松落地AI模型服务,实现数据价值的变现......
阿里云日志服务简介
阿里云日志服务给用户提供了对非结构化、半结构化和结构化数据进行存储、查询、分析和可视化等服务的一站式综合性服务平台。
结构化数据就是类似于二维表格那样的数据,数据类型和格式都是固定的数据,数据可以很容易地进行查询和分析。是一种schema-on-write的数据,即数据写入的时候,schema(数据类型和格式)就确定了。
非结构化数据的数据格式不固定,灵活性很强,比如文本、图像、音视频等。
半结构化数据介于结构化数据和非结构化数据之间的数据类型,它们具有一些结构化特征,但也包括一些非结构化元素。常见的半结构化数据类型包括XML和JSON数据等。
阿里云日志服务的数据处理能力
对于这几种类型的数据,阿里云日志服务都支持存储、查询和分析等操作。阿里云日志服务还支持对非结构化数据进行处理整理成为结构化数据。在结构化数据上的查询、分析和可视化的操作更加丰富。
互联网服务的海量运作数据
互联网服务的运作数据主要用于诊断服务系统是否有异常、问题的原因出在哪里、用户的偏好和习惯、如何把用户分类、服务的性能和质量、资源是否得到充分使用等等。
互联网服务在运作过程中,收集到数据量是惊人的。一个大的互联网服务通常是由大量的计算机组成的分布式系统。为了监测系统运作是否正常,时时刻刻都在收集系统的运作状态和指标数据。一个大的互联网服务有1000个计算机集群是很常见的。假设每个计算机集群又包含了大约100台计算机,每台计算机对其中的10,000个对象提供服务。假设每10秒采集一组指标,这一组指标包含10个单独的指标,假设每个指标用4个字节来记录。那么,一天可以产生(10个指标/次采样) * (6次采样/分钟) * (60分钟/小时) * (24小时/天) * (10000对象/计算机) * (100台计算机/计算机集群) * (1000计算机集群) = 8.64+e12个指标/天。也就是一天会产生超过8万亿个的指标数据样本。因此,互联网服务自动产生的运作数据量是惊人的。
这么大的数据量,会消耗数据存储成本和管理成本,如果没有好好利用上,会造成巨大的财务浪费。但是,如果能够好好利用上,能够快速地生成自动智能分析数据的服务,自动地从数据中诊断出服务系统是否有异常、问题的原因出在哪里、自动地修复系统,则可以提升系统运维的效率,解放运维工程师的劳动力,缩减运维成本,同时还能提高服务的质量、提升用户的信任度、提升服务对用户的黏性,实现数据价值的变现。再有,如果能够利用数据智能地分析出用户的喜好和行为习惯,可以让产品或者服务的广告更加有效,提升广告到销售的转化率,也能把数据的价值转换称为营业收入。另外,如果能够利用数据智能地分析出系统的资源调度存在缺陷、发现系统运作的资源热点和瓶颈,自动地改进调度,则可以提升系统资源的利用率,提升ROI(Return of Investment),也会提升服务质量,提升用户的满意度和对用户的黏性。
因此,数据的产生和存储需要消耗成本,但是也有很大的潜在价值。如果不能很好地挖掘和提炼变现,大数据则会是一块成本中心。相反,如果能够很好地挖掘和提炼变现,将会是服务的价值中心。阿里云日志服务存储服务中提供的AI服务,就是要帮助用户快速把数据转换成为价值。
阿里云日志服务的AI服务变现数据价值
让高价值的AI计算在您的数据里唾手可得
目前很多机构和团队都知道数据的潜力,所以大都会先把系统运作的数据收集起来,放到分布式的大数据管理平台上,比如日志服务或者其他的数据仓库、数据湖中。要用这些数据做高级的AI计算来挖掘知识和发现洞见,通常需要把这些数据读取到进行AI计算的环境中,在AI计算环境中计算完毕后,再把计算结果写回到大数据管理平台里。比较常见的做法就是数据科学家/AI机器学习工程师用自己熟悉的Python机器学习库,把数据读取到客户端的内存中,分析完以后再写回到大数据存储平台。这种计算方式是把数据拉到AI计算的方式。但是这种方法的效率非常低下,首先需要把数据从大数据管理平台转移到客户端的内存,有大量的数据被转移到外部,消耗大量的网络带宽,同时客户端的机器的算力很有限,而AI算法大都又特别消耗算力,因此这种方法的效率比较低下,很难充分发挥挖掘数据的潜力。参考下图的把数据拉到AI计算的方式。
常见的低效的AI计算
阿里云日志服务把AI计算集成到日志服务平台里了,并且以SQL函数的方式给用户使用。这种方式是把AI计算拉到数据的方式。这种方式不仅可以让高价值的AI计算就像在地上捡西瓜那么容易,还让整个AI计算的链路变得非常高效。由于AI计算的算法已经集成在阿里云日志服务中了,因此不需要把数据从大数据存储平台转移到外部AI计算的环境,从而大大地减少了数据的外部流动,不仅仅节省带宽,而且节省成本,因为在云平台里的大量数据往外传输的成本往往是比较高的,但是数据在数据中心内部的流转的成本是很低的甚至是免费的。另外,阿里云日志服务是一个分布式的存储和计算平台,每个集群有成百上千台服务器,这些服务器的算力通常要远高于客户端用来做AI算法的算力。阿里云日志服务提供的AI计算在后台自动分布式并行处理,自动地充分利用每个集群里成百上千的服务器进行分布式并行计算,无需用户花心思去设计和实现分布式并行处理的程序,让AI计算的分布式并行计算很简单。因此,阿里云日志服务的AI服务的效率非常高。参考下图的把AI计算拉到数据的方式。
阿里云日志服务的高效的AI服务
总之,阿里云日志服务的AI服务是用户落地AI应用变现数据价值的极简易、极高效的方式。
怎么使用阿里云日志服务轻松落地您的AI应用
阿里云日志服务提供了一系列的AI应用服务,帮助用户轻松地落地AI应用。为了方便用户了解如何把阿里云日志服务的AI服务和自己的数据结合起来,快速地变现数据的价值,我们提供了一系列的AI应用的实践范例,供用户参考。
预测服务
什么时候您需要预测服务?
预测的作用是帮助提前规划,减少资源消耗,降低成本,未雨绸缪。
最简单的例子,就是天气预报。提前几天预测台风的到来,可以提前做好准备,降低损失,这样不会措手不及。提前预测是否会下雨,可以帮助管理出行计划。
在企业生产里,产品的需求是波动的,有了对产品将来一段时间的需求比较准确的预测,可以帮助合理提前安排采购计划,生产计划,方便人员排班部署。否则,会出现产品过剩、库存积压、资金不能通畅流转;或者用户想买产品而买不到,选择竞争对手的产品,浪费机会成本,降低自己的竞争力。这是因为采购或者生产都需要时间的,在物流供应链里的术语叫提前期(lead time)。如果采购、运输或者生产不需要时间,能够瞬间完成,这时候是不需要提前预测的。
在IT系统自动化领域里,用户的请求是波动的,用户的请求量决定了资源的消耗量。资源的调度也是需要时间的,比如为了实现服务的弹性伸缩,自动租用和释放虚拟计算机来满足高峰期的用户的请求和减少低谷期的资源的消耗。由于租用、启动VM,安装特定的软件包等等都需要时间,提前预测好用户的请求量,就能帮助提前规划资源调度。否则,如果资源不足,用户的请求可能没法及时地响应,超时出错,用户体检非常差。如果资源过多,造成资源浪费。有了准确的预测,就能帮助在正确的时间准备正确数量的资源。
总之,在企业生产或者计算机服务里,用户的需求是外部的,生产和资源调度等是企业内部的(Logistics),内部的可控性通常比外部的可控性要高很多,预测能够帮忙连接企业外部需求和内部的组织管理,让内部生产和组织平滑运作,降低成本,提升用户体验。
阿里云日志服务的AI预测服务
阿里云日志服务提供的预测服务,不同于其他的预测服务,阿里云日志存储提供的AI预测服务把所有数学建模的细节都包起来,对用户没有任何数学建模知识上的任何要求,只要求会点SQL,把数据表对应的列填到指定的函数参数就可以了。这样可以降低AI预测模型的使用门槛,让您的AI预测服务更容易落地。
另外,阿里云日志服务提供的预测服务不仅可以用于短期的预测,还可以比较准确地对远期的情况进行预测。
对于预测服务,我们直接用图来描述吧。我们提供了三个预测效果的可视化展示,参考下面的三个图。其中蓝色的曲线表示到目前为止的最近一段时间的历史数据,红色的曲线是模型预测出来的未来的时间点的指标数值。对三个指标数据组成的时间序列数据分别进行预测,分别对预测了接下来的1440个时间点(分钟)的指标数值。其他的大部分预测模型对近期的几个时间点预测比较准确,如果往前预测很多个时间点,预测效果就变得很差了。但是,可以看到阿里云存储日志服务在往前预测超过上千的时间点的情况下,还能保持比较高的准确度。
时间序列预测范例一
时间序列预测范例二
时间序列预测范例三
指标数据通常是以高维二维表指标数据的形式保存的,参考下面的高维指标数据。这一类的指标数据都有一个时间维度列、一个或者多个指标数值列、一个或者多个上下文维度列。
高维指标数据例子: metric_data_table
cluster |
server |
metric_name |
time_period |
metric_value |
Cluster-A01 |
Server-01 |
request_count |
2024-01-01 00:00:00 |
180 |
Cluster-A01 |
Server-01 |
request_count |
2024-01-01 00:01:00 |
200 |
Cluster-A01 |
Server-01 |
request_count |
2024-01-01 00:06:00 |
150 |
Cluster-A01 |
Server-01 |
request_count |
2024-01-01 00:08:00 |
175 |
Cluster-A01 |
… |
... |
... |
... |
Cluster-A01 |
Server-01 |
network_ingress |
2024-01-01 00:00:00 |
2000000000 |
Cluster-A01 |
Server-01 |
network_ingress |
2024-01-01 00:01:00 |
2500000000 |
Cluster-A01 |
Server-01 |
network_ingress |
2024-01-01 00:02:00 |
1200000000 |
... |
... |
... |
... |
在这个例子的数据中,每个cluster的每个server的每个metric_name的time_period和metric_value的两个字段构成一个时间序列。可以使用阿里云日志服务中的ts_forecast(…)函数按照下面的SQL语句来对每一个cluster的每个server的每个metric_name的指标数据分别进行预测。
select cluster, server, metric_name, ts_forecast( array_agg(time_period), --时间序列中的时间数据拼成的数组 array_agg(metric_value), --时间序列中的指标数值列拼成的数组 '2024-01-01 00:00:00', -- 时间序列历史数据开始的时间点(该点有历史数据)以便自动填充数据 '2024-01-08 00:00:00', -- 时间序列历史数据结束的时间点(第一个时间点没有历史数据)以便自动填充数据 '2024-01-10 00:00:00', -- 指定要预测的结束的时间点(不包含该点) '1 minute' -- 指定时间序列的相邻点的时间间隔以方便自动填充数据 ) as forecast_outcome from metric_data_table where time_period >= '2024-01-01 00:00:00' -- 指定历史数据开始的时间点 and time_period < '2024-01-08 00:00:00' -- 指定历史数据结束的时间点 group by cluster, server, metric_name
ts_forecast(…)函数的参数规范参考这个例子的注释部分。这个例子是把2024-01-01 00:00到2024-01-07 23:59的分钟级别的数据交给ts_forecast(…)函数,让其帮忙预测从2024-01-08 00:00一直到2024-01-09 23:59的分钟级别的2880个时间点的指标的数值。
这里的每个cluster的每个server的每个metric_name的预测是相互独立的,阿里云日志服务能够自动地把预测计算分发到后台成百上千台计算机进行分布式并行计算,因此,计算速度会非常快。
另外,用户在存储数据的时候,为了节省空间,通常会把数据值为0的数据点移除。ts_forecast(…)函数能够帮我们把这些数据自动地填补回来,帮助用户在预测时减少了数据预处理的工作量。
因此,阿里云日志服务的预测服务的接口非常简单,不需要数学建模的知识,计算速度快。
异常检测
细粒度对象的异常检测
互联网服务运作的指标数据很大一部分的作用在于自动地诊断服务系统是否有异常、如果有问题,问题出在哪里。这些指标的历史数据会呈现出一定的模式,比如大概率在那个范围内波动,如果超出了某个范围将是很罕见的现象等。指标之间可能还会有关联关系,比如系统的请求压力会影响系统请求的平均延迟。
阿里云日志服务提供的AI异常检测服务通过自动分析一组指标的潜在模式,然后判断指标是否遵循这些潜在的模式。如果指标的数值和潜在的模式不匹配,则判断为异常。判断的异常分等级,一级异常表示概率为0.1左右的小概率事件才会出现的指标值,二级异常表示概率为0.01左右的小概率事件才会出现的指标值,三级异常表示概率为0.001左右的小概率事件才会出现的指标值,以此类推。
例如,参考下面的例子,假设我们把收集到的两个指标数据的数据投射到一个二维平面上。可以使用阿里云日志服务提供的模式分析函数帮助分析指标数据内在的模式。模式分析函数发现这两个指标的数据以99%的概率落在红色内圈里,即如果落在内圈外外圈内,为二级异常。两个指标的数据以99.9%的概率落在红色外圈里,即如果落在外圈外,为三级异常。当然还有四级、五级异常等等,为了简化,没有把对应的圈画出来。用户可以自主地选择过滤保留哪一个级别以上的异常。
指标数据分布模式的识别
我们用一些范例数据和SQL语句来描述如何用阿里云日志存储的AI服务来进行异常检测。这个过程分两步:第一步,在历史数据中分析指标模式;第二步,结合最新收集的数据和前一步分析出来的模式进行异常检测。
高维指标数据例子: metric_data_table
cluster |
server |
time_period |
request_count |
network_traffic |
latency_us |
Cluster-A01 |
Server-01 |
2024-01-01 00:00:00 |
180 |
2000000000 |
100 |
Cluster-A01 |
Server-01 |
2024-01-01 00:01:00 |
200 |
2500000000 |
120 |
Cluster-A01 |
Server-01 |
2024-01-01 00:06:00 |
150 |
1200000000 |
110 |
Cluster-A01 |
Server-01 |
2024-01-01 00:08:00 |
175 |
1800000000 |
115 |
… |
… |
... |
... |
… |
… |
上面的表格展示了对每个cluster的每个server的每个数据采集周期的三个数量指标:request_count、network_traffic和latency_us。我们可以用下面的SQL语句对每个cluster的每个server的最近一段时间的三个指标的数据进行联合模式分析,每个cluster的每个server都有属于自己的统计的联合指标模式分析。这是给每个cluster的每个server一个私人定制的模式分析。我们可以使用下面的SQL语句进行模式分析,然后把指标联合模式分析的结果保存到metric_pattern_table中,也可以放在带with语句的通用表表达式(Common Table Expression)中。
select cluster, server, '2024-01-01 00:00:00' as time_window_begin, '2024-01-08 00:00:00' as time_window_end, summarize( array_agg(array[request_count, network_traffic, latency_us]) ) as metric_ pattern from metric_data_table where time_period >= '2024-01-01 00:00:00' -- 指定历史数据开始的时间点 and time_period < '2024-01-08 00:00:00' -- 指定历史数据结束的时间点 group by cluster, server
模式分析结果表: metric_pattern_table
cluster |
server |
time_window_begin |
time_window_end |
metric_pattern |
Cluster-A01 |
Server-01 |
2024-01-01 00:00:00 |
2024-01-08 00:00:00 |
{…} |
… |
… |
… |
… |
... |
然后我们可以用下面的SQL语句,结合之前从历史数据中识别出来的指标模式,对最新收集到数据进行异常检测,过滤保留4级以上的异常(万分之一的小概率的异常)。结果类似于metric_anomaly_table结果表中的数据。
select md.cluster, md.server, anomaly_level( mp.metric_pattern, array[md.request_count, md.network_traffic, md.latency_us] ) as anomaly_level, -- 结合统计出来的数据模式和最新收集到的数据,计算异常等级 md.request_count, md.network_traffic, md.latency_us from metric_data_table as md join metric_pattern_table as mp on md.cluster = mp.cluster and md.server = mp.server where md.time_period >= '2024-01-08 00:00:00' -- 指定异常检测数据开始的时间点 and md.time_period < '2024-01-08 00:01:00' -- 指定异常检测数据结束的时间点 and anomaly_level( mp.metric_pattern, array[md.request_count, md.network_traffic, md.latency_us] ) >=4
异常检测结果表: metric_anomaly_table
cluster |
server |
time_period |
anomaly_level |
request_count |
network_traffic |
latency_us |
Cluster-A01 |
Server-01 |
2024-01-0800:00:00 |
5 |
180 |
2000000000 |
100000 |
… |
… |
… |
... |
… |
… |
… |
解决告警过多的问题
在上面的这个例子里,我们异常检测的粒度是每个cluster的每个server。用户在用阿里云日志服务的AI异常检测服务的时候,可以自主地选择自己想要的检测粒度。对于一个中大型的互联网服务,系统有上百万的服务器(server)是常见的,我们选取了四级以上的异常等级来过滤保留异常。假设我们每分钟对所有的服务器都检测一次,每分钟基本上都会检测出数以十计的异常。如果对这些异常都作为一次告警,那将会有大量的告警,形成告警洪流,服务系统的运维工程师将会疲于奔命,最终会对这些告警麻木。
为了降低异常告警的洪流,我们在细粒度的异常检测结果的基础上,在更粗的粒度上再使用相似的方法进行异常检测,起到异常结果聚合的作用。在这个例子里,抑制告警洪流的步骤为:
1. 在每分钟,对于每个cluster,计算有异常的server的比率。例如有的cluster有异常的server的比率是1.5%,有的是0.5%,有的是0%等等。
2. 以cluster为粒度,以server异常的比率作为指标,抽象统计指标的分布模式。
3. 以cluster为粒度,结合统计出来的分布模式,对每个cluster的server异常的比率指标做异常检测,把异常率特别高的cluster检测出来。
这样,在以cluster为粒度的server异常率的指标进行二次异常检测,会很大程度地降低异常的数量,起到异常告警洪流抑制的效果。
如果我们把在server粒度的结果在cluster粒度上聚合计算异常比率的结果类似于下面的表格。
异常检测结果汇总表: cluster_server_anomaly_table
time_period |
cluster |
server_count |
anomalous_server_count |
anomaly_rate |
2024-01-08 00:00:00 |
Cluster-A01 |
200 |
2 |
1% |
… |
… |
… |
... |
… |
Cluster粒度的server异常率的分布有两种情况:一是各个Cluster的server的异常率差不多,随机均匀分布,这是相对正常的情况,由于分布式系统是用大量商用的不非常可靠的软硬件使用冗余设计的方法给用户提供相对可靠的服务,软硬件的故障随机地分布到各个集群中,因此是相对正常的情况,如下面第一个图所示。二是有异常的server集中在极少数的几个cluster中,说明这几个cluster有一些系统性的故障,因此需要告警引起运维工程师的注意,如下面第二个图所示。
Cluster的server异常率均匀分散的情况——可接受的异常
Cluster的server异常率严重倾斜的情况——某些cluster有系统性的异常
我们可以使用下面的SQL语句实现更粗粒度的二次异常检测,实现告警洪流的抑制。
with anomaly_dist_pattern as ( select time_period, summarize( array_agg(array[anomaly_rate]) ) as anomaly_distribution_pattern -- 再次进行模式提取 from cluster_server_anomaly_table where time_period = '2024-01-08 00:00:00' -- 指定异常检测的时间点 group by time_period ) select csa.time_period, csa.cluster, anomaly_level( adp.anomaly_distribution_ pattern, array_agg(array[csa.anomaly_rate]) ) as anomaly_level, -- 对cluster的服务器异常率计算异常等级 csa.anomaly_rate from cluster_server_anomaly as csa join anomaly_dist_pattern as adp on csa.time_period = adp.time_period where csa.time_period = '2024-01-08 00:00:00' and anomaly_level( adp.anomaly_distribution_ pattern, array_agg(array[csa.anomaly_rate]) ) >= 3
负载均衡测量
负载均衡是在分布式计算机系统运维中一个非常常见的需求。如果分布式计算机系统的负载在内部分发处理不均衡,容易在系统的内部产生局部热点,即一部分计算服务器要处理大量的请求,非常繁忙,而另外很多计算服务器却又空闲着。热点的服务器需要更长的时间来处理用户请求,造成用户请求的服务质量下降。另外,空闲的计算服务器也是对计算资源的浪费。因此,分布式计算机系统通常需要不断地均衡分布式计算系统的各个服务器的负载。
要进行负载均衡操作之前,我们首先要能先测量出来系统的负载是否均衡。
负载均衡的测量考虑负载在时间和空间(服务器)之间的分布,比如下面图表展示的集群服务器的负载分布还是比较均衡的,各个服务器随着不同的时间一起变高变低。
分布式计算系统的负载在时间和空间(服务器)分布的范例
在计算负载均衡的时候,我们在每个时间点切一刀,得到一个切面,在这个切面上反映了负载在不同服务器上的分布,参考下面三种不同的切面。其中负载阴影部分的面积在由最大值确定的矩形框的面积的占比是这一时刻的均衡度。如果完全均衡,则面积占比是100%。如果非常不均衡,极少数的服务器承担了绝大部分的负载,则面积占比接近于0。把一个时间段内的每一个时刻的负载均衡度以负载的均值作为权重,进行加权平均,得到的是这一个时间段内的负载均衡度。
假设我们收集到了分布式计算系统的负载指标数据,结果如下表所示。表中包含了CPU、内存和网络带宽的负载,为了方便比较,这些负载都归一化到[0, 1]的区间。每个服务器1分钟一行负载数据。
分布式计算系统的负载指标数据范例——server_load
cluster_id |
server_id |
time_period |
cpu_load |
ram_load |
network_load |
C001 |
S001 |
2024-01-01 00:00 |
0.1 |
0.8 |
0.5 |
C001 |
S001 |
2024-01-01 01:00 |
0.2 |
0.7 |
0.4 |
... |
... |
... |
... |
... |
... |
C001 |
S002 |
2024-01-01 00:00 |
0.85 |
0.3 |
0.9 |
C001 |
S002 |
2024-01-01 01:00 |
0.7 |
0.4 |
0.8 |
... |
... |
... |
... |
... |
... |
负载均衡度的测量计算可以使用阿里云日志服务中how_balanced(...)函数帮忙计算。下面是参考的计算负载均衡度的SQL语句。
-- 把server_load中的每一个server_id的综合指标时间序列数据聚合称为时间数组和指标数组 with server_time_series as ( select cluster_id, server_id, array_agg(to_unixtime(date_parse(time_period, '%Y-%m-%d %H:%i'))) as time_periods, array_agg(cpu_load + ram_load + network_load) as metric_values from server_load where time_period >= '2024-01-01 00:00' and time_period < '2024-01-02 00:00' group by cluster_id, server_id ), -- 对每个cluster每个server的时间序列数据中的缺失的0数值的时间点分别填充回来 imputed_server_series as ( select cluster_id, server_id, ts_fill_missing( time_periods, metric_values, to_unixtime(date_parse('2024-01-01 00:00', '%Y-%m-%d %H:%i')), to_unixtime(date_parse('2024-01-02 00:00', '%Y-%m-%d %H:%i')), '1 minute', 'value=0') as imputed_time_series -- 该字段是由时间点数组和指标值的数组构成的一个二维数组 from server_time_series ) -- 给每个Cluster分别计算其负载均衡度 select cluster_id, how_balanced(array_agg(imputed_time_series[2])) as balance from imputed_server_series group by cluster_id
在上面的SQL语句计算负载均衡度的例子中的计算步骤为:
- 先把cpu_load、ram_load、network_load加起来形成一个综合的负载指数的指标。
- 然后用array_agg(...)聚合函数把每个cluster_id和每个server_id的一段时间的综合指标数据以及对应的时间点拼装成两个数组,来描述对应的时间序列。
- 为了节省存储空间,原始的时间序列可能只包含指标数值为非零的数据,我们用ts_fill_missing(...)的数据预处理函数把指标数值为0的数据的时间点补充完整。
- 使用array_agg(...)各自cluster_id的负载在时间和空间上分布的数据拼装成为一个二维数组,然后使用how_balanced(...)函数给每个cluster_id对应的负载时空分布的数据计算负载均衡度。
决策树自动分类分析
自动分类判别分析是一个非常常用的机器学习的方法。阿里云日志服务提供了使用决策树自动分类判别的功能。自动分类判别分析先对一批历史数据进行分析,分析各种类型的实例包含些什么独特的模式,下次给定模型一个新的实例的属性特征,模型根据之前的模式分析,自动地判断该实例属于哪一种分类。
例如,可以应用于识别判断信用卡用户的每笔消费是否为盗用的,可以用于自动识别判断用户的访问是否为恶意攻击的请求,可以用于判断每一次的统计意义上检测出来的异常是否为运维工程师真正关心的异常,可以用于根据病人的症状判断病人的病情等等。
阿里云日志服务提供了的决策树自动分类判别分析主要有两个过程:(1) 用历史数据训练决策树模型的过程,(2) 用训练好的决策树对给定的实例进行判别分类的过程。
我们用一个范例数据来介绍如何使用阿里云日志服务中的决策树进行自动判别分析。在使用阿里云日志服务提供了的决策树自动分类判别分析时,无需了解决策树建模的细节,只需要按照相应的格式要求组织数据并且把数据喂给相应的机器学习函数就可以了。
决策树模型训练
在介绍使用阿里云日志服务的决策树模型之前,我们先来介绍一下阿里云日志服务的决策树模型的数据要求和范例数据。决策树模型的训练要求把训练数据组织成为一个二维表格,参考下面的二维表格范例数据sleep_health_data_table。表格中的一行就是一个病人实例,每一列是病人的属性特征信息如性别、年龄、职业、平均睡眠时长等等。最后一列sleep_disorder是睡眠健康问题的诊断结果。这些数据都是对以往的病人的数据收集的结果,可以用来训练一个决策树模型,来自动地识别出病人的属性特征信息和睡眠健康问题之间的关联模式。
病人睡眠问题数据表:sleep_health_data_table
person_id | gender | age | occupation | sleep_duration | quality_of_sleep | physical_activity_level | stress_level | bmi_category | blood_pressure_systolic | blood_pressure_diastolic | heart_rate | daily_steps | sleep_disorder -----------+--------+------+----------------------+----------------+------------------+-------------------------+--------------+---------------+-------------------------+--------------------------+------------+-------------+---------------- 1 | Male | 27.0 | Software Engineer | 6.1 | 6.0 | 42.0 | 6.0 | Overweight | 126.0 | 83.0 | 77.0 | 4200.0 | None 2 | Male | 28.0 | Doctor | 6.2 | 6.0 | 60.0 | 8.0 | Normal | 125.0 | 80.0 | 75.0 | 10000.0 | None 3 | Male | 28.0 | Doctor | 6.2 | 6.0 | 60.0 | 8.0 | Normal | 125.0 | 80.0 | 75.0 | 10000.0 | None 4 | Male | 28.0 | Sales Representative | 5.9 | 4.0 | 30.0 | 8.0 | Obese | 140.0 | 90.0 | 85.0 | 3000.0 | Sleep Apnea 5 | Male | 28.0 | Sales Representative | 5.9 | 4.0 | 30.0 | 8.0 | Obese | 140.0 | 90.0 | 85.0 | 3000.0 | Sleep Apnea 6 | Male | 28.0 | Software Engineer | 5.9 | 4.0 | 30.0 | 8.0 | Obese | 140.0 | 90.0 | 85.0 | 3000.0 | Insomnia 7 | Male | 29.0 | Teacher | 6.3 | 6.0 | 40.0 | 7.0 | Obese | 140.0 | 90.0 | 82.0 | 3500.0 | Insomnia 8 | Male | 29.0 | Doctor | 7.8 | 7.0 | 75.0 | 6.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 9 | Male | 29.0 | Doctor | 7.8 | 7.0 | 75.0 | 6.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 10 | Male | 29.0 | Doctor | 7.8 | 7.0 | 75.0 | 6.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 11 | Male | 29.0 | Doctor | 6.1 | 6.0 | 30.0 | 8.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 12 | Male | 29.0 | Doctor | 7.8 | 7.0 | 75.0 | 6.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 13 | Male | 29.0 | Doctor | 6.1 | 6.0 | 30.0 | 8.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 14 | Male | 29.0 | Doctor | 6.0 | 6.0 | 30.0 | 8.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 15 | Male | 29.0 | Doctor | 6.0 | 6.0 | 30.0 | 8.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 16 | Male | 29.0 | Doctor | 6.0 | 6.0 | 30.0 | 8.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None 17 | Female | 29.0 | Nurse | 6.5 | 5.0 | 40.0 | 7.0 | Normal Weight | 132.0 | 87.0 | 80.0 | 4000.0 | Sleep Apnea 18 | Male | 29.0 | Doctor | 6.0 | 6.0 | 30.0 | 8.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | Sleep Apnea 19 | Female | 29.0 | Nurse | 6.5 | 5.0 | 40.0 | 7.0 | Normal Weight | 132.0 | 87.0 | 80.0 | 4000.0 | Insomnia 20 | Male | 30.0 | Doctor | 7.6 | 7.0 | 75.0 | 6.0 | Normal | 120.0 | 80.0 | 70.0 | 8000.0 | None :
参考上面的数据,各个字段的含义见下面的表格。其中最后一个字段sleep_disorder的内容有三类。我们的决策树模型例子中使用这个字段作为目标变量字段,是决策树模型的输出。例子中决策树模型的输入变量是病人的属性和特征数据列。
字段 |
描述 |
说明 |
person_id |
病人编码ID |
|
gender |
性别 |
|
age |
年龄 |
|
occupation |
职业 |
|
sleep_duration |
睡眠时长 |
|
quality_of_sleep |
睡眠质量 |
|
physical_activity_level |
运动量 |
|
stress_level |
压力等级 |
|
bmi_category |
身高体重类别 |
|
blood_pressure_systolic |
收缩血压 |
正常值为90mmHg-140mmHg |
blood_pressure_diastolic |
舒张血压 |
正常值为60mmHg-90mmHg |
heart_rate |
心率 |
正常值为60次/分-100次/分 |
daily_steps |
每日步数 |
|
sleep_disorder |
睡眠问题 |
None: 没有睡眠问题;Insomnia: 难入睡,中度睡眠问题;Sleep Apnea: 严重睡眠问题 |
有了可用于决策树模型训练的数据,可以使用阿里云日志服务的决策树模型训练函数decision_tree_classifier来获得模型。决策树模型训练函数decision_tree_classifier是一个聚合(Aggregation)函数,函数的参数名称、类型和解释如下:
decision_tree_classifier( target_variable varchar, -- 输出变量的值 input_variable_array array(varchar), -- 输入变量的值构成的数组 target_variable_name varchar, -- 输出变量的名字 input_variable_name_array array(varchar), -- 输入变量的名字构成的数组 input_variable_type_array array(varchar), -- 输入变量的类型构成的数组 <optional> model_options varchar -- 非必需的模型控制参数 )
然后,我们可以参考下面的SQL函数看怎么调用这个函数
select decision_tree_classifier( sleep_disorder, array[cast(person_id as varchar), cast(gender as varchar), cast(age as varchar), cast(occupation as varchar), cast(sleep_duration as varchar), cast(quality_of_sleep as varchar), cast(physical_activity_level as varchar), cast(stress_level as varchar), cast(bmi_category as varchar), cast(blood_pressure_systolic as varchar), cast(blood_pressure_diastolic as varchar), cast(heart_rate as varchar), cast(daily_steps as varchar)], 'sleep_disorder', array['person_id', 'gender', 'age', 'occupation', 'sleep_duration', 'quality_of_sleep', 'physical_activity_level', 'stress_level', 'bmi_category', 'blood_pressure_systolic', 'blood_pressure_diastolic', 'heart_rate', 'daily_steps'], array['ID_NUM', 'X_STR_CATEGORICAL', 'X_NUMERIC', 'X_STR_CATEGORICAL', 'X_NUMERIC', 'X_NUMERIC', 'X_NUMERIC', 'X_NUMERIC', 'X_STR_CATEGORICAL', 'X_NUMERIC', 'X_NUMERIC', 'X_NUMERIC', 'X_NUMERIC'] ) as sleep_health_model from sleep_health_data_table
SQL返回的结果如下所示。
sleep_health_model ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"returnCode":0,"message":"OK","decisionTreeEncode":"gANjc2tsZWFybi50cmVlLl9jbGFzc2VzCkRlY2lzaW9uVHJlZUNsYXNzaWZpZXIKcQApgXEBfXECKFgJAAAAY3JpdGVyaW9ucQNYBAAAAGdpbmlxBFgIAAAAc3BsaXR0ZXJxBVgEAAAAYmVzdHEGWAkAAABtYXhfZGVwdGhxB05YEQAAAG1pbl9zYW1wbGVzX3NwbGl0cQhLFFgQAAAAbWluX3NhbXBsZXNfbGVhZnEJSwpYGAAAAG1pbl93ZWlnaHRfZnJhY3Rpb25fbGVhZnEKRwAAAAAAAAAAWAwAAABtYXhfZmVhdHVyZXNxC05YDgAAAG1heF9sZWFmX25vZGVzcQxOWAwAAAByYW5kb21fc3RhdGVxDU5YFQAAAG1pbl9pbXB1cml0eV9kZWNyZWFzZXEORz+EeuFHrhR7WBIAAABtaW5faW1wdXJpdHlfc3BsaXRxD05YDAAAAGNsYXNzX3dlaWdodHEQWAgAAABiYWxhbmNlZHERWAkAAABjY3BfYWxwaGFxEkcAAAAAAAAAAFgOAAAAbl9mZWF0dXJlc19pbl9xE0sXWAsAAABuX2ZlYXR1cmVzX3EUSxdYCgAAAG5fb3V0cHV0c19xFUsBWAgAAABjbGFzc2VzX3EWY251bXB5LmNvcmUubXVsdGlhcnJheQpfcmVjb25zdHJ1Y3QKcRdjbnVtcHkKbmRhcnJheQpxGEsAhXEZQwFicRqHcRtScRwoSwFLA4VxHWNudW1weQpkdHlwZQpxHlgDAAAAVTExcR+JiIdxIFJxIShLA1gBAAAAPHEiTk5OSyxLBEsIdHEjYolDhEkAAABuAAAAcwAAAG8AAABtAAAAbgAAAGkAAABhAAAAAAAAAAAAAAAAAAAATgAAAG8AAABuAAAAZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABTAAAAbAAAAGUAAABlAAAAcAAAACAAAABBAAAAcAAAAG4AAABlAAAAYQAAAHEkdHElYlgKAAAAbl9jbGFzc2VzX3EmY251bXB5LmNvcmUubXVsdGlhcnJheQpzY2FsYXIKcSdoHlgCAAAAaThxKImIh3EpUnEqKEsDaCJOTk5K/////0r/////SwB0cStiQwgDAAAAAAAAAHEshnEtUnEuWA0AAABtYXhfZmVhdHVyZXNfcS9LF1gFAAAAdHJlZV9xMGNza2xlYXJuLnRyZWUuX3RyZWUKVHJlZQpxMUsXaBdoGEsAhXEyaBqHcTNScTQoSwFLAYVxNWgqiUMIAwAAAAAAAABxNnRxN2JLAYdxOFJxOX1xOihoB0sEWAoAAABub2RlX2NvdW50cTtLCVgFAAAAbm9kZXNxPGgXaBhLAIVxPWgah3E+UnE/KEsBSwmFcUBoHlgDAAAAVjU2cUGJiIdxQlJxQyhLA1gBAAAAfHFETihYCgAAAGxlZnRfY2hpbGRxRVgLAAAAcmlnaHRfY2hpbGRxRlgHAAAAZmVhdHVyZXFHWAkAAAB0aHJlc2hvbGRxSFgIAAAAaW1wdXJpdHlxSVgOAAAAbl9ub2RlX3NhbXBsZXNxSlgXAAAAd2VpZ2h0ZWRfbl9ub2RlX3NhbXBsZXNxS3RxTH1xTShoRWgeWAIAAABpOHFOiYiHcU9ScVAoSwNoIk5OTkr/////Sv////9LAHRxUWJLAIZxUmhGaFBLCIZxU2hHaFBLEIZxVGhIaB5YAgAAAGY4cVWJiIdxVlJxVyhLA2giTk5OSv////9K/////0sAdHFYYksYhnFZaEloV0sghnFaaEpoUEsohnFbaEtoV0swhnFcdUs4SwFLEHRxXWKJQvgBAAABAAAAAAAAAAgAAAAAAAAAFAAAAAAAAAAAAAAAAGBXQIxVVVVVVeU/7AIAAAAAAAAjAAAAAGCHQAIAAAAAAAAABwAAAAAAAAAQAAAAAAAAAAAAAAAAAOA/Os7p5i3y4j9qAgAAAAAAAFi6jsHEM4FAAwAAAAAAAAAEAAAAAAAAABMAAAAAAAAAAAAAAAAQYEDSdORBSg3bP+QAAAAAAAAAZbNva5f3ckD//////////////////////v////////8AAAAAAAAAwAAAAAAAAAAANgAAAAAAAADdq1evXr0+QAUAAAAAAAAABgAAAAAAAAAWAAAAAAAAAAAAAAAA4LVAtALg68NO0z+uAAAAAAAAALo4eoDBC3FA//////////////////////7/////////AAAAAAAAAMBsIUDNeQPfPywAAAAAAAAAzbIsy7KsUUD//////////////////////v////////8AAAAAAAAAwBCB6oIYErM/ggAAAAAAAAAXGF6bKUFpQP/////////////////////+/////////wAAAAAAAADAemDLWrmn0T+GAQAAAAAAAK+BWy/k325A//////////////////////7/////////AAAAAAAAAMCIcoA8/1e2P4IAAAAAAAAABRfF+eywaEBxXnRxX2JYBgAAAHZhbHVlc3FgaBdoGEsAhXFhaBqHcWJScWMoSwFLCUsBSwOHcWRoV4lD2LGqqqqqKm9AUaqqqqoqb0CYqqqqqipvQDcMwzAMw25A81YgXYF0bkDeFV7hFV5OQOG2bdu27WtAXnpm6ZmlQUAERmAERmBGQAAAAAAAAAAA3atXr169PkAAAAAAAAAAAOG2bdu27WtAdSPVjVQ3EkAERmAERmBGQEySJEmSJD1AAAAAAAAAAAByHMdxHMdEQJckSZIkSWhAdSPVjVQ3EkAqmZIpmZIJQKyqqqqqqjZAebjG4hoLakBzP/dzP/cvQHqe53me5wlAU2xKsSnFFkAsJVMyJZNnQHFldHFmYnViWBAAAABfc2tsZWFybl92ZXJzaW9ucWdYBgAAADAuMjQuMnFodWIu","decisionTreeInText":"|--- blood_pressure_diastolic \u003c\u003d 93.50\n| |--- bmi_category.Normal \u003c\u003d 0.50\n| | |--- blood_pressure_systolic \u003c\u003d 128.50\n| | | |--- class: None\n| | |--- blood_pressure_systolic \u003e 128.50\n| | | |--- daily_steps \u003c\u003d 5600.00\n| | | | |--- class: Sleep Apnea\n| | | |--- daily_steps \u003e 5600.00\n| | | | |--- class: Insomnia\n| |--- bmi_category.Normal \u003e 0.50\n| | |--- class: None\n|--- blood_pressure_diastolic \u003e 93.50\n| |--- class: Sleep Apnea\n","uniqueLabels":["Insomnia","None","Sleep Apnea"],"confusionMatrix":[[120,14,20],[8,420,10],[2,10,144]],"dataColumnNames":["person_id","gender","age","occupation","sleep_duration","quality_of_sleep","physical_activity_level","stress_level","bmi_category","blood_pressure_systolic","blood_pressure_diastolic","heart_rate","daily_steps","sleep_disorder"],"dataColumnTypes":{"occupation":"X_STR_CATEGORICAL","blood_pressure_diastolic":"X_NUMERIC","gender":"X_STR_CATEGORICAL","heart_rate":"X_NUMERIC","blood_pressure_systolic":"X_NUMERIC","stress_level":"X_NUMERIC","daily_steps":"X_NUMERIC","physical_activity_level":"X_NUMERIC","bmi_category":"X_STR_CATEGORICAL","sleep_duration":"X_NUMERIC","quality_of_sleep":"X_NUMERIC","sleep_disorder":"Y_STR_CATEGORICAL","age":"X_NUMERIC","person_id":"ID_NUM"},"categoricalVariableValues":{"bmi_category":["Normal","Normal Weight","Obese","Overweight"],"gender":["Female","Male"],"occupation":["Accountant","Doctor","Engineer","Lawyer","Manager","Nurse","Sales Representative","Salesperson","Scientist","Software Engineer","Teacher"]}} (1 row)
训练的决策树模型的结果以JSON的格式返回。如果仅仅是把训练的决策树模型用于对新病人数据的判别的话,则不需要关注决策树模型的JSON结果,只需要把这个结果交个另外一个决策树判别函数decision_tree_predict就可以了。如果对决策树模型本身或者输入和输出变量的关系感兴趣的话,可以看一下JSON数据里面的内容。其中的decisionTreeInText用文本的方式可视化了决策树模型。
把里面的内容打印出来,结果如下:
|--- blood_pressure_diastolic <= 93.50 | |--- bmi_category.Normal <= 0.50 | | |--- blood_pressure_systolic <= 128.50 | | | |--- class: None | | |--- blood_pressure_systolic > 128.50 | | | |--- heart_rate <= 73.00 | | | | |--- class: Insomnia | | | |--- heart_rate > 73.00 | | | | |--- class: Sleep Apnea | |--- bmi_category.Normal > 0.50 | | |--- class: None |--- blood_pressure_diastolic > 93.50 | |--- class: Sleep Apnea
从这颗决策树里第一层的判断我们可以看到,是否有高血压是影响睡眠问题的最重要的因素,在第一层的第二个分支里描述了,如果舒张血压的值超过93.5(正常值为60mmHg-90mmHg),基本上就比较难以入睡。这个例子的决策树的其他更详细的内容可以参考上面决策树的可视化的结果。
使用决策树模型进行判别分析
如果我们上面训练决策树模型的SQL结果保存在数据表sleep_health_model_01中,也可以放在带with语句的通用表表达式(Common Table Expression)中,我们可以把这个模型和新的输入数据结合起来,作为诊断模型,对病人的睡眠问题进行判别。
决策树判别预测标量函数的规格为:
decision_tree_predict( decision_tree_model_in_json varchar, -- 决策树模型的JSON描述,模型训练的结果 input_variable_array array(varchar) -- 新的输入变量数据 )
参考下面的SQL来使用决策树模型对新的输入数据进行判别分析。
select nid.person_id, decision_tree_predict( gm.sleep_health_model, array[cast(person_id as varchar), cast(gender as varchar), cast(age as varchar), cast(occupation as varchar), cast(sleep_duration as varchar), cast(quality_of_sleep as varchar), cast(physical_activity_level as varchar), cast(stress_level as varchar), cast(bmi_category as varchar), cast(blood_pressure_systolic as varchar), cast(blood_pressure_diastolic as varchar), cast(heart_rate as varchar), cast(daily_steps as varchar)]) as predicted_value from sleep_health_model_01 as gm cross join sleep_health_data_table as nid order by person_id
查询的结果类似下:
person_id | predicted_value -----------+----------------- 1 | None 2 | None 3 | None 4 | Sleep Apnea 5 | Sleep Apnea 6 | Sleep Apnea 7 | Sleep Apnea 8 | None ...
注:这个例子里只有一个分组,因此我们在把要预测病人实例表和模型表进行关联(join)的时候使用了Cross Join。一般情况下我们在用decision_tree_classifier函数来识别决策树模型的时候,会使用group by子句对每个分组进行个性化的决策树模型识别,在表关联的时候,用相应的字段进行关联。
自动回归和预测分析
回归模型和预测用途
回归和预测分析也是机器学习中常用的数据分析方法。和决策树自动分类模型类似,需要从一批历史数据中学习到输入变量组和输出变量之间的函数关系,然后应用学习到的函数关系对新的输入变量组的值预测,推断出输出变量的值。和决策树模型不一样的是,决策树模型的输出变量是离散型的,而回归和预测分析的变量是连续数字型的。
回归分析可以用来分析输出变量和输入变量组之间的函数关系。比如请求的延迟(输出变量)和请求的大小、请求的类型等(输入变量)有关系,我们可以用回归的方法识别出它们之间的函数关系。这样就可以用请求的大小、请求的类型等输入变量的值去推算请求的延迟的大小。如果收集到的请求的延迟的数值和推算出来的请求的延迟的数值相差很大,比如它们之间的差别超过了5倍的平均误差,则在统计意义上来说是很罕见的,可以合理地怀疑这一次请求是异常。所以也可以用来做异常检测分析。
回归分析也可以用来预测。例如,可以用来预测系统中对象的剩余寿命。一个大型的计算机系统中会使用到大量的硬件组件例如硬盘等。我们就以预测硬盘的剩余寿命作为例子,我们可以收集历史数据,对于每一个磁盘的每一天,收集磁盘的累积使用时间、累积写入数据量、累积读出数据量、最近一周内的写IO的平均延迟、最近一周内的读IO的平均延迟等等输入变量信息,直到磁盘的寿命结束为止。同时,然后对于寿命已经终止的磁盘,回头对磁盘之前收集到数据,根据数据收集的日期和磁盘寿命终止的日期的时间差,可以计算出磁盘的剩余寿命,把这个剩余寿命作为回归分析的输出变量,其中的磁盘状态变量如累积使用时间等等作为预测磁盘剩余寿命的输入变量。可以利用回归模型描述这些状态变量和磁盘寿命的函数关系。
磁盘寿命数据表——disk_life_data_table
disk_type |
disk_id |
date |
days_to_die |
living_days |
total_written_gb |
total_read_gb |
write_io_latency_us |
read_io_latency_us |
HDD-001 |
1 |
2018-01-01 |
1855 |
1 |
0.2 |
0.1 |
450 |
200 |
HDD-001 |
1 |
2018-01-02 |
1854 |
2 |
1.5 |
0.8 |
465 |
180 |
... |
... |
... |
... |
... |
... |
... |
... |
回归建模和预测函数使用范例
我们可以使用下面的SQL语句对每一个disk_type的磁盘的寿命和磁盘的状态变量之间建立回归模型。
select disk_type, linear_model( array_agg(array[ living_days, total_written_gb, total_read_gb, write_io_latency_us,read_io_latency_us]), -- 输入变量的值构成的二维数组 array_agg(days_to_die) -- 输出变量的值构成的一维数组 ) as disk_life_model from disk_life_data_table group by disk_type
从历史数据中训练好的回归模型以JSON的格式返回,SQL返回结果类似于下面的表格:
disk_type |
disk_life_model |
HDD-001 |
{"coefficients": ...} |
... |
... |
通过模型训练,可以把模型训练的结果保存到一个数据表中,比如disk_life_model_table,也可以是带with语句的通用表表达式(Common Table Expression)。然后我们就可以应用这个模型,对线上的磁盘的寿命进行预测了。使用阿里云日志服务的回归模型预测的方法如下面的SQL语句。
select ds.disk_type, ds.disk_id, linear_model_predict( dlm.disk_life_model, -- 之前训练的模型 array_agg(array[ living_days, total_written_gb, total_read_gb, write_io_latency_us,read_io_latency_us]) -- 线上磁盘的状态变量 from disk_state_data_table as ds join disk_life_model_table as dlm on ds.disk_type = dlm.disk_type
用户画像或者系统对象聚类分析
聚类分析用途简介
聚类分析可以帮助我们把系统中众多的对象根据他们的属性的相似度进行自动归类。原来的对象众多繁杂,聚类以后,会分成数量不多的分组,每个分组内的对象是比较相似的,不同组的对象差异比较大。因此,聚类分析能够帮助我们简化商业运作的策略。
聚类分析方法通常用于用户画像分析过程中。例如,在广告推广中,我们要面对众多的用户分发广告。
一种极端的方案是一刀切,印发一样的广告,发给所有的用户。这种一刀切的方案的好处是处理起来简单,缺点是每个用户对同一个广告阅读的体会不一样,有的容易被内容打动,有的对广告上面的内容不感兴趣,但是换一种广告表达方式,就有可能打动这个用户。
另外一种极端的方案是完全私人订制,每个人看到的广告都不一样,这样用户被广告打动的概率会最高,但缺点是运作复杂。
使用聚类分析把相似的用户画像分到一个组,对同一个组的用户分发同样的广告,不同组的用户分发的广告不一样,这是上面两种方案的折衷平衡的方案。这样,相对于私人订制方案,可以降低广告运作的成本,同时相对于一刀切的方案,也能提升广告的转化率。
聚类分析的示意图如下:
在系统中对象,有很多属性或者数量指标。通过对象的属性和指标的相似度自动进行聚类分组。
负载均衡例子
在分布式系统管理中,负载均衡是很常见的需求。现在分布式系统是用一系列商用廉价的服务器,水平连接而成的一个计算机系统。分布式系统收到的请求会分发给系统中不同服务器去响应请求。由于分布式系统中管理的对象非常多,数量基本上都是按亿计算,同一个用户的前后多次的请求可能也有状态关联,系统中的对象通常会被组织成为分区,系统会把一个分区中包含的对象统一交给一个服务器专门管理,简化元数据的管理。
在分布式系统中,最理想的就是负载能够均衡处理。如果负载不能均衡,某些服务器的负载非常高,产生局部热点,而另外一些服务器又很闲,这样在局部热点服务器中被服务的请求需要排队等候,这些用户请求的延迟会很高,体验会很差。另外一方面,其他的机器很闲,没事情做,导致服务器资源的浪费。
在分布式系统中,系统局部热点的现象非常常见,需要进行负载均衡,对系统内的分区在不同的服务器中进行迁移,从热的服务器迁移到冷的服务器。
由于分区迁移的操作需要切断该分区的流量,重新在其他服务器上加载,会对用户的请求造成短时间的不可用,所以分区的迁移在冷却的时候操作,对系统造成的负面影响最低。
分区的迁移,需要确定分区的去向服务器,迁往的服务器和迁离的服务器平时的负载应当比较不一样,才能起到负载均衡的作用。这时候,就可以用聚类分析,根据服务器的负载特征属性对服务器进行聚类。迁移的时候,迁移到不同类组的服务器中。
下面我们用具体数据和SQL来展示,展示的仅仅是负载均衡处理的原型和聚类函数用法。
数据范例
假设收集到的数据表如下。表中包含了CPU、内存和网络带宽的负载,为了方便比较,这些负载都归一化到[0, 1]的区间。每个服务器1分钟一行负载数据。
server_load
cluster_id |
server_id |
time_period |
cpu_load |
ram_load |
network_load |
C001 |
S001 |
2024-01-01 00:00 |
0.1 |
0.8 |
0.5 |
C001 |
S001 |
2024-01-01 01:00 |
0.2 |
0.7 |
0.4 |
... |
... |
... |
... |
... |
... |
C001 |
S002 |
2024-01-01 00:00 |
0.85 |
0.3 |
0.9 |
C001 |
S002 |
2024-01-01 01:00 |
0.7 |
0.4 |
0.8 |
... |
... |
... |
... |
... |
... |
聚类分析SQL数据处理和分析流程
具体的数据处理和分析流程参考下面的SQL代码。阅读的时候,请参考其中的注释。这个例子结合了我们提供的时序填充,向量拼接,聚类分析等函数,是一个综合的例子。
我们可以看到,很简短的SQL代码就可以帮助我们实现非常高级的分析功能。
-- 数据处理第一步,对每一个服务器的不同的负载的一天的数据填充成为一个时间序列 -- 负载数据可能只包含非0的负载,0负载需要填充回去 -- 同一种类型的负载会构成一个时间序列 with imputed_server_load as ( select cluster_id, server_id, ts_fill_missing(array_agg(to_unixtime(time_period)), array_agg(cpu_load), to_unixtime(timestamp '2024-01-01 00:00:00'), to_unixtime(timestamp '2024-01-02 00:00:00'), '1 minute', 'value=0' ) as cpu_load_vector, -- 生成CPU负载时间序列,是一个二维数组包含了时间点数组和指标值数组 ts_fill_missing(array_agg(to_unixtime(time_period)), array_agg(ram_load), to_unixtime(timestamp '2024-01-01 00:00:00'), to_unixtime(timestamp '2024-01-02 00:00:00'), '1 minute', 'value=0' ) as ram_load_vector, -- 生成RAM负载时间序列,是一个二维数组包含了时间点数组和指标值数组 ts_fill_missing(array_agg(to_unixtime(time_period)), array_agg(network_load), to_unixtime(timestamp '2024-01-01 00:00:00'), to_unixtime(timestamp '2024-01-02 00:00:00'), '1 minute', 'value=0' ) as network_load_vector -- 生成Network负载时间序列,是一个二维数组包含了时间点数组和指标值数组 from server_load where time_period >= '2024-01-01 00:00:00' and time_period < '2024-01-02 00:00:00' group by cluster_id, server_id ), -- 数据处理第二步 -- 把三种类型的负载拼接成为一个更长的向量 -- cpu_load_vector、ram_load_vector和network_load_vector中包含了两个向量 -- 第一个向量是时间序列的时刻,第二个是指标的数值,所以我们取第二个向量出来拼接 -- 这样每个服务器就有一个反映一天当中各个时刻的负载的特征向量了 concated_server_load as ( select cluster_id, server_id, vector_concat( vector_concat(cpu_load_vector[2], ram_load_vector[2]), network_load_vector[2] -- 下标2是把二维数组的第2个元素——指标值构成的数组提取出来 ) as server_load_vector -- 把三个时间序列拼接成为一个长向量 from imputed_server_load ), -- 数据处理第三步 -- 调用clustering_centroids函数,把一个集群内的服务器按照负载特征向量聚类成5类 -- 得到5个类心,数字5在这里只是示意作用,具体多少类,可以根据业务确定 server_centroids as ( select cluster_id clustering_centroids( array_agg(server_load_vector), 5 ) as cluster_centroids from concated_server_load group by cluster_id ) -- 数据处理第四步 -- 调用to_cluster_label根据各个服务器的负载特征向量和各个类心进行比较 -- 然后把该服务器归类 -- 这样在做分区迁移的时候,可以选择迁往不同聚类分组的服务器 select s.cluster_id, s.server_id, to_cluster_label( c.cluster_centroids, s.server_load_vector ) as server_cluster_label from concated_server_load as s join server_centroids as c on s.cluster_id = c.cluster_id
阿里云日志服务中的ScheduledSQL——让AI计算成为自动计算服务
之前介绍的阿里云日志服务的AI计算,是以SQL的形式介绍的。这仅仅是ad hoc的分析。我们可以结合阿里云日志服务中的ScheduledSQL的功能把AI计算形成定期计算的服务。要在阿里云日志服务生成持续执行的预测计算任务,在查询分析的界面上提供了一个 “定时保存分析结果”的按钮,点击这个按钮,参考下图,之后会弹出窗口,然后在这个窗口上配置这个定时执行的AI计算就可以了。
ScheduledSQL任务的配置很直观。ScheduledSQL计算任务会定时把预测计算的SQL所产生的计算结果写入到另外一个日志库,如果这个目标日志库还不存在,需要先创建。另外要配置的是调度时间间隔和SQL读取的数据窗口等。