应用性能管理场景下自动探查风险
本步骤在ECI控制台和Lindorm控制台操作。Intel Chronos环境以及Jupyter Notebook已经制成了镜像,您可以购买弹性容器实例ECI和云数据库Lindorm版,快速搭建本案例所需环境。
- 开通弹性容器实例ECI。
1)登录ECI控制台,购买ECI实例。
说明:
- 地域:华东1(杭州)
- CPU:2 vCPU及以上。
- 内存:4 GiB及以上。
- 镜像:registry-vpc.cn-hangzhou.aliyuncs.com/lindorm-paas/lindormchronos,镜像版本选择v1。
- 弹性公网IP:您需要自动创建或使用已有的弹性公网IP。
2)ECI实例创建成功后,单击安全组ID,设置安全组规则,手动设置公网12345端口的访问。
- 开通云原生多模数据库Lindorm。
说明:本案例以体验为主,开通的为单节点Lindorm数据库。真实业务场景中,请根据业务情况,购买集群版Lindorm数据库,选择TSDB时序引擎。
1)登录Lindorm控制台,在实例列表页,单击创建,购买Lindorm实例。
说明:
- 选择 “Lindorm单节点(按量付费)”。
- Lindorm数据库的地域,需与ECI实例保持一致,均为华东1 可用区F。
2)配置白名单:进入Lindorm实例的访问控制页面,将ECI绑定的公网IP添加入Lindorm的白名单中。
说明:您可在ECI弹性容器实例列表页,查看ECI公网地址。
3)开通公网访问:进入Lindorm实例的数据库连接页面,选择时序引擎,单击开通外网地址。
- 登录Jupyter Notebook:浏览器中输入http://{ECI公网地址}:12345/?token=1234qwer。
说明:
- 您可在ECI弹性容器实例列表页,查看ECI公网地址。
- 本案例为您提供2份Notebook文件。
- 打开Notebook文件apm-predict-notebook(imcomplete).ipynb:请参照本案例步骤二至步骤六,您可在本notebook文件中,手动进行体验操作。
- 打开Notebook文件apm-predict-notebook.ipynb:已为您模拟所有步骤(步骤二至步骤六),您只需将真实的Lindorm时序引擎公网地址填入导入数据步骤中的代码url='http://{Lindorm时序引擎公网地址}/api/v2/sql'中即可。单击Run All,可自动化运行该场景。运行该场景需要一定的时间,请耐心等待,直到输出the predicted values and actual values(for the test data)图表。
本操作在Jupyter Notebook文件apm-predict-notebook(imcomplete).ipynb中进行;若您选择Notebook文件apm-predict-notebook.ipynb,仅修改Lindorm时序引擎公网地址后,便可自动化运行该步骤。
- 运行以下命令,向Lindorm TSDB写入模拟数据。
说明:
- 您可通过Lindorm控制台,单击实例后,在数据库连接-时序引擎页面,查看公网信息。
- 公网信息写入url='http://{Lindorm时序引擎公网地址}/api/v2/sql'中。
import csv import requests import time def datetime2timestampMillis(datetime): timeArray = time.strptime(datetime, '%Y-%m-%d %H:%M:%S') ts = int(time.mktime(timeArray)) * 1000 return str(ts) # url='http://{Lindorm时序引擎公网地址}/api/v2/sql' url = 'http://ld-nf4m02l455ql1aql3-public-standalone.lindorm.rds.aliyuncs.com:8242/api/v2/sql' query = {'database': 'default'} # 首先通过CREATE TABLE语法创建一张名为Apdex_253的数据表 ddl = 'CREATE TABLE Apdex_253 (app_id VARCHAR TAG, region VARCHAR TAG, time BIGINT, Apdex DOUBLE, Availability DOUBLE, Memory_used DOUBLE, Health DOUBLE, PhysicalPercent DOUBLE, HeapPercent DOUBLE, ThroughPut DOUBLE, DiskFree DOUBLE, OnlineUserNum_total DOUBLE, ART_http DOUBLE, CPU_used DOUBLE, SwapPercent DOUBLE, ActiveThreadsNum DOUBLE, Http_error DOUBLE, ART_sql DOUBLE)' response = requests.post(url, params = query, data = ddl) print('返回码:' + str(response.status_code) + ' 返回文本:' + response.text) if response.status_code == 200: print('创建数据表Apdex_253成功') else: print('数据表Apdex_253已存在') with open('Apdex_253.csv') as file: reader = csv.reader(file) header = next(reader) dml_prefix = 'INSERT INTO Apdex_253 (app_id, region, time, Apdex, Availability, Memory_used, Health, PhysicalPercent, HeapPercent, ThroughPut, DiskFree, OnlineUserNum_total, ART_http, CPU_used, SwapPercent, ActiveThreadsNum, Http_error, ART_sql) values ' dml = dml_prefix i = 0 for row in reader: dml = dml + '('app1','cn-shanghai',' + datetime2timestampMillis(row[15]) + ',' + row[0] + ',' + format(float(row[1]), '.4f') + ',' + format(float(row[2]), '.4f') + ',' + row[3] + ',' + row[4] + ',' + row[5] + ',' + row[6] + ',' + row[7] + ',' + row[8] + ',' + row[9] + ',' + format(float(row[10]), '.4f') + ',' + row[11] + ',' + row[12] + ',' + row[13] + ',' + row[14] + ')' i = i + 1 if i < 100: dml = dml + ',' else: response = requests.post(url, params = query, data = dml) print('返回码:' + str(response.status_code) + ' 返回文本:' + response.text) if response.status_code == 200: print('写入100条数据成功') else: # 由于单机版Lindorm存在写入QPS限制,若写入失败,尝试重新写入 for retries in range(3): print('写入失败,10秒后尝试重新写入,重试次数:' + str(retries)) time.sleep(10) response = requests.post(url, params = query, data = dml) print('返回码:' + str(response.status_code) + ' 返回文本:' + response.text) if response.status_code == 200: print('重试写入成功') break i = 0 dml = dml_prefix time.sleep(10) response = requests.post(url, params = query, data = dml[:-1]) print('返回码:' + str(response.status_code) + ' 返回文本:' + response.text) print('数据已导入至Lindorm TSDB')
- 运行以下命令,从Lindorm TSDB读取模拟数据至Dataframe中。
import pandas as pd import json select = 'SELECT * FROM Apdex_253 WHERE app_id = 'app1' AND time >= 1518297531000 AND time <= 1518298310000' response = requests.post(url, params = query, data = select) data_json = json.loads(str(response.content, 'utf-8')) rows = data_json['rows'] columns=['timestamp', 'Apdex', 'Availability', 'Memory_used', 'Health', 'PhysicalPercent', 'HeapPercent', 'ThroughPut', 'DiskFree', 'OnlineUserNum_total', 'ART_http', 'CPU_used', 'SwapPercent', 'ActiveThreadsNum', 'Http_error', 'ART_sql'] df = pd.DataFrame(columns = columns) for row in rows: row_dict = { 'timestamp': [row[2]], 'Apdex': [row[3]], 'Availability': [row[4]], 'Memory_used': [row[5]], 'Health': [row[6]], 'PhysicalPercent': [row[7]], 'HeapPercent': [row[8]], 'ThroughPut': [row[9]], 'DiskFree': [row[10]], 'OnlineUserNum_total': [row[11]], 'ART_http': [row[12]], 'CPU_used': [row[13]], 'SwapPercent': [row[14]], 'ActiveThreadsNum': [row[15]], 'Http_error': [row[16]], 'ART_sql': [row[17]] } df = df.append(pd.DataFrame(row_dict), ignore_index=True) df
执行结果如下:
timestamp Apdex Availability Memory_used Health PhysicalPercent HeapPercent ThroughPut DiskFree OnlineUserNum_total ART_http CPU_used SwapPercent ActiveThreadsNum Http_error ART_sql 0 1518268731000 0.95 1.0 305.3653 0.75 0 0.34 4 1.150000e+10 15 20001 0.0 0 17 107 0 1 1518268732000 0.95 1.0 347.3177 0.90 0 0.11 3 1.150000e+10 14 20001 0.0 0 15 107 0 2 1518268733000 0.95 1.0 120.8081 0.87 0 0.15 4 1.150000e+10 14 20001 0.0 0 16 107 0 3 1518268734000 0.95 1.0 162.8656 0.84 0 0.19 4 1.150000e+10 14 20001 0.0 0 16 107 0 4 1518268735000 0.95 1.0 218.7050 0.79 0 0.26 2 1.150000e+10 14 20001 0.0 0 15 107 0 ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... 775 1518269506000 0.91 1.0 300.0148 0.76 0 0.31 5 1.150000e+10 6 20001 0.0 0 16 0 0 776 1518269507000 0.91 1.0 323.5476 0.75 0 0.33 6 1.150000e+10 6 20001 0.0 0 17 0 0 777 1518269508000 0.91 1.0 76.9357 0.93 0 0.08 6 1.150000e+10 6 20001 0.0 0 16 0 0 778 1518269509000 0.91 1.0 102.1893 0.90 0 0.11 3 1.150000e+10 6 20001 0.0 0 15 0 0 779 1518269510000 0.91 1.0 129.3080 0.88 0 0.14 0 1.150000e+10 6 20001 0.0 0 15 0 0 780 rows × 16 columns
本操作在Jupyter Notebook文件apm-predict-notebook(imcomplete).ipynb中进行。通过预处理,将一些噪声信息进行剔除。若您选择Notebook文件apm-predict-notebook.ipynb,则自动化运行该步骤。
- 运行以下代码,将时间戳转化为时间变量,并去除一直为定值的特征:PhysicalPercent,SwapPercent, ART_sql。
df['datetime'] = pd.to_datetime(df.timestamp, unit='ms') df.drop(['PhysicalPercent', 'SwapPercent', 'ART_sql', 'timestamp'], axis=1, inplace=True) df
执行结果如下:
Apdex Availability Memory_used Health HeapPercent ThroughPut DiskFree OnlineUserNum_total ART_http CPU_used ActiveThreadsNum Http_error datetime 0 0.95 1.0 305.3653 0.75 0.34 4 1.150000e+10 15 20001 0.0 17 107 2018-02-10 13:18:51 1 0.95 1.0 347.3177 0.90 0.11 3 1.150000e+10 14 20001 0.0 15 107 2018-02-10 13:18:52 2 0.95 1.0 120.8081 0.87 0.15 4 1.150000e+10 14 20001 0.0 16 107 2018-02-10 13:18:53 3 0.95 1.0 162.8656 0.84 0.19 4 1.150000e+10 14 20001 0.0 16 107 2018-02-10 13:18:54 4 0.95 1.0 218.7050 0.79 0.26 2 1.150000e+10 14 20001 0.0 15 107 2018-02-10 13:18:55 ... ... ... ... ... ... ... ... ... ... ... ... ... ... 775 0.91 1.0 300.0148 0.76 0.31 5 1.150000e+10 6 20001 0.0 16 0 2018-02-10 13:31:46 776 0.91 1.0 323.5476 0.75 0.33 6 1.150000e+10 6 20001 0.0 17 0 2018-02-10 13:31:47 777 0.91 1.0 76.9357 0.93 0.08 6 1.150000e+10 6 20001 0.0 16 0 2018-02-10 13:31:48 778 0.91 1.0 102.1893 0.90 0.11 3 1.150000e+10 6 20001 0.0 15 0 2018-02-10 13:31:49 779 0.91 1.0 129.3080 0.88 0.14 0 1.150000e+10 6 20001 0.0 15 0 2018-02-10 13:31:50 780 rows × 13 columns
- 运行以下代码,绘制ART_HTTP变量随时间变化的趋势图。
ax = df.plot(y='ART_http', figsize=(16,6), title='ART_http throughout time')
执行结果如下:
本操作在Jupyter Notebook文件apm-predict-notebook(imcomplete).ipynb中进行,开启Auto TS训练器,配置相关参数,为后续的时间序列预测作准备。若您选择Notebook文件apm-predict-notebook.ipynb,则自动化运行该步骤。
- 执行以下命令,初始化Intel Chronos的RayOnSpark对话,为应用分配核心数量与内存。
说明:本案例为2核3G。
# init RayOnSpark in local mode from zoo import init_spark_on_local from zoo.ray import RayContext sc = init_spark_on_local(cores=2, spark_log_level='INFO') ray_ctx = RayContext(sc=sc, object_store_memory='3g') ray_ctx.init()
打印信息显示如下时,表明RayOnSpark对话初始化成功。
{'node_ip_address': '192.168.1.246', 'raylet_ip_address': '192.168.1.246', 'redis_address': '192.168.1.246:62111', 'object_store_address': '/tmp/ray/session_2021-06-09_11-48-50_555076_7849/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2021-06-09_11-48-50_555076_7849/sockets/raylet', 'webui_url': '192.168.1.246:8266', 'session_dir': '/tmp/ray/session_2021-06-09_11-48-50_555076_7849', 'metrics_export_port': 60115, 'node_id': 'ce77953bf94f2e6d8e9a4e8d792743eb3b8af3673e15993521913476'}
- 运行以下代码,配置AutoTS训练器。
说明:
- dt_col:时间的表头,本案例中指'datetime'。
- target_col:预测目标的表头,本案例中指'ART_http'。
- extra_feature_col:所有可用的额外特征,本案例将所有其他特征以列表形式输入。
- horizon:预测的步数,本案例中为5。
- name:项目名称。
extra_feature_col = list(df.columns) extra_feature_col.remove('ART_http') extra_feature_col.remove('datetime')
from zoo.chronos.autots.forecast import AutoTSTrainer trainer = AutoTSTrainer(dt_col='datetime', target_col='ART_http', horizon=5, extra_features_col=extra_feature_col, name='Ali-POC-AutoTS-HTTP-3')
- 运行以下代码,对训练和测试集进行划分,设置lookback值,为训练任务提供超参数搜索。
说明:本案例中,lookback值区间为10-12。
look_back = (10,12)
from zoo.chronos.preprocessing.utils import train_val_test_split train_df, val_df, test_df = train_val_test_split(df, val_ratio=0, test_ratio=0.3, look_back=look_back[0])
- 运行以下代码,使用一个内置的搜索空间LSTMGridRandomRecipe,为训练任务进行最佳模型和最佳参数的搜索。
from zoo.chronos.config.recipe import LSTMGridRandomRecipe
%%time ts_pipeline = trainer.fit(train_df, train_df, recipe=LSTMGridRandomRecipe( num_rand_samples=2, epochs=1, look_back=look_back, training_iteration=50), metric='mse')
本操作在Jupyter Notebook文件apm-predict-notebook(imcomplete).ipynb中进行。若您选择Notebook文件apm-predict-notebook.ipynb,则自动化运行该步骤。
运行以下代码,预测时间序列。
pred_df = ts_pipeline.predict(test_df)
rmse, smape = ts_pipeline.evaluate(test_df, metrics=['rmse', 'smape'], multioutput='uniform_average') print('Evaluate: the root mean square error is', rmse) print('Evaluate: the smape value is', smape)
本操作在Jupyter Notebook文件apm-predict-notebook(imcomplete).ipynb中进行。若您选择Notebook文件apm-predict-notebook.ipynb,则自动化运行该步骤。
自定义以下绘图函数,绘制时间序列预测结果。
import os import numpy as np import pandas as pd import matplotlib.pyplot as plt from zoo.automl.common.metrics import RMSE, MSE, sMAPE %matplotlib inline
# plot the predicted values and actual values (for the test data) def plot_result(test_df, pred_df, dt_col='datetime', value_col='ART_http_0', look_back=5): pred_value = pred_df[value_col].values true_value = test_df['ART_http'].values[look_back:] fig, axs = plt.subplots(figsize=(16, 6)) axs.plot(pred_df[dt_col], pred_value, color='red', label='predicted values') axs.plot(test_df[dt_col][look_back:], true_value, color='blue', label='actual values') axs.set_title('the predicted values and actual values (for the test data)') plt.xlabel(dt_col) plt.xticks(rotation=45) plt.ylabel(value_col) plt.legend(loc='upper left') plt.show()
plot_result(test_df, pred_df, dt_col='datetime', look_back=ts_pipeline.internal.config['past_seq_len'])
预测结果如下:
说明:本案例中您将预测到:变量ART_http(http请求响应时长)在观测点之后5秒的数据。
实验地址:https://developer.aliyun.com/adc/scenario/ef37743d41794bc295abaf627725e5e3