uxmpp提供大型数据集的实时查询。例如,一个云服务提供商,帮助其他企业监控其HTTP流量。每当一个客户端收到HTTP请求时,云服务就会收到一条日志记录。您希望获取所有这些记录并创建HTTP分析仪表板,为您的客户提供洞察,例如其网站所服务的HTTP错误数量。重点是您希望此数据显示尽可能少的延迟,以便您的客户可以修复其网站的问题。
或者,也许您正在建立一个广告网络,并希望在其广告系列上向客户展示点击率。在此示例中,延迟也很关键,原始数据量也很高,历史数据和实时数据都很重要。
接下来澳门游戏平台注册网站构建一个类似的数据模型。澳门游戏平台注册网站将使用一个简单的模式来读取HTTP事件数据。
--在master节点上运行。 CREATE TABLE http_request ( site_id INT, ingest_time TIMESTAMPTZ DEFAULT now(), url TEXT, request_country TEXT, ip_address TEXT, status_code INT, response_time_msec INT ); SELECT create_distributed_table('http_request', 'site_id');
澳门游戏平台注册网站对http_request使用site_id列进行hash分配。这意味着特定站点的所有数据都将存在于同一个分片中。
这里分片计数使用的默认值。建议在实际群集中分片数设置为CPU核数的2-4倍。
--生成假数据。
在uxsql控制台后台执行下面的SQL语句,创建一个pluxsql函数insert_http_request。该函数向表http_request插入一条数据,并随机休眠一段时间。
CREATE OR REPLACE FUNCTION insert_http_request() RETURNS VOID AS $$ BEGIN INSERT INTO http_request ( site_id, ingest_time, url, request_country, ip_address, status_code, response_time_msec ) VALUES ( trunc(random()*32), clock_timestamp(), concat('http://example.com/', md5(random()::text)), ('{China,India,USA,Indonesia}'::text[])[ceil(random()*4)], concat( trunc(random()*250 + 2), '.', trunc(random()*250 + 2), '.', trunc(random()*250 + 2), '.', trunc(random()*250 + 2) )::inet, ('{200,404}'::int[])[ceil(random()*2)], 5+trunc(random()*150) ); PERFORM ux_sleep(random() * 0.25); END; $$LANGUAGE pluxsql;
新建一个SHELL脚本generate.sh,作用是循环不断地向表http_request插入数据。
#!/bin/bash while [ 1 ] do ./uxsql -c "SELECT insert_http_request()" done
执行SHELL脚本,生成实时数据。(如需停止生成数据,使用CTRL+Z中断脚本执行)
bash generate.sh
生成数据后,澳门游戏平台注册网站进行一个简单的查询。
SELECT site_id, date_trunc('minute', ingest_time) as minute, COUNT(1) AS request_count, SUM(CASE WHEN (status_code between 200 and 299) THEN 1 ELSE 0 END) as success_count, SUM(CASE WHEN (status_code between 200 and 299) THEN 0 ELSE 1 END) as error_count, SUM(response_time_msec) / COUNT(1) AS average_response_time_msec FROM http_request WHERE date_trunc('minute', ingest_time) > now() - '5 minutes'::interval GROUP BY site_id, minute ORDER BY minute ASC;
上述设置可以有效运行,但是有两个缺点:
每次都必须遍历每一行。例如,如果您的客户对过去一年的趋势感兴趣,那么您的查询将从头开始汇总过去一年的每一行。
存储成本将与数据摄取率和可查询历史记录的长度成比例增长。实际中,澳门游戏平台注册网站可能希望将原始事件保留较短的时间段(一个月),并查看较长时间段(年)的历史图表。
澳门游戏平台注册网站可以通过将原始数据汇总到预先聚合的表中来克服这两个缺点。在这里,澳门游戏平台注册网站将原始数据聚合到一个表单中,该表存储1分钟间隔的摘要。在生产系统中,您可能还需要1小时和1天的间隔,这些间隔对应相应的缩放级别即可。当用户想要上个月的请求时间时,可以简单地读取并绘制过去30天中每一天的值。
CREATE TABLE http_request_1min ( site_id INT, ingest_time TIMESTAMPTZ, --每分钟 error_count INT, success_count INT, request_count INT, average_response_time_msec INT, CHECK (request_count = error_count + success_count), CHECK (ingest_time = date_trunc('minute', ingest_time)) ); SELECT create_distributed_table('http_request_1min', 'site_id'); CREATE INDEX http_request_1min_idx ON http_request_1min (site_id, ingest_time);
在这里,通过site_id来进行分布,并且分片数数和复制因子和http_request相同。因为这三个都是匹配的,所以分http_request片和分http_request_1min片之间存在一对一的对应关系,这形成了共址表,使连接等查询更快。
为了填充表http_request_1min澳门游戏平台注册网站将定期运行INSERT INTO SELECT。可以借助下面的存储过程,可以将其设置为定时任务,定时执行SELECT rollup_http_request();。
CREATE OR REPLACE FUNCTION rollup_http_request() RETURNS void AS $$ BEGIN INSERT INTO http_request_1min ( site_id, ingest_time, request_count, success_count, error_count, average_response_time_msec ) SELECT site_id, minute, COUNT(1) as request_count, SUM(CASE WHEN (status_code between 200 and 299) THEN 1 ELSE 0 END) as success_count, SUM(CASE WHEN (status_code between 200 and 299) THEN 0 ELSE 1 END) as error_count, SUM(response_time_msec) / COUNT(1) AS average_response_time_msec FROM ( SELECT *, date_trunc('minute', ingest_time) AS minute FROM http_request ) AS h WHERE minute > ( SELECT COALESCE(max(ingest_time), timestamp '1901-10-10') FROM http_request_1min WHERE http_request_1min.site_id = h.site_id ) AND minute <= date_trunc('minute', now()) GROUP BY site_id, minute ORDER BY minute ASC; END; $$ LANGUAGE pluxsql;
再对其进行查询:
SELECT site_id, ingest_time as minute, request_count, success_count, error_count, average_response_time_msec FROM http_request_1min WHERE ingest_time > date_trunc('minute', now()) - '5 minutes'::interval;
汇总使查询更快,但澳门游戏平台注册网站仍需要使旧数据过期以避免无限制的存储成本。只需确定您希望为每个粒度保留数据的时间长度,并使用标准查询来删除过期数据。例如,澳门游戏平台注册网站决定将原始数据保留一天,每分钟保留一个月的聚合:
DELETE FROM http_request WHERE ingest_time < now() - interval '1 day'; DELETE FROM http_request_1min WHERE ingest_time < now() - interval '1 month';
可以将这些查询包装在一个函数中,并在cron作业中每分钟调用一次。