<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>kafka on Digi Hunch</title><link>https://static.digihunch.com/tag/kafka/</link><description>Recent content in kafka on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Wed, 02 Apr 2025 13:03:25 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/kafka/index.xml" rel="self" type="application/rss+xml"/><item><title>Autoscaling on Kubernetes Platform</title><link>https://static.digihunch.com/2022/03/autoscaling-in-kubernetes-from-metric-based-to-event-driven/</link><pubDate>Mon, 28 Mar 2022 13:14:00 -0400</pubDate><guid>https://static.digihunch.com/2022/03/autoscaling-in-kubernetes-from-metric-based-to-event-driven/</guid><description>&lt;img src="https://static.digihunch.com/wp-content/uploads/2025/04/feature-k8s-autoscaling.webp" alt="Featured image of post Autoscaling on Kubernetes Platform" /&gt;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-introduction"&gt;Introduction&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The concept of autoscaling on Kubernetes platform dates from the era where virtualization first became widespread and the overhead of provisioning a new server became lightweight through the use of &lt;a href="https://help.ubuntu.com/community/CloudInit"&gt;cloud-init&lt;/a&gt;. With public cloud, customers operate on usage-based billing. Autoscaling allows workload to scale down during idle times to reduce cost, and scale up during peak time to meet the demand of business traffic. Vertical autoscaling replaces a VM with one of higher capacity, which is usually interruptive. Horizontal autoscaling adds or removes VMs to adjust capacity, and works in conjunction with load balancing mechanism to assign load to a specific target in the group. Unless otherwise specified, we simply refer to horizontal autoscaling as autoscaling. Depending on what triggers autoscaling, it can be metrics based or event driven.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Metric-based autoscaling is based on VM (or Pod) metrics in the autoscaling group. The metrics are mostly about CPU usage, memory, IOPS, number of connections, etc. For example, when the average CPU utilization across all VMs in the last five minutes hits 70% threshold, then the scaler introduces a new VM into the autoscaling group. The trigger can factor in a variety of metrics. Advanced autoscaling APIs can also support lifecycle hooks, i.e. custom activities upon creation of new VMs during scale-up, or upon deletion of existing VMs during scale-down. Other aspects of custom behaviours include a cool-off period, i.e a no-activity window after the previous scaling activity. Since scaling activities are re-active. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Using real-time metrics as a trigger of scaling is not always a good idea. For example, a buggy order processing program may consume 100% of CPU due to an infinite loop, or 99% of memory due to memory leak. Metric-based scaling may fire off even though there is currently no order pending in the queue. Event-driven approach is more flexible. Event can fire from any type of source. For example, in Kubernetes, when scheduler fails to schedule a Pod due to constraints, it is an event This event can trigger scaling. In some case, a metric hitting a threshold fires an event. For example, scale up when size of order queue reaches 20. In this sense, metric-based autoscaling is a special case of event-driven autoscaling. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With Kubernetes, let&amp;#8217;s examine node group autoscaling (aka cluster autoscaling) and workload autoscaling (Pod autoscaling). &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-node-group-autoscaling"&gt;Node Group Autoscaling&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Cluster autoscaler is the mechanism to auto-scale node groups for Kubernetes. As per its &lt;a href="https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#is-cluster-autoscaler-compatible-with-cpu-usage-based-node-autoscalers"&gt;documentation&lt;/a&gt;, any metric-based cluster/node group autoscalers are NOT compatible with CA. They are also not particularly suitable for Kubernetes in general. Take AKS for example, the events to trigger scale-up and scale-down are as below:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;The cluster autoscaler component can watch for pods in your cluster that can&amp;#8217;t be scheduled because of resource constraints. The cluster then automatically increases the number of nodes.&lt;/li&gt;&#10;&lt;li&gt;The cluster autoscaler decreases the number of nodes when there has been unused capacity for a period of time. Pods on a node to be removed by the cluster autoscaler are safely scheduled elsewhere in the cluster.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both are in essence event driven. The behaviours can be fine-tuned with a number of &lt;a href="https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca"&gt;parameters&lt;/a&gt; as below:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;scan-interval&lt;/li&gt;&#10;&lt;li&gt;scale-down-delay-after-add&lt;/li&gt;&#10;&lt;li&gt;scale-down-delay-after-delete&lt;/li&gt;&#10;&lt;li&gt;scale-down-delay-after-failure&lt;/li&gt;&#10;&lt;li&gt;scale-down-unneeded-time&lt;/li&gt;&#10;&lt;li&gt;scale-down-unready-time&lt;/li&gt;&#10;&lt;li&gt;scale-down-utilization-threshold&lt;/li&gt;&#10;&lt;li&gt;max-graceful-termination-sec&lt;/li&gt;&#10;&lt;li&gt;balance-similar-node-groups&lt;/li&gt;&#10;&lt;li&gt;expander: random, most-pods, least-waste, priority &lt;/li&gt;&#10;&lt;li&gt;skip-nodes-with-local-storage&lt;/li&gt;&#10;&lt;li&gt;skip-nodes-with-system-pods&lt;/li&gt;&#10;&lt;li&gt;max-empty-bulk-delete&lt;/li&gt;&#10;&lt;li&gt;new-pod-scale-up-delay&lt;/li&gt;&#10;&lt;li&gt;max-total-unready-percentage&lt;/li&gt;&#10;&lt;li&gt;max-node-provision-time&lt;/li&gt;&#10;&lt;li&gt;ok-total-unready-count&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The parameters above constitute the autoscaler profiler, and are effective if cluster autoscaler is enabled. For many implementations, cluster autoscaler can be enabled and disabled even after the cluster has been created, and the parameters can be changed. The overhead of provisioning a new node should not be overlooked, because that is usually the window that a Pod needs to wait to get scheduled. As stated in CA&amp;#8217;s &lt;a href="https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#how-is-cluster-autoscaler-different-from-cpu-usage-based-node-autoscalers"&gt;FAQ&lt;/a&gt;, the main purpose of CA is to get pending pods a place to run, instead of pre-emptively accommodating to increasing workload.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The delay in pod scheduling while adding a new node can be controlled to a certain degree with one of the two workarounds below:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;With HPA or KEDA, set lower threshold so the workload level scaling acts more aggressive than the increase of demand. This buys some buffer time&lt;/li&gt;&#10;&lt;li&gt;Use a tool to puff up utilization, such as &lt;a href="https://artifacthub.io/packages/helm/deliveryhero/cluster-overprovisioner"&gt;cluster overprovisioner&lt;/a&gt;, which deploys pods that&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;request enough resources to reserve virtually all resources for a node&lt;/li&gt;&#10;&lt;li&gt;consume no actual resources&lt;/li&gt;&#10;&lt;li&gt;use a priority class that causes them to be evicted as soon as any other Pod needs it.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In practice the cluster autoscaler setup should be conservative and keep node size as stable as it can. For example, a 20 minutes idle-window (low utilization) on a node is not worth the overhead to remove a node and add it back in 20 minute later.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When the cluster do need to scale down by removing a node, one common symptom is failing to scale down because some Pods have nowhere else to schedule to. H&lt;a href="https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-types-of-pods-can-prevent-ca-from-removing-a-node"&gt;ere&lt;/a&gt; is a list of possible causes as &lt;a href="https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#troubleshooting"&gt;troubleshooting&lt;/a&gt; tips.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If node scaling should be triggered sparsely, then pod scaling is by design very dynamic. Cloud native applications should assume that pod scaling occurs very frequently.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In late 2021, AWS released the open-source project &lt;a href="https://aws.amazon.com/blogs/aws/introducing-karpenter-an-open-source-high-performance-kubernetes-cluster-autoscaler/"&gt;Karpenter&lt;/a&gt; for cluster autoscaler. Karpenter addresses some challenges with native Cluster Autoscaler on &lt;a href="https://static.digihunch.com/2022/12/eks-impression/"&gt;EKS&lt;/a&gt;. Karpenter is gaining momentum and now adding support for other cloud service providers including Azure. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-workload-autoscaling"&gt;Workload Autoscaling&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Stateless workload are controlled by a Deployment object, which is associated with a replicaSet object. For stateless workload we can use &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/"&gt;HorizontalPodAutoscaler&lt;/a&gt;, or HPA. There is a VerticalPodAutoscaler (VPA) which is much less common. HPA is metrics based with flexible options such as specifying an object, depending on what metrics are available via &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#support-for-metrics-apis"&gt;metrics API&lt;/a&gt;. There are two versions of HorizontalPodAutoscaler: autoscaling/v1 and autoscaling/v2. The latter supports scaling policies, such as adjusting downscale stabilization window, and limiting scale down rate. No matter which API version, the metric-based triggers in HPA are fairly limited.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We already know that metrics are not always the best indicator to trigger scaling. We need an option to trigger scaling based on the status of other components such as queue size. KEDA (Kubernetes Event Driven Autoscaling) is a great option to consider for horizontal workload scaling. KEDA works with HPA, and significantly enriches trigger options. Apart from metrics, KEDA can use a number of external mechanisms as triggers, for example:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;RabbitMQ/Kafka/SQS: scale based on queue size&lt;/li&gt;&#10;&lt;li&gt;Azure Log Analytics: scale based on a kusto query result against Azure Log Analytics&lt;/li&gt;&#10;&lt;li&gt;AWS CloudWatch, Azure Monitor: scale based on metrics from Azure Monitor/AWS CloudWatch&lt;/li&gt;&#10;&lt;li&gt;Azure Pipelines: scale based on agent pool queues of Azure Pipeline&lt;/li&gt;&#10;&lt;li&gt;Elasticsearch: scale based on elasticsearch query result&lt;/li&gt;&#10;&lt;li&gt;Kubernetes Workload: scale based on the count of running pods of a specified workload&lt;/li&gt;&#10;&lt;li&gt;MSSQL, MySQL, Postgres, Cassandra: scale based on a query result&lt;/li&gt;&#10;&lt;li&gt;Prometheus: scale based on prometheus query result&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://keda.sh/docs/2.6/concepts/"&gt;KEDA &lt;/a&gt;is a single-purpose and lightweight component. With KEDA, we don&amp;#8217;t need to explicitly define HPA. It allows us to select from a longer list of triggering mechanisms for our auto scaler. We shall not underestimate the work needed to select the most suitable trigger because having an incorrect trigger (e.g. bad metrics) is costly. Let&amp;#8217;s take Java applications as an example. Java workload operates in a JVM inside of the container. JVM request the entire heap size from operating system. The &lt;a href="https://static.digihunch.com/2020/08/java-garbage-collection/"&gt;garbage collection&lt;/a&gt; activities also consumes a good portion of CPU cycles. This pattern makes CPU and memory metrics inaccurate as an indicator for scaling activity. Because of this we need to find out what is the best scaler for Java application, based on understanding of how the entire solution stack works as a whole.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The other aspect that KEDA beats HPA is its ability to scale to 0. This can be helpful when a service is idle most of the time but cannot shut down.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-keda-lab"&gt;KEDA lab&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;let&amp;#8217;s use &lt;a href="https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/"&gt;Kafka&lt;/a&gt; as an example to configure KEDA for a dummy workload. We create a &lt;a href="https://github.com/digihunch/real-quicK-cluster"&gt;mock cluster&lt;/a&gt; using Kind with a simple &lt;a href="https://github.com/digihunch/real-quicK-cluster/blob/main/kind/kind-config.yaml"&gt;configuration file&lt;/a&gt;. Then, let&amp;#8217;s start with the following dummy workload with replica count set to 1:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Namespace&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;workload&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;apps&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Deployment&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;workload&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;replicas&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;selector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;matchLabels&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;template&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;labels&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;containers&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;image&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;neilpeterson&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ports&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;containerPort&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;env&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;TITLE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;Welcome to Azure Kubernetes Service (AKS)&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Service&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;workload&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;LoadBalancer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;ports&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;port&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;80&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;selector&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;app&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We need to install KEDA and Kafka using Helm:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm repo add kedacore https://kedacore.github.io/charts&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install keda kedacore/keda -n keda --create-namespace&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm repo add bitnami https://charts.bitnami.com/bitnami&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install kafka bitnami/kafka -n kafka --create-namespace --set volumePermissions.enabled&lt;span style="color:#f92672"&gt;=&lt;/span&gt;true --set replicaCount&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Watch for all Pods to come up. Also read the notes from Kafa installation and confirm the Kafka service address. Now, we will apply KEDA scaled object, defined as below:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-js" data-lang="js"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;keda&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;sh&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1alpha1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;ScaledObject&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;scaledobject&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;namespace&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;workload&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;spec&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;scaleTargetRef&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;apiVersion&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;apps&lt;/span&gt;&lt;span style="color:#f92672"&gt;/&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;v1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;kind&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Deployment&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;aks&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;helloworld&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;one&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;pollingInterval&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;cooldownPeriod&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;30&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;idleReplicaCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;minReplicaCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;maxReplicaCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;fallback&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;failureThreshold&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;replicas&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;advanced&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;restoreToOriginalReplicaCount&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;horizontalPodAutoscalerConfig&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;behavior&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;scaleDown&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;stabilizationWindowSeconds&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;300&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;policies&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Percent&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;value&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;100&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;periodSeconds&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;triggers&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;-&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;type&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;metadata&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;bootstrapServers&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0.&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;headless&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;kafka&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;svc&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;cluster&lt;/span&gt;.&lt;span style="color:#a6e22e"&gt;local&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;9092&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;consumerGroup&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;my&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;group&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Make&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sure&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;that&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;this&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;consumer&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;group&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;same&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;one&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;as&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;the&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;one&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;that&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;is&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;consuming&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;topics&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;topic&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;test&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;#&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Optional&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;lagThreshold&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;5&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;offsetResetPolicy&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;latest&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The field definitions are on KEDA deploy &lt;a href="https://keda.sh/docs/1.4/concepts/scaling-deployments/"&gt;documentation&lt;/a&gt;. Items under Kafka trigger are on the trigger &lt;a href="https://keda.sh/docs/2.6/scalers/apache-kafka/"&gt;documentation&lt;/a&gt;. In this lab we set the idelReplicaCount to 0. It will scale up with average lag of all partitions reaching 5. In the next few steps, we&amp;#8217;ll mock up some messages posted to the Kafka topic named &amp;#8220;test&amp;#8221; for consumer group my-group. We can watch deployment size grow along with the growth of lags.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To emulate Kafka client activity, we can spin up a Kafka test Pod:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl run kafka-client --restart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Never&amp;#39;&lt;/span&gt; --image docker.io/bitnami/kafka:2.8.1-debian-10-r73 --namespace kafka --command -- sleep infinity&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl exec --tty -i kafka-client --namespace kafka -- bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;From within the Pod, we can leverage the client-side scripts located in /opt/bitnami/kafka/bin/. For example, to post message to a topic (e.g. named test):&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kafka-console-producer.sh --topic test --broker-list kafka-0.kafka-headless.kafka.svc.cluster.local:9092,kafka-1.kafka-headless.kafka.svc.cluster.local:9092,kafka-2.kafka-headless.kafka.svc.cluster.local:9092 &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The Helm installer also gives the command with broker list. To consume messages from a topic (e.g. test) to a given consumer group:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kafka-console-consumer.sh --topic test --bootstrap-server kafka.kafka.svc.cluster.local:9092 --group my-group&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can have two command terminals, post test messages on one terminal and watch it consumed nearly immediately on the other terminal.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Kafka trigger &lt;a href="https://keda.sh/docs/2.6/scalers/apache-kafka/"&gt;documentation &lt;/a&gt;suggests that the number of replicas will not exceed the number of partitions on a topic when a topic is specified. To make this lab work, we need to have set 5 partitions:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kafka-topics.sh --alter --bootstrap-server kafka.kafka.svc.cluster.local:9092 --topic test --partitions &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kafka-topics.sh --describe --bootstrap-server kafka.kafka.svc.cluster.local:9092 --topic test&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once we confirm five partitions, we can spin up two command terminals, one to produce message and the other to consume messages. If working, we can stop the consumer and use the command below to watch for the lag for each partition. &lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kafka-consumer-groups.sh --bootstrap-server kafka.kafka.svc.cluster.local:9092 --describe --group my-group&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now we can artificially trigger scaling by increasing average lag. We keep posting messages on the producer (each carriage return posts a message), and we can check the lag after posting:&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large"&gt;&lt;img loading="lazy" decoding="async" width="1396" height="413" src="https://static.digihunch.com/wp-content/uploads/2022/03/image.png" alt="" class="wp-image-3884"/&gt;&lt;figcaption class="wp-element-caption"&gt;Growth of average lags&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The size of deployment starts with 0 as defined in the scaled object. As the average exceeds 5, we can see deployment size growing.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full"&gt;&lt;img loading="lazy" decoding="async" width="576" height="405" src="https://static.digihunch.com/wp-content/uploads/2022/03/image-1.png" alt="" class="wp-image-3885"/&gt;&lt;figcaption class="wp-element-caption"&gt;Growth of deployment size&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This lab is an oversimplified scenario to illustrate the idea of scaling. Kafka is a typical queue construct and other queue configuration such as RabbitMQ or AWS SQS works in very similar ways. Real life use case involves more aspects to consider, such as multiple topics, and &lt;a href="https://keda.sh/docs/2.6/concepts/authentication/"&gt;authentication&lt;/a&gt;.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-connection-triggered-wake-up"&gt;Connection triggered wake-up&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;KEDA uses Events to scale workload from zero to one (wake up). There is no way to scale (wake up) based on an incoming web request. In many cases, such as serverless configuration, we need to scale the deployment size from zero to N once the service receives incoming web request. This is not supported by KEDA. By definition KEDA uses Events to wake up. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is an &lt;a href="https://github.com/kedacore/http-add-on"&gt;HTTP-add-on&lt;/a&gt; for KEDA still at beta but it is trying to address this problem. &lt;a href="https://github.com/kedacore/http-add-on/blob/main/docs/design.md"&gt;This&lt;/a&gt; page shows the design. Suppose a service has scaled down to zero, the followings will happen to wake it up:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;The incoming request is routed to an interceptor behind the service&lt;/li&gt;&#10;&lt;li&gt;interceptor keeps track of number of pending HTTP request&lt;/li&gt;&#10;&lt;li&gt;The scaler periodically watches for the size of the pending queue on the interceptor&lt;/li&gt;&#10;&lt;li&gt;Based on the queue size, the scaler reports scaling metrics as appropriate to KEDA&lt;/li&gt;&#10;&lt;li&gt;As the queue size increases, the scaler instructs KEDA to scale up as appropriate&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The periodical check activity is the key to make it work and also what makes it a pseudo-trigger. &lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-summary"&gt;Summary&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Fine-tuning autoscaling is important to the performance of workload on Kubernetes. At node level, we briefed on cluster autoscaler and suggest that we only use it sparsely. At pod level, we introduced native HPA as well as KEDA, with an example. We also discussed KEDA has limitations and the HTTP-add-on. In the &lt;a href="https://static.digihunch.com/2022/04/knative-introduction-serving/"&gt;next &lt;/a&gt;post, we&amp;#8217;ll explore Knative&amp;#8217;s autoscaling capability.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2022/03/istio-operation-gotchas/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Istio Operation Gotchas&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2022/04/kubernetes-operator/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Operator&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Intro to Big Data Projects</title><link>https://static.digihunch.com/2020/09/intro-to-big-data-projects/</link><pubDate>Thu, 10 Sep 2020 21:33:00 -0400</pubDate><guid>https://static.digihunch.com/2020/09/intro-to-big-data-projects/</guid><description>&lt;p class="wp-block-paragraph"&gt;Modern applications produce super large datasets beyond what traditional data-processing application can handle. Big data is a discipline that specialize in processing such data. For example, analysis, information extraction etc. The scale of large dataset grows well beyond the capacity of a single computer, which calls for computing power delivered by multi-node clustered systems. Intensive computing tasks are completed in a distributed system consisting multiple nodes each performing some tasks, known as High-Performance Computing Cluster (HPCC).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Cluster computing inherit the challenges of distributed system. Moreover, two main challenges to solve are: distributed storage, and distributed computation. In Apache Hadoop projects, HDFS and MapReduce address these two challenges respectively. Now the Hadoop ecosystem has evolved to include several core projects:&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;HDFS&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A distributed file system for reliably storing huge amount of unstructured, semi-structured or structured data in the form of files. Parts of a single large file can be stored on different nodes across the cluster. HDFS works in master-slave mode:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;NameNode (master): holds file system namespace, controls access, keep track of DataNodes and replication factor &lt;/li&gt;&lt;li&gt;DataNode (slave): stores user data&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;HDFS is Java-based so is portable across all platforms. User interact with HDFS using a command-line interface called &amp;#8220;FS shell&amp;#8221;. There is also an interface called FUSE (filesystem in userspace) to mount HDFS to Linux OS. Since HDFS supports commodity hardware it is great for storing data for further processing. However, HDFS is not suitable for storing data related to applications requiring low latency access, nor is it good for simultaneous writes to the same file. Also HDFS is not suitable for large number of small files because the metadata for each file needs to be stored on the NameNode and is held in memory. &lt;a href="https://hadoop.apache.org/docs/stable1/hdfs_design.html"&gt;Here&lt;/a&gt; is the architecture guide for HDFS, and this &lt;a href="https://data-flair.training/blogs/hadoop-hdfs-data-read-and-write-operations"&gt;page&lt;/a&gt; expands further on the read and write operations in HDFS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Compared to NAS(e.g. NFS), HDFS is distributed by design. The data blocks are distributed across different nodes. NFS storage may or may not be distributed depending on the implementation. HDFS is designed to work with MapReduce paradigm, where computation is moved to the data. In NAS, data is stored separately from the computations. Lastly, NAS is usually made up of enterprise grade hard drive but HDFS works with commodity hardware.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;MapReduce&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hadoop MapRecude is a distributed algorithm framework that allows parallel processing of huge amounts of data. It breaks a large chunk into smaller ones to be processed separately on different data nodes and automatically gather the results across the multiple nodes to return a single result. If the duration of linear data processing can be done during night hours, it makes sense to choose Hadoop MapReduce. MapReduce runs on Hadoop cluster but also supports other database formats like Cassandra and HBase. MapReduce includes:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Job: a unit of work to be performed as requested by the client.&lt;/li&gt;&lt;li&gt;Task: Jobs are divided into sub-jobs known as tasks. The tasks can be run independent of each other on different nodes. There are two types of tasks: &lt;ul&gt;&lt;li&gt;Map task is performed by map() function to process one or more chunks of data and produce the output results&lt;/li&gt;&lt;li&gt;Reduce task is performed by reduce() function to consolidate the results produced by each of the map task&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;JobTracker: like the storage (HDFS), the computation (MapReduce) also works in master-slave fashion. A JobTracker node acts as the master to schedule task on appropriate nodes, coordinate execution of tasks, get the result back after execution of each task, re-execute failed tasks, and monitor overall progress. There is only one JobTracker node per Hadoop Cluster.&lt;/li&gt;&lt;li&gt;TaskTracker: a TaskTracker node acts as teh slave and is responsible for executing a task assigned to it by the JobTracker. There are usually a number of JobTracker nodes in a Hadoop Cluster. They execute the heavy lifting tasks.&lt;/li&gt;&lt;li&gt;Data Locality: if MapReduce cannot place the data and the compute on the same node, data locality put the compute on the node nearest to the respective data node(s) which contains the data to be processed.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The MapReduce programming model includes these steps: input-&amp;gt;split-&amp;gt;map-&amp;gt;combine-&amp;gt;shuffle&amp;amp;sort-&amp;gt;reduce-&amp;gt;output.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://ars.els-cdn.com/content/image/3-s2.0-B9780128093931000064-f06-04-9780128093931.jpg?_" alt=""/&gt;&lt;figcaption&gt;MapReduce programming model&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading"&gt;YARN&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;YARN (yet another resource negotiator) is a system to schedule applications and services on an HDFS cluster and manage the cluster resources like memory and CPU. The two components are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;ResourceManager: receives the processing requests, and then passes the parts of requests to corresponding NodeManager accordingly based on the needs. ResourceManager is a central authority.&lt;/li&gt;&lt;li&gt;NodeManager: installed on every DataNode, is responsible for execution of the task on every single DataNode, monitoring the resource usage and reporting to the ResourceManager.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading"&gt;HBase&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A key-value pair NoSQL database based on HDFS storage, with column family data representation, and mater-slave replication. HBase is based on Google&amp;#8217;s BigTable concept (similar to Cassandra). It runs on a cluster of commodity hardware and scales linearly. Compared with Cassandra, HBase doesn&amp;#8217;t have a query language of its own. You will have to work with JRuby-based shell, or Apache Hive. HBase is also a master-slave architecture and it uses Zookeeper as a status manager. In that sense, Cassandra is a &amp;#8220;self-sufficient&amp;#8221; database technology whereas HBase relies on other components in Hadoop. This &lt;a href="https://www.scnsoft.com/blog/cassandra-vs-hbase"&gt;article&lt;/a&gt; also compares the data model difference between the two.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Hive&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hive is a SQL interface over MapReduce for developers and analysts who prefer SQL interface over native Java MapReduce programming to query and manage large datasets residing in HDFS. With Hive you can map a tabular structure on to data stored in distributed storage. The Hive queries are written in SQL-like language known as HiveQL, executed via MapReduce. When a HiveQL query is issued, it triggers a Map and/or Reduce job(s) to perform the operation defined in the query.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Pig&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A scripting interface over MapReduce for developers who prefer scripting interface over the native Java MapReduce programming. It is a runtime environment with a shell (named &lt;strong&gt;Grunt Shell&lt;/strong&gt;) for execution of MapReduce jobs via a high-level scripting language called Pig Latin. Pig is an abstraction (high-level programming language) on top of a Hadoop cluster. The Pig Latin query/command are complied into one or more MapReduce jobs and then executed on Hadoop cluster. The most common commands in Pig are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;DUMP: displays the results to screen&lt;/li&gt;&lt;li&gt;STORE: stores the results to HDFS&lt;/li&gt;&lt;/ul&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://2.bp.blogspot.com/-w7KeAnwWnBQ/WfYBJzgtvQI/AAAAAAAAAMk/D58SpZfK7lkJ8QnKnQZW268mKzRvuOOnACLcBGAs/s640/HadoopStack.png" alt="Apache Hadoop Ecosystem"/&gt;&lt;figcaption&gt;Hadoop Ecosystem&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are some other Apache projects, which are sometimes considered as in the Hadoop ecosystem as well:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;Oozie&lt;/strong&gt;: worflow scheduling system to manage Hadoop jobs. In Oozie, a workflow is defined as a collection of control flow nodes and action nodes in a directed acyclic graph. Control flow nodes define the beginning and the end of a workflow, as well as a mechanism to control the workflow execution path. Action nodes are the mechanism by which a workkflow triggers the execution of a computation/processing task, such as MapReduce, Pig, etc.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Sqoop&lt;/strong&gt; (SQL-to-Hadoop): a command-line interpreter tool for importing data from database (e.g. MySQL, data warehouse, etc) into the Hadoop environment (e.g. HDFS, Hive). It can also export the data back.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Flume&lt;/strong&gt;: data ingestion for streaming logs into Hadoop environment. Flume is a distributed and reliable service for collecting and aggregating huge amounts of log data.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;ZooKeeper&lt;/strong&gt;: distributed service coordinator, as previously &lt;a href="https://static.digihunch.com/2020/08/zookeeper/"&gt;discussed&lt;/a&gt;. It is based on a Paxos algorithm variant called ZAB protocol.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Ambari&lt;/strong&gt;: a framework for provisioning, managing and monitoring Hadoop clusters.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hortonworks &lt;a href="https://www.cloudera.com/downloads/hortonworks-sandbox.html"&gt;sandbox&lt;/a&gt; provide a VM image that have some Hadoop services pre-installed for beginners to get a taste of how it works all together.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Spark&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hadoop is used in the industry owing to a simple programming model (MapReduce) but the speed and waiting time (between queries and running the program). Spark is introduced to speed up the computing process. Spark uses Hadoop for storage (HDFS) and processing. It extends the MapReduce model to efficiently use more types of computations which includes interactive queries and stream processing. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Spark started as a sub-project of Hadoop in 2009 but since 2014 Apache has run it as a top-level project. It is a lightning-fast in-memory cluster computing technology. The features are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Speed: in-memory computing makes super fast processing;&lt;/li&gt;&lt;li&gt;Built-in APIs supports multiple languages: Scala, Python and Java;&lt;/li&gt;&lt;li&gt;Advanced analytics &amp;#8211; apart from map and reduce, Spark also has libraries that supports SQL query, near real-time stream processing, Graph algorithms and machine learning.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Spark can run in &lt;a href="https://spark.apache.org/docs/latest/spark-standalone.html"&gt;standalone mode&lt;/a&gt;, on &lt;a href="https://spark.apache.org/docs/latest/running-on-mesos.html"&gt;Mesos&lt;/a&gt;, or with &lt;a href="https://spark.apache.org/docs/latest/running-on-yarn.html"&gt;YARN cluster manager&lt;/a&gt;. The document also provides guide on deployment on EC2 and &lt;a href="https://spark.apache.org/docs/latest/running-on-kubernetes.html"&gt;Kubernetes&lt;/a&gt;. Spark contains these components:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Spark Core: the underlying general execution engine for spakr platform that all other functionality is built upon. It provides in-memory computing and referencing datasets in external storage systems.&lt;/li&gt;&lt;li&gt;SparkSQL: a components on top of Spark Core that introduces a new data abstraction called SchemaRDD, which supports both structured and semi-structured data.&lt;/li&gt;&lt;li&gt;Spark Streaming: perform streaming analytics on top of Spark Core. It ingests data in mini-batches and performs RDD (Resilient Distributed Datasets) transformation on the fly.&lt;/li&gt;&lt;li&gt;MLib: a distributed machine learning framework &lt;/li&gt;&lt;li&gt;GraphX: a distributed graph-processing framework&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The speed of Spark is owing to its fundamental data structure &amp;#8211; Resilient Distributed Datasets (RDD), an immutable distributed collection of objects. Each dataset in RDD (object collection) is divided into logical partitions, which can be computed on different nodes of the cluster. The object can be any type of Python, Java or Scala object, including user-defined classes. There are two ways to create RDDS:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Parallelizing an existing collection in your driver program&lt;/li&gt;&lt;li&gt;Referencing a dataset from external storage system (e.g. HDFS, HBase) or data source offering a Hadoop Input Format&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can also create RDD based on other existing RDDs. This &lt;a href="https://www.tutorialspoint.com/apache_spark/apache_spark_rdd.htm"&gt;page&lt;/a&gt; explains further how RDD speeds up computing compared to MapReduce.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/09/host-legacy-application-with-docker-compose/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Host legacy application in Docker 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/09/spark-cassandra-and-python/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Spark, Cassandra and Python&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Zookeeper Summary</title><link>https://static.digihunch.com/2020/08/zookeeper/</link><pubDate>Wed, 26 Aug 2020 23:10:00 -0400</pubDate><guid>https://static.digihunch.com/2020/08/zookeeper/</guid><description>&lt;h3 class="wp-block-heading" id="h-distributed-systems"&gt;Distributed systems&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Distributed system involves &lt;span style="text-decoration: underline;"&gt;independent computing entities&lt;/span&gt; linked together by network. The components &lt;span style="text-decoration: underline;"&gt;communicate and coordinate&lt;/span&gt; with each other to achieve a &lt;span style="text-decoration: underline;"&gt;common goal&lt;/span&gt;. In early days, designers and developers often had made some assumptions (aka. fallacies) of distributed computing:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;The network is reliable&lt;/li&gt;&#10;&lt;li&gt;Latency is zero&lt;/li&gt;&#10;&lt;li&gt;Bandwidth is infinite&lt;/li&gt;&#10;&lt;li&gt;Network is secure&lt;/li&gt;&#10;&lt;li&gt;Topology doesn&amp;#8217;t change: in reality, components to a network get removed/added over time. the system should tolerate such changes.&lt;/li&gt;&#10;&lt;li&gt;There is one administrator: for distributed systems to function, they interact with external system beyond administrative control.&lt;/li&gt;&#10;&lt;li&gt;Transport cost is zero:&amp;nbsp; cost is involved everywhere, in the form of CPU cycles spent, to actual dollars paid to service provider.&lt;/li&gt;&#10;&lt;li&gt;Network is homogenous&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These fallacies make coordinating distributed computing entities a huge challenge and Zookeeper is introduced to address these challenges. Zookeeper implements common tasks for distributed coordination, such as:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Configuration Management (propagate configuration changes to all worker nodes dynamically)&lt;/li&gt;&#10;&lt;li&gt;Naming service&amp;nbsp;&lt;/li&gt;&#10;&lt;li&gt;Distributed synchronization (locks and barriers)&lt;/li&gt;&#10;&lt;li&gt;Cluster membership operations (e.g. detection of node leave/join)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ZooKeeper is a centralized coordination service for the distributed application. ZooKeeper itself is distributed as well. It runs on its own cluster of servers called a ZooKeeper ensemble, separate from application&amp;#8217;s cluster. Distributed consensus, group management, presence protocols, and leader election are implemented by the service so that the application developers do not need to reinvent the wheel by implementing them on their own.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://zookeeper.apache.org/doc/r3.6.1/images/zkservice.jpg" alt="ZooKeeper Service"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Developers will have to use APIs through ZooKeeper&amp;#8217;s client library, which has language bindings for almost all popular programming languages. The client library is responsible for the interactions of an application with the ZooKeeper service. For testing with API access one can alternatively use its Java-based command-line shell (zkCli.sh)&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ zkCli.sh -server zknode:2181&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 class="wp-block-heading" id="h-how-zookeeper-works"&gt;How Zookeeper works&lt;/h3&gt;&#10;&lt;h4 class="wp-block-heading" id="h-data-model"&gt;Data Model&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ZooKeeper allows distributed process to coordinate with each other through a shared hierarchical namespace of data registers (znodes). The hierarchy start with root node which has child znode(s). Each znode can have their children, as well as store its own data (hence the name data register). The data in a znode is stored in byte format for a maximum of 1MB (ZooKeeper by design is just a coordinator service of host application, so its own data set size is fairly small).&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="360" height="368" src="https://static.digihunch.com/wp-content/uploads/2023/01/zkdm.jpeg" alt="" class="wp-image-7753" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/zkdm.jpeg 360w, https://static.digihunch.com/wp-content/uploads/2023/01/zkdm-293x300.jpeg 293w" sizes="auto, (max-width: 360px) 100vw, 360px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Zookeeper data model&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Znodes have two types (set at time of creation) &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;persistent znode: for storing persistent data, such as configuration. The znodes and their data will exist even if the creator client dies.&lt;/li&gt;&#10;&lt;li&gt;ephemeral znode: deleted by ZooKeeper service when the creating client&amp;#8217;s session ends (due to disconnection or explicit termination). It can also be explicitly deleted by creator client through delete API call. They cannot have children. Their visibility is controlled by ACL policy&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ZooKeeper can assign an incremental sequence number as part of znode name during its creation. This makes a sequential node. Both persistent znode and ephemeral znode can be either sequential or not.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In typical client-server architecture, server is passively open and do not initiate communication to client. Client pulls information from server. This is however an anti-pattern for large scale distributed system. ZooKeeper implements a Watch mechanism where clients can get notifications from ZooKeeper service, instead of having to poll for events. Clients can register with the ZooKeeper service (by setting a watch on znode) for any changes associated with a znode. A watch will only trigger notification once, and needs to be re-registered (by client) for trigger the next notification. A watch is triggered upon:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Any changes to the data of a znode;&lt;/li&gt;&#10;&lt;li&gt;any changes to the children of a znode;&lt;/li&gt;&#10;&lt;li&gt;Creation of deletion of a znode&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ZooKeeper guarantees that notifications are delivered in the order of event occurrence. When a client disconnects from ZooKeeper server, it doesn&amp;#8217;t receive any watches until the connection is re-established. &lt;/p&gt;&#10;&lt;h4 class="wp-block-heading" id="h-api-operations"&gt;API Operations&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The ZooKeeper operations are:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Operation&lt;/td&gt;&lt;td&gt;Description&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;create&lt;/td&gt;&lt;td&gt;Creates a znode in the specified path&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;delete&lt;/td&gt;&lt;td&gt;Deletes a znodes from the specified path. Not allowed if the znode has children. version number required&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;exists&lt;/td&gt;&lt;td&gt;Check if a znode at the specified path exists, and get version number; support watch&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;getChildren&lt;/td&gt;&lt;td&gt;Get a list of children of a znode; support watch&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;getData&lt;/td&gt;&lt;td&gt;get the data associated with a znode; support watch&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;setData&lt;/td&gt;&lt;td&gt;writes data into the data field of a znode. Version number required.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;getACL&lt;/td&gt;&lt;td&gt;get the ACL of a znode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;setACL&lt;/td&gt;&lt;td&gt;set the ACL in a znode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;sync&lt;/td&gt;&lt;td&gt;synchronizes a client&amp;#8217;s view of a znode &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The write operations (setData, create, delete) are atomic, durable and eventually consistent. Every znode has a stat structure including cZxid, mZxid an dpZxid that keeps track of the ID of the transactions that created, last modified this znode, or pertains to adding or removing its children.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Production znode ensemble with more than one node is running in quorum mode. Updates to ZooKeeper tree by clients must be persistently stored in this quorum of nodes for a transaction to be completed successfully. Odd number of node is recommended to avoid split-brain where network partition causes two subsets of servers in the ensemble function independently, and different clients get different results for the same requests, depending upon the server they are connected to.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All ZooKeeper nodes are listed in the configuration for client application to randomly pick from and try to connect and establish a session. The session is associated with every operation the client executes in a ZooKeeper service. The session also has a timeout period specified by the application client during session establishment. If the connection remains idle for more than the timeout period, the server expires the session. Appropriate session timeout should be set based on network condition. Sessions are kept alive by client sending heartbeat to ZooKeeper service. Application developer needs to handle connection-loss scenarios properly.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading" id="h-leader-election-and-atomic-broadcast"&gt;Leader Election and Atomic Broadcast&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ZooKeeper ensemble contains a leader nodes, follower nodes and observer nodes.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;The leader node is elected by the cluster. It handles all write requests. &lt;/li&gt;&#10;&lt;li&gt;The follower nodes are leader candidates that are not elected. They are backup to the leader nodes. They handle read request, and receive the updates proposed by the leader, and through a majority consensus mechanism, a consistent state is maintained across the ensemble. &lt;/li&gt;&#10;&lt;li&gt;The observer nodes are ineligible as leader candidates. They have otherwise the same function as followers.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The service relies on the replication mechanism to ensure that all updates are persistent in all servers that constitute the ensemble. This is the core mechanism in ZooKeeper, implemented as a special atomic messaging protocol called ZooKeeper Atomic Broadcast (ZAB). ZAB (a variant of Paxos algorithm) ensures the election of new leader in the event of old leader crash, and ensures integrity of data. It defines three states (looking, following and leading) of a node, and goes through four phases (election, discovery, sync, broadcast) in its operation.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All read requests (exists, getData, getChildren) are process locally by the ZooKeeper node where the client is connected to. This makes read operation fast. All write requests (create, delete, and setData) are forwarded to the leader in the ensemble, which carries out the client request as a transaction. A transaction is identified by zxid and is idempotent. Transaction also satisfies the property of isolation (no transaction is interfered with by any other transaction). Only after a majority of the followers acknowledge that they have persisted the change does the leader commit the update.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://zookeeper.apache.org/doc/r3.6.1/images/zkcomponents.jpg" alt="ZooKeeper Components"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Transaction processing involves two steps in ZooKeeper: leader election and atomic broadcast. This resembles a two-phase commit protocol (which also includes a leader election and an atomic broadcast)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ZooKeeper use local storage to persist transactions. The transactions are logged to transaction logs, in sync&amp;#8217;ed write, requiring a dedicated block device separated from boot device of server. The local storage also keep point-in-time copies (snapshots) of the ZooKeeper tree.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-zookeeper-recipes"&gt;ZooKeeper Recipes&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The ZooKeeper recipes defines high-level implementation (construct) of some common distributed coordination mechanism:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Barrier_(computer_science)"&gt;Barrier&lt;/a&gt;: any thread/process must stop at this point and cannot proceed until all other threads/processes reach this barrier.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://computersciencewiki.org/index.php/Queue"&gt;Queue&lt;/a&gt;: allow FIFO in distributed system&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Lock_(computer_science)"&gt;Lock&lt;/a&gt;: Fully distributed locks that are globally synchronous, meaning at any snapshot in time no two clients think they hold the same lock.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Leader_election"&gt;Leader Election&lt;/a&gt;: designate a single process as the organizer of some task distributed among several nodes.&lt;/li&gt;&#10;&lt;li&gt;Group membership: node may join or leave a group, which needs to be made available to clients. An alternative to ZooKeeper to manage group membership is &lt;a href="https://en.wikipedia.org/wiki/Gossip_protocol"&gt;gossip protocol&lt;/a&gt;.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="http://jasonwilder.com/blog/2014/02/04/service-discovery-in-the-cloud/"&gt;Service discovery&lt;/a&gt;: help client to determine IP and port for a service that are hosted by multiple servers.&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Two-phase_commit_protocol"&gt;Two-phase commit&lt;/a&gt;: a mechanism for atomic commitment in two steps: first a commit request phase involving a voting by participants; and second, either a commit action, or an abort action, based on the voting result.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading" id="h-zookeeper-administration"&gt;Zookeeper Administration&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The official &lt;a href="https://zookeeper.apache.org/doc/r3.6.1/zookeeperAdmin.html"&gt;documentation&lt;/a&gt; includes all we need to know about administration. In addition, we need to configure &lt;a href="https://logging.apache.org/log4j/1.2/manual.html"&gt;log4j&lt;/a&gt; for proper logging. As best practices, we also should turn off &lt;a href="https://static.digihunch.com/2018/04/centos-remove-swap-safely/"&gt;swapping&lt;/a&gt; on ZooKeeper. We should clean up the data directory periodically if auto purge is not enabled. For optimal performance, ZooKeeper transaction log should be configured in a dedicated device.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For monitoring, ZooKeeper responds to a small sets of four-letter commands issued through telnet or nc to server&amp;#8217;s client port. This allows the admin to check health of server or diagnose any problems. This requires the following property in zoo keeper config:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4lw.commands.whitelist=stat, ruok, conf, isro, wchc&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The value can be set to asterick to allow all four-letter keyword. Once enabled, we can check server status&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ echo ruok | nc localhost &lt;span style="color:#ae81ff"&gt;2181&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;imok&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;More four-letter commands are listed &lt;a href="https://zookeeper.apache.org/doc/r3.1.2/zookeeperAdmin.html#sc_zkCommands"&gt;here&lt;/a&gt;. Apart from the four-letter commands, ZooKeeper can also be managed through Java Management Extensions (&lt;a href="https://www.oracle.com/java/technologies/javase/javamanagement.html"&gt;JMX&lt;/a&gt;).&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apache ZooKeeper is a coordination service for distributed application. It has become the solution for high availability for many other projects. Some of Apache&amp;#8217;s well known open-source distributed services include:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Apache Hadoop (an umbrella of projects including many components for BigData processing such as Hadoop Common, Hadoop Distributed File System (HDFS), Hadoop YARN (yet another resource negotiator) and Hadoop MapReduce)&lt;/li&gt;&#10;&lt;li&gt;Apache HBase: non-relational database on top of HDFS&lt;/li&gt;&#10;&lt;li&gt;Apache Hive: data warehouse with SQL-like interface&lt;/li&gt;&#10;&lt;li&gt;Apache Kafka: stream processing&lt;/li&gt;&#10;&lt;li&gt;Apache Nifi: automated data flow processing. &lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Some of them, such as Nifi, has an embedded implementation of ZooKeeper ensemble if there isn&amp;#8217;t a separate ensemble. There is some limitation with embedded Zookeeper ensemble. First, we cannot start ZooKeeper without starting Nifi service on the same server. Second, we need to orchestrate the configuration so that the ZooKeeper ensemble does not grow too large. We need to keep in mind that the ZooKeeper ensemble is a separate cluster of its own, and the it is not recommended to have more than 7 nodes on ZooKeeper.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/08/virtualization-4-of-4-networking/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 4 of 4 – Networking&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/09/host-legacy-application-with-docker-compose/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Host legacy application in Docker 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Kafka high-level Overview</title><link>https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/</link><pubDate>Tue, 21 Jul 2020 23:19:00 -0400</pubDate><guid>https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/</guid><description>&lt;h3 class="wp-block-heading" id="h-zookeeper"&gt;Zookeeper&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;General definition of distributed system: a software system that is composed of &lt;strong&gt;independent &lt;/strong&gt;computing entities linked &lt;strong&gt;together &lt;/strong&gt;by a computer network whose components communicate and coordinate with each other to achieve a common computational goal. Implementing coordination among components of a distributed system is hard. For example, designated master node becomes single point of failure; cluster needs to detect availability of new nodes as it joins cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Zookeeper is designed to &lt;strong&gt;simplify cluster coordination&lt;/strong&gt;. Zookeeper implements key aspects in cluster coordination, such as distributed consensus, group management, presence protocols and leader election. In order to coordinate a cluster, zookeeper itself also runs in its own cluster, called &lt;strong&gt;ensemble&lt;/strong&gt;. Zookeeper exposes a simple but powerful interface of primitives. Applications can be designed on these primitives implemented through ZooKeeper APIs to solve the problems of distributed synchronization, cluster configuration management, group membership, etc.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://zookeeper.apache.org/doc/r3.4.6/images/zkservice.jpg" alt=""/&gt;&lt;figcaption class="wp-element-caption"&gt;Zookeeper Ensemble&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Clients can connect to a Zookeeper service by connecting to any member of the ensemble. The members of the ensemble are aware of each other&amp;#8217;s state. As long as a majority of the nodes are available, the service will be available. &lt;strong&gt;Zookeeper cli (zkCli.sh)&lt;/strong&gt; can be used to connect to Zookeeper server. they can be downloaded from &lt;a href="https://zookeeper.apache.org/releases.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Zookeeper is integrated with many other services apart from Kafka, such as Nifi and Hadoop.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-kafka"&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://kafka.apache.org/"&gt;Kafka &lt;/a&gt;is a messaging system that is horizontally scalable, fault tolerant. It can also serve as queue storage system and stream processing system. It is distributed and use Zookeeper for cluster coordination. Each node is called a broker.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://kafka.apache.org/25/images/log_anatomy.png" alt=""/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Topics &lt;/strong&gt;in Kafka (think of table in database) is a category or feed name to which messages (records) are published. Topic is broken up into ordered commit logs called partitions. Each partition has an ID. Each message in a partition is assigned an offset. Topics that are created in Kafka are distributed across brokers based on the partition, replication, and other factors. Each partition is replicated across several brokers depending on replication factor. For each partition, Kafka elect one replica as the leader of partition.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Writes to a partition is generally sequential. Reading messages can either be from the beginning, or rewind or skip to any port in partition given an offset value. Data in a topic is retained for a configurable period of time. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;strong&gt;message &lt;/strong&gt;is a unit of data in Kafka, in the format of key-value pair. A key is used to control the message that is to be written to partitions. Messages with the same keys are always written to the same partition (hash map)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;strong&gt;producer &lt;/strong&gt;publishes new message to a topic. Producers do not care which partition the message is written to and will balance messages over every partition of a topic evenly. Directing messages to a partition is done using the message key and a partitioner, this will generate a hash of the key and map it to a partition.&lt;/p&gt;&#10;&lt;figure class="wp-block-image is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://kafka.apache.org/25/images/log_consumer.png" alt="" width="370" height="225"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;strong&gt;consumer &lt;/strong&gt;is subscribed to one or more topics and read messages sequentially. The consumer keeps track of messages it has consumed by keeping track on the offset of the message. The offset is a bit of metadata (an integer value that continually increases) that kafka adds to each message. Each partition has a unique offset which is stored with the offset of the last consumed message. A consumer can stop and start without losing its current state.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A Kafka &lt;strong&gt;broker &lt;/strong&gt;is designed to operate as part of a cluster. One broker in the cluster also function as the cluster&amp;#8217;s controller, which is responsible for administrative operations such as: assigning partitions to brokers; monitoring for broker failures in cluster. A particular partition is owned by a broker and that broker is called the leader of the partition.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All consumers and producers operating on that partition must connect to the leader.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Kafka cluster may replicate across cluster using MirrorMaker.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Reference: &lt;strong&gt;Kafka: The Definitive Guide: Real-Time Data and Stream Processing at Scale&lt;/strong&gt;&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2023/01/kafka-780x1024.jpeg" alt="" class="wp-image-7913" width="207" height="272" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/kafka-780x1024.jpeg 780w, https://static.digihunch.com/wp-content/uploads/2023/01/kafka-229x300.jpeg 229w, https://static.digihunch.com/wp-content/uploads/2023/01/kafka-768x1008.jpeg 768w, https://static.digihunch.com/wp-content/uploads/2023/01/kafka.jpeg 1036w" sizes="auto, (max-width: 207px) 100vw, 207px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt; &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/07/nfs-network-file-system-and-rpc-remote-procedure-call/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;How RPC and NFS work&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/07/overview-of-virtualization/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 1 of 4 – Hypervisor&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>