记一次victoriaMetrics代理性能优化问题

2022-05-13 00:00:00 集群 缓存 请求 指标 验证

近有做一个Prometheus metrics代理的一个小项目,暂称为prom-proxy,目的是为了解析特定的指标(如容器、traefik、istio等指标),然后在原始指标中加入应用ID(当然还有其他指标操作,暂且不表)。经过简单的本地验证,就发布到联调环境,跑了几个礼拜一切正常,以为相安无事。但自以为没事不代表真的没事。
昨天突然老环境和新上prom-proxy的环境都出现了数据丢失的情况,如下图:

prom-proxy有一个自服务指标request_total,经观察发现,该指标增长极慢,因而一开始怀疑是发送端的问题(这是一个误区,后面会讲为何要增加缓存功能)。
进一步排查,发现上游发送端(使用的是victoriaMetrics的vmagent组件)出现了如下错误,说明是prom-proxy消费的数据跟不上vmagent产生的数据:
2022-03-24T09:55:49.945Z warn VictoriaMetrics/app/vmagent/remotewrite/client.go:277 couldn't send a block with size 370113 bytes to "1:secret-url": Post "xxxx": context deadline exceeded (Client.Timeout exceeded while awaiting headers); re-sending the block in 16.000 seconds
出现这种问题,首先想到的是增加并发处理功能。当前的并发处理数为8(即后台的goroutine数目),考虑到线上宿主机的core有30+,因此直接将并发处理数拉到30。经验证发现毫无改善。
另外想到的一种方式是缓存,如使用kafka或使用golang自带的缓存chan。但使用缓存也有问题,如果下游消费能力一直跟不上,缓存中将会产生大量积压的数据,且Prometheus监控指标具有时效性,积压过久的数据,可用性并不高又浪费存储空间。
下面是使用了缓存chan的例子,s.reqChan的初始大小设置为5000,并使用cacheTotal指标观察缓存的变更。这种方式下,数据接收和处理变为了异步(但并不完全异步)。
上面一开始有讲到使用request_total查看上游的请求是个误区,是因为请求统计和请求处理是同步的,因此如果请求没有处理完,就无法接收下一个请求,request_total也就无法增加。

func (s *Server) injectLabels(w http.ResponseWriter, r *http.Request) {     data, _ := DecodeWriteRequest(r.Body)     s.reqChan <- data     cacheTotal.Inc()     w.WriteHeader(http.StatusNoContent) }  func (s *Server) Start() {     go func() {         for data := range s.reqChan {             cacheTotal.Dec()             processor := s.pool.GetWorkRequest()             go func() {                 processor.JobChan <- data                 res := <-processor.RetChan                 if 0 != len(res.errStr) {                     log.Errorf("err msg:%s,err.code:%d", res.errStr, res.statusCode)                     return                 }             }()         }     }() }

相关文章