Influxdb WAL写性能优化

现象

我们网关的metrics数据的存储用的是时序数据库influxdb,每天500亿的调用量,30秒一个点,有很多维度的监控,应用,接口,机器,域名维度,机房维度,响应码,等等指标的统计,用了2台influxdb,分别负责不同的mertics存储。

经常出现写influxdb慢,导致监控数据延迟,影响监控和报警,我们是怀疑influxdb写wal日志性能问题引起的,现在chatgpt这么活,也是先和chatgpt 请教了一番,说怎么优化,chatgpt 提到了influxdb 和wal
相关的一个优化参数:wal-fsync-delay, 官方的解释是:

# The amount of time that a write will wait before fsyncing.  A duration
  # greater than 0 can be used to batch up multiple fsync calls.  This is useful for slower
  # disks or when WAL write contention is seen.  A value of 0s fsyncs every write to the WAL.
  # Values in the range of 0-100ms are recommended for non-SSD disks.
  wal-fsync-delay = "10ms"

官方建议0-100ms,这个事我们后来改为10ms,

chatgtp的解析是:

wal-fsync-delay是InfluxDB中的一个参数,用于控制WAL文件的持久化策略。

WAL是InfluxDB中的Write-Ahead-Log,即先写入WAL文件,再写入内存。这种方式可以提高写入性能,但也存在一定的风险,因为WAL文件在发生故障时可能会导致数据的丢失。因此,InfluxDB提供了wal-fsync-delay参数来控制WAL文件的持久化策略,从而在性能和数据安全之间做出平衡。

具体来说,wal-fsync-delay参数控制了WAL文件的持久化延迟时间,即多久将WAL文件中的数据写入磁盘。默认情况下,wal-fsync-delay参数设置为0,表示每次写入WAL文件后立即将数据写入磁盘。这种方式可以保证数据的安全性,但也会对写入性能造成影响。

如果将wal-fsync-delay参数设置为正整数,则表示延迟一定的时间后才将WAL文件中的数据写入磁盘。例如,将wal-fsync-delay设置为100ms,则表示每次写入WAL文件后,等待100ms再将数据写入磁盘。这种方式可以提高写入性能,但也会增加数据丢失的风险。

就是必须大于0,write 操作等待这个delay的时间,因为这个配置项是fsync delay,我们知道wal日志刷盘必须要做系统调用fsync操作,才能保障日志到真正持久化到磁盘,否则只是在os的缓冲区,机器挂了还是会丢数据,所以当时我们理解是越延迟fsync,性能就越高,因为默认是写一次就刷一次,这样会影响性能。

而且这个配置默认是100ms,按照chatgpt的理解,所以我们调大到1s,也就是想1s刷一次盘,但是改完后,写入操作反而越来越慢,监控延迟越来越大。没办法,只能改回去

后来看了influxdb的代码:

func (l *WAL) scheduleSync() {
    // If we're not the first to sync, then another goroutine is fsyncing the wal for us.
    if !atomic.CompareAndSwapUint64(&l.syncCount, 0, 1) {
        return
    }

    // Fsync the wal and notify all pending waiters
    go func() {
        var timerCh <-chan time.Time

        // time.NewTicker requires a > 0 delay, since 0 indicates no delay, use a closed
        // channel which will always be ready to read from.
        if l.syncDelay == 0 {
            // Create a RW chan and close it
            timerChrw := make(chan time.Time)
            close(timerChrw)
            // Convert it to a read-only
            timerCh = timerChrw
        } else {
            t := time.NewTicker(l.syncDelay)
            defer t.Stop()
            timerCh = t.C
        }
        for {
            select {
            case <-timerCh:
                l.mu.Lock()
                if len(l.syncWaiters) == 0 {
                    atomic.StoreUint64(&l.syncCount, 0)
                    l.mu.Unlock()
                    return
                }

                l.sync()
                l.mu.Unlock()
            case <-l.closing:
                atomic.StoreUint64(&l.syncCount, 0)
                return
            }
        }
    }()
}

每个写请求都会调用scheduleSync() 函数

经过分析代码,发现这个参数如果配置100ms,那每个请求都会等待100ms,等100ms内的写请求一起刷盘,最后返回,不知道influxdb为啥这样设计,每个写请求还要wait,不是我们认为的写可以立即返回,只是刷盘延迟100ms

分析出了这个问题,我们把wal-fsync-delay 参数调整为10ms,果然监控监控就不在延迟了,而且实时性也提高了,之前不出问题,正常延迟在2分钟,现在延迟只有30秒了,明显提高了写性能。

另外,我们也想直接关闭influxdb的wal日志,因为我们事监控数据,挂了丢了数据也能接受,只有写得快,influxdb 需要更高的版本才能支持关闭,我们的版本还不支持。

另外聪明的同学也会问,为啥不用vm存储引擎,不错,vm存储引擎就事不写wal日志的,所以事mertics的最合适的存储引擎了,我们的rpc 服务的监控目前就事用的这个,非常稳定,我们只是目前没有时间来迁移,后面是要迁移到vm的。

所以现在chatgpt 是很火,但他的答案我们还是要辩证分析,才能用之。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容