Skip to content

feat: cache object pruning #1630

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 23 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion docs/documentation/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,29 @@ setting, where this flag usually needs to be set to false, in order to control t
See also an example implementation in the
[WebPage sample](https://github.com/java-operator-sdk/java-operator-sdk/blob/3e2e7c4c834ef1c409d636156b988125744ca911/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageOperator.java#L38-L43)

## Monitoring with Micrometer
## Optimization of Caches

** Cache pruning is an experimental feature. Might a subject of change or even removal in the future. **

Operators using informers will initially cache the data for all known resources when starting up
so that access to resources can be performed quickly. Consequently, the memory required for the
operator to run and startup time will both increase quite dramatically when dealing with large
clusters with numerous resources.

It is thus possible to configure the operator to cache only pruned versions of the resources to
alleviate the memory usage of the primary and secondary caches. This setup, however, has
implications on how reconcilers deal with resources since they will only work with partial
objects. As a consequence, resources need to be updated using PATCH operations only, sending
only required changes.

To see how to use, and how to handle related caveats regarding how to deal with pruned objects
that leverage
[server side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/) patches,
please check the provided
[integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/c688524e64205690ba15587e7ed96a64dc231430/operator-framework/src/test/java/io/javaoperatorsdk/operator/CachePruneIT.java)
and associates reconciler.

Pruned caches are currently not supported with the Dependent Resources feature.

## Automatic Generation of CRDs

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import io.fabric8.kubernetes.api.model.HasMetadata;
Expand Down Expand Up @@ -83,6 +84,14 @@ public Set<String> getNamespaces() {
DEFAULT_NAMESPACES_SET.toArray(String[]::new)));
}

@Override
@SuppressWarnings("unchecked")
public Optional<UnaryOperator<P>> cachePruneFunction() {
return Optional.ofNullable(
Utils.instantiate(annotation.cachePruneFunction(), UnaryOperator.class,
Utils.contextFor(this, null, null)));
}

@Override
@SuppressWarnings("unchecked")
public Class<P> getResourceClass() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

import io.fabric8.kubernetes.api.model.HasMetadata;
Expand Down Expand Up @@ -38,6 +39,7 @@ public class ControllerConfigurationOverrider<R extends HasMetadata> {
private OnUpdateFilter<R> onUpdateFilter;
private GenericFilter<R> genericFilter;
private RateLimiter rateLimiter;
private UnaryOperator<R> cachePruneFunction;

private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
finalizer = original.getFinalizerName();
Expand All @@ -56,6 +58,7 @@ private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
dependentResources.forEach(drs -> namedDependentResourceSpecs.put(drs.getName(), drs));
this.original = original;
this.rateLimiter = original.getRateLimiter();
this.cachePruneFunction = original.cachePruneFunction().orElse(null);
}

public ControllerConfigurationOverrider<R> withFinalizer(String finalizer) {
Expand Down Expand Up @@ -158,6 +161,12 @@ public ControllerConfigurationOverrider<R> withGenericFilter(GenericFilter<R> ge
return this;
}

public ControllerConfigurationOverrider<R> withCachePruneFunction(
UnaryOperator<R> cachePruneFunction) {
this.cachePruneFunction = cachePruneFunction;
return this;
}

@SuppressWarnings("unchecked")
public ControllerConfigurationOverrider<R> replacingNamedDependentResourceConfig(String name,
Object dependentResourceConfig) {
Expand Down Expand Up @@ -208,7 +217,7 @@ public ControllerConfiguration<R> build() {
onUpdateFilter,
genericFilter,
rateLimiter,
newDependentSpecs);
newDependentSpecs, cachePruneFunction);
}

public static <R extends HasMetadata> ControllerConfigurationOverrider<R> override(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
Expand Down Expand Up @@ -49,8 +50,10 @@ public DefaultControllerConfiguration(
OnUpdateFilter<R> onUpdateFilter,
GenericFilter<R> genericFilter,
RateLimiter rateLimiter,
List<DependentResourceSpec> dependents) {
super(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter, namespaces);
List<DependentResourceSpec> dependents,
UnaryOperator<R> cachePruneFunction) {
super(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter, namespaces,
cachePruneFunction);
this.associatedControllerClassName = associatedControllerClassName;
this.name = name;
this.crdName = crdName;
Expand Down Expand Up @@ -116,4 +119,5 @@ public Optional<Duration> maxReconciliationInterval() {
public RateLimiter getRateLimiter() {
return rateLimiter;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
Expand All @@ -19,18 +20,23 @@ public class DefaultResourceConfiguration<R extends HasMetadata>
private final OnAddFilter<R> onAddFilter;
private final OnUpdateFilter<R> onUpdateFilter;
private final GenericFilter<R> genericFilter;
private final UnaryOperator<R> cachePruneFunction;

public DefaultResourceConfiguration(String labelSelector, Class<R> resourceClass,
OnAddFilter<R> onAddFilter,
OnUpdateFilter<R> onUpdateFilter, GenericFilter<R> genericFilter, String... namespaces) {
this(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter,
namespaces == null || namespaces.length == 0 ? DEFAULT_NAMESPACES_SET
: Set.of(namespaces));
: Set.of(namespaces),
null);
}

public DefaultResourceConfiguration(String labelSelector, Class<R> resourceClass,
OnAddFilter<R> onAddFilter,
OnUpdateFilter<R> onUpdateFilter, GenericFilter<R> genericFilter, Set<String> namespaces) {
OnUpdateFilter<R> onUpdateFilter,
GenericFilter<R> genericFilter,
Set<String> namespaces,
UnaryOperator<R> cachePruneFunction) {
this.labelSelector = labelSelector;
this.resourceClass = resourceClass;
this.onAddFilter = onAddFilter;
Expand All @@ -39,6 +45,7 @@ public DefaultResourceConfiguration(String labelSelector, Class<R> resourceClass
this.namespaces =
namespaces == null || namespaces.isEmpty() ? DEFAULT_NAMESPACES_SET
: namespaces;
this.cachePruneFunction = cachePruneFunction;
}

@Override
Expand All @@ -56,6 +63,11 @@ public Set<String> getNamespaces() {
return namespaces;
}

@Override
public Optional<UnaryOperator<R>> cachePruneFunction() {
return Optional.ofNullable(this.cachePruneFunction);
}

@Override
public Class<R> getResourceClass() {
return resourceClass;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.OperatorException;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
Expand Down Expand Up @@ -108,4 +110,11 @@ default Set<String> getEffectiveNamespaces() {
}
return targetNamespaces;
}

/**
* See {@link ControllerConfiguration#cachePruneFunction()} for details.
*/
default Optional<UnaryOperator<R>> cachePruneFunction() {
return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.function.UnaryOperator;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration;
Expand All @@ -29,6 +30,7 @@ class DefaultInformerConfiguration<R extends HasMetadata> extends
private final SecondaryToPrimaryMapper<R> secondaryToPrimaryMapper;
private final boolean followControllerNamespaceChanges;
private final OnDeleteFilter<R> onDeleteFilter;
private final UnaryOperator<R> cachePruneFunction;

protected DefaultInformerConfiguration(String labelSelector,
Class<R> resourceClass,
Expand All @@ -38,15 +40,18 @@ protected DefaultInformerConfiguration(String labelSelector,
OnAddFilter<R> onAddFilter,
OnUpdateFilter<R> onUpdateFilter,
OnDeleteFilter<R> onDeleteFilter,
GenericFilter<R> genericFilter) {
super(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter, namespaces);
GenericFilter<R> genericFilter,
UnaryOperator<R> cachePruneFunction) {
super(labelSelector, resourceClass, onAddFilter, onUpdateFilter, genericFilter, namespaces,
cachePruneFunction);
this.followControllerNamespaceChanges = followControllerNamespaceChanges;

this.primaryToSecondaryMapper = primaryToSecondaryMapper;
this.secondaryToPrimaryMapper =
Objects.requireNonNullElse(secondaryToPrimaryMapper,
Mappers.fromOwnerReference());
this.onDeleteFilter = onDeleteFilter;
this.cachePruneFunction = cachePruneFunction;
}

@Override
Expand All @@ -67,6 +72,11 @@ public Optional<OnDeleteFilter<R>> onDeleteFilter() {
public <P extends HasMetadata> PrimaryToSecondaryMapper<P> getPrimaryToSecondaryMapper() {
return (PrimaryToSecondaryMapper<P>) primaryToSecondaryMapper;
}

@Override
public Optional<UnaryOperator<R>> cachePruneFunction() {
return Optional.ofNullable(this.cachePruneFunction);
}
}

/**
Expand Down Expand Up @@ -102,6 +112,7 @@ class InformerConfigurationBuilder<R extends HasMetadata> {
private OnDeleteFilter<R> onDeleteFilter;
private GenericFilter<R> genericFilter;
private boolean inheritControllerNamespacesOnChange = false;
private UnaryOperator<R> cachePruneFunction;

private InformerConfigurationBuilder(Class<R> resourceClass) {
this.resourceClass = resourceClass;
Expand Down Expand Up @@ -202,12 +213,18 @@ public InformerConfigurationBuilder<R> withGenericFilter(GenericFilter<R> generi
return this;
}

public InformerConfigurationBuilder<R> withCachePruneFunction(
UnaryOperator<R> cachePruneFunction) {
this.cachePruneFunction = cachePruneFunction;
return this;
}

public InformerConfiguration<R> build() {
return new DefaultInformerConfiguration<>(labelSelector, resourceClass,
primaryToSecondaryMapper,
secondaryToPrimaryMapper,
namespaces, inheritControllerNamespacesOnChange, onAddFilter, onUpdateFilter,
onDeleteFilter, genericFilter);
onDeleteFilter, genericFilter, cachePruneFunction);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.function.UnaryOperator;

import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import io.javaoperatorsdk.operator.processing.event.rate.LinearRateLimiter;
Expand Down Expand Up @@ -118,4 +119,25 @@ MaxReconciliationInterval maxReconciliationInterval() default @MaxReconciliation
* accessible no-arg constructor.
*/
Class<? extends RateLimiter> rateLimiter() default LinearRateLimiter.class;

/**
* <p>
* <b>This is an experimental feature, might be a subject of change and even removal in the
* future.</b>
* </p>
* <p>
* In order to optimize cache, thus set null on some attributes, this function can be set. Note
* that this has subtle implications how updates on the resources should be handled. Notably only
* patching of the resource can be used from that point, since update would remove not cached
* parts of the resource.
* </p>
* <p>
* Note that this feature does not work with Dependent Resources.
* </p>
*
*
*
* @return function to remove parts of the resource.
*/
Class<? extends UnaryOperator> cachePruneFunction() default UnaryOperator.class;
}
Loading