开源纯C#工控网关+组态软件(七)数据采集与归档

 一、   引子

 在当前自动化、信息化、智能化的时代背景下,数据的作用日渐凸显。而工业发展到如今,科技含量和自动化水平均显著提高,但对数据的采集、利用才开始起步。

对工业企业而言,数据采集日益受到重视,主要应用场景包括:

  1. 节能降耗。投入(如车间的水电气能耗、设备工时、原料耗用)和产出(产量、批数)这些成本核算的关键数据通过传感器采集,取代人工抄表已成为趋势。

  2. 绩效考评。投入、产出、损耗、工时数据,其对管理者的决策支持、对员工的绩效评估都很重要。

  3. 批次追溯。食品安全形势日益严峻,对物料的追溯也成为国家硬指标。追溯就是追根溯源,批次生产的每个环节都需要数据跟踪。

  4. 设备管理。如设备的运行时长对于设备保养、故障频率对于设备维护、设备参数对于工艺优化。

数据既然如此重要,对于SCADA不但必须有,而且高要求:

  1. 准确性。信号不能失真,采集精度和时间戳尽可能精确;也不能带入太多干扰和噪音。

  2. 完整性。信号不能频繁丢失、丢步、跳步,万一信号断开,要快速重连,或者有冗余机制。

  3. 大容量。大数据,首先要能撑的起这个“大”。大项目动辄几万点,采集频率又高,一天下来数据量都惊人,日积月累更是天量。例如对于 1万点的系统, 1秒钟存储一次,每次单点占用 8字节,保存 10年的数据量将有 10000*8*10*365*86400=25228800000000字节,也就是 23TGB。若用 80GB硬盘存放,需 293块硬盘。如此庞大的数据量,还要求快速插入、快速查询。

要实现这些指标,非常具有挑战性。

二、   实时库与历史库

  • 概述

工控环境特殊性在于,大量测点快速变化,需高速存取, IO密集型;数据结构简单规则,无非就是名称/ID、值、时间戳这些;数据流式存储,只需在尾部插入,不删不改。

因此常规的关系数据库不仅存取速度跟不上,也显得杀鸡用牛刀。实时库和历史库就是为工业环境准备的,测点的实时数据存储在内存,保证最快的存取速度;数据超过一定范围需要转储入历史库,我这里用了自定义格式的二进制文件,力求数据单元空间占用最小化、同时查询速度最大化。

  • 实时库

测点数据在内存中,包含【下位机映射缓存:ICache】→【快照数据集:TagList】→【历史数据缓存:HistoryList】这样的三级结构。

ICache是下位机当前数据的缓存,随扫描过程实时更新,继承IReaderWriter接口,可读可写,可以通过Tag的Read\Write读取和更新。

对当前所有测点数据的快照查询,可以通过Tag的清单列表MetaTagList结合神器Linq实现。Linq对内存列表数据的查询能力可以说既强大又优雅,这是微软送给C#码农的礼物,不再赘述。

测点数据改变就会生成一条新的记录。这些记录如马上转储到数据库或文件,则测点数量多变化快,其IO是系统不能承担之重。但如果测点记录堆积过多不及时清理,则一方面可靠性下降,如系统崩溃、断电就会发生大量数据点丢失,同时内存占用越来越大,影响系统性能。所以测点历史数据的缓存容量应可根据测点数量和存取频率自适应或由用户自定义。

  • 历史库

海量的测点数据,普通关系数据库是难以招架的。如SQL SERVER免费版只有4-10个G上限。而这个容量可能一个月就溢出了。

因此,为了适应天量数据,就需要二进制文件存储。有人会问为啥不用NO SQL,Hadoop这些高大上的东东,我的观点是不追求高大上,因为工控数据不同于搜索引擎,都是简单而标准的结构。可以根据其特点进行有针对性的设计,无需部署复杂的NO SQL架构也一样可以实现高性能。

历史数据库要最大限度的压缩数据,同时又要保证快速插入、快速查询。

如何保证数据单元最小化?

分析存储结构,一条记录包括变量名、当前值、时间戳。

变量名可能为一个长字符串,数据量大之后显然是过于冗长。因此代之以ID号(2字节)。还可以进一步压缩,如相同变量存在一起,ID也可以省了。

当前值大部分是浮点数,4字节,这个不能缩减,否则影响数据精度。

时间戳为DateTime,要占8字节,但如果数据按日排序,日期部分省去,4个字节的时间部分就可以精确到毫秒。

这样,通过合理设计存储结构,一条记录可以压缩到8个字节(开关量5个字节)。

如何保证快速插入记录?

存档文件日积月累肯定是越来越庞大,如果采用覆盖式写入或更新写入,不仅可靠性下降,读写成本也越来越高。想快速插入必须保证每次写入不改变原来的数据,仅仅在末尾追加。

如何保证快速查询?

首先为保证可靠性和数据容量限制,数据分月存放。文件名为【年-月.bin】。如需跨月查询,按文件名搜索拼接即可。开头256个字节存放日期索引。32*8字节,对应每日记录的头指针,也即上一日记录的末尾。

主索引下,每一天的记录头为日内索引区。包含一个索引数组,每一项索引有变量ID、变量长度、数量。如要查某日某ID的变量,即可先找到ID,再根据其变量长度*数量累加计算,即可定位到该变量的第一条记录。

同一变量的记录按时间戳顺序排列。这样,要定位到该变量某一时间的记录,即可对时间戳采用二分法快速定位。

字符串类型的归档比较特殊,专门在EventLog作为日志存取。

三、   数据转储流程

  • 为什么要建立三级转储

数据在什么情况下会被采集?默认是变化了采集。如果一个数据长期不变,但需要定期采样,可以设置归档周期:

 

数据被采集之后首先是存在内存中。内存的特点是快,小。存取快,但是容量有限,采样数据堆积多了就要清理转储到关系数据库。

为什么要多一层关系数据库?因为采样的数据是时间序列的,但最终二进制文件的索引结构按照变量-时间戳排布,比如依次排入变量A-13:40,变量B-13:41,变量A-13:42这样一个时间序列,如直接写二进制存档文件就需按变量排序并重新整理写入,文件越大其写入效率越低,对系统拖累越大。而先转储到关系数据库,再定期将上一日的数据转储到二进制文件,既可以充分利用关系数据库的高性能批量插入功能(在SQL SERVER就是Sqlbulkcopy),又可利用关系库的查询排序能力,一举两得,转储之后数据库记录清空,也避免关系库容量溢出的问题。

由上所述,转储包含【历史数据缓存:HistoryList】→【关系数据库:Log_HDA】→【二进制文件:bin文件】三级。

每转储成功一次,上一级的数据就清空,保证每一级之间的数据不重叠。

这样一来,数据记录就分布于三个位置:内存、关系库、二进制文件。要查询数据,就需要对这三部分数据进行“拼接”。拼接的规则就是以当前级最末一条记录的时间戳为准。如当前级中没有,就查下一级。

  • 源头:内存数据库

内存数据库是一个HistoryData列表。有两种情况可以触发清理:定期清理、溢出清理。定期清理是设置固定的周期。溢出就是超过一定大小,到时间就转到关系库。可由server.xml配置。

  • 中介:关系数据库

就是数据库的Log_HDA表。承上(内存)启下(二进制文件),暂存数据。也包含ID、值、时间戳这几个字段。每天凌晨开始,网关服务调用DataHelper内部的WriteToFile方法(实际是调用关系库的WRITEHDATA存储过程),对暂存的测点记录按时间、变量排序,转储到二进制文件中。如写入失败,判断最后一个时间戳,下一次继续追加写入,类似断点续传。

  • 存储:二进制数据库

二进制存档文件按月存放,自带索引。所有对其操作均在DataHelper的HDAIOHelper 类中。包括从数据库写入、查询、定期转储、压缩归档(用旋转门算法)等。为提高读写性能,采用内存映射文件MemoryMappedFile。

四、   应用场景

  • 数据应用场景

数据的应用场景,主要是查询、显示、挖掘。查询→生成各种报表、图表,以供人工分析比较;显示→图形化展示,一目了然;挖掘→结合先进的挖掘工具,找出数据内在关联性,提供决策支持。

 

  • 数据查询

目前支持的查询场景包括:按时间段检索、按变量ID检索、获取某变量在一段时间内的平均值/最大值/最小值/初始值/当前值。如要对一段记录执行复杂查询(如按时间间隔分组等),需要取出该时间段内所有记录,用Linq查询。

  • 数据显示

目前支持实时数据显示和历史数据趋势图。我这里用了一套微软俄罗斯研究院的DynamicDataDisplay开源组件,性能不错,很适合动态图显示,目前还发展出了javascript版本。

 

  • 数据报表

