mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 20:24:09 +00:00
Merge pull request #12975 from wojtek-t/switch_cacher_for_pods
Switch on Cacher for pods, endpoints and nodes.
This commit is contained in:
commit
46ca41c8e3
@ -430,7 +430,7 @@ func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter)
|
|||||||
func (m *Master) init(c *Config) {
|
func (m *Master) init(c *Config) {
|
||||||
healthzChecks := []healthz.HealthzChecker{}
|
healthzChecks := []healthz.HealthzChecker{}
|
||||||
m.clock = util.RealClock{}
|
m.clock = util.RealClock{}
|
||||||
podStorage := podetcd.NewStorage(c.DatabaseStorage, c.KubeletClient)
|
podStorage := podetcd.NewStorage(c.DatabaseStorage, true, c.KubeletClient)
|
||||||
|
|
||||||
podTemplateStorage := podtemplateetcd.NewREST(c.DatabaseStorage)
|
podTemplateStorage := podtemplateetcd.NewREST(c.DatabaseStorage)
|
||||||
|
|
||||||
@ -446,10 +446,10 @@ func (m *Master) init(c *Config) {
|
|||||||
namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(c.DatabaseStorage)
|
namespaceStorage, namespaceStatusStorage, namespaceFinalizeStorage := namespaceetcd.NewREST(c.DatabaseStorage)
|
||||||
m.namespaceRegistry = namespace.NewRegistry(namespaceStorage)
|
m.namespaceRegistry = namespace.NewRegistry(namespaceStorage)
|
||||||
|
|
||||||
endpointsStorage := endpointsetcd.NewREST(c.DatabaseStorage)
|
endpointsStorage := endpointsetcd.NewREST(c.DatabaseStorage, true)
|
||||||
m.endpointRegistry = endpoint.NewRegistry(endpointsStorage)
|
m.endpointRegistry = endpoint.NewRegistry(endpointsStorage)
|
||||||
|
|
||||||
nodeStorage, nodeStatusStorage := nodeetcd.NewREST(c.DatabaseStorage, c.KubeletClient)
|
nodeStorage, nodeStatusStorage := nodeetcd.NewREST(c.DatabaseStorage, true, c.KubeletClient)
|
||||||
m.nodeRegistry = minion.NewRegistry(nodeStorage)
|
m.nodeRegistry = minion.NewRegistry(nodeStorage)
|
||||||
|
|
||||||
serviceStorage := serviceetcd.NewREST(c.DatabaseStorage)
|
serviceStorage := serviceetcd.NewREST(c.DatabaseStorage)
|
||||||
|
@ -32,8 +32,24 @@ type REST struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewREST returns a RESTStorage object that will work against endpoints.
|
// NewREST returns a RESTStorage object that will work against endpoints.
|
||||||
func NewREST(s storage.Interface) *REST {
|
func NewREST(s storage.Interface, useCacher bool) *REST {
|
||||||
prefix := "/services/endpoints"
|
prefix := "/services/endpoints"
|
||||||
|
|
||||||
|
storageInterface := s
|
||||||
|
if useCacher {
|
||||||
|
config := storage.CacherConfig{
|
||||||
|
CacheCapacity: 1000,
|
||||||
|
Storage: s,
|
||||||
|
Type: &api.Endpoints{},
|
||||||
|
ResourcePrefix: prefix,
|
||||||
|
KeyFunc: func(obj runtime.Object) (string, error) {
|
||||||
|
return storage.NamespaceKeyFunc(prefix, obj)
|
||||||
|
},
|
||||||
|
NewListFunc: func() runtime.Object { return &api.EndpointsList{} },
|
||||||
|
}
|
||||||
|
storageInterface = storage.NewCacher(config)
|
||||||
|
}
|
||||||
|
|
||||||
store := &etcdgeneric.Etcd{
|
store := &etcdgeneric.Etcd{
|
||||||
NewFunc: func() runtime.Object { return &api.Endpoints{} },
|
NewFunc: func() runtime.Object { return &api.Endpoints{} },
|
||||||
NewListFunc: func() runtime.Object { return &api.EndpointsList{} },
|
NewListFunc: func() runtime.Object { return &api.EndpointsList{} },
|
||||||
@ -54,7 +70,7 @@ func NewREST(s storage.Interface) *REST {
|
|||||||
CreateStrategy: endpoint.Strategy,
|
CreateStrategy: endpoint.Strategy,
|
||||||
UpdateStrategy: endpoint.Strategy,
|
UpdateStrategy: endpoint.Strategy,
|
||||||
|
|
||||||
Storage: s,
|
Storage: storageInterface,
|
||||||
}
|
}
|
||||||
return &REST{store}
|
return &REST{store}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
|
|
||||||
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
||||||
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
|
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
|
||||||
return NewREST(etcdStorage), fakeClient
|
return NewREST(etcdStorage, false), fakeClient
|
||||||
}
|
}
|
||||||
|
|
||||||
func validNewEndpoints() *api.Endpoints {
|
func validNewEndpoints() *api.Endpoints {
|
||||||
|
@ -49,8 +49,24 @@ func (r *StatusREST) Update(ctx api.Context, obj runtime.Object) (runtime.Object
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewStorage returns a RESTStorage object that will work against nodes.
|
// NewStorage returns a RESTStorage object that will work against nodes.
|
||||||
func NewREST(s storage.Interface, connection client.ConnectionInfoGetter) (*REST, *StatusREST) {
|
func NewREST(s storage.Interface, useCacher bool, connection client.ConnectionInfoGetter) (*REST, *StatusREST) {
|
||||||
prefix := "/minions"
|
prefix := "/minions"
|
||||||
|
|
||||||
|
storageInterface := s
|
||||||
|
if useCacher {
|
||||||
|
config := storage.CacherConfig{
|
||||||
|
CacheCapacity: 1000,
|
||||||
|
Storage: s,
|
||||||
|
Type: &api.Node{},
|
||||||
|
ResourcePrefix: prefix,
|
||||||
|
KeyFunc: func(obj runtime.Object) (string, error) {
|
||||||
|
return storage.NoNamespaceKeyFunc(prefix, obj)
|
||||||
|
},
|
||||||
|
NewListFunc: func() runtime.Object { return &api.NodeList{} },
|
||||||
|
}
|
||||||
|
storageInterface = storage.NewCacher(config)
|
||||||
|
}
|
||||||
|
|
||||||
store := &etcdgeneric.Etcd{
|
store := &etcdgeneric.Etcd{
|
||||||
NewFunc: func() runtime.Object { return &api.Node{} },
|
NewFunc: func() runtime.Object { return &api.Node{} },
|
||||||
NewListFunc: func() runtime.Object { return &api.NodeList{} },
|
NewListFunc: func() runtime.Object { return &api.NodeList{} },
|
||||||
@ -69,7 +85,7 @@ func NewREST(s storage.Interface, connection client.ConnectionInfoGetter) (*REST
|
|||||||
CreateStrategy: minion.Strategy,
|
CreateStrategy: minion.Strategy,
|
||||||
UpdateStrategy: minion.Strategy,
|
UpdateStrategy: minion.Strategy,
|
||||||
|
|
||||||
Storage: s,
|
Storage: storageInterface,
|
||||||
}
|
}
|
||||||
|
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
|
@ -44,7 +44,7 @@ func (fakeConnectionInfoGetter) GetConnectionInfo(host string) (string, uint, ht
|
|||||||
|
|
||||||
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
|
||||||
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
|
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
|
||||||
storage, _ := NewREST(etcdStorage, fakeConnectionInfoGetter{})
|
storage, _ := NewREST(etcdStorage, false, fakeConnectionInfoGetter{})
|
||||||
return storage, fakeClient
|
return storage, fakeClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,8 +57,24 @@ type REST struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewStorage returns a RESTStorage object that will work against pods.
|
// NewStorage returns a RESTStorage object that will work against pods.
|
||||||
func NewStorage(s storage.Interface, k client.ConnectionInfoGetter) PodStorage {
|
func NewStorage(s storage.Interface, useCacher bool, k client.ConnectionInfoGetter) PodStorage {
|
||||||
prefix := "/pods"
|
prefix := "/pods"
|
||||||
|
|
||||||
|
storageInterface := s
|
||||||
|
if useCacher {
|
||||||
|
config := storage.CacherConfig{
|
||||||
|
CacheCapacity: 1000,
|
||||||
|
Storage: s,
|
||||||
|
Type: &api.Pod{},
|
||||||
|
ResourcePrefix: prefix,
|
||||||
|
KeyFunc: func(obj runtime.Object) (string, error) {
|
||||||
|
return storage.NamespaceKeyFunc(prefix, obj)
|
||||||
|
},
|
||||||
|
NewListFunc: func() runtime.Object { return &api.PodList{} },
|
||||||
|
}
|
||||||
|
storageInterface = storage.NewCacher(config)
|
||||||
|
}
|
||||||
|
|
||||||
store := &etcdgeneric.Etcd{
|
store := &etcdgeneric.Etcd{
|
||||||
NewFunc: func() runtime.Object { return &api.Pod{} },
|
NewFunc: func() runtime.Object { return &api.Pod{} },
|
||||||
NewListFunc: func() runtime.Object { return &api.PodList{} },
|
NewListFunc: func() runtime.Object { return &api.PodList{} },
|
||||||
@ -76,7 +92,7 @@ func NewStorage(s storage.Interface, k client.ConnectionInfoGetter) PodStorage {
|
|||||||
},
|
},
|
||||||
EndpointName: "pods",
|
EndpointName: "pods",
|
||||||
|
|
||||||
Storage: s,
|
Storage: storageInterface,
|
||||||
}
|
}
|
||||||
statusStore := *store
|
statusStore := *store
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ import (
|
|||||||
|
|
||||||
func newStorage(t *testing.T) (*REST, *BindingREST, *StatusREST, *tools.FakeEtcdClient) {
|
func newStorage(t *testing.T) (*REST, *BindingREST, *StatusREST, *tools.FakeEtcdClient) {
|
||||||
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
|
etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
|
||||||
storage := NewStorage(etcdStorage, nil)
|
storage := NewStorage(etcdStorage, false, nil)
|
||||||
return storage.Pod, storage.Binding, storage.Status, fakeClient
|
return storage.Pod, storage.Binding, storage.Status, fakeClient
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,7 +989,8 @@ func TestEtcdWatchPodsMatch(t *testing.T) {
|
|||||||
|
|
||||||
pod := &api.Pod{
|
pod := &api.Pod{
|
||||||
ObjectMeta: api.ObjectMeta{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
|
Namespace: "default",
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
},
|
},
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/cache"
|
"k8s.io/kubernetes/pkg/client/unversioned/cache"
|
||||||
"k8s.io/kubernetes/pkg/conversion"
|
"k8s.io/kubernetes/pkg/conversion"
|
||||||
"k8s.io/kubernetes/pkg/runtime"
|
"k8s.io/kubernetes/pkg/runtime"
|
||||||
@ -62,9 +63,14 @@ type CacherConfig struct {
|
|||||||
// Cacher is responsible for serving WATCH and LIST requests for a given
|
// Cacher is responsible for serving WATCH and LIST requests for a given
|
||||||
// resource from its internal cache and updating its cache in the background
|
// resource from its internal cache and updating its cache in the background
|
||||||
// based on the underlying storage contents.
|
// based on the underlying storage contents.
|
||||||
|
// Cacher implements storage.Interface (although most of the calls are just
|
||||||
|
// delegated to the underlying storage).
|
||||||
type Cacher struct {
|
type Cacher struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
|
// Underlying storage.Interface.
|
||||||
|
storage Interface
|
||||||
|
|
||||||
// Whether Cacher is initialized.
|
// Whether Cacher is initialized.
|
||||||
initialized sync.WaitGroup
|
initialized sync.WaitGroup
|
||||||
initOnce sync.Once
|
initOnce sync.Once
|
||||||
@ -93,6 +99,7 @@ func NewCacher(config CacherConfig) *Cacher {
|
|||||||
|
|
||||||
cacher := &Cacher{
|
cacher := &Cacher{
|
||||||
initialized: sync.WaitGroup{},
|
initialized: sync.WaitGroup{},
|
||||||
|
storage: config.Storage,
|
||||||
watchCache: watchCache,
|
watchCache: watchCache,
|
||||||
reflector: cache.NewReflector(listerWatcher, config.Type, watchCache, 0),
|
reflector: cache.NewReflector(listerWatcher, config.Type, watchCache, 0),
|
||||||
watcherIdx: 0,
|
watcherIdx: 0,
|
||||||
@ -134,7 +141,32 @@ func (c *Cacher) startCaching(stopChannel <-chan struct{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Watch (signature from storage.Interface).
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Backends() []string {
|
||||||
|
return c.storage.Backends()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Versioner() Versioner {
|
||||||
|
return c.storage.Versioner()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Create(key string, obj, out runtime.Object, ttl uint64) error {
|
||||||
|
return c.storage.Create(key, obj, out, ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Set(key string, obj, out runtime.Object, ttl uint64) error {
|
||||||
|
return c.storage.Set(key, obj, out, ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Delete(key string, out runtime.Object) error {
|
||||||
|
return c.storage.Delete(key, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
func (c *Cacher) Watch(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
|
func (c *Cacher) Watch(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
|
||||||
// We explicitly use thread unsafe version and do locking ourself to ensure that
|
// We explicitly use thread unsafe version and do locking ourself to ensure that
|
||||||
// no new events will be processed in the meantime. The watchCache will be unlocked
|
// no new events will be processed in the meantime. The watchCache will be unlocked
|
||||||
@ -156,13 +188,34 @@ func (c *Cacher) Watch(key string, resourceVersion uint64, filter FilterFunc) (w
|
|||||||
return watcher, nil
|
return watcher, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements WatchList (signature from storage.Interface).
|
// Implements storage.Interface.
|
||||||
func (c *Cacher) WatchList(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
|
func (c *Cacher) WatchList(key string, resourceVersion uint64, filter FilterFunc) (watch.Interface, error) {
|
||||||
return c.Watch(key, resourceVersion, filter)
|
return c.Watch(key, resourceVersion, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements List (signature from storage.Interface).
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Get(key string, objPtr runtime.Object, ignoreNotFound bool) error {
|
||||||
|
return c.storage.Get(key, objPtr, ignoreNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) GetToList(key string, listObj runtime.Object) error {
|
||||||
|
return c.storage.GetToList(key, listObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
func (c *Cacher) List(key string, listObj runtime.Object) error {
|
func (c *Cacher) List(key string, listObj runtime.Object) error {
|
||||||
|
return c.storage.List(key, listObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListFromMemory implements list operation (the same signature as List method)
|
||||||
|
// but it serves the contents from memory.
|
||||||
|
// Current we cannot use ListFromMemory() instead of List(), because it only
|
||||||
|
// guarantees eventual consistency (e.g. it's possible for Get called right after
|
||||||
|
// Create to return not-exist, before the change is propagate).
|
||||||
|
// TODO: We may consider changing to use ListFromMemory in the future, but this
|
||||||
|
// requires wider discussion as an "api semantic change".
|
||||||
|
func (c *Cacher) ListFromMemory(key string, listObj runtime.Object) error {
|
||||||
listPtr, err := runtime.GetItemsPtr(listObj)
|
listPtr, err := runtime.GetItemsPtr(listObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -191,6 +244,16 @@ func (c *Cacher) List(key string, listObj runtime.Object) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) GuaranteedUpdate(key string, ptrToType runtime.Object, ignoreNotFound bool, tryUpdate UpdateFunc) error {
|
||||||
|
return c.storage.GuaranteedUpdate(key, ptrToType, ignoreNotFound, tryUpdate)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements storage.Interface.
|
||||||
|
func (c *Cacher) Codec() runtime.Codec {
|
||||||
|
return c.storage.Codec()
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cacher) processEvent(event cache.WatchCacheEvent) {
|
func (c *Cacher) processEvent(event cache.WatchCacheEvent) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
@ -327,13 +390,23 @@ func (c *cacheWatcher) sendWatchCacheEvent(event cache.WatchCacheEvent) {
|
|||||||
if event.PrevObject != nil {
|
if event.PrevObject != nil {
|
||||||
oldObjPasses = c.filter(event.PrevObject)
|
oldObjPasses = c.filter(event.PrevObject)
|
||||||
}
|
}
|
||||||
|
if !curObjPasses && !oldObjPasses {
|
||||||
|
// Watcher is not interested in that object.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
object, err := api.Scheme.Copy(event.Object)
|
||||||
|
if err != nil {
|
||||||
|
glog.Errorf("unexpected copy error: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
switch {
|
switch {
|
||||||
case curObjPasses && !oldObjPasses:
|
case curObjPasses && !oldObjPasses:
|
||||||
c.result <- watch.Event{Type: watch.Added, Object: event.Object}
|
c.result <- watch.Event{Type: watch.Added, Object: object}
|
||||||
case curObjPasses && oldObjPasses:
|
case curObjPasses && oldObjPasses:
|
||||||
c.result <- watch.Event{Type: watch.Modified, Object: event.Object}
|
c.result <- watch.Event{Type: watch.Modified, Object: object}
|
||||||
case !curObjPasses && oldObjPasses:
|
case !curObjPasses && oldObjPasses:
|
||||||
c.result <- watch.Event{Type: watch.Deleted, Object: event.Object}
|
c.result <- watch.Event{Type: watch.Deleted, Object: object}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func waitForUpToDateCache(cacher *storage.Cacher, resourceVersion uint64) error
|
|||||||
return wait.Poll(10*time.Millisecond, 100*time.Millisecond, ready)
|
return wait.Poll(10*time.Millisecond, 100*time.Millisecond, ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestList(t *testing.T) {
|
func TestListFromMemory(t *testing.T) {
|
||||||
fakeClient := tools.NewFakeEtcdClient(t)
|
fakeClient := tools.NewFakeEtcdClient(t)
|
||||||
prefixedKey := etcdtest.AddPrefix("pods")
|
prefixedKey := etcdtest.AddPrefix("pods")
|
||||||
fakeClient.ExpectNotFoundGet(prefixedKey)
|
fakeClient.ExpectNotFoundGet(prefixedKey)
|
||||||
@ -151,7 +151,7 @@ func TestList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
result := &api.PodList{}
|
result := &api.PodList{}
|
||||||
if err := cacher.List("pods/ns", result); err != nil {
|
if err := cacher.ListFromMemory("pods/ns", result); err != nil {
|
||||||
t.Errorf("unexpected error: %v", err)
|
t.Errorf("unexpected error: %v", err)
|
||||||
}
|
}
|
||||||
if result.ListMeta.ResourceVersion != "5" {
|
if result.ListMeta.ResourceVersion != "5" {
|
||||||
|
@ -58,3 +58,11 @@ func NamespaceKeyFunc(prefix string, obj runtime.Object) (string, error) {
|
|||||||
}
|
}
|
||||||
return prefix + "/" + meta.Namespace() + "/" + meta.Name(), nil
|
return prefix + "/" + meta.Namespace() + "/" + meta.Name(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NoNamespaceKeyFunc(prefix string, obj runtime.Object) (string, error) {
|
||||||
|
meta, err := meta.Accessor(obj)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return prefix + "/" + meta.Name(), nil
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user