Skip to content

Commit c0db39b

Browse files
authored
Break background cache writes into batches of 100 (#2135)
* Break background cache writes into batches of 100 This improves parallelism and observability. Fixes #2134 Signed-off-by: Bryan Boreham <[email protected]>
1 parent 151c577 commit c0db39b

File tree

4 files changed

+36
-23
lines changed

4 files changed

+36
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
* [ENHANCEMENT] Cassandra Storage: User no longer need `CREATE` privilege on `<all keyspaces>` if given keyspace exists. #2032
5858
* [ENHANCEMENT] Cassandra Storage: added `password_file` configuration options to enable reading Cassandra password from file. #2096
5959
* [ENHANCEMENT] Experimental Memberlist KV: expose `-memberlist.gossip-to-dead-nodes-time` and `-memberlist.dead-node-reclaim-time` options to control how memberlist library handles dead nodes and name reuse. #2131
60+
* [ENHANCEMENT] Background cache writes are batched to improve parallelism and observability. #2135
6061
* [BUGFIX] Alertmanager: fixed panic upon applying a new config, caused by duplicate metrics registration in the `NewPipelineBuilder` function. #211
6162
* [BUGFIX] Experimental TSDB: fixed `/all_user_stats` and `/api/prom/user_stats` endpoints when using the experimental TSDB blocks storage. #2042
6263
* [BUGFIX] Experimental TSDB: fixed ruler to correctly work with the experimental TSDB blocks storage. #2101

docs/configuration/config-file-reference.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -629,7 +629,7 @@ results_cache:
629629
# CLI flag: -frontend.memcache.write-back-goroutines
630630
[writeback_goroutines: <int> | default = 10]
631631
632-
# How many chunks to buffer for background write back.
632+
# How many key batches to buffer for background write-back.
633633
# CLI flag: -frontend.memcache.write-back-buffer
634634
[writeback_buffer: <int> | default = 10000]
635635
@@ -1501,8 +1501,8 @@ index_queries_cache_config:
15011501
# CLI flag: -store.index-cache-read.memcache.write-back-goroutines
15021502
[writeback_goroutines: <int> | default = 10]
15031503

1504-
# Cache config for index entry reading. How many chunks to buffer for
1505-
# background write back.
1504+
# Cache config for index entry reading. How many key batches to buffer for
1505+
# background write-back.
15061506
# CLI flag: -store.index-cache-read.memcache.write-back-buffer
15071507
[writeback_buffer: <int> | default = 10000]
15081508

@@ -1546,8 +1546,8 @@ chunk_cache_config:
15461546
# CLI flag: -memcache.write-back-goroutines
15471547
[writeback_goroutines: <int> | default = 10]
15481548
1549-
# Cache config for chunks. How many chunks to buffer for background write
1550-
# back.
1549+
# Cache config for chunks. How many key batches to buffer for background
1550+
# write-back.
15511551
# CLI flag: -memcache.write-back-buffer
15521552
[writeback_buffer: <int> | default = 10000]
15531553
@@ -1581,8 +1581,8 @@ write_dedupe_cache_config:
15811581
# CLI flag: -store.index-cache-write.memcache.write-back-goroutines
15821582
[writeback_goroutines: <int> | default = 10]
15831583
1584-
# Cache config for index entry writing. How many chunks to buffer for
1585-
# background write back.
1584+
# Cache config for index entry writing. How many key batches to buffer for
1585+
# background write-back.
15861586
# CLI flag: -store.index-cache-write.memcache.write-back-buffer
15871587
[writeback_buffer: <int> | default = 10000]
15881588

pkg/chunk/cache/background.go

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type BackgroundConfig struct {
3333
// RegisterFlagsWithPrefix adds the flags required to config this to the given FlagSet
3434
func (cfg *BackgroundConfig) RegisterFlagsWithPrefix(prefix string, description string, f *flag.FlagSet) {
3535
f.IntVar(&cfg.WriteBackGoroutines, prefix+"memcache.write-back-goroutines", 10, description+"How many goroutines to use to write back to memcache.")
36-
f.IntVar(&cfg.WriteBackBuffer, prefix+"memcache.write-back-buffer", 10000, description+"How many chunks to buffer for background write back.")
36+
f.IntVar(&cfg.WriteBackBuffer, prefix+"memcache.write-back-buffer", 10000, description+"How many key batches to buffer for background write-back.")
3737
}
3838

3939
type backgroundCache struct {
@@ -80,21 +80,33 @@ func (c *backgroundCache) Stop() {
8080
c.Cache.Stop()
8181
}
8282

83+
const keysPerBatch = 100
84+
8385
// Store writes keys for the cache in the background.
8486
func (c *backgroundCache) Store(ctx context.Context, keys []string, bufs [][]byte) {
85-
bgWrite := backgroundWrite{
86-
keys: keys,
87-
bufs: bufs,
88-
}
89-
select {
90-
case c.bgWrites <- bgWrite:
91-
c.queueLength.Add(float64(len(keys)))
92-
default:
93-
c.droppedWriteBack.Add(float64(len(keys)))
94-
sp := opentracing.SpanFromContext(ctx)
95-
if sp != nil {
96-
sp.LogFields(otlog.Int("dropped", len(keys)))
87+
for len(keys) > 0 {
88+
num := keysPerBatch
89+
if num > len(keys) {
90+
num = len(keys)
91+
}
92+
93+
bgWrite := backgroundWrite{
94+
keys: keys[:num],
95+
bufs: bufs[:num],
96+
}
97+
select {
98+
case c.bgWrites <- bgWrite:
99+
c.queueLength.Add(float64(len(keys)))
100+
default:
101+
c.droppedWriteBack.Add(float64(len(keys)))
102+
sp := opentracing.SpanFromContext(ctx)
103+
if sp != nil {
104+
sp.LogFields(otlog.Int("dropped", len(keys)))
105+
}
106+
return // queue is full; give up
97107
}
108+
keys = keys[num:]
109+
bufs = bufs[num:]
98110
}
99111
}
100112

pkg/chunk/cache/cache_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ const userID = "1"
2222
func fillCache(t *testing.T, cache cache.Cache) ([]string, []chunk.Chunk) {
2323
const chunkLen = 13 * 3600 // in seconds
2424

25-
// put 100 chunks from 0 to 99
25+
// put a set of chunks, larger than background batch size, with varying timestamps and values
2626
keys := []string{}
2727
bufs := [][]byte{}
2828
chunks := []chunk.Chunk{}
29-
for i := 0; i < 100; i++ {
29+
for i := 0; i < 111; i++ {
3030
ts := model.TimeFromUnix(int64(i * chunkLen))
3131
promChunk := prom_chunk.New()
3232
nc, err := promChunk.Add(model.SamplePair{
@@ -119,7 +119,7 @@ func (a byExternalKey) Less(i, j int) bool { return a[i].ExternalKey() < a[j].Ex
119119

120120
func testCacheMiss(t *testing.T, cache cache.Cache) {
121121
for i := 0; i < 100; i++ {
122-
key := strconv.Itoa(rand.Int())
122+
key := strconv.Itoa(rand.Int()) // arbitrary key which should fail: no chunk key is a single integer
123123
found, bufs, missing := cache.Fetch(context.Background(), []string{key})
124124
require.Empty(t, found)
125125
require.Empty(t, bufs)

0 commit comments

Comments
 (0)