Skip to content

Commit 6d4b879

Browse files
authored
[Feature] Agency Cache memory usage reduction (#1325)
1 parent 3a5f042 commit 6d4b879

File tree

15 files changed

+429
-101
lines changed

15 files changed

+429
-101
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
44
- (Maintenance) Add govulncheck to pipeline, update golangci-linter
5+
- (Feature) Agency Cache memory usage reduction
56

67
## [1.2.28](https://github.com/arangodb/kube-arangodb/tree/1.2.28) (2023-06-05)
78
- (Feature) ArangoBackup create retries and MaxIterations limit

cmd/cmd.go

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import (
4949
"github.com/arangodb/kube-arangodb/pkg/api"
5050
deploymentApi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
5151
"github.com/arangodb/kube-arangodb/pkg/crd"
52+
"github.com/arangodb/kube-arangodb/pkg/deployment/agency/cache"
5253
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
5354
"github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/scheme"
5455
"github.com/arangodb/kube-arangodb/pkg/logging"
@@ -228,6 +229,9 @@ func init() {
228229
if err := features.Init(&cmdMain); err != nil {
229230
panic(err.Error())
230231
}
232+
if err := cache.Init(&cmdMain); err != nil {
233+
panic(err.Error())
234+
}
231235
}
232236

233237
func Execute() int {

pkg/deployment/agency/cache.go

+8-21
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,21 @@ import (
2727

2828
"github.com/rs/zerolog"
2929

30-
"github.com/arangodb/go-driver"
31-
"github.com/arangodb/go-driver/agency"
32-
3330
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
3431
"github.com/arangodb/kube-arangodb/pkg/generated/metric_descriptions"
3532
"github.com/arangodb/kube-arangodb/pkg/logging"
33+
"github.com/arangodb/kube-arangodb/pkg/util/arangod/conn"
3634
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3735
"github.com/arangodb/kube-arangodb/pkg/util/globals"
3836
"github.com/arangodb/kube-arangodb/pkg/util/metrics"
3937
)
4038

39+
type Connections map[string]conn.Connection
40+
4141
type health struct {
4242
namespace, name string
4343

4444
leaderID string
45-
leader driver.Connection
4645

4746
agencySize int
4847

@@ -52,14 +51,6 @@ type health struct {
5251
election map[string]int
5352
}
5453

55-
func (h health) Leader() (driver.Connection, bool) {
56-
if l := h.leader; l != nil {
57-
return l, true
58-
}
59-
60-
return nil, false
61-
}
62-
6354
func (h health) CollectMetrics(m metrics.PushMetric) {
6455
if err := h.Serving(); err == nil {
6556
m.Push(metric_descriptions.ArangodbOperatorAgencyCacheServingGauge(1, h.namespace, h.name))
@@ -145,14 +136,11 @@ type Health interface {
145136
// LeaderID returns a leader ID or empty string if a leader is not known.
146137
LeaderID() string
147138

148-
// Leader returns connection to the Agency leader
149-
Leader() (driver.Connection, bool)
150-
151139
CollectMetrics(m metrics.PushMetric)
152140
}
153141

154142
type Cache interface {
155-
Reload(ctx context.Context, size int, clients map[string]agency.Agency) (uint64, error)
143+
Reload(ctx context.Context, size int, clients Connections) (uint64, error)
156144
Data() (State, bool)
157145
DataDB() (StateDB, bool)
158146
CommitIndex() uint64
@@ -206,7 +194,7 @@ func (c cacheSingle) Health() (Health, bool) {
206194
return nil, false
207195
}
208196

209-
func (c cacheSingle) Reload(_ context.Context, _ int, _ map[string]agency.Agency) (uint64, error) {
197+
func (c cacheSingle) Reload(_ context.Context, _ int, _ Connections) (uint64, error) {
210198
return 0, nil
211199
}
212200

@@ -278,7 +266,7 @@ func (c *cache) Health() (Health, bool) {
278266
return nil, false
279267
}
280268

281-
func (c *cache) Reload(ctx context.Context, size int, clients map[string]agency.Agency) (uint64, error) {
269+
func (c *cache) Reload(ctx context.Context, size int, clients Connections) (uint64, error) {
282270
c.lock.Lock()
283271
defer c.lock.Unlock()
284272

@@ -313,7 +301,7 @@ func (c *cache) Reload(ctx context.Context, size int, clients map[string]agency.
313301
return index, nil
314302
}
315303

316-
func (c *cache) reload(ctx context.Context, size int, clients map[string]agency.Agency) (uint64, error) {
304+
func (c *cache) reload(ctx context.Context, size int, clients Connections) (uint64, error) {
317305
leaderCli, leaderConfig, health, err := c.getLeader(ctx, size, clients)
318306
if err != nil {
319307
// Invalidate a leader ID and agency state.
@@ -363,7 +351,7 @@ func (c *cache) ShardsInSyncMap() (ShardsSyncStatus, bool) {
363351

364352
// getLeader returns config and client to a leader agency, and health to check if agencies are on the same page.
365353
// If there is no quorum for the leader then error is returned.
366-
func (c *cache) getLeader(ctx context.Context, size int, clients map[string]agency.Agency) (agency.Agency, *Config, health, error) {
354+
func (c *cache) getLeader(ctx context.Context, size int, clients Connections) (conn.Connection, *Config, health, error) {
367355
configs := make([]*Config, len(clients))
368356
errs := make([]error, len(clients))
369357
names := make([]string, 0, len(clients))
@@ -427,7 +415,6 @@ func (c *cache) getLeader(ctx context.Context, size int, clients map[string]agen
427415

428416
for id := range names {
429417
if h.leaderID == h.names[id] {
430-
h.leader = clients[names[id]].Connection()
431418
if cfg := configs[id]; cfg != nil {
432419
return clients[names[id]], cfg, h, nil
433420
}

pkg/deployment/agency/cache/config.go

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2023 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package cache
22+
23+
import (
24+
"time"
25+
26+
"github.com/spf13/cobra"
27+
28+
"github.com/arangodb/kube-arangodb/pkg/util"
29+
"github.com/arangodb/kube-arangodb/pkg/version"
30+
)
31+
32+
func Init(cmd *cobra.Command) error {
33+
f := cmd.PersistentFlags()
34+
35+
ee := version.GetVersionV1().IsEnterprise()
36+
37+
f.BoolVar(&global.PollEnabled, "agency.poll-enabled", ee, "The Agency poll functionality enablement (EnterpriseEdition Only)")
38+
39+
if !ee {
40+
if err := f.MarkHidden("agency.poll-enabled"); err != nil {
41+
return err
42+
}
43+
}
44+
45+
f.DurationVar(&global.RefreshDelay, "agency.refresh-delay", util.BoolSwitch(ee, 500*time.Millisecond, 0), "The Agency refresh delay (0 = no delay)")
46+
47+
return nil
48+
}
49+
50+
var global Config
51+
52+
type Config struct {
53+
PollEnabled bool
54+
RefreshDelay time.Duration
55+
}

pkg/deployment/agency/config.go

+8-26
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -22,41 +22,23 @@ package agency
2222

2323
import (
2424
"context"
25-
"encoding/json"
2625
"net/http"
2726

28-
"github.com/arangodb/go-driver"
29-
"github.com/arangodb/go-driver/agency"
27+
"github.com/arangodb/kube-arangodb/pkg/util/arangod/conn"
28+
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3029
)
3130

32-
func GetAgencyConfig(ctx context.Context, client agency.Agency) (*Config, error) {
33-
return GetAgencyConfigC(ctx, client.Connection())
34-
}
35-
36-
func GetAgencyConfigC(ctx context.Context, conn driver.Connection) (*Config, error) {
37-
req, err := conn.NewRequest(http.MethodGet, "/_api/agency/config")
38-
if err != nil {
39-
return nil, err
40-
}
41-
42-
var data []byte
43-
44-
resp, err := conn.Do(driver.WithRawResponse(ctx, &data), req)
31+
func GetAgencyConfig(ctx context.Context, connection conn.Connection) (*Config, error) {
32+
resp, code, err := conn.NewExecutor[any, Config](connection).ExecuteGet(ctx, "/_api/agency/config")
4533
if err != nil {
4634
return nil, err
4735
}
4836

49-
if err := resp.CheckStatus(http.StatusOK); err != nil {
50-
return nil, err
51-
}
52-
53-
var c Config
54-
55-
if err := json.Unmarshal(data, &c); err != nil {
56-
return nil, err
37+
if code != http.StatusOK {
38+
return nil, errors.Newf("Unknown response code %d", code)
5739
}
5840

59-
return &c, nil
41+
return resp, nil
6042
}
6143

6244
type Config struct {

pkg/deployment/agency/definitions.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -25,6 +25,8 @@ import (
2525
"strings"
2626
)
2727

28+
type ReadRequest [][]string
29+
2830
const (
2931
ArangoKey = "arango"
3032
ArangoDBKey = "arangodb"
@@ -66,6 +68,24 @@ func GetAgencyReadKey(elements ...string) []string {
6668
return elements
6769
}
6870

69-
func GetAgencyReadRequest(elements ...[]string) [][]string {
71+
func GetAgencyReadRequest(elements ...[]string) ReadRequest {
7072
return elements
7173
}
74+
75+
func GetAgencyReadRequestFields() ReadRequest {
76+
return GetAgencyReadRequest([]string{
77+
GetAgencyKey(ArangoKey, SupervisionKey, SupervisionMaintenanceKey),
78+
GetAgencyKey(ArangoKey, PlanKey, PlanCollectionsKey),
79+
GetAgencyKey(ArangoKey, PlanKey, PlanDatabasesKey),
80+
GetAgencyKey(ArangoKey, CurrentKey, PlanCollectionsKey),
81+
GetAgencyKey(ArangoKey, CurrentKey, CurrentMaintenanceServers),
82+
GetAgencyKey(ArangoKey, TargetKey, TargetHotBackupKey),
83+
GetAgencyKey(ArangoKey, TargetKey, TargetJobToDoKey),
84+
GetAgencyKey(ArangoKey, TargetKey, TargetJobPendingKey),
85+
GetAgencyKey(ArangoKey, TargetKey, TargetJobFailedKey),
86+
GetAgencyKey(ArangoKey, TargetKey, TargetJobFinishedKey),
87+
GetAgencyKey(ArangoKey, TargetKey, TargetCleanedServersKey),
88+
GetAgencyKey(ArangoDBKey, ArangoSyncKey, ArangoSyncStateKey, ArangoSyncStateIncomingKey, ArangoSyncStateIncomingStateKey),
89+
GetAgencyKey(ArangoDBKey, ArangoSyncKey, ArangoSyncStateKey, ArangoSyncStateOutgoingKey, ArangoSyncStateOutgoingTargetsKey),
90+
})
91+
}

pkg/deployment/agency/state.go

+9-46
Original file line numberDiff line numberDiff line change
@@ -22,68 +22,31 @@ package agency
2222

2323
import (
2424
"context"
25-
"encoding/json"
2625
"net/http"
2726

28-
"github.com/arangodb/go-driver"
29-
"github.com/arangodb/go-driver/agency"
30-
27+
"github.com/arangodb/kube-arangodb/pkg/util/arangod/conn"
3128
"github.com/arangodb/kube-arangodb/pkg/util/errors"
3229
)
3330

34-
func (c *cache) loadState(ctx context.Context, client agency.Agency) (StateRoot, error) {
35-
conn := client.Connection()
36-
37-
req, err := client.Connection().NewRequest(http.MethodPost, "/_api/agency/read")
38-
if err != nil {
39-
return StateRoot{}, err
40-
}
41-
42-
var data []byte
43-
44-
readKeys := []string{
45-
GetAgencyKey(ArangoKey, SupervisionKey, SupervisionMaintenanceKey),
46-
GetAgencyKey(ArangoKey, PlanKey, PlanCollectionsKey),
47-
GetAgencyKey(ArangoKey, PlanKey, PlanDatabasesKey),
48-
GetAgencyKey(ArangoKey, CurrentKey, PlanCollectionsKey),
49-
GetAgencyKey(ArangoKey, CurrentKey, CurrentMaintenanceServers),
50-
GetAgencyKey(ArangoKey, TargetKey, TargetHotBackupKey),
51-
GetAgencyKey(ArangoKey, TargetKey, TargetJobToDoKey),
52-
GetAgencyKey(ArangoKey, TargetKey, TargetJobPendingKey),
53-
GetAgencyKey(ArangoKey, TargetKey, TargetJobFailedKey),
54-
GetAgencyKey(ArangoKey, TargetKey, TargetJobFinishedKey),
55-
GetAgencyKey(ArangoKey, TargetKey, TargetCleanedServersKey),
56-
GetAgencyKey(ArangoDBKey, ArangoSyncKey, ArangoSyncStateKey, ArangoSyncStateIncomingKey, ArangoSyncStateIncomingStateKey),
57-
GetAgencyKey(ArangoDBKey, ArangoSyncKey, ArangoSyncStateKey, ArangoSyncStateOutgoingKey, ArangoSyncStateOutgoingTargetsKey),
58-
}
59-
60-
req, err = req.SetBody(GetAgencyReadRequest(GetAgencyReadKey(readKeys...)))
31+
func (c *cache) loadState(ctx context.Context, connection conn.Connection) (StateRoot, error) {
32+
resp, code, err := conn.NewExecutor[ReadRequest, StateRoots](connection).Execute(ctx, http.MethodPost, "/_api/agency/config", GetAgencyReadRequestFields())
6133
if err != nil {
6234
return StateRoot{}, err
6335
}
6436

65-
resp, err := conn.Do(driver.WithRawResponse(ctx, &data), req)
66-
if err != nil {
67-
return StateRoot{}, err
68-
}
69-
70-
if err := resp.CheckStatus(http.StatusOK); err != nil {
71-
return StateRoot{}, err
37+
if code != http.StatusOK {
38+
return StateRoot{}, errors.Newf("Unknown response code %d", code)
7239
}
7340

74-
var r StateRoots
75-
76-
if err := json.Unmarshal(data, &r); err != nil {
77-
return StateRoot{}, err
41+
if resp == nil {
42+
return StateRoot{}, errors.Newf("Missing response body")
7843
}
7944

80-
if len(r) != 1 {
45+
if len(*resp) != 1 {
8146
return StateRoot{}, errors.Newf("Invalid response size")
8247
}
8348

84-
state := r[0]
85-
86-
return state, nil
49+
return (*resp)[0], nil
8750
}
8851

8952
type StateRoots []StateRoot

0 commit comments

Comments
 (0)