利用微软的RDLC报表和Chart图表的强大功能,可以方便的设计出各种复杂报表、图表。顺带赞一下RDLC,集成于Visual Studio和SQL SERVER,可以在Web显示,支持内嵌表格、仪表、图表、钻取报表,还可以方便的导出为Excel、Pdf、Word,与.NET 完美集成,强烈推荐。

  • 未来改进

分布式:对一个大系统,分布式是必须的。即数据分别在不同节点采集、存储,但形式上依然是一个整体,可以统一查询和传输。

内存映像:目前的测点缓存模式存在可靠性不足的问题(如突然断电或系统崩溃造成的数据丢失),可依赖Sqlite和内存映像解决。

MQTT:物联网通行的MQTT协议可以解决不同系统之间的实时订阅传输问题。

查询扩展:原生支持按时间间隔分组取出数据等常用查询场景,可以有效提高查询性能。

安全控制:采用证书认证方式,加强权限管理,防止数据传输过程中被篡改。

数据归档流程:

五、   下面的计划

  • 网关层接口概述

  • 上下位机通讯原理

  • 如何实现一个设备驱动

  • 如何设计图元

  • 数据采集与归档

  • VS插件模块及原理

  • 归档模块及文件格式

  • 如何进行功能扩展

  • 组态变量表达式实现

github地址:https://github.com/GavinYellow/SharpSCADA。QQ群:102486275

相关文章: 

  • .NET十年回顾

  • 开源纯C#工控网关+组态软件

  • 开源纯C#工控网关+组态软件(三)加入一个新驱动:西门子S7

  • 开源纯C#工控网关+组态软件(四)上下位机通讯原理

  • 开源纯C#工控网关+组态软件(五)从网关到人机界面

  • 开源纯C#工控网关+组态软件(六)图元组件

原文:http://www.cnblogs.com/evilcat/p/7909578.html


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322607.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实践出真知之Spring Cloud之基于Eureka、Ribbon、Feign的真实案例

转载自 实践出真知之Spring Cloud之基于Eureka、Ribbon、Feign的真实案例 Eureka是Spring Cloud Eureka的简称,是Netflix提供的组件之一。通过Eureka可以提供服务注册、发现、负载均衡、降级、熔断等功能。本篇主要介绍Eureka作为服务注册中心,以及实现…

从零开发一个laravel项目的增删改查、详情

环境要求: wampcomposer 创建laravel项目: composer create-project --prefer-dist laravel/laravel person快速完成person注册登录开发 1、migration php artisan make:migration create_people_table$table->increments(id);$table->string…

使用Api分析器与Windows兼容包来编写智能的跨平台.NET Core应用

本文翻译自Scott Hanselman博客:https://www.hanselman.com/blog/WritingSmarterCrossplatformNETCoreAppsWithTheAPIAnalyzerAndWindowsCompatibilityPack.aspx正文:这是最近这几周你应该知道的一对.Net Core界的优秀工具。我们在编写或者移植跨平台代码…

实验进行中:.NET WebAssembly支持

目前四大主流浏览器都默认支持WebAssembly,而.NET社区也在继续推动为.NET开发者提供相关能力,来将他们的代码编译成WebAssembly,然后在浏览器上运行。WebAssembly是一种二进制web格式,旨在以接近原生的性能运行不是用JavaScript语…

Js对象如何添加方法、查看Api

js万物皆对象,要带着观察对象的眼观去看待每一个函数、变量。 为什么要用到原型? Es6以前,js中没有如ooa编程当中的class,但是要用到类,怎么办呢,构造函数就应运而生,但是构造函数里面添加方法…

微软人工智能和对话平台--知识商城体验

前言微软最新发布 知识商城了!这是一个人工智能和对话平台应用的场景。他可以让开发者带着想法 出做天马行空的创造性工作!你只需要稍微动动手,如:拖拽板块,就可以做到极致对答、代码自动生成!想象一下&…

Spring @Import注解配置类方法内部调用没有注入属性值的坑

一、场景复现 application.yaml spring:application:name: config-testprofiles:active: devconfig:config-01:name: zhansancode: 001config-02:name: lisicode: 002导入配置类 Configuration Import(ImportConfig.class) public class Config {BeanConfigurationPropertie…

使用Xamarin开发手机聊天程序 -- 基础篇(大量图文讲解 step by step,附源码下载)

如果是.NET开发人员,想学习手机应用开发(Android和iOS),Xamarin 无疑是最好的选择,编写一次,即可发布到Android和iOS平台,真是利器中的利器啊!而且,Xamarin已经被微软收购…

Spring Boot 数据库连接池入门

转载自 芋道 Spring Boot 数据库连接池入门 本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-19 目录。 原创不易,给点个 Star 嘿,一起冲鸭! 1. 概述 在我们的项目中,数据库连接池基…

.net core 实现简单爬虫—抓取博客园的博文列表

一.介绍一个Http请求框架HttpCode.CoreHttpCode.Core 源自于HttpCode(传送门),不同的是 HttpCode.Core是基于.net standard 2.0实现的,移除了HttpCode与windows相耦合的api,且修改了异步实现,其余特性完全与…

SpringBoot2.1.9 Mybatis由于@Mapper注解多数据源配置不生效问题

一、场景复现 (1)项目 目录 配置文件 spring:application:name: multi-datasourceprofiles:active: dev1datasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/base?…

使用Windows兼容包简化向.NET Core的迁移

从.NET迁移到.NET Core的一个主要原因,在于后者具备在Linux上运行的能力。但是对于大型企业应用,不可能实现一步迁移到位。由此,Microsoft推荐采用一种逐步迁移做法:第一步,迁移到ASP.NET Core(依然使用.NE…

springboot使用xml配置mybatis

前面用注解配置了mybatis&#xff0c;非常的简单&#xff0c;但是在写动态sql语句的时候会非常的麻烦&#xff0c;所以这边我们用xml来重新配置一下 在resource目录下新建 SqlMapConfig.xml 主配置文件 <?xml version"1.0" encoding"UTF-8" ?> &…

SpringBoot2.1.9 Mybatis多数据源配置

一、配置文件 目录 application.yaml spring:application:name: multi-datasourceprofiles:active: devdatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/base?autoReconnecttrue&ze…

自动类型安全的REST .NET标准库refit

在SCOTT HANSELMAN 博客上看到一个好东西《Exploring refit, an automatic type-safe REST library for .NET Standard》&#xff0c;他推荐了一个.NET标准1.4 的自动类型安全的REST库refit。 refit 类似于Java的Retrofit&#xff0c;是一套RESTful架构的.NET客户端实现&#x…

Visual Studio的语言服务器协议

语言服务器协议&#xff08;LSP&#xff09;是Visual Studio Code的一个重要组件。语言服务器实际上是单独运行的编译器或分析器&#xff0c;它负责处理各种任务&#xff0c;如编译器错误报告、文本悬浮、代码自动完成&#xff08;也就是IntelliSense&#xff09;等。语言服务器…

C#和NewSQL更配 —— TiDB入门

一、背景在上一篇尝试CockroachDB&#xff08;传送门在此&#xff1a;http://www.cnblogs.com/Zachary-Fan/p/cockroachdb_net_csharp.html&#xff09;的过程中&#xff0c;发现如果从常规的RDBMS迁移过去几乎是不太可能的事情&#xff0c;所以掉头开始调研一下也是这2年比较火…

Mysql调优你不知道这几点,就太可惜了

转载自 Mysql调优你不知道这几点&#xff0c;就太可惜了 一、Mysql的逻辑分层 Mysql分为&#xff1a;连接层、服务层、引擎层、存储层。 当客户端向服务端发起操作请求的时候&#xff0c;执行过程是这样的&#xff1a; 1、客户端端与Mysql服务端的连接层建立连接&#xff…

Unity/DotNetty中集成Lidgren实现可靠UDP

lidgren有几个优点&#xff1a;分channel&#xff0c;每个channel都有单独的消息队列&#xff0c;不互相影响。每个消息可以单独选择使用可靠/不可靠传输。支持内网穿透自带加密算法。前端Unity&#xff1a;先贴一张前端使用的网络框架图&#xff1a;Lidgren的Github地址&#…

欢乐纪中A组周六赛【2019.4.13】

前言 做A组被虐好惨 成绩 RankRankRank是有算别人的 RankRankRankPersonPersonPersonScoreScoreScoreAAABBBCCC222巨佬WHF巨佬WHF巨佬WHF140140140404040100100100000222巨佬ZZY巨佬ZZY巨佬ZZY140140140404040100100100000555巨佬HJW巨佬HJW巨佬HJW10010010010010010000000014…