时序数据库之TDengine

物联网、工业互联网的数据特点

物联网、工业互联网的数据是流式数据,像视频流,而且单个数据点的价值很低,甚至丢失一小段时间的数据也不影响分析的结论,也不影响系统的正常运行。但看似简单的事情,由于数据记录条数巨大,导致数据的实时写入成为瓶颈,查询分析极为 缓慢,成为新的技术挑战。传统的关系型数据库、NoSQL 数据库以及流式计算引擎由于没有充分利用物联网数据的特点,性能提升极为有限,只能依靠集群技术,投入更多的计算资源 和存储资源来处理,系统的运营维护成本急剧上升。

面对这一高速增长的物联网数据市场,近几年出现一批专注时序数据处理的公司,比如美国的InfluxData,其融资已经超过1.3亿美元,其产品InfluxDB在IT运维监测方面有相当的市场占有率。在工业控制领域老牌实时数据库公司OSIsoft在2017年5月获得软银12亿美元的投资,期望成为新兴的物联网领域的数据库的领头羊。开源社区也十分活跃,比如基于HBase开发的OpenTSDB。中国国内,阿里、百度、华为都有基于OpenTSDB的产品。

2017年成立的北京涛思数据科技有限公司看好这一市场,不依赖任何第三方软件或开源软件,在吸取众多传统关系型数据库、NoSQL 数据库、流式计算引擎、消息队列等软件的优点之后自主开发了TDengine Database,一个完整的时序大数据处理引擎。TDengine Database的性能远超InfluxDB, 而且其安装、部署、维护简单,使用SQL接口,学习成本几乎为零,有望成为时序数据处理市场的一匹黑马。

各种类型数据库特点

从数据库的定义来说,数据库就是一个数据管理系统,是用来存放数据文件的一个软件,支持用户的添加,修改,删除,查询等操作。所以从定义上讲,时序数据库和关系 / 非关系数据库是一样的,都是用来存放数据的。只是存储的数据特点不同,应用的场景也不尽相同:

  • 关系型数据库 ( SQL ):主要用来存储结构化数据,使用实物保证数据一致性,使用SQL语言来进行查询操作,。典型代表主要有 MySQL, Oracle, SQL Server 等。
  • 非关系型数据库 ( NoSQL ): 主要用来存储非结构化数据,数据可以不通过验证进行存储,使用 JSON 数据对象进行查询操作。典型代表主要有 MongoDB, Redis 等。

而时序数据库主要存储实时数据,最明显的特点就是每条数据都会带有时间戳属性。在电力、石化、冶金、智能汽车、监控等领域应用比较广泛。典型代表主要有 influxDB,TimescaleDB. 另外不得不推荐一下 TDengine (),从个人的使用情况来看,功能强大,性能远远超出预期。

能否用关系/非关系型数据库代替时序数据库?

一方面如果数据采集频率少,数据量不大的话,使用关系/非关系型数据库代替时序数据库是完全没有问题的。

另一方面,从时序数据的特点(采集频率高、数据量大)来看,关系/非关系型数据库很难满足这样高的性能需求。在大数据场景下,如果性能达不到要求,数据没有办法被有效存储的话,那么这样的数据库是无法代替时序数据库的。

举一个简单的例子,在相同的测试环境(16 核 64G 内存)拿 MySQL 和 TDengine 做一下 benchmark 的对比测试 :

分别使用 MySQL 自带的 benchmark 工具 mysqlslap 和 TDengine 自带的 benchmark 工具taosbenchmark,使用16个线程,写入单表10万条记录,表结构为1个timestamp类型,2个int类型,2个字符串类型,测试结果如下:

MySQL
mysqlslap -uroot -p1234 --concurrency=16 --number-of-queries=100000 --create-sc hema=tests --query="INSERT INTO meters(c0, c1, c2, c3) VALUES (RAND() * 100, RAND() * 100, uuid(), uuid())"

TDengine

taosBenchmark -b int,int,binary\(128\),binary\(128\) -n 100000 -t 1 -T 16

同样写入 10 万条记录的情况下,MySQL 使用自带的 mysqlslap 工具需要 75 秒完成,而 TDengine 使用自带的 taosBenchmark 只需要不到 1 秒。在差距如此巨大的情况下可以看到使用 MySQL 代替时序数据库处理时序数据是比较困难的。当然由于测试工具不同,这里只是做一个示例,测试本身算不上严谨。

TDengine

TDengine 是一个具有 SQL 支持的高性能、可扩展的时间序列数据库。其包含集群功能的代码在GNU AGPL v3.0下是开源的除了数据库,它还提供缓存、流处理、数据订阅等功能,以降低开发和运营的复杂性和成本。TDengine 区别于其他 TSDB 具有以下优势。

 

 

  • 高性能:TDengine 在数据摄取和查询方面优于其他时间序列数据库,同时通过创新设计和专用存储引擎显着降低存储成本和计算成本。

  • 可扩展性:TD​​engine 通过其原生分布式设计提供开箱即用的可扩展性和高可用性。可以通过简单的配置添加节点,以实现更大的数据处理能力。此外,此功能是开源的。

  • SQL 支持:TDengine 使用 SQL 作为查询语言,从而降低学习和迁移成本,同时增加 SQL 扩展以更好地处理时序数据,并支持方便灵活的无模式数据摄取。

  • All in One:TDengine内置缓存、流处理和数据订阅功能,部分场景不再需要集成Kafka/Redis/HBase/Spark等软件。它使系统架构更加简单和易于维护。

  • 无缝集成:TDengine无需一行代码,提供与Telegraf、Grafana、EMQX、Prometheus、StatsD、collectd等第三方工具的无缝集成。更多的将被集成。

  • 零管理:安装和集群设置可以在几秒钟内完成。数据分区和分片是自动执行的。可以通过 Grafana 或其他 DevOps 工具监控 TDengine 的运行状态。

  • 零学习成本:以 SQL 作为查询语言,支持 Python、Java、C/C++、Go、Rust、Node.js 连接器等无处不在的工具,学习成本为零。

  • 交互式控制台:TDengine 提供对数据库的便捷控制台访问,以运行即席查询、维护数据库或管理集群,无需任何编程。

TDengine可广泛应用于物联网(IoT)、车联网、工业物联网、DevOps、能源、金融等诸多场景。

用户手册、系统设计与架构、工程博客,详见TDengine文档(中文版请点击这里)。

从 TDengine shell 运行 SQL 命令很容易,这与其他 SQL 数据库相同。

CREATE DATABASE demo;
USE demo;
CREATE TABLE t (ts TIMESTAMP, speed INT);
INSERT INTO t VALUES('2019-07-15 00:00:00', 10);
INSERT INTO t VALUES('2019-07-15 01:00:00', 20);
SELECT * FROM t;
          ts          |   speed   |
===================================
 19-07-15 00:00:00.000|         10|
 19-07-15 01:00:00.000|         20|
Query OK, 2 row(s) in set (0.001700s)

 

IoTSharp.EntityFrameworkCore.Taos

IoTSharp.Data.Taos 是一个采用TDengine的原生动态库构建的ADO.Net提供程序。 它将允许你通过.Net Core 访问TDengine 数据库。


IoTSharp.EntityFrameworkCore.Taos 是一个Entity Framework Core 的提供器, 基于IoTSharp.Data.Taos实现。 (原名称为 Maikebing.EntityFrameworkCore.Taos)


NuGet 名称版本下载量说明
IoTSharp.Data.Taos IoTSharp.Data.Taos 努吉特 ADO.Net Core 基础组件
IoTSharp.EntityFrameworkCore.Taos IoTSharp.EntityFrameworkCore.Taos 努吉特 供EF Core使用的组件
IoTSharp.HealthChecks.Taos IoTSharp.HealthChecks.Taos 努吉特 供Asp.Net Core 使用的健康检查组件

