Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
f85b7ae8
Commit
f85b7ae8
authored
May 30, 2018
by
Cong Ding
Committed by
Wenjia Zhang
Jun 26, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
etcd: reuse leases for keys in a time window
Reuse leases for keys in a time window, to reduce the overhead to etcd caused by using massive number of leases Fixes #47532
parent
1a1c0bab
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
158 additions
and
6 deletions
+158
-6
BUILD
staging/src/k8s.io/apiserver/pkg/storage/etcd3/BUILD
+2
-0
lease_manager.go
...g/src/k8s.io/apiserver/pkg/storage/etcd3/lease_manager.go
+102
-0
lease_manager_test.go
.../k8s.io/apiserver/pkg/storage/etcd3/lease_manager_test.go
+44
-0
store.go
staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go
+6
-6
store_test.go
staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go
+4
-0
No files found.
staging/src/k8s.io/apiserver/pkg/storage/etcd3/BUILD
View file @
f85b7ae8
...
@@ -10,6 +10,7 @@ go_test(
...
@@ -10,6 +10,7 @@ go_test(
name = "go_default_test",
name = "go_default_test",
srcs = [
srcs = [
"compact_test.go",
"compact_test.go",
"lease_manager_test.go",
"store_test.go",
"store_test.go",
"watcher_test.go",
"watcher_test.go",
],
],
...
@@ -45,6 +46,7 @@ go_library(
...
@@ -45,6 +46,7 @@ go_library(
"compact.go",
"compact.go",
"errors.go",
"errors.go",
"event.go",
"event.go",
"lease_manager.go",
"store.go",
"store.go",
"watcher.go",
"watcher.go",
],
],
...
...
staging/src/k8s.io/apiserver/pkg/storage/etcd3/lease_manager.go
0 → 100644
View file @
f85b7ae8
/*
Copyright 2018 The Kubernetes 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
etcd3
import
(
"context"
"sync"
"time"
"github.com/coreos/etcd/clientv3"
)
// leaseManager is used to manage leases requested from etcd. If a new write
// needs a lease that has similar expiration time to the previous one, the old
// lease will be reused to reduce the overhead of etcd, since lease operations
// are expensive. In the implementation, we only store one previous lease,
// since all the events have the same ttl.
type
leaseManager
struct
{
client
*
clientv3
.
Client
// etcd client used to grant leases
leaseMu
sync
.
Mutex
prevLeaseID
clientv3
.
LeaseID
prevLeaseExpirationTime
time
.
Time
// The period of time in seconds and percent of TTL that each lease is
// reused. The minimum of them is used to avoid unreasonably large
// numbers. We use var instead of const for testing purposes.
leaseReuseDurationSeconds
int64
leaseReuseDurationPercent
float64
}
// newDefaultLeaseManager creates a new lease manager using default setting.
func
newDefaultLeaseManager
(
client
*
clientv3
.
Client
)
*
leaseManager
{
return
newLeaseManager
(
client
,
60
,
0.05
)
}
// newLeaseManager creates a new lease manager with the number of buffered
// leases, lease reuse duration in seconds and percentage. The percentage
// value x means x*100%.
func
newLeaseManager
(
client
*
clientv3
.
Client
,
leaseReuseDurationSeconds
int64
,
leaseReuseDurationPercent
float64
)
*
leaseManager
{
return
&
leaseManager
{
client
:
client
,
leaseReuseDurationSeconds
:
leaseReuseDurationSeconds
,
leaseReuseDurationPercent
:
leaseReuseDurationPercent
,
}
}
// setLeaseReuseDurationSeconds is used for testing purpose. It is used to
// reduce the extra lease duration to avoid unnecessary timeout in testing.
func
(
l
*
leaseManager
)
setLeaseReuseDurationSeconds
(
duration
int64
)
{
l
.
leaseMu
.
Lock
()
defer
l
.
leaseMu
.
Unlock
()
l
.
leaseReuseDurationSeconds
=
duration
}
// GetLease returns a lease based on requested ttl: if the cached previous
// lease can be reused, reuse it; otherwise request a new one from etcd.
func
(
l
*
leaseManager
)
GetLease
(
ctx
context
.
Context
,
ttl
int64
)
(
clientv3
.
LeaseID
,
error
)
{
now
:=
time
.
Now
()
l
.
leaseMu
.
Lock
()
defer
l
.
leaseMu
.
Unlock
()
// check if previous lease can be reused
reuseDurationSeconds
:=
l
.
getReuseDurationSecondsLocked
(
ttl
)
valid
:=
now
.
Add
(
time
.
Duration
(
ttl
)
*
time
.
Second
)
.
Before
(
l
.
prevLeaseExpirationTime
)
sufficient
:=
now
.
Add
(
time
.
Duration
(
ttl
+
reuseDurationSeconds
)
*
time
.
Second
)
.
After
(
l
.
prevLeaseExpirationTime
)
if
valid
&&
sufficient
{
return
l
.
prevLeaseID
,
nil
}
// request a lease with a little extra ttl from etcd
ttl
+=
reuseDurationSeconds
lcr
,
err
:=
l
.
client
.
Lease
.
Grant
(
ctx
,
ttl
)
if
err
!=
nil
{
return
clientv3
.
LeaseID
(
0
),
err
}
// cache the new lease id
l
.
prevLeaseID
=
lcr
.
ID
l
.
prevLeaseExpirationTime
=
now
.
Add
(
time
.
Duration
(
ttl
)
*
time
.
Second
)
return
lcr
.
ID
,
nil
}
// getReuseDurationSecondsLocked returns the reusable duration in seconds
// based on the configuration. Lock has to be acquired before calling this
// function.
func
(
l
*
leaseManager
)
getReuseDurationSecondsLocked
(
ttl
int64
)
int64
{
reuseDurationSeconds
:=
int64
(
l
.
leaseReuseDurationPercent
*
float64
(
ttl
))
if
reuseDurationSeconds
>
l
.
leaseReuseDurationSeconds
{
reuseDurationSeconds
=
l
.
leaseReuseDurationSeconds
}
return
reuseDurationSeconds
}
staging/src/k8s.io/apiserver/pkg/storage/etcd3/lease_manager_test.go
0 → 100644
View file @
f85b7ae8
/*
Copyright 2018 The Kubernetes 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
etcd3
import
(
"testing"
)
func
TestGetReuseDurationSeconds
(
t
*
testing
.
T
)
{
testCases
:=
[]
struct
{
ttl
int64
duration
int64
}{
{
ttl
:
3600
,
duration
:
60
,
},
{
ttl
:
1000
,
duration
:
50
,
},
}
lm
:=
newDefaultLeaseManager
(
nil
)
for
i
:=
0
;
i
<
len
(
testCases
);
i
++
{
dur
:=
lm
.
getReuseDurationSecondsLocked
(
testCases
[
i
]
.
ttl
)
if
dur
!=
testCases
[
i
]
.
duration
{
t
.
Errorf
(
"Duration error: ttl %v, expected duration %v, get %v
\n
"
,
testCases
[
i
]
.
ttl
,
testCases
[
i
]
.
duration
,
dur
)
}
}
}
staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go
View file @
f85b7ae8
...
@@ -70,6 +70,7 @@ type store struct {
...
@@ -70,6 +70,7 @@ type store struct {
pathPrefix
string
pathPrefix
string
watcher
*
watcher
watcher
*
watcher
pagingEnabled
bool
pagingEnabled
bool
leaseManager
*
leaseManager
}
}
type
elemForDecode
struct
{
type
elemForDecode
struct
{
...
@@ -107,8 +108,9 @@ func newStore(c *clientv3.Client, quorumRead, pagingEnabled bool, codec runtime.
...
@@ -107,8 +108,9 @@ func newStore(c *clientv3.Client, quorumRead, pagingEnabled bool, codec runtime.
// for compatibility with etcd2 impl.
// for compatibility with etcd2 impl.
// no-op for default prefix of '/registry'.
// no-op for default prefix of '/registry'.
// keeps compatibility with etcd2 impl for custom prefixes that don't start with '/'
// keeps compatibility with etcd2 impl for custom prefixes that don't start with '/'
pathPrefix
:
path
.
Join
(
"/"
,
prefix
),
pathPrefix
:
path
.
Join
(
"/"
,
prefix
),
watcher
:
newWatcher
(
c
,
codec
,
versioner
,
transformer
),
watcher
:
newWatcher
(
c
,
codec
,
versioner
,
transformer
),
leaseManager
:
newDefaultLeaseManager
(
c
),
}
}
if
!
quorumRead
{
if
!
quorumRead
{
// In case of non-quorum reads, we can set WithSerializable()
// In case of non-quorum reads, we can set WithSerializable()
...
@@ -758,13 +760,11 @@ func (s *store) ttlOpts(ctx context.Context, ttl int64) ([]clientv3.OpOption, er
...
@@ -758,13 +760,11 @@ func (s *store) ttlOpts(ctx context.Context, ttl int64) ([]clientv3.OpOption, er
if
ttl
==
0
{
if
ttl
==
0
{
return
nil
,
nil
return
nil
,
nil
}
}
// TODO: one lease per ttl key is expensive. Based on current use case, we can have a long window to
id
,
err
:=
s
.
leaseManager
.
GetLease
(
ctx
,
ttl
)
// put keys within into same lease. We shall benchmark this and optimize the performance.
lcr
,
err
:=
s
.
client
.
Lease
.
Grant
(
ctx
,
ttl
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
return
[]
clientv3
.
OpOption
{
clientv3
.
WithLease
(
clientv3
.
LeaseID
(
lcr
.
ID
)
)},
nil
return
[]
clientv3
.
OpOption
{
clientv3
.
WithLease
(
id
)},
nil
}
}
// decode decodes value of bytes into object. It will also set the object resource version to rev.
// decode decodes value of bytes into object. It will also set the object resource version to rev.
...
...
staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go
View file @
f85b7ae8
...
@@ -1186,6 +1186,10 @@ func testSetup(t *testing.T) (context.Context, *store, *integration.ClusterV3) {
...
@@ -1186,6 +1186,10 @@ func testSetup(t *testing.T) (context.Context, *store, *integration.ClusterV3) {
cluster
:=
integration
.
NewClusterV3
(
t
,
&
integration
.
ClusterConfig
{
Size
:
1
})
cluster
:=
integration
.
NewClusterV3
(
t
,
&
integration
.
ClusterConfig
{
Size
:
1
})
store
:=
newStore
(
cluster
.
RandClient
(),
false
,
true
,
codec
,
""
,
prefixTransformer
{
prefix
:
[]
byte
(
defaultTestPrefix
)})
store
:=
newStore
(
cluster
.
RandClient
(),
false
,
true
,
codec
,
""
,
prefixTransformer
{
prefix
:
[]
byte
(
defaultTestPrefix
)})
ctx
:=
context
.
Background
()
ctx
:=
context
.
Background
()
// As 30s is the default timeout for testing in glboal configuration,
// we cannot wait longer than that in a single time: change it to 10
// for testing purposes. See apimachinery/pkg/util/wait/wait.go
store
.
leaseManager
.
setLeaseReuseDurationSeconds
(
1
)
return
ctx
,
store
,
cluster
return
ctx
,
store
,
cluster
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment