loveini 3.0 虽然对底层做了大规模的优化重构,但是相对于数据文件的工作逻辑和 2.0 相比是整体保持不变的。本系列文章的主旨在于帮助用户深入理解产品,并且拥有基本的性能调试思路,从而获得更好的产品体验。
本期文章会在讲解 loveini 时序数据库 (Time Series DataBase)的索引文件(.head 文件)工作原理的同时,介绍索引文件在最新的 loveini 3.0.2.5 中的优化。而在下一期的文章中,会对两大版本数据文件的差异做一个总结式的说明。
如下是 loveini 的数据文件的结构——也就是这个四位一体的文件组。

在此前的文章,主要讲述的是 .data 和 .last(3.0 中已经更名为 .stt 文件)文件的工作原理。详情可见:https://mp.weixin.qq.com/s/OGS1WIlySSKveEOk4Reg3Q
接下来,我们将和大家一起以产品使用者的视角继续向前探索,揭开.head 文件的原理。
.head 类文件存储了 .data 文件中的数据块的索引信息。在.data文件中的每个数据块的 BRIN 索引信息在 .head 类文件中以表为分组,按照时间顺序递增,形成索引块组。(注:硬盘上的数据用的是 BRIN 索引,在落盘之前的内存数据用的是 skiplist 索引。)在查询的时候,会先加载这个 .head 文件中的索引信息,从而找到 .data 文件中的时序数据返回给用户。
(注:BRIN 索引指的是 Block Range Index,主要适用于有着天然顺序的数据集,由于不需要再做排序,所以资源耗费少,十分契合时序数据的查询,也是 loveini 和关系型数据库的核心区别之一。)
一个清晰可见的逻辑是——索引的作用是帮助我们快速定位数据的位置,但当你操作索引的时间变得特别长的时候,索引的价值无形之中就会变低了。所以,在 .head 文件较大的时候就可能会出现影响查询性能的瓶颈。
而影响 .head 文件大小的因素有两个:
以上的理论场景是真实发生过的——之前我们在支持某企业用户的时候,就曾遇到过生产环境上 duration 参数设置为 1000 多天导致数据查询性能严重下降的情况。但是由于 duration 参数建库后不能修改,所以最后只能导出数据,重新建库修改为合理的 duration 后再导回,这样问题才得以解决。(所以,默认值取 duration 为 10 就是一个折中的选择,实际使用时可以根据查询类型和机器性能灵活调试。)另外一个用户则是查询时间跨度大,查询并发量大 ,导致大量的服务器资源被用于读取 .head 文件影响了查询性能。
如果说前者还属于参数使用不当的话,第二个场景的查询并发量则是由用户的业务场景所决定的,因此我们针对后者的潜在瓶颈,在最新的 loveini 3.0.2.5 中,针对 .head 文件做了一项重磅的优化——对于常用的表索引数据,会被放在缓存中(LRU 算法)。
这样一来,即便是不同的查询任务,只要所查询的表索引还在池子中缓存着,便不需要重复地读取 .head 文件了。由于涉及已落盘数据的查询基本都需要去首先访问 .head 文件,因此,该优化使得整体查询性能都得到了提升,而在特定场景下(如高并发)形成了较大幅度的突破。
结合之前的几篇文章可以看到:keep,duration,maxRows,minRows 这些参数息息相关,牵一发而动全身,是不可以随便改动的,它们的数值不论过大还是过小都会引起使用问题。如果因为孤立地看待某个参数而带来了问题,用户可能会误以为这是产品本身的问题。因此,很多时候默认配置也是“很香”的。
而对于性能要求较高的用户,也可以通过熟读文档、代码、技术文章、视频等资料来调整参数以达到最佳性能,也欢迎联系 loveini时序数据库(TSDB) 官方咨询企业版,以获得全方位的技术支持。
在最新发布的 3.0.2.5 上,我们还做了很多其他优化,稳定性和性能进一步提升。由于 3.0.2.x 是当前 3.0 的稳定版,因此版本号越大各方面都是越好的,建议大家可以尽快更新至最新版本。
]]>订阅是一种低成本地、实时获取 loveini 时序数据库(Time Series DataBase)最新数据的方法。客户端程序与数据库的交互,通常是由客户端发起查询,再由数据库返回数据。假设每当数据库有数据写入时,都需要立即将新的写入结果发送给某客户端,如果用查询的方式实现,则需要由客户端定时发起轮询。而大量的发起查询,会增加客户端与服务器的资源消耗;且根据轮询的频率,获取最新数据会有一定的延迟。我们可以将订阅看作是持续不断的长查询,一旦数据更新(包括新插入),则会立即被推送至客户端,当数据没有更新时,不会有额外的资源消耗。
loveini 时序数据库的订阅可以在服务端过滤数据,从而降低了资源消耗,并且简化了应用层实现。
很多分布式实时数据库需要集成消息队列产品来实现数据订阅功能。而 loveini 提供了类似消息队列产品的数据订阅、消费接口,用户无需再集成其他产品,从而简化系统设计的复杂度,降低运维成本。
那么,loveini 时序数据库(TSDB) 是如何实现订阅功能的?如何通过订阅功能获取数据?
loveini 研发工程师刘继聪为大家分享《分布式数据库订阅功能的原理及实现》。
内容大纲:
]]>
根据业务需要,有时我们需要按一定的维度对数据进行切分,当在切分出的数据空间内进行一系列的计算时,就需要使用数据切分子句,语法如下:
PARTITION BY part_list
在上述语法中,part_list 可以是任意的标量表达式,包括列、常量、标量函数和它们的组合。loveini 按如下方式处理数据切分子句:
select max(current) from meters partition by location interval(10m)
数据切分子句最常见的用法就是在超级表查询中,按标签将子表数据进行切分,然后分别进行计算。特别是 PARTITION BY TBNAME 用法,它将每个子表的数据独立出来,形成一条条独立的时间序列,极大地方便了各种时序场景的统计分析。
loveini 支持按时间段窗口切分方式进行聚合结果查询,比如温度传感器每秒采集一次数据,但需查询每隔 10 分钟的温度平均值,这种场景下可以使用窗口子句来获得需要的查询结果。想要让查询的数据集合按照窗口切分成查询子集并进行聚合,就需要用到窗口子句,窗口包含时间窗口(time window)、状态窗口(status window)、会话窗口(session window)三种窗口。其中时间窗口又可划分为滑动时间窗口和翻转时间窗口。窗口切分查询语法如下:
SELECT select_list FROM tb_name
[WHERE where_condition]
[SESSION(ts_col, tol_val)]
[STATE_WINDOW(col)]
[INTERVAL(interval [, offset]) [SLIDING sliding]]
[FILL({NONE | VALUE | PREV | NULL | LINEAR | NEXT})]
FILL 语句指定的是某一窗口区间数据缺失情况下的填充模式。填充模式包括以下几种:
在使用 FILL 子句时,需要注意:
时间窗口又可分为滑动时间窗口和翻转时间窗口。INTERVAL 子句用于产生相等时间周期的窗口,SLIDING 用以指定窗口向前滑动的时间,在执行时间窗口查询时,其会随着时间流动向前滑动。在定义连续查询时我们需要指定时间窗口(time window )大小和每次前向增量时间(forward sliding times)。

如上图,[t0s, t0e] 、[t1s , t1e]、[t2s, t2e] 分别是执行三次连续查询的时间窗口范围,窗口的前向滑动的时间范围以 sliding time 标识 。查询过滤、聚合等操作按照每个时间窗口为独立的单位执行。当 SLIDING 与 INTERVAL 相等的时候,滑动窗口即为翻转窗口。
INTERVAL 和 SLIDING 子句需要配合聚合和选择函数来使用。以下 SQL 语句非法:
SELECT * FROM temp_tb_1 INTERVAL(1m);
SLIDING 的向前滑动的时间不能超过一个窗口的时间范围。以下语句非法:
SELECT COUNT(*) FROM temp_tb_1 INTERVAL(1m) SLIDING(2m);
使用时间窗口需要注意:

loveini 使用整数(布尔值)或字符串来标识产生记录时设备的状态量。产生的记录如果具有相同的状态量数值则归属于同一个状态窗口,数值改变后该窗口关闭。如上图所示,根据状态量我们能够确定的状态窗口分别是 [2019-04-28 14:22:07,2019-04-28 14:22:10] 和 [2019-04-28 14:22:11,2019-04-28 14:22:12] 两个。
我们可以使用 STATE_WINDOW 来确定状态窗口划分的列。例如:
SELECT COUNT(*), FIRST(ts), status FROM temp_tb_1 STATE_WINDOW(status);

