From f05d0796e617d7ba55b6571aee206f1300daf706 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Wed, 11 Oct 2023 15:24:54 +0300 Subject: [PATCH 01/18] demystifying activator on path --- blog/config/nav.yml | 1 + .../demystifying-activator-on-path.md | 171 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 blog/docs/articles/demystifying-activator-on-path.md diff --git a/blog/config/nav.yml b/blog/config/nav.yml index 450bf3667b..a41b55bdd1 100644 --- a/blog/config/nav.yml +++ b/blog/config/nav.yml @@ -46,6 +46,7 @@ nav: - releases/announcing-knative-v0-3-release.md - releases/announcing-knative-v0-2-release.md - Articles: + - articles/demystifying-activator-on-path.md - articles/knative-eventing-vision.md - articles/new_event_discovery_features.md - articles/getting-started-blog-p2.md diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md new file mode 100644 index 0000000000..6f7eb82a41 --- /dev/null +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -0,0 +1,171 @@ +# Demystifying Activator on path + +**Author: [Stavros Kontopoulos](https://twitter.com/s_kontopoulos), Principal Software Engineer @ RedHat** + +**Date: 2023-10-11** + +_In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ + +A knative service can operate in two modes:proxy mode and serve mode. +When in proxy mode Activator is on the data path and it will stay on path until certain conditions are met. +When these conditions are met Activator is removed from the path and the service transitions to serve mode. +Although it was not always like that when a service scales from/to zero activator is added by default to the path. +This default setting often confuses users for reasons we will see next as it is possible that activator will not +be removed unless enough capacity is available. This is intended as one of the Activator's roles is to offer backpressure capabilities so that it can make sure that a service could serve the traffic. + + +## Background + +The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to +calculate metrics and make scaling decisions. Let's see inde tail what happens when a new Knative service is created. +Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. Then the Configuration reconciler creates a Revision resource and +the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. +The Route reconciler will create the ingress resource that will be picked up by the Knative net-* components responsible +for managing traffic locally in the cluster and externally to the cluster. +Now the creation of the PA earlier triggers the KPA reconciler which goes through certain steps in order to setup an autoscaling configuration for the revision: +- creates an internal Decider resource that holds the initial desired scale in `decider.Status.DesiredScale`and +sets up a pod scaler via the multi-scaler component. The pod scaler every two seconds calculates a new Scale +result and makes a decision based on the condition `decider.Status.DesiredScale != sRes.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. Goal is the KPA to get the latest scale result. +- creates a Metric resource that triggers the metrics collector controller to setup a scraper for the revision pods. +- calls a scale method that decides the number of wanted pods and also updates the revision deployment +- creates/updates a ServerlessService (SKS) that holds info about the operation mode (proxy or serve) and stores the activators used in proxy mode. That SKS create/update event triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the K8s deployment. +This in combination with the networking setup done by the net-* components is the +- updates the PA and reports the active and wanted pods in its status + +## Capacity and Operation Modes in Practice + +As described earlier Activator will be removed if enough capacity is available and there is an invariant that needs to +hold, that is EBC (excess burst capacity)>0, where EBC = TotalCapacity - ObservedInPanicMode - TargetBurstCapacity(TBC). + +Let's see an example of a service that has a target concurrency of 10 and tbc=10: + +```yaml +apiVersion: serving.knative.dev/v1 +kind: Service +metadata: + name: autoscale-go +spec: + template: + metadata: + annotations: + autoscaling.knative.dev/target: "10" + autoscaling.knative.dev/target-burst-capacity: "10" + spec: + containers: + - image: ghcr.io/knative/autoscale-go:latest +``` + +Initially when the ksvc was deployed there was no traffic and one pod is created by default for verification reasons. + +Until the pod is up we have: +```bash +$ kubectl get sks +NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAME READY REASON +autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-00001-private Unknown NoHealthyBackends +``` +When the pod is up we have: + +```bash +$ oc get po +NAME READY STATUS RESTARTS AGE +autoscale-go-00001-deployment-6cc679b9d6-xgrkf 2/2 Running 0 24s + +$ oc get sks +NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAME READY REASON +autoscale-go-00001 Serve 2 autoscale-go-00001 autoscale-go-00001-private True +``` + +The reason why we are in Serve mode is because EBC=0. In the logs we get: + + +```bash +{"severity":"DEBUG","timestamp":"2023-10-10T15:29:37.241575214Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=1 Total1PodCapacity=10.000 ObsStableValue=0.000 ObsPanicValue=0.000 TargetBC=10.000 ExcessBC=0.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +``` + +EBC = 10 - 0 - 10 = 0 + +Note that due to the fact that there is no traffic we see no observations during panic or stable windows. + +Since there is no traffic we scale back to zero and sks is back to proxy mode: + +```bash +$ kubectl get sks +NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAME READY REASON +autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-00001-private Unknown NoHealthyBackends +``` + +In debug mode also in the logs you can see the state that the autoscaler operates for the specific revision. +In this case we go directly to: + +``` +{"severity":"DEBUG","timestamp":"2023-10-10T15:29:37.241523364Z","logger":"autoscaler","caller":"scaling/autoscaler.go:247","message":"Operating in stable mode.","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +``` + +Let's send some traffic (experiment was run on Minikube): + +```bash +hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168.39.43:32718?sleep=1000" +``` + +Initially activator when get a request in it sends stats to the autoscaler which tries to +scale from zero based on some initial scale (default 1): + +``` +{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178498172Z","logger":"autoscaler.stats-websocket-server","caller":"statserver/server.go:193","message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:1 AverageProxiedConcurrentRequests:0 RequestCount:1 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}","commit":"f1617ef","address":":8080"} +{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178733422Z","logger":"autoscaler","caller":"statforwarder/processor.go:64","message":"Accept stat as owner of bucket autoscaler-bucket-00-of-01","commit":"f1617ef","bucket":"autoscaler-bucket-00-of-01","knative.dev/key":"default/autoscale-go-00001"} +``` + +``` +{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178920551Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=1.000 ObsPanicValue=1.000 TargetBC=10.000 ExcessBC=-11.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +``` + +Later on as traffic continues we get proper statistics from activator closer to the rate: + +``` +{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.949001622Z","logger":"autoscaler.stats-websocket-server","caller":"statserver/server.go:193","message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:18.873756322609804 AverageProxiedConcurrentRequests:0 RequestCount:19 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}","commit":"f1617ef","address":":8080"} +``` + +``` +{"severity":"INFO","timestamp":"2023-10-10T15:32:56.432854252Z","logger":"autoscaler","caller":"kpa/kpa.go:188","message":"Observed pod counts=kpa.podCounts{want:1, ready:0, notReady:1, pending:1, terminating:0}","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb","knative.dev/key":"default/autoscale-go-00001"} + +{"severity":"DEBUG","timestamp":"2023-10-10T15:32:57.241052566Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +``` + +Since the pod is not up yet: EBS = 0*10 - floor(19.874) - 10 = -30 + + +Given the new statistics kpa decides to scale to 3 pods. + +``` +{"severity":"INFO","timestamp":"2023-10-10T15:32:57.241421042Z","logger":"autoscaler","caller":"kpa/scaler.go:370","message":"Scaling from 1 to 3","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"6dcf87c9-15d8-41d3-95ae-5ca9b3d90705","knative.dev/key":"default/autoscale-go-00001"} +``` + +But let's see why is this so. The log above comes from the multi-scaler which reports +a scaled result that contains EBS as reported above and a desired pod count for different windows. + +Roughly the final desired number is (minus corner cases): + +dspc := math.Ceil(observedStableValue / spec.TargetValue) +dppc := math.Ceil(observedPanicValue / spec.TargetValue) + +The target value is the utilization in terms of concurrency and that is is 0.7*(revision_target). +In this case this is 7. So we have for example for the panic window: ceil(19.874/7)=3 + +**Note:** if RPS is used then the utilization factor is 0.75. + +Later on when revision is scaled we have: + +``` +{"severity":"INFO","timestamp":"2023-10-10T15:33:01.320912032Z","logger":"autoscaler","caller":"kpa/kpa.go:158","message":"SKS should be in Serve mode: want = 3, ebc = 0, #act's = 2 PA Inactive? = false","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"f0d22038-130a-4560-bd67-2751ecf3975d","knative.dev/key":"default/autoscale-go-00001"} + +{"severity":"DEBUG","timestamp":"2023-10-10T15:33:03.24101879Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=3 Total1PodCapacity=10.000 ObsStableValue=16.976 ObsPanicValue=15.792 TargetBC=10.000 ExcessBC=4.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +``` + +EBS = 3*10 - floor(15.792) - 10 = 4 + +Later on the sks transitions to Serve mode as we have enough capacity until traffic stops and deployment is scaled back to zero. + +### Conclusion + +It is often confusing of how and why services stuck in proxy mode or how users can manage Activator on path. +This is important especially when you just started with Knative Serving. With the detailed example above hopefully we have demystified this fundamental behavior of the Serving data plane. From 4e113b9c4d3a7259eb8600b41ff3cb3504c70dda Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Wed, 11 Oct 2023 16:18:20 +0300 Subject: [PATCH 02/18] some fixes --- .../articles/demystifying-activator-on-path.md | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 6f7eb82a41..4b8ae3ea61 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -17,19 +17,26 @@ be removed unless enough capacity is available. This is intended as one of the A ## Background The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to -calculate metrics and make scaling decisions. Let's see inde tail what happens when a new Knative service is created. +calculate metrics and make scaling decisions. Let's see in detail what happens when a new Knative service is created. + Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. Then the Configuration reconciler creates a Revision resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. The Route reconciler will create the ingress resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. + Now the creation of the PA earlier triggers the KPA reconciler which goes through certain steps in order to setup an autoscaling configuration for the revision: + - creates an internal Decider resource that holds the initial desired scale in `decider.Status.DesiredScale`and sets up a pod scaler via the multi-scaler component. The pod scaler every two seconds calculates a new Scale result and makes a decision based on the condition `decider.Status.DesiredScale != sRes.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. Goal is the KPA to get the latest scale result. + - creates a Metric resource that triggers the metrics collector controller to setup a scraper for the revision pods. + - calls a scale method that decides the number of wanted pods and also updates the revision deployment + - creates/updates a ServerlessService (SKS) that holds info about the operation mode (proxy or serve) and stores the activators used in proxy mode. That SKS create/update event triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the K8s deployment. This in combination with the networking setup done by the net-* components is the + - updates the PA and reports the active and wanted pods in its status ## Capacity and Operation Modes in Practice @@ -39,7 +46,7 @@ hold, that is EBC (excess burst capacity)>0, where EBC = TotalCapacity - Observe Let's see an example of a service that has a target concurrency of 10 and tbc=10: -```yaml +``` apiVersion: serving.knative.dev/v1 kind: Service metadata: @@ -143,10 +150,14 @@ Given the new statistics kpa decides to scale to 3 pods. But let's see why is this so. The log above comes from the multi-scaler which reports a scaled result that contains EBS as reported above and a desired pod count for different windows. -Roughly the final desired number is (minus corner cases): +Roughly the final desired number is (there is more logic that covers corner + cases and checking against min/max scale limits): +``` dspc := math.Ceil(observedStableValue / spec.TargetValue) dppc := math.Ceil(observedPanicValue / spec.TargetValue) +``` + The target value is the utilization in terms of concurrency and that is is 0.7*(revision_target). In this case this is 7. So we have for example for the panic window: ceil(19.874/7)=3 From 5e3a87efaced3fd30fd4974e8e95fd0d7753fa48 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Fri, 13 Oct 2023 15:33:57 +0300 Subject: [PATCH 03/18] Apply suggestions from code review - Roland MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Huß --- blog/docs/articles/demystifying-activator-on-path.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 4b8ae3ea61..02b2c8f9cc 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -6,18 +6,18 @@ _In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ -A knative service can operate in two modes:proxy mode and serve mode. -When in proxy mode Activator is on the data path and it will stay on path until certain conditions are met. +A knative service can operate in two modes: proxy mode and serve mode. +When in proxy mode, Activator is on the data path, and it will stay on the path until certain conditions (more on this later) are met. When these conditions are met Activator is removed from the path and the service transitions to serve mode. -Although it was not always like that when a service scales from/to zero activator is added by default to the path. +However, it was not always like that when a service scales from/to zero, the activator is added by default to the data path. This default setting often confuses users for reasons we will see next as it is possible that activator will not -be removed unless enough capacity is available. This is intended as one of the Activator's roles is to offer backpressure capabilities so that it can make sure that a service could serve the traffic. +be removed unless enough capacity is available. This is intended as one of the Activator's roles is to offer backpressure capabilities so that a Knative service is not overloaded by incoming traffic. ## Background The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to -calculate metrics and make scaling decisions. Let's see in detail what happens when a new Knative service is created. +make scaling decisions. Let's see in detail what happens when a new Knative service is created. Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. Then the Configuration reconciler creates a Revision resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. From 2b40854e3f86b758d588352e73a25ada7507f1e7 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Fri, 13 Oct 2023 15:35:07 +0300 Subject: [PATCH 04/18] Update blog/docs/articles/demystifying-activator-on-path.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Roland Huß --- blog/docs/articles/demystifying-activator-on-path.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 02b2c8f9cc..06aca90128 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -8,7 +8,7 @@ _In this blog post you will learn how to recognize when activator is on the data A knative service can operate in two modes: proxy mode and serve mode. When in proxy mode, Activator is on the data path, and it will stay on the path until certain conditions (more on this later) are met. -When these conditions are met Activator is removed from the path and the service transitions to serve mode. +When these conditions are met, Activator is removed from the data path, and the service transitions to serve mode. However, it was not always like that when a service scales from/to zero, the activator is added by default to the data path. This default setting often confuses users for reasons we will see next as it is possible that activator will not be removed unless enough capacity is available. This is intended as one of the Activator's roles is to offer backpressure capabilities so that a Knative service is not overloaded by incoming traffic. From a2902350f3a65438efc797fc0a1006c58e8a0a24 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Mon, 6 Nov 2023 13:48:12 +0200 Subject: [PATCH 05/18] update --- .../demystifying-activator-on-path.md | 51 ++++++++++++++----- docs/serving/autoscaling/autoscaler-types.md | 46 ++++++++++++++++- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 06aca90128..7d9182ba6d 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -7,19 +7,18 @@ _In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ A knative service can operate in two modes: proxy mode and serve mode. -When in proxy mode, Activator is on the data path, and it will stay on the path until certain conditions (more on this later) are met. +When in proxy mode, Activator is on the data path (which means the incoming requests are routed through the Activator component), and it will stay on the path until certain conditions (more on this later) are met. When these conditions are met, Activator is removed from the data path, and the service transitions to serve mode. However, it was not always like that when a service scales from/to zero, the activator is added by default to the data path. -This default setting often confuses users for reasons we will see next as it is possible that activator will not -be removed unless enough capacity is available. This is intended as one of the Activator's roles is to offer backpressure capabilities so that a Knative service is not overloaded by incoming traffic. - +This default setting often confuses users for reasons we will see next as it is possible that activator will not be removed unless enough capacity is available. +This is intended as one of the Activator's roles is to offer backpressure capabilities so that a Knative service is not overloaded by incoming traffic. ## Background -The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to -make scaling decisions. Let's see in detail what happens when a new Knative service is created. +The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to make scaling decisions. +Let's see in detail what happens when a new Knative service is created. -Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. Then the Configuration reconciler creates a Revision resource and +Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. The Route reconciler will create the ingress resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. @@ -128,14 +127,40 @@ scale from zero based on some initial scale (default 1): Later on as traffic continues we get proper statistics from activator closer to the rate: -``` -{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.949001622Z","logger":"autoscaler.stats-websocket-server","caller":"statserver/server.go:193","message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:18.873756322609804 AverageProxiedConcurrentRequests:0 RequestCount:19 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}","commit":"f1617ef","address":":8080"} -``` ``` -{"severity":"INFO","timestamp":"2023-10-10T15:32:56.432854252Z","logger":"autoscaler","caller":"kpa/kpa.go:188","message":"Observed pod counts=kpa.podCounts{want:1, ready:0, notReady:1, pending:1, terminating:0}","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb","knative.dev/key":"default/autoscale-go-00001"} - -{"severity":"DEBUG","timestamp":"2023-10-10T15:32:57.241052566Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +{ + "severity":"DEBUG", + "timestamp":"2023-10-10T15:32:56.949001622Z", + "logger":"autoscaler.stats-websocket-server", + "caller":"statserver/server.go:193", + "message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:18.873756322609804 AverageProxiedConcurrentRequests:0 RequestCount:19 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}", + "commit":"f1617ef", + "address":":8080" +} + +{ + "severity":"INFO", + "timestamp":"2023-10-10T15:32:56.432854252Z", + "logger":"autoscaler", + "caller":"kpa/kpa.go:188", + "message":"Observed pod counts=kpa.podCounts{want:1, ready:0, notReady:1, pending:1, terminating:0}", + "commit":"f1617ef", + "knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", + "knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler", + "knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb", + "knative.dev/key":"default/autoscale-go-00001" +} + +{ + "severity":"DEBUG", + "timestamp":"2023-10-10T15:32:57.241052566Z", + "logger":"autoscaler", + "caller":"scaling/autoscaler.go:286", + "message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000", + "commit":"f1617ef", + "knative.dev/key":"default/autoscale-go-00001" +} ``` Since the pod is not up yet: EBS = 0*10 - floor(19.874) - 10 = -30 diff --git a/docs/serving/autoscaling/autoscaler-types.md b/docs/serving/autoscaling/autoscaler-types.md index 56f1e5a045..9323147ab0 100644 --- a/docs/serving/autoscaling/autoscaler-types.md +++ b/docs/serving/autoscaling/autoscaler-types.md @@ -121,6 +121,50 @@ spec: annotations: autoscaling.knative.dev/target: "70" ``` - +``` +{ + "severity": "DEBUG", + "timestamp": "2023-10-10T15:32:56.949001622Z", + "logger": "autoscaler.stats-websocket-server", + "caller": "statserver/server.go:193", + "message": "Received stat message: { + Key: default/autoscale-go-00001, + Stat: { + PodName": activator-59dff6d45c-9rdxh, + AverageConcurrentRequests: 18.873756322609804, + AverageProxiedConcurrentRequests": 0, + RequestCount: 19, + ProxiedRequestCount: 0, + ProcessUptime: 0, + Timestamp: 0 + } + }", + "commit": "f1617ef", + "address": ":8080" +} + +{ + "severity":"INFO", + "timestamp":"2023-10-10T15:32:56.432854252Z", + "logger":"autoscaler", + "caller":"kpa/kpa.go:188", + "message":"Observed pod counts=kpa.podCounts{want:1, ready:0, notReady:1, pending:1, terminating:0}", + "commit":"f1617ef", + "knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", + "knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler", + "knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb", + "knative.dev/key":"default/autoscale-go-00001" +} + +{ + "severity":"DEBUG", + "timestamp":"2023-10-10T15:32:57.241052566Z", + "logger":"autoscaler", + "caller":"scaling/autoscaler.go:286", + "message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000", + "commit":"f1617ef", + "knative.dev/key":"default/autoscale-go-00001" +} +``` !!! important If you are creating revisions by using a service or configuration, you must set the annotations in the _revision template_ so that any modifications will be applied to each revision as they are created. Setting annotations in the top level metadata of a single revision will not propagate the changes to other revisions and will not apply changes to the autoscaling configuration for your application. From a44dd8ae66b27843e481186f200e967d30c33775 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Mon, 13 Nov 2023 14:19:10 +0200 Subject: [PATCH 06/18] fix --- docs/serving/autoscaling/autoscaler-types.md | 46 +------------------- 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/docs/serving/autoscaling/autoscaler-types.md b/docs/serving/autoscaling/autoscaler-types.md index 9323147ab0..56f1e5a045 100644 --- a/docs/serving/autoscaling/autoscaler-types.md +++ b/docs/serving/autoscaling/autoscaler-types.md @@ -121,50 +121,6 @@ spec: annotations: autoscaling.knative.dev/target: "70" ``` -``` -{ - "severity": "DEBUG", - "timestamp": "2023-10-10T15:32:56.949001622Z", - "logger": "autoscaler.stats-websocket-server", - "caller": "statserver/server.go:193", - "message": "Received stat message: { - Key: default/autoscale-go-00001, - Stat: { - PodName": activator-59dff6d45c-9rdxh, - AverageConcurrentRequests: 18.873756322609804, - AverageProxiedConcurrentRequests": 0, - RequestCount: 19, - ProxiedRequestCount: 0, - ProcessUptime: 0, - Timestamp: 0 - } - }", - "commit": "f1617ef", - "address": ":8080" -} - -{ - "severity":"INFO", - "timestamp":"2023-10-10T15:32:56.432854252Z", - "logger":"autoscaler", - "caller":"kpa/kpa.go:188", - "message":"Observed pod counts=kpa.podCounts{want:1, ready:0, notReady:1, pending:1, terminating:0}", - "commit":"f1617ef", - "knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", - "knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler", - "knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb", - "knative.dev/key":"default/autoscale-go-00001" -} - -{ - "severity":"DEBUG", - "timestamp":"2023-10-10T15:32:57.241052566Z", - "logger":"autoscaler", - "caller":"scaling/autoscaler.go:286", - "message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000", - "commit":"f1617ef", - "knative.dev/key":"default/autoscale-go-00001" -} -``` + !!! important If you are creating revisions by using a service or configuration, you must set the annotations in the _revision template_ so that any modifications will be applied to each revision as they are created. Setting annotations in the top level metadata of a single revision will not propagate the changes to other revisions and will not apply changes to the autoscaling configuration for your application. From 3099f20480eaa5b0eb64baf72b36eb0d35901b93 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Mon, 13 Nov 2023 17:21:44 +0200 Subject: [PATCH 07/18] add some diagrams --- .../demystifying-activator-on-path.md | 49 ++++++++++-------- blog/docs/articles/images/ebc.png | Bin 0 -> 49592 bytes blog/docs/articles/images/panic.png | Bin 0 -> 44856 bytes blog/docs/articles/images/readypods.png | Bin 0 -> 37769 bytes 4 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 blog/docs/articles/images/ebc.png create mode 100644 blog/docs/articles/images/panic.png create mode 100644 blog/docs/articles/images/readypods.png diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 7d9182ba6d..107b38a489 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -6,7 +6,11 @@ _In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ -A knative service can operate in two modes: proxy mode and serve mode. +The activator acts as a component on the data path to enable traffic buffering when a service is scaled-to-zero. +One lesser known feature of activator is, that it can act as a request buffer that handles back-pressure with the goal to not overload a Knative service. +For this, a Knative service can define how much traffic it can handle using [annotations](https://knative.dev/docs/serving/autoscaling/autoscaling-targets/#configuring-targets). +The autoscaler component will use this information to calculate the amount of pods needed to handle the incoming traffic for a specific Knative service +When serving traffic a knative service can operate in two modes: proxy mode and serve mode. When in proxy mode, Activator is on the data path (which means the incoming requests are routed through the Activator component), and it will stay on the path until certain conditions (more on this later) are met. When these conditions are met, Activator is removed from the data path, and the service transitions to serve mode. However, it was not always like that when a service scales from/to zero, the activator is added by default to the data path. @@ -18,30 +22,30 @@ This is intended as one of the Activator's roles is to offer backpressure capabi The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to make scaling decisions. Let's see in detail what happens when a new Knative service is created. -Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. Then the Configuration reconciler creates a `Revision` resource and -the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. -The Route reconciler will create the ingress resource that will be picked up by the Knative net-* components responsible -for managing traffic locally in the cluster and externally to the cluster. +Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. +Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. +The Route reconciler will create the ingress resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. -Now the creation of the PA earlier triggers the KPA reconciler which goes through certain steps in order to setup an autoscaling configuration for the revision: +Now, the creation of the PA triggers the KPA reconciler which goes through certain steps in order to setup an autoscaling configuration for the revision: - creates an internal Decider resource that holds the initial desired scale in `decider.Status.DesiredScale`and -sets up a pod scaler via the multi-scaler component. The pod scaler every two seconds calculates a new Scale -result and makes a decision based on the condition `decider.Status.DesiredScale != sRes.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. Goal is the KPA to get the latest scale result. +sets up a pod scaler via the multi-scaler component. The pod scaler calculates a new Scale result every two seconds and makes a decision based on the condition `decider.Status.DesiredScale != scaledResult.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. Goal is the KPA to get the latest scale result. - creates a Metric resource that triggers the metrics collector controller to setup a scraper for the revision pods. -- calls a scale method that decides the number of wanted pods and also updates the revision deployment +- calls a scale method that decides the number of wanted pods and also updates the K8s raw deployment that corresponds to the revision. -- creates/updates a ServerlessService (SKS) that holds info about the operation mode (proxy or serve) and stores the activators used in proxy mode. That SKS create/update event triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the K8s deployment. -This in combination with the networking setup done by the net-* components is the +- creates/updates a ServerlessService (SKS) that holds info about the operation mode (proxy or serve) and stores the number of activators that should be used in proxy mode. +The number of activators depends on the capacity that needs to be covered. +That SKS create/update event triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the K8s deployment. +Also in proxy mode that controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). +This in combination with the networking setup done by the net-* components is the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. - updates the PA and reports the active and wanted pods in its status ## Capacity and Operation Modes in Practice -As described earlier Activator will be removed if enough capacity is available and there is an invariant that needs to -hold, that is EBC (excess burst capacity)>0, where EBC = TotalCapacity - ObservedInPanicMode - TargetBurstCapacity(TBC). +As described earlier Activator will be removed if enough capacity is available and there is an invariant that needs to hold, that is EBC (excess burst capacity)>0, where EBC = TotalCapacity - ObservedInPanicMode - TargetBurstCapacity(TBC). Let's see an example of a service that has a target concurrency of 10 and tbc=10: @@ -81,7 +85,7 @@ NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAM autoscale-go-00001 Serve 2 autoscale-go-00001 autoscale-go-00001-private True ``` -The reason why we are in Serve mode is because EBC=0. In the logs we get: +The reason why we are in Serve mode is that because EBC=0. In the logs we get: ```bash @@ -100,8 +104,7 @@ NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAM autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-00001-private Unknown NoHealthyBackends ``` -In debug mode also in the logs you can see the state that the autoscaler operates for the specific revision. -In this case we go directly to: +When you enable debug logs, you can see this also in the autoscaler logs. In this case we go directly to: ``` {"severity":"DEBUG","timestamp":"2023-10-10T15:29:37.241523364Z","logger":"autoscaler","caller":"scaling/autoscaler.go:247","message":"Operating in stable mode.","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} @@ -113,8 +116,7 @@ Let's send some traffic (experiment was run on Minikube): hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168.39.43:32718?sleep=1000" ``` -Initially activator when get a request in it sends stats to the autoscaler which tries to -scale from zero based on some initial scale (default 1): +Initially activator when get a request in it sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): ``` {"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178498172Z","logger":"autoscaler.stats-websocket-server","caller":"statserver/server.go:193","message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:1 AverageProxiedConcurrentRequests:0 RequestCount:1 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}","commit":"f1617ef","address":":8080"} @@ -172,11 +174,9 @@ Given the new statistics kpa decides to scale to 3 pods. {"severity":"INFO","timestamp":"2023-10-10T15:32:57.241421042Z","logger":"autoscaler","caller":"kpa/scaler.go:370","message":"Scaling from 1 to 3","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"6dcf87c9-15d8-41d3-95ae-5ca9b3d90705","knative.dev/key":"default/autoscale-go-00001"} ``` -But let's see why is this so. The log above comes from the multi-scaler which reports -a scaled result that contains EBS as reported above and a desired pod count for different windows. +But let's see why is this is the case. The log above comes from the multi-scaler which reports a scaled result that contains EBS as reported above and a desired pod count for different windows. -Roughly the final desired number is (there is more logic that covers corner - cases and checking against min/max scale limits): +Roughly the final desired number is (there is more logic that covers corner cases and checking against min/max scale limits): ``` dspc := math.Ceil(observedStableValue / spec.TargetValue) @@ -201,6 +201,11 @@ EBS = 3*10 - floor(15.792) - 10 = 4 Later on the sks transitions to Serve mode as we have enough capacity until traffic stops and deployment is scaled back to zero. +The above are shown visually next with graphs describing ebc, ready pods and +![Excess burst capacity over time](/blog/articles/images/ebc.png) +![Ready pods over time](/blog/articles/images/readypods.png) +![Panic mode over time](/blog/articles/images/panic.png) + ### Conclusion It is often confusing of how and why services stuck in proxy mode or how users can manage Activator on path. diff --git a/blog/docs/articles/images/ebc.png b/blog/docs/articles/images/ebc.png new file mode 100644 index 0000000000000000000000000000000000000000..2113092265fec735d4774747a345f7713d97f65d GIT binary patch literal 49592 zcmeFZby$>J_cxA#h=3>{9U>tjDbfR2fJjJ(Qc8>r4H83|AV??@QbTt$bgHD(fG~99 zFmwzsH2gMt!t*@moZtI>|9!vLHJ38?4g21Et+m(stj}8e_ES}nCp$xbhJb*8OyTYw zbpnDDC<21xWT#JoD+I&J&EVf-j_UHa2y#0ZX9)-{5-8lcsp)FC5KA1Rj5%zQaiQL= z@hOy*y%HLiu1X<$*YB<=s)oVDsIexH*FBl)yevD1rl$X;6n0iiys&wBZJ%S1WV@2d zbca;y{-~o2YJS6e|L`ydD!z;=cj?%bM!|zx7o96V-#X5I|_{}se1RBh%rmOa(zB3?sqi7 zGU~^84PDP{2Rdso9H@aaDHIX?7HoGvh{u; zoAJul>;8j%Lyrn83j4qM4n_`?9@6wyT#&L2-FzK+IQkWD=UaIMTcxo4EQQOHG{@~Z zVULYP=BnM#oDdDsg+w?ab-Y-62>` zCZDPC_fxKxjTeWtaCr7bW@$GHWyzo$85FWB(?!kKcSG%-h0L}%Nj~oVXc!75e(oyn z!yx)NUfY75-x)KD5rEVF;)S2xIDYdoD!OLaFZX5YqsEyf*D4qxZ^*}wy4PVswB-)w zb(1r9U%e``8}AfU^6;dq*NE{ywD}lrHNCa-gY(A@fiBW{Qc>T^jq%*qwmYnlW;dxvI^4=-AD4hOHqS z_GX<#aN>UJhK;x)A_|h_IJ7%|)5^`(zxTku_@ThlNrtV3>aP!m5Z`K+@8r~$nv?b% zbZaQ@j(=@pe#P*qkX+=E9ZIJN^OZql`O^y*=`V5eDmN6Iz9zozDuEmHWa7`6*A$#V zQhUGaoTd!c{Is6FbXeY2J5o%Zhi7~{%4BqBJ{6U`C8)}H=0e-sm;og0F!z;P%kbvP z{?b@{xI0aAGzqH5gEsb|u+lrX;-{Wt2X!;OspnHWj509sbE4KOCnajsWfE9y2i1ve z2M*ZG`5wF;JJ?dROmhn(>de}IJLvS@b-?-k5Y7@ib!DK?T&}gTSkV2e@0QiJ>33B0 z)rqm5{w%3Jvc)L0ELJB@adlW@zE5ZklJ8Ek=Q#}-H7dQJlWTZ8@>_#I8MKwXZ)#}S zw%*;cWIS&w?Hn_;kNZ6u*d`$dgsnc>fy~P>L+mpI?>XBUEQPKcKrOGM6(m2HX_APw$g6gNHJQ&Zl9kttZSB z6QI70Wy?zx#}9ez?*0l1uAB$^jE4Io5wdARMbLud69OBHCfm@F#2dFy3aU;fvDj_}Q-_Z*I#re9-LWo~OP7<#Xr@W3tISu9^D^55y2n4R7)vg$$B+=~w- zAfp#$$-AB#Xk(4&i&7Q0>EGjJt~%r+UG9GHVK|J%T2^zNB4B2S9@Up~%63TIp}Pci zQn@OO08wd2$Cg&(cZ(2b{B`}g!uRcgw9LoYrTwTI_vuCnwU~L{dgqSaXs2;cu$-5B z(pP2p}PjJUkl}2 zuysfoC5?7hQ{B+GGOztp=C#|bH6t4&z131@%N@=8?r2HL7;Kez%=9PLlrV1N!Yox~ zl3%@g#a^`0F^3X>%~2?;qXl6NpVkSNrq z<*v;pifBbW?R}K0l-52gDXkQ_hE^(`iN42+ zed41Lp5;XaT<66*bp?w$0jHQKLEE8h1n1O(1gy-3ZW5FuAy%n&1nyC0p zvJXAk`Dt8qsz}Rw+F_9UG1WY1vmw|N2f7!bOj7MO4dLTs_6mdYY`X%h^$?JYycVFY%G8vI++*zCn-b zz7Z40@d{fSW?9%m*6x_4YZ3DN>M3!=V)qbe^`Yh^{7{2}ZqBbb@OO$9+a)0=P$2m4jz8e;=8#iF=;;9ZJeVy_6q`_~!sG5F1 z=G$pg2}DbBBT-ta<&WudWbUgy?yFk6%Ls8et~@6b#7#b$Wt|*0*!VCrR~~_0m>Wr1 z$BgymHI09YlP?&Lbs8+3fK%?mByG~<5o?%^=dU$(E(a{A)jASC!BF13WpV-re3nJk?X+=!~(&xn1y!#dG|_AVNzP}Iq_Kz1TVg2RTh z$JT{wcEx7bM&{(-@){jJvu5e&saQ?T@trG@-yaNqd>5so&iDW~Qlb%(W9z)1*e=06 zk)?US>>5rdAG~m?I9VzsM7x%GVsW5Ga8M*Gy7Sc_t4&>*G=yB{7u(ZCsA@eORh6e6>fh=FH9g_?{K?O=4s_EF9jpp3+~X93j(1(@wq-B2Rg#sjaS5WpqKn@^qt@iWb(PC(c(-6jgnhtguM5M@1E zoUO@Qs{~mK7t2~4TSSL%WtxrWzDurj$-<^lq82hDv87{&RGC3;UYhOwnUR(9+#_ki z8Of$!{qN`7&$~o%nYVnr={{Yq<4cp^OnyHj8Q+F<)2{Stz3XavRSK6Ke(F9`7l%Rw z%wjIlY`y@#8$1|TLlG&$FO|d_r`^B+*KVy!!shjO1*m!^YlWtBzgKUyBzkI{%Ui4^ zG<)xrrlB7O-il|*cS0AjD`(Ov33un1t5;hn@(y{%n@67%RI>0GZANCM^+!}!iZ#lW z^qI4a>6S3Z@pVVcT;?BLch4Fr`9QM#N^kk`*OvR8Nh2ib+cPf*i<1g1do8|ue;41j z%%dm`6OtDR^)3u7S=TQPE8`;8Y)waRWZ^W+Q;RZUc1YQc92PB_H111jWQSwi{iB3+ zP(tpxLr5%tLgU&9CG$-XsnSzAjIt4_Qq1GlhjUSSrL*&|Sk!Ht7U5S>DT-8|lM@a* z2Cu>oR+E_)?fIRclR$o!RRTZ zJn+dece{^}cza<@p1p0$c|nG*_7J`vzU-ofg4gsvqTO-vA`aHBIh45qZI2;_rApeX zp+*mimdUNf%iKCP>KaTA*0PhLIQCrENR`nJ=QVGu>?9QE5g*veb?Jpy=J!LU}Yf8l;a-MkaSqdV(=iXO6}v^rckN4>n!YQ+$6=+?l))E@tU0O;*Z=Fi7P`k_gu-DI^ zYo+yv)8&RCC`c9-fzC?oY4iRNjS|ngaB(iusyM644R6TXuG1IGJ&Iqpg==Ts?FsM< z%*3odX!SXqprWS;F`YI%h$9Vp_a~k8BI1T>3-UowwoMP(+-Od33Toun5{z(BT(g)}>rRBZLN2rLS{Az|@A;9cMIx#zq4%S$ z@l@ziw+_Abl~H#c`-Q>X%979OlZoL>S$Z>Q+vKVkq2fp=$}tyqJEGZG5NZ{&cQn!YKLx1d=Qiqj>t+xK=b+@6X3Az8P+AK{@6&Y zi#b`Zh{0N@Ti#4lwIIi>Xr_%+USa8C*51p@>FvmM^vR)`U1E*t+)f0!woo>p0PdaZ z@`iGwvoa6%kI8;TJRaIfffhxoqYWpq4IkDNKxCH8$}R3Oe;byrosOpFuU*j$*^F`D zO4dQ3$*;`89Z|&zjoBjR^TJlzFCgyq9y{qagT>=lU^2&w69#fR^m6J|Wrn%F>Rjc4 zG$0is-KO^t>axX$RbC(5I^0S`&Tdp8-N;7jF0{f9r>zfXBe33UO0$vJ^$y5YxVFqr zjHI`MySB{gx79lN`x7O5Linp)LSSnU+0*~CFh`v=Y} zf&FE!RZ=GJIPcAIR-@kZ3EDnp(e#{=wvMnU-oxX+5OyN>Nd~W}75nugJiU$4$BQd% z_!ciHJ4Se<^XBCmrc{+A^tfA!SPCIqv1hwQY}AFI-pt~;yi$B>Mehz^>0t~7OUS$e z=dZdk(vF5h#!7xR`)SNwckB;8C(&N>Vnt-==~1SJ`pYB279#i(WY)5GWY+tLs|prO ztV>jQ#dT0RSt*q;EUY-=!=Rs@luWkB*3Qmuby?1hQB91VUx8b7&|vjLsnVR5h_R*5 z{d9_gX0FghCoNbV9|zqWyrWWa^u6g+ZoP?4D`IE^LBK&u7U!k;;bL*!+LF=PC&NA8 z76zu=El?@$2qx`HDN&0RF)tZc&7oKK_TR03?Oo1yo8SUg&BDgX-;SK+M zecb|QBtCn+>^W0WY+|*wV$Lbm>8(2tYf{uJ|FiW945b0U)5t(>ee37vcLCQaWDwuhv|+! zs1C!1;xtjuvzQ8`t}^umpQ&j^R-8gN+VS_~1VtdS`~Y(Xi(?aZ%+tY zE>DltDee(T*@U<|o9Un`Gac0`gKA~Glkv4$YL{}IbyfEGR(on->hpaM;o8?S4gEH{ zYhDhjEW!d}jjZ3;3x!YaI~hHZIg<|k2%=Z_~tH+!D|l1$=+_7n-6Oc_uTFvlzV$j zj?KYsHb~ccwy)+N2GB zl%WN=04@}+*|*Gapp3`+|p2ZlYt2}T)C2g4#0ehw>nG^|I=HHj8v zJo^>Yi!bqzRwgGU#3_BIt1s25d$AUt!&%Pc_jvEYnG~1(LJHQ1= zmb8E%91oWQ7*+sWuZxEeDIG~jO$|usH<3Am3j^C?W>3MI71R-guWy1?oWh737lKg& z{eQ0cXxPFZ!!}(>N`jEw3jxEDg2#bjk9{~2yyowM|GyNaUr5Y$BR7u`lCHqsJ{>n+ zP207p1xf(KzQKrF-#@~)Ha?vPl~^LSonpCdcg09AGF61KJnX^Cy;~w=DYIk-e;6Cg zZOE#V76em4FYVq`$U}ub-JwvZ$zFD@=gt?W@9mN2`LZM*@6K|5axZ?$W!m7wtPqta}|^R9H=CBCNsSON|-VX%%o-l-d!KbsXxE3|KIwSU+NfFNIX(fXk-XC?^A@~>xQKj272)~JT;oCuQaRpp!3Vd%CdQDtYS@0N zc>#ccXqwNXMu$D-F)Uo}X?P>*n#!}a`>QlNHN8|$Q5y~TV&pmM%vPLZ4iRhNP-{A% z@HF^YTaX!I%GLo!&8d^uiv@rChO^>U(O^h|MEiI5G;*Q9t!i*<_O7z!yG>YXg6ZuH z5bnp0s|-m~s-`s_sut=#3iwz>n>9uoW@m~@5K=Av=J`ZF&nJV11~Z@;lPc24Z>nJ* zHAwsOn;cx^LRvBigiTq<Q9c&vP#IpJ5bMnEK8`kg+>Y<;RqYo$JfDG(x%cvG3FGHW4lKxJOm3r&!B%0O~ z#dtO%d-)OzKQC0P(u0>eQpo4h^;Z*j74dT$Vy}EFK!Nbm4<9lwxN289(p-=2>h|O< z)8`9})#4E82%HzRZ;rasmdV$j8+=l8AtJBgqIX5*c5M1veFe&KrHVZ6yr~?)oLk(qTw4`iS;Usf^j}OZcGo9;2-!_{>k0b-u(h$ znc{&B4VA^wAI}}+KRT;Q`Oq)e<@PL#_tSeaJ^7vI(wCXC{CC{bKzX2F}TLQ6AvAUYQNI zx!BFEiw7|Evpy2a2Q3H*=2M3KCFY#h%zF4sB-(c#tv_>4*Uc@;h`118{lh@YsG5K1 z*lg&B4e<^A(60SJ$q&nFEdg3~Gf~kmsUFV}vl>e{)YVD9_)h9!%cXsk)A)+fj{iq> z4*fSXtd^KF%V?$A;Q`|_0D_7pcvM=lfSMA?)oJqk{j_a$^Js*LT80N*k) zz&1Y|L_~tR_AsH<@o?!8m%%kNxb(KDfSqQ5v;OnFPct_QMT)1YqZUv>{}C+M8R-7Q zw?+qQVBqyzx{T79t!wXU9&x$3x8OYRjGeY0`A~3&6H~rw2s5J`#@Gu$E!wIZ1C4vj7J5J_H?&j% z$+{*Jh2z)~-hh|9$PBhtM|hru-WF~_lD+d>c=6MTt0DeVlqU?tlo6n1UMGmKKcu%p@(W)1LyTa0AF%7v zO~d83q`70ALQ&$ZjC4ZHU*B%R9187lcLD17mhv0w2ry+!`fHGOK-wolvI4*K_&mz| z-a@Rz_ zFV!Qkqc2VDCK3_vDXck$)z4t`?oo6w6M;c${%w%8i6ol<+B}&x5Bc*nK6nyE;b(6q z1jRhHWlR^|*?n)ldYQik8N(9;p#UJ|=|5v1ptG?fvd2iB1rzf4*9pZ|j(jY>5rI9kS=m{xJcnZxzCukzK97Us>(Jh# z0-C9LEG~fr8>XET7BAI;JmyNRgUO4eJ|WTxaTyXJKurP&`}P>a69mqR0MVdz1qE*P zS9Kd|6?@7lXy}Cl*eBFRqLzwR+nWVpajs$)kTktqfGDAY`)IY6}dWV-%KA8v4au_=bjBvA_-gn7=@~UxLC6I>@KJL z>!L9O1dz8`>ImLbR`Kwk@<@R^B<(j|Q;CKfR%hDVkmZJbVGum+-o@ah}aeVPDaNh2}L*%<6*MRf>6`YGQTy9zW7G~dH zq!lq?j`E%KgJra?Fepx~phb69^F&A**usuHnr={s6;KD#kN!#UPknA%rZzkyyM7=3 z&#E>@(C`MU+>*Fg%0WYqcQ3^hK7h!x18) z)RmiVweEO;pjK9)6_8q087e23`u|8N_dlM0YqU9!8!lC(UE+(~SsH*rZHjM$ip`Jz z{wG$L#Mv}C&T4=l!k@kEmzdGIHh6!sU?(X$uf&b}B-woG0qm+|cQRy1LDF?M5kk^} z_{Vf*>JFUwnh14M5ZJblZ_u6@3$K9K_EQCKN_S$)@szAjhM)bt*lNumkoMnLi}@Gj zhFi;%27jJKN`%_qu6r+ff9{#|5Ph(V_8d+h`QWsn8`$>$1MQY$Khf$}WDCVfNH7i* zrgnI@mbmihrM5a2XR^Ac0B?@J(ApKL{0wI$qIP0Y?Vt4d7jv{4wZIK$*pk`|cP6w& zoeLtRQzt4~9CGFHco>1rJS4d}KOG8v89|jrbd*rVe*&BD%Uu!RApe9nzh%Y4Rz1xz zoG9zcCU$~27A6Geo~=ux$3!O!n?TE4AkJmLKu-9D5 zJ1d1S1LGVGbI0U>z$Pmao zf^)(Gi`eAF|MRh$a$Vc>LTg+^E{~e>*fJZ(&_o9egmGa8_`ZD}AqUR!;Gcm=+Sj#+ zv3ip(bpr&8r`X9H!!yd12e04WSpE#~Q3vCvQvJ^7v46*9efD|C0z90?9L^@hxVU6dos=_emVpV72%X z985I0*@F>hKlxGeH7{V#jw`82>QzsH)F?UEML@UJ*AtL=LcSe>X> zi4U}vzn5#o(GHi*qL7?EY%kAwPgh5MejAOh21N|~nGaG#YKX;&1x5b7Tlm*eQcheb zyd6G;=BQq>kZ~Jc;)~?325d`$xe?RluWK(#C-Xf4Qu-O`t3P0E&I^{gDMO{Lt;7mV zOM<;&Qmcl_a%WXo2!YXjIWn4mW)Y{^e@jOzg~wxud=hSnN9e4$llgycP~1tF)6$v? z)1m;GFnjX&o*+P;W=g*!&%a?AfkQ&z+<5Ry-I#KnG=b3SAxZd>49_WO$E{`@FA^Z&PP z>KMl=DCT_=8;c06ZBz+tSSGUN+gxJyQRg_qSPz0alz`0&SnlrMo9xK+k^eKC2Yq*AVae6U?dMVW;rs4cSU#C3Z) z9{ge-rrZT95L*5gx4O57 zUw1OE={?G464;mx<<=_fozcH_-Ps6YQ($-)MMal(^?^#|c@U zDl>&hJpQI9o)oF5WActegZ5VSuu>fzl!+Ey+|BoNEvgQH#+x?GS4r#=#D?zD5?tB2o=mhB#P z))ZmoqXCR3P1cp14CVVh=PBGl>tvhby?Tml=?Fyfk%v)R_?MQXMEt!jA#hj})w9B`=H>@K`~ ztt~cIrVTF7jY;A{Sv0TZ#^Fsm%LqYpVgD;ONqH4n(8dNj$Am}#&#BNoTmpDbeS~>Q zquG%8x9g?6fai=zi_8H$XXN#E>$j~X?HCJZOBKD6{k1$BB}B?{Nsgg#ilI2hdi$}v z#}^^gXs?3TFy`u~0?G;jovN|dD%MrYhuWSv!}h-Gy8Kcg4F!`ZCy7u++VfjI6rzm0 zHdouzW6?{VL{xOU!6Bu)PNE$UT^5&cL&reWV%WJZnF>ksYqlj)MeO@Xw+H=pFBDpv zu$gI+2CQeqrtLv|>)K25vXuvxQ@FVcpQ4EtN9P-h%4@z#V#KAA;n@Q}o{QYU>bM8V zrr^vvbKz1)J;CNY`mZ-^gXN#3uVRHLTtLRTixbHMlmncn-Nx@IBUl5`IlAfFLO2)7 zoKpDbt(+%cui*AJTvk8U-tnH+TMW-}ZZAQyBewY*BS@+x86sRpvj!rKSMaj%n#g^h z_OV3o9{r7Tw2vQ8onrKA1RFo7 zr|8u7Yb*MD-3*C8zk#ioaJ`!Kw*mzY+)|`>02_a#5S=@a2|0LjI!d%e2jML_-neA} zuvtb3-<_vvkcSSR3)Q*-m7**^=l(JjIyRtZ@BwEf{Ag?llwdkK=AuHOS;V`e!11{_ zYxgBX9xC_i?y9`U2F5j+48RN!==oH7(R>|%kR8}yg?y-nw-o~EqL_jHu&;y8=kt{j zd1G%r=SuCa?#9U{AlS4yTsjuYkh+gFxpX8Z;EyX+^dAEN?w2uR@=Gc3&nyU#yjO5l z&bJ}jc_6qSbSI=6H4V$3@4mO%tS0Ic+=to5f8isYzYkY=OLu5+>R2mAj~9+O#6QR$ zT?xahK#CW{bvmpn-szVG-1d&`88scq$Fn^ds$%vZ4!?hjP9^|Qk3=(u&I)imMJUVJ zB*^ZuiU)Dc7L@1R1=Ju=rFr^k@d)>o~1Boh{Ip0JTWp~W>mV)uh z3~kQg3&LmV&nJ8+G1XCzURix2IUe4!mbqbM3@Qn#)h#EUs2|#gR;DH6dF&@CC@J5v z;17Z@meNhVc`j^;ib9ahbrVC<5xDOW@!P_0`X~SJN9`5xO|poH+<>~&oC=7jH!D@J zjCmd;PWr^1fKH4!K<&ezn{?r7T+-UPd`$#HDT|N&ONn^Xu3LuZW$b2XcY>pmtiN3d zILeot{x;2wVMo0UZ=7hgeG1o>w9aBGUF5;?6L|W};9`V`1T5Gw11bj#tuA0;$P!DZ z{#u4}`ejcEVX5Lqh?v1Q=#a&Qfx?UTa~FuA@2Y~9)2LmAub>=+09yLJzWb+A8x?R6 zs2Zd5!Z%F$RMsQc^eVTqZ#53vXFAychnB7PY(_8?x;uls%yyC|3|oI<*SwE^hC=+p z`w>GG-SFy_5hqvARo{=osYFL%s2MJn$OjndfWPJG#1s%|?STzT)v!L+cz0ic(5set z5Tn|&PnXhK9eqeYWfLEztJ3mVR^w=hC^*|lHV^Tq=7$hQ%#V@JNM^~@fpdoW-~>th zeIUC{3Q$4*`vv`ue2hv3hMm%?af~!XPiInE9q*nNZ~>$)J`B}0z=y(E7B_^4bu~w_ zSyJrG6>HtUzVzB4u8m|z6OeBFAV>OBN`DXlKr?ept#bygnWRgUK961cuc9)?N=BUE z+GbwY{}>rnbM1!v1+ABZ!R!f#_+5t8r8#BYwds$4H*c2*CV{{A0{l+)9Vx}siYJJv z4+G$`*qIAOaqdl{f^X198v%Nhb?-mN%d8o;ACSH*kRJ-SK03;N<2bhtTyzY%Dq&{_ajy?s9SCt2e>zV}}tjV?NE>7oxpgEmyT2D%S~D`r zURwy2`Eeu2%t&3a%3@&UjR4gZQ>!N1(X8!|v0&V# zuAsu%@Z~33kf<4+yu0uc#)5>iDn?~NRpLTl`WZ74SZQ-TrWrfEK{0Pm++?GwK&Itm zMuC`}Y6SKT^CK>;FSJ@H8ilgsJ!HNSZ_2nfNI6_c{T4tdOQ|>q^LK^CvuLzEefi=4bKjggJLYk zy!CGbrI;+j<%rrm4j9tmquP7BI~MJ<5EVTEi-+T^K{itl*ISH}&xkpkER*Y~esOfWV<)Tu{v{$8CU! z%VvI&8o0-XYSnIfG=&9V!{(g-;C;{^Wwg&2dkH+mWk!_Ph5Bj$g30jC_T`}`La3(u zh|eitlEMAPkM3C$V>` z(cHsRS*cwjYXGV>*F*Z5WaA2|rqEPs_p~lIYH?TPj^>?*;Anqqme9^_8yp;GW^uf{ zzB=cc#&id)gzFzR(jO@^uOX@IhCI;F92~kajN~?lxVO6t55zI01$3yx5u5l2RjW&G zkj*xeA8)T%z`wZSAnCDAHTn=qceT&@W){tS{C+D+;$4gucpMD8*8^7s8`?M^f z7RL&^0XG56fcEh0T)@wJO7M~kE)|lJo)Z$d>9#k?^W5Dd0Y+ET`!qB9v@#wy?uL0v z(G_=>4B9^oqYr*Hj-e4>Tezy&iwp)1C|hMJV&7L_EfBrsF~mpJ7RPXObTpT7phyVf zy?V{-aE(jl!1HXdPELIFi3+9J$N1Rld;}Nj%W;M4M{ec!w!1$u7bu5ZL?Nl`A7gDw zPgQ8l3utbFy^-@Yd-gN59Y$4&`&fPP z!bITE)AbVq`V=c;85w}UD?lB5*}1_4e`!BBJnha?^4l392it6OmOG(Pqpx~KfFqGI zF>(iu9rrqR+(M!AbPThfiE$7oXCAK|*$6B%Q=Od=-QnKISPdI9$>_J`+uSm=FP!sK z5rO*A*_PzThQ1FVx``JI!OmE71g!+v*dE9Ges5*GpW}r+TabC*v-9NPC5VDNDL}Y# zKs`Z@xe*Y!K7JC;EW=A(%LJ-sKar*P_w7oS;g9=r*&;!{EtQ?CXaTmaPkx&)pJ(}n z93YPkH{Qqroj|t33+b48{_pjb`fju$KN5!NxWL;U?eB35SHL;pV2DWE9X z<@$-%ybmpFCR(>T3o{C!L8PEb@ET@-=!u9{0%Yjqpsx*Rce#PgID;AB?38w%I{7;v zOwf3iOuhyp{Y5}`v2SeTqkusKwD_q$FRQ3}jBB3xE28-aw?B!%4<@5W(s7;Dr%A}N z85}M1(}qC>S7mT^zSYmDS%{|oabNq0h}3oFGSutb#en_Qdn|fW@<291MVW*xNG;RA zQbo8(M`tEA=oNY|oMv#j*)h18R=;<1so}dCIIBFuC^Bn}36>e5l>){S(xCrl!EE86 z4rp=KtYs?a@^7yE8noq2TAV8_N?PjzX6eeK{Q*K8{m$j$6M`((=B(Q0?}kH(j+m+W?1{GxJ7 zz_6Zx4w7{t=fjD5ci}_!Izx@4P;%(Ff2wBBnOwwX`)qXS;WH1oL!x00clxI3g<-Wa z0*&Lq>$=m4t&+g|%XIggcrqZ^cCr8lYCh37R6iPlK|9P}nwL((ZHA;ckKy*79PYQv zIDZLbHF*l>(>zB@XJN&oas>V?PIq(-0J3|vvA+KCkc)c(I2wHP=8;f7dr3szLuJZY zQn~<7yW`?=z%#7JY`q?Kxl7t%aJL0={p3d>j(llAV3f!GrAe%j80W!uYNkg%0-G;j zjAuW3v=jXs#*APNZ$sm@b0#MClb}KD{%yOU4t|`+UXR`p?IS(1BjvTdFOUgfy8Qi^ zM(`2=L8m)3!!9m%e6t`>@1K)cB`J5TrPZ%JFq-aedd=p@S+2*TowHL*)*g1&5A)dE%26}Cx;tz#q-S};z>?Wo-#9FB6czO*B*Q90T^)frfz zVO#UCpiI$SwthNqvX~%BM70M8QmXrW2TS7G+MFvr?6$7*)A2^k(B62QS zRvCba*p8hKCbXR`)K5`=gP&gu!R#C!{s_|M<9QMG!?UpGzrqZOBuE-bL=KS#!nz@L zspGik06rJ+xBBs|j@u4=Pc7z+;3|958#@BjOR7OF69`P0 zSi~q7YBs@axgZqk4o@pB1^s8XHNj0)q8qh`hgq~Q@VxuGCh#LKUXz#>51JGzZFV2T zIOk1YCF(_n1E@1>(oFgkz9AmUt#)$mP$egQQu!K4n*{Xn`IqJ7GI0Ebi9fZx;O}&Rp3_(qh>{&`bXU~ zhc@T5YxGZF@|l-3oCaNt>r?J5-R>9crp2r47eLx>#WKH+zXMm{7u*d>gA6qdMj${M zB{M=1>@o(ZRzDc)6MU67M*Q&|QkA%_541w;jN5BFA^wIgb?GQhO8yd*AgDuQp`xW}CZy~}dqs4+M72&4azJEy-V ztbknhvdWqeN=Vlks?AGf6lA5I8|gM5b{AVTRK{Osb(M!kLrRw=&x<>n%8vCJ-g@p) zetq)jeOTYcTkY|CvTe+LlCBzMaL^J|9`UTZ=H1UOto>juQa;2m#` z+B;cB$$v8ofZKj{6KsS*0~uZ=;wcaIAIi8n@EoiR2d|&G{q=Fpq1`grECX?`#+hQR zaeKy#`2I303f%V=#4CKHBaPZ_iu94^daMCBJgTD?gyazg#j8Gt(01hsw~Re(SziT( z&7*T6D!aFWKuKJ~d)`%!jI_y`@L7HIn_-Q?*U|>Zr{13dJ>L=Kvt-~{!_hB;0;y`$ zD1d>WYAQlIBZN{6Z+O%yVt|MiJ=-u9yrY9?y8pJpmS~-2Y1fIQ&cFpcq}q7k2fT9V>G+(cVwS>_%!h7jdC}D*EjCgkt}XUiBt)lpO72< zj`%VT3Nak!UXq~Ocj?4qJ4|MW#XU{2Lg`fU2Ft4QFZ4 zwu~6)rVY2vYlvR9z5!kvGamGXFka;B?o_9s$JSRJ@V+YqUWVdr z6kT3-Hh)Q8?CX40PmR~u2jsU*OC!`W_M}qJf(UbT?8I@9#$jmb(B`a&EsR#5Z$B9Q zNlj1;?kG37##5AWk@rae&gz)vhbYi+fAZT4b1oG14dD!M9!cRMFO0Jj1MmH!yHK_L zM!QKn!8QGbHwL~lth-mH6M@ZLtXuh14ccS*3`8s`Ks43+|CoF4xSIR_e;lEbgpi~q zD($4wPN`5zsHCl_z3Vj5-qO-uXqQTR5=HB@_g<$xPUE!uJq|9H_xtVoyuH7F{cblm zx9hlW=e%Ce^_chj{pn{j3XFSnBJZ+<5Sq$7cAX zKG(dPk%7*I`_)H#j?Y}3@o2{BiGN(w^7dG_7m`0~m;RW6Q1hL1jsClB_O%trj`ee| zf?^PY-(uyxry)YDY&tg!vmV}P8|6S=czo0BxWfd5_kaJTuk~!VKG(3gT3mOn?2+O5 zrtC1Mir4u95ga`47Q%d+wT-Yj@WxjXdkrZqd!wKXeWX=Yhg_>ER474DjN}ek+b7MC zIH_j6Yx%d36e(%$XPE#VPzDjbZaM;dT{(p)XR#@uU{C)%_~>e!km%&6l` zy|uh86La9O_>}X}BNMm@hYzh$LM>P*>uuW>c)-7l2UxaU_J}I;(rEZ{BF>i6Eo-}H z9K5|_MWDRYm2J%Rv8rnEVO8e(<5f$)mpu)|au{~#p`6Wb`v=|&Wfm~DMv)`gBcduX zGe1f_Z`H0%87^WwgFg$uI1mtxzlHMY-<|^sYPy5gz+$Yn1^g}v*3s1hH?iEj6!CyPxJ_??R{Q7n{aInVGb z3LLyc24JqzxA&%Jy70N(eVYeS%E@s(0x!|C3sO-%LXeu|{F0hP`<+Jjy-_>5Ta+1# zSuq>_5_O9U$G_1IN|m{GvCB`Jm*0W4Ev=X*U{c*>XHZ~r!SV1@i4 z3+V08tdVT3A{JyjCH{3ElFP{5@}u7|jS$;h9{afHS-DFZ!U6xBVBC*=fuAf=s6T&u z0h%j^!?Gq(0+$%hcjtc9sccr1f$Up835^OQE=)AtKc`Z3JFZ>2!;N4<3{(zZa7f6{ zAmwd|pa_sv?o~r336<8@=6I?`;)pejw(VFlSyjyp+QD9f#C;X|*L=iDYceqDOn*Q7 z+oWU2Pr6u;tSrZ{@t-fU`0-qMcy1yW{?^tCkJgvt{@VzPOS9@mJ1MmbAH2}p4Va}@ zn71s*@1Y=es3(cY%{0eusKof3G1IsSd3FVdnf@M3@z;BQ*Nd&WDpO-=9+6>q->jx-Z|S-a>=+Zwq`T;^neTTI06*_ z;DuzLN1wM;CfjJ)#2UO=wVYM_ohhs}+b#+OJ+>)iE0j^!85yq8?%geZ*)ku7j^d(m zCI^BK$;SJwH~dKrUt%Q|<>Yo>$J!0b_obx}%D0QBrTTi}i4Kdf6z#iqMF|hyg}K8IH+Jds)IiFBxUyz7>XL{RNN&2BV9n5;aeg7*i1(G~-ZI#IZ>c8H{ z2bZYm1g9eM^$l5)!)wRtrRb5n#m`F@!qBqkp5kOIf3b6V_L+;ZZ+NQiy_{DBfn^6ch+$bW zsTN=&{<9_mEp5uSvYA$I`@H5L&7~SF?tKNXD*6(<=$qlbMDXP#J%pc?I1cZkNKyBb zkcldT`0GP{^r(Al=z1WsRgjx%ZeLYtyB%g3?~M8W3T35CQbMyBp}wl8z)%-0G_4` z%kJ(6+!D6U8tV8CA6nI^Wy{_7Z-*5M?2|o5nL|9@eOb~qV_k&H>GOKW^ZQOsP_PWG zh|Z%&TDM56sRg4}mU5N>UK;(rb&zD7XQzHPRpWD6#3O+edD+yKAKjyTMwyfy*b|rz zy>U*L?;WY2W0nd0eB*gH6vf#H@-9p0+_C z97}CCz+(*#@@rEfhw7bLUyZs!DWX90hSd9KQNw+pHg<9%Selz-5(E!!BPK2 zYZ!N5Jrw|D&${v>>68%L_kk9x7Kpc5QS4E=%c%MW?mWWEnvV3URH#q9qWBWcQSz7l z9%mE|5Pfyf?k_CBO_i8$Wh#JDIg-x*0QIN&v9=vP`%L-TG7~pcrT?WQ&qu~MwvjPz z*0mkNf^1O3gP0ymlRVTB(8z_zT(QIjspca&x^>Tgc>DLcN)=ON4jXe6z#PrnHFU!a z-9VH(;Y{{HXzEM)G@KYLNBPnAY7%{%qjI$&R`K?@|A%4Cku&QmR18DW5{k;sm|^Lw zm7CZKA~bni0k+ku^D0)aj~LW2li--lStr8AUs~-^?1;@+q=55lwj}Hk1AM5RkqN1I zSnVs@8UbV+6Eo=TN=Ft;BPd(j&`Qq%rk@*-x1IC>heK(;Ap@tB-_a?x#bFvQ1VAIQ30cZSC9j4Di zFuX~}Ii zt4_Ae{Cb()^$>3$+@%nXcdIF0D^r6ZyF!WTZ!HC|*d0c`HCqOw?}-(18}--1FBM|_ z*jM(n@gBNeL61J3+$VJficx&aeVi8#cV`iSSc#{Q}2D+Bg)$L$u%yf4JXJvN~_ zasiK_%BI7GodeJXgazhw;6Ry z;E9reS)`;XF`IG>hMd>kea<7^?sLo8ffB^gxi86jD@S9!=J<%zH_|_RiKdY>rPCO- zkFh88`m{k{SE}jmdO=cWM$G8b{%)otkjxA6}@u_ ziHYo-2^Rb<(=BtycIapfCXV7QbTbtOz02mukWqNG>aN(*9Cp2+YyI;L@(bAk3hNVB zpDX=d&v1_QKy9uf&E+Mh%SbPdD+Yw{X^a?_J?a__M<>uZZV4@-4GVaJ`c~5KhYzEb z=U4sD@+C9Z20L82&QP&iPUa}l_#q&TR?#EkdPvV|&fN9HgvCMp0C6L|*yH@KdhJN~ zx^KmB?@m-d2QH?NTCLZFA8_y-U%QlJ&n;l9e;CeGECtcQ_f?uv_k6V>nE;)*v0X<> zy(#FT7V!wGvKz4!h`$6d=IjHZ%w@=0JDXuW6E&K$! z)X@XC6*Xl-e|aq!hg|8=7IoUK1GOQ<7u5^-6;gW1%X-=++R;ebhm}c#+t0&&gg%7T zRUdS`VI6`B3`#Jae8+-xEOs5rmVh$Hv9&JDLg~Y5ueZ=()|t>imBV>$g`U9oghvir zSr!z>;-@L3A^?gONOyj+2T&z82M@lzQZPPQW3|V+8~SA2W!aW6>p|cro-4uUMST9Gt9fA(~rWBp6sWoX{(F9{eS> zz92Ph|(T?BBcYwB$mRbmMEXN4;=0qd7oxjuaqntlXf znaWk^mtseHSCvdhRuI>skBv1%lV?3(@CzkWtHMdSPg;?5X7WQOn%_wE)NU6%Z0ig) zy)00)CQMiCbccPUucnJ4xHv!x`wr|dEClgKegip%D}S2qTCy%C`I4F{?%`E{^H3bB zRvV``X9NV0C_7yPA_z(>Ir49hoT;J{=yQscM4^hjQIaMhu#2@r*<;73ya+gZ9 z`YC1^kkip0rv(uDvRPvHvLteP9%IeK;lWIc(W-W!E?-`_QN|71M_U5}2h^PSmwb8F z5Y9?8FU|@jMarD5zhR~4v-lk9cf3`Ah#{1iwa0}``MEAJK4vjJly+5_9>YK0jgcMR z=SB20Jn zaa>9wkZL5JEwvw#iiyn_IHFV$L2MEL=!56y{Om?M^EiA5!5eqU#R#dA`LUKmIlCc( zrOg&Ln28?Xa4iGO++$Uye20q_?{XPf}H`*E^LM{=zmZglg`@|Yfk zlsTY4LKmra<6-K9_30h<>IH~;U^~P*j#tyEP3NpVvZB*3dn};HG4j-~!&G_8kIX=@ zbJ;d8mDr?Izl{HJZizX~krd@)u5WVIoL+HK_|Ar*4KMZwLoHvLREVbFEkD^U?s22o zGD`wQ4) z7=m?!Dz}=Lq0xVnHbVr#grxc5`9HTf==X3>I~FNtZh`qm7j~ zb3K8WaOU9x9Ur`lj_*~guldE6O3ZosKvm$J>35MvaA}TRER(6VXbC^0Pf%+ScayFR znj-MY96nJ!q03-RoY0Tn5+CWYDhs_uBNE7B)G|HNvv%P)8^XBV;ygut2%$?c=ZA?o z`=;zYE#LXUbI$XEultDvbPb8@1MgH1z&3Q=ZTAzSoJ4OwCZ&t$NaCl{v|Tp}>LN0= z-;pEHmxoMA=`4Lu{lST=z7DREA0& ztvnsV^>AWdB~*?J zS6-Lt+0(Df7M#KSG9SQ#$KURspX|)0W+;1jlG~(Tyr`2;qb@AhxBouDdt(K}z@`Uo z?iukX`26?lpXE1*FuicM@e(J0(XcNY9i->5gS9;5$Y~X%JhqwJ`fpfva4-6qTvQiM z(#gzh38t&jo1=mop0$%o!r=RIYOamd$B@QTvp8(EF04C^A9Q_l9-hGE%?C0E&v}J(uWD`~AhRch60|eO#x&GdH9CUPfBP>P z;Mq$^QE`dk!9D(-MxyD{&mD-+V%j+p&$F>cCm@#J$BZLvv}ZL^uXDxf6f62{V@!o> z!K0%e-+MOFKPr5hZLj~VV~zn?vS!C-26Zi&Gv;whe6_jZRZCUv&39#l6(svRRcwnc zfV<_N?c)Z!UHprWkM@&ApJx|5f@L`NWhvnu8A}2ehhHrZF3!3{;F{%F;o6P47uQ%N ze7ybrF*eonIepm2Z5^{?vrc6}1_(_HXGsI&P+}ODQfzc9))JA4c}pNyd;gz@n@A@y zTsa8&8c%veojJbhf&D=!-PD4Q1$8ylN@oNU=2fd2U_voM6uz&L>vA{qq<8dn^FAlz ztgSh zl8YztJoy<*mk0LF)5*k2__$|XP*`L7Ah|7Q4?9S3GYfZE6Oi~AujDPU^!&3{!dxy@ z_KXSH^CT)UWF6M=kD=f}%5zXO7AEiVzk2S5c3PzWNB@4TBF9=X3S;_xNYjLN!z1Hq zh32cp*5THA$(R}Md?!vi=n&?jz~Sym+p+1rhMkG;Hhs%YUdfl2D)NKIlt=T!3fVA} zxJk*~VSph0<0EzI13uz3dMShZ`Caj zf{te^`KZX0Zn}WU z%jksdX?PM^_LW+^3X)%~5O3vtI{1Cx$}Usbb%{pJTg~f;+}%q}uVVA zI>&ib9;vtB)#iQ>ohonWos$GbhY3Ak9ldehtA+C&^y7SEElam?LCIHXStl#lV%n6> zD6y*1r6Dlx>$@l;+azhutG0l3}Pejmq~xTXFGdag2=JQ@zS% z)a-oSsH4d(2dTJ403#9dD2r1aibZDyg-2aJA_z&?c!_)H@D>(o0nhiWbG< zRXs7d%KB`=PuaHo)Ofe9tup(qgK(?VOVdM^+A)Y@^z#?3#1YabGoNNjA&y-$kLA01 zJ4V6roL^RXC+be#9!g}jwj+jn<7hA=?afNq9C9giX3nd-ui^r}Kuq-9s96yr=K4sm z&=&7{=RT0||7L0YQn8{FlrWSAlIDk7dBE-b=EmTF$*MbO!%V_(KKDj``9g2lRfa`HoW|bs`q-m`tgYmy}9zaDP5Itd$EqoH>&uk znlsz6cqcAlzPj9Elw$u@`WY)^ZZW3&wvQ~X7RT9o<>PLHdu@XXU2jtekfD(O28yz+ z+yY;E<*(Q{8M_^q!Mm)j5*ep&-v~qLheRb~%S<+qK`BC<0fgnHHCiS)`j#X~&281q zrm9sk?s)wNdxWGFAOMY2Df9(1^0>8!6whpmGL$=lP`E-t85on~^h!-Cd6KYEe zxbbo_uICx^)mb2~2NoXR!w^@X2_9%3!+mjy_=P|u4o?o>3(*}DE?j8ko9oz6$)yU* zy)1Ql+u-w&lFt%hJjj3WQp{U^x`2xXw|yZAXBU~+;T!MfU-Md(LP-0*DB6QyDr|4Z zj{9~@r-`L#S!OMZ&*@l!i(X~J5cW?>N0c1#@Za{h%^ED+|0tv>r{>{yzGGH3HJJNX zeC2dU#_Ei&kyyzrPvw$~tOoH($ZOTd#UAlvM3NQEe;O;I9Ioni(afJAXD5>p++~Ys zOL?nOUUkXrfF>=k>F)EqOUz4UZJjqGJ6zHg<95QB({L1XY+uYZ#wT_E;=k zUhI57xmCoXZ5lvqT$9}}soTD8_yy!bf-i@c*L>oK~| zHqKg2Y!nz7*Q+E5>9rptfI(h9$AS!*w*34~wP8slC24WNiz8XSf-Y2Q%0oBCNjc4- zCZ-}@YbB}u{=IxUrykx+@Gh2zLS`&MUgIr|)vH~xx2hSO2_}-kOplsm%BCB-Hgb$A zo?nU2?!whtZCm8feb%ZgaLuB_rB#=oeQ$3TLB$)cu;%K1pgT8J^237iNhg%KsnrwP zj{2vqGRW14tBgnZFi;OEvcmHgyoKP>xOqqnSfWMjSpQyCmk%nr45Qk;aD;EijL)+( za=1JlMsHh=>#XZ{p9KQQo!$!Fw1STjZYRD(@|CQih@rJq+uQ%np#K8LnviO&*|=iH zqH(7zy<92VBd&BWR_FE8t!L7!p%SF0TfYOnI3d|AX(RrVWiW;aHYLjNi$kn+SagL z^p}d|w@~HFHOS|8E}Q3G@qdM5%kSyyEv~1BM`6EyJw1Z&6fi@?Vm-UN%J%T!IuI{U zLFT)K>P{5_KtUS}+|0P{O#UKE`SV_EieOTs`d)>WTKUUua}M245 zI@zP2lp9cw3log+58eP372UOPT{ZoycI36W&8|U%<*qpBl-9~{ivi5TG|3M^XsY~k ztbAsRCPZtLK#bL`Iey9xC>Yy;AD9;;K=R1O;V&N24^NA4!C7SaFuVfqEJTAjhH9ZD zVOCo?nJS%-p52k(+^<+B+PgKZy|*WvJHx#jJHsd!b#1Xgf>k|R1Y zv0fXx*MCRB;+x8MxCG=;jQgv`yE{b+DPr@P5l0_xJl!5e8mB80`}GD2uhtfWdME^N zu`JZKvnOhE$Fgvf==~d!l>HC0#hsny zp@=j0a;{1ObUu179Snfh`7wSU1+0)X)n5zyt(-Gn6k(W?4ywzRNAJeC9mc7w#T_&0 zELs`{4!TYB8xYjVjxpRr>kHKpicjiwS=JbbH3()9&{5sywW+} z&*K{#C$>DIsKVBx?2o-!D9YM8@Placa;^ZHjmj1Vj+T5?mn_nRKt zI|)3r5ab}1iwDg{;q`|9B`=VVN&8A$H~p9x4{BA#M%;Epv3`^acSPRz`q4&<4`m5B z(_H-IcDago1Okuef~4?*)av6n=m4_5hxwrVb9>wpv5OIcW;W)?2T>xJQGb2|?2JZI z{$@rSPa&MrK2u$_o6#;^y3LcmV@*ukpyCxUL0FX^y~XZ0d=8HB)yW{(Q{)Ha1*x*O zKKo(hA(2`Vqgx|ifg1;bD>6m?yc7YGBoULxh>fCQ?*1;qW}{&{Daz}5^M@t(oKz~0 zdZUuxZ}jEpm^~YA@%wZ_tIIZ1=Zu!NIxT(~%%-0)(+-d`(X7|9_u|Otq^HuWw%n;? zSYWh)x^v%-`Y-wT&z%;20m<4i?J09cjH&@AMK;@-r2cI8=}SImK5h6YfTjec;kKb& z6CL1B_ztE!2oJpb>i4-0O86=1yvwuIDXqLS8apC^d`Zgl;ZgjQ;rjcr5m6Kzcb*eGnADoGQ}B3Ay{`~K=2Fe_w0ExBm3q$Q?_~nqLiQw% zN=%)=!l!Z^<0!$jT>nW*?W7bP2~$j7XKt7= zwLvx8!>tHrHB85&8AU{<4s*)~6{AXuvu8+2-9kVIzGs!pHn&>xO9T&2rb>m^GtCK2 z;V>JJL)jdXK7ehJAAbjjFRa0s$w4g)MIyVVp@73DOs(RV1i`&)UY-PTEb4HObz8rK3UImtIRPzeY#uOoBvFC#CH z>aKJI>n7sURX8#t+h106_FZYhCZ-N@awE+@8dun#?is1x#z0-UJeb&?sL*UULE3y} z=&n}7<1=!5E0TycA_z;=K6o;Bzh^=QZ>Jw>ro_h$I!{93Ek)XpFdYj;_uXN=8;rraG|8JupepQq?OZePmhe({4IpC? z3f(pST5G}SoU3kMeF99vvYeck$4!KERG^{(*yK{}60%$pQ1?uIO>B=TF&j^nHs5}C zSF2wA|6xih-2)&0g$4Nc>B(@mWi!wK1)obR97u(%sf%>tt`{76bK#|-Rs8o$KY^G2 zIazzy$qIN=p_GGGZWv_hiZT0ZRjL18)xF&$Tn>^+^tPcHuJyw5&?aH@*y|JVH^Vyq zALf3!U&R#aPmc2k%(V;FX`BeZfY#@}2SS`rz(nR(@V{b*jsNoV`L0}~3mLZ+TabkN z1*3C9*RQ02A-y%^I2nqb#km+H4KI}LhDi^Nksunt8J6cv@Rm8Y~$ zWA(Q8n5AxRvOJ8y!lME_5*C%~3&XkWIckhr4Tei(tUGM^SP2omyTsVNJ2?CS%cBdk z?RnO3FHmTugv)7VNl$Up==l46oRWxR$0xNc0fT(_{XQd+Uq2bcC#uemqRug>ut%P~Vtm3_LR{mXEiN(pmr0=e(s;P0Voy9W znnEf%t-S9e|AzK+jJY6Ag~K0FuLIOpffSD+>D_L64?ly!&a4YJ^W z-8$qX04MT*jE?|q7&b57j*QN>`(Uc|HJCz-;cEMsB6C=lszjchz`G}NzGL$)M)_ct z{aWBWRahg~wEaO5#{1ekgIHYIO-go6W%_$=wg3B5H@c@Y-f1*k<$u8&62`AqYI$02 z+PbPEYvQ5}rC~1IEMXiBGrZ6>_hGENn3=@!p3w67xei6-IZE#r$BX(LQ+(mxpi34V zu&7o2VX9CSxO+tx!Z4mb$GH%oL#9+_>B8&|J;|;aI|*m3V4jl#dciK48H3_W3=Mf4 zNIL20D$mOc)K?hJ<%-)#&I@+wK(VxsJ_CG6QH{&3Trf(h?{J`+IGf4G90dH#Yp=d-DrcFf>jl)UW@va6H_#ajin`?gR!z-vuATE#ukKI2A4sXg0Ext0XB|`_)Q#D+;#8( z12+G?(NRw-JK5~<{v4N4zgw~%cWnquEl8Rq)I7!hB#|wfaRgTTi}&3Ec%c>bTv;>t zISq(S{_bS{h|{-s1j*|+gxYrAAH7f{;;$nVb(L?N@4Fmba$BxOX#_R_mm zq~jzpJK12ytK%zQA-ewllay%n`cu#`9jZX4C%%6AWTWCrB`_NK8+K!)Mw$J{o#9qmAYAQd^VjFQl<*+H+X+a~Um9tpWv?xn- zp?U^HhWJdUef@bGa4LgkgLRv6kRzXA(huMK{iF+R>CmXAJ>sI+=`EmPxA>Yg**B8$ z%f4tAXsoJ+31Mb5U5jeuF*>J?zWLwh0~H(Pc*D?%zDlqj`9!MLXKUeWlWM81`af<0f`5>iomB zELd;O$tX2zH(iCc+tIqWL~RsjtHtQBjk}W&?#jz_Qe1fyhFY0=%BWz~c>8q?5!i?i$ z)2c0;Wn=;)cFy)yJnw1(uD|yQpSStlf%U{g!t8!vnI`4OO1&zB1|e|KuxX z(3B?^{maQgUuC0$`xBb(Qr+9D_!4^PEGMXX+O#QFU=zQi|B8P@wrd4xTkQ`)MQg0(;%cYI@S6gKOQ=_9ZlAd17yzZ;H<;(6)`I=}zt1_OC` za-3k@_z(NA2X__`hiqC$NAc0Ir9);ppPcIi!9)@1?~FPxu`>gFMx`L&#)rj+;|4h1A{F#udweANp2J`yo{G{W7JlH@qG-qf2Lt zILsCh6WYC)w|5X+<`>_l8-XWaRX%8U%%2sBSiZ*gnj6Z7G%j$tJT~W9hr#}b^*gj( zzx@70bfAC%Ejal(56$|@{4YU_X=^AB6ib3=#a9RQvshnBlmy3}gmu5b;m=_x2O?g! zWZ<>`pJP41f-I*(wL)4`?n|88fvtA5Xvb|;!c^^1;~rjvia+Pu=kZv4W$-`juOQvV ztsDGMcoxjiMTJ1w#JCvZ8@2KSmSo4(VkjF?l~3pY%UTg6^Ai^=fLAZiJ+cyk{dU=5 z%PA5ytXqpy;|3%_%{{hNEF*>MH>TSk?GV7u<~XdMzHUgKkdU~v%^`MtU|9v*%=f1d z@^hj=JsynL1S}!}+;JefbRl5F@uFPT+1@1GLuY#k+W0 zY>0siy!2mSQh!x-qAJg>PuC2xX*Qo@ifY4s()wE5V>d`PXL3}p^Yxi?HoldT+TQVs zW#`t1!;H@ISdo_Rs-G7T-QLp2iiCVyqfV23(VL&bP&G%cH6?NUmo=hC;`=^R+1hPx zyhdV=mYq{0VcI*e1q^h7-VV{#!vfh)=8n38aF|nK_r8^xHoQ09Lc^WSHxO%#(iL1f zkV*JO3fBxQjc+VTkWaRIp=UdveXK48UE1+u&|v(#l=j1ylaF_Mus0>tJbaL~c>c&3 z(q$3fCtGKD@l{6gu^9K9H!&j75vLvWzGCG5Ua!H@Lza`LVZBaU#_8hzm-S-N8{dE) z+BL^DkQFuGCH z|Fm_#@J@}`sb}^&qbKBao`3EuCOmq6!WUx_aC$MWz2r>Svm3|LyxvxQ2=Mz9nCzFy zw{bIF#{3R73vNP!-9QO6x*h`MD z`i?W-4X+xNRg3+QZP>L<(&4abQ5v10koM9VKVKw%URMyka2dce`=3zYRjozivZ=2) zIFwsHsJEWmx+CJ2^BE%XW~Zn=u37o0>fg!>NNHQn89}dl^Q3+^D7CX!} zDmQ2^Ssvx$2y5Rs%jbL2NFaHPhy7e)l5<>iI7NGfRee<@i*oVvTB~A>Q4k8|mD;`X zdIa~?i4W>F;bpy6r*5BS^$jI77^$Ol`uzS-+R}IqyJ^vg+L6eYfzTnw7tk!oL+|I| zJ*U^tT+UD8*z&9~<1(_^KWfMruDRfL{%do~ev61T;ruG6rZchZuU#g;;3!f5xo3gv zqZP`lXF4m^c7>WLmh7F_@6J_0uy)RCV8 zD+k^3Z&^aL-}mAzBpq;FLNyLn#rs<^Sy7-pPCINJtz4RnL;mQ$1f{=Jkf(9S&P0#a zLGVbf*BSLsUOx@Ieyg^X4L-C&c)%;D(r?{xAlJ?S+U;{Iiv-{G@>h1>vt2cr4kE-ri* z&YzZKl$K;%qZ-3Fbt8@TpUgiL%TbzP(=bEd?oh1KL8rrg!2_7{_Lp~jiJ1qnb===& z9au;eWyyn|S1NJ^p{xZinDI4oRK>84-&hv^^9S~o>s~bOUmHltLGm=GLuT-MclnVLhpkg;;pt2KeI@@SuM@ z#5qdfahBPn-s7P=*9KVIKV1xCoC{_f-WX{)r>|a{CjY|_G0y@EExYZLQiE+02A~f5 z`v~tpw@shL-HR;B=z)~f)6uqDSk2f!og2=JCsC}n3lDzabN~2glzE7c^dT0a?cR73 zo0Rs5$D>MSHId<45>C0P$oB-{6Aw3&AHr1XNxvv(Hn6Aq+<&C4Eoy zX?w1x5|$*J06+KB=KW@~Lk2YR=`u`HnLF^w|9mGb$H~gBFSyniWVKa&Y!j_YF9(a( zckq`G6k9O)ehcfr?skeRyhrwSQOw9`PPu6-Ie9e*d!YjqCS{@R%nbFd1t0%@iDgD_=kqz zJ8#4mWGdZRf*rvL{^_gM$OL?h*?~DN4J1H@{Zs1v8;^z0k?_twwt&AtZ&oB+_kS4T zNIm^*&kQp%BcgCo8Dup6bciwEpdc{BnYREugByN-n~4AB5C`c>Xw(>+fFv5zLF6fm zFK+Xi+6u-us6*XPv03LC+d$)~2qRxN(O24|e@X-)Pn znZPB+QT~ql;M8ir-5nhHb-9g4cHJTjX2F2s`AZq4y%}IIVk~}S(%+LWIQhRj=rLTZ zN1SIDLs4tYB6kx&i1JU}noKOE+nh6;yBc|FdU~9AN~1 z{6%Kpj~zm#KM^f|{zX>r>d-mktg`72mV+{9{)gSggca^N$rpouvm zMzOqg78pq6DTC+UZ^A|ASfF&X65McycYW6b+H+(V4e2Sc!t2-J`2JGgcZB*rOIit_ zgdIFSrRL2nEs+RmOiUW%5t_xT4BoPhZ@aGtn7rTDCZh6Vgy0$_p(mRK%xRP_29-|u zSykB9Eyt-+f5A|VcURE3Wne)up?nnJOaI1}{75!}QP(twvid!ap9wwUM&WpKD-5yV z?CTcO}8N)|>IMggEp@Vu{`*wIavF(g?D{KMAyEV&Cap!5Nq1;ucz9D9$ zsGSFu2}NzL8txIY<$on`U{{~)=L5HVpN-NX6P7DedK6K!iX7Ac&P-Rl#;@a(>5>$0 zn38liN#{_7|3&yIv&}qq7?jXD{kg$C@C(C^A}{FR%7-i*H$T}J<|~I`NG@=$zSA^* zJmLCf;QOn>rF|qLZ(_d}DCD=ciZeVOqspuF7R9w!=DP4IjCt*)_XN?90p&GLN ztNL>2;)7d#Ks0h}P`vV{hB4%}X659@`oBXdueYhyjn4#rdEt)JqsG6}-PlehYfHs+ zki};=KYN;(8)$w?!MGS}YK3FY_pT&mkQF4J7_nURptD#UEa>bFG%ggNcr86Xh!Vx? zldA}O9o+FHHa{UzppbM*yr-?cdSUp@yXzra?K6QlksHECZk@|5;(a2r!RBssTPbf- znfcAu!ps`KEQ&G3wUdAWQBKKlse@>u5z9w;cd$^)q zx#)!30~Xwm^mh=0m{t8CmbKenSR)IqJ&$fDri=fT==QB2;U6CWh>td34j{@{S!4I z+zk0)I!v5LVVOXj>m?qTlsIY;C>MxF-Ln<`X<2@T_K}20$Sd5T*Y|6l52l)sMjBg3 zmxWmJujVLrNZpVV{7Y)@0`-`qwYl0k5P17}|Jqymw@4f?j>cz$b?dYs1Ry*8YyI`# zGh(oUY#<=~6-)y+1AO>NjQMv@0q>`AH-SM_9O zJ7)n@*JRNp6~$wNAIswH+5G|Awr}>%8nWco+?}sdbislGN~y3n#kkZkf9eogqh?|{ z*@9EYI)>ON(Y!ag_DdC%*j5h*l_Msl_l^nlbhwQ+nzcAx-Kmg> zb<8~>O2;H}BQ`WyK0dhP!(4A5y=>kk5mC{{yy+_<_)=$E1XcGNRP?$&A&?&ho|f%M zwgcY61`Ar?6>%7gTC2Ye?y)_BkYS~)&;Xu+4QJNb?#Cj_&t7X;gwPZ)|4+aRUX7&aon#^2{iujx8kb z^p>4jy`F`(wlPAl-+t5buwaR3tgf|hp2)6gm%Q_VHUf;ybvU`v(bAR z1Q2%P$oN<6IgI8yNZ&_ywloLURc%w7s$LZjX(ngCGkr{{^p4<@wB@XjVq_um(Pqk8 zVv7nw`U%(P7>BEGw*_e?)MqH|n{zbo)LNVrDO2E5bEqI4+h9Puh!9Ma$Bx zm9CZ~4jeq*0SK{xP0?KLTzFA>NOgI?T5eIV%S)rx(XEtRl6RK+&TwnQC+DWFLl3Xy z#d3A(0qGWy31?Q<6V*pP0OQ%>_Jn>mpVwBIIl3Ovi0g2hdN^d89o95wb09ohkI?%x zqFyqFcvI?4oR;yq8&KRn?CQ9(etAx6@ny)Mu;cY=!DZ#$hDK=JsDoVRB~>JASu=jn zN4}x2HI&shLOcEutU{Ez(qB`Vmp1GZmr$85JqI7$(Qiv=Jn|s9|4?LSqj2hj_`|b) zWf7%Lqi;i@e)whmvnsle#(}mr?DE??f+H+8xtA4J%p58-$Znrv_GAiQ$xXh ztBsTTdZ8;DW%7VU;ojC3xjj*0U1bWE&}x7Es;S8u1%K*Si{{%4c3+owa;5|=4<8YH zNn$jxF({C`q1I0FK9$=9_|FTD?w}v8w*z_Sg2n)2F*9|b#u5NF{1V1Y8UE~|snp9$n_(W;w=y~{ZbXv+rWm&m`bZps|ji;>CeVXLX_3aN@r*D6- z;q@1G;Z9SZiQOt4^@}4G zVtEX0q!W;`h`#lmdYpPMjEzB2b@waLy50a=vgG?lmBQE2hYCwd@224l#0nnYSe}3t zm~CIlC*KYcPX%IXM{?U2Qg7(Rw%NOQG&%EZw*fCrLlZ$;vC6H&U_e@e_w!CxSLo zk3Bj2{c{m*w{_e;lqfD6YnF~FI&$$6MtMstqdt6a_8(n3K%}AGS=}?t?7b503T(c8rL+(JF^+- z((RU9_Q6}z_Tv5GD|Wg2+0p4N!}7Y}3z;^Hi)Qa9+0V=fMts71DNJ?Af>W(R;Tq*l z5vpwYJ5$OTd&vmf%o`f6?yf^yvCaW-Uky@nk|U&)p-Ao>)~~*@?Ze55Xd*h#p%%%M zia&v@n0v~bxVF(E+f#PdER2%dSfXb4{tHHX9Vvj*e#PiOsYqJR>9+Kzd(zP^5uT}(m*-<{`S+JbsHajgx9vx$ciJr4 zt&)`4DRjHbJWN+nO=3Y!yu5nA>`((`cm2a{e12o@o{Fu*ZQ4Wp%Te#8<}=B;$*j}{ z)k^j{ob>L6VXVon;2c7uI#^1i^-_B6=&k4Z()%fz3p8m!;p9O|uL_@&A88ZFE-H%# zHPYnu%BKd~(;~zUPsy8&Z!`(jWNWo^+a_7djnzdGaFAqu*u3LBl86|_KY5PNg6E9m z`sv$em_47+6jNz#zAtnd4Gr~pIY-8AJlt=W6(?EObN%+UjS_Mj!56`X4>B{(Rk*iY zIwIP?X@#k`s9LLPE?zRQO_5^Hcn4h2MC-ci>vKMeUs6-a$mZU|dA-H7{ADEZzM zh5Nb@Nvw}D`gxO#S-qK&m`$lm759uurLflVZFEysxLJvPQY&7Yb6JkHiG_&I$#Ldh zj7YysuEPY?+{+BO(?`P;^Oij=%;*+vE#Aj?csDJm#dr6#cy-5(P7!WQ9=}G#1p%bzrfp6K$nhm%>^ z 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 RaYw*MPut*l&QaTI{{gWkXy^a{ literal 0 HcmV?d00001 diff --git a/blog/docs/articles/images/panic.png b/blog/docs/articles/images/panic.png new file mode 100644 index 0000000000000000000000000000000000000000..9f871a270ca15c2e847248957a7cb0d8b4761a5b GIT binary patch literal 44856 zcmeFZcTkht`UWaZ1OyZdA|)!)qzckQQ3OOfNJkJ6VxdSUQ~?!{Cem9_x^#&&=^(vC zI-x2MB3%-Cy(_rgd%Hd7{LVjj=FXin!|Wj&v%dAMw?EJOt^f@+MQX~kl!p!-qE@lY*#I9S3T^yV0cog&|=$A?%GYdp|IBxx@qp6W!UYF z_7V3{2kyl(m}Td-5LS49$IAnYk6nkF3QgiGl2GkRN1k0f|Cp7C?%Z!bVjMoCtwQ-U z|Kd*@F2oTqlk*p4iU0ZY9YV^9s!%4AdjKc6p4Y$y8!$3%V}e^TkUrzNw>!b3tJM&bW>&>@OX zL`1C)Oi$ajFaCB6FG3Ds#3j6}RDXNdW8~mn?T!hmhyC`l=OlgCS^UddSc_;lGk&_{A$YRs7rhmZc&QAnB?O5FPGqa@T;0U zG2Pf8$B(p$0qZiOPm1z8eCe!go`mB@N_UTp=znc}fe|lXaBLG5M~5)0d#9{4uzlWJCf6ueXmBtQT8H-23uhSzQgw0%HSkyZu{Q11^;z&WZd|oq z?h}={JLZr-xh_MK(w;_t_j=N4PIt7tf+-i*d1(0#Z;tWq<+TNw7YX9wkL!!{-nh>_ zFWu>WJ=5gAA5I-3;Z5c>>T;+7#qZl6+TY;+sJeEK#QQn#uu1W(C$xH2%6!v(aYWos zxo_@s_Go=$`&OBVaJh`dBBjR`rbNtRN{sS!Gb}+le~p$gsI||ErQZ?L!}=J5Nh?^v z?3*>rK_&;rX=<>m6Rm=2pL3n$j9peO8uwt2)<;9jFFST4UA-Gl`sobyr>|c$S6C~H zB?4rERp;wZ6bp4*YQkJ~N&z4Gdk2;mk z?oe^-Z(p;*sQ)fMPWMY(_JyBB+nP(n6$7ek^ynKAb0BJv1 zxbR_arJ<}|;6W$V#@hDn=5R?47F*Y7yH3`0zB=q&wW#IZT;Dq%#KK+p0G3s%7Y(_D}ewMv&OtMHHAaKtY46m z%gu9H|0GugMACUl-cQ%hPC0V!bD0In1_=?g=$noedh0|dx0b+dMC29evO8=N(wY#L zac5R98P_u@8N64MIgaypK!}nC9QudKX%IfvN4I2Y+*IeY;BjkF+(K_MQJiqaTn=`*g+9J3Z|UBo)I<|Y zMg5>6COt&lTZ{izwj;G$s0XE~&CYR1)fMW1fb^&2eq5QGcl0J{56@P*tTu(5mTH__ zJ1hFex@Y@1Wu0CY+zN575ccXD4qQHew z@PuMWVogu@_Bj|0WDn{FRYCOR^|YSK`}D;|)lM_uZp;;!cvRI6%cY2NrrU;6FJ5Bu z1@>x^FM8KbNoTs%_i1>qWUhZYcarB7JxTeM2Dm)somKa_@4XXxm(3naju@3^SCZ+;i}c$+s;;K2>|N$>52b-C~4zR#Oet#3v& zcIv<6*Ojs0Sx^h76K)&X@G+d(wm@LoIZ=!vwsJk4<^tx9dgjG~)^jqJ(qOAcX<^?u zCL2?lgHP2>V#B1{q^$Rp^(!Wrtz2EC_khsimzJKEKhn7@ z%@SF>u!RvFS$Fj|KV6AoUB5G-&3~swd1)dgvPZM@j zRdR_Gg-BeCV2-()>9|+*iBQKg0q^Q1zjhjNC$73xS8CGUs(fp#PhGvYM&5gLN5_Is zWaw5_&tcWsaYU7sQ9%5bpS*(E$VUg-vmcnOj;vevsW`_DSFSWR?Q@}K2VJDPhmWDj z7e9(uPD6_KgFN64lXVl=#8qgV3nR>!-j+Z96~c#Zau~8`)+-M4Q1`$!l-wV1p**cN zN6wc0(5QS*^24Gq1xjtfA4DZOUU#*cyrlK7i54e%qVHy-mn6@wf08Q7x^rhBeP%${ zP+@=V+=Fr3tn(iqEJ0y=cl3vxBy40EM_gdSDcnwZv_&j0r-Nrx_rnx#FP*ZnjrF>n zy8C{r52om!t95@ECfIwqw;HSPi^MN}rzO&BahT4x&hELToXa?n{VXq+MKG#2YvD_h zVsNZl(M8>k*|gNuGlE%B2H6n;T}0xk~XcR=!zfT#DIfoY}TcS&0-&Y4(=5 zOtFYrKVE;QyS#M2^I_>~I%T7OPp_3_BQKIPdy>y>**Y`SY}fAli_45GDoV9sDI9g3 z9Fn-4r|VrItnb}XUX$E&qN5r#r}8U_m9VZEV!54+ix2(EAL>d^X3spFUZ1lqIqUsN z!!uh(V#H3F&3vY6=y0&<6Mm7sCoV}z_ivQUW;n0DY@D}l%$jCeas9=~r@$q}CtV*&4ojbOC)7lUMpF z=Df#bB`SD5S*Q)qjS3MQ6IL6JfO601SKdol&KGROuVm<*UE=Uw?Pr?mj1+1c2!4$f zjE?#=^_IDNm=iv>vfH^bnYn*n717s@e{NgyRwq9I)^4A@yXf^H|8jO-)XQwl_(RLh zw9WeZSxw~#T4rgRW;}MTzgjsJMqI|JJ{CzBkXyZ#g87PMU3n!P}P$NG2r1(yh;Gd%r(N z)Y8m>9V0NduOn1Bs~;;`)Vuw0h&OosX`g!ogXn6=>Z7H+XIp;HhI(h8mPl{Z>3_`K z`=*uRMGx)&LgV;Q6Y^j;lWmkmeM4~lj=&4wP5fCp1Uo7=KNq>&kp<1R*hPyQ^qlVFF_$U;n+-d(uWxdJ};X0BDfsrH>GI=Yhj!@rz;RKX zOR(nB*LPQ0?5AU4eIjfp1*Z%u_eU}p1mu{q^~%$9U{6iAap z$LfrfJJ5^mbU9HkvRyvt9DWc_C(h=$&yM2O%ddSEfJ#`d6)3u8QfZX1R$CAxoQ0k* zk=ddP$MPs94rkrDmvkB?MW!>ESb`A8=Zwwh7QO2ueYkBiXX97Cm9_n@T3wDeUk@9* zMk$LaA5OL`qP#zzGse)ge35-(f(k`{9>u(+-jJ8%T|aL(ifWy#qk4(JQ++Y0%qxTZ zQf!w7$d0r)#HC6J=anxDKPY-<@rl~-sIQypMk1Eu>{0{bk@NR)OGKaGFkQkA)=T|`1I+1Svx}LYP zRb~R~#^Ac9uNMd2DGjbx;<28MLDT3et=zH1J=an8Th;G92I)*!!+47l40f-?Y#oWG z>rtE?wegrSP+DAd`A}z0JNm#wfXA8<`jw$#XF5)3N<24lNWJ4?wnZ<)c#jTp_92(k zj27EbxUO=Fs14e#kvzZG9sBUKVaFQ6`VrdPcRA87(tD^Zi(zn>arH{n0?b&;bbWcR zk^EB#i=>ZdHKgt}14(!JE$B`QjsOT^xQ zA^ISJmi%sguDs_a2YUO;zbPq6^P!!4v=P{AfAi9JD11u8VXNn}4XNGFEXC0*bRAU; z-M8?t*z&zAU$E0h8|0$XN1ol=^tN}PnAM;-_mc*1_#S*|sj<*vwMWL*^LyH|gO)?% zy1+%em60=0x_U``tWHez3iZm&;GpaHMon$~8A)>nnmssaJ|C0c4%{IFbtya6WVL9n zCu28eb^g-)<^rub!}~b6Zam#PxUz{5sp)Fu{5qp4r|I6TzpLF?0n&@waCd4TG1xuX z7_Hp3xV%kGp^X!sc}E|V*7G3Qu-uF`g2$wHLtpoOGTB>82XD#m9F{?|cRdmo8V004 zEmx~C?CW`Y8hV~L>_e0#&f*spx6f>IF6%C3X1lZxcvdzvtGD2%Aiy36 zFm4!))p#Yn96QvU$E>VlEE14r4rF`Q}R`t!YzBJp>*lu zwCkp~B`b$TMZBsmS!*xJa39y(g=$rc*ke@cGE8kmq({>C-n^BTrVoIwGYZi@>bI^- zu#?g#)$nqyL?FGaCAHvt_!nD4YqI7KJVT4AgOl)Ec376lP+m+v&u)I(3NIX2aN-xd z>2nY;4P+~J5+%yun?Z_8p1{6cm|SOs__!qxi)CUy-z?~rYzu2e&Kglf8eZ6`&0t&} zcvl^4Fig`iyE_L$y&fVmCp#(2ZFw~`h(T{vI)97d0$UA3^`+b~tZrR}?f&^mY-;Zk zG<*GB^|oE~GEw#i)!mA)Es{EZcW*^4EgEA7Oq#;N{+ecXqRc|WhYY=m_@!b-(?Pyl z0!hp71=(sE0%NNia#Hn`^4zL*Jx>{S)MdK_^eu^G^WVu%@}J$fE)|qic9g$*lVWzv z?!@zTw}~LcQ7f@L=k;ttwp-C6SzO?nu z6~n|~n=750)zSs&XonEYFYa5mm(-XQr5S#Q{2!15;p1Z(0wj6%U;O2NkmLb8`9DbV zr&a$ClKeAO{r?Cg`9GNdhu`{tiMxm@mUf)KLWxzrcFi|!v`~oZ2$OhNP(_)?cegVk zWMaGv6C3Xi*}Kxcil{e#P(9D%Mx3EW9!5ubUR}+0CGkDEGQ|c7ml#~)1u@(sYOSp^ znd225aR`%4aNTBj@=}nLzS@^BT|Jyy=O~z{^+QBvX~cB{&z_fTCI+O+>2u;mR2Vc@ zcNoND28tK?~nxS)yJqAJ|^wewU{GE}j%{oQG%Y;k#sDxm9~*Y>DP zJs3@GhhECiFxQ?4UV00K`NR%8ezhZT zO%K)1ufSbb73$+~OhlE)7JS!4W8K@xM`zN$2-KwQtnhTM*)bLgv#_Twx+1}isp zLXnEGG>gcTGur1^ihiA6&)?SP-G;Fkv=PG{uJ=E2_dhs}tB=vnqy@&s*^A0PCa&Ty z)}=+rCmLQ7lTm%+@8(b^s$LX=P3M&!{nqmgd8OM%l5aRFs##|BF}irfs?^GeAY(59 z6&vY~p?y=YEi4!)G!U$%EI>{*_Gp5fl1v#sZNF=KDQi8qv-c9YeuW4UkjWR zkDP#!265-A%#f}uv|=*A6IziUt^++dv6%t1XFdY_itqBwVUOnF23p`s-D`XKNcsA_ z;<;m2q8HiO?{vRfE3Is#KEAfHRE~E+@HRYn00YmB&OMr5jo)eZW9hAu_lA!Z3q7S! z*Fx}Ce&$^a!dYF`pemniM?MqaU3^LS6j+`DH9Fc`x9AATHhAHC8-3%65K5#j_`{=C zhty9A!=~%xxWZ`PjV~u0(9YrHQkfV*c-4G2>B>@LEDXE&B8NEummsY6elQTnL^W$5 z$&L|!lyJ9*9wV+hwZB~oPG@iXXqi7L$nGh)Qu}4$r%x)RYdLzK@ohX2$Fo3_3{_U1N^<*Y6AC&CK&e9)&4tVE85k&lm97quU<@?Q*hFFd zp_w{z`xe8J&i(>6aa^c0ex;g2t;kZw7dRfi*DJn1*8p}UNw6!A5iMr$)z@GRvr<)r z9_jMejOoG!MF{ST2z@g?FX`GDp}q*LvNGG9JL;WK<#InxR5#t%cI3$Qy>~%i5w=cX zrTzpf6$RTm9l=i62wylBYjSiV1*L^4drMxTGvGZ9A3&WCioM&4XG^0K0GnAnoD2;N zd@6*pXI084EOe3JAqd;E)3yM+d7yRnwx^o!aK^KBq(^5|;Ze@y znus*EYv3%8U<~|$%PG`OhPHJ!@%CvV$k>#CWS$RC!Qsas`NGlGqSjNjxqPp%N$XDq z>|cxHRp3$ZB@KkdbaK`NdHs}Sy~Xf>$Lb`UETrU?A~=hSf1E`_o1cC-JBrr*@grfv zJ~oA)9zUT9ugbhm{Co}b`>O!AnMj8*aF(`t7lPyARBA=O5in*)1)3b02uF3qVw)gq zUrviQ*y%XfTMRI(L^-Jzcx7r1D>}&_P_;OzzAy{_)V&tufbYJ!6^%9 zac?`B9;t7P#~By85S5*#PC43epk?FvgH~2bf~EJC%;*p)g<^>iOkdU=HM*foDq2VMtza& zWJV-#`-f2kaS+s$AXY*o`MX#TgRP!<7rDD8Dc~BEgyRw80(*V@A5B9Ak#zg?C)fia zlqxjSM1DUOyG#D$YKkhH&zVKQ5*&Hj=+y|=gMb}vT0*@05deQb{pc3Fkg}itc3PR$ zb^tre$UHH8Z}*UZfGQ%8*!-~e&s9L|WXGukGeC1K`3NBRQlNotzz7K* z;=q?D{D_*);6>1zrD+mC121x+eCr;^Lit_!UZAQ4qpiy=rZ+?7WcQDQCAf%#GN6Iw zKAfnD3t+Rs7b^)a`xRj=X~J2Qz5}1%Tsc_cJ+#E5-7o&qT(#Bqmn7Nhui*Q9M^(pHgG>TpWTcCvyxzU0x5Z8P<4wS&<7{J- zjK=3siaujQmvW+wdb%BHG`0Ed@*C_OZ3NX6 zIeX~Tf9FlW@zmeQiibt;ZwjfV zHa95VY|CmR@Y6);!EgVoH7syYnAx$po~g1j^2mG;TsA+M%9ap;6L+Boo+O?|<_xj}ss${t?)}6Pqd`iTcj2==sT< zA>s8muc<5%zzr@M*Mv|0qIhqibFV&KoW>w{osqM{3EJsD=t@Bs;=6Q6TXHR}E zOA^N?aB~QlLowok-tfCpeLvpNKN_@2$hM3aLrmW9Fq#skh3U8{POV_kXig0>i?sn16zagKT$PO zfiI2>1TDXBlx(m$Og zFtQAg2KLKQ+cTv{anBj*&Rm;6OQ8+=RY>+Y% z%E^D36@ah;A4)h>wO#u`rKAs7FX{`f5`$G*e~iMwU75qjOku zLvT!7mlu2F+e@+A({Z1f7e^@yfcndoOZmT5Y*@^8Gn0XEO$(R-^?d z@6rn)R1|AbjvV2W^~?*L6_u{CM4xAlB?YPTT}kkd7G5B|4z)V;8;DnCEYeN|;YM;3 z=?9E4A=R-Z3ttrl?we3Mq;GslgGzcn+L>GCL?urg;r^pq9qTKt(JV49-G zF$TB5FJ*Qb2;r9JAb$IGgQ_i_FIyROMuSp?_#i8ehj((KMu*)s7jL@o3@?6e3!SIeVlNu zf9l1u0SzeFY*f6&f6^1+ET;^Jb_zO-ix)1z7blx$dMx#YI5u7Z2RO?Pij$YDIcI*T z$}fpM{Qz#KZHxr;+({QNj`&S9P@03T#Y~MwoKWGeT@(Kqai_~6Op-oK()?~8te>9M z$t&79`vz(h(pyO5I@vpJ*)G($`HDN*A`Hn&1&~4BC-=4KBVh40hM##c zXyO+l&b749(MLpE^PC{r^6)LI#bZ9DQP}iE#mT6wfw%IL?%!)+i~`P$S{3-6iyMNw zV;#F4hu>%i9xlcA-_*D;`T>6?$6)oMJ?6t2nQ|*qPR~<>CS{vMJO#Qw|E)nsuhbmv zjP>$LkgzzsH6;eI*G3@ioQ4OU;;bOU_ubQ>iprm>)*@irgN9u~7&PU}wUxKq`W-Bn z=KCHJ+i|1(X&`cm?3K%#jL5I6F)}np)eYy4e#4!)q*p4K=)ifhuBgc9Orde6tn}o# z9%z$^LNUBl=KEOF4dp~dO?>zu1Qapc^6>XbX9sj~{8X8;jEq`3=nZ)~OUmEbDO@XkRog-7zCl9!lW z*53+g=Hi6!>z7#Slk&Q&)Z8u^eW9@4_i13zVY$DXqVcGc#;#sxvg+sx8E#6} zSCXBKH~B(J{3OS2b7BvbdNSgx3WE7l@h$jbSFK;6#R@dET~995hiJ#Cd#5B^5gsNQ z8Z`GzCx%pwBjX&~$!mER@w5>mg=*)BD2~*A+^@PPZGSGtSG$F)Il3)=HMul{m9)2D zV#BnB^VPsmpLNJd2syd92b6&fk9i`w$32@@1K^&HRJVzwy60b5;eB>*xyB`;zV_V;NF|`d}Ky!1q+V(>4e8KJbmkPN#H+xrTeVy&Xy7`+(v|fuLX)IYK8503y6~-G8>KzmK+-am0 z-?&t4{&|B8H1-%vRELnHzXc5&WC8EhgxQOnZxHnpB%KynklOD>{BYx zG(^2EG-Qu1P6I%_%6ghCzS)@FSjYAWiBqn(7P~IWK$%rOmY?0AhM| zu2bvqK{`wb9VwS43$6d=-hd8xY<#mL^l(2iO?sA~G;Mlk_R5Uk6RPalTscwWQVc(qh8I!(pRo-X5Tz$e7>4p>uPz^G@^3; zg7V~BsL{)w?oI#*f&Mk=+ZCk~g22C_YQ31GEES~SskCG`qqCBdfv*9YfAfimNCtG6 z;3K$Dn#3Q<#4%{g8cjz6!1q!crcF-q={lm%U3X5@x&doyTN{$JHu3$q!>GkuU$`B* zfz7Um8ly4uv9P#0u*hZq>I$P2{kZKm1HGxMH0UFGmfdP>)oZW3%NHY(eBx46H8I4y zilQgUivqN+i+uWMkRs98RG%}(iPAk$lqUnsc`}2%z%yDLKd%c%T&eT-CCh0`kdjvi z^D9zvqdqYPUs$cE+V`Iel<~Qzkk7hrD-c<7?= zr%+bKjzRX2?{7g3)~gB<J9@^*Lyj(y)l5@66;3F%CoKriY>kG5;vE7UM z#iQ<-5dYAafsUtU(kJ;YuAhC`)CzJG?F{goKZ5bR6)^3V^tRdVBVw0O<_HfOsbQ(0 zREHZ5)B3&9c^oK%5TD!ejq-QFE-%mR$+C#@K4C8Juo&L`=w?@@JXMAgklBM;nTSsM zZ)$*a>tDtu1@KN*A9MKFaS06W0x`a-<4ZMT<1`ahlGzOVNVj}3m%P+c6+-so4CG{< zK~~W73^(FZ3i02&k{@p;=gDcPzbJe%lu!($tAWsYfZ7v^r#~R`24jTx5OREjB9nxi zR<1+9cJu!EUh;~w#SAaYCf(1P7KfAsgVpW8>Snl+j=(m4r>4RMulilF7$Q?VO{M+X&=Z`@;0gCZ4;2)U~0sbMN#vuO)EQ9Lh4iiDDp`)(*WyT%TGq`zL zQakO@HU0gyic)1lIb%;ao^;ZJIhZzr+;Kg5g>5kg&LYqqN@y@jGW#hnsH3_Jotz9*0$-{t2a25_h! zqV)sV$K;W00w&72cPnzlgP=cbZLNZIk5?WIGtfdkaMyNL=Da|2I1$T|;9>407N1(b+6VXI*U45*4AdeiOC8+FA)y?Vurquz`XCHJ2sD2Y$-0Ze1086-5J z2&S4vQ&6dpxVzfDQ=WokW?;>VjcqNJTt8?|K)Je# zSBipKSrt0h)Z>{GwJL-`yuWx1X))XaO!|WxbzE=0b;3S*l1&ZwlE+IeHk6{j<>~~k z1i^)RUvX-0cMvF;q8jBFtkiTn{td#!c!CbjA}I32bGrk7whI+V*T98(y?CJ&nR=z} z5doAtuyGxLasG|>_@sj9lSIi_?K8Al(q10(wE2AZ*x7;X;DvH;`2c+2UC;w*7k%;% zb-vAwnj{`vkLN14hF7o%FoC1H3a|Ko#VPL!{120 zdjyiNv2CUjIPfdWIS_T=oBL4_?v1a(Q_Ch2bC>&!9KJ4JoOs(W7mOJOEt6zEcaB9a z+4u)9b%wG<$1ug?m`=XXw0!1es@(kOZRY~7X3##L4WllcS5O9%8QA| z3@i>bqf8WoRvHRp2D}Udf5v(`^q*=X1lN5%^5~QH#`emC6|41v^WEh8(3cXbZsw2I zEnUCl#hbUVu{Whdn@HWGXtECKyZL^GRi4`sXXioX%SiB00B7Y9olr9EgcYL~gh#P>auCY`)*63^PU%2AGtPpy+US zZNy)^teb5svgZ@h3kr_OKt_9!L76zD72h2_-i9la9{RGzvosgQ%!RTK?*)Qit~a!C z6CKR0HsxJcdyym9>Ts_jVI=-XJAyo6@gBnB?1+|6~)1y{t_<3`k2Wn^R1GQ z@>K8@f>A;586Vo#!oXc+_-~$e@xK?6c)F%@G#$D=H{F2wv;H+}0Jzi-bs)gVB7pb1 z*JI)Ifb^~i-WXI$y_G3(%i*_X_r1-R#jMc9jDdO;ejpE+NTzG}%eT@pFxFJ$^fXL z$8KV7a2i@k+#^#nUq~8m@x0b-u2YI&P^V?Y&qW#EwYO?@P$_`TyaA37m@XlqlhQ$K zJ1$SWY~w^3e0;+^6o8vQ_RWgvIWB?vK8^5Of<4C*?D<3jNe7{bdGf-);0eJ`^&h_d z{;{Eqv0;`NAsJ^AI{c;L0$JE=x@(c{!(X#YrVSsvxj6x-AwC*7j9T-ZjRlwRr5Af9 z5v4WEuf@N%94cP80zH57RC6>T&~>%`3ZQtsj&zc#{)%Yo&&WW18V)7zk+us zU|d%h)R%{nFUJVFkb#*yKl0gIO;Ne!?>C!9U9G=<)3*<3dC!HqT#HEao86NIa0Dy) zhQ`hgPh#;#B75hNJ98nR{+p6V3r4_{-fAM)(vF)@{d*hFv5YbGa-d!;N1jznln8z= z6b+hMo!@M1%6~5RG>_nRR~lghKs#d@c-gBdyMx{}Q*)Q#2!@*e1)w|!6}bk2ZB!mS z>;a%B(vO>fu;Q!*9Li4|r$GgwSGgLn943%7;1`)a@TJz>*6b_;zz#4bG(Q9u4kPly%kV!)y ze}GhHbV5VVeybP@$A0<7`i#eGtCHg;*lm%jN(CoIuH$XsfF_5#2Wf|5^` zO5%k60EK?~0cv2LS2$50?-3xN2vBLE9Sv@)fTnTm&SXfE-Ta2qhb5U)$R8Fjw78<*m@ZXGi6x`HV)lH|`Tdx>MBkSSkJgAS{T zZSMlKdJT;pece{Pz|M4g-vbLK2CtIQ8?YP7Qnp?a`~3pU;V6exky5Ilr2u$PE{wagH5^Y*Bs zT{&Re#+b1+FvWKxqT)@ars}kJNYg9eu(W~08u5M#@n!;)L#^~lAzR6X5`ZP91=9~i z0opfJ19-&lBl*vMDvE**Xk++O<9w0JE1N% z3k^;Kpy%T&Y`rQ1R!#w{_HK1JI8>aK=+|#s8BoP0RA)bMg!A|6t8&5B1;rs2y;7Qp z6ovanD&M`6rSc<6QEqesaUlukg5P`Llbts^~psx-d zX90?5_%x$!)ciUqF@Y1%W5c2&i>JLYbL0*2mHx2LaA+j0)-mNLh z#Mqnn{}vK}VBgI75V(-&7Kib#UQ9Q`v2UeM^72GGU5xB7JXX_as|sKI+#UEb0(;{- zx{4ozcK(Ex237g+H!Is4@M31WTjZe4=ozZN5%l{l7vgUb8a1L1&`+CiteF>+gcYK9 z1FUHm07aP`t9gC}Zu3>XVGi(>Gkl=s<0fmxX`uWEtx&(PG=Z^Dh>RT_+#Y-FZnF4b z#}3NIH=)k~_~6J0{PxVA?4nS6sLX9nl)BW3nt^!0Z#t{HYQ7`Jpf}4WM-)@R(gY4H z_&W&Rh2cPv|0;=nVw&+uiXoF7>jP$O{Yj4js*-}Z@C-LO1h5LkkWLuC?P944p->{! zk!Cn(yZ?n}Q-vX^h2p5g1$*(g;5Lg_)8czklyVOpHhRYVk++EKCA z#RH_`eHpN1#;$@#R1{)-C{yop>V<99%U81^6)|;ng<}*}&WE%#VS$A@qo;!#kxV z%Z;=U2mX+7_Xiqn2>g7a)nJJe;aSmR8)s6IJZPvF^UNyn1eo{fweyqpX7R=Ip9sZO zSf$YyfIb+wM8&NTvf~IKHH6=;m|OdlkXxN)M$TvFz(@IF zeK&Tv!GoZ)SBn_AP+{MZ?xwBC(Wl698I1V${Jf14yg2@`(5!{b!^FvN#}?{xkEkd=AwS@2XKr z3Hur9pAHZjkp2m`5IPj8KAr}wdEMjpPy!aZ=W*~Vbrx4Www{UOM|O_WX6dCt73)xo zo?IyB6P;fBfPg|G%h@n!o4T%56yXvYG&&Av#c_L06@JpAgXc*RbzEzs2GTi1N+C0NOZWJhc{dV31qMRnB!SH^`3m6@;Q z?c@AeCI6c=yA3aDUpUrMCMp?kdtznL1X`^)~z+gBr z|ATCK6SCWh5C4L9s|yha6KjK&SW$4R$k}qQG5@#Whz19t!xt23lG2L)f|P|?@gFWr zPZcfMYDL-a=XXZ&&`wO=f_vqJkqg@bjKTY|1I|0+Z;AUKsjU}CZKv839ugQAE;Xo{ zBk6=QdhKm}lSYP;t;b%Ym8(=b&j4tEB>4z^4yN#rrWj_Mx$q?P)27`-K$sWy@2kR# zPubo|1S!Sh(0FLITHKM5izrm(nNNyIu|lX&k(DpSvk}-#KF2^tZ3OS(hh{DjFe)>{ zky9A--8ZLQ6o25{pg2SxBP%ZqlWoU{v#~uT@u!*e#ZwNu#=)E`|36ZXQg!=C(C#ot1J2A`6cNO{EC2hYPTtabHs5jB*iflH!({e}D z0vK+m)a7UJzbj8Q@wuxfs*i!vXTpj>^^s(^RQy--6Lz?WmV5X2Pfm4O@FwZ6uFcMp z=Iqw(plV3gpK9c0C4M}fjqF`7RXFRBXTe>=Bu)Ezx7Mnt<00#4(jx;Yb>?+*5qoWO zk#+?>pBx?C)I<9M(ZX7=ac)Z-)U{4%(EE$Jqen6e%YsT?w(g-9)(J<_ox- zU>9q50qxUP%=#8HU-glnY_=Pf#E0r>+Iq!Ng4~&x7%Ggs>QT^`0QZ`@O8amev}Kg* z!!k_yhC6A5VMBnv5lTQhoILo5C46+qVU>Cf7`z*(=(zLoSQhrgxxeiKA)LSO~vU*LJmH9h7~+jINKjb0c7L z`Fr#0H~xxt3A=k-C^QUv9r*SW5lEM#AQ+$}9~Ilj5l}EtDs4wx zG9x5&;|Q2!Ajij0ISi%V+tn1O<$m(HH&t1?fNA{x7xAO{;W1GV94DRtbvj$`CfwvA zv#3yBrTu-{VUl{e#2&OAEA0PxdJHST#=iDDFsD^L8?rMPCu9v zfVDBplpAS-01dVbC}NBKc67HA@#S!Au_yaMUFSZmkonkM*?fAlWSo{Ed6t&+GR%W^ zSUht*b~_jm2riQe3gm}EQnrig2v<#nxC5%Ev3r?tbBAR;c}QX?n6K=5HB-e5x$HI3 zIvb3$64spC>N&s_VL|xw(aK|Rld4NE_C4=)LS>9mev&reC0zOx$4_9y-JUzIg8VPg zYGqdokpjC9qm6(`&L|9&0J(qbMC2x304U$yYKhEe^FbcM)GUB#Cq3`39)C|D0b1%M zQu)K2DW5(C3=doC57n~Ei<+-PkA_0_hri}L<36^rFJ+rSrTX*+4v}umeHBbTKT8QV4SmGrV zp&g)y4Pt1#{P5V42WTyG!)hSX*g$7sQ*cuWhv zEK5&@qA$70wc>m4F=aK43^hVp&<%>Tx6zOmukfY$0O=_K?;+#u1&pY#E8aUDI#3NB zv;-;@%EJ8xDc6fwXf?P?1(y1Smh}5fbo_GDTUJ-Q#e%<>AyDvuCKu_l9M*U9k)nRC zlb||@{m6ijxIB#c_I>Fv4sRQv{1vQ+_ zKu@S_&D3`9MTiGq7*=om=)~$3c-64q_UxZ9(cf~%U(y*tI`Aq&&xODU2FBzRkm>O1 zch+N9HalbI{RX%R1#IP(?y>x8>rN=Qo!1u|^@|;4`5mCSN`xdN*}c`_<8mm!K_5#zyj4jPyqMi`UF%@qlwjZWQ}CCxCedQ) zhK0FNHrct0w*xXk``eEurQ^Csf1+`q`Rpfi6|DeF8+w0-m~gob@Y59ZQDU@JDswlI z&JIW|YJp5X*cfE;!;4;|9eo`!k`3gc%2S)cF52H)A8I4|P`BPCWlymC1B^xObS(Fu z91rMb{>kG4hR+;f{E|t$;)co%u}5d6hD2WeNx6)qmqWN7;GlhA*{bX`uk@R{#*ssd zWvs`kfdc*k@BK|~zf!Dvc_x13OO=?Qi+d8AqEXdrM21(YIR4u8oQ>DhYwY82ZOXQ{a&$&=8WHw$PH>mTiP6TpyTka2KjCxGq%`ivPsVL3iYZfDxDIs$UH(5%Ekf)3*$4pq zX*y{EUzGNvGwifBoN(nDVJ6?_gZe&#E%aezUhR%jwdi~MFJ6cP{s z^QIr_=puMT&}>(xqvtJQEZTyXgrweS$WDij>u?{ZhJe1kAO4k^Fed_-)qmiK7z1YL zk8AT(E|37oXQb^aP!0vSm)l48#quDW2i7{^{w+XO{6J&~unEXS`3Nn=9E5i#P^Av= zJZEpkiYvBaH;pxVGua4m9`G{vU=L*EvkpVkk?<#sL!`nR#U{jkGq$b z!+n;*JAPzck<9fLNFU8^;=-g}InVq#H0AUht z;S>RTI{<9)zQ7?zuX7oxhpa!ww-t|y;CH@qaOrP>IUEn8)$7oqSN~c3MG!?+Rt=?*2*Y%oo_p`G>3hPr9gA6`UQajdE8DHjLUUV zUK?SX8}%ZcR{N*r1BaXrV0Jdb=vAsCOLhx;+bk$PYh^-{4F=v5`l$W@pE_ypiMHXJ z9%&cc166g&E#*&>f8&<^9A6$m(#i8JG+&woH?0s@AM#LyLKv~qjmKLx&@pei&+weJ zB#tKLPsd)M$?H4i@9aaolb!2X260{2F272+^z_H*ataXcG18&54ygN+GVKu|eG{Yz zS)ewitWh=Ket(P*D$I0rtqAn*G>HrWs=SNtL%tLSEnTd;q5?1WO_uWf2GvFSA8{}8 zdoqcG&Y^Yo-B>u(_JSL@$G{A6n8`B~3) z?VPy7n>LGKrA8EmUAVj~Fs*FNX5dL4W6M^DBE}P46JT~Vl|a4x3;MDXjO*PpFt7x> zM_zg}9s@7M;j}=#(#ZhEM7U6Nw%Xu`TD;!K&9);^s@ST_Ec4VEA(0rpL-;C%OKyEz0 z{=qBZKN)#+*pn2(B#u(tAKaDRc28n@c^i z8CT$H#Fna$QH2ZqqN#VrE@&gT^;E7KwIVa)0S|sDq~PvGtw0(2d*T6^1oE68QU_tD zQ(qPU7G37v4EtH&eoff!W|nIJ0Tg}!G$~{6u*AAB4B@~|By{^C%GCNs?Fh&prH@<3 zI{+H*pA;2=T?+;(ioR!%$O*S(+6R{nv{jx3PPg0uF<`4woA7M9-64&V;{N(my+!$x z{)A4k=f8G}{c!i1h-W4wz-`xNt}m-!WVPjkR3J#p#M`75Vwm6CBT#GaZ=CDXurlaZoI=WspNC zP}Y-m^Dq^7o~t#n#0O9`{GJAB>-;%HC%#o=E$V}uH0DG(YZRrcgR}BZB>lK13eE~k zjBpHxdNbC|lYvQ7Z?K#eBDd@d@9Z<2)$tpQAHhK3|I^-k$5Y+Ef8a@>BuODNBt%A5 zI97^~os~^yMz&**B0JgZPzaH|_a^I*y=5KQj_mb&9ZL6ocYi;h&!4}?@A2!89`ARj z^FFU}y{_wdUDxxv-Z(OM=ij03VoHH-JJ;u7W<#E?@^W{vmhvnhCh+ZDM)kGK26RgQ z#qP83Ww2r@$9+H)({ApE9vPSpLy&(jFc(0$&G$K9sep3S_fBVd3P3^YACBNp-ovTl z0OBQGxlN#s0T)bu(W(O?QrR2`u6NDu#1=zq(V z|NIFesQ$HYsKS{nEU;mK@a4*{)k3$`ydF*=9Jw1x4_Ati6b!ojpP)`DaN<*qByt}L zT*1;&&YD#j>X+n20dIf`PpS{CW(Q4?`v-kjKDKer?0jOl+L=fFhs$ux75FIv`hb1f zGx9?><(1rO*O0jkQon#e@D~@rV_gQsV;*1d$_5?vw%40kN95BldTk~_*5$&4QC2r* zX2;u<@(BzGtyRh^C6GahzJw};y5UA~DJ1rCHEIig3NtXctb1vn@IXW5=-h~e8or`e zz4R zH$|!*)HxPfNSdZcHouQzi=0QIhlrLM4BCo7nN)A1Rq$HO4(9rec?8nI2?X=guw6`t zQI$Xv(84nx0@P(-rmsl!`T?x{0I}h;dy9&CHaZS{%TqF_MPO4bl7ozH0r6(Fl6iX$ z8R%4-c-*!6!x|rG%8diM;n9ylU9LK5z*T}q&D$UuN3){&F8NF|gPYdR$-t5zgA)a_ zC_zb2(UWm#gpK{jCFUhFx)~ek+*4spYzY_o-kHpDp3Z2=#i=izT(Iit+8)iVd=NBNL1sZrK zKK0RQG?xcr&}Uz71CYngs%%0L;6|X@Iz%F!8uTuJz7gQq&VmZhKeEq2Ce%Jsl2ycZS9P?EX-6=L?3aYM{3SiC*c8nUtwy1g%1N9kmEKJ;=qRjJplgV zi#?44N6rZ4xJZPB`2-s%G#9E@O}bLJz8=RV7s(ZH(|L4}xHXkQU8!#~sqZfp8bQ5w zKh!`AY8rz#dy9{Hgzr7a04Owl4>bpgz9WfoVsW=Ld;Eo$Z{0A_Ufdwm5xM$p?lH*LBdX#ZlMWp z-w3Bm5t(NrbM-vU)K`h`_qB+P71OT(uc&owyvt_w5@S5uHEzr8j<<-n(f5iBd94|5 zyk4IXeBkkjESIDeYi_^4O#m0&**hjL@AbvA_+BLjwzf^nR~n^pi4nGg$rtAOHx|bk zvKJp{iQ?f+v{^kYuC-M>G8M~S6Tkr6n7zS)(XRki`q%DQ4LH+n#^aoARKDwa`DJQ2 z4oLKOK{NE(qO+Hm_Ral55P0djfVkvYbB)n?$JKt_lR4Y`NN8$b0)Qf%%!r~=2 zE5I{I-OB7g4)M1g3HE}1{<^zIRTb-Qfggm+N^y?TDQ;qeWvBIW zw!E!DM}tP(u+|9Q!RaBpLhYRxRU8Y&_!s@=wf#+)WU8EkRZQ(_&xqp-m*irZOxxNB zr(4Bgv_lj`AE%)XZ~40mgGdV~O$raZ-LEz<60tpvr@&BiIFll)8;W2*yHc%B55FuZ zp7_WfZbj^F_cAZGaOq|$yK-Bba{+sGgXHZH!RRmRlLZtL?d_Tg(5YxI_H=kxh(XRy z2pLi5XYQd2Mdqlo>22dtFDaogUp@a616O1(Ze*1u8^4MG&e)j7_MG2}>}N}r>6Ty) zDbKYOQ{Kt~QD!ly3wvVzvsy6R0c0$788Ng^6n4a|FFcn)2W2v@iPR27+e~`lM~MU$mWqeK zA%Eb9*GQ^c2?kI23ZilE&8Mp!f-V)qA#bbD*fifVYsz*PE>Xj|^U&ovfI(|A#kx?` zYPCj1;7JXm{lq=jXVI0vY3>&G~?Moz_oRf=(a}YVhh9XFU={U>qTcDO%G=_Btl`BWzU` zmvf>pnz&azT8zH<#weudv z=&(4=P09zoY(E9fC7N;j40mE&nT11 zF}bbvFB1-Du=WJM)*fSKknuQ=T@VXHk@NIV;v#HY#~~Z4 zX($4|hgbQWIxwEc+i`1&Y;PdmS@Scp_?SYA8fEPxt+wZUGdn#uNN!6dLnQdD=-_f8 zXxr5&N5@_Jq~5aebmp1k`uC%`9BS;ZKi&OtAtkuc^-(BoJt|j|8^zq5Gs7*-bkn*V z98Kx?0?L=ZV3gBEH}AVq!{2orbM^0|!ghg>n3J$e+lUe>EamgoU;~CQHJ3CX&OuQq z$uH|y-i)up@(&<}c7%{%k);Gd;<;bcy#kVEAhc@u-{w5hbKS5n8{^YcCtsh3fWFbn zcdgAyh~E{Bh(ss8Fpi7s%7+k0e4h4$Naty8R}HPNM9wZmZyh=B1D@xgg<@L8trXJ~ zPK&0ZCZplNJaIpo9T*}%VR?YFeMHI11h*vg+*zZ|PoL^Ur4!dDWTxRE_$5~Qo((!a zb-G=l@2_qr8RLW^o;ED?G@^di4vi=!4HD0X>yKM-#PXIImj%i=Gnj@x+>R{|8@+V@ ze7ihM{tUc5T@H2k8g+-&8IT@Rk~J&BXfo7r?&}kn<`NIVU@j!kcSfAbx%3s;*x_h& znZ42s7pkXLFj#quX>QyrAA+^!%grs}7)_up6K}_zf`}x@@jOJKwy_G&7{#Dc*zixs_a)rkDRRibx_$Q(i(brP=XNCK@r=U{<`U%& zuL5g)0|3px5}tsRP0Q)&tzAfpg6suEx@WVxG>1_$$oo*CLUDAFJ07H}Fq<-FWdyBH zD<26dAbBs|Pw&xqhm0MnCmSb6Ew)k4tr_mSsl0`f;Ay18!b~*oD76f9!Q^OA<)fwf z>q}dZro^ri1>p-$as?PIR-Yzqjdf81(zX5m86h)zq9^zth?WaaqN*KXaXi_hb|%<5}Dsz15eK3xLZnXhhcid))oGDc5Ks)vn} zf~bxNc=!S%Jc0=wtqU289(ncgufvL0^bZ=KE;z6NFER4FvxgXn1iuAAp=DWZ)XJ?q zsI)$hg_RowLA0SgNrw3G9G64Ak^ft!1oeHC8^(#^I8LEBj{f$^VBMT{GjQDH7gruI zy&d~S88L?lBc@%G1a2Q%6GNIM(_Bp*dh>; zLiB!^n8ix7-Be~EyA>pH)C1XfaO7Yi@Q%?J(ct;>{y6w4KvQeEV0*B?Log`02g@R3 z`AAs!-XIs3t!kn+>ERun;-h->@U+(9sL!&nxc6bZt#UB=_>x3bcJSmb=V?nLP*51V zd87X6aqp~hIUw$RDzGdK^nKa^QCObddHr($^PZ^c`p*D#{*{;&3AA;@9R@$}492-g zK(e|hEDvRRTJ7PJ_#>+DV1+~LVJO6){cKw-Ag%pYmVYr+$GxuN?ntmf3!hPEzicOf z?6rm1e{-F|`M6>>8aS2Gp)FW6`#7Rwou>wfZ%Q~gD74bUSJ>P6O;x#|m9}I={A2vc zSQ@q~{DbS6B$jYuFcvN{VBAj1iNHn2Pu-_(a@Gj+g*V7(gdKQa;VGqsF{zKFe%}%Z zyh-PTb0?I+=YlY=qZ*1N9vlM}crqWSMi!}7oN(TqdgBJP(gmG}6XaJm+5qa7M73V{ zU6gpL1rhU-d%AU#7wF_z%wr!)#qtLgI(z0Uc%COeDN+J*>F5h0eCOIOerx`z_XCPg zX^5y`Jtqo2pd#7LR$-0Kt7E=e*O=bYN>PbQ$3BYT7ux)RQ3eJYf((Jki;}4t2j#J*L2yBS3l8Z-kO(G@K|L@ohQ^dv#&; z;>GLDII2lFqJi->lLe})PrrP?BAG&1ph9dSX0zDHwGhrH(ReiQ*Nl-9S@8U&0pz~D zh?W!)@J>}wH0_@Wt-R-T!M}|;J}c5`uS2~}qwtIU=q-0F19qIAYk&O$f~v>axhHMGi_?#g0o^V|DD|fDwG(6tvqzWe!o&46p}~MUA5| z!c@(5mFf04viWg}&F`HbDw|H~4S@VLNe!?-KROQ;no+~;md~Ik&Tyl%nBO@?G=DiJ zsCr3OD@|11Bmy|;AZvdvXwj@ZTKr(Ij(_EIi&YMQbtIW!Y0I|U z(5M0I``(R?{Sm;7lOu?V0O1v#WFvun-#I;jH`~dH8tJZHMVZPwD4XRl;`R3BUh^?d z?0pPd8Aaa}ZMEXjsEi^`xhLpdcdHJK{1|>z;at%Jl-c z`26$C4u9wPIM|mCLgo7aUHwOx1Vo%U=X(QgGH8ypg5}QyCKS-!Kd!g7>`ELMiDWPxxUcc<$-&7$y;XW%gT)5_rEYk-|LxrH`xrT zvjFzxck1z?m!*bFUn|o3am85#MosOmAq*sE{%WoX=YJca^EV88M@O2d#_X}rd?zVu z)HC;kaO7tPQcNQl&4k>*BIcpF2m@3JCj}hc=V$m)&7hpLB2PNM{1kAI7^EPmi?%C# zFOlx``$SXhHhHCWA=PR<+-i3HAx+^1Ha{5SfqoD(IObrJg5AXsg|(j~Du3#}`sVdY zfukA1316NWn_nz}pZ$NGy06Zitfwos{_kg>l5MQw9PW-LPkx3^C24oa;~@f4TcJNbb9#U#=C{PjBzvASxFSh zH@D7o=YwNDq6LZ&PkOhZh)k!mDVdbuTU&4P`?j#)8J&ewAGn3MVWVE@K&FoA{jIJ* z`}ZPIKuqd>K!L!5&Xjzns(d!8&OPa$$dRNEN-!foq7n}n5~u@qGNDr~2t<$B?qc;S zzo|@-2u=Br-lYd;9X>ckT`jiRW127LkKBT+-@pC{CC{TXC0jBK-jBx` zQi|&JviXo>R8X+b6Q_EDc@SVoH4jf|4ESvyvYtuWuCdH%&GgTiKZd=rx9L# zi_?u57KKSf%07Bey_6W^kP%r+Q;==(~lIjmPDpzNQ zKh?)R4mDtvy+w!W-}D#W`fuedITK}3PlJNg4*@jXM~ri}sc99priiPsJYa(^bJhCJ z6^-7FUG}s7K20tP1C_)oW|IJi92YztXOm8JO6kBkIdxdC;1OCYoDzDINOqUVZRVJz!=D4m+08lS~F#`C40@D;r(=fj9b0P$n$f#k|aZ}e|?5QRs zTxi*1+6X1AxBr$U`(?7_p_wvS-fNc;ROi=;Y*LLz!ZhZ6g2p3#&+b@4twDKL$r?a( zz?EqYFVs>Ns1Si+2Ifw7jM712lYUL)A*aKa|LGq66^MO(3Ty5C?#n!WL9}v&TW8)r zQ@4zBAnuDRcSD8c>H1i`fz|b#dPi~U!<*?DV5e6BA{>O*Y!5;(x zThpm^1_(w*1th3&a?`XWuRaf~IqP*t$$t|9_6US=SSyu!>5)d`?x=LtRLRBUV9Enm z>0K3ez0}`8W$!3ods7EsfRYqOq9LU$qhZe`Ws8OIgMlcrdA}#HEnoW_T9BqOVF$m` z1#t6y(n^Gi^?jg(eK1-lC$Bu-P*MnpFZ}u*>vq86a;GJ|%3S?-Y$E)^OPE2i4-X;S zS0K5(cfuK>621tFN>dun5|i@V5_9Jn)ST#znG3g)g zxj&6SJRPg@Hp}d;zB0wv4PM(=qr|&)(`3xS#PJ1&lk;SyRVnBWVc1{JKg5;gtzNdJ zySfb>sDzS}w@wTZwgAo;8JWck*7ftyaSF~h6&(s_pDfJVzhH7!(oy4Eh;uMa-pEvQ zH>$!=5+um~^)OfK&g>w27YuvGD8^m$ukerAs+f&AlQv$Oe{<)0yzjSbYZGXNPNn!+ z91fJT3eV=z3}Td|M82Kfr1dJB7lzti7wa$51^(qS5@H>Doy%;1EuQ-ep-NscziVM6 z1hi?IwvY%Ypo6CgaYKg_AhbcM#-ATSrS5+1Fh_;;5L@9dlCGl#9cM==?>pg)X>xFT z9duUjq-x9<D+mR~RQFERLU1Wh;R;V+Iy5=dkbn8vBK$LSk>71z`(b}WO;zDu>&`Bn-dNj~*H4|f-fmG5>9 zoL_STWZm($xx`^9=XP&87UpMo4F^h2ELUK@d4+SMdx2w^l0&Yr2E&h}3Wth{$^vnS z{=8#*Jce0Lx2iZm6kq1-OZ5%Rdu5v?cY?<5MZA1f-Al4*@?>>mrFq$~plw4{)|taR zBxR~{Tr!}%qP>GQAm|y`^YnhR1dVjH4&2KQoSD*v-V}zsL`{Ae|OR`bxRh}5`0}9!~4ByUa6s4(I-{550J9! z=Dx(Jh-J|MXPc^i1mfZhBT;G;B)5aEFn~Wc(Ez142qIwlu-&#F?Ex!sxUup?8e6vU;7a=wspv!qf)4vf~7t zoTmc&+Aq#i80;1@*sonHnn&2Zo7l(V?rVs)q1)>0lQOYV|%H3-fH`+P_W<<>(k z&wZx^K!fRQiO^ol>GYhh8c#pT8g{TZt8WLaJvuD645F4!N0D_vH0`9u z7d3no--SZ`6X0)(A9r*OnBIvPH&MREfmAE;IDb&Oz+uW;2*C{66moYWD8YQ^joKBG z(_KOFpi$T>h^hCqg}Df_d{2plAPdCuT?#$UJA=H2#e2N_c4PXBnlf&<7iUu-65Juc zQ+oGU88{^;+xu@1l0ueqUG-BE=v0I?c|V$1kd=Bz;nux>EEPy?T|ffp!ncU|yx*5KTlhamQUo{Rw1p?vNZ+>t8h zd4ThfZJ4;m+~+8WbS$yEd>3+Y1=N9^&hly>in@F3eVpXc!L;-KI!!RZA$*@?;#R9p zb_OX}AttBGD_ma!&>#6^ok74ul1dw3&p}j_>ZJFs6hMkUn|o&>)dsOE%I1!@I*4T1 zQ|Hm?Z=+T?0TM%x@)o543Fn`}(xge1WAfQ~X!Gcf<9iUlA%%?k;-@US2aqj$0(AZp zQ(w6FE#LGQ@1l15r1|b&Wj+m}lziUvYQx`V@>5oh<9jI7IQP3-Jiw@4cv-n$zA2LO znjPs@U!e$P1UULCh=qxxvI1fOMjK2A9#T_p`e?LA}KfE8rW|FTGU6K zEFauUAu%||F(Op(6g*&O?)O_5e$IRVxhT+ynJi&Bts-uZ`ax9I@hZqV{`)V2Ejx-Q zEVb)=F|-+4qDacGgKJWMh617h8iD-}(+vPQyP#m@4OEOU5DBr#yzc#B8fx!K5efx* z=zn^^P8kJt4v#qO#nX)kMVr7bNyiv8jC(J+<18RNbCc=+sw9p@7*L=ARqbzQ8=MRr zY7M<^gsR0VXyB)#^;0*Xqh7Fp>GcH_zCP)OZvFes2-fcq6jV98cR@&*@RP&)bbV@g z&J5I0lOoj7m-^SQqCzYeKnjo^#k~IK&jOWV=S1PdLGod`B$}|aup2C5+iS&rXear= zTYi4~QsC{iM1f$N0L@H z`wD=~(_*H0ngH?R4yJ?ae0VH_MS<#xejEn-w<8}6aV=xGx&RhH(T3UDEU`a-NyRVY z{*}9M7yi^$cF|vA|DUBW1hV2^Um5^{`9r-GonqkZRMh((xDJ34$!^TB7Vv(9|9*H- zy@y50TV@$^bTsoJTdP9J20&@lf>M$Hd}4vAjEM`jr*@bw@gn3Y=mUE=lB@`jFu8Ko zGJmQX$aDPdhoihxmJ6z(->|Z`}fy`*O3CIE|Tu*wc2BO zJU+_*a*Ba1;ibxP2~me>I@Ms4J^RjqgqTNNuX^;wD&CCWK9lNyThU*Ok@coJt7_Q4 zYIAu$;7(Zi6Zx{`*P#C9b{hyfq2d<*uE)Wq7EoU`7YTy&|9IdX4$dUAGM;-y7jmS5 zMB&cqZv3}BH4mzfSs6+(?f?A!^(IJ@)`sB?tj9P{4`$_Yec}h9xD%UzvWn+s2A`lv z1^=d%XEq;~U%v}4DDOP90pSe7&%V{nRewbQ$2MsQyiVv}a1@FY;cp*ySM9nxpDc1D zF_8ysRK0~JmDNKgo4a~Wvw z8N4#$;{fbW(#Rh`Ome2g#gsYU^gTEj1IUpIPp(f#LI1OM5jeVi)!e)=2(my2m*^9j zKxhJBJ38c;D53yx6C3EKLIW((2mny}EhrUt7bq#GzpJ<`>b1?iUC{8&25;M_NF7#I zxYdaLheiKCRuAMjUD5&xhuHhUsmKLSU=@dzP6}DUh+Y!#1V=}$B~^z+K*?(J z0r@@r^I+vff)h}=vTP>xGVfTG?mDWnCqWs&nGDWJ*_D!qkqNp?{y6V{LDkDsREo+K zMv6r~2%74JS!+om2tYHoCI*fOPT(VkFjK89dmqQpq3sw9wxGypVJubEj~bo^HG`O_ zq7cQc49|b%Nab#W@YZEg{5TA+1jT}jb7O@UDu+riwb%P}hgI1o7N&;qAT4?5+DTnh zAkh4R8E&qcqZ@HhZ8%&@vhhM5);-5AmaXy+hX7!S@pIZSzkvO2-zdUO(}awuUyt6ORId(2=?dlkm)NET3( z;ohpW#6sMcH&JlgA)u|YfcxxlRUT#t1Lj-47;H}id3vgZTW2_{C9;H>9z99Q012o& z6z2NWH18sLdW_cH4$v%09un49Mh_T*xc)O^IWmp`E)K4g(Ly?S&>QRi<%7t)MfLKE zTP*rteut?j9WL9(L0;HdTX@&wrOLBi4bZr%r09EbXqP@)mk{UXqbnu%e!ckIP4tQ~ zzc(`WT>?EkD51#ih|)i%^sH*Xq>oDOQRHB%e8mS=pz)->d~33ij}ffk5e&gdt5Dc7 zGjCNSDO_Ry7J6n&M|gH>NJ-1>5-YOa^kV3+ zZ`&enF}_vqaHValZ$?mFR=A0qnVM`wWi$!i4ao?m1~l(b7SR4sFl)GzK2lV+2Vl3EYAVHiX~M>*OMe z*i@&`>tf%Bm9`??wE+iZ@H6;Y$5n}nnL#B9zCKtv4G{eA@%(ld&?qHVo5q`D^JO$% zo%``HO70Pva(4;v)H>G0+moR}Qj$X*rhdpp(ySge5FU=sj~gbK8RXVTD`B7E<}l)| z0y=)ZP3{HGX0M!IzJWOip3}JkJ`T%dSS@z$X++=`VdK{;9kR0kii-o$-oL!4W%4)( zaQ(OM{_i>roIq_Em}CgbbA1YKPBS(CRCfRWfBb*l^7PS&Eo1&V=VyLhxDA8g#i&;} zPRQv${koWY;D*eQcsGLk>m|`>rx!(loLGi)m*n>EfBN}Z=j$^wgOXy0Yg??BaMawQ z72<1(DdThszZROa9P(I`W-I$w>3s>s8|H#b$~3rpHnAA>5tH)Tke66JZ)iST@-OT$ zXbP&Lwq7PFww~dE(W{=7Z`u^eBvl#Br`_dnoEaxsjnBs-WY(<1Oc&O%WpVl$%S3LN|eH-5L@V5I^NX@Z!eoqL?j@6=_`)2 zKe4cYpI1}Lafi}L=jhydrymVlDE{_gg$urP7^8>Qks07xF=wh*>8Y(;CgVFF_HBW= zKd@x1#D)2X32V-w8{6PR`JHbOpf$=iyHhbI-NsDZ z*{P0-JyiB6&jVv(&;a&udotj@-P)a6+Qy2T#o9&rhRD99GQ)l@qJsFWH|DO}fT@ky zt`;Cib1~6*-2r#BUp6G-ro^m25k~@FhkCIGr?W>kiwPZawgc5>NN1-l*uK=7wM})0 zyeB8ySkaAOQBIc@BQQ?adW0}*uXgR8zPE6&FK`m@7PYz3#U|2reCV#0 z$%x`52E=YImopIi>2u*y6z*bqeZ==T^<_jyilHPZ1k+>T?7u?cLN0kT?a(c8@S(ZT zm%`n(gZ<=mWiIm!O8BQK0qtG!j5w~wxfef>@$MgSJ|*6Dz2;=i;yiYVnF?o z2DjZB*v`wzZ?_+0&ZR#p%BZv>$aJB&-V)|d4flzYr>Bcbceny_uq3to7Q5xFSIal! z;0cvCb%CR2#!6()eBmKT`(8CEQCt^_B!isMi)Zv=EUK ze6-x5U7HEyOMO~-&GLC(knbirH$HQJmKR9yYLCYsC1|v_G>&f_*jy8Cgx5u^yjnQl z72vqu{|(;@5|K3wL_>fv=9>_<>?eE5AK&+l-wl=zC3wkh1UVknf92wT7m0eRDHBYjv=wEQiYJmdnu;*4GqiLbecHP`_aTXc14yd(jgg zgeQog74dShhx@7P zvXL%#SlDij?XYThm+9QKd{af{kCGeI;_b%QJ4=noZcm(XPufMtZJmwBH|WY(AX?lr zR%j#W$vDGNHdP0=)7EI#5{7vie0~Iy%l;GzJqSOts)+zQfu{Mv{hB^^!?#~6qvvsN zZB$r(`&zY#d;jW#tF6T!vOY#DvYqF}z4U00U?XR*$P;j>bFA*1r?FDN1w>|B-2uOT zm$!nj-fKKGhE)d^MBKT0HJuutS8I=2NEA}>W>KVU)xIaJ3TgEI;^AB-I~P}&;?HqB zT0r)`XrvSTks^|ZW^Ywvf9-B)e}H46Qn%ygL7X5g>|A=#d}sRi51*s^e4=2H%ACQ$ zocj(FEMAgoZd`=^!tPEblY-B3mxcGO_Ah-5T=+~_{&XN_8@Zot@>Enn{-eLe$0pkF z0G@~*Ml_BGrMpYgbnq{2tS+459s)d>;RwI!XyV{#k5@-3yLu2BV3P5sx;^^eVAoKK}ZcZzF0)87pSqk+SNVB zt;16Zwd16I=^-e-YaHm3l`Syw@MaEyq>-lSV(84aX7at&jkTJH@q??>@K5m(1KeTd zcS^!jP_~qHZJY3U?|TXX)7M=pPs!R=T!t_?J`~!FUYpYJ-;U3+TWYAzu?l9kvu%rF z$C?o*tXtHJNm%A1?Mjhso3v5IY4GTzjGdf&81AF~w)f5S)D5yEajmx;zHbkv?(KpjLowxjo1?;Rp#C+TEPEB}5>JkF%$U%C>uRcnWBr^v z*|!-zp##pkfQ9~i3+I;yjd!hYkm`>V%2mzgePQ@2-0#Z_7Y&SS9FmNGZ`F!HCr3v? z@EJ-m?s7yjrcNG9_x`&dr`E=B{0ETPjilf?r@|%>IBd6k14=hoX@wv!Eim;5V!&}Vd%~Ne$u?!4 zxt<`C@Aw&JVQ!^ELDM3za)3SW5{=_`n@GN}16Ji<{Y_n$AnR)}F6UirkbJ^dxos;H zSXCPR)oN#a0gJScrYpR+;=5>XR)jltXV$_CLz!WI@dWbnJi~T^DSpEajF(iQ%6^T6 z`JwvjPruYQK29MnkuBnqfrUi)JzJ0+Oif#x=N}B}^P(vUZdJ;n29%GfKFket1wZmB z)&xiFRBx3uxQD_frczq4v#4UhnWm8+|r0yTm)kW_g>Z{P3zqrc(P_ZE+H-2gMO*=793M7Ll2RWz)-KO9qVO zs<2)nIRa!l8cQ=Q<`sknYUe!tiDD@lN}h1n_qRvcjWGv`#7)c zQne=->j*2m9Ocm`smZZXP>UO;56pcKWMWEM|>$XWJ9jtk!fk#2e)cdqv}f#e2?T?@0|#a!z6t%h178}P4no0+hn5O;*yUJ z?x%|kF{zdN`cNP4q4npb@fL2a?V$(ivpuhMn&MkutZ?Zez<)~TVq0Y7T*CR`dRBSdG_|#kMJ=WvB14;U;tSkAkqSi5bb`mvW zl0Lem4-y+Y#Fg4ToB2$hPjui=Ijyvy@}e=qz-D~0IE_Kaj3TONl5ZcmH*T+cIBYaOVs-^w0 z#uZ!$BgsZ~62<2J4K{r0%|4wVNV-uP@c;cs$l=?O7FBtrWK_GNbcpmHZ5;20mE;fH zlPZ;Zf)p2VllJY!#We43_Dx9-OU=iMLmNzL@KHY7Tg&EH8+$~eIo^#MM&*R^2Ra$# z^Y2AuLvN<tKcNs)qSW-%zM``H)APEE`8?v+{XYuSBWoqy53mvqsB#2_;Ft zr&Vg{n3S&qmS1lZT5v6f6G)ov&C>c`RJk}{BGWzHvnMSG<>6N-js|MLg=Dkyra(xc+m%!ggWAZI|R%rZ;F_&(9y|K0Bx_*$= zXjoY)Jy@lwI(5*V1L%<=e7!HUdxE@z3m*%oqI=r}+{jVvFOyWQ;?Q?VrQq%12m)f3 zikX?F`naderJ|x-Yb{r+@l_?smh;M)GnWg+9tu4bAxP(R@+gQYyfK;X606X*j%dF@ zOHvRPM#A41v*PR?Q?&BoaSf!=pCl~U;ZFW;rR?~l`9zmag{<%EKExMnG9JLy=e5E1 zZOz+_F&3_%IH>W&1T<2D@u21U_p`p0&*YHhpdc5ZwctnlkJP)A5+Nx! z&t&e(fEMoLH-87n1ke7wUd2LvLiI172tsFBPygFrF6gPNgAt)?Q$v4#haBaop;1~9 zin*OTssBFxTTTSjKHYOsi}~jVkE_vvT=Cs}zD)HiI`AtL@K&$|e5AX!=g_agsIo#$xNBiCA;&uRmS#qy-WE9u3pPT`DyCtm^>D^^Gdd2!clwA53Kx@@YYfW)wy7mE#j@5b=w zafkaNKTJIvZPI}nuc~$Zs?_um8jTzJSh;Dx>$= zn?9D{Mn=N+MVx)?TY5e?YFXAyNx!z5W8E@;%d`967vn%>ex z)ct(k(xMAWn*PBE>8isEE6(L)5-C9};Z?Q=1b=bh@Fm$NYtT)0tZ6k~{5V@)QQ@x# zd(ndpD4m=lZ$pgD`7Vy5k@#&l2Qq@FQ1T1J!V+O-zV7Kup zs4%785xw4j>z`qwb|6h?YQ;a8HB7kAjhjY!FRHLL`6vf02VPe9G9Qoe1kr^W9W)fX zR1=p}q{>YN&{;ECH%bL7)c~1Ml&ep7Apbrx)Yd;F5c%R;C2 z$6I3p_IUiRj<>@3gStp-b+lyepf1bI_YBodoMzc!UJz^-ZI(7n$Ztpp(ZVAKDm>`H4T_LS( zGy>^r6a1dXmW#pjrJucYgyyb*0Kt#orm?gzjJUlA+7yr`E(E9@wQZ@1NT zCrfAvZq2d|%WOH|lJXMnSQ<3Nih0Up<~tv4Q~q=1u4dzdH$sTLZ12Y)PHbJH7${gr z91wBYa9578lfXF_U*Am^mZ5W9zTYI>+14x7x(@u|`oZ-Gy!+)Zo~SAiZ`FL%6AB`Q z^4m`*S!AuJqAjiJ*zDESlJ~-*EyrAcFg{J&zJ{@3&sVdS_3#i;;YxYanjRFHUSVs9 zp}qLe0|x3wxo3$C`%D=%%;m7-R5|>u)Sg6EUd1JU2rBziSdpaU1GqD-p)BD$h-Gu^swp@KxTiktZH%#+wmM5>5kFcH*Fi}6JNwIP(NOI%(ipC)u9?#HmhXs{o z?WIQ|A|LiT(;9_qcq$L&+IS+eG@7=`aO+DDB@1uq4M%@GVoy^FL;M-s6ugE8gvDJ( zK0;LLnGWP!hDN(VK#GC+;dAc;qhSeJ;>7k4{m%^*dy41w?3&!Gg5DP$UDC~W7^*E= zRrdNp)K_Nn4ij)jVdi6{o?c4_tjy|!!&k`e<%Hs38L`(1nW_jJ%9iV^~2 zMQ^-ZIBuRXmIX1He9)7waznoHhi~`G_2sFTKc=}KK7_axMG!J-5VS>h5^lWUe^G8M zexbx6p!eubn9#tSMl%3kCcAU0CI?8zjOgoEQtsNsTh-YfUeKWCU`VZEb>>am485sY z?$kbD`y)lzZ+CTNxG$9t#9d>#U2hELK7WuED7m)VT43+-_S9bdx~QiD-h#WgC&wh( zZMcSC0^aC3#in`!kUK(hCgz z#xu3>KLZ1AX*)FsHeTl%+-Ppj;J31$G{~QFl7?^Kxj#bK^s}xHKqD5W=5j1}& zo7Kl)zCr$RypqSObkkiBc%G=e?t1^o`NB*##;-8J1t?%fm?-{f_);OKpZ7^<5F&V~?<0YytKPMGm_6oyPbmBlE1cV0PN0RyQ znU*DM-UQ`0fh#T}-c?83KETrG>T79cIPA&q=Wj_5oH-XXr|++r4hP}9E5KUY9&Hld zE`hB z>fTRkf~Qhg84S;SQoQ52!@xDQpzgS~jMPFGALbWImC3y2wOvpfSGL7siPV{HjRP&9 zHagLXw>*CC^eYe$!p43zb0Q^kqTtPUE}0LE{O7tG&s+g5F>DXZ1w_KD#+}c2Ho_a= z@r*Txo}yhAf^XJVD*4A6kyYgP{WCr5vJrVRtH|6r%wWfdKV{tL34nf$XfM}KM!$=X zdR<@tXJ4kz#KeLG8AJZgu4E09X?6ZbV|gp)AavsedT!JB_SV74qyDaqbMa=+;qT5WJ{-;>9dIKzD zra=qAPhq@y8BM7*50qDdzABXiM1lLz#l*Ivl@XL`o)XgCKRqzTFd#4+PX>P>)M5pg z!jw2{efCSB*dd?4V=QMR`XJ&wxK-kE9-EKG5>`e*l;E!n6PY literal 0 HcmV?d00001 diff --git a/blog/docs/articles/images/readypods.png b/blog/docs/articles/images/readypods.png new file mode 100644 index 0000000000000000000000000000000000000000..74211961b547edbe0752da342853920c064ae919 GIT binary patch literal 37769 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 literal 0 HcmV?d00001 From 6f8a86bb18811bf49eee98e0e6d7588ede0d656e Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 14 Nov 2023 14:26:31 +0200 Subject: [PATCH 08/18] add timeline and several fixes --- .../demystifying-activator-on-path.md | 208 +++++++++++++----- blog/docs/articles/images/timeline.png | Bin 0 -> 23546 bytes 2 files changed, 155 insertions(+), 53 deletions(-) create mode 100644 blog/docs/articles/images/timeline.png diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 107b38a489..c5702497fc 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -2,7 +2,7 @@ **Author: [Stavros Kontopoulos](https://twitter.com/s_kontopoulos), Principal Software Engineer @ RedHat** -**Date: 2023-10-11** +**Date: 2023-11-14** _In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ @@ -10,10 +10,11 @@ The activator acts as a component on the data path to enable traffic buffering w One lesser known feature of activator is, that it can act as a request buffer that handles back-pressure with the goal to not overload a Knative service. For this, a Knative service can define how much traffic it can handle using [annotations](https://knative.dev/docs/serving/autoscaling/autoscaling-targets/#configuring-targets). The autoscaler component will use this information to calculate the amount of pods needed to handle the incoming traffic for a specific Knative service -When serving traffic a knative service can operate in two modes: proxy mode and serve mode. + +In detail when serving traffic, a Knative service can operate in two modes: proxy mode and serve mode. When in proxy mode, Activator is on the data path (which means the incoming requests are routed through the Activator component), and it will stay on the path until certain conditions (more on this later) are met. When these conditions are met, Activator is removed from the data path, and the service transitions to serve mode. -However, it was not always like that when a service scales from/to zero, the activator is added by default to the data path. +For example, when a service scales from/to zero, the activator is added by default to the data path. This default setting often confuses users for reasons we will see next as it is possible that activator will not be removed unless enough capacity is available. This is intended as one of the Activator's roles is to offer backpressure capabilities so that a Knative service is not overloaded by incoming traffic. @@ -22,9 +23,9 @@ This is intended as one of the Activator's roles is to offer backpressure capabi The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that uses metrics from pods to make scaling decisions. Let's see in detail what happens when a new Knative service is created. -Once the user creates a new service the corresponding Knative reconciler creates a Knative Configuration and a Knative Route for that service. +Once the user creates a new service the corresponding Knative reconciler creates a Knative `Configuration` and a Knative `Route` for that service. Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. -The Route reconciler will create the ingress resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. +The Route reconciler will create the `Ingress` resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. Now, the creation of the PA triggers the KPA reconciler which goes through certain steps in order to setup an autoscaling configuration for the revision: @@ -36,18 +37,49 @@ sets up a pod scaler via the multi-scaler component. The pod scaler calculates a - calls a scale method that decides the number of wanted pods and also updates the K8s raw deployment that corresponds to the revision. - creates/updates a ServerlessService (SKS) that holds info about the operation mode (proxy or serve) and stores the number of activators that should be used in proxy mode. -The number of activators depends on the capacity that needs to be covered. -That SKS create/update event triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the K8s deployment. -Also in proxy mode that controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). -This in combination with the networking setup done by the net-* components is the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. + The number of activators specified in the SKS depends on the capacity that needs to be covered. - updates the PA and reports the active and wanted pods in its status +!!! note + + The SKS create/update event above triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the raw K8s deployment. + Also in proxy mode that SKS controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). + This in combination with the networking setup done by the net-* components (driven by the Ingress resource) is roughly the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. + + ## Capacity and Operation Modes in Practice -As described earlier Activator will be removed if enough capacity is available and there is an invariant that needs to hold, that is EBC (excess burst capacity)>0, where EBC = TotalCapacity - ObservedInPanicMode - TargetBurstCapacity(TBC). +As described earlier Activator will be removed if enough capacity is available. Let's see how this capacity is calculated +but before that let's introduce two concepts: the `panic` and `stable` windows. +The `panic` window is the time duration where we don't have enough capacity to serve the traffic. It happens usually with a sudden burst of traffic. +The condition that describes when to enter the panic mode and start the panic window is: + +``` +dppc/readyPodsCount >= spec.PanicThreshold +``` +where +``` +dppc := math.Ceil(observedPanicValue / spec.TargetValue) +``` +The target value is the utilization in terms of concurrency and that is 0.7*(revision_target). +0.7 is the utilization factor for each replica and when reached we need to scale out. + +**Note:** if the KPA metrics Requests Per Second(RPS) is used then the utilization factor is 0.75. + +The `observedPanicValue` is the calculated average value seen during the panic window for the concurrency metric. +The panic threshold is configurable (default 2) and expresses the ratio of desired versus available pods. -Let's see an example of a service that has a target concurrency of 10 and tbc=10: +After we enter panic mode in order to exit we need to have enough capacity for a period that is equal to the stable window size. + +To quantify the idea of enough capacity to deal with bursts of traffic we introduce the notion of the Excess Burst Capacity(EBC) that needs to be >=0. +It is defined as: + +``` +EBC = TotalCapacity - ObservedPanicValue - TargetBurstCapacity(TBC). +``` + +Let's see an example of how these are calculated in practice. Here is a service that has a target concurrency of 10 and tbc=10: ``` apiVersion: serving.knative.dev/v1 @@ -65,7 +97,16 @@ spec: - image: ghcr.io/knative/autoscale-go:latest ``` -Initially when the ksvc was deployed there was no traffic and one pod is created by default for verification reasons. +The scenario we are going to demonstrate is deploye the ksvc, let it scale down to zero and then send traffic for 10 minutes. +We then collect the logs from the autoscaler and visualize the EBC, ready pods and panic mode over time. +The graphs are shown next. + +![Excess burst capacity over time](/blog/articles/images/ebc.png) +![Ready pods over time](/blog/articles/images/readypods.png) +![Panic mode over time](/blog/articles/images/panic.png) + + +Let's describe inde tail what we see above. Initially when the ksvc is deployed there is no traffic and one pod is created by default for verification reasons. Until the pod is up we have: ```bash @@ -85,11 +126,16 @@ NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAM autoscale-go-00001 Serve 2 autoscale-go-00001 autoscale-go-00001-private True ``` -The reason why we are in Serve mode is that because EBC=0. In the logs we get: +The reason why we are in Serve mode is that because EBC=0. When you enable debug logs, in the logs you get: - -```bash -{"severity":"DEBUG","timestamp":"2023-10-10T15:29:37.241575214Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=1 Total1PodCapacity=10.000 ObsStableValue=0.000 ObsPanicValue=0.000 TargetBC=10.000 ExcessBC=0.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} +``` + "severity": "DEBUG", + "timestamp": "2023-10-10T15:29:37.241575214Z", + "logger": "autoscaler", + "caller": "scaling/autoscaler.go:286", + "message": "PodCount=1 Total1PodCapacity=10.000 ObsStableValue=0.000 ObsPanicValue=0.000 TargetBC=10.000 ExcessBC=0.000", + "commit": "f1617ef", + "knative.dev/key": "default/autoscale-go-00001" ``` EBC = 10 - 0 - 10 = 0 @@ -104,12 +150,6 @@ NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAM autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-00001-private Unknown NoHealthyBackends ``` -When you enable debug logs, you can see this also in the autoscaler logs. In this case we go directly to: - -``` -{"severity":"DEBUG","timestamp":"2023-10-10T15:29:37.241523364Z","logger":"autoscaler","caller":"scaling/autoscaler.go:247","message":"Operating in stable mode.","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} -``` - Let's send some traffic (experiment was run on Minikube): ```bash @@ -119,19 +159,46 @@ hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168. Initially activator when get a request in it sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): ``` -{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178498172Z","logger":"autoscaler.stats-websocket-server","caller":"statserver/server.go:193","message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:1 AverageProxiedConcurrentRequests:0 RequestCount:1 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}","commit":"f1617ef","address":":8080"} -{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178733422Z","logger":"autoscaler","caller":"statforwarder/processor.go:64","message":"Accept stat as owner of bucket autoscaler-bucket-00-of-01","commit":"f1617ef","bucket":"autoscaler-bucket-00-of-01","knative.dev/key":"default/autoscale-go-00001"} + "severity": "DEBUG", + "timestamp": "2023-10-10T15:32:56.178498172Z", + "logger": "autoscaler.stats-websocket-server", + "caller": "statserver/server.go:193", + "message": "Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:1 AverageProxiedConcurrentRequests:0 RequestCount:1 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}", + "commit": "f1617ef", + "address": ":8080" + + "severity": "DEBUG", + "timestamp": "2023-10-10T15:32:56.178733422Z", + "logger": "autoscaler", + "caller": "statforwarder/processor.go:64", + "message": "Accept stat as owner of bucket autoscaler-bucket-00-of-01", + "commit": "f1617ef", + "bucket": "autoscaler-bucket-00-of-01", + "knative.dev/key": "default/autoscale-go-00001" ``` +The autoscaler enters panic mode since we don't have enough capacity, EBS is 10*0 -1 -10 = -11 ``` -{"severity":"DEBUG","timestamp":"2023-10-10T15:32:56.178920551Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=1.000 ObsPanicValue=1.000 TargetBC=10.000 ExcessBC=-11.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} -``` + "severity": "DEBUG", + "timestamp": "2023-10-10T15:32:56.178920551Z", + "logger": "autoscaler", + "caller": "scaling/autoscaler.go:286", + "message": "PodCount=0 Total1PodCapacity=10.000 ObsStableValue=1.000 ObsPanicValue=1.000 TargetBC=10.000 ExcessBC=-11.000", + "commit": "f1617ef", + "knative.dev/key": "default/autoscale-go-00001" + + "severity": "INFO", + "timestamp": "2023-10-10T15:32:57.24099875Z", + "logger": "autoscaler", + "caller": "scaling/autoscaler.go:215", + "message": "PANICKING.", + "commit": "f1617ef", + "knative.dev/key": "default/autoscale-go-00001" +``` Later on as traffic continues we get proper statistics from activator closer to the rate: - ``` -{ "severity":"DEBUG", "timestamp":"2023-10-10T15:32:56.949001622Z", "logger":"autoscaler.stats-websocket-server", @@ -139,9 +206,7 @@ Later on as traffic continues we get proper statistics from activator closer to "message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:18.873756322609804 AverageProxiedConcurrentRequests:0 RequestCount:19 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}", "commit":"f1617ef", "address":":8080" -} -{ "severity":"INFO", "timestamp":"2023-10-10T15:32:56.432854252Z", "logger":"autoscaler", @@ -152,9 +217,7 @@ Later on as traffic continues we get proper statistics from activator closer to "knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler", "knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb", "knative.dev/key":"default/autoscale-go-00001" -} -{ "severity":"DEBUG", "timestamp":"2023-10-10T15:32:57.241052566Z", "logger":"autoscaler", @@ -162,49 +225,88 @@ Later on as traffic continues we get proper statistics from activator closer to "message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000", "commit":"f1617ef", "knative.dev/key":"default/autoscale-go-00001" -} ``` - Since the pod is not up yet: EBS = 0*10 - floor(19.874) - 10 = -30 - -Given the new statistics kpa decides to scale to 3 pods. +Given the new statistics kpa decides to scale to 3 pods at some point. ``` -{"severity":"INFO","timestamp":"2023-10-10T15:32:57.241421042Z","logger":"autoscaler","caller":"kpa/scaler.go:370","message":"Scaling from 1 to 3","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"6dcf87c9-15d8-41d3-95ae-5ca9b3d90705","knative.dev/key":"default/autoscale-go-00001"} + "severity": "INFO", + "timestamp": "2023-10-10T15:32:57.241421042Z", + "logger": "autoscaler", + "caller": "kpa/scaler.go:370", + "message": "Scaling from 1 to 3", + "commit": "f1617ef", + "knative.dev/controller": "knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", + "knative.dev/kind": "autoscaling.internal.knative.dev.PodAutoscaler", + "knative.dev/traceid": "6dcf87c9-15d8-41d3-95ae-5ca9b3d90705", + "knative.dev/key": "default/autoscale-go-00001" ``` But let's see why is this is the case. The log above comes from the multi-scaler which reports a scaled result that contains EBS as reported above and a desired pod count for different windows. -Roughly the final desired number is (there is more logic that covers corner cases and checking against min/max scale limits): +Roughly the final desired number is (there is more logic that covers corner cases and checking against min/max scale limits) +derived from the dppc we saw earlier. + +In this case the target value is 0.7*10=10. So we have for example for the panic window: dppc=ceil(19.874/7)=3 + +As metrics get stabilized and revision is scaled enough we have: ``` -dspc := math.Ceil(observedStableValue / spec.TargetValue) -dppc := math.Ceil(observedPanicValue / spec.TargetValue) + "severity": "INFO", + "timestamp": "2023-10-10T15:33:01.320912032Z", + "logger": "autoscaler", + "caller": "kpa/kpa.go:158", + "message": "SKS should be in Serve mode: want = 3, ebc = 0, #act's = 2 PA Inactive? = false", + "commit": "f1617ef", + "knative.dev/controller": "knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", + "knative.dev/kind": "autoscaling.internal.knative.dev.PodAutoscaler", + "knative.dev/traceid": "f0d22038-130a-4560-bd67-2751ecf3975d", + "knative.dev/key": "default/autoscale-go-00001" + + + "severity": "DEBUG", + "timestamp": "2023-10-10T15:33:03.24101879Z", + "logger": "autoscaler", + "caller": "scaling/autoscaler.go:286", + "message": "PodCount=3 Total1PodCapacity=10.000 ObsStableValue=16.976 ObsPanicValue=15.792 TargetBC=10.000 ExcessBC=4.000", + "commit": "f1617ef", + "knative.dev/key": "default/autoscale-go-00001" ``` +EBS = 3*10 - floor(15.792) - 10 = 4 -The target value is the utilization in terms of concurrency and that is is 0.7*(revision_target). -In this case this is 7. So we have for example for the panic window: ceil(19.874/7)=3 +Then when we reach the required pod count and metrics are stable we get EBC=3*10 - floor(19.968) - 10=0: -**Note:** if RPS is used then the utilization factor is 0.75. +``` + "severity": "DEBUG", + "timestamp": "2023-10-10T15:33:59.24118625Z", + "logger": "autoscaler", + "caller": "scaling/autoscaler.go:286", + "message": "PodCount=3 Total1PodCapacity=10.000 ObsStableValue=19.602 ObsPanicValue=19.968 TargetBC=10.000 ExcessBC=0.000", + "commit": "f1617ef", + "knative.dev/key": "default/autoscale-go-00001" +``` -Later on when revision is scaled we have: +A few seconds later, one minute after we get in panicking mode we get to stable mode (un-panicking): ``` -{"severity":"INFO","timestamp":"2023-10-10T15:33:01.320912032Z","logger":"autoscaler","caller":"kpa/kpa.go:158","message":"SKS should be in Serve mode: want = 3, ebc = 0, #act's = 2 PA Inactive? = false","commit":"f1617ef","knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler","knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler","knative.dev/traceid":"f0d22038-130a-4560-bd67-2751ecf3975d","knative.dev/key":"default/autoscale-go-00001"} - -{"severity":"DEBUG","timestamp":"2023-10-10T15:33:03.24101879Z","logger":"autoscaler","caller":"scaling/autoscaler.go:286","message":"PodCount=3 Total1PodCapacity=10.000 ObsStableValue=16.976 ObsPanicValue=15.792 TargetBC=10.000 ExcessBC=4.000","commit":"f1617ef","knative.dev/key":"default/autoscale-go-00001"} + "severity": "INFO", + "timestamp": "2023-10-10T15:34:01.240916706Z", + "logger": "autoscaler", + "caller": "scaling/autoscaler.go:223", + "message": "Un-panicking.", + "commit": "f1617ef", + "knative.dev/key": "default/autoscale-go-00001" ``` -EBS = 3*10 - floor(15.792) - 10 = 4 +The sks also transitions to Serve mode as we have enough capacity until traffic stops and deployment is scaled back to zero (activator is removed from path). +For the experiment above since we have stable traffic for almost 10 minutes we don't observe any changes as soon as we have enough pods ready. +Note that when traffic goes down and until we adjust the pod count, for some short period of time, we have more ebc than we need. -Later on the sks transitions to Serve mode as we have enough capacity until traffic stops and deployment is scaled back to zero. +The major events are also depected in the timeline bellow: -The above are shown visually next with graphs describing ebc, ready pods and -![Excess burst capacity over time](/blog/articles/images/ebc.png) -![Ready pods over time](/blog/articles/images/readypods.png) -![Panic mode over time](/blog/articles/images/panic.png) +![timeline](/blog/articles/images/timeline.png) ### Conclusion diff --git a/blog/docs/articles/images/timeline.png b/blog/docs/articles/images/timeline.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe604f124715ee4218568cdf3734a1cc5661503 GIT binary patch literal 23546 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 Date: Tue, 14 Nov 2023 15:14:55 +0200 Subject: [PATCH 09/18] updates --- .../demystifying-activator-on-path.md | 23 +++++++++++++----- blog/docs/articles/images/timeline.png | Bin 23546 -> 31997 bytes 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index c5702497fc..1f53a0adc7 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -62,24 +62,35 @@ where ``` dppc := math.Ceil(observedPanicValue / spec.TargetValue) ``` -The target value is the utilization in terms of concurrency and that is 0.7*(revision_target). -0.7 is the utilization factor for each replica and when reached we need to scale out. -**Note:** if the KPA metrics Requests Per Second(RPS) is used then the utilization factor is 0.75. +dppc stands for desired panic pod count and expressed what autoscaler needs to achieve in panic mode. +The target value is the utilization in terms of concurrency that the autoscaler aims for and that is calculated as 0.7*(revision_total). +Revision total is the maximum possible value of scaling metric that is permitted on the pod and defaults to 100 (container concurrency default). +The value 0.7 is the utilization factor for each replica and when reached we need to scale out. + +**Note:** if the KPA metric Requests Per Second(RPS) is used then the utilization factor is 0.75. The `observedPanicValue` is the calculated average value seen during the panic window for the concurrency metric. The panic threshold is configurable (default 2) and expresses the ratio of desired versus available pods. After we enter panic mode in order to exit we need to have enough capacity for a period that is equal to the stable window size. +That also means that autoscaler will try to get enough pods ready in order to increase the capacity. +Also note here that when operating outside the panic mode the autoscaler does not use `dpcc` but a similar quantity: +`dspc := math.Ceil(observedStableValue / spec.TargetValue)` which is based on metrics during the stable period. -To quantify the idea of enough capacity to deal with bursts of traffic we introduce the notion of the Excess Burst Capacity(EBC) that needs to be >=0. +To quantify the idea of enough capacity and to deal with bursts of traffic we introduce the notion of the Excess Burst Capacity(EBC) that needs to be >=0. It is defined as: ``` EBC = TotalCapacity - ObservedPanicValue - TargetBurstCapacity(TBC). ``` -Let's see an example of how these are calculated in practice. Here is a service that has a target concurrency of 10 and tbc=10: +`TotalCapacity` is calculated as ready_pod_count*revision_total. The default TBC is set to 200. +Now with the above defaults and given the fact that a request needs to stay around for some time in order concurrency metrics to show enough load, it means you can't get EBC>=0 with a hello-world example. +The latter which is often confusing for the newcomer as the Knative service never enters serve mode. +In the next example we will show the lifecycle of a Knative service that also moves to serve mode and how ebc is calculated in practice. + +Here is a service that has a target concurrency of 10 and tbc=10: ``` apiVersion: serving.knative.dev/v1 @@ -106,7 +117,7 @@ The graphs are shown next. ![Panic mode over time](/blog/articles/images/panic.png) -Let's describe inde tail what we see above. Initially when the ksvc is deployed there is no traffic and one pod is created by default for verification reasons. +Let's describe in detail what we see above. Initially when the ksvc is deployed there is no traffic and one pod is created by default for verification reasons. Until the pod is up we have: ```bash diff --git a/blog/docs/articles/images/timeline.png b/blog/docs/articles/images/timeline.png index 7fe604f124715ee4218568cdf3734a1cc5661503..a8af770b1d6c58500f0f628e5711b7e66bd1323e 100644 GIT binary patch literal 31997 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çnuzo7~( zxELVV6|Vs#(W-v{nF$xvQE%GBj+(%(A)X2pb*$X6`K>N#X$m~a&yo^3KjO-3%^dUZ z{DFk9WV1>RSI2j~HaR4u^jq54u~>hUK>pj-yq#^$k491wU?TNZJjsH^$J&)>GC-+>J^YKF;wu7! z806$?H*mH>p1-ngDSd-eqO<|!2w4n$YL zI(J?(Q&8Bro|^Rq3_soV0!=({E$DbO9z1?*R>*bK;l~De`WoD+?E+-TA3S(JQrwj! zLz0dymzMU!V_vb($cL*81j|h&jNMoR_WMN0T;-NUDPDugn+!-ZCv_#^ z-~Z#suc3tK<*{C_(@CI4S(jpG;1a+vs|D#^3KU}l(p@+wZe75N(fb@t+|Av+A=5;D z>6CW@+F>kh@;!o_P%;zmsHK0^3f04PRKdh)1|$F;G)MNN?{?{dQdA*MZz)A zR>A-m$bbZFwEkWg2Ggwb0fWx(Sxo4x!DEBt#OlAl>u4G1*YoZtKQ#3a#{h<-yGe{v z@x^cN?!1VLgBxNN#9CllL*Lb8WywvuW5>}>h=vDB&NNGp-3nAsfxGEramOlTr<7-&N`=90 zkax)E4?{w3Wn~E=b0nxg_83&_2lhGU`u1JBtQ&T`vlb@XICj7th_N-t=1Sd!K3X(c zJJ>&E<>j}aSZC>)DFc{*55~WK{dF+m*`bXaHxi~w@v}AC4@M&M>}NEX`)txGXU=TH z#C~nv@~XY2D7mHw^C#rHRgHdpUw{8A2v`^)_AV~O(uGLLJTiu#$6$1TR7MzeXR##g zUo7}#5HXNl!lghba%~n|*M+ax@0Gv*0(8(PaUcf%Z3A^a)qX<{}f^!z^vu1tvaiM7gI~k zFr2-ei|$!+=;`T^RTT7^Ug`eu;4tc}I4x8mq)6@e)Kp4FUHi9%mzM@(fVs3K)Rtc@ z8H8}3ck8;ge%anK!gtXNlHn8R@5{@}bASGjFAdYT0`S}B;&+%D574$hftD(9(4rT{ zW5;b_m3Z>}IXj1HloCLS^3%hm*1}n!yc+5H#H{1lB8vDE4{u>&aSP~YnEl})~#|B^QWOp$jZsB)_fJYi-iTckqP!QCgfAh{T_@Q z(5s{~v6Lni{=i7j+Fh_L&H0WA<%PigKxd4I+d=rkunj^U3XD+(-XKu~q177IJ`t4T z^g-u(u3zK^AZFd!3#YXCn}Y~g#)0)5l(@Q3(gvoS%*~Oo6m+>*tsx%grLl#1>Oh< zpu**v0k8kXq>U#P6*r-29;t|5jzeQRWZN!k@&}!f;9&9%`TL~)4DPl3npm2gUVINL zkE?(dC*(S&3p#5d@dd6Po6k&!hdC9ZjSNBeP$6hW@f)`ku;SH2YLqvDoOJU=FTm` zTd2>u=*#}_K*7=?y@zro`GRlBnz@&JSpSmv=yz+0 zGfb3gJW25-PRon#Jv}{)hcD5PywYSfbb%WGokFKho$3M}`!O)^rRa)luOn{HLfxqE z?09D&GEyhMtOIO2AtM71Xdr!Ntv(F5+AyKZz>x5|Axwd^-3m9Q1I_6g~ z&Ma(gh?$3Uz_~a@x&o)6GUTbCc*NuOk~kYCEHQejFFyBP`m=>uIOTI`bMV85bLfXe z>BD=$)d}4rbDPnGxhy1VZ78qy2~bAtZaSAR?`)z*16m+_^%gmTFv%;z5TnpxUSZ8p zdO)Flh%*>gJ=oLtd!>eOJ1Eu~d4Q!B@P3H%0DOPcjcdpG$D8=rS9GbR=3+J-m-WsCKqAWv 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 Kn^^1le*Xp3<%eSc literal 23546 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 Date: Tue, 19 Mar 2024 12:43:22 +0200 Subject: [PATCH 10/18] address some comments --- .../demystifying-activator-on-path.md | 81 ++++--------------- 1 file changed, 14 insertions(+), 67 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 1f53a0adc7..694c8ac006 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -2,11 +2,11 @@ **Author: [Stavros Kontopoulos](https://twitter.com/s_kontopoulos), Principal Software Engineer @ RedHat** -**Date: 2023-11-14** +**Date: 2024-03-19** _In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ -The activator acts as a component on the data path to enable traffic buffering when a service is scaled-to-zero. +The [activator](https://github.com/knative/serving/tree/main/docs/scaling#activator) acts as a component on the data path to enable traffic buffering when a service is scaled-to-zero. One lesser known feature of activator is, that it can act as a request buffer that handles back-pressure with the goal to not overload a Knative service. For this, a Knative service can define how much traffic it can handle using [annotations](https://knative.dev/docs/serving/autoscaling/autoscaling-targets/#configuring-targets). The autoscaler component will use this information to calculate the amount of pods needed to handle the incoming traffic for a specific Knative service @@ -128,11 +128,11 @@ autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-0000 When the pod is up we have: ```bash -$ oc get po +$ kubectl get po NAME READY STATUS RESTARTS AGE autoscale-go-00001-deployment-6cc679b9d6-xgrkf 2/2 Running 0 24s -$ oc get sks +$ kubectl get sks NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAME READY REASON autoscale-go-00001 Serve 2 autoscale-go-00001 autoscale-go-00001-private True ``` @@ -140,13 +140,10 @@ autoscale-go-00001 Serve 2 autoscale-go-00001 autoscale-go-0000 The reason why we are in Serve mode is that because EBC=0. When you enable debug logs, in the logs you get: ``` - "severity": "DEBUG", + ... "timestamp": "2023-10-10T15:29:37.241575214Z", "logger": "autoscaler", - "caller": "scaling/autoscaler.go:286", "message": "PodCount=1 Total1PodCapacity=10.000 ObsStableValue=0.000 ObsPanicValue=0.000 TargetBC=10.000 ExcessBC=0.000", - "commit": "f1617ef", - "knative.dev/key": "default/autoscale-go-00001" ``` EBC = 10 - 0 - 10 = 0 @@ -161,7 +158,7 @@ NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAM autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-00001-private Unknown NoHealthyBackends ``` -Let's send some traffic (experiment was run on Minikube): +Let's send some traffic (experiment was run on Minikube and hey tool was used for generating the traffic): ```bash hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168.39.43:32718?sleep=1000" @@ -170,88 +167,55 @@ hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168. Initially activator when get a request in it sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): ``` - "severity": "DEBUG", + ... "timestamp": "2023-10-10T15:32:56.178498172Z", "logger": "autoscaler.stats-websocket-server", "caller": "statserver/server.go:193", "message": "Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:1 AverageProxiedConcurrentRequests:0 RequestCount:1 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}", - "commit": "f1617ef", "address": ":8080" - - "severity": "DEBUG", - "timestamp": "2023-10-10T15:32:56.178733422Z", - "logger": "autoscaler", - "caller": "statforwarder/processor.go:64", - "message": "Accept stat as owner of bucket autoscaler-bucket-00-of-01", - "commit": "f1617ef", - "bucket": "autoscaler-bucket-00-of-01", - "knative.dev/key": "default/autoscale-go-00001" ``` The autoscaler enters panic mode since we don't have enough capacity, EBS is 10*0 -1 -10 = -11 ``` - "severity": "DEBUG", + ... "timestamp": "2023-10-10T15:32:56.178920551Z", "logger": "autoscaler", "caller": "scaling/autoscaler.go:286", "message": "PodCount=0 Total1PodCapacity=10.000 ObsStableValue=1.000 ObsPanicValue=1.000 TargetBC=10.000 ExcessBC=-11.000", - "commit": "f1617ef", - "knative.dev/key": "default/autoscale-go-00001" - "severity": "INFO", "timestamp": "2023-10-10T15:32:57.24099875Z", "logger": "autoscaler", "caller": "scaling/autoscaler.go:215", - "message": "PANICKING.", - "commit": "f1617ef", - "knative.dev/key": "default/autoscale-go-00001" - + "message": "PANICKING." ``` Later on as traffic continues we get proper statistics from activator closer to the rate: ``` - "severity":"DEBUG", + ... "timestamp":"2023-10-10T15:32:56.949001622Z", "logger":"autoscaler.stats-websocket-server", - "caller":"statserver/server.go:193", "message":"Received stat message: {Key:default/autoscale-go-00001 Stat:{PodName:activator-59dff6d45c-9rdxh AverageConcurrentRequests:18.873756322609804 AverageProxiedConcurrentRequests:0 RequestCount:19 ProxiedRequestCount:0 ProcessUptime:0 Timestamp:0}}", - "commit":"f1617ef", "address":":8080" - "severity":"INFO", + ... "timestamp":"2023-10-10T15:32:56.432854252Z", "logger":"autoscaler", "caller":"kpa/kpa.go:188", "message":"Observed pod counts=kpa.podCounts{want:1, ready:0, notReady:1, pending:1, terminating:0}", - "commit":"f1617ef", - "knative.dev/controller":"knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", - "knative.dev/kind":"autoscaling.internal.knative.dev.PodAutoscaler", - "knative.dev/traceid":"7988492e-eea3-4d19-bf5a-8762cf5ff8eb", - "knative.dev/key":"default/autoscale-go-00001" - "severity":"DEBUG", + ... "timestamp":"2023-10-10T15:32:57.241052566Z", "logger":"autoscaler", - "caller":"scaling/autoscaler.go:286", "message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000", - "commit":"f1617ef", - "knative.dev/key":"default/autoscale-go-00001" ``` Since the pod is not up yet: EBS = 0*10 - floor(19.874) - 10 = -30 Given the new statistics kpa decides to scale to 3 pods at some point. ``` - "severity": "INFO", "timestamp": "2023-10-10T15:32:57.241421042Z", "logger": "autoscaler", - "caller": "kpa/scaler.go:370", "message": "Scaling from 1 to 3", - "commit": "f1617ef", - "knative.dev/controller": "knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", - "knative.dev/kind": "autoscaling.internal.knative.dev.PodAutoscaler", - "knative.dev/traceid": "6dcf87c9-15d8-41d3-95ae-5ca9b3d90705", - "knative.dev/key": "default/autoscale-go-00001" ``` But let's see why is this is the case. The log above comes from the multi-scaler which reports a scaled result that contains EBS as reported above and a desired pod count for different windows. @@ -264,25 +228,15 @@ In this case the target value is 0.7*10=10. So we have for example for the panic As metrics get stabilized and revision is scaled enough we have: ``` - "severity": "INFO", "timestamp": "2023-10-10T15:33:01.320912032Z", "logger": "autoscaler", "caller": "kpa/kpa.go:158", "message": "SKS should be in Serve mode: want = 3, ebc = 0, #act's = 2 PA Inactive? = false", - "commit": "f1617ef", - "knative.dev/controller": "knative.dev.serving.pkg.reconciler.autoscaling.kpa.Reconciler", - "knative.dev/kind": "autoscaling.internal.knative.dev.PodAutoscaler", - "knative.dev/traceid": "f0d22038-130a-4560-bd67-2751ecf3975d", - "knative.dev/key": "default/autoscale-go-00001" - - - "severity": "DEBUG", - "timestamp": "2023-10-10T15:33:03.24101879Z", + + ... "logger": "autoscaler", "caller": "scaling/autoscaler.go:286", "message": "PodCount=3 Total1PodCapacity=10.000 ObsStableValue=16.976 ObsPanicValue=15.792 TargetBC=10.000 ExcessBC=4.000", - "commit": "f1617ef", - "knative.dev/key": "default/autoscale-go-00001" ``` EBS = 3*10 - floor(15.792) - 10 = 4 @@ -290,24 +244,17 @@ EBS = 3*10 - floor(15.792) - 10 = 4 Then when we reach the required pod count and metrics are stable we get EBC=3*10 - floor(19.968) - 10=0: ``` - "severity": "DEBUG", "timestamp": "2023-10-10T15:33:59.24118625Z", "logger": "autoscaler", - "caller": "scaling/autoscaler.go:286", "message": "PodCount=3 Total1PodCapacity=10.000 ObsStableValue=19.602 ObsPanicValue=19.968 TargetBC=10.000 ExcessBC=0.000", - "commit": "f1617ef", - "knative.dev/key": "default/autoscale-go-00001" ``` A few seconds later, one minute after we get in panicking mode we get to stable mode (un-panicking): ``` - "severity": "INFO", "timestamp": "2023-10-10T15:34:01.240916706Z", "logger": "autoscaler", - "caller": "scaling/autoscaler.go:223", "message": "Un-panicking.", - "commit": "f1617ef", "knative.dev/key": "default/autoscale-go-00001" ``` From 6bf67e627e33ce28062521f18a291a0301a08ec5 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 12:54:06 +0200 Subject: [PATCH 11/18] add ref to the sample app --- blog/docs/articles/demystifying-activator-on-path.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 694c8ac006..ee61bf58b9 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -158,12 +158,18 @@ NAME MODE ACTIVATORS SERVICENAME PRIVATESERVICENAM autoscale-go-00001 Proxy 2 autoscale-go-00001 autoscale-go-00001-private Unknown NoHealthyBackends ``` -Let's send some traffic (experiment was run on Minikube and hey tool was used for generating the traffic): +Let's send some traffic. ```bash hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168.39.43:32718?sleep=1000" ``` +!!! note + + The experiment was run on Minikube and the [hey](https://github.com/rakyll/hey) tool was used for generating the traffic. + For more on the hey tool and the sample app we use in the post check the section [Autoscale Sample App - Go](../../../../../docs/serving/autoscaling/autoscale-go/README.md). + + Initially activator when get a request in it sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): ``` From 797e799f2c8aadb6c5e690d167c1be0928fc4ea1 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 14:00:36 +0200 Subject: [PATCH 12/18] grammar, typos and other fixes --- .../demystifying-activator-on-path.md | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index ee61bf58b9..0c179d6f6d 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -6,17 +6,17 @@ _In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ -The [activator](https://github.com/knative/serving/tree/main/docs/scaling#activator) acts as a component on the data path to enable traffic buffering when a service is scaled-to-zero. -One lesser known feature of activator is, that it can act as a request buffer that handles back-pressure with the goal to not overload a Knative service. +The [activator](https://github.com/knative/serving/tree/main/docs/scaling#activator) acts as a component on the data path to enable traffic buffering when a service is scaled to zero. +One lesser-known feature of the activator is that it can act as a request buffer that handles back pressure, protecting a Knative service from overloading. For this, a Knative service can define how much traffic it can handle using [annotations](https://knative.dev/docs/serving/autoscaling/autoscaling-targets/#configuring-targets). -The autoscaler component will use this information to calculate the amount of pods needed to handle the incoming traffic for a specific Knative service +The autoscaler component will use this information to calculate the number of pods needed to handle the incoming traffic for a specific Knative service. -In detail when serving traffic, a Knative service can operate in two modes: proxy mode and serve mode. -When in proxy mode, Activator is on the data path (which means the incoming requests are routed through the Activator component), and it will stay on the path until certain conditions (more on this later) are met. -When these conditions are met, Activator is removed from the data path, and the service transitions to serve mode. -For example, when a service scales from/to zero, the activator is added by default to the data path. -This default setting often confuses users for reasons we will see next as it is possible that activator will not be removed unless enough capacity is available. -This is intended as one of the Activator's roles is to offer backpressure capabilities so that a Knative service is not overloaded by incoming traffic. +In detail, when serving traffic, a Knative service can operate in two modes: the `proxy` mode and the `serve` mode. +When in proxy mode, activator is on the data path (which means the incoming requests are routed through the activator component), and it will stay on the path until certain conditions are met (more on this later). +If these conditions are met, activator will be removed from the data path, and the service will transition to serve mode. +For example, when a service scales from/to zero, the activator is added to the data path by default. +This default setting often confuses users, as the activator will not be removed from the path unless enough capacity is available. +This is by intention, as one of the activator's roles is to offer back pressure capabilities so that a Knative service is not overloaded by incoming traffic. ## Background @@ -27,32 +27,32 @@ Once the user creates a new service the corresponding Knative reconciler creates Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. The Route reconciler will create the `Ingress` resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. -Now, the creation of the PA triggers the KPA reconciler which goes through certain steps in order to setup an autoscaling configuration for the revision: +Now, the creation of the PA triggers the KPA reconciler, which goes through certain steps in order to set up an autoscaling configuration for the revision: - creates an internal Decider resource that holds the initial desired scale in `decider.Status.DesiredScale`and sets up a pod scaler via the multi-scaler component. The pod scaler calculates a new Scale result every two seconds and makes a decision based on the condition `decider.Status.DesiredScale != scaledResult.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. Goal is the KPA to get the latest scale result. -- creates a Metric resource that triggers the metrics collector controller to setup a scraper for the revision pods. +- creates a Metric resource that triggers the metrics collector controller to set up a scraper for the revision pods. - calls a scale method that decides the number of wanted pods and also updates the K8s raw deployment that corresponds to the revision. - creates/updates a ServerlessService (SKS) that holds info about the operation mode (proxy or serve) and stores the number of activators that should be used in proxy mode. The number of activators specified in the SKS depends on the capacity that needs to be covered. -- updates the PA and reports the active and wanted pods in its status +- updates the PA and reports the active and wanted pods in the PA's status !!! note The SKS create/update event above triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the raw K8s deployment. - Also in proxy mode that SKS controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). - This in combination with the networking setup done by the net-* components (driven by the Ingress resource) is roughly the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. + Also, in the proxy mode the SKS controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). + In combination with the networking setup done by the net-* components (driven by the Ingress resource), this is roughly the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. ## Capacity and Operation Modes in Practice -As described earlier Activator will be removed if enough capacity is available. Let's see how this capacity is calculated -but before that let's introduce two concepts: the `panic` and `stable` windows. -The `panic` window is the time duration where we don't have enough capacity to serve the traffic. It happens usually with a sudden burst of traffic. +As described earlier, the activator will be removed from the path, assuming enough capacity is available. +Let's see how this capacity is calculated, but before that, let's introduce two concepts: the `panic` and `stable` windows. +The `panic` window is the time duration that denotes a lack of capacity to serve the traffic. It happens usually with a sudden burst of traffic. The condition that describes when to enter the panic mode and start the panic window is: ``` @@ -63,10 +63,10 @@ where dppc := math.Ceil(observedPanicValue / spec.TargetValue) ``` -dppc stands for desired panic pod count and expressed what autoscaler needs to achieve in panic mode. +The `dppc` stands for desired panic pod count and expresses what autoscaler needs to achieve in panic mode. The target value is the utilization in terms of concurrency that the autoscaler aims for and that is calculated as 0.7*(revision_total). -Revision total is the maximum possible value of scaling metric that is permitted on the pod and defaults to 100 (container concurrency default). -The value 0.7 is the utilization factor for each replica and when reached we need to scale out. +Revision total is the maximum possible value of the scaling metric that is permitted on the pod and defaults to 100 (container concurrency default). +The value 0.7 is the utilization factor for each replica and when that is reached we need to scale out. **Note:** if the KPA metric Requests Per Second(RPS) is used then the utilization factor is 0.75. @@ -74,8 +74,8 @@ The `observedPanicValue` is the calculated average value seen during the panic w The panic threshold is configurable (default 2) and expresses the ratio of desired versus available pods. After we enter panic mode in order to exit we need to have enough capacity for a period that is equal to the stable window size. -That also means that autoscaler will try to get enough pods ready in order to increase the capacity. -Also note here that when operating outside the panic mode the autoscaler does not use `dpcc` but a similar quantity: +That also means that the autoscaler will try to get enough pods ready in order to increase the capacity. +Also, note here that when operating outside the panic mode the autoscaler does not use `dpcc` but a similar quantity: `dspc := math.Ceil(observedStableValue / spec.TargetValue)` which is based on metrics during the stable period. To quantify the idea of enough capacity and to deal with bursts of traffic we introduce the notion of the Excess Burst Capacity(EBC) that needs to be >=0. @@ -86,11 +86,11 @@ EBC = TotalCapacity - ObservedPanicValue - TargetBurstCapacity(TBC). ``` `TotalCapacity` is calculated as ready_pod_count*revision_total. The default TBC is set to 200. -Now with the above defaults and given the fact that a request needs to stay around for some time in order concurrency metrics to show enough load, it means you can't get EBC>=0 with a hello-world example. +Now with the above defaults and given the fact that a request needs to stay around for some time in order for concurrency metrics to show enough load, it means you can't get EBC>=0 with a hello-world example. The latter which is often confusing for the newcomer as the Knative service never enters serve mode. -In the next example we will show the lifecycle of a Knative service that also moves to serve mode and how ebc is calculated in practice. +In the next example, we will show the lifecycle of a Knative service that also moves to serve mode and how EBC is calculated in practice. -Here is a service that has a target concurrency of 10 and tbc=10: +Here is a service that has a target concurrency value of 10 and tbc=10: ``` apiVersion: serving.knative.dev/v1 @@ -108,8 +108,8 @@ spec: - image: ghcr.io/knative/autoscale-go:latest ``` -The scenario we are going to demonstrate is deploye the ksvc, let it scale down to zero and then send traffic for 10 minutes. -We then collect the logs from the autoscaler and visualize the EBC, ready pods and panic mode over time. +The scenario we are going to demonstrate is to deploy the ksvc, let it scale down to zero and then send traffic for 10 minutes. +We then collect the logs from the autoscaler and visualize the EBC values, ready pods, and panic mode over time. The graphs are shown next. ![Excess burst capacity over time](/blog/articles/images/ebc.png) @@ -181,7 +181,7 @@ Initially activator when get a request in it sends stats to the autoscaler which "address": ":8080" ``` -The autoscaler enters panic mode since we don't have enough capacity, EBS is 10*0 -1 -10 = -11 +The autoscaler enters panic mode since we don't have enough capacity, EBC is 10*0 -1 -10 = -11 ``` ... "timestamp": "2023-10-10T15:32:56.178920551Z", @@ -214,7 +214,7 @@ Later on as traffic continues we get proper statistics from activator closer to "logger":"autoscaler", "message":"PodCount=0 Total1PodCapacity=10.000 ObsStableValue=19.874 ObsPanicValue=19.874 TargetBC=10.000 ExcessBC=-30.000", ``` -Since the pod is not up yet: EBS = 0*10 - floor(19.874) - 10 = -30 +Since the pod is not up yet: EBC = 0*10 - floor(19.874) - 10 = -30 Given the new statistics kpa decides to scale to 3 pods at some point. @@ -224,7 +224,7 @@ Given the new statistics kpa decides to scale to 3 pods at some point. "message": "Scaling from 1 to 3", ``` -But let's see why is this is the case. The log above comes from the multi-scaler which reports a scaled result that contains EBS as reported above and a desired pod count for different windows. +But let's see why is this is the case. The log above comes from the multi-scaler which reports a scaled result that contains EBC as reported above and a desired pod count for different windows. Roughly the final desired number is (there is more logic that covers corner cases and checking against min/max scale limits) derived from the dppc we saw earlier. @@ -245,7 +245,7 @@ As metrics get stabilized and revision is scaled enough we have: "message": "PodCount=3 Total1PodCapacity=10.000 ObsStableValue=16.976 ObsPanicValue=15.792 TargetBC=10.000 ExcessBC=4.000", ``` -EBS = 3*10 - floor(15.792) - 10 = 4 +EBC = 3*10 - floor(15.792) - 10 = 4 Then when we reach the required pod count and metrics are stable we get EBC=3*10 - floor(19.968) - 10=0: @@ -264,15 +264,15 @@ A few seconds later, one minute after we get in panicking mode we get to stable "knative.dev/key": "default/autoscale-go-00001" ``` -The sks also transitions to Serve mode as we have enough capacity until traffic stops and deployment is scaled back to zero (activator is removed from path). +The `sks` also transitions to `serve` mode as we have enough capacity until traffic stops and deployment is scaled back to zero (the activator is removed from the path). For the experiment above since we have stable traffic for almost 10 minutes we don't observe any changes as soon as we have enough pods ready. -Note that when traffic goes down and until we adjust the pod count, for some short period of time, we have more ebc than we need. +Note that when traffic goes down and until we adjust the pod count, for some short period of time, we have more `ebc` than we need. -The major events are also depected in the timeline bellow: +The major events are also shown in the timeline bellow: ![timeline](/blog/articles/images/timeline.png) ### Conclusion -It is often confusing of how and why services stuck in proxy mode or how users can manage Activator on path. -This is important especially when you just started with Knative Serving. With the detailed example above hopefully we have demystified this fundamental behavior of the Serving data plane. +It is often confusing how and why services are stuck in proxy mode or how users can manage the activator when the latter is on the data path. +This is important, especially when you are just getting started with Knative Serving. With the detailed example above, hopefully, we have demystified this fundamental behavior of the Serving data plane. From 026a968205a7df8dd4331ffd0d3b45969314b2cf Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 14:35:14 +0200 Subject: [PATCH 13/18] more grammar fixes --- .../articles/demystifying-activator-on-path.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 0c179d6f6d..aa3aa1211b 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -4,7 +4,7 @@ **Date: 2024-03-19** -_In this blog post you will learn how to recognize when activator is on the data path and what it triggers that behavior._ +_In this blog post, you will learn how to recognize when the activator is on the data path and what triggers that behavior._ The [activator](https://github.com/knative/serving/tree/main/docs/scaling#activator) acts as a component on the data path to enable traffic buffering when a service is scaled to zero. One lesser-known feature of the activator is that it can act as a request buffer that handles back pressure, protecting a Knative service from overloading. @@ -12,11 +12,11 @@ For this, a Knative service can define how much traffic it can handle using [ann The autoscaler component will use this information to calculate the number of pods needed to handle the incoming traffic for a specific Knative service. In detail, when serving traffic, a Knative service can operate in two modes: the `proxy` mode and the `serve` mode. -When in proxy mode, activator is on the data path (which means the incoming requests are routed through the activator component), and it will stay on the path until certain conditions are met (more on this later). -If these conditions are met, activator will be removed from the data path, and the service will transition to serve mode. +When in proxy mode, the activator is on the data path (which means the incoming requests are routed through the activator component), and it will stay on the path until certain conditions are met (more on this later). +If these conditions are met, the activator will be removed from the data path, and the service will transition to serve mode. For example, when a service scales from/to zero, the activator is added to the data path by default. This default setting often confuses users, as the activator will not be removed from the path unless enough capacity is available. -This is by intention, as one of the activator's roles is to offer back pressure capabilities so that a Knative service is not overloaded by incoming traffic. +This is by intention, as one of the activator's roles (as mentioned above) is to offer back pressure capabilities so that a Knative service is not overloaded by incoming traffic. ## Background @@ -27,10 +27,10 @@ Once the user creates a new service the corresponding Knative reconciler creates Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. The Route reconciler will create the `Ingress` resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. -Now, the creation of the PA triggers the KPA reconciler, which goes through certain steps in order to set up an autoscaling configuration for the revision: +Now, the creation of the PA triggers the KPA reconciler, which goes through certain steps to set up an autoscaling configuration for the revision: - creates an internal Decider resource that holds the initial desired scale in `decider.Status.DesiredScale`and -sets up a pod scaler via the multi-scaler component. The pod scaler calculates a new Scale result every two seconds and makes a decision based on the condition `decider.Status.DesiredScale != scaledResult.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. Goal is the KPA to get the latest scale result. + sets up a pod scaler via the multi-scaler component. The pod scaler calculates a new Scale result every two seconds and makes a decision based on the condition `decider.Status.DesiredScale != scaledResult.DesiredPodCount` whether to trigger a new reconciliation for the KPA reconciler. The goal is the KPA to get the latest scale result. - creates a Metric resource that triggers the metrics collector controller to set up a scraper for the revision pods. @@ -44,7 +44,7 @@ sets up a pod scaler via the multi-scaler component. The pod scaler calculates a !!! note The SKS create/update event above triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the raw K8s deployment. - Also, in the proxy mode the SKS controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). + Also, in the proxy mode, the SKS controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). In combination with the networking setup done by the net-* components (driven by the Ingress resource), this is roughly the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. @@ -108,7 +108,7 @@ spec: - image: ghcr.io/knative/autoscale-go:latest ``` -The scenario we are going to demonstrate is to deploy the ksvc, let it scale down to zero and then send traffic for 10 minutes. +The scenario we are going to demonstrate is to deploy the ksvc, let it scale down to zero, then send traffic for 10 minutes. We then collect the logs from the autoscaler and visualize the EBC values, ready pods, and panic mode over time. The graphs are shown next. From a2eaca0445c9bffd172c77cc788ff6da05dc49d5 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 14:42:57 +0200 Subject: [PATCH 14/18] change personal link --- blog/docs/articles/demystifying-activator-on-path.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index aa3aa1211b..3de220bbf0 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -1,8 +1,6 @@ # Demystifying Activator on path -**Author: [Stavros Kontopoulos](https://twitter.com/s_kontopoulos), Principal Software Engineer @ RedHat** - -**Date: 2024-03-19** +**Author: [Stavros Kontopoulos](https://www.linkedin.com/in/stavroskontopoulos), Principal Software Engineer @ RedHat** _In this blog post, you will learn how to recognize when the activator is on the data path and what triggers that behavior._ From 7bf1090efd85f4e47682b00c22859964e50928a6 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 14:52:28 +0200 Subject: [PATCH 15/18] make title specific --- blog/docs/articles/demystifying-activator-on-path.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 3de220bbf0..032637f3b6 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -1,4 +1,4 @@ -# Demystifying Activator on path +# Demystifying Activator on the data path **Author: [Stavros Kontopoulos](https://www.linkedin.com/in/stavroskontopoulos), Principal Software Engineer @ RedHat** From 188b56096704e5be1b4ce8fc0754392de94d7b1d Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 15:44:47 +0200 Subject: [PATCH 16/18] more fixes --- .../articles/demystifying-activator-on-path.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 032637f3b6..18e51357bc 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -84,9 +84,15 @@ EBC = TotalCapacity - ObservedPanicValue - TargetBurstCapacity(TBC). ``` `TotalCapacity` is calculated as ready_pod_count*revision_total. The default TBC is set to 200. -Now with the above defaults and given the fact that a request needs to stay around for some time in order for concurrency metrics to show enough load, it means you can't get EBC>=0 with a hello-world example. -The latter which is often confusing for the newcomer as the Knative service never enters serve mode. -In the next example, we will show the lifecycle of a Knative service that also moves to serve mode and how EBC is calculated in practice. + +For the Knative Autoscaler it holds the following. + +!!! important + If EBC >=0 then we have enough capacity to serve the traffic and the activator will be removed from the path. + +Now with the above defaults and given the fact that a request needs to stay around for some time in order for concurrency metrics to show enough load for the counted period, it means you can't get EBC>=0 with a hello-world example where requests finish pretty quickly. +The latter is often confusing for the newcomer as it seems that the Knative service never enters the serve mode. +In the next example, we will show the lifecycle of a Knative service that also moves to the serve mode and how EBC is calculated in practice. Here is a service that has a target concurrency value of 10 and tbc=10: @@ -165,10 +171,10 @@ hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168. !!! note The experiment was run on Minikube and the [hey](https://github.com/rakyll/hey) tool was used for generating the traffic. - For more on the hey tool and the sample app we use in the post check the section [Autoscale Sample App - Go](../../../../../docs/serving/autoscaling/autoscale-go/README.md). + For more on the hey tool and the sample app we use in the post check the section [Autoscale Sample App - Go](../../../../../docs/serving/autoscaling/autoscale-go/). -Initially activator when get a request in it sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): +Initially activator when receives a request, sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): ``` ... From 6a23a6237acec27e805c55f05e86e34bac1cca00 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Tue, 19 Mar 2024 16:09:52 +0200 Subject: [PATCH 17/18] explain a bit what app was used for tests --- blog/docs/articles/demystifying-activator-on-path.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 18e51357bc..5d99c96002 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -92,9 +92,9 @@ For the Knative Autoscaler it holds the following. Now with the above defaults and given the fact that a request needs to stay around for some time in order for concurrency metrics to show enough load for the counted period, it means you can't get EBC>=0 with a hello-world example where requests finish pretty quickly. The latter is often confusing for the newcomer as it seems that the Knative service never enters the serve mode. -In the next example, we will show the lifecycle of a Knative service that also moves to the serve mode and how EBC is calculated in practice. - -Here is a service that has a target concurrency value of 10 and tbc=10: +In the next example, we will show the lifecycle of a Knative service that also moves to the serve mode and how EBC is calculated in practice. +Also, the example uses a sample app that controls how long a request stays around via a sleep operation, see section [Autoscale Sample App - Go](../../../../../docs/serving/autoscaling/autoscale-go/). +Thus, here is the service for the example that has a target concurrency value of 10 and tbc=10: ``` apiVersion: serving.knative.dev/v1 @@ -171,8 +171,6 @@ hey -z 600s -c 20 -q 1 -host "autoscale-go.default.example.com" "http://192.168. !!! note The experiment was run on Minikube and the [hey](https://github.com/rakyll/hey) tool was used for generating the traffic. - For more on the hey tool and the sample app we use in the post check the section [Autoscale Sample App - Go](../../../../../docs/serving/autoscaling/autoscale-go/). - Initially activator when receives a request, sends stats to the autoscaler which tries to scale from zero based on some initial scale (default 1): From 2214e4bf377fecc886d01d7298819ccbdf723238 Mon Sep 17 00:00:00 2001 From: Stavros Kontopoulos Date: Wed, 20 Mar 2024 11:12:03 +0200 Subject: [PATCH 18/18] address comments --- blog/docs/articles/demystifying-activator-on-path.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/blog/docs/articles/demystifying-activator-on-path.md b/blog/docs/articles/demystifying-activator-on-path.md index 5d99c96002..333a37e89f 100644 --- a/blog/docs/articles/demystifying-activator-on-path.md +++ b/blog/docs/articles/demystifying-activator-on-path.md @@ -22,7 +22,7 @@ The default pod autoscaler in Knative (KPA) is a sophisticated algorithm that us Let's see in detail what happens when a new Knative service is created. Once the user creates a new service the corresponding Knative reconciler creates a Knative `Configuration` and a Knative `Route` for that service. -Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a Pod Autoscaler(PA) resource along with the K8s deployment for the service. +Then the Configuration reconciler creates a `Revision` resource and the reconciler for the latter will create a PodAutoscaler(PA) resource along with the K8s deployment for the service. The Route reconciler will create the `Ingress` resource that will be picked up by the Knative net-* components responsible for managing traffic locally in the cluster and externally to the cluster. Now, the creation of the PA triggers the KPA reconciler, which goes through certain steps to set up an autoscaling configuration for the revision: @@ -43,8 +43,8 @@ Now, the creation of the PA triggers the KPA reconciler, which goes through cert The SKS create/update event above triggers a reconciliation for the SKS from its specific controller that creates the required public and private K8s services so traffic can be routed to the raw K8s deployment. Also, in the proxy mode, the SKS controller will pick up the number of activators and configure an equal number of endpoints for the revision's [public service](https://github.com/knative/serving/blob/main/docs/scaling/SYSTEM.md#data-flow-examples). - In combination with the networking setup done by the net-* components (driven by the Ingress resource), this is roughly the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. - + In combination with the networking setup done by a Knative networking component (driven by the Ingress resource), this is roughly the end-to-end networking setup that needs to happen for a ksvc to be ready to serve traffic. + The Knative networking component can be any of the following: net-istio, net-kourier, net-contour, and net-gateway-api. ## Capacity and Operation Modes in Practice