Skip to content

Commit 14dfa70

Browse files
committed
fix: add VolumeStats cache to avoid massive statfs calls
1 parent 93d7cc3 commit 14dfa70

File tree

4 files changed

+34
-2
lines changed

4 files changed

+34
-2
lines changed

pkg/blob/blob.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ type DriverOptions struct {
170170
KubeAPIQPS float64
171171
KubeAPIBurst int
172172
EnableAznfsMount bool
173+
VolStatsCacheExpireInMinutes int
173174
}
174175

175176
// Driver implements all interfaces of CSI drivers
@@ -208,6 +209,8 @@ type Driver struct {
208209
dataPlaneAPIVolCache azcache.Resource
209210
// a timed cache storing account search history (solve account list throttling issue)
210211
accountSearchCache azcache.Resource
212+
// a timed cache storing volume stats <volumeID, volumeStats>
213+
volStatsCache azcache.Resource
211214
}
212215

213216
// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
@@ -246,6 +249,13 @@ func NewDriver(options *DriverOptions) *Driver {
246249
if d.dataPlaneAPIVolCache, err = azcache.NewTimedCache(10*time.Minute, getter, false); err != nil {
247250
klog.Fatalf("%v", err)
248251
}
252+
253+
if options.VolStatsCacheExpireInMinutes <= 0 {
254+
options.VolStatsCacheExpireInMinutes = 10 // default expire in 10 minutes
255+
}
256+
if d.volStatsCache, err = azcache.NewTimedCache(time.Duration(options.VolStatsCacheExpireInMinutes)*time.Minute, getter, false); err != nil {
257+
klog.Fatalf("%v", err)
258+
}
249259
return &d
250260
}
251261

pkg/blob/blob_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ func TestNewDriver(t *testing.T) {
9191
fakedriver.Version = driverVersion
9292
fakedriver.accountSearchCache = driver.accountSearchCache
9393
fakedriver.dataPlaneAPIVolCache = driver.dataPlaneAPIVolCache
94+
fakedriver.volStatsCache = driver.volStatsCache
9495
assert.Equal(t, driver, fakedriver)
9596
}
9697

pkg/blob/nodeserver.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
volumehelper "sigs.k8s.io/blob-csi-driver/pkg/util"
30+
azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
3031

3132
"github.com/Azure/azure-sdk-for-go/storage"
3233
"github.com/container-storage-interface/spec/lib/go/csi"
@@ -479,13 +480,26 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS
479480
return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume path was empty")
480481
}
481482

483+
// check if the volume stats is cached
484+
cache, err := d.volStatsCache.Get(req.VolumeId, azcache.CacheReadTypeDefault)
485+
if err != nil {
486+
return nil, status.Errorf(codes.Internal, err.Error())
487+
}
488+
if cache != nil {
489+
resp := cache.(csi.NodeGetVolumeStatsResponse)
490+
klog.V(6).Infof("NodeGetVolumeStats: volume stats for volume %s path %s is cached", req.VolumeId, req.VolumePath)
491+
return &resp, nil
492+
}
493+
482494
if _, err := os.Lstat(req.VolumePath); err != nil {
483495
if os.IsNotExist(err) {
484496
return nil, status.Errorf(codes.NotFound, "path %s does not exist", req.VolumePath)
485497
}
486498
return nil, status.Errorf(codes.Internal, "failed to stat file %s: %v", req.VolumePath, err)
487499
}
488500

501+
klog.V(6).Infof("NodeGetVolumeStats: begin to get VolumeStats on volume %s path %s", req.VolumeId, req.VolumePath)
502+
489503
volumeMetrics, err := volume.NewMetricsStatFS(req.VolumePath).GetMetrics()
490504
if err != nil {
491505
return nil, status.Errorf(codes.Internal, "failed to get metrics: %v", err)
@@ -517,7 +531,7 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS
517531
return nil, status.Errorf(codes.Internal, "failed to transform disk inodes used(%v)", volumeMetrics.InodesUsed)
518532
}
519533

520-
return &csi.NodeGetVolumeStatsResponse{
534+
resp := &csi.NodeGetVolumeStatsResponse{
521535
Usage: []*csi.VolumeUsage{
522536
{
523537
Unit: csi.VolumeUsage_BYTES,
@@ -532,7 +546,12 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS
532546
Used: inodesUsed,
533547
},
534548
},
535-
}, nil
549+
}
550+
551+
klog.V(6).Infof("NodeGetVolumeStats: volume stats for volume %s path %s is %v", req.VolumeId, req.VolumePath, resp)
552+
// cache the volume stats per volume
553+
d.volStatsCache.Set(req.VolumeId, *resp)
554+
return resp, nil
536555
}
537556

538557
// ensureMountPoint: create mount point if not exists

pkg/blobplugin/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ var (
5555
kubeAPIBurst = flag.Int("kube-api-burst", 50, "Burst to use while communicating with the kubernetes apiserver.")
5656
appendMountErrorHelpLink = flag.Bool("append-mount-error-help-link", true, "Whether to include a link for help with mount errors when a mount error occurs.")
5757
enableAznfsMount = flag.Bool("enable-aznfs-mount", false, "replace nfs mount with aznfs mount")
58+
volStatsCacheExpireInMinutes = flag.Int("vol-stats-cache-expire-in-minutes", 10, "The cache expire time in minutes for volume stats cache")
5859
)
5960

6061
func main() {
@@ -96,6 +97,7 @@ func handle() {
9697
KubeAPIQPS: *kubeAPIQPS,
9798
KubeAPIBurst: *kubeAPIBurst,
9899
EnableAznfsMount: *enableAznfsMount,
100+
VolStatsCacheExpireInMinutes: *volStatsCacheExpireInMinutes,
99101
}
100102
driver := blob.NewDriver(&driverOptions)
101103
if driver == nil {

0 commit comments

Comments
 (0)