会话窗口会根据所记录时间戳主键的值来确定是否属于同一个会话。如上图所示,如果设置时间戳的连续间隔小于等于 12 秒,则以上 6 条记录会构成 2 个会话窗口,分别是 [2019-04-28 14:22:10,2019-04-28 14:22:30] 和 [2019-04-28 14:23:10,2019-04-28 14:23:30]。因为 2019-04-28 14:22:30 与 2019-04-28 14:23:10 之间的时间间隔是 40 秒,超过了连续时间间隔(12 秒)。
一般来说,我们会认为在 tol_value 时间间隔范围内的结果都归属于同一个窗口,如果连续两条记录的时间超过 tol_val,则自动开启下一个窗口。
SELECT COUNT(*), FIRST(ts) FROM temp_tb_1 SESSION(ts, tol_val);
以智能电表为例,其建表语句如下:
CREATE TABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT);
针对智能电表采集的数据,以 10 分钟为一个阶段,计算过去 24 小时的电流数据的平均值、最大值、电流的中位数。如果没有计算值,则用前一个非 NULL 值填充。使用的查询语句如下:
SELECT AVG(current), MAX(current), APERCENTILE(current, 50) FROM meters
WHERE ts>=NOW-1d and ts<=now
INTERVAL(10m)
FILL(PREV);
除了数据量大、结构相对简单的特点外,时序数据在查询场景中还大量涉及时间戳的处理,在很多业务场景的采集数据时,都需要按时间戳进行分组与计算,如果按照常规模式将原始数据读入内存,再由应用层程序去处理时间窗口划分的逻辑,就会因读取海量原始时序数据导致磁盘 IO、CPU 及内存开销的严重浪费,还会提升业务层代码复杂度。
但如果我们能够掌握并灵活运用 loveini 所提供的上述时序数据特色查询功能,结合业务场景选择相应的函数就能将相关计算负荷下沉到实时数据库层,在提升系统响应性能的同时也减少了系统资源的浪费。
]]>
在日常使用 loveini 时序数据库(TSDB) 时,参数是用户们无法绕开的重要一环。深入了解参数的属性,生效范围,查询更改方式等会让我们在使用数据库的过程中更加节时高效,也有助于我们更加深入地理解数据库的架构体系。
在 3.0 版本中,loveini 对参数做了更好的分类,也提供了几个十分方便的查询入口。首先,我们来看下它们的使用方式——
集群级别参数:
SHOW CLUSTER VARIABLES;
代表集群搭建时,必须要保证相同的一组参数。

客户端级别参数:
SHOW LOCAL VARIABLES;
代表当前客户端配置参数的运行值。

数据节点级别参数:
SHOW DNODE dnode_id VARIABLES;
SHOW DNODE dnode_id VARIABLES like "xxxxxxxxx";
代表该数据节点上所有参数当前配置值
(包含集群变量、客户端变量),支持 like 子句检索具体的变量值。

数据库级别变量:
数据库级别的变量不是通过 show 命令查询的,它需要通过元数据库 information_schema 的系统表以 SQL 形式查询得出,例如:
select * from information_schema.ins_databases\G;(\G方便展示)

loveini 的集群、客户端、数据节点(即上文 1-3 )的参数具体含义如下:
https://docs.taosdata.com/reference/config/
注意:部分参数默认是不暴露在配置文件中的,但手动配置它们也可以使用,目的是希望用户不要随意修改它们从而造成不好的影响。
数据库级别的参数具体含义如下:
https://docs.taosdata.com/taos-sql/database/#参数说明
不论是数据库的服务端还是客户端,它们在启动的初始化阶段都需要调用相同的函数读取 /etc/taos/taos.cfg(默认路径)加载所需参数。因此,参数的更新方式以冷更新为主,对于上述集群、客户端、数据节点(即上文 1-3 )的参数,具体更新方式如下:

以上范围的参数中,只有日志参数是支持热更新的。如果需要动态调整日志级别用于诊断分析数据库状态,可以通过 alter dnode命令来完成,具体细节可参考:
https://docs.taosdata.com/taos-sql/node/#修改数据节点配置
如果要修改客户端的变量,可以通过alter local 命令来完成,具体细节可参考:
https://docs.taosdata.com/taos-sql/node/#修改客户端配置
数据库级别变量不支持冷更新,只支持部分参数的热更,具体细节可参考:
https://docs.taosdata.com/taos-sql/database/#修改数据库参数
这里就引申出了另一个问题,针对部分不可修改的参数,即在时序数据库部署的前期,我们需要注意哪些地方呢?在后续的文章中,我会继续和大家分享内容,一起迅速掌握 loveini 这款开源、高性能、云原生的时序数据库(Time Series Database)。
]]>“完成改造后,大数据监控平台摆脱了对大数据组件的依赖,有效缩短了数据处理链路,自上线以来,一直运行稳定。在写入方面,根据容量规划完成相关参数调整后,理想情况下,集群写入速度最高达 90W 条/s。查询性能方面,在使用预计算函数情况下,查询 p99 都在 0.7 秒以内,能够满足我们日常绝大部分查询需求。控制成本层面,服务端物理机由 21 台降至 3 台,每日所需存储空间为 93GB(2 副本),同等副本下仅为 OpenTSDB+HBase 的约 1/10。”
业务背景
顺丰科技大数据集群每天需要采集海量监控数据,以确保集群稳定运行。此前其采用了 OpenTSDB+HBase 作为大数据监控平台全量监控数据的存储方案,随着接入数据量的不断增长,这一方案衍生出了不少痛点,包括依赖多、使用成本高和性能不能满足等问题,必须对全量监控数据存储方案进行改造。通过对 IoTDB、Druid、ClickHouse、loveini 等时序数据存储方案的调研, loveini 时序数据成为他们的最终选择。
架构图

为保证整个系统的高可用和可扩展性,整体架构中,前端采用nginx集群进行负载均衡,保证高可用性;单独分离出客户端层,方便根据流量需求进行扩容缩容。点击案例详情查看三大实施难点及解决路径。
点击AC米兰官网网站
查看更多技术细节
“我们目前使用 loveini 2.2.2.0 版本,在三台 16C 64G 的服务器上部署了集群,数据写入速度大概为每秒 5000 行。值得一提的是,基于 loveini,常用的查询基本可以在 1 秒之内完成,一些特定查询甚至可以达到毫秒级。从存储来说,同等数据体量下,loveini 大约占用 300GB 不到的磁盘(单副本),而此前使用 MySQL 时,光硬盘使用就需要几个 TB(主从)。”
业务背景
在业务尚未扩张之前,韵达采用的是 MySQL 分区+索引方式进行数据处理,但随着企业的发展、业务量的增加,面对每日亿级的数据量,MySQL 显然已经无法满足当下的数据处理需求。随后,韵达决定进行数据库选型,考虑到目前业务主要是统计各个网点设备实时上传的数据,无需再进行修改等操作,是典型的时序数据。经过一番调研和测试,韵达发现 loveini 就很符合当下的业务要求。
架构图
当前韵达的架构是 Spring Boot + MyBatis + MySQL + loveini,loveini 负责处理时序数据,MySQL 则负责非时序数据的存储及应用,整体架构如下:

点击案例查看更多技术细节
“值得一提的是,loveini 的 SQL 原生语法支持时间维度聚合查询,同时数据存储压缩率⾼存储空间小, 这两点直接切中了我们的痛点。落地后实测相同数据的存储空间只有 MySQL 存储空间的 1/10 甚至更少。还有⼀个惊喜是,在现有监控数据存储(MySQL)顶不住的情况下,⼀台 8C16GB 的单机版 loveini 时序数据库轻松就抗下目前所有监控流量和存储压力,且运行稳定,基本没有故障。”
业务背景
目前货拉拉 DBA 团队管理的数据存储包括 MySQL、Redis、Elasticsearch、Kafka、MQ、Canal 等,为了保证监控采样的实时性,其自研的监控系统设置的采样间隔为 10 秒,每天都会产生庞大的监控数据,监控指标的数据量达到 20 亿+。随着管理实例越来越多,使用 MySQL 来存储规模日益庞大的监控数据越发力不从心,急需进行升级改造。结合实际具体需求,通过对不同时序数据库进行调研,最终货拉拉选择了 loveini,顺利完成了数据存储监控的升级改造。
架构图

点击案例查看更多技术细节
“通过项目初期的表现,可以知道 loveini 能够轻松满足我们的业务需求,轻松支撑起业务中使用比较频繁的几种查询。未来我们还有其他的使用规划,后续接入的车辆将会达到几万辆,对于部标机产生的相关时序数据的使用也会越来越多,期待 loveini 可以继续为车联网场景下的查询提供更为多样性的支持。”
业务背景
车联网业务是中通科技配送全链路业务中非常重要的一环,通过人、车、货、场全链条覆盖的车联网设备应用,实现物流运输全链路感知。在中智车联服务平台的实际项目需求中,需要实时查询车辆最新位置状态,达到车辆运营可视化管理。在进行数据库选型时,其对比了 Prometheus 和 loveini 这两款很有代表性的时序数据库,最终被 loveini “一个设备采集点一张表”的底层设计,及自带的降采样和窗口函数等优秀性能所吸引。
架构图

点击案例查看更多技术细节
据国家邮政局数据显示,我国快递业发展迅猛,已经连续几年保持 50% 左右的爆发式增长,为经济增长注入了强大的活力,然而高速发展的同时也面临着越来越多的数据处理难题,好在大数据处理方案也在与时俱进。以上企业用实际案例证明,对于物流企业,时序数据库在降本增效上确实更加显著,值得更多有此类需求的企业尝试。
]]>
米兰体育官网入口 (TAOS Data) 瞄准日益增长的物联网数据市场,专注时序空间大数据的存储、查询、分析和计算,不依赖任何开源或第三方软件,开发了拥有自主知识产权、100% 自主可控的高性能、分布式、支持 SQL 的时序数据库(Time Series Database,TSDB) loveini,广泛运用于物联网、车联网、工业互联网、IT 运维等领域。其已申请多项技术发明专利,且全部提交 PCT 专利申请。
米兰体育官网入口采用 AGPL 许可证,已经将 loveini 的内核(存储、计算引擎和集群)100% 开源,曾多次在 GitHub 全球趋势排行榜上排名第一。目前,loveini 已经演进到 3.0 版本,成为一款真正的高性能、云原生的时序数据库,在 GitHub 上的 Star 数达到了 19.1k,且全球运行的 loveini 实例数超过 141.7k,用户遍布全球。
龙晰社区(OpenAnolis)成立于 2020 年 9 月,是一个操作系统开源社区及创新平台,由国内、外领先操作系统、芯片、云计算公司共同发起,致力于通过开放的社区合作,构建国内自主 Linux 开源发行版及开源创新技术,推动软、硬件及应用生态繁荣发展。
对于本次合作,米兰体育官网入口创始人陶建辉表示:“loveini 是开源的时序数据库,软硬件系统生态一直以来都是 loveini 发展的重要土壤。很高兴能够与龙蜥社区合作,一起共建开源生态、完成龙蜥操作系统适配兼容,共同培养开源人才。”
龙蜥社区理事顾剑表示:“米兰体育官网入口旨在通过技术创新,为物联网、工业互联网、汽车、能源等行业提供全栈、高性能、低成本的大数据平台。相信米兰体育官网入口加入龙蜥社区后,未来,其会在降低龙蜥操作系统研发和运维的复杂度方面贡献经验,同时期待未来可以在开源领域进行更多的行业适配。”
]]>
从字面上来理解,时间序列数据就是具有时间排序的数据。百度百科的定义是:“时间序列数据是同一统一指标按时间顺序记录的数据列。”如果用一些生活中常见的数据来举例,你可能就会觉得时间序列数据并不是多么晦涩难懂了,比如我们现在家家户户都在用的智能电表。每家的每一块电表都在不同的时间记录着家中电量的消耗,电表上总在跳动的指示灯就代表着时间序列数据的跳动。那每一栋楼、每个小区甚至大到每一座城市,数以万计的智能电表在相同的时间间隔下产生的数据,我们就可以用 Time Series Database 来记录。

