Skip to content

Commit ef07dfa

Browse files
Add latency metrics to mode2 (grafana#88011)
* Also call storage on mode1. Add metrics * Update comment * Don't use compare function for now * Remove very important space * Improve code readability on modes 1 and 2 * Fix tests * Return error from legacy write * Renume useless defer * Start adding logging for mode2 * Retrurn errors is storage read fails * Finish adding latency metrics to mode2 * Emit kind to metrics instead * Fix var name * Return if legacy delete list fails * Unify latency calls * Fix get function
1 parent c4aca05 commit ef07dfa

File tree

2 files changed

+78
-21
lines changed

2 files changed

+78
-21
lines changed

pkg/apiserver/rest/dualwriter_mode1.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ type DualWriterMode1 struct {
1919
Log klog.Logger
2020
}
2121

22-
const (
23-
mode1Str = "1"
24-
)
22+
const mode1Str = "1"
2523

2624
// NewDualWriterMode1 returns a new DualWriter in mode 1.
2725
// Mode 1 represents writing to and reading from LegacyStorage.
@@ -69,7 +67,7 @@ func (d *DualWriterMode1) Create(ctx context.Context, original runtime.Object, c
6967

7068
// Get overrides the behavior of the generic DualWriter and reads only from LegacyStorage.
7169
func (d *DualWriterMode1) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
72-
log := d.Log.WithValues("name", name, "resourceVersion", options.ResourceVersion, "kind", options.Kind)
70+
log := d.Log.WithValues("kind", options.Kind)
7371
ctx = klog.NewContext(ctx, log)
7472
var method = "get"
7573

@@ -127,7 +125,7 @@ func (d *DualWriterMode1) Delete(ctx context.Context, name string, deleteValidat
127125
d.recordLegacyDuration(true, mode1Str, options.Kind, method, startLegacy)
128126
return res, async, err
129127
}
130-
d.recordLegacyDuration(false, mode1Str, options.Kind, method, startLegacy)
128+
d.recordLegacyDuration(false, mode1Str, name, method, startLegacy)
131129

132130
go func() {
133131
startStorage := time.Now()

pkg/apiserver/rest/dualwriter_mode2.go

+75-16
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package rest
22

33
import (
44
"context"
5+
"time"
56

67
"github.com/grafana/grafana/pkg/services/apiserver/utils"
78
apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -22,6 +23,8 @@ type DualWriterMode2 struct {
2223
Log klog.Logger
2324
}
2425

26+
const mode2Str = "2"
27+
2528
// NewDualWriterMode2 returns a new DualWriter in mode 2.
2629
// Mode 2 represents writing to LegacyStorage and Storage and reading from LegacyStorage.
2730
func NewDualWriterMode2(legacy LegacyStorage, storage Storage) *DualWriterMode2 {
@@ -39,52 +42,78 @@ func (d *DualWriterMode2) Mode() DualWriterMode {
3942
func (d *DualWriterMode2) Create(ctx context.Context, original runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
4043
log := d.Log.WithValues("kind", options.Kind)
4144
ctx = klog.NewContext(ctx, log)
45+
var method = "create"
4246

47+
startLegacy := time.Now()
4348
created, err := d.Legacy.Create(ctx, original, createValidation, options)
4449
if err != nil {
4550
log.Error(err, "unable to create object in legacy storage")
51+
d.recordLegacyDuration(true, mode2Str, options.Kind, method, startLegacy)
4652
return created, err
4753
}
54+
d.recordLegacyDuration(false, mode2Str, options.Kind, method, startLegacy)
4855

4956
createdLegacy, err := enrichLegacyObject(original, created, true)
5057
if err != nil {
5158
return createdLegacy, err
5259
}
5360

61+
startStorage := time.Now()
5462
rsp, err := d.Storage.Create(ctx, created, createValidation, options)
5563
if err != nil {
5664
log.WithValues("name").Error(err, "unable to create object in storage")
57-
return rsp, err
65+
d.recordStorageDuration(true, mode2Str, options.Kind, method, startStorage)
5866
}
59-
return rsp, nil
67+
d.recordStorageDuration(false, mode2Str, options.Kind, method, startStorage)
68+
return rsp, err
6069
}
6170

6271
// It retrieves an object from Storage if possible, and if not it falls back to LegacyStorage.
6372
func (d *DualWriterMode2) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
6473
log := d.Log.WithValues("name", name, "resourceVersion", options.ResourceVersion, "kind", options.Kind)
6574
ctx = klog.NewContext(ctx, log)
66-
s, err := d.Storage.Get(ctx, name, &metav1.GetOptions{})
75+
var method = "get"
76+
77+
startStorage := time.Now()
78+
res, err := d.Storage.Get(ctx, name, options)
6779
if err != nil {
80+
// if it errors because it's not found, we try to fetch it from the legacy storage
6881
if apierrors.IsNotFound(err) {
69-
log.Info("object not found in storage")
70-
return d.Legacy.Get(ctx, name, &metav1.GetOptions{})
82+
d.recordStorageDuration(false, mode2Str, options.Kind, method, startStorage)
83+
84+
log.Info("object not found in storage, fetching from legacy")
85+
startLegacy := time.Now()
86+
res, err = d.Legacy.Get(ctx, name, options)
87+
if err != nil {
88+
log.Error(err, "unable to fetch object from legacy")
89+
d.recordLegacyDuration(true, mode2Str, options.Kind, method, startLegacy)
90+
}
91+
d.recordLegacyDuration(false, mode2Str, options.Kind, method, startLegacy)
92+
return res, err
7193
}
94+
d.recordStorageDuration(true, mode2Str, options.Kind, method, startStorage)
7295
log.Error(err, "unable to fetch object from storage")
73-
return d.Legacy.Get(ctx, name, &metav1.GetOptions{})
96+
return res, err
7497
}
75-
return s, nil
98+
return res, err
7699
}
77100

78101
// List overrides the behavior of the generic DualWriter.
79102
// It returns Storage entries if possible and falls back to LegacyStorage entries if not.
80103
func (d *DualWriterMode2) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
81104
log := d.Log.WithValues("kind", options.Kind, "resourceVersion", options.ResourceVersion, "kind", options.Kind)
82105
ctx = klog.NewContext(ctx, log)
106+
var method = "list"
107+
108+
startLegacy := time.Now()
83109
ll, err := d.Legacy.List(ctx, options)
84110
if err != nil {
85111
log.Error(err, "unable to list objects from legacy storage")
86-
return nil, err
112+
d.recordLegacyDuration(true, mode2Str, options.Kind, method, startLegacy)
113+
return ll, err
87114
}
115+
d.recordLegacyDuration(false, mode2Str, options.Kind, method, startLegacy)
116+
88117
legacyList, err := meta.ExtractList(ll)
89118
if err != nil {
90119
log.Error(err, "unable to extract list from legacy storage")
@@ -98,15 +127,20 @@ func (d *DualWriterMode2) List(ctx context.Context, options *metainternalversion
98127
return nil, err
99128
}
100129

130+
// TODO: why do we need this?
101131
if optionsStorage.LabelSelector == nil {
102132
return ll, nil
103133
}
104134

135+
startStorage := time.Now()
105136
sl, err := d.Storage.List(ctx, &optionsStorage)
106137
if err != nil {
107138
log.Error(err, "unable to list objects from storage")
108-
return nil, err
139+
d.recordStorageDuration(true, mode2Str, options.Kind, method, startStorage)
140+
return sl, err
109141
}
142+
d.recordStorageDuration(false, mode2Str, options.Kind, method, startStorage)
143+
110144
storageList, err := meta.ExtractList(sl)
111145
if err != nil {
112146
log.Error(err, "unable to extract list from storage")
@@ -133,11 +167,17 @@ func (d *DualWriterMode2) List(ctx context.Context, options *metainternalversion
133167
func (d *DualWriterMode2) DeleteCollection(ctx context.Context, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions, listOptions *metainternalversion.ListOptions) (runtime.Object, error) {
134168
log := d.Log.WithValues("kind", options.Kind, "resourceVersion", listOptions.ResourceVersion)
135169
ctx = klog.NewContext(ctx, log)
170+
var method = "delete-collection"
171+
172+
startLegacy := time.Now()
136173
deleted, err := d.Legacy.DeleteCollection(ctx, deleteValidation, options, listOptions)
137174
if err != nil {
138175
log.WithValues("deleted", deleted).Error(err, "failed to delete collection successfully from legacy storage")
139-
return nil, err
176+
d.recordLegacyDuration(true, mode2Str, options.Kind, method, startLegacy)
177+
return deleted, err
140178
}
179+
d.recordLegacyDuration(false, mode2Str, options.Kind, method, startLegacy)
180+
141181
legacyList, err := meta.ExtractList(deleted)
142182
if err != nil {
143183
log.Error(err, "unable to extract list from legacy storage")
@@ -153,33 +193,42 @@ func (d *DualWriterMode2) DeleteCollection(ctx context.Context, deleteValidation
153193
return deleted, nil
154194
}
155195

196+
startStorage := time.Now()
156197
res, err := d.Storage.DeleteCollection(ctx, deleteValidation, options, &optionsStorage)
157198
if err != nil {
158199
log.WithValues("deleted", res).Error(err, "failed to delete collection successfully from Storage")
200+
d.recordStorageDuration(true, mode2Str, options.Kind, method, startStorage)
159201
}
202+
d.recordStorageDuration(false, mode2Str, options.Kind, method, startStorage)
160203

161204
return res, err
162205
}
163206

164207
func (d *DualWriterMode2) Delete(ctx context.Context, name string, deleteValidation rest.ValidateObjectFunc, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
165208
log := d.Log.WithValues("name", name, "kind", options.Kind)
166209
ctx = klog.NewContext(ctx, log)
210+
var method = "delete"
167211

212+
startLegacy := time.Now()
168213
deletedLS, async, err := d.Legacy.Delete(ctx, name, deleteValidation, options)
169214
if err != nil {
170215
if !apierrors.IsNotFound(err) {
171216
log.WithValues("objectList", deletedLS).Error(err, "could not delete from legacy store")
217+
d.recordLegacyDuration(true, mode2Str, options.Kind, method, startLegacy)
172218
return deletedLS, async, err
173219
}
174220
}
221+
d.recordLegacyDuration(false, mode2Str, options.Kind, method, startLegacy)
175222

176-
deletedS, _, errUS := d.Storage.Delete(ctx, name, deleteValidation, options)
177-
if errUS != nil {
178-
if !apierrors.IsNotFound(errUS) {
179-
log.WithValues("objectList", deletedS).Error(errUS, "could not delete from duplicate storage")
223+
startStorage := time.Now()
224+
deletedS, _, err := d.Storage.Delete(ctx, name, deleteValidation, options)
225+
if err != nil {
226+
if !apierrors.IsNotFound(err) {
227+
log.WithValues("objectList", deletedS).Error(err, "could not delete from duplicate storage")
228+
d.recordStorageDuration(true, mode2Str, options.Kind, method, startStorage)
180229
}
181230
}
182-
231+
d.recordStorageDuration(false, mode2Str, options.Kind, method, startStorage)
183232
return deletedLS, async, err
184233
}
185234

@@ -205,12 +254,16 @@ func (d *DualWriterMode2) Update(ctx context.Context, name string, objInfo rest.
205254
return nil, false, err
206255
}
207256

257+
startLegacy := time.Now()
208258
obj, created, err := d.Legacy.Update(ctx, name, &updateWrapper{upstream: objInfo, updated: updated}, createValidation, updateValidation, forceAllowCreate, options)
209259
if err != nil {
210260
log.WithValues("object", obj).Error(err, "could not update in legacy storage")
261+
d.recordLegacyDuration(true, mode2Str, options.Kind, "update", startLegacy)
211262
return obj, created, err
212263
}
264+
d.recordLegacyDuration(false, mode2Str, options.Kind, "update", startLegacy)
213265

266+
// if the object is found, create a new updateWrapper with the object found
214267
if foundObj != nil {
215268
obj, err = enrichLegacyObject(foundObj, obj, false)
216269
if err != nil {
@@ -223,7 +276,13 @@ func (d *DualWriterMode2) Update(ctx context.Context, name string, objInfo rest.
223276
}
224277
}
225278

226-
return d.Storage.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options)
279+
startStorage := time.Now()
280+
res, created, err := d.Storage.Update(ctx, name, objInfo, createValidation, updateValidation, forceAllowCreate, options)
281+
if err != nil {
282+
log.WithValues("object", res).Error(err, "could not update in storage")
283+
}
284+
d.recordStorageDuration(err != nil, mode2Str, options.Kind, "update", startStorage)
285+
return res, created, err
227286
}
228287

229288
func (d *DualWriterMode2) Destroy() {

0 commit comments

Comments
 (0)