共计 3994 个字符,预计需要花费 10 分钟才能阅读完成。
问题背景
发电设备中经常会搁置传感器(DCS)来采集数据以监控设施运行的情况,某团体设计的电力监控统计零碎,须要实时采集传感器的数据后保留,而后提供按时段的实时查问统计性能。
零碎设计规模将反对 20 万个传感器(以下称为测点),采集频率为每秒一个数据,即每秒总共会有 20 万条数据,总时间跨度在 1 年以上。在这个根底上实现任意指定时段的多个测点数据统计,包含最大、最小、均匀、方差、中位数等。
零碎原结构图为:
零碎中,用户冀望的统计响应提早为:从 20 万个测点中任取 100 个测点,统计频率最高可能每隔若干秒调用一次,从总时间跨度中统计任意一天的数据,预期执行工夫在 1 分钟内,另外还会有少许离线工作,最长的时间段跨度长达一年。
现有的数据中台中没有计算能力,仅存储数据,计算时须要通过 RESTful 接口取出数据再统计。经测试,通过 RESTful 接口从数据中台取数,取出 100 个测点一天的数据量就须要 10 分钟工夫,还没有开始计算,取数的工夫曾经远远超出了实现计算的预期工夫。
基于现有构造,实现上述统计工作,性能上无奈达到预期要求,须要将数据从新存储。
解决办法
第一步,梳理数据和计算要求
数据结构如下:
| 字段名 | 类型 | 中文名 |
| — | —| —|
| TagFullName | 字符串 | 测点名 |
| Time | 长整型 | 工夫戳 |
| Type | 数值 | 数据类型 |
| Qualitie | 数值 | 品质码 |
| Value | 浮点数 | 数值 |
计算要求为:在每秒生成 20 万条记录的时序数据中,任意时间段内,从 20 万个测点中任取 100 个测点的数据,别离基于每个测点的数值序列统计最大、最小、方差、中位数等后果。
第二步,确定存储和计算计划
20 万测点一天的数据,仅 Value 字段,就要 200000*86400* 4 字节,至多 64g 内存,当总时间跨度为 1 年时,数据量会有数十 T,单台服务器内存显然装不下。多台服务器集群,又会带来很高的治理和洽购老本。
简略按工夫为序存储的数据,能够迅速找到相应工夫区间,但即便是这样,单个测点一天也有 86400 条记录,20 万个测点共 17.28 亿条,每次统计都要遍历这个规模的数据,也很难满足性能要求。
那么测点号上建设索引是否可行?
索引只能疾速定位数据,但这些数据如果在外存中不是间断存储的,硬盘有最小读取单位,会导致大量无用数据量读出,使得计算变得很慢,同样也无奈满足性能要求。此外,索引占用空间会随着数据量增大而增大,并且插入数据的保护开销也更大。
如果数据能够按测点号物理有序存储,并在测点号上建设索引,相比时序物理有序存储,查找时,待查找的测点记录变得紧凑了,须要读入的块也就少了。100 个测点的数据存成文本约 300m 不到,这样即便应用外存也能够满足性能要求。
只有历史冷数据时,解决起来比较简单,定时将数据按指定字段排序即可。但实际上,每秒都会有 20 万个测点的新数据,因为历史数据规模微小,如果每次获取几秒热数据都与历史数据整体按测点号、工夫排序,即便不算排序,仅是重写一遍的工夫老本上都无奈承受。
这时,须要将冷热数据辨别看待。不再变动的冷数据能够按测点秩序筹备好。这里有一点变通,因为要将十分晚期的数据删除(比方一年前的),如果所有冷数据都按测点排序时,会导致数据保护比拟麻烦,删除晚期数据会导致重写一遍所有数据。因而,能够设计为先按工夫分段,每段时间内的数据按测点、工夫有序,整体数据还是按工夫有序。工作需要是按天计算,这里按天分段就比拟适合,更长跨度的离线计算性能损失也不是很大。每当一天过来时,将昨天数据按上述规定排序后存储,当天的数据作为热数据处理。然而,当天内的数据量还是太大了,仍然无奈全副装入内存,还须要再分。
通过一些测试后确认,咱们发现将数据按热度分为三层能够满足要求。第一层,十分钟内的热数据通过接口读入内存;第二层,每过 10 分钟,将过来 10 分钟的内存数据按测点、工夫有序保留到外存;第三层,每过一天,将过来 24 小时内的所有每 10 分钟的数据按测点、工夫有序归并。总数据为:一年的数据由 365 段每天数据,加 144 段当天数据和一段内存数据。
分层后的冷热数据属于不同的数据源,须要独立计算同源数据的后果后,再将后果合并起来,算出最终的统计后果。即便计算方差、中位数这种须要全内存统计的状况,100 个测点一天的数据量,也只须要 64m 内存。
第三步,确定技术选型和计划
从上述的存储计划中得悉,须要将实时数据按工夫分段,段内按测点号、工夫物理有序存储,惯例数据库显然没方法做到这点。此外,拆分数据须要能够反对按自定义时间段灵便地拆分;数据存储时要具备高性能索引;冷热数据属于不同层(不在同一个数据源),计算时须要别离计算后再合并。
实现该工作,用 Java 硬编码工作量微小,Spark 写起来也很麻烦。开源的集算器 SPL 语言提供上述所有的算法反对,包含高性能文件、物理有序存储、文件索引等机制,可能让咱们用较少的代码量疾速实现这种个性化的计算。
取数不能再用原零碎的 RESTful 接口,也不适合间接通过 API 从 DCS 获取数据。用户方约定后引入 kafka 缓冲数据,屏蔽 DCS 层,同时还能够将 DCS 的数据提供给不同的消费者应用。变更后的零碎结构图如下:
阐明:
- DCS 零碎每秒推送 20 万个测点数据至 Kafka MQ。
- Kafka MQ 到 SPL:应用 SPL 基于 Kafka API 封装的 Kafka 函数,连贯 Kafka、生产数据。
- 内存缓冲:循环从 Kafka 生产数据(kafka_poll),每轮循环确保 10 秒以上的数据量,将每轮前 10 秒的数据补全后,按测点、工夫序,保留成文件并读入内存。
- 分层数据文件:按不同时间段将冷热数据文件分层。
- 统计时将冷热数据混合计算。
- 反对每个测点名对应一个 CSV 文件作为数据源计算。
- 统计接口以 HTTP 服务形式供内部利用调用并将统计后果通过回调接口返回给内部利用。
第四步,施行优化计划
现有的 RESTful 接口取数太慢了,接口变为从 kafka 生产数据。存储数据时,将字符串类型的测点名数字化后保留,以取得更小的存储量和更好的运算性能。
在第二步中曾经提到,数据量较大时,无奈将数据都放在内存中计算,所以思考采纳冷热分层计划,将数据分为三层,每天的冷数据按测点号、工夫有序(下文中的所有外存文件存储均采纳该序,不再反复阐明),用组表存储,因为大表对性能的影响很大,存储成组表有利于晋升零碎整体性能;当天的每 10 分钟的冷数据用,集文件存,因为集文件创建和应用都更简略,用来存储小表会很便捷,也不会因为索引块而升高存储效率;10 分钟内的热数据从 kafka 间接读到内存,因为数据自身是通过 kafka 接口获取的,另外数据可能有肯定的提早,不适宜每秒取数即写出。
测试后发现,10 分钟内的热数据,从 kafka 获取后再解析 json,岂但须要耗费大量内存,而且解析 json 也须要破费很长的工夫。这样在内存中间接加载热数据是没方法用来统计计算的,所以将热数据改为每 10 秒存成一个集文件。
接下来开始实现统计计算局部。每天组表中的冷数据计算较快,然而当天的 144 个集文件计算很慢。通过计算能够晓得,每 10 分钟的数据量约 1.2 亿条记录,这个规模的数据能够用组表来存储,另外还能够再加一层每 2 小时一个组表文件,来缩小当天总文件数的数量(从 144 个变成了 24 个)。实际上,计算时采纳的二分查找是对单个文件内有序的测点号应用的,缩小了文件个数,也就是缩小了总查找次数。
最终,咱们把数据分成了 4 层。第一层:提早 10 秒的集文件热数据;第二层,每 10 分钟的组表冷数据;第三层,每 2 小时的组表冷数据;第四层,每天的组表冷数据。因为每层数据都按测点号、工夫有序,所以每一层都能够用归并,疾速生成下一层数据文件。
这时的冷数据计算曾经很快了,能够满足理论应用,然而热数据的计算相比冷数据还是很慢。察看发现,热数据的所有集文件都加起来大概 3G,不算很大,内存能够装下。理论测试,把文件读到内存中再查找相比间接外存文件查找能够快出好几倍。
已知的统计计算,分为最大值、最小值、中位数、方差、平均值等,不尽相同,然而之前的数据查找是一样的。都用二分法,找出对应测点号组的数据,再用工夫过滤,即可失去相应的 value 值。
实测成果
通过几天工夫的 SPL 编码、测试,优化的成果非常明显。优化之后的测试后果如下(耗时为毫秒):
| 测点数
时间段 | 10 | 50| 100|
| — | — | — | — |
| 10 分钟 | 467| 586 | 854|
| 1 小时 | 1739 | 3885 | 4545|
| 6 小时 | 2599 | 7489| 13138|
| 1 天 | 4923| 16264 | 30254|
阐明:测试环境应用的机械硬盘,对并发计算不敌对,更换为固态硬盘后,测试后果还会有较大的晋升。
后记
解决性能优化难题,最重要的是设计出高性能的计算计划,无效升高计算复杂度,最终把速度提上去。因而,一方面要充沛了解计算和数据的特色,另一方面也要熟知常见的高性能算法和存储计划,能力就地取材地设计出正当的优化计划。本次工作中用到的根本高性能算法和存储计划,都能够从上面这门课程中找到:点击这里学习性能优化课程,有趣味的同学能够参考。
传统数据库的性能比拟繁多,只能解决一个环节的问题,比方内存数据库解决热数据问题,大数据平台解决冷数据。而以后问题须要多种技术组合,如果使用多种产品混合实现,又会带来架构的复杂性,减少零碎的危险。而且业界中的大数据库产品的架构也较为死板,对存储层根本不提供可编程能力,很难基于这些产品实现某些非凡设计的计划。
相比之下,集算器则领有凋谢的技术架构和弱小的编程能力(SPL 语言),能够被深度管制,从而实现各种就地取材设计的计划。
SPL 材料
- SPL 下载
- SPL 源代码
欢送关注我的布告号:字母哥杂谈,回复 003 赠送作者专栏《docker 修炼之道》的 PDF 版本,30 余篇精品 docker 文章。字母哥博客:zimug.com