背景
由于Prometheus自身容量有限,不适合存储大量数据,所以需要将数据写入远端存储。由于我对ES比较熟悉,所以选择了ES作为远端存储,adapter为 prometheus-es-adapter。
环境搭建好后,很快就看到ES中已经有数据流入,就以为大功告成了,但第二天发现数据只写了半个小时就中断了。
1.增大cpu和内存
通过初步排查后,发现是 prometheus-es-adapter
挂掉了,原因是OOMKilled(内存溢出),所以就将cpu增加到1000m,内存增加到1Gi,之后运行正常了。
但观察半天后,发现数据写入经常出现长时间间断,如下图:
2. 增大队列容量
由于我目前对Prometheus接触还比较少,于是带着问题去请教运维同学,运维同学检查完Prometheus配置后,指出可能是remote_write.queue_config.capacity
设置过小,导致大量数据来不及写入ES而被丢弃。下面默认capacity是10:
remote_write:
- url: http://prometheus-es-adapter-service.kube-system.svc.cluster.local:8000/write
remote_timeout: 30s
queue_config:
capacity: 10 # 默认capacity是10
max_shards: 1000
min_shards: 1
max_samples_per_send: 100
batch_send_deadline: 5s
min_backoff: 30ms
max_backoff: 100ms
于是我将remote_write.queue_config.capacity
增大为1000:
remote_write:
- url: http://prometheus-es-adapter-service.kube-system.svc.cluster.local:8000/write
remote_timeout: 30s
queue_config:
capacity: 10000 # capacity设置为10000
max_shards: 1000
min_shards: 1
max_samples_per_send: 100
batch_send_deadline: 5s
min_backoff: 30ms
max_backoff: 100ms
3. 启动调试
但发现并没有起作用。这是把这个过程看成是生产者-消费者模式的话,那Prometheus
就是生产者,prometheus-es-adapter
是消费者,既然问题不在Prometheus,很可能就在prometheus-es-adapter
这边。于是我按照说明文档,设置环境变量DEBUG=true
开启调试模式。
Env Variables | Default | Description |
---|---|---|
ES_URL | http://localhost:9200 | Elasticsearch URL |
ES_USER | Elasticsearch User | |
ES_PASSWORD | Elasticsearch User Password | |
ES_WORKERS | 1 | Number of batch workers |
ES_BATCH_MAX_AGE | 10 | Max period in seconds between bulk Elasticsearch insert operations |
ES_BATCH_MAX_DOCS | 1000 | Max items for bulk Elasticsearch insert operation |
ES_BATCH_MAX_SIZE | 4096 | Max size in bytes for bulk Elasticsearch insert operation |
ES_ALIAS | prom-metrics | Elasticsearch alias pointing to active write index |
ES_INDEX_DAILY | false | Create daily indexes and disable index rollover |
ES_INDEX_SHARDS | 5 | Number of Elasticsearch shards to create per index |
ES_INDEX_REPLICAS | 1 | Number of Elasticsearch replicas to create per index |
ES_INDEX_MAX_AGE | 7d | Max age of Elasticsearch index before rollover |
ES_INDEX_MAX_DOCS | 1000000 | Max number of docs in Elasticsearch index before rollover |
ES_INDEX_MAX_SIZE | Max size of index before rollover eg 5gb | |
ES_SEARCH_MAX_DOCS | 1000 | Max number of docs returned for Elasticsearch search operation |
ES_SNIFF | false | Enable Elasticsearch sniffing |
STATS | true | Expose Prometheus metrics endpoint |
DEBUG | false | Display extra debug logs |
可以看到有日志正常输出,说明prometheus-es-adapter确实接收到了数据,并尝试写入ES,但为什么ES没有收到数据呢?(后来仔细观察,发现ES是有数据写入的,只不过速度很慢)
prometheus-es-adapter 日志
4. 监控内存
于是我猜想:是不是prometheus-es-adapter把数据写入了队列中,等待数据达到一定数量后再批量写入呢?或者是消费线程太少,导致消息处理不过来而造成大量堆积呢?
如果是这样,那必定会占用大量内存,内存空闲率必然要不断下降,这也可以解释之前遇到的OOMKilled。
于是我通过watch
命令去监控prometheus-es-adapter
容器的内存空闲率:
$ watch -n 1 'free -m'
下面两张图是观察了5分钟的结果,可以看到内存空闲率在不断下降。
2019-12-17 09:12:20 2019-12-17 09:17:56
于是我尝试着将ES_WORKERS
增加为20,果然一段时间后数据就追上来了。
总结
这个问题的根本原因是:prometheus-es-adapter处理线程太少,导致数据不能及时写入ES而致使Prometheus队列爆满,数据被大量丢弃或堆积在prometheus-es-adapter的处理队列中。这也是为什么只有一段时间有数据的原因及prometheus-es-adapter发生OOMKilled的原因。
要解决这个问题,需要修改两个地方:
- 增大Prometheus队列大小,避免队列爆满导致数据被丢弃
- 增加prometheus-es-adapter处理线程数量,使数据被快速写入远端存储
- 如果想让数据快速追上来,而历史数据又不太重要,可以尝试重启Prometheus
网友评论