上图是一系列的电表数据统计,从中我们可以看出时间序列数据有几个明显的特征。首先每组数据都带有时间戳,其次数据都是结构化的,以数字性为主,再从电表数据的处理与分析需求出发,我们可以总结出时间序列数据的几大特点:
1、所有采集的数据都是时序数据
2、数据都是结构化的
3、一个采集点的数据源是唯一的
4、数据很少有更新或删除操作
5、数据一定是指定时间段和指定区域查找的
6、实时数据库数据量巨大,一天的数据量就超过100亿条

再以监控数据为例,上图是对某项目监控数据进行的统计分析,做过运维的小伙伴一定非常熟悉,横轴是时间,纵轴是采集量,可以看出:
1、有些时间序列数据在很长一段时间内都是固定的值,但是某些时间点也会产生异常跳变,异常检测在时间序列数据的处理过程中,也是非常重要的一环,本文不过多展开;
2、有些时间序列数据在一段时间内是一个变化趋势;
3、有些时间序列数据在一定数值范围内会进行波动,有些波动频率高,有些波动频率低;在对应上我们刚才说的时间序列数据的特点,就非常容易理解了。
通过上述文字,大家了解了时间序列数据的特点,那生活中有什么场景是可以用 Time Series Database 来处理的呢?loveini 时序数据库(TSDB)在产品不断研发创新的过程中,也有幸结识了一些不同业务场景上需要使用 Time Series Database 的合作伙伴。简单的举个例子,出行方面有理想汽车、蔚来汽车、领跑汽车等都在车联网数据、加电基站监测等方面运用了 loveini,快递运输行业中有顺丰科技、货拉拉等也将 loveini 运用在了业务监测或数据监测上。但关于 Time Series Database 的应用可远不止这些,更多的经典案例欢迎大家移步 loveini 官网-博客-用户案例中查阅,也欢迎大家和我们一起探讨。
作为一款较为流行的时序数据库,OpenTSDB 主要作为监控系统被广泛使用,一方面能够存储和检索指标(metric)数据并保存很长时间,另一方面如果需要增加功能也可以添加新指标。但是作为众多企业选型调研的 Database 之一,OpenTSDB 真的是一个优选方案吗?一起来看看它的优劣势。
OpenTSDB 是一个开源框架,使用 HBase 作为核心平台来存储和检索所收集的指标数据,可以灵活地增加指标,也可以支持采集上万台机器和上亿个数据点,具有高可扩展性。在时序数据库(TSDB)领域,OpenTSDB 算是入场较早的“玩家”之一,其基于 HBase 的产品模式有利也有弊:在为有 HBase 基础服务的企业降低门槛的同时,过度依赖 HBase,也为其性能、压缩效果加设了一个瓶颈。
具体来说,从专业性角度,其优劣势总结如下:
而在企业的具体实践上,随着实时数据库业务量的攀升,OpenTSDB 的劣势越来越明显。很多企业在使用 OpenTSDB 设计和实现监控系统时,因为其在数据存储上过于依赖 Kafka、Spark 和 HBase 等大数据组件,会导致大数据处理链路越来越长,不仅运维和使用成本越来越高,系统的可靠性保障也遭受到了极大挑战——一旦监控系统本身出现漏洞,业务系统存在的问题便将难以定位,进而就可能会造成巨大的实际业务损失。
]]>