1. 背景
某些设备随着时间产生的实时数据,没有关联查询的需要。数据量是每秒12条,每条不超过256Bytes,每天100万条,存储90天,9KW条。查询访问并发数也就在10个/秒左右,感觉这种容量在避开时间段范围太大的情况后,采用MySQL分库、分表的话,满足存储和查询也是没问题的,但还是很想试试时序数据库,既能够满足现状,也可以hold住未来不同的容量。
2. 准备
一直想试试国产的TDengine,正好这次学习了下她的白皮书。考虑到存量用户数量和文档,先选择了在一台机械硬盘服务器上搭建好了influxdb v2.3.0 docker环境。代码中SDK采用官方的influxdb-client-go,通过TDengine白皮书了解到时序数据库为提高根据时间查询的效率,有几个建议:
- 每个设备一张表,即使多个设备的数据格式一模一样。从而避免根据设备Id来条件查询。
- 表中不同的列也存储在不同的独立空间。
- 推荐SSD作为存储设备,通常IOPS要求不低于1000MB/S。
这些要求对于Influxdb也一样,比如v1.8版本的硬件要求:https://docs.influxdata.com/influxdb/v1.8/guides/hardware_sizing/, 虽然没搜索到v2.3.0对硬件的要求,但看这个链接:https://community.influxdata.com/t/hardware-recommendations-for-influxdb-2-0-in-production/18360,v2.0和v1.8的硬件配置一样,v2.3.0可能也差不多。
3. 问题
自测时发现当以1条/秒的速度写入数据时,存在不能及时查询到最新数据的情况,改为调用SDK中WriteAPIBlocking()来保障每次都写入而不延迟,效果就好多了。同时也暴露了阻塞/延迟写入的配置参数。
等发布到测试环境,很块导致Linux物理主机的内存被buff/cache耗尽,从而其他服务不正常,并且iostat -mtx 2显示util很高,就改为5秒发送一次数据来,刚开始还行,24小时后还是出现相同问题。用下面命令倒是也可以显著清理:
echo 1 /proc/sys/vm/drop_caches
其他小伙伴使用过windows上的v1.7.8,演示每秒写入100条都没问题,落盘也很快。于是有如下考虑:
- 阻塞写入导致每次都触发磁盘IO,可用合并写入。
- 机器的磁盘太慢。
就先好好看了SDK代码,把合并写入的详细参数暴露出来配置,在本地测试1条/秒的数据量,连续12小时都正常。
4. 真相
第2天得知influxdb相关的锅,其他软件在保存视频录像。遂暂时放下性能探究。
5. 印象点
- 磁盘再慢,往往也不会0.2条/秒数据的插入都有问题,应该早点怀疑到有其他原因导致系统内存耗尽。
- influxdb文档很全面,v2之后不再采用SQL语法,使得没法被Go语言自带database/sql来兼容,还需要独立的SDK接入。有的网友推荐Clickhouse。v2采用的flux语法怪怪,还得重新学习。
- influxdb存储书数据时采用UTC时间,也就是你插入中国时区UTC+8时间数据,她会根据系统时区做转换,导致查询时用中国时区时间的结果不对。但按理influxdb系统时区如果是UTC就不应该有这个问题,没再细究了。
- 官方的influxdb-client-go(https://github.com/influxdata/influxdb-client-go)在合并写入Write.go功能实现中,有2个协程,一个做buffer合并,一个调用Service.go做实际写入,由于Service.go的核心代码没有加锁,所以如果调用者中途主动调用Write.Flush(),看上去出现问题。提了个issuecoroutine safe in internal/write/service.go,也得到了官方确认。