• InfluxDB 内存消耗分析及性能优化


    目录

    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>>

    保存每个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结构:

    >
    >
    >
    可以发现同一个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监控)【干货】 - 掘金

  • 相关阅读:
    java毕业设计图书个性化推荐系统mybatis+源码+调试部署+系统+数据库+lw
    使用flutter的Scaffold脚手架开发一个最简单的带tabbar的app模板
    VM系列振弦采集模块传感器激励方法
    实现本地访问云主机,以及在云主机搭建FTP站点
    应用层DoS
    MQ(二)RabbitMQ快速入门
    【网络安全】修改Host文件实现域名解析
    【云原生之Docker实战】使用Docker部署jenkins持续集成工具
    6、ByteBuffer内部结构
    在c++11 的unordered_set和unordered_map中插入pair或tuple作为键值
  • 原文地址:https://blog.csdn.net/Daybreak1209/article/details/125989031