2016-09-21 21:44:27 +00:00
|
|
|
// Copyright 2014 The Prometheus Authors
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package chunk
|
|
|
|
|
|
|
|
import "github.com/prometheus/client_golang/prometheus"
|
|
|
|
|
|
|
|
// Usually, a separate file for instrumentation is frowned upon. Metrics should
|
|
|
|
// be close to where they are used. However, the metrics below are set all over
|
|
|
|
// the place, so we go for a separate instrumentation file in this case.
|
|
|
|
var (
|
2016-09-28 21:33:34 +00:00
|
|
|
Ops = prometheus.NewCounterVec(
|
2016-09-21 21:44:27 +00:00
|
|
|
prometheus.CounterOpts{
|
|
|
|
Namespace: namespace,
|
|
|
|
Subsystem: subsystem,
|
|
|
|
Name: "chunk_ops_total",
|
|
|
|
Help: "The total number of chunk operations by their type.",
|
|
|
|
},
|
|
|
|
[]string{OpTypeLabel},
|
|
|
|
)
|
2016-09-28 21:33:34 +00:00
|
|
|
DescOps = prometheus.NewCounterVec(
|
2016-09-21 21:44:27 +00:00
|
|
|
prometheus.CounterOpts{
|
|
|
|
Namespace: namespace,
|
|
|
|
Subsystem: subsystem,
|
|
|
|
Name: "chunkdesc_ops_total",
|
|
|
|
Help: "The total number of chunk descriptor operations by their type.",
|
|
|
|
},
|
|
|
|
[]string{OpTypeLabel},
|
|
|
|
)
|
2016-09-28 21:33:34 +00:00
|
|
|
NumMemDescs = prometheus.NewGauge(prometheus.GaugeOpts{
|
2016-09-21 21:44:27 +00:00
|
|
|
Namespace: namespace,
|
|
|
|
Subsystem: subsystem,
|
|
|
|
Name: "memory_chunkdescs",
|
|
|
|
Help: "The current number of chunk descriptors in memory.",
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
namespace = "prometheus"
|
|
|
|
subsystem = "local_storage"
|
|
|
|
|
|
|
|
// OpTypeLabel is the label name for chunk operation types.
|
|
|
|
OpTypeLabel = "type"
|
|
|
|
|
|
|
|
// Op-types for ChunkOps.
|
|
|
|
|
|
|
|
// CreateAndPin is the label value for create-and-pin chunk ops.
|
2016-09-28 21:33:34 +00:00
|
|
|
CreateAndPin = "create" // A Desc creation with refCount=1.
|
2016-09-21 21:44:27 +00:00
|
|
|
// PersistAndUnpin is the label value for persist chunk ops.
|
|
|
|
PersistAndUnpin = "persist"
|
|
|
|
// Pin is the label value for pin chunk ops (excludes pin on creation).
|
|
|
|
Pin = "pin"
|
|
|
|
// Unpin is the label value for unpin chunk ops (excludes the unpin on persisting).
|
|
|
|
Unpin = "unpin"
|
|
|
|
// Clone is the label value for clone chunk ops.
|
|
|
|
Clone = "clone"
|
|
|
|
// Transcode is the label value for transcode chunk ops.
|
|
|
|
Transcode = "transcode"
|
|
|
|
// Drop is the label value for drop chunk ops.
|
|
|
|
Drop = "drop"
|
|
|
|
|
|
|
|
// Op-types for ChunkOps and ChunkDescOps.
|
|
|
|
|
|
|
|
// Evict is the label value for evict chunk desc ops.
|
|
|
|
Evict = "evict"
|
|
|
|
// Load is the label value for load chunk and chunk desc ops.
|
|
|
|
Load = "load"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
2016-09-28 21:33:34 +00:00
|
|
|
prometheus.MustRegister(Ops)
|
|
|
|
prometheus.MustRegister(DescOps)
|
|
|
|
prometheus.MustRegister(NumMemDescs)
|
2016-09-21 21:44:27 +00:00
|
|
|
}
|
|
|
|
|
storage: Evict chunks and calculate persistence pressure based on target heap size
This is a fairly easy attempt to dynamically evict chunks based on the
heap size. A target heap size has to be set as a command line flage,
so that users can essentially say "utilize 4GiB of RAM, and please
don't OOM".
The -storage.local.max-chunks-to-persist and
-storage.local.memory-chunks flags are deprecated by this
change. Backwards compatibility is provided by ignoring
-storage.local.max-chunks-to-persist and use
-storage.local.memory-chunks to set the new
-storage.local.target-heap-size to a reasonable (and conservative)
value (both with a warning).
This also makes the metrics intstrumentation more consistent (in
naming and implementation) and cleans up a few quirks in the tests.
Answers to anticipated comments:
There is a chance that Go 1.9 will allow programs better control over
the Go memory management. I don't expect those changes to be in
contradiction with the approach here, but I do expect them to
complement them and allow them to be more precise and controlled. In
any case, once those Go changes are available, this code has to be
revisted.
One might be tempted to let the user specify an estimated value for
the RSS usage, and then internall set a target heap size of a certain
fraction of that. (In my experience, 2/3 is a fairly safe bet.)
However, investigations have shown that RSS size and its relation to
the heap size is really really complicated. It depends on so many
factors that I wouldn't even start listing them in a commit
description. It depends on many circumstances and not at least on the
risk trade-off of each individual user between RAM utilization and
probability of OOMing during a RAM usage peak. To not add even more to
the confusion, we need to stick to the well-defined number we also use
in the targeting here, the sum of the sizes of heap objects.
2017-03-01 14:17:31 +00:00
|
|
|
// NumMemChunks is the total number of chunks in memory. This is a global
|
|
|
|
// counter, also used internally, so not implemented as metrics. Collected in
|
|
|
|
// MemorySeriesStorage.
|
|
|
|
// TODO(beorn7): Having this as an exported global variable is really bad.
|
|
|
|
var NumMemChunks int64
|