influxdb内存消耗分析及性能优化(代码片段)

钟艾伶 钟艾伶     2022-11-30     532

关键词:

目录

SERIES CARDINALITY 序列基数

什么是SERIES CARDINALITY

cardinality的计算

查看db序列基数

数据

一个sql查询的执行过程

查询语句

数据读取的流程

基于内存的倒排索引

作用

核心数据结构及其作用

举个例子:

优缺点

基于磁盘的倒排索引-TSI文件

TSI文件的作用

TSI文件的结构

Influxdb中基于磁盘的倒排索引文件TSI结构解析

Time Series Index (TSI) details

内存消耗分析及性能优化

show stats 查看内存使用情况

提出猜想

验证猜想

Go runtime内存释放机制:

性能优化:

线上验证

TODO


SERIES CARDINALITY 序列基数

什么是SERIES CARDINALITY

cardinality反应了series的维度,即不同的series的数量。

序列基数是影响内存(RAM)使用量的主要因素。

cardinality的计算

某个measuremnt的cardinality值 = distinct(tag1value) * distinct(tag2value) * ...也就说所有tag可能取值的乘积。

When influxdb counts cardinality in a Measurement, 
it counts the combination of all tags. 

For example, if my measurement has the following tags: 
3 os, 200 devices, 3 browsers, 
then the cardinality is > 3x200x3=1800. 

查看db序列基数

SHOW SERIES CARDINALITY on db  查看某db的series维度数量
-- show estimated cardinality of the series on current database
SHOW SERIES CARDINALITY

-- show estimated cardinality of the series on specified database
SHOW SERIES CARDINALITY ON mydb

-- show exact series cardinality
SHOW SERIES EXACT CARDINALITY

-- show series cardinality of the series on specified database
SHOW SERIES EXACT CARDINALITY ON mydb

数据

> SHOW SERIES CARDINALITY on appMetrics
cardinality estimation
----------------------
105336
> SHOW SERIES CARDINALITY on hardWareMetrics
cardinality estimation
----------------------
10703

> SHOW SERIES EXACT CARDINALITY ON hardWareMetrics
name: burrow_group
count
-----
112

name: disk
count
-----
14256

name: diskio
count
-----
3920

name: influxdb_database
count
-----
40

name: influxdb_httpd
count
-----
8

name: influxdb_shard
count
-----
1905


一个sql查询的执行过程

查询语句

select sum(pc) from advertise
where publisher=‘atlasdata’ and platform = ‘baidu’
and time>='2018-08-01' and time <'2018-09-01'

数据读取的流程

  1. 第一步:找出atlasdata发布在baidu的所有广告的seriesKey
  2. 第二步:根据seriesKey找到这些广告2018年8月份的数据,通过时间范围确定存储2018年8月份数据的shardgroup, 再根据seriesKey进行hash找到shardgroup下存储这些数据源的shard
  3. 第三步:找出这些数据中的pc端的数据,扫描每个shard中的TSM文件中的index block,找到符合条件的data block,再在data block中把符合条件的所查询的数据筛选出来进行聚合
    提问: ??如何找到所有广告的seriesKey、?倒排索引

倒排索引

一个未经处理的数据库中,一般是以文档ID作为索引,以文档内容作为记录。

而Inverted index (倒排索引、反向索引)指的是将单词或记录作为索引,将文档ID作为记录,这样便可以方便地通过单词或记录查找到其所在的文档。

场景

文档——>关键词

但是这样检索关键词的时候很费力,要一个文档一个文档的遍历一遍。

于是人们发明了倒排索引~从关键词到文档的映射

关键词——>文档

这样,只要有关键词,立马就能找到关键词在哪个文档里出现过

基于内存的倒排索引

作用

提高数据源维度的查询效率:找出符合查询条件的所有数据源的seriesKey

核心数据结构及其作用

  • map<tagkey, map<tagvalue, List<SeriesID>>>

保存每个tag对应的所有值对应的所有seriesID,通过条件(比如 tag1='value')获取满足条件的所有数据源的唯一标识

tagkey: 数据源属性名称

tagvalue: tagkey所指属性的值

SeriesID:满足tagkey=tagvalue的所有数据源的唯一标识,seriesID与数据源唯一标识SeriesKey一一对应

  • map< SeriesID,SeriesKey>

保存seriesID和SeriesKey的映射关系,通过seriesID获取seriesKey

为什么第一个双重map中不直接用SeriesKey呢?是为了节省内存空间.

举个例子:

假如现在有3个Tag组合形成一个seriesKey:measurement=m_name,tag_1=value_1,tag_2=value_2,tag_3=value_3。那么构造形成的双重map结构:

<tag_1, <value_1, seriesKey>>
<tag_2, <value_2, seriesKey>>
<tag_3, <value_3, seriesKey>>
可以发现同一个seriesKey在内存中有多份冗余,而且seriesKey = measurement + tags,随着tag值的增加,内存消耗非常明显,因此为了节省内存消耗,采用Int对seriesKey进行编码,代替双重map中的seriesKey

优缺点

优点

  •      加快数据源维度的查询效率

缺点

  • 受限于内存大小
  •  一旦InfluxDB进程宕掉,需要扫描解析所有TSM文件并在内存中重新构建,恢复时间很长。

基于磁盘的倒排索引-TSI文件

InfluxDB实现了基于磁盘的倒排索引,用TSI文件来存储索引信息

TSI文件的作用

提高数据源维度的查询效率:找出符合查询条件的所有数据源的seriesKey,并解决内存索引受限于内存大小、恢复时间长的问题。

TSI文件的结构

 Measurement Block

           找到对应的measurement信息,并获取表的tag对应的Tag block的offset/size

Measurement Block结构:

Measurement Block由三大部分组成

  • Block Trailer : 记录各模块的offset和size
  • HashIndex : 记录每个measurement的偏移量
  • Mesurement : 记录具体表的信息,包括表的名称、所有tag对应的Tag Block的offset和size等

Measurement Block的扫描流程如下:

  • 首先在TSI文件的Index File Trailer部分获取整个Mesurement Block的offset和size,
  • 然后再根据Measurement Block中的Block Trailer和Hash Index确认要查询的表对应的Measurement的位置,
  • 读取对应的Measurement中的Tag Block的offset和size

Influxdb中基于磁盘的倒排索引文件TSI结构解析

Influxdb中基于磁盘的倒排索引文件TSI结构解析 - 腾讯云开发者社区-腾讯云

Time Series Index (TSI) details

InfluxDB stores measurement and tag information in an index so data can be queried quickly.
In earlier versions, the index was stored in-memory, requiring a lot of RAM and restricting the number of series that a machine could hold (typically, 1-4 million series, depending on the machine).
Time Series Index (TSI) stores index data both in memory and on disk, removing RAM restrictions. This lets you store more series on a machine. TSI uses the operating system’s page cache to pull hot data into memory, leaving cold data on disk.

内存消耗分析及性能优化

index-version = "inmem"

inmem:基于内存

tsi1:基于磁盘


The default (inmem) index is an in-memory index that is recreated at startup. To enable the Time Series Index (TSI) disk-based index, set the value to tsi1.

show stats 查看内存使用情况

> show stats
name: runtime
Alloc      Frees     HeapAlloc  HeapIdle   HeapInUse  HeapObjects HeapReleased HeapSys    Lookups Mallocs   NumGC NumGoroutine PauseTotalNs Sys        TotalAlloc
-----      -----     ---------  --------   ---------  ----------- ------------ -------    ------- -------   ----- ------------ ------------ ---        ----------
1453852384 218795736 1453852384 1682595840 1571332096 9628928     0            3253927936 178461  228424664 96    334          784143583    3418348024 55161719256

name: queryExecutor
queriesActive queriesExecuted queriesFinished queryDurationNs recoveredPanics
------------- --------------- --------------- --------------- ---------------
1             73169           73168           27803545203003  0


name: database
tags: database=_internal
numMeasurements numSeries
--------------- ---------
12              1283

name: database
tags: database=metrics
numMeasurements numSeries
--------------- ---------
862             105336

name: database
tags: database=telegraf
numMeasurements numSeries
--------------- ---------
40              10703



HeapIdle:1.6G
HeapInUse:1.5G
HeapReleased:0g

按照go的内存分配空间布局规则,可以根据如下计算方式估计go的当前堆内存:

(HeapIdle)1.6-(HeapReleased)0+(HeapInUse) 1.5= 0.1G

提出猜想

???为什么进程RES实际占用12G, 而当前进程runtime堆占用内存仅有0.1G ???

 猜想:目前influxd进程持有的有效内存为 0.1G, 而系统进程RES为12G。猜想存在12-0.1=12g的内存,进程标记不再使用,系统也没有进行回收。

验证猜想

模拟一个进程,像操作系统申请占用12g内存,再top ,发现influxd占用0.1G内存,模拟程序占用12G内存

Go runtime内存释放机制:

linuxMADV_DONTNEED:释放内存效率低,但会让RSS数量下降很快(表象数据释放了,但实际还在慢慢释放,并未立即释放所有idle的内存)

MADV_FREE:释放内存更勤快,更高效。但RSS不会立刻下降,而是要等到系统有内存压力了,才会延迟下降。优化参数GODEBUG=madvdontneed=1 

一直以来 go 的 runtime 在释放内存返回到内核时,在 Linux 上使用的是 MADV_DONTNEED,虽然效率比较低,但是会让 RSS(resident set size 常驻内存集)数量下降得很快。不过在 go 1.12 里专门针对这个做了优化,runtime 在释放内存时,使用了更加高效的 MADV_FREE 而不是之前的 MADV_DONTNEED。

这样带来的好处是,一次 GC 后的内存分配延迟得以改善,runtime 也会更加积极地将释放的内存归还给操作系统,以应对大块内存分配无法重用已存在的堆空间的问题。不过也会带来一个副作用:RSS 不会立刻下降,而是要等到系统有内存压力了,才会延迟下降。为了避免像这样一些靠判断 RSS 大小的自动化测试因此出问题,也提供了一个 GODEBUG=madvdontneed=1 参数可以强制 runtime 继续使用 MADV_DONTNEED。

原来是由于go内部优化而使进程内存没有立即释放,解答了内存高消耗的疑惑。

性能优化:

  • influx使用 inmem 引擎时(默认),在retention policy时会消耗过高的内存
  • 使用 GODEBUG=madvdontneed=1 可以让go程序尽快释放内存

因此对配置文件influxdb.conf做了如下优化:

# 详细配置说明见官方文档
# https://docs.influxdata.com/influxdb/v1.8/administration/config/#data-settings
 
[data]
  #说明: wal预写日志log,用于事务一致性
  #默认为0,每次写入都落盘。
  #修改为1s, 根据业务场景,不保证强一致性,可采用异步刷盘
  #[优化点]:用于减轻磁盘io压力
  wal-fsync-delay = "1s"
   
  #说明: influx索引
  #默认为inmem,创建内存型索引,在delete retention会消耗过高内存
  #修改为tsi1, 注意重建tsi1索引(https://blog.csdn.net/wzy_168/article/details/107043840)
  #[优化点]:降低删除保留策略时的内存消耗
  index-version = "tsi1"
   
  #说明: 压缩TSM数据,一次落盘的吞吐量
  #默认48m
  #修改为64m
  #[优化点]:增大写入量,减轻io压力
  compact-throughput = "64m"

修改配置后,重启influx 

线上验证

influxd进程重新运行一周之后,再次观察系统状态

TODO

增加influx 中间件监控,监控cpu、内存、磁盘io 等服务器资源消耗情况,将排查过成功的数据可视化,直接web观测数据情况

REF :

influxdb内存消耗分析及性能优化【追踪篇】

InfluxDb高内存占用优化(Flink监控)【干货】

InfluxDb高内存占用优化(Flink监控)【干货】 - 掘金

influxdb内存消耗分析及性能优化(代码片段)

...基于磁盘的倒排索引-TSI文件TSI文件的作用TSI文件的结构Influxdb中基于磁盘的倒排索引文件TSI结构解析TimeSeriesIndex(TSI)details内存消耗分析及性能优化showstats查看内存使用情况提出猜想验证猜想Goruntime内存释放机制:性能优化:线... 查看详情

android性能优化之leakcanary的使用及项目中的实际运用(代码片段)

文章目录引言1.什么是内存泄露?2.内存泄漏造成什么影响?3.什么是LeakCanary?4.LeakCanary工作机制(原理)5.项目中的实际运用场景及分析方法6.总结引言Andorid项目中我们会使用第三方开源库来检查内存泄露情况,使用时我们得了解... 查看详情

markdownprofiling&profiler性能分析及优化(代码片段)

查看详情

iostableview性能优化及分析

....减少cell中控件的数量view对象尽量缩减控件的数量,避免消耗较多的资源,并且也影响渲染的性能,不适用就隐藏3.使用不透明视图避免消耗性能去渲染4.使用局部更新 如果只是更新某组的话,使用reloadSection进行局部更新5.... 查看详情

现代图片性能优化及体验优化指南(代码片段)

...、透明通道、动画、编解码性能、压缩算法、颜色支持、内存占用、兼容性方面,对比它们:图片类型Alpha通道动画编解码性能压缩算法颜色支持内存占用兼容性GIF支持支持较高无损压缩索引色(256)基本一致ALLPNG-8/PNG-24支持不支... 查看详情

android进阶——性能优化之bitmap位图内存管理及优化概述(代码片段)

...BitmapFactory.Options6、BitmapRegionDecoder7、BitmapShader三、Bitmap的内存1、图片的像素与内存四、位图的底层存储位置五、Bitmap的压缩1、**质 查看详情

android进阶——性能优化之bitmap位图内存管理及优化概述(代码片段)

...BitmapFactory.Options6、BitmapRegionDecoder7、BitmapShader三、Bitmap的内存1、图片的像素与内存四、位图的底层存储位置五、Bitmap的压缩1、**质 查看详情

android进阶——性能优化之bitmap位图内存管理及优化概述(代码片段)

...BitmapFactory.Options6、BitmapRegionDecoder7、BitmapShader三、Bitmap的内存1、图片的像素与内存四、位图的底层存储位置五、Bitmap的压缩1、**质 查看详情

android性能优化之利用leakcanary检测内存泄漏及解决办法(转)(代码片段)

利用LeakCanary检测内存泄漏及解决办法利用LeakCanary检测内存泄漏及解决办法什么是内存泄漏内存泄漏造成什么影响什么是LeakCanaryLeakCanary捕获常见内存泄漏以及解决办法错误使用单例造成的内存泄漏Handler造成的内存泄漏线程造成... 查看详情

android性能优化之内存泄漏检测以及内存优化(中)(代码片段)

上篇博客我们写到了Java/Android内存的分配以及相关GC的详细分析,这篇博客我们会继续分析Android中内存泄漏的检测以及相关案例,和Android的内存优化相关内容。  上篇:Android性能优化之内存泄漏检测以及内存优化&... 查看详情

android性能优化内存优化分析gc日志(代码片段)

...;会把相应消息会输出到Logcat中,可以看出来虚拟机的内存情况,这为我们做内存优化提供了另外一个可参考的依据,要尽量减少stoptheworld类型的GC。本文介绍如何查看GC日志,先做到看懂GC日志。Dalvik日志消息在Dal... 查看详情

android性能优化内存优化分析gc日志(代码片段)

...;会把相应消息会输出到Logcat中,可以看出来虚拟机的内存情况,这为我们做内存优化提供了另外一个可参考的依据,要尽量减少stoptheworld类型的GC。本文介绍如何查看GC日志,先做到看懂GC日志。Dalvik日志消息在Dal... 查看详情

硬核:jvm性能调优,有哪些好用的内存分析神器?(代码片段)

...访问量的电商、物联网、金融、社交等系统来说,JVM内存优化是非常有必要的,可以提高系统的吞吐量和性能。通常调优的首选方式是减少FGC次数或者FGC时间,以避免系统过多地暂停。FGC达到理想值后,比如一天... 查看详情

mysql系列-性能优化神器explain使用介绍及分析(代码片段)

...ySQL提供了一个EXPLAIN命令,它可以对 SELECT 语句进行分析,并输出 SELECT 执行的详细信息,以供开发人员针对性优化。 EXPLAIN命令用法十分简单,在SELECT语句前加上Explain就可以了,例如:EXPLAINSELECT*fromuser_infoWHEREid<300;下... 查看详情

ios性能优化-allocations分析内存分配(代码片段)

AllocationsAllocations用来分析静态内存分配。Demo项目DemoAppDemo是一个简单的图片应用:首页只有一个简单的入口;次级页面会读取本地图片,加滤镜,然后按照瀑布流的方式显示出来;第三个页面提供大图显示... 查看详情

redis性能调优——内存优化(代码片段)

本篇主要介绍Redis内存优化的一些技巧。1.内存消耗1、内存使用统计Redis可以通过infomemory命令来查看内存使用情况,属性说明如下:属性名属性说明used_memoryRedis分配器分配的内存量,也就是实际存储数据的内存总量use... 查看详情

android—性能优化2—内存优化(代码片段)

文章目录性能优化:工具:memoryprofilerLeakCanaryarthookepic库java内存管理机制java内存回收机制Android内存管理机制Dalvik与Art区别LowMemoryKiller内存抖动解决内存泄漏解决第一个内存泄漏点内存很大的bitmap第一个地方生成二维码的时候每隔... 查看详情

android进阶——性能优化之bitmap位图内存管理及优化(代码片段)

引言位图一、Bitmap概述Bitmap直接继承Object并实现了Parcelable接口,是用于描述图片内部像素、像素类型、像素内部存储的编码格式、长、宽、颜色等一系列描述信息的对象,是Android中一切图形图像与硬件关联的重要对象&#x... 查看详情