程洪泽:TDengine架构设计及在云服务中的应用

Posted 七牛云

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了程洪泽:TDengine架构设计及在云服务中的应用相关的知识,希望对你有一定的参考价值。

 
本文根据程洪泽(涛思数据联合创始人)于 2021 年 7 月 17 日举办的「ECUG Meetup 第 2 期 | 云原生基础设施落地实践·北京站」上的分享整理而成。

获取「讲师完整版 PPT」 ,请添加 ECUG 小助手微信(微信ID:ECUGCON)并备注「ECUG PPT」。其余讲师的分享也将于后续陆续放出,敬请期待。

程洪泽:TDengine架构设计及在云服务中的应用
扫码添加 ECUG 小助手





本文长达 6000 余字,以下为正文:

大家好,TDengine 是我们公司的研发小组独立自主开发的一个时序数据处理平台,我们的核心代码都已经开源在 Github 上,有兴趣的可以去上面看一下。
 
我今天分享的内容主要包括五部分:
 
1、物联网数据及应用特点
2、TDengine 架构如何设计及技术介绍
3、TDengine 的应用场景
4、TDengine 在云服务中的应用
5、总结



 

一、物联网数据及应用特点

物联网有信息物理融合系统、云计算、边缘计算、大数据分析、人工智能与机器学习这五项关键技术。

 

1. 物联网数据的特点有哪些?


1)物联网数据大部分都是传感器采集的,它是时序数据,天然带有时间戳,这些时序数据达到服务器时都是有序递增的。当然,这个有序递增不是绝对的,有些可能产生乱序的,这个乱序有可能是网络延迟,还有可能是业务需求,比如一边采集新数据,一边有老数据导入做分析。


2)传感器采集的数据一般都是结构化数据,数据模型相对比较固定。固件不升级的话,它采集的量一般不会发生变化。

 
3)数据流量比较平稳,但是非常巨大。这点和电商数据不太一样,比如双十一时,电商数据会出现陡增,平常没有那么高流量,但是物联网数据比较平稳,每隔 15 分钟采集一条,或者每个传感器每 1 秒采集一条,是相对固定的。
 
4)时间序列的数据源唯一确定,相互之间不产生影响。
 
5) 数据价值随着时间流逝逐渐递减。物联网数据中,一般大家比较关心最新的状态,比如工厂的监测一般比较关注的点是现在多少台机器在开工、多少台机器没开工、哪几台机器出现了故障,老的数据意义相对小,甚至不要都可以。
 
6) 数据很少有更新或者删除。当然,这也不是绝对的,像有些造个假,或者设计得不合理,有些脏数据,但是整体数据的删除和更新是比较少的。
 
 

2. 物联网应用的特点有哪些?

 
1)数据以写操作优先,写入性能要求高,不需要事物支持。系统能够持续稳定、可靠的写入数据,确保不会因为其他操作导致写入失败。
 
2)查询要匹配特定的时间线或数据标签。实时状态查询、数据降精度、整体趋势分析较多,普通DB 无法提供这种函数。
 
3)查询请求基本上是程序驱动, Ad hoc 查询较少,有较为严格的 QPS 的要求。
 
4)查询多采用标签形式进行数据过滤,联合查询需求较少。查询过程中通常使用时间线标签过滤,较少的情况下有跨时间线联合查询。
 
5) 查询类型特殊,不同于RDS 提供的查询功能。包含大量的特殊查询:聚合、断面、插值、topK,多种形式的时间窗口,最近状态查询、数据降维、整体趋势分析较多。
 
6) 对存储资源比较敏感,因为随着时间的递增,数据一直在涨,对存储要求比较高。


 
 

二、TDengine 架构设计及技术介绍

 
TDengine 开源网址是 https://www.github.com/taosdata/TDengine ,大家有兴趣可以去点个关注或者帮我们找代码,更欢迎贡献代码。
 
我们社区版的开源是在 2019 年 7 月 12 号,开源了单机版本,2020 年 8 月 3 号把集群版开源,截止目前有 15700+ Star,4000+ Fork,4900+ Issue,这只是 open 的数据,不是全部的。
 
也分享一些其他时序数据库的开源信息(数据统计截止至 2021 年 6 月 16 日):

- InfluxDB 开源 6 年了,Star 20300,Fork 2900。 我们的 Star 不如 InfluxDB,但是有信心超过它,但是很意外的是它 Fork 比我们少,可能是因为我们用 C 写的,InfluxDB 目前用 Go 写的;
- openTSDB 开源 6 年,star 数是 4300,fork 是 1200;
- TimeScale 开源 4 年时间,star 数是 10200,fork 是 550。


 

1. TDengine 的优势是什么?

 
1)充分利用物联网时序数据的特点,设计自己的存储和查询引擎。采用创新的存储结构,可以充分利用这些特点的同时把性能比通用数据库提升 10 倍以上。
 
2)TDengine 尽全力做好融合功能,有消息队列、有缓存、有查询等功能集合,理论不需要再集成各种开源组件,但是无需再集成有条件,业务没有那么复杂,大幅度降低维护和应用成本。
 
3)提供很多第三方连接的组件。存储系统的提升导致存储资源的降低。
 
4)通过列式存储和专有的压缩算法,将数据压缩到通用数据库的十分之一,这样可以大大节省硬件成本。
 
5) 提供强大的分析功能。
 
6) 零运维成本和零学习成本。
 
 

2. TDengine 融合功能

 
程洪泽:TDengine架构设计及在云服务中的应用
  
TDengine 一直在做的,也是现在已经有了很大覆盖的功能,包含消息队列、缓存、数据库、连续计算、数据订阅等等,我们要做一个开源物联网时序数据的大数据平台。所以 TDengine 在 IoT 提供三方面支持:云计算、边缘计算、大数据分析。
  

3. 原生分布式架构

 
我们现在具体聚焦一下 TDengine 的整体架构。在 TDengine 中每个采集点是一张表在 TDengine 中,TDengine 在设计之初是分布式架构,大家从这张图可以看出来,这张图写了 4 个节点,可以部署在 4 台机器上,根据配置,每个节点可以承担不同的功能。数据节点 3 和数据节点 4 写了两个管理节点。除了管理节点之外,还有数据节点功能,管理节点主要是做什么?管理节点在 TDengine 中主要是存储元数据,比如表的分布信息、集群状态管理、状态维护等等。数据节点是专门存储数据的功能。
 
程洪泽:TDengine架构设计及在云服务中的应用
 
怎么做写入和查询?首先,客户端发请求到管理节点去要表的信息,比如我要写一张表,这张表到底在哪里,管理节点将这些信息返回给客户端应用。假设这个查询和写入覆盖很多个节点上不同的 vnode,会下发各个子请求下去,下去之后进行并发进行处理。在数据节点上我们做了虚拟化,我们认为在一个数据节点上可以划分为多个虚拟节点,每个虚拟节点存储了部分表的数据,同时,虚拟节点还是做高可靠的一个单元,比如虚拟节点 1.2、2.3、3.1 可以在 TDengine 中组成一个虚拟节点组,虚拟节点组中的各个节点可以互为备份。假设 1.2 这个节点出现问题,虚拟节点 2.3 和 3.1 都可以起来服务。
 
 

4. 多种数据类型、极致的存储压缩

 
程洪泽:TDengine架构设计及在云服务中的应用
 
TDengine 和接口很相似,提供各种数据类型,为什么要提供这些?因为我们前面讲过,在物联网中采集的数据一般都是结构化的,另外,它的波动性比较小,比如你测一个温度,温度不会忽高忽低,它一般是个趋势,这点非常适合列存储和压缩,为什么?因为变化率不大的值列式存放,利用取差值等形式可以将数据变化局限在非常小的范围内,压缩算法就非常好发挥作用。因为压缩和数据分布熵值有关,如果你压缩好,就尽可能把它的范围缩小。
 
我们针对不同的数据类型,采用了不同的压缩算法,比如采用了 Delta-Delta 等等。同时开放一级压缩、二级压缩两个选项,一级用专有算法压缩,二级算法是专有算法压缩后再用通用算法压缩一次,这是可以配置的。
 
 

5. 契合物联网数据特点的数据模型

 
程洪泽:TDengine架构设计及在云服务中的应用
  
上面三张图显示了三个传感器的设备,“12345”表示这三个传感设备在不同的时刻产生的数据。它的顺序可能是这样的,但一个传感器采集的数据是有序递增的,在 TDengine 中,一个传感器、一张表的好处在于将这些数据分流在不同的表中,在不同的表中相当于做了一个分流,如果不做这样的 append,查找一类的就比较麻烦。
 
所以将一个写入做成一个 append,只有 O(1) 的时间复杂度,因此写入的复杂度会大大提升。后面会讲乱序数据怎么处理。
 
 

6. 数据节点虚拟化

 
在我们数据节点上分成很多虚拟节点,每个虚拟节点包含很多张表的所有数据,假设有 1 万张表,其中 1000 表在第一个虚拟节点里,另外 1000 张在下一个虚拟节点里,这样的好处是什么?
 
首先,可以利用并发处理不同的数据,第二是它可以做复杂均衡,Vnode 作为高可靠的一个单元,它可以通过挪动、增加或删除、同步 Vnode 表示节点间的负载均衡。
 
在表内是如何分布呢?我们没有采用一致哈希进行分布,我们采用的是 Round-Robin 方式,默认是每 1000 个表一个阶梯,比如第一张表放 Vnode1,1000-2000 个放在 Vnode2,假设这个用户可以用 5 个 Vnode,塞完 5 个表以后再从第一个再塞,好处是可以使资源均衡分布。
 
在不同 vnode 上的数据分布,每个虚拟节点都由两部分数据构成 —— 内存数据和硬盘数据。写入时,数据先在内存中进行缓存,缓存到一定地步之后再写到这个上,是个两级结构。
 
 

7. 超级表

 
大家注意到这个模型有个缺点,一个设备一张表,假设有 1 个亿传感器,要建 1 亿张表,要想查某个小区的传感器的求和,要把所有的表都扔进去吗?这显然是不合理的。怎么解决这个问题?
 
前面讲到我们一般查询某些具有共同属性的时间线聚合,我们怎么把共同属性表达出来?系统中用的是超级表,超级表是具有沟通的 Schema(音译)、共同元数据表的集合,可以认为创建一个超级表,它下面可以有很多子表,对超级表的查询相当于作用到它下面所有的子表。比如可以查一个超级表的平均值,假设它下面有 100 万张表,我就相当于对这 100 万张表做了查询,这样用一个超级表就解决了这个问题。
 
另外,我们还提供了动态建表的功能,刚才竞品提到 InfluxDB,它的优点是写入时间创建表,我们没有采用这个方式,我们采用的是一个可以提供自动建表,可以指定表名,同时指定它的超级表名,然后给它的值,写入的时候 TDengine 会自动检测,同时将数据写入。
 
这是超级表在 TDengine 中的分布情况,超级表还有一个好处,它的 Schema 是所有子表共享的,这样 Schema 只需要存一份就可以了。内存中缓存了超级表与子表的关系,同时存储了每个表的值,这样做标签过滤时在内存操作的,速度非常快。做真实的数据查询是首先进行标签的过滤,过滤出相应的表,将表的数据返回到客户端,客户端拿到这些表的分布,到对应的节点上查相应的表。这个过程采用的是标签静态数据和动态数据分离,可以有效消除冗余和降低存储成本。另外,超级表还有一个好处是动态增删某些属性非常方便,只需要对一张超级表增删就可以了。
 
程洪泽:TDengine架构设计及在云服务中的应用
 
这是超级表的查询例子,它的标签是这种形式的,第一步先做标签过滤,过滤出哪些表满足这些条件,这些表的分布返回客户端,客户端拿到这些分布去相应的节点上查询相应的表数据。在服务端聚合后,会返回到客户端进行二阶聚合。
 
 

8. 基于预计算(SMA)的查询处理

 
另外,我们根据时序数据的特点做了预计算,什么叫预计算?就是落盘归档时,一张表的数据是连续存放的,它形成一个数据块。但是在这些物联网的查询当中,一般最大值、最小值查得是非常频繁的,我们可以在这些数据块的前面预先把这些值计算出来,就是预计算,这时如果它查的是最大值,我已经算好了,在硬盘上直接读出来就可以了。
 
每张表的数据是按块落盘的,在落盘的时候会进行预算,如果你查询的时候覆盖的范围覆盖了多个数据块,如果它全部覆盖数据块,直接把它的预计算拿出来就可以用了;如果它的时间区间正好在数据块的时间范围内,必须把这个数据块读出来,再进行计算,就能够大大减少聚合查询的消耗时间,提升聚合查询的效率。
 
 

9. 两级聚合查询处理

 
程洪泽:TDengine架构设计及在云服务中的应用
 
这是两级聚合,因为我们把数据打散到各个 vnode 当中,查询时是多个子查询并发打下去,打下去每个 vnode 并行计算,计算之后得到一个结果。比如算 SAM 值,算 1 亿张表求和,假如它有 10 个 vnode,发 10 个请求,每个 vnode 并行一个 SAM 值上来,将这个 SAM 返回客户端,客户端做第二级查询,就可以得到这个值了。
 
 

10. 数据生命周期管理

 
我刚才讲到时序数据有个很大的特点,就是随着时间的递增,数据的时效性价值会逐渐递减,有时有些数据需要丢弃,有些数据需要经常拿出来查一查,这时候我们可以利用这一特点。比较热的数据是缓存到内存中的,但内存不是无限增长的,它买了之后要到硬盘上存下来。但是这有个什么特点?越近的数据,查的可能性越大,这样我们就可以把最近的数据放到速度比较快但成本比较高的介质上,比如 SSD。
 
对于一些再老一点的数据,时效性没有那么大的、查询频率没有那么高的,可以再往上,把它放在成本比较低的比如机械硬盘上去,再低的就可以放到便宜的网络存储,再低的就可以删掉了。
 
程洪泽:TDengine架构设计及在云服务中的应用
 
这就是数据的分级存储,分级存储怎么用?提供服务时配置各个硬盘,创建时指定三个参数就可以了,keep 对应第一级这个界线,第 keep2 对应这个界线。除了分级存储,还有多盘存储,同一级上可以利用多块盘,为什么利用多块盘?我们可以将写入压力分散在不同硬盘上,目前可以分三级,每级可以挂 16 块盘。这 16 块盘是怎么用的呢?你在创建时用 R-R 的方式将文件分散在不同的硬盘上去,这样对不同的写入可以充分利用不同盘上进行写入。
 
我们接口非常简单,是 SQL 操作,语法用 mysql 一类的都没什么问题。我们也提供了很多查询功能,比如模糊匹配等等。另外,我们根据时序数据查询特点提供了专有功能,比如窗口查询、降采样、最近记录、SESSION、加权平均。另外,产品化要支持很多平台的,不同的平台支持起来比较费劲,但是我们在此方面做了很大努力,现在主流开发语言都已经支持了。不同的操作系统也都支持,包括一些国产的也都支持了。




三、TDengine 的应用场景

 
程洪泽:TDengine架构设计及在云服务中的应用
 
因为物联网,首先是跟工业相关的,比如水表、气表、管线监测、服务基础设施、DevOps、车联网、物联网,等等,这是 TDengine 目前已经涵盖了服务的应用场景。



 
四、TDengine 在云服务中的应用
  
 
这张图是我们目前在做的,也是 TDengine 目前想自己搞出来的一套云服务,但整体来讲是比较中规中矩的。我们本身支持原生的分布式,所以做这些只是一个比较正常的架构。
 
另外,TDengine 在上云上也做了一些功能,比如:多租户、多用户、用量统计、服务自愈、资源、用量控制、运行监控、网页服务、边云协同。
 
TDengine 云服务的弹性计算是我们目前正在努力做的方向。刚才我给大家讲的两级聚合,它是有一些问题的,它的问题是并发度只能和查询涉及到的 vnode 个数相关,如果你涉及 1 个 vnode,就只能用一个 vnode 资源查询,这是有所限制的。我们可以怎么做?可以将查询功能放进来,有了查询以后,我们将查询进行分解,将执行图下发到各个不同节点上去,不同的节点可以从同一个 vnode 拉数据,这样可以大大提高并发,是我们正在做的一项工作,还是比较有意义的。




五、总结

 
TDengine 主要是分析和利用了工业物联网的数据特点,自己设计和开发了系统。我们这个系统开发非常不容易,全部都是用 C 写的,对外依赖包很少,基本都是压缩库一类的。
 
另外,TDengine 后续还有很多要改进的地方,比如:
 
1)二进制类型的存储;
2)提升列的数量限制。目前支持 1024,后面会放到 1096;
3)字符串索引;
4)改善对第三方数据库管理工具的支持。
 
希望大家可以贡献代码或者加入我们,我们团队非常开放,我特别喜欢团队的氛围,氛围非常扁平,没有那么多上下级的关系。



 

Q & A

 

1. TDengine 是基于列式存储的思想?不知道它的写入性能如何?

 
程洪泽:TDengine 是基于列式存储的思想,虽然是列式存储的,但是它是行列混合的,内存中是一个行存储,硬盘上是一个列存。好处是内存中的行存可以直接 append 进去,只需要维护一个跳表索引就可以了。为什么要维护跳表索引?首先,它是线性的,各种操作可以在无锁的情况下进行操作。另外,跳表索引本身的有序性,我们的代码做了优化,优化点在哪?时序数据是有序递增,有可能有一点点回退时间,从前往后找比较慢,但是从后往前找比较快,这样对回退性乱序处理非常快。插入性能也是有保证的。
 
 

2. 写入时一致性能保证吧?因为最终要列式存储进行落盘的,这个过程是异步的?还是同步的?

 
程洪泽:数据写入进行 WAL,然后直接写 TSDB,如果 TSDB 里有缓存、有内存,它会在里面先进行缓存,进行跳表索引。当内存、缓存区达到一定地步,比如我们现在默认三分之一,三分之一时会将这部分进行刷盘。
 

3. TDengine 是日志先行的?


程洪泽:对。
 

4. 第二个问题是您刚才说到你们的聚合能力,是一个总表下发多个线程,同时计算子表。你们这个聚合计算结果是完全精确的吗?我知道 ES(音译)的聚合结果有的是不精确的,有的带上条件。咱们这个精确是不是每次把涉及到所有的数据都扫一遍?比如计算平均值,只 Limit 其中 10 条数据,我理解这个过程是把数据都集中到一台机器上才能计算准确的。

 
程洪泽:肯定精确。对于全数据扫描我们没有特别处理,因为对超级表的 Limit 查询是一个伪需求,你 1 亿张表上来之后,Limit 10 条没有意义。



5. TDengine 引擎现在支持建索引的吗?

 
程洪泽:目前我们只建了时间上面的,我们后面会有很多工作,这也是让我感到比较兴奋的一点,我们可能会加一个逻辑时间到索引,还可以挂一些其他普通列的索引等等,这都是我们接下来要完善的方向。
 

6. 咱们是基于物联网的数据库,我的印象中,普通数据库不能丢数据,但是对于咱们应用来说,首先落到内存,从内存才能最终落地。在这个过程中,是不是咱们作为物联网的数据库允许这部分数据的丢失?比如列存没落地到的时候,然后喀嚓断电。

 
程洪泽:不会。WAL 就是干这个事情的,WAL 就是在写之前先写一个 log。要刷盘能够保证稳定的可靠性,但是这中间有平衡,假如每个请求过来时都写 WAL,那性能很慢。支持每秒刷盘 200-300 次就顶天了,但是一些通用做法是将你的请求合并写入 WAL,然后返回 Response 说给你写进去了。它写进 TSDB 的内存里,其实已经有一个镜像是在 WAL 里面了,在 WAL 里面如果它挂了,这时候内存数据全没了,但是 WAL 有,你可以从里面恢复出来的。
 

7. 咱们有写 log 的步骤防止内存那个,但是这有一定容忍度的,允许一小部分在那个特殊情况下的丢失,但是咱们保障性能和安全性的平衡。

 
程洪泽:对。很多产品在这方面都有介绍的,他们有很多策略:首先,你可以周期性刷盘,比如每 3 秒刷一次,可以保证你顶多丢 3 秒的数据;如果你数据要求比较高,来了一批就得刷一次,那样你性能会下降,但是安全性得到保障;还有的利用操作系统缓存,你也不刷,操作系统什么时候满了给你刷。这主要是看平衡,取决于你用哪个策略。



 
关于七牛云、ECUG 和 ECUG Meetup

七牛云:七牛云成立于 2011 年,作为国内知名的云计算及数据服务提供商,七牛云持续在海量文件存储、CDN 内容分发、视频点播、互动直播及大规模异构数据的智能分析与处理等领域的核心技术进行深度投入,致力于以数据科技全面驱动数字化未来,赋能各行各业全面进入数据时代。

ECUG:全称为 Effective Cloud User Group(实效云计算用户组),成立于 2007 年的 CN Erlounge II,由许式伟发起,是科技领域不可或缺的高端前沿团体。作为行业技术进步的一扇窗口,ECUG 汇聚众多技术人,关注当下热点技术与尖端实践,共同引领行业技术的变革。

ECUG Meetup :ECUG、七牛云联合打造的技术分享系列活动,定位于开发者以及技术从业者的线下聚会,目标是为开发者打造一个高质量的学习与社交平台,期待每一位参会者之间知识的共创、共建和相互影响,产生新知推动认知发展以及技术进步,通过交流促进行业共同进步,为开发者以及技术从业者打造更好的交流平台与发展空间。



往期活动回顾



对 ECUG 各类技术活动感兴趣的同学,可添加 ECUG 小助手微信(微信ID:ECUGCON)进入活动交流群,获取更多活动信息。
  
扫码添加 ECUG 小助手

以上是关于程洪泽:TDengine架构设计及在云服务中的应用的主要内容,如果未能解决你的问题,请参考以下文章

极客道场 | 深度剖析Raft及在NewSQL中的使用

江苏农信 SDN 技术应用在云平台架构设计实践经验 | 最佳实践

受限玻尔兹曼机原理及在推荐系统中的应用

正则语法及在php中的应用

Python设计模式中单例模式的实现及在Tornado中的应用

基于云原生的架构体系