需求情景:现有一数据库表,用于记录每一台设备的各种指标项数据,每台设备指标项约150个左右,共有10台设备(后期还会增加),每台设备每2秒写入1次数据,即:数据库单表每秒写入数据量=10台设备*150个指标项数据/2 = 750 写/秒 的并发。单日写数据量高达6,480万。在单台数据库服务器的情况下肯定并发卡死,更不用谈查询效率。
解决方案:
这是一个很重要的改动,网上有很多说法,类似“数据中台”之类的,就是专门有个地方以串行方式接收数据,保证数据不掉。这里用的不是数据中台的全部,只是用了其部分思想。如此,每台设备每次传输的数据,不管有多少,在程序采集端就构建为一条json字符串。10台设备现在每2秒传一次的写并发现在为:10/2 = 5写/秒,相较于750写/秒的并发,大大减少。单日写入数据为:43.2万,记录从数量上看减少150倍。
为保障写表效率,尽量不做索引。数据库表结构如下:
表结构说明:
is_split的作用是用于程序级实现数据的转移,后面做读表的时候有用。
这里,为了保证写效率,只对主键建立了索引,其实,这个索引不建立都没有什么问题。
此处的读写分离不是真正意义上的读写分离,没有用到rose等专用软件来做。就是通过定时事物进行数据的批量写完成。
如上图所示,device_data数据定时写入device_data_read表中。存储过程如下所示:
CREATE DEFINER=`root`@`%` PROCEDURE `DW_division`()
begin
declare temp_latest_id bigint(50);
select id into temp_latest_id from device_data order by id desc limit 1;-- 通过雪花id找到所要处理的数据的锚点。
insert into device_data_read(id,json_str,record_time,is_split,iot_id)
select id,json_str,record_time,1,json_extract(json_str,'$.iotid') from device_data where iot_id is null and id<=temp_latest_id;
update device_data set is_split=1, iot_id=json_extract(json_str,'$.iotid') where iot_id is null and id<=temp_latest_id;
end
之前用雪花id的作用在此处就体现出来了,可以通过有序的数字类型,快速锚定数据点。这里做了两步操作:
定时调用存储过程,由于对查询的效率实施性要求并不是那么高,此处的数据传输方案是10秒1次,建立一个定时任务即可。如下图:
读表在结构上与写表完全一致,但在索引建立上,可以根据自身查询需要建立多个索引字段。
如上图所示,读表增加了1个索引。
考虑到单表单日数据还是有43.2万,在超过千万数据的情况下,查询无论如何都会非常慢。此时,通过引入表分区和动态表分区(通过定时任务,每天调用一次表分区函数)思想,将每日数据做成一个表分区,即可较好地解决实时查询问题。如下图:
建立动态表分区时有几个需要注意的地方:
alter table device_data_read add partition(partition 分区名 values less than (to_days('分区值')))
基于上述代码,构建存储过程如下:
CREATE DEFINER=`root`@`%` PROCEDURE `auto_table_division`()
begin
declare tempTimeStr varchar(40);
declare parName varchar(40);
declare sqlstr varchar(2000);
set tempTimeStr = date_format(NOW(),'%Y%m%d');
set parName = CONCAT("p",tempTimeStr);
set sqlstr = "alter table device_data_read add partition(partition 分区名 values less than (to_days('分区值')))";
set sqlstr = replace(sqlstr,'分区名',parName);
set sqlstr = replace(sqlstr,'分区值',now());
set @sqlstrPara = sqlstr;
select @sqlstrPara;
prepare sqlsentence from @sqlstrPara;
execute sqlsentence;
DEALLOCATE prepare sqlsentence;
end
业务逻辑比较简单,代码不详述。
SCADA实现了实施高效展示(最大延时10秒)