From c91dff18721022b13e365c1df716d6ab77ba721e Mon Sep 17 00:00:00 2001 From: chentao <421224811@qq.com> Date: Tue, 23 Mar 2021 13:06:39 +0800 Subject: [PATCH] add proposal --- docs/img/img-20210301001.png | Bin 0 -> 40779 bytes docs/img/img-20210323001.png | Bin 0 -> 27030 bytes docs/img/img-20210323002.png | Bin 0 -> 18209 bytes ...-enhancement_of_YurtHub_caching_ability.md | 375 ++++++++++++++++++ 4 files changed, 375 insertions(+) create mode 100644 docs/img/img-20210301001.png create mode 100644 docs/img/img-20210323001.png create mode 100644 docs/img/img-20210323002.png create mode 100644 docs/proposals/20210301-enhancement_of_YurtHub_caching_ability.md diff --git a/docs/img/img-20210301001.png b/docs/img/img-20210301001.png new file mode 100644 index 0000000000000000000000000000000000000000..72f7d7e8e9baacca4e7c02f214c4f4705be66cee GIT binary patch literal 40779 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 N$JWXTs<7~i`wu8068-=H literal 0 HcmV?d00001 diff --git a/docs/img/img-20210323001.png b/docs/img/img-20210323001.png new file mode 100644 index 0000000000000000000000000000000000000000..934c0b254863a4c0d9ac3d40fccbc6a86333da71 GIT binary patch literal 27030 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 VEFi$<9=r^eJ%%LWeFK-M{{nOFlxP3| literal 0 HcmV?d00001 diff --git a/docs/img/img-20210323002.png b/docs/img/img-20210323002.png new file mode 100644 index 0000000000000000000000000000000000000000..060a4d7e965a0c56f6271fe92591417e177f836e GIT binary patch literal 18209 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 literal 0 HcmV?d00001 diff --git a/docs/proposals/20210301-enhancement_of_YurtHub_caching_ability.md b/docs/proposals/20210301-enhancement_of_YurtHub_caching_ability.md new file mode 100644 index 00000000000..648480f603b --- /dev/null +++ b/docs/proposals/20210301-enhancement_of_YurtHub_caching_ability.md @@ -0,0 +1,375 @@ +--- +title: Proposal to enhance the caching ability of YurtHub +authors: + - "@qclc" + - "@GsssC" +reviewers: + - "@rambohe-ch" +creation-date: 2021-03-01 +last-updated: 2021-03-01 +status: provisional + +--- + +# Proposal to enhance the caching ability of YurtHub + +## Table of Contents + +- [Title](#title) + - [Table of Contents](#table-of-contents) + - [Summary](#summary) + - [Motivation](#motivation) + - [Goals](#goals) + - [Description of Yurthub's existing cache ability](#description-of-Yurthub's-existing-cache-ability) + - [serializerManager](#serializerManager) + - [Problem One](#problem-one) + - [cacheManager](#cacheManager) + - [Problem Two](#problem-two) + - [Problem Three](#problem-three) + - [Proposal](#proposal) + - [1. Delete resourceToKindMap and resourceToListKindMap](#1-delete-resourceToKindMap-and-resourceToListKindMap) + - [1.1 Design detail](#1.1-design-detail) + - [2. Decode the unregistered Custom Resources into Unstructured structure](#2-decode-the-unregistered-Custom-Resources-into-Unstructured-structure) + - [2.1 Design detail](#2.1-design-detail) + - [Add unstructuredNegotiatedSerializer](#add-unstructuredNegotiatedSerializer) + - [Determine the resource type based on request.URL and select the appropriate serializer](#determine-the-resource-type-based-on-request.URL-and-select-the-appropriate-serializer) + - [3. Abstract the logic of processing objects into a separate processing layer](#3-Abstract-the-logic-of-processing-objects-into-a-separate-processing-layer) + - [3.1 Design detail](#3.1-design-detail) + - [Implementation History](#implementation-history) + +## Summary + +YurtHub can currently only cache resources defined in [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62). This proposal mainly tries to put forward and realize a set of scheme, so that YurtHub is no longer limited by resource types, and Custom Resources can be cached. + +## Motivation + +When network between cloud and edge disconnected, if any pod(eg: calico) on the edge node that used some resources(like crd) not in the above map want to run continuously, that is to say, the pod can not restarted successfully because resources(like crd) are not cached by yurt-hub. + +### Goals + +- To remove the restriction that yurthub can only cache certain resources; +- To support decoding Custom Resources that are not registered in the scheme as `Unstructured` structures; +- To improve the scalability of YurtHub by abstracting the logic of processing objects into a separate processing layer; + +## Description of Yurthub's existing cache ability + +This section briefly describes how Yurthub receives and caches response with resources from Kube-apiserver, mainly involving the CacheManager and SerializerManager modules. Yurthub caches resources, which roughly requires two steps: + +![temp](../img/img-20210323002.png) + +**Step 1:** Decode the byte stream contained in `Response.Body` into `Runtime.Object` type in memory, so that YurtHub can operate the Object; + +**Step 2:** Encode the runtime.Object type into the corresponding byte stream and save it to the hard disk. + +The limitations of the existing caching ability in YurtHub are mainly in the first step: One is the limitation of [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62); The second is the lack of a serializer to decode and encode Custom Resources. + +### serializerManager + +SerializerManager is used to manage the serializers that decode and encode K8S resources. When SerializerManager is initialized, the structure of the built-in resources in the Client-Go library is registered in the scheme, such as the Pod structure example: + +```go +type Pod struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + Spec PodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` + Status PodStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} +``` + +Currently Yurthub can only encode and decode resources under [these paths](https://github.com/kubernetes/client-go/blob/master/kubernetes/scheme/register.go): + +```go +admissionregistrationv1 "k8s.io/api/admissionregistration/v1" +admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" +appsv1 "k8s.io/api/apps/v1" +appsv1beta1 "k8s.io/api/apps/v1beta1" +appsv1beta2 "k8s.io/api/apps/v1beta2" +auditregistrationv1alpha1 "k8s.io/api/auditregistration/v1alpha1" +authenticationv1 "k8s.io/api/authentication/v1" +authenticationv1beta1 "k8s.io/api/authentication/v1beta1" +authorizationv1 "k8s.io/api/authorization/v1" +authorizationv1beta1 "k8s.io/api/authorization/v1beta1" +autoscalingv1 "k8s.io/api/autoscaling/v1" +autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1" +autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2" +batchv1 "k8s.io/api/batch/v1" +batchv1beta1 "k8s.io/api/batch/v1beta1" +batchv2alpha1 "k8s.io/api/batch/v2alpha1" +certificatesv1beta1 "k8s.io/api/certificates/v1beta1" +coordinationv1 "k8s.io/api/coordination/v1" +coordinationv1beta1 "k8s.io/api/coordination/v1beta1" +corev1 "k8s.io/api/core/v1" +discoveryv1alpha1 "k8s.io/api/discovery/v1alpha1" +eventsv1beta1 "k8s.io/api/events/v1beta1" +extensionsv1beta1 "k8s.io/api/extensions/v1beta1" +networkingv1 "k8s.io/api/networking/v1" +networkingv1beta1 "k8s.io/api/networking/v1beta1" +nodev1alpha1 "k8s.io/api/node/v1alpha1" +nodev1beta1 "k8s.io/api/node/v1beta1" +policyv1beta1 "k8s.io/api/policy/v1beta1" +rbacv1 "k8s.io/api/rbac/v1" +rbacv1alpha1 "k8s.io/api/rbac/v1alpha1" +rbacv1beta1 "k8s.io/api/rbac/v1beta1" +schedulingv1 "k8s.io/api/scheduling/v1" +schedulingv1alpha1 "k8s.io/api/scheduling/v1alpha1" +schedulingv1beta1 "k8s.io/api/scheduling/v1beta1" +settingsv1alpha1 "k8s.io/api/settings/v1alpha1" +storagev1 "k8s.io/api/storage/v1" +storagev1alpha1 "k8s.io/api/storage/v1alpha1" +storagev1beta1 "k8s.io/api/storage/v1beta1" +v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +runtime "k8s.io/apimachinery/pkg/runtime" +schema "k8s.io/apimachinery/pkg/runtime/schema" +serializer "k8s.io/apimachinery/pkg/runtime/serializer" +utilruntime "k8s.io/apimachinery/pkg/util/runtime" +``` + +#### Problem One + +Because scheme currently only saves the above fixed resources' structures, when YurtHub receives Custom Resources returned from kube-apiserver, it cannot find the corresponding GO type structure to decode Custom Resources. + +### cacheManager + +CacheManager provides methods for managing resources cached on edge nodes, which are divided into three main functions: + +- Determining whether the response message needs to be cached +- The resource byte stream from Kube-apiserver is decoded into `runtime.Object` and stored in memory. When the YurtHub operation is completed, the object is converted to a byte stream and stored on the hard disk + +- When cloud-edge communication is unhealthy, edge nodes use `QueryCache(...)` to find resources cached locally. + +```go +// CacheManager is an adaptor to cache runtime object data into backend storage +type CacheManager interface { + CacheResponse(ctx context.Context, prc io.ReadCloser, stopCh <-chan struct{}) error + QueryCache(req *http.Request) (runtime.Object, error) + UpdateCacheAgents(agents []string) error + ListCacheAgents() []string + CanCacheFor(req *http.Request) bool +} +``` + +#### Problem Two + +Since the serializer currently used by YurtHub will lose GVK information when decoding resource objects. So we need to [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62) to obtain the corresponding kind information according to resource name. The two maps have the following three main functions: + +- `CanCacheFor(req *http.Request)` function uses a resourceToKindMap to determine if the response message needs to be cached; + +- `SaveOneObject(...)`, `SaveListObject(...)` and `SaveWatchObject(...)` use resourceToKindMap to obtain the kind information corresponding to the resource name, which is used to cache the response message; + + Because the resolved object does not contain GVK information. But when caching objects, GVK information needs to be set. The above two maps pre-store some resource-to-kind mappings, which can be used to cache resources and retrieve the corresponding kind based on the resource name in the request.URL . + +- The `queryListObject(...)` function uses the resourceToListKindMap member to query the List object + +##### Why the decoding process loses GVK information + +Currently, yurthub use [serializer.WithoutConversionCodecFactory](https://github.com/alibaba/openyurt/blob/7095962687e2666a27d14e436b96ef893b228beb/pkg/yurthub/kubernetes/serializer/serializer.go#L48) as NegotiatedSerializer generated serializers for different formats of byte streams (json, yaml or protobuf). It will explicitly ignore requests to perform conversion. When decoding, it parses the group and version information from the byte stream, directly decoding the resource into its original version. + +According to the source code analysis, the resource's GVK information is erased when decoded using the serializer generated by `WithoutConversionCodecFactory`. Here is the actual [decoder code](https://github.com/kubernetes/kubernetes/blob/994b5c6cc20bda188ac9bc33217f2dbc7ecf45bb/staging/src/k8s.io/apimachinery/pkg/runtime/helper.go#L256) that is invoked: + +```go +// Decode does not do conversion. It removes the gvk during deserialization. +func (d WithoutVersionDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into Object) (Object, *schema.GroupVersionKind, error) { + obj, gvk, err := d.Decoder.Decode(data, defaults, into) + if obj != nil { + kind := obj.GetObjectKind() + // clearing the gvk is just a convention of a codec + kind.SetGroupVersionKind(schema.GroupVersionKind{}) + } + return obj, gvk, err +} +``` + +Due to the above limitations, Yurthub can only cache resources defined in [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62). + +#### Problem Three + +Yurthub combines the byte stream decoding and object processing logic together, resulting in a high level of coupling and some code redundancy. For example, all the `SaveOneObject (...)`, `SaveListObject(...)` and `SaveWatchObject(...)` need to set the object's GVK information: + +```go +func (cm *cacheManager) saveWatchObject(ctx context.Context, info *apirequest.RequestInfo, r io.ReadCloser, stopCh <-chan struct{}) error { + //...... + accessor.SetAPIVersion(obj, apiVersion) + accessor.SetKind(obj, kind) + //...... +} +``` + +```go +func (cm *cacheManager) saveListObject(ctx context.Context, info *apirequest.RequestInfo, b []byte) error { + //...... + accessor.SetKind(items[i], kind) + accessor.SetAPIVersion(items[i], apiVersion) + //...... +} +``` + +```go +func (cm *cacheManager) saveOneObject(ctx context.Context, info *apirequest.RequestInfo, b []byte) error { + //...... + accessor.SetKind(obj, kind) + accessor.SetAPIVersion(obj, apiVersion) + //...... +} +``` + +## Proposal + +### 1. Delete [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62) + +Remove the restriction that only certain resources can be cached by removing [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62). Removing the above restriction requires solving the problem which is preserving the original GVK information while decoding the corresponding resources; + +#### 1.1 Design detail + +Define a new `WithVersionCodecFactory` replace the [serializer.WithoutConversionCodecFactory](https://github.com/alibaba/openyurt/blob/7095962687e2666a27d14e436b96ef893b228beb/pkg/yurthub/kubernetes/serializer/serializer.go#L48) as a negotiatedSerializer, which can retain GVK information while decoding resources. Here is part of the WithVersionCodecFactory code + +```go +// WithVersionCodecFactory is a CodecFactory that will explicitly ignore requests to perform conversion. +// It keeps the gvk during deserialization. +// This wrapper is used while code migrates away from using conversion (such as external clients) +type WithVersionCodecFactory struct { + serializer.CodecFactory +} + +// DecoderToVersion returns an decoder that does not do conversion, and keeps the gvk information +func (f WithVersionCodecFactory) DecoderToVersion(serializer runtime.Decoder, _ runtime.GroupVersioner) runtime.Decoder { + //return versioning.NewDefaultingCodecForScheme(s.scheme, nil, decoder, nil, gv) + return WithVersionDecoder{ + Decoder: serializer, + } +} + +// WithVersionDecoder keeps the group version kind of a deserialized object. +type WithVersionDecoder struct { + runtime.Decoder +} + +// Decode does not do conversion. It keeps the gvk during deserialization. +func (d WithVersionDecoder) Decode(data []byte, defaults *schema.GroupVersionKind, into runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) { + obj, gvk, err := d.Decoder.Decode(data, defaults, into) + return obj, gvk, err +} +``` + +### 2. Decode the unregistered Custom Resources into `Unstructured` structure + +Unstructured allows objects that do not have Golang structs registered to be manipulated generically. This can be used to deal with the API objects from a plug-in. + +```go +//Unstructured objects still have functioning TypeMeta features-- kind, version, etc. +type Unstructured struct { + // Object is a JSON compatible map with string, float, int, bool, []interface{}, or + // map[string]interface{} + // children. + Object map[string]interface{} +} +``` + +#### 2.1 Design detail + +##### Add unstructuredNegotiatedSerializer + +On the basis of the existing NegotiatedSerializer increase a new unstructuredNegotiatedSerializer, used to decode the structure of the unregistered Custom Resources. + +```go +type unstructuredNegotiatedSerializer struct { + scheme *runtime.Scheme + typer runtime.ObjectTyper + creator runtime.ObjectCreater +} + +// SerializerManager is responsible for managing *rest.Serializers +type SerializerManager struct { + // NegotiatedSerializer is used for obtaining encoders and decoders for multiple + // supported media types. + NegotiatedSerializer runtime.NegotiatedSerializer + //TO-ADD: use to decode the CR + unstructuredNegotiatedSerializer runtime.NegotiatedSerializer +} +``` + +##### Select the appropriate serializer based on GVK information + +When cache resources, get the GVK information of resource based on the GVR in `request.URL` and `RESTMapper` (which is used to check whether the GVK is in the scheme according to the GVR information). An implementation of `RESTMapper` is as follows: + +```go +type DefaultRESTMapper struct { + defaultGroupVersions []schema.GroupVersion + + resourceToKind map[schema.GroupVersionResource]schema.GroupVersionKind + kindToPluralResource map[schema.GroupVersionKind]schema.GroupVersionResource + kindToScope map[schema.GroupVersionKind]RESTScope + singularToPlural map[schema.GroupVersionResource]schema.GroupVersionResource + pluralToSingular map[schema.GroupVersionResource]schema.GroupVersionResource +} +``` + +If the resource's GVK has been registered, use the original serializer, otherwise use the serializer returned by `unstructuredNegotiatedSerializer` . + +![unstructure](../img/img-20210301001.png) + +### 3. Abstract the logic of processing objects into a separate processing layer + +The object processing logic is divided into two layers: filtering layer and processing layer. For each GVR, the corresponding filtering, adding, updating and deleting logic is set and managed. + +#### 3.1 Design detail + +The following is a flowchart for decoding, processing, and saving runtime.Object locally: + +![new flow](../img/img-20210323001.png) + +In the cacheManager, add `handlerLayer` to process object: + +```go +type cacheManager struct { + sync.RWMutex + storage StorageWrapper + serializerManager *serializer.SerializerManager + //add handlerLayer to process object + handlerLayer HandlerLayer + cacheAgents map[string]bool +} +``` + +Followings are definitions of `HandlerLayer` interface and its related structs. It can use the `AddHandler(...)` functions to add the handlers for different GVR. + +```go +type HandlerLayer interface { + AddHandler(gvr schema.GroupVersionResource, handler ResourceEventHandler) error + GetHandler(gvr schema.GroupVersionResource) ResourceEventHandler +} + +//handlerLayers store and manage the handler funcs for each GVR +type handlerLayer struct { + handlers map[schema.GroupVersionResource]ResourceEventHandler +} + +// ResourceEventHandler is the interface used to process the object in different events +type ResourceEventHandler interface { + OnAdd(obj interface{}) + OnUpdate(oldObj, newObj interface{}) + OnDelete(obj interface{}) +} +``` + +Followings are definitions of `ResourceEventHandlerFuncs` and `FilteringResourceEventHandler` which will implement the `ResourceEventHandler` interface + +```go +// ResourceEventHandlerFuncs store the func for Add, Update, Delete event of object +type ResourceEventHandlerFuncs struct { + AddFunc func(obj interface{}) + UpdateFunc func(oldObj, newObj interface{}) + DeleteFunc func(obj interface{}) +} + +// FilteringResourceEventHandler add the filter func based on the ResourceEventHandlerFuncs +type FilteringResourceEventHandler struct { + FilterFunc func(obj interface{}) bool + Handler ResourceEventHandlerFuncs +} +``` + +## Implementation History + +- [ ] 03/01/2021: Proposed idea. +- [ ] 03/01/2021: Commit the PR about delete [resourceToKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L46) and [resourceToListKindMap](https://github.com/openyurtio/openyurt/blob/4d7463a40801c29d09c4f7d10ba46b73cb019915/pkg/yurthub/cachemanager/cache_manager.go#L62) (https://github.com/openyurtio/openyurt/pull/225) +- [ ] 03/23/2021: Update this proposal \ No newline at end of file