TDengine技术开放日 — 从技术创新和设计思想,认识TDengine

 

如何使用?

例子:

    ///Specify the name of the database
    string database = "db_" + DateTime.Now.ToString("yyyyMMddHHmmss");
      string database = "db_" + DateTime.Now.ToString("yyyyMMddHHmmss");
      var builder = new TaosConnectionStringBuilder()
      {
            DataSource = "127.0.0.1",
            DataBase = database,
            Username = "root",
            Password = "kissme",
            Port=6060
            };
    //Example for ADO.Net 
    using (var connection = new TaosConnection(builder.ConnectionString))
    {
        connection.Open();
        Console.WriteLine("create {0} {1}", database, connection.CreateCommand($"create database {database};").ExecuteNonQuery());
        Console.WriteLine("create table t {0} {1}", database, connection.CreateCommand($"create table {database}.t (ts timestamp, cdata int);").ExecuteNonQuery());
        Console.WriteLine("insert into t values  {0}  ", connection.CreateCommand($"insert into {database}.t values ('{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ms")}', 10);").ExecuteNonQuery());
        Console.WriteLine("insert into t values  {0} ", connection.CreateCommand($"insert into {database}.t values ('{DateTime.Now.AddMonths(1).ToString("yyyy-MM-dd HH:mm:ss.ms")}', 20);").ExecuteNonQuery());
        var cmd_select = connection.CreateCommand();
        cmd_select.CommandText = $"select * from {database}.t";
        var reader = cmd_select.ExecuteReader();
        Console.WriteLine(cmd_select.CommandText);
        Console.WriteLine("");
        ConsoleTableBuilder.From(reader.ToDataTable()).WithFormat(ConsoleTableBuilderFormat.MarkDown).ExportAndWriteLine();
        Console.WriteLine("");
        Console.WriteLine("DROP TABLE  {0} {1}", database, connection.CreateCommand($"DROP TABLE  {database}.t;").ExecuteNonQuery());
        Console.WriteLine("DROP DATABASE {0} {1}", database, connection.CreateCommand($"DROP DATABASE   {database};").ExecuteNonQuery());
        connection.Close();
    }
    //Example for  Entity Framework Core  
    using (var context = new TaosContext(new DbContextOptionsBuilder()
                                            .UseTaos(builder.ConnectionString).Options))
    {
        Console.WriteLine("EnsureCreated");
        context.Database.EnsureCreated();
        for (int i = 0; i < 10; i++)
        {
            var rd = new Random();
            context.sensor.Add(new sensor() { ts = DateTime.Now.AddMilliseconds(i), degree = rd.NextDouble(), pm25 = rd.Next(0, 1000) });
        }
        Console.WriteLine("Saveing");
        context.SaveChanges();
        Console.WriteLine("");
        Console.WriteLine("from s in context.sensor where s.pm25 > 0 select s ");
        Console.WriteLine("");
        var f = from s in context.sensor where s.pm25 > 0 select s;
        var ary = f.ToArray();
        ConsoleTableBuilder.From(ary.ToList()).WithFormat(ConsoleTableBuilderFormat.MarkDown).ExportAndWriteLine();
        context.Database.EnsureDeleted();
    }
    Console.WriteLine("");
    Console.WriteLine("Pass any key to exit....");
    Console.ReadKey();

 

用于物联网的超级表示例:

IoTSharp/Storage/TaosStorage.cs



鸣谢:

https://www.zhihu.com/question/408178021/answer/2400714433

https://www.taosdata.com/engineering/105.html

https://github.com/taosdata/TDengine

https://github.com/IoTSharp/EntityFrameworkCore.Taos

 

posted @ 2022-07-02 12:00  春光牛牛  阅读(1587)  评论(0编辑  收藏  举报