Skip to content

events: make kube broadcaster shutdown gracefully and tune correlator so we don't loose events#777

Merged
openshift-merge-robot merged 1 commit intoopenshift:masterfrom
mfojtik:events-shutdown
Apr 27, 2020
Merged

events: make kube broadcaster shutdown gracefully and tune correlator so we don't loose events#777
openshift-merge-robot merged 1 commit intoopenshift:masterfrom
mfojtik:events-shutdown

Conversation

@mfojtik
Copy link
Contributor

@mfojtik mfojtik commented Apr 21, 2020

This change will wire the broadcaster Shutdown() function into library-go event recorder.
This is later facilitated in controllercmd builder, where this is called when the binary leader election change.

In addition, this change will provide more fine-tuned correlator options that operators which send a lot of events and don't want to loose events should use. These are default now for controllercmd builder based operators.

@deads2k
Copy link
Contributor

deads2k commented Apr 21, 2020

/hold

this will cause panics if we try to write events after shutdown. You probably don't want that.

@openshift-ci-robot openshift-ci-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 21, 2020
@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 21, 2020

@deads2k this will flush what is in sink and waits until all those events are recorded... it is true that "new" events that arrived after we called shutdown won't make it... but I dunno how can we stop them coming. we can time the shutdown as the last thing we call AFTER all controllers are down?

@deads2k
Copy link
Contributor

deads2k commented Apr 21, 2020

@deads2k this will flush what is in sink and waits until all those events are recorded... it is true that "new" events that arrived after we called shutdown won't make it... but I dunno how can we stop them coming. we can time the shutdown as the last thing we call AFTER all controllers are down?

The issue isn't that we don't get them. The issue is that the event write will panic because the incoming channel is closed.

@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 22, 2020

/retest

@mfojtik mfojtik force-pushed the events-shutdown branch 2 times, most recently from c25731d to ada3238 Compare April 22, 2020 08:20
@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 22, 2020

@deads2k proof: openshift/cluster-kube-apiserver-operator#837

I made some tweaks:

  • During shutdown we switch to normal client, so we keep creating events even if the broadcaster is flushing
  • I added prometheus counter for events, so in future we can check how many events we send and how many events we see
  • I tweaked the upstream broadcaster to allow twice as much events from a single source than normal (this should improve our events throughput, although I would want to see the current rate of dropped events first maybe).

Name: "total_events_count",
Help: "Total count of events processed by this event recorder per involved object",
StabilityLevel: metrics.ALPHA,
}, []string{"namespace", "name"})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@deads2k i think this will have reasonable cardinality and can show us how many events we receive per operator... i wonder if we want to break this into warnings vs. normal events :-)

i imagine an alert that can fire if we see "abnormal" amount of "warning" events in a period of time...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mfojtik mfojtik force-pushed the events-shutdown branch 5 times, most recently from 0584af7 to c4cafbc Compare April 22, 2020 11:39
@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 22, 2020

/retest

found typo in resourcesynccontroller unit test: #780

@mfojtik mfojtik force-pushed the events-shutdown branch 2 times, most recently from 7f935c9 to ceda9aa Compare April 22, 2020 13:11
@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 22, 2020

@deads2k updated, made it configurable.

@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 22, 2020

updated the proof as well: openshift/cluster-kube-apiserver-operator#837


// fallbackRecorder is used when the kube recorder is shutting down
// in that case we create the events directly.
fallbackRecorder Recorder
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh what a wicked web we weave

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can just log the events that come after shutdown... i think the chance we leak events after shutdown is triggered is really small (the window is basically ~1-2s, but this makes sure we don't miss any event at all...

fallbackRecorder Recorder
}

var DefaultOperatorEventRecorderOptions = record.CorrelatorOptions{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still forgot the keyFunc that needs to include the message to avoid de-duping different messages like we have today.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyFunc added


var DefaultOperatorEventRecorderOptions = record.CorrelatorOptions{
BurstSize: 60, // default: 25 (change allows a single source to send 50 events about object per minute)
QPS: 1. / 60., // default: 1/300 (change allows refill rate to 1 new event every 2 minutes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think is just 1.0 for one per second. We want them all!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@mfojtik mfojtik changed the title events: wire shutdown events: make kube broadcaster shutdown gracefully and tune correlator so we don't loose events Apr 23, 2020
kubeInformers := informers.NewSharedInformerFactoryWithOptions(o.kubeClient, 10*time.Minute, informers.WithNamespace(o.Namespace))

eventRecorder := events.NewKubeRecorder(o.kubeClient.CoreV1().Events(o.Namespace), "cert-syncer",
eventRecorder := events.NewKubeRecorder(o.kubeClient.CoreV1().Events(o.Namespace), record.CorrelatorOptions{}, "cert-syncer",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want the operator level one for this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@deads2k
Copy link
Contributor

deads2k commented Apr 23, 2020

before change, openshift-kube-apiserver-operator had 186 events, now it has 383 events. There's a lot, but I think we can manage it.

@deads2k
Copy link
Contributor

deads2k commented Apr 23, 2020

@mfojtik some with the same message are showing up as separate events now. This surprises me.

04:39:27 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:27 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:27 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:28 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:28 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:28 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:28 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:29 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:29 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:41 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)
04:39:58 (1) "openshift-kube-apiserver-operator" OperatorStatusChanged Status for clusteroperator/kube-apiserver changed: Degraded message changed from "NodeControllerDegraded: The master nodes not ready: node ""ip-10-0-132-198.us-east-2.compute.internal"" not ready since 2020-04-23 08:34:47 +0000 UTC because KubeletNotReady (runtime network not ready: NetworkReady=false reason:NetworkPluginNotReady message:Network plugin returns error: No CNI configuration file in /etc/kubernetes/cni/net.d/. Has your network provider started?)

from proof PR https://prow.svc.ci.openshift.org/view/gcs/origin-ci-test/pr-logs/pull/openshift_cluster-kube-apiserver-operator/837/pull-ci-openshift-cluster-kube-apiserver-operator-master-e2e-aws-serial/321

@mfojtik
Copy link
Contributor Author

mfojtik commented Apr 23, 2020

@deads2k those messages are truncated, see #784

i think increase of events is reasonable... if should consider which events are useful and which are not and how many we fire from controllers perhaps?

event.Reason,
event.Message,
},
""), event.Message
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

odd idention

// Event emits the normal type event.
func (r *upstreamRecorder) Event(reason, message string) {
defer r.incrementEventsCounter(corev1.EventTypeNormal)
if r.isShuttingDown() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this races

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

races how?

// Warning emits the warning type event.
func (r *upstreamRecorder) Warning(reason, message string) {
defer r.incrementEventsCounter(corev1.EventTypeWarning)
if r.isShuttingDown() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this races

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shutdown can be called after isShuttingDown left the lock. We would lose events.

kubeInformers := informers.NewSharedInformerFactoryWithOptions(o.kubeClient, 10*time.Minute, informers.WithNamespace(o.Namespace))

eventRecorder := events.NewKubeRecorder(o.kubeClient.CoreV1().Events(o.Namespace), "cert-syncer",
eventRecorder := events.NewKubeRecorder(o.kubeClient.CoreV1().Events(o.Namespace), events.RecommendedClusterSingletonCorrelatorOptions(), "cert-syncer",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

award for the longest identifier! 🏆

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

goes to @deads2k for suggesting it :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it has some Java smell, am not surprised :D

@mfojtik mfojtik force-pushed the events-shutdown branch 2 times, most recently from 1288255 to c04379f Compare April 24, 2020 12:03

// NewKubeRecorder returns new event recorder.
func NewKubeRecorder(client corev1client.EventInterface, sourceComponentName string, involvedObjectRef *corev1.ObjectReference) Recorder {
func NewKubeRecorder(client corev1client.EventInterface, options record.CorrelatorOptions, sourceComponentName string, involvedObjectRef *corev1.ObjectReference) Recorder {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to break this interface?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can make NewKubeRecorderWithOptions ?

// Event emits the normal type event.
func (r *upstreamRecorder) Event(reason, message string) {
r.shutdownMutex.Lock()
defer r.shutdownMutex.Unlock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a long lock. Use a RW lock and lock here read-only, and write-lock in the shutdown call func.

// This is needed if the binary is sending a lot of events.
// Using events.DefaultOperatorEventRecorderOptions here makes a good default for normal operator binary.
func (b *ControllerBuilder) WithEventRecorderOptions(options record.CorrelatorOptions) *ControllerBuilder {
b.eventRecorderOptions = options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected to set it to the recommended options by default. Is that the case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sttts
Copy link
Contributor

sttts commented Apr 27, 2020

/approve
/lgtm

@openshift-ci-robot openshift-ci-robot added the lgtm Indicates that a PR is ready to be merged. label Apr 27, 2020
@openshift-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: mfojtik, sttts

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci-robot openshift-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Apr 27, 2020
@deads2k
Copy link
Contributor

deads2k commented Apr 27, 2020

/hold cancel

@openshift-ci-robot openshift-ci-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 27, 2020
@openshift-merge-robot openshift-merge-robot merged commit 6d48516 into openshift:master Apr 27, 2020
bertinatto pushed a commit to bertinatto/library-go that referenced this pull request Jul 2, 2020
events: make kube broadcaster shutdown gracefully and tune correlator so we don't loose events
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants