<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Natan Silnitsky on Medium]]></title>
        <description><![CDATA[Stories by Natan Silnitsky on Medium]]></description>
        <link>https://medium.com/@natansil?source=rss-32e883029628------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*o0yUSQpD5IgMjD1jD_Fm6g.jpeg</url>
            <title>Stories by Natan Silnitsky on Medium</title>
            <link>https://medium.com/@natansil?source=rss-32e883029628------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 03:21:49 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@natansil/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[50x Faster and 100x Happier: How Wix Reinvented Integration Testing]]></title>
            <link>https://natansil.medium.com/50x-faster-and-100x-happier-how-wix-reinvented-integration-testing-065439276f1a?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/065439276f1a</guid>
            <category><![CDATA[integration-testing]]></category>
            <category><![CDATA[testing]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[hexagonal-architecture]]></category>
            <category><![CDATA[mocking]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sat, 28 Jun 2025 18:33:08 GMT</pubDate>
            <atom:updated>2025-06-28T18:33:08.283Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/720/1*a13yIaltmagL8O3ukUkABg.jpeg" /></figure><p><strong>Why Tests Matter in Software Engineering</strong><br>Integration tests are essential for verifying real-world interactions between system components. However, running and maintaining them — especially with Docker-based setups — often leads to slow feedback, flakiness, and complex configuration headaches.</p><p><strong>Wix engineers tackled this challenge</strong> and developed a new approach that cuts testing time by more than 50x, all while streamlining the workflow for developers.</p><h3>Highlights from the Wix Solution</h3><ul><li><strong>In-Memory Integration Testing:</strong><br>Wix replaced external dependencies (like databases and RPC services) with in-memory implementations for testing. This avoids slow Docker containers, reduces infrastructure overhead, and increases reliability.</li><li><strong>Hexagonal Architecture:</strong><br>Business logic is decoupled from infrastructure concerns using well-defined ports and adapters. This makes it simple to switch between real and in-memory collaborators in tests, preserving the consistency between test and production code.</li><li><strong>App Context Builder:</strong><br>Dependency wiring is managed automatically, ensuring test environments stay in sync with production without extra developer effort.</li></ul><h3>Benchmarks and Impact</h3><ul><li>Nearly 100% of new Wix integration tests now use this method.</li><li>Feedback cycles are much shorter, making it easier to detect and fix issues early.</li><li>Flakiness and configuration errors common in Docker-based tests are largely eliminated.</li></ul><h3>Read the Full Engineering Deep-Dive</h3><p>Curious about the architectural patterns, implementation details, and performance benchmarks behind this approach?</p><p><strong>Check out the full engineering post here:</strong><br><a href="https://bo.wix.com/wixchat?chatId=e661b47a-23f8-47ad-9e77-c5302c2b644e#">50x Faster and 100x Happier: How Wix Reinvented Integration Testing</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=065439276f1a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Scaling Horizons: Effective Strategies for Wix’s Scaling Challenges]]></title>
            <link>https://medium.com/wix-engineering/scaling-horizons-effective-strategies-for-wixs-scaling-challenges-29ab44b2d5b4?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/29ab44b2d5b4</guid>
            <category><![CDATA[sharding]]></category>
            <category><![CDATA[hash-keys]]></category>
            <category><![CDATA[routing]]></category>
            <category><![CDATA[vertical-scaling]]></category>
            <category><![CDATA[horizontal-scaling]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sun, 28 Jul 2024 13:40:57 GMT</pubDate>
            <atom:updated>2024-07-29T05:11:46.228Z</atom:updated>
            <content:encoded><![CDATA[<p>Have you ever faced the challenge of scaling your services and databases as demand skyrockets? If <a href="https://www.nops.io/blog/horizontal-vs-vertical-scaling">vertical scaling</a> has led you to resource bottlenecks, service downtime, and potential revenue loss, you’re not alone. And what about when a single tenant’s activity throws the entire system off balance, causing outages and stability issues?</p><p>Scaling a platform as expansive as Wix is no small feat. As a leading website-building platform catering to millions of users globally, the need to handle enormous traffic and vast datasets is ever-growing. Today, we delve into the battle-tested strategies Wix employs to tackle these scaling challenges and ensure a smooth, reliable service for our users.</p><p>By the end of this article, you’ll have a clearer understanding of which strategies might work best for your own use-case.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*9IRl4PKSJV8f1PlHg2yBOw.jpeg" /></figure><h3>A Glimpse into Wix’s Scale</h3><p>To understand the magnitude of our operations:</p><ul><li>Our system comprises<strong> 4,000 microservices</strong></li><li>We handle <strong>4 billion HTTP transactions daily</strong></li><li>We produce <strong>70 billion Kafka messages every day</strong></li><li>Our systems manage over <strong>4 petabytes of data</strong></li></ul><p>Operating at such a colossal scale inherently comes with unique challenges. Our infrastructure must not only accommodate today’s demands but also scale to meet future growth as more users join our platform.</p><h3>Vertical vs. Horizontal Scaling</h3><p>When it comes to microservices scaling, there are two basic options:</p><ul><li><strong>Vertical Scaling (Scaling Up</strong>): Increasing the power of an existing machine by adding more CPU, RAM, etc.</li><li><strong>Horizontal Scaling (Scaling Out)</strong>: Expanding the system by adding more machines to handle the load.</li></ul><p>Initially, vertical scaling might seem straightforward. However, real-world constraints quickly emerge, such as bottlenecks and escalating costs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/974/0*qiT8-CkEvhGa5EG9" /></figure><p>For instance, our Redis machine used by our rate limiting service frequently hit 100% CPU utilization. This caused disruptions and triggered fallbacks to simpler algorithms. Despite upgrading to more powerful CPUs multiple times, we still faced these issues.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JOdUl0EwGCjMLnzC" /></figure><p>This clearly illustrates the limitations of vertical scaling. At a certain point of higher traffic loads, all Redis users need to move to a cluster of Redis machines, i.e., horizontally scale Redis usage.</p><h3>The Horizontal Scaling Paradigm</h3><p>To effectively manage our scaling needs, we’ve shifted towards horizontal scaling. This approach involves distributing workloads across multiple machines, significantly enhancing system responsiveness and reliability.</p><p>It’s more efficient for distributing traffic and preventing bottlenecks, but it requires complex management to ensure coherent operation across all machines. Horizontal scaling requires careful selection of routing/sharding keys (how data is managed and routed).</p><h3>Routing and Sharding Strategies</h3><p>Efficient data management across different nodes requires effective routing and sharding strategies. These strategies aim for uniform data distribution and consistency, thereby reducing latency and boosting overall performance by distributing data and queries effectively.</p><h4>Fixed Routing</h4><p>In fixed routing, data or traffic is assigned to specific shards or paths based on predefined keys. This method helps maintain consistency and predictability.</p><h4>Dynamic Routing</h4><p>Dynamic routing adjusts the distribution of data or traffic on-the-fly based on custom rules or mathematical functions. This method offers flexibility and scalability, particularly for applications with fluctuating demand. For instance, we employ hashing functions to achieve uniform distribution in a consistent manner.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/491/0*7GjDMkoGrQAmEaVj" /></figure><h3>Highlighting Wix Scaling Examples</h3><p>As Wix scales, we face various challenges in managing high loads, ensuring reliability, and maintaining performance consistency across different services. Here’s how we address these challenges with our routing and sharding key selection strategies:</p><h4><strong>1. Kafka Infra Services Fixed-Key Scaling Strategies</strong></h4><p>Wix operates multiple proxy services that handle Kafka traffic. Here, we will focus on two critical services: the Wix Kafka consumer proxy, which caches messages and reduces broker connections for improved efficiency and performance, and Wix’s Kafka-to-HTTP-webhooks translation service, which exposes events to external apps running on the Wix platform.</p><p>Managing high volumes of Kafka traffic through these services presents significant challenges:</p><p><strong>Pain Points:</strong></p><ul><li><strong>Single Points of Failure:</strong> An issue with even one Kafka connection can potentially bring down the entire service, as the impact can be significant in a single service deployment. This includes issues like CPU or memory exhaustion, which can propagate and affect overall service performance.</li><li><strong>Noisy Neighbors:</strong> Maintaining high reliability and performance for each individual tenant is challenging when all service instances handle requests from all tenants, making it difficult to isolate issues impacting one tenant from affecting others.</li></ul><p><strong>Our Solutions:</strong></p><p>To tackle these issues, we implement horizontal scaling with straightforward <strong>fixed-keys</strong> traffic routing:</p><ul><li><strong>Fixed Clusters Keys Routing:</strong> We deploy consumer proxies for each Kafka cluster. This strategy avoids single points of failure by ensuring efficient message consumption and distributing the load evenly among consumers.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*c8k3RwD1hmfmWNww" /></figure><ul><li><strong>Fixed QoS Groups Keys Routing on Kafka Dimension:</strong> Our Kafka-to-HTTP-webhooks translation system uses QoS tiers to segment data. By doing so, we ensure that higher QoS tenants maintain reliability even when other segments experience frequent timeouts.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Jwop4Kcy5GFPw3Fy" /></figure><p>Currently, this fixed-keys traffic routing method effectively ensures high availability and performance for all tenants. However, we are considering introducing more dynamic key selections based on live metrics such as traffic and latency to further enhance our capabilities if needed in the future.</p><h4><strong>2. Web Traffic Management</strong></h4><p><strong>Fixed Segments:</strong> At Wix, web traffic is divided into two fixed segments: <br>the Editor segment (site editing and business management) and the Public segment (serving sites to visitors). This decoupling — driven by the need to transform data structures during the publishing process — allows us to tailor service levels for different functions.</p><p>The Public segment, affecting all users, demands the highest service levels regarding availability, performance, risk of change, and recovery time. The Editor segment, impacting fewer users, can operate with lower service levels, allowing for greater agility.</p><p><strong>Dynamic Routing:</strong> Load balancers dynamically route traffic across multiple servers. For instance, nginx routes *.wix.com traffic to the Editor segment and wixsite.com or user domains to the Public SSR segment. This ensures efficient web request management and seamless performance during traffic spikes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/990/0*k1jXaBUzXOlTVJXY" /></figure><h4>3. Reactions App Using Kafka &amp; DynamoDB to Scale</h4><p>Reactions are a key feature for social interaction on Wix sites and mobile apps, including likes, stars, thumbs up, comments, and more. To support millions of users, the system needs to be fast, reliable, and scalable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/517/0*jhivBRmUTQoHkcQU" /></figure><p>Here’s how we address the key design considerations:</p><ul><li><strong>High Write Throughput:</strong> Many users will post reactions simultaneously, requiring a system that can handle a high volume of concurrent writes.</li><li><strong>Low Latency Reads:</strong> Users expect to see reactions in real-time, necessitating a system that provides immediate feedback.</li><li><strong>Scalability:</strong> As Wix grows, the reactions system must scale seamlessly to accommodate increasing loads.</li></ul><p><strong>Dynamic Routing on Kafka Dimension <br></strong>For the Reactions app, we use Kafka’s partitioning and message-handling capabilities to manage high loads efficiently.</p><ul><li><strong>Partitioning</strong>: Divides topics for parallel processing and horizontal scaling.</li><li><strong>Performance &amp; Durability</strong>: Ensures high throughput, low latency, and reliable data storage.</li><li><strong>Order Guarantee</strong>: Maintains event order within each partition.</li><li><strong>Scalability</strong>: Sharding patterns and increasing partitions enable seamless growth.</li><li><strong>Dynamic Message Routing</strong>: Messages are dynamically produced to different partitions based on their keys. This allows for balanced load distribution and ensures efficient processing.</li><li><strong>Consumer Parallelism</strong>: Consumers in a group are assigned different partitions. To scale, increase the number of partitions.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Qj8O7yX6sOWedqSR" /></figure><p>By dynamically routing messages to partitions, we ensure the Reactions app processes real-time interactions efficiently, supporting high write throughput and low latency reads.</p><p><strong>Dynamic data Sharding (DynamoDB): <br></strong>DynamoDB uses tables with primary keys for data distribution. Composite primary keys (partition and sort keys) enable optimized data access and the storage of multiple items with the same partition key.</p><ul><li><strong>Partition Key Importance:</strong> Distributes data across storage partitions, balancing load and scaling the database.</li><li><strong>Schema Flexibility:</strong> Allows each item to have unique attributes.</li><li><strong>Capacity Limits:</strong> Each partition holds up to 10 GB of data and supports up to 3,000 read or 1,000 write capacity units.</li><li><strong>Internal Hash Function:</strong> Uses the partition key as input to a hash function to determine storage partitions, ensuring efficient data retrieval and load distribution.</li></ul><p>These advanced sharding techniques allow DynamoDB to dynamically adjust to data and throughput demands, maintaining consistent performance. This scalability ensures the reactions system can seamlessly grow alongside Wix.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/802/0*0YcHw9sks3Yp-O9f" /></figure><h4>4. Data Locality for Enterprise Customers</h4><p><strong>Fixed Data Sharding</strong> <br>For enterprise customers with specific data locality requirements, Wix employs fixed geographic sharding to comply with regulations like GDPR. This ensures that data, such as employee-related information, is stored only in specified regions (e.g., only in the EU or the US). Wix has data centers in both the US and Europe and supports tenants in choosing where their data is persisted. Some tenants may opt for regional storage while others prefer global copies. Most of Wix’s microservices data is stored in MySQL tables.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*i968G6pzIEiEWGqW" /></figure><p><strong>Dynamic Data Routing<br></strong>Using ProxySQL, a high-performance load balancer for MySQL, Wix dynamically routes database traffic while maintaining geographic sharding. ProxySQL allows for:</p><ul><li><strong>Intelligent Query Routing:</strong> Distributes database traffic for optimal load balancing and performance.</li><li><strong>Enhanced High Availability:</strong> Redirects traffic away from failed nodes to maintain uninterrupted database access.</li><li><strong>Sharding Support:</strong> Manages large datasets and scales out by routing queries to the appropriate shards.</li></ul><p>ProxySQL enables configuring custom query rules to route specific SQL traffic to predefined groups of nodes within a MySQL cluster. Routing decisions are made based on regular expressions in SQL statements, ensuring efficient performance and compliance with data locality requirements.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Z7ISlwhPh296p9pS" /></figure><h3>Key Takeaways</h3><p>Implementing horizontal scaling comes with increased complexity in system modeling, architecture, and management. However, these strategies are essential to ensuring our platform remains fast, reliable, and scalable, meeting the diverse needs of our growing user base.</p><ul><li><strong>Choosing Keys to Split:</strong> Carefully analyze the workload and traffic patterns to select the most effective keys for sharding and routing.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/976/0*9-6LZFXkG7FpAs-B" /></figure><ul><li><strong>Tech Stack Choice:</strong> Select a tech stack that supports efficient scaling strategies. Technologies such as Kafka, DynamoDB, and ProxySQL offer robust capabilities for horizontal scaling.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/951/0*ysY_Tb2C8k4L2_SU" /></figure><h4>Overall Scaling Strategy Selection</h4><p>The following diagram illustrates a decision tree to guide you in selecting the optimal scaling strategy for your use case. This decision tree focuses on three key considerations:</p><ol><li><strong>Resource Usage and Cost:</strong> Evaluate the resources required and the associated costs of different scaling strategies.</li><li><strong>Number of Potential Tenants:</strong> Consider the number of different tenants your system needs to support.</li><li><strong>Complexity of Potential Routing Rules:</strong> Assess the complexity of the routing rules needed to manage traffic and data effectively.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*IBbjaaouGf9_FzeG" /></figure><h3>Conclusion</h3><p>Scaling a platform as vast as Wix requires an ongoing commitment to innovative solutions and flexible strategies. By blending <strong>vertical</strong> and <strong>horizontal</strong> scaling with <strong>fixed</strong> and <strong>dynamic</strong> routing and sharding techniques, Wix optimizes performance, adapts to evolving requirements, and ensures a reliable service. <br>This approach equips Wix to handle current demands while preparing for future growth, and it can provide valuable insights for anyone facing similar scaling challenges.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on<a href="https://twitter.com/NSilnitsky"> Twitter</a>, <a href="https://www.linkedin.com/in/natansilnitsky/">LinkedIn</a>, and Medium.</p><p>You can also visit<a href="https://www.natansil.com/"> my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><p><strong>Further reading:</strong></p><ul><li><a href="https://medium.com/wix-engineering/leader-election-and-sharding-practices-at-wix-microservices-6e6b853e4852">Leader election and Sharding Practices at Wix microservices</a></li><li><a href="https://medium.com/wix-engineering/how-to-choose-the-right-database-for-your-service-97b1670c5632">How to choose the right database for your service</a></li><li><a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f">4 Microservices Caching Patterns at Wix</a></li><li><a href="https://medium.com/wix-engineering/6-event-driven-architecture-patterns-part-1-93758b253f47">6 Event-Driven Architecture Patterns — Part 1</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=29ab44b2d5b4" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/scaling-horizons-effective-strategies-for-wixs-scaling-challenges-29ab44b2d5b4">Scaling Horizons: Effective Strategies for Wix’s Scaling Challenges</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Wix manages Schemas for Kafka (and gRPC) used by 2000 microservices]]></title>
            <link>https://medium.com/wix-engineering/how-wix-manages-schemas-for-kafka-and-grpc-used-by-2000-microservices-2117416ea17b?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/2117416ea17b</guid>
            <category><![CDATA[schemaregistry]]></category>
            <category><![CDATA[protobuf]]></category>
            <category><![CDATA[kafka]]></category>
            <category><![CDATA[apache-kafka]]></category>
            <category><![CDATA[schema]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Wed, 15 Mar 2023 06:38:19 GMT</pubDate>
            <atom:updated>2023-03-18T09:41:05.182Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5nSKYHsf7Zoky1x4r0dO3A.png" /><figcaption>Created using DALL-E 2</figcaption></figure><p>Managing Kafka event schemas for 2000 microservices can be quite challenging and painful. Potential challenges include:</p><ol><li>How can you maintain safe schema evolution and avoid catastrophic <a href="https://www.confluent.io/blog/spring-kafka-can-your-kafka-consumers-handle-a-poison-pill/">poison pills</a> that will bring down your Kafka consumers?</li><li>How can you make schemas easily discoverable and avoid wasting precious dev time?</li><li>How can you enforce good documentation to avoid usage mistakes and severe data corruption?</li><li>How do you automatically sync changes in schemas across different tech stacks to avoid duplication mistakes and stale versions?</li></ol><p>Over the past few years, Wix has experienced tremendous growth in both scale and complexity.</p><p>From a <a href="https://en.wikipedia.org/wiki/WYSIWYG">WYSIWYG</a> visual website editor to a complete ecosystem of features that empowers self-creators and design agencies to create professional websites, and allows anyone from individuals to large enterprises to manage their online presence and business.</p><p>Intro article: <a href="https://medium.com/wix-engineering/how-wix-accelerated-open-platform-dev-with-standardized-apis-schemas-e4fbbf25f5d8">How Wix Accelerated Open Platform Dev with Standardized APIs &amp; Schemas</a></p><p>However, this growth introduced a technical challenge in managing a growing list of event schemas (for Kafka) and API designs (for gRPC) from hundreds of services.</p><p>Wix developers and API experts have implemented various tools and practices to make sure all the above challenges are met, dev velocity is kept high, and production issues are kept to a minimum.</p><h3>Wix schemas are defined with protobuf</h3><p>Previously, the standard schema definitions at Wix backend were written as <a href="https://docs.scala-lang.org/tour/case-classes.html">Scala case classes</a> serialized to <a href="https://www.json.org/json-en.html">JSON</a>. It was mainly used for RPC as well as Kafka payloads (At the time, Kafka was less heavily used for microservices). Custom JSON-based de/serializers were created for the JVM and Node.js services (as javascript became a second language for wix backend).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dCZE6Fzl0LV4Y0K-" /></figure><p><strong>Enter gRPC and protobuf<br></strong>As Wix scale grew tremendously, both in terms of traffic (500 Billion HTTP requests per day), but also in terms of product areas (many verticals such as hotels, restaurants, bookings, etc…) and developers (&gt;1000 devs), a <strong><em>standard</em></strong> microservice API architecture was introduced based on <a href="https://grpc.io/">gRPC</a> communication and <a href="https://protobuf.dev/">protocol buffers</a> (aka protobuf) <a href="https://en.wikipedia.org/wiki/Interface_description_language">IDLs</a>.</p><p><strong>Why Protobuf<br></strong>Tools that generate client and server code from protobuf definitions are available for many languages, offer fast parsing, and allow forward compatibility in many cases.</p><p>In order to avoid different standards for gRPC and Kafka, <strong>Protobuf was also used to describe Kafka event schemas</strong> and not only gRPC services.</p><h3>Discovering Schemas</h3><p>Schema Registries like <a href="https://docs.confluent.io/platform/current/schema-registry/index.html#sr-overview">Confluent’s</a> or <a href="https://www.apicur.io/registry/">Red Hat’s</a> allow you to store your schema in one central location. This can provide many benefits such as:</p><ul><li>Central location to track all schemas used in production</li><li>Document the data format required for each topic</li><li>Centralized control of schema evolution</li></ul><p>In addition, they offer an API for Kafka producers &amp; consumers and other clients (such as <a href="https://cloudevents.io/">cloudEvents</a>) to fetch the current version of the schema in order to understand how to serialize or deserialize the events.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1001/0*gzmAmBsahSsvpXg8" /><figcaption><a href="https://docs.confluent.io/platform/current/schema-registry/index.html#sr-overview">https://docs.confluent.io/platform/current/schema-registry/index.html#sr-overview</a></figcaption></figure><p><strong>Wix Docs<br></strong>At Wix, we have our own web product for discovering and presenting schemas called <a href="https://dev.wix.com/api/rest/getting-started">Wix Docs</a>. It is used for Wix third-party application development.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*YBiTwPW8Krp7MdnO" /></figure><p>Screenshot of Wix publicly available API (REST, webhooks, SDKs)</p><p>Wix Docs utilizes build tools (e.g. Bazel) plugins, which collect API &amp; Schema information from .proto, documentation.yaml and .md files.</p><p>The plugin generates <a href="https://www.openapis.org/">OpenApi</a> swagger.json files and sends them to Wix Docs services to be able to store and view the documentation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KYo6i8i4zoreXU-t" /></figure><p><strong>Automatic Schema discovery &amp; updates<br></strong>In addition to Wix Docs, Wix also has a service called <strong><em>Business Schema</em></strong> that provides a list of business-entities and a machine-readable “API descriptor” for each <strong><em>Domain Entity</em></strong> with its actions and <strong>events</strong>. Business-schema API and events allow Wix developers to build client libraries, IDE plugins, and other tools that dynamically interact with Wix APIs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*SSpD170X-qsiGhRK" /></figure><h3>Serializing Schemas at Wix</h3><p><strong>Wix Kafka Client “Greyhound” takes care of serialization out-of-the-box<br></strong>Kafka producers and Kafka consumers are not used directly in Wix microservices.</p><p>Instead, an additional layer called <a href="https://github.com/wix/greyhound">Greyhound</a> is used. Greyhound seeks to provide a higher-level interface to Kafka and to express <a href="https://github.com/wix/greyhound#main-features">richer semantics</a> such as parallel message handling or retry policies with ease.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/591/0*Tu3kp8eSTxEhRrdW" /></figure><p><strong>Open Source Greyhound Schema flexibility<br></strong>The open-source <a href="https://github.com/wix/greyhound/blob/master/core/src/main/scala/com/wixpress/dst/greyhound/core/producer/Producer.scala#L25-L33">Greyhound producer</a> and Greyhound Consumer <a href="https://github.com/wix/greyhound/blob/master/core/src/main/scala/com/wixpress/dst/greyhound/core/consumer/domain/RecordHandler.scala#L16"><em>RecordHandler</em></a> are flexible and allow for any type of payload de/serializer</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/724/0*Tq-jAinHfVc8SuEc" /></figure><p>With Open Source Greyhound, a Schema Registry can be used, the same way it would have been when <a href="https://docs.confluent.io/cloud/current/sr/schema_registry_ccloud_tutorial.html#example-producer-code">directly using</a> Kafka producers and consumers, in order to fetch the current schema. The Kafka provided SerDe can be wrapped inside the Greyhound SerDe and configured for Producer and RecordHandler seen above.</p><p><strong>Wix Greyhound default JSON Serializer/Deserializer<br></strong>For Wix needs, Greyhound has an additional dedicated layer (which is not open-sourced).<br>The “Wix” producer and consumer API provide out-of-the-box support for <strong><em>SerDe</em></strong> (Serializer/Deserializer).</p><p>While it is possible to override the SerDe, defaults are used for 99.9% of use cases.</p><p>For the Wix producer, the <strong><em>default</em></strong> serializer accepts <strong>protobuf</strong>-derived Scala case classes and serializes them with JSON protocol to bytes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/693/0*43FqFfJ35t2Sta_W" /></figure><p>For the Wix consumer, the <strong><em>default</em></strong> deserializer does exactly the reverse, accepts bytes and deserializes them with JSON protocol to protobuf-derived Scala case classes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/668/0*0qnfOV22ir7rd2rx" /><figcaption>Consumed event deserialized from bytes</figcaption></figure><h3>Schema Evolution &amp; Validation</h3><p><a href="https://docs.confluent.io/platform/current/schema-registry/index.html#sr-overview">Confluent Schema Registry</a> provides <a href="https://docs.confluent.io/platform/current/schema-registry/avro.html#schema-evolution-and-compatibility">compatibility checks</a> as schemas evolve. Each Schema change is assigned a unique version with validation done according to the configured compatibility type for the schema. The main types are BACKWARD (the default) and FORWARD.</p><p>When<a href="https://docs.confluent.io/platform/current/schema-registry/schema-validation.html#add-sv-to-an-existing-topic"> validation is turned on</a> for a topic, the registry will not allow producers to produce a message according to a schema that will fail to be consumed because of backward or forward compatibility issues.</p><p><strong>Wix Validation<br></strong>Most of the schema validations at Wix are the responsibility of the developer, to make sure that they don’t introduce breaking changes. There are extensive internal <em>API lifecycle</em> guidelines that describe how Schemas should be introduced and changed (Including backwards compatibility, maturity levels, and versioning.)</p><p><strong>Automatic validation<br></strong>In order to help developers and avoid compatibility issues, a dedicated tool was developed in order to make sure there are no breaking changes in proto files.</p><h3>Building and Syncing Schemas inside CI/CD pipeline</h3><p>There are 2 major build systems at Wix. <br>One is based on Bazel for JVM languages and services, and the other one is called Falcon (internal build tool) for Java/TypeScript and Node services.</p><p>Each has its own ways of sharing and compiling protobuf schema definitions.</p><p><strong>Intra Bazel/Scala dependencies<br></strong>Bazel dependencies can potentially be compiled from scratch (<strong>no semantic versioning!</strong>). For proto file dependencies between two Scala services built by Bazel, all compiled artifacts (including Scala jars created from proto files) are stored in caches to improve build performance. Recompilation is avoided as long as the proto files haven’t changed.</p><p><strong>Bazel build targets<br></strong>Protobuf build targets that collect all of a service’s proto files together are defined as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/595/0*ClMTGZN8zgxGqbQf" /></figure><p><em>wix_proto_library</em> targets are actually macros that encapsulate creation of the original <em>proto_library</em> and also <em>proto_npm_package</em> for creation of NPM packages for interoperability with Node.js services.</p><p>Jars including the generated Scala files are the output of <em>wix_scala_proto_library</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/572/0*Ceep4gNxsGNP4hhi" /></figure><p><strong>Intra Node dependencies<br></strong>Node services rely on an in-house library called <em>wix-proto-codegen</em> that scans proto NPM package dependencies (in package.json) and generates JavaScript and TypeScript classes for it. <br>It utilizes the <a href="https://www.npmjs.com/package/protobufjs">protobufjs</a> npm package as its encoding engine.</p><p><strong>package.json declaration<br></strong>Usually <em>wix-proto-codegen</em> is run via <em>package.json</em> as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/538/0*5cgUd_OxbTu44kJ1" /></figure><p>A gRPC client is automatically generated after dev adds proto npm package as a dependency.</p><p><strong>Scala-&gt;Node.js dependencies<br></strong>In order for proto files originating in the Scala CI system to be consumable by the Node.js CI system a dedicated service called <em>proto-sync service</em> was created.</p><p><em>proto-sync</em> listens to build events coming from Bazel via another Wix service, filters only proto targets and triggers a build event in the Node.js CI server. (The build artifact will be created first, if it hasn’t yet.)</p><p>This build event will create a standard NPM module (with <strong>upgraded version</strong>) and will upload it to the NPM private registry.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pmsrDelT0SEOxigQhTJxBQ.png" /></figure><p>Soon this flow will change and NPM packages will be generated directly from Bazel build.</p><p><strong>Node.js-&gt;Scala dependencies<br></strong>In order for proto files originating in the NPM registry to be consumable by the Bazel build tool, they have to be copied to a dedicated GitHub repository and Bazel build files have to be created alongside them. Now they can be consumed as a source-dependency by other Bazel targets.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/851/0*B7tGmGfLmwIbqXC7" /></figure><h3>Summary</h3><p>While popular Schema Registry solutions for Kafka like Confluent’s can be very helpful with Schema management, it didn’t fit Wix’s unique needs and circumstances (Supporting gRPC, Kafka, and derived external APIs in one holistic standardized way).</p><p>Wix infrastructure and Devex teams have created an extensive array of frameworks and tools to support Schema management and development velocity. These Include automatic discovery, serialization, and validation.</p><p><strong>Meeting the challenges<br></strong>Challenges included multiple technological stacks and many legacy services that required support and complex migration.</p><p>All challenges were handled successfully as an organizational mindset change was made to treat every single schema very carefully and thoughtfully as it will most probably be consumed by developers external to Wix.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on <a href="https://twitter.com/NSilnitsky">Twitter</a>, <a href="https://www.linkedin.com/in/natansilnitsky/">LinkedIn</a>, and Medium.</p><p>You can also visit <a href="https://www.natansil.com/">my website</a>, where you will find my previous blog posts, talks I gave at conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><p>Further reading:</p><ul><li><a href="https://medium.com/wix-engineering/how-wix-accelerated-open-platform-dev-with-standardized-apis-schemas-e4fbbf25f5d8">How Wix Accelerated Open Platform Dev with Standardized APIs &amp; Schemas</a></li><li><a href="https://medium.com/wix-engineering/troubleshooting-kafka-for-2000-microservices-at-wix-986ee382fd1e">Troubleshooting Kafka for 2000 Microservices at Wix</a></li><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2117416ea17b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/how-wix-manages-schemas-for-kafka-and-grpc-used-by-2000-microservices-2117416ea17b">How Wix manages Schemas for Kafka (and gRPC) used by 2000 microservices</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Wix Accelerated Open Platform Dev with Standardized APIs & Schemas]]></title>
            <link>https://medium.com/wix-engineering/how-wix-accelerated-open-platform-dev-with-standardized-apis-schemas-e4fbbf25f5d8?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/e4fbbf25f5d8</guid>
            <category><![CDATA[schema]]></category>
            <category><![CDATA[standards]]></category>
            <category><![CDATA[open-platform]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[api-development]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sat, 11 Mar 2023 20:22:38 GMT</pubDate>
            <atom:updated>2023-07-06T05:13:19.833Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lq3-0g-S5WFAffNX8t0T6g.png" /><figcaption>Created using Midjourney</figcaption></figure><p>Over the past few years, Wix has experienced tremendous growth in both scale and complexity.</p><p>From a <a href="https://en.wikipedia.org/wiki/WYSIWYG">WYSIWYG</a> visual website editor to a complete ecosystem of features that empowers self-creators and design agencies to create professional websites, and allows anyone from individuals to large enterprises to manage their online presence and business.</p><p>However, this growth introduced a technical challenge in managing a growing list of disparate API designs and event schemas from hundreds of services.</p><p>Wix developers and API experts have implemented various tools and standardized practices to make sure the above challenge is met, dev velocity is kept high, and production issues are kept to a minimum.</p><h3>Standard APIs &amp; Event Schemas — Standardization effort</h3><p>In the early days of Wix services, most of them were monoliths, with APIs based on internal use cases only and not exposed to 3rd party developers.</p><p>In order to incorporate standardization and cultivate the “open platform” mindset, It was important to move from feature-based APIs (that mostly frontend uses) to domain-based API designs and event schemas.</p><p><strong>Designing part of a platform<br></strong>The idea was to define a service’s main entities, then define the APIs and events and also define how everybody would use them, looking not only at your immediate use cases, but also research the API as a product. Talk to potential 3rd party apps developers, go over similar APIs that exist in other companies.</p><p>This allowed for better efficiency throughout the company, as APIs and events were re-used instead of duplicated. At the same time, common infrastructure and terminology were formed.</p><p>For more on adopting an API first approach you can read <a href="https://swagger.io/resources/articles/adopting-an-api-first-approach/">this article</a>.</p><p><strong>Exposed externally<br></strong>Wix now has a comprehensive developer platform that enables the extension of Wix websites and back-office capabilities. The platform consists of two parts:</p><ol><li>Extending websites with <a href="https://www.wix.com/velo/">Velo</a> — a JavaScript based development environment for both frontend and backend code.</li><li>Wix <a href="https://www.wix.com/app-market">App Market</a> for third-party applications.</li></ol><p>Most of Wix’s microservices internal gRPC APIs are exposed as <a href="https://dev.wix.com/api/rest/getting-started">REST APIs</a> via automatically generated thin wrappers for applications and also <a href="https://www.wix.com/velo/reference/api-overview">Velo APIs</a>.</p><p>Wix’s microservices Kafka Events are now automatically open to <em>external</em> developers via <a href="https://dev.wix.com/api/rest/getting-started/webhooks">Webhooks</a> for applications and <a href="https://www.wix.com/velo/reference/wix-bookings-backend/events/introduction#wix-bookings-backend_events_introduction_introduction">Velo Events</a> .</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1000/0*mCla2aI1lQcmoglV" /><figcaption>For more information on the Standardization effort you can listen to <a href="https://www.wix.engineering/podcast/episode/ade5af7c/wix-engineering-podcast-platformization">this</a> podcast episode or read the <a href="https://www.wix.engineering/post/platformization-e12-full-transcript">transcript</a>.</figcaption></figure><h3>Wix schemas are defined with protobuf</h3><p>Previously, the standard schema definitions at Wix backend were written as <a href="https://docs.scala-lang.org/tour/case-classes.html">Scala case classes</a> serialized to <a href="https://www.json.org/json-en.html">JSON</a>. It was mainly used for RPC as well as Kafka payloads (At the time, Kafka was less heavily used for microservices). Custom JSON-based de/serializers were created for the JVM and Node.js services (as javascript became a second language for wix backend).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*S7HhtIigk-oST-HD" /></figure><p><strong>Enter gRPC and protobuf<br></strong>As Wix scale grew tremendously, both in terms of traffic (500 Billion HTTP requests per day), but also in terms of product areas (many verticals such as hotels, restaurants, bookings, etc…) and developers (&gt;1000 devs), a <strong><em>standard</em></strong> microservice API architecture was introduced based on <a href="https://grpc.io/">gRPC</a> communication and <a href="https://protobuf.dev/">protocol buffers</a> (aka protobuf) <a href="https://en.wikipedia.org/wiki/Interface_description_language">IDLs</a>.</p><p><strong>Why Protobuf<br></strong>Tools that generate client and server code from protobuf definitions are available for many languages, offer fast parsing, and allow forward compatibility in many cases.</p><p><strong>Both RPC and REST<br></strong>Google provides protobuf http extension that enables the dev to define http mapping per RPC method. It also provides JSON-serializers to/from scala case-classes that were auto-generated by protobuf. This uncovered the ability to use a single schema definition to model both RPC and REST APIs without any additional translation infra.</p><h3>Event-driven architecture &amp; Domain Events</h3><p>In the last couple of years, emphasis started to shift to a more event-driven microservices architecture approach with the introduction of <a href="https://www.martinfowler.com/eaaDev/DomainEvent.html">domain events</a>.</p><p>A common standard was defined for sending events from services related to a specific domain (e.g. <a href="https://dev.wix.com/api/rest/wix-stores/catalog/products/product-changed-webhook">product-changed</a>) in order to ensure a streamlined approach for clients to consume events.</p><p>This setup serves both Wix consumers (using Protobuf serialized with JSON and streamed via Kafka), and external consumers (via <a href="https://dev.wix.com/api/rest/getting-started/webhooks">webhooks</a> and <a href="https://www.wix.com/velo/reference/wix-stores-backend/events/introduction#wix-stores-backend_events_introduction_introduction">Velo events</a>).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/766/0*e_DI71ptInAfBNm4" /><figcaption>Example of <a href="https://dev.wix.com/api/rest/wix-stores/catalog/products/product-created-webhook">Product Created Webhook</a> in JSON format</figcaption></figure><p><strong>Domain events</strong><br>Domain events are meaningful business events notifying of a change in the state of the domain entity. Examples:</p><ul><li>Entity created</li><li>Entity updated</li><li>Entity deleted</li><li>Email sent to member</li><li>Payment transaction started</li></ul><p>The domain events common proto defines an envelope with <strong>common metadata</strong> in order to make it easier for infrastructure and “horizontal” services to consume them (more on this in the following section).</p><h3>Discovering APIs &amp; Schemas with Wix Docs</h3><p>At Wix, we have our own web product for discovering and presenting schemas called <a href="https://dev.wix.com/api/rest/getting-started">Wix Docs</a>. It is used for Wix third-party application development.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*iExVcuYGuQtrpp24" /><figcaption>Screenshot of Wix publicly available API (REST, webhooks, SDKs)</figcaption></figure><p>Wix Docs utilizes build tools (e.g. Bazel) plugins, which collect API &amp; Schema information from .proto, documentation.yaml and .md files.</p><p>The plugin generates <a href="https://www.openapis.org/">OpenApi</a> swagger.json files and sends them to Wix Docs services to be able to store and view the documentation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qCwza78SYhhvTLPs" /></figure><p><strong>Automatic API &amp; Schema discovery &amp; updates<br></strong>In addition to Wix Docs, Wix also has a service called <strong><em>Business Schema</em></strong> that provides a list of business-entities and a machine-readable “API descriptor” for each <strong><em>Domain Entity</em></strong> with its actions and <strong>events</strong>. Business-schema API and events allow Wix developers to build client libraries, IDE plugins, and other tools that dynamically interact with Wix APIs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*5xNIXbN1Zy48YIv9" /></figure><h3>Schema Evolution &amp; Validation at Wix</h3><p>Most of the schema validations at Wix are the responsibility of the developer, to make sure that they don’t introduce breaking changes. There are extensive internal <em>API lifecycle</em> guidelines that describe how Schemas should be introduced and changed (Including backwards compatibility, maturity levels, and versioning.)</p><p>Because of the API-first “Open Platform” mentality, all developers have built the mindset to make sure they change their public APIs and schemas in a safe manner.</p><p><strong>Automatic validation<br></strong>In order to help developers and avoid compatibility issues, a dedicated tool was developed in order to make sure there are no breaking changes in proto files.</p><p><strong>Version Migration<br></strong>A typical schema version lifecycle at Wix goes through these stages:</p><ol><li>Create the model</li><li>Stabilization</li><li>Add features / abilities / enhances / fixes</li><li>Deprecation</li><li>End-of-life</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/877/0*cMl3GneNeNg2sZ9q" /><figcaption>Example of a deprecated field from a blog related schema</figcaption></figure><p>In case a breaking change must be introduced, the old version is marked as deprecated, and a new version is created.</p><h3>Summary</h3><p>In order to reach the “Open Platform” vision, Wix has created detailed guidelines and an extensive array of frameworks and tools to support Schema management and development velocity. These Include automatic discovery, serialization, and validation.</p><p><strong>Mindset Change<br></strong>An organizational mindset change was made to build a truly open platform that treats every single schema very carefully and thoughtfully as it will most probably be consumed by developers external to Wix.</p><p><strong>Higher dev velocity<br></strong>As a testament to this success, the rate of new business microservices creation and overall event consumption has risen dramatically in the last few years.</p><p>Despite having over 2000 event-driven microservices in production, Wix is able to onboard a new business domain and integrate it with the surrounding ecosystem, consuming all the necessary APIs and events, in just a few days.</p><p><strong>A true open platform<br></strong>In addition, this new domain is then automatically open to third-party application developers and Wix website developers, creating one seamless experience for both internal &amp; external developers throughout the lifetime of this API &amp; Schema version.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on <a href="https://twitter.com/NSilnitsky">Twitter</a>, <a href="https://www.linkedin.com/in/natansilnitsky/">LinkedIn</a>, and Medium.</p><p>You can also visit <a href="https://www.natansil.com/">my website</a>, where you will find my previous blog posts, talks I gave at conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><p>Further reading:</p><ul><li><a href="https://medium.com/wix-engineering/how-wix-manages-schemas-for-kafka-and-grpc-used-by-2000-microservices-2117416ea17b">How Wix manages Schemas for Kafka (and gRPC) used by 2000 microservices</a></li><li><a href="https://medium.com/wix-engineering/5-tips-for-writing-great-client-libraries-f6d02d57fdcc">5 tips for writing great client SDK libraries</a></li><li><a href="https://medium.com/wix-engineering/5-database-technologies-used-by-2000-wix-microservices-e4769638b8c3">5 Database technologies used by 2000 Wix microservices</a></li><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e4fbbf25f5d8" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/how-wix-accelerated-open-platform-dev-with-standardized-apis-schemas-e4fbbf25f5d8">How Wix Accelerated Open Platform Dev with Standardized APIs &amp; Schemas</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Troubleshooting Kafka for 2000 Microservices at Wix]]></title>
            <link>https://medium.com/wix-engineering/troubleshooting-kafka-for-2000-microservices-at-wix-986ee382fd1e?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/986ee382fd1e</guid>
            <category><![CDATA[event-streaming]]></category>
            <category><![CDATA[event-driven-architecture]]></category>
            <category><![CDATA[microservices]]></category>
            <category><![CDATA[apache-kafka]]></category>
            <category><![CDATA[kafka]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Fri, 09 Dec 2022 20:44:06 GMT</pubDate>
            <atom:updated>2023-04-01T09:00:52.080Z</atom:updated>
            <content:encoded><![CDATA[<p>Debugging microservices’ event driven communication is not trivial, especially when it’s based on event streaming platforms like <strong>Apache Kafka</strong>. While scale grows more easily and the distributed system becomes more decoupled and resilient, the operational aspects become much harder.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/929/0*15wUfgBaQKl6BObm" /><figcaption>Microservices communicating via Kafka with production issue in Inventory service</figcaption></figure><p>How do you understand why your service’s database has some incorrect values? (<strong>And increase your org dev velocity?</strong>) How do you get to the root cause and reduce debugging time? (<strong>And save money and effort?</strong>) Event processing sometimes fails or is extremely slow and a consumer lag builds up, how do you bring it back down?</p><p>In the past, Wix developers had experienced stressful, anxiety-filled moments where they needed to fix some urgent production issue related to the event streaming layer, but they were blind to the root causes and powerless to fix them in a straightforward fashion. Instead they were required to drop processing of many events or execute time-consuming DB fixing scripts.</p><p>In the last few years my <em>Data streams</em> team, in charge of the event-driven infrastructure on top of Kafka, created many tools and services in order to give the full power and visibility to Wix developers to easily troubleshoot and fix event-streaming related production issues. We have seen the incident resolution time dramatically decrease with more pinpoint solutions that avoid costly database repairs.</p><p>Following are 5 must-have-features to easily troubleshoot and fix event-streaming related production issues:</p><h3>1. Trace events flow</h3><p><strong>Ecommerce flow<br></strong>Consider the classic ecommerce flow, where a user places an order and triggers a chain of events:</p><ul><li><em>OrderCreated</em> event is produced by order service</li><li>Payment service consumes the order events, performs payment and produces a <em>paymentCompleted</em> event</li><li>Inventory service consumes <em>paymentCompleted </em>event<em> </em>and<em> </em>produces inventoryUpdated event</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*dTwt5wg8CzacilLA" /><figcaption>Events flow following order creation</figcaption></figure><p>Of course, the actual Wix ecommerce system is much more complex and has many different events flowing between many different microservices.</p><p><strong>Data corruption<br></strong>At some point Wix developers noticed that the inventory service database does not reflect the actual inventory levels of some products.</p><p>Even with this simplified example, you can start seeing how hard it is to track the events flow and get a clue for the root cause of the issue. Was the <em>OrderCreated</em> or <em>PaymentCompleted</em> event produced correctly? Do they contain all relevant products? Or maybe the inventory service failed to process the <em>PaymentCompleted</em> event correctly?</p><p>Without proper tracing tools, developers were left searching logs of each service for clues, or manually streaming many events in multiple topics in the hopes of finding the potentially faulty events.</p><p><strong>Request Ids</strong> <strong>Propagation<br></strong>In order to easily trace the flow for each request throughout ecommerce services, we put the original <em>requestId</em> in the event headers. These headers are then deserialized and written as extra metadata to monitoring and logging infrastructure. The <em>requestId</em> is also put in headers for new produced events which recursively allows to propagate this metadata in all participating services.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*BVNA3vWFGuOnsM2A" /><figcaption>requestId and userId propagation</figcaption></figure><p>This “Context propagation” is provided out-of-the-box for all Wix service by <a href="https://github.com/wix/greyhound">Greyhound</a>, a JVM library and polyglot sidecar that forms a data streaming abstraction layer on top of Kafka with many features that help developers with features that Kafka itself lacks, like produce/consume retry strategies and higher performance parallel and batch consumers.</p><p>By having the request Id attached to all logs and metrics, we can easily see in Grafana dashboards which services successfully processed events related to this <em>requestId</em>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/898/0*wj10jgHTvYE0S-cy" /><figcaption>events tracing between artifact via request id</figcaption></figure><p>Logs are also easily filterable by the <em>requestId</em>, so you can see relevant logs for this event in all services at once, including the logs of the relevant inventory database changes.</p><p><strong>Open Telemetry<br></strong>In addition to placing <em>requestId</em> in Kafka record headers, Greyhound also exports <a href="https://opentelemetry.io/">OpenTelemetry</a> <a href="https://opentelemetry.io/docs/concepts/observability-primer/#distributed-traces">traces</a> and spans information. While the data is currently available for each service internally, In the near future, full distributed tracing information will be provided, including full breakdown of operations</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*tyl_-p9E76MHYOSR" /><figcaption>event handling breakdown via Open Telemetry</figcaption></figure><h3>2. Easily lookup a specific event payload</h3><p><strong>Continuing Ecommerce data inconsistency investigation<br></strong>Let’s continue the ecommerce example from the tracing segment above. We want to investigate why the Inventory service database does not reflect the actual inventory levels of some products.</p><p>Let’s say we are satisfied that <strong>all</strong> events were successfully produced and consumed by looking at the tracing dashboards for the suspicious user requests. Next we want to investigate if all products were accounted for in the <em>OrderCreated</em> and <em>PaymentCompleted</em> events related to the suspicious user requests.</p><p><strong>Kafka Control Plane Apps<br></strong>In order to do that we need to look at the relevant event payloads. Some Kafka control plane applications allow you to stream and filter events, including <a href="https://github.com/provectus/kafka-ui">UI for Apache Kafka</a>, <a href="https://docs.confluent.io/platform/current/control-center/index.html">Confluent Control Center</a>, and <a href="https://www.conduktor.io/">Conduktor</a>. You can also use <a href="https://docs.confluent.io/platform/current/tutorials/examples/clients/docs/kafka-commands.html#consume-records">Kafka CLI tools</a> to find relevant events.</p><p><strong>Wix Custom Control Plane — Event Stream View<br></strong>At Wix, we created our own custom control plane, in order to utilize the power of Wix’s <a href="https://github.com/wix/greyhound">Greyhound</a> Platform’s metrics and configuration. One of the first features we implemented was the ability to stream events from specific topics. The user first chooses which region and Kafka cluster he wishes to stream from. They can also choose to filter the stream, to start from some time in the past, and/or from some partition or offset. They can also specify specific text to search for in Kafka record key, payload or headers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lNgIxxlZWShnYJP5" /><figcaption>Event payload streaming on Wix Kafka Control Plane</figcaption></figure><p>In our ecommerce Inventory investigation case, we can search for the suspicious requestIds and look inside their payloads and check if all the items are accounted for.</p><p><strong>Duplicate processing and Idempotency<br></strong>As it Turns out, the events had all the items in place, but upon closer examination of the logs, it was discovered that the Inventory service processed the same events twice. Because of some partial failure during processing that happens from time to time. The service developers didn’t make sure to include deduplication protection in their database updates and make them idempotent. <br>For more information on how to introduce idempotency to your service, you can review the 5th pitfall from one of my <a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">previous articles</a>.</p><h3>3. Investigate “slow” consumers root cause</h3><p><strong>Consumer Lag Alert<br></strong>At Wix, once a consumer fails to keep up with the amount of produced events for more than 30 minutes, an alert is triggered in <a href="https://grafana.com/">Grafana</a> and the consumer owning team is notified in <a href="https://slack.com/">Slack</a>. For Kafka this phenomenon is called Consumer Lag (for <em>queue</em> based brokers such as <a href="https://www.rabbitmq.com/">RabbitMQ</a> it’s simply called a large and growing queue.)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/938/0*rZKyW3rw8fU2ACOp" /><figcaption>Kafka Lag alert on Wix Slack channel</figcaption></figure><p><strong>Inventory Service Lag<br></strong>Let’s go back to our ecommerce example. A consumer lag is building up for the Inventory service <em>Payments</em> topic consumer. The developers are starting to be worried that the inventory database will not reflect the reduced inventory due to recent completed purchases.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*3krlJhU6ZHMZV456" /><figcaption>Inventory service consumer lag</figcaption></figure><p><strong>Produced/Consumed Rate Grafana graph<br></strong>As they start to investigate the consumer lag following the Slack alert, WixStores developers go to the Inventory service Grafana dashboard and see the difference in the throughput between producer and consumer for the <em>Payments</em> topic. While the produce rate is ~4K RPM, the consume rate is only ~1K RPM.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/870/0*LkP3oPLL1MdQeSZf" /></figure><p><strong>“Stuck” Consumers Grafana graph<br></strong>Another very important graph that <em>Inventory</em> Service devs can view is called <em>Longest Running Consumer Handler</em>, where they can see if any/all consumer instances are “stuck” on handling.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bvSBJDST9KS2Qhpu" /><figcaption>Longest running Consumer Handler gauge shown in Grafana graph</figcaption></figure><p>This graph is made possible by <a href="https://github.com/wix/greyhound">Greyhound</a>, our Kafka wrapper library and service. Greyhound exposes a <a href="https://prometheus.io/">Prometheus</a> gauge for each topic consumer handlers, such that it measures the currently longest running consumer handler (the longest running provided lambda function) running in this pod. For more on how Greyhound works, you can check out <a href="https://youtu.be/1dRXXV6pNRU?t=292">this</a> video.</p><p><strong>Restart “stuck” Kubernetes pod<br></strong>Back to the investigation. According to the above Grafana graph, it seems like the <em>Inventory</em> Service Payments topic consumer is stuck in one of the <a href="https://kubernetes.io/">Kubernetes</a> pods. The developer decides to restart the pod in the hopes that the issue will go away and Payments topic consumption rate will go back to normal.</p><p>But alas, it doesn’t help. The consumer rate stays lower than the producer rate. But not to worry, there are other monitoring tools she still hasn’t used.</p><p><strong>Consumers Lag View in the Wix Kafka Control Plane<br></strong>In order to help the developers investigate the root cause of consumer lags, we created a dedicated view in our custom control plane where the developers can easily see which Kafka topic partitions have the most lag.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*MZJlFCHX8a3TtLgR" /><figcaption>Consumer Lag breakdown by partition</figcaption></figure><p>In the ecommerce inventory case, after the pod restart, the lag kept growing for the same partition, just with another pod being assigned to it.</p><p><strong>View “last” event<br></strong>In case the lag is mostly found in 1 partition, the devs can click on “Last Message” button and view the current event being processed, to understand if its payload or headers may cause the issue</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rG08ocG_ATUJCi4R" /><figcaption>view “stuck” event payload</figcaption></figure><p>After reviewing the event payload, the developer understood that the event includes a huge amount of items, which the <em>Inventory</em> service fetched to memory and caused the Kubernetes pod’s service container to run out of memory, which caused the JVM process to become unstable and the consumer handler to get “stuck” and <em>lag</em> to build up.</p><h3>4. Skip or replay events</h3><p>Continuing with our ecommerce example, in the last segment, we reached a situation where the <em>Payments</em> topic <em>Inventory</em> service consumer lag was caused by a “rogue” event with a huge payload. <br>The developer decided that the best course of action would be to just <strong><em>skip</em></strong> the event, as she saw in the stream view (described above in section 2) that the issue is isolated to just this one event. It will also mean she can fix the underlying issue in a more relaxed setting, and then <strong><em>replay</em></strong> the event once the bug is fixed.</p><p><strong><em>How to skip or replay events in Kafka?<br></em>1. Kafka SDK seek API<br></strong>While Kafka allows consumers to skip or replay events by using the <a href="https://kafka.apache.org/31/javadoc/org/apache/kafka/clients/consumer/KafkaConsumer.html#seek(org.apache.kafka.common.TopicPartition,long)">seek api</a>, it’s not realistic to expect that the consumer code will know in advance the exact scenarios when it is needed to skip events, how many events, and so on.</p><p><strong>2. Kafka-consumer-groups.sh command<br></strong>In the past, we utilized <a href="https://www.hadoopinrealworld.com/how-to-change-or-reset-consumer-offset-in-kafka/#:~:text=How%20to%20change%20consumer%20offset,flag%20to%20change%20the%20offset.">kafka-consumer-groups.sh cli script</a> in order to change the consumer group current event offsets, but it required <strong>shutting down all consumer pods</strong>, so they will be able to start again with the newly configured offsets.</p><p>Another disadvantage is that it’s not easy and straightforward to work with this command line interface, so it was mostly up to our streaming infra dev team to execute these skips/replays on behalf of other backend developers at Wix.</p><p><strong>3. Change consumer group name<br></strong>In cases where it’s possible to drop all unprocessed events, another option is to change the consumer group name, and start processing events “from latest” offsets.<br>If replaying all available events is possible, the configuration of “from beginning” can be set</p><p><strong>4. Easily request Greyhound to skip or replay events<br></strong>Recently, my streaming infra team developed a way to request from <a href="https://github.com/wix/greyhound">Greyhound</a>, our Kafka wrapper library and service, to skip or replay events.</p><p>Currently the request is done via RPC, but soon there will be a new <strong><em>Skip/Replay events view</em></strong> in our Wix Custom Kafka Control Plane.</p><p>The user requests to change a consumer group’s offsets for one or more partitions.<br>Either with the explicit offset value, or from some timestamp.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*jegycZcEOtUAyQKk" /><figcaption>Skip/Reply events API</figcaption></figure><ol><li>The inventory service configuration is changed to include the new reset-offsets configuration.</li><li>The configuration change causes the service pods to restart and the consumers to start from the requested offsets to start from.</li><li>An additional mechanism makes sure that the <strong>reset will not happen again</strong> on subsequent restarts, but its details are not in the scope of this article.</li></ol><p><strong><em>Inventory</em> service consumer group lag finally drops<br></strong>Once the <em>Inventory</em> service consumer group successfully skips the problematic event after the developer requests it from <a href="https://github.com/wix/greyhound">Greyhound</a>, the consumer group lag starts to drop and the production issue is resolved successfully.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*L14j8S09CQiZC5SN" /><figcaption>Kafka consumer lag dropping after skip</figcaption></figure><h3>5. Redistribute Single Partition Consumer Lag</h3><p>There are times where a consumer lag is caused by a <strong><em>misconfigured Kafka event key</em></strong>. When an event is produced with a <strong><em>key</em></strong>, all events that share the same key are produced to the same partition and thus are processed sequentially.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/750/0*FQ0Z21jllHGlI2MJ" /><figcaption>produce with same key always goes to same partition</figcaption></figure><p>Events with the same key produced to the same partition. Each Partition is processed sequentially by a different Consumer pod (C1..C4)</p><p><strong>Misconfigured Kafka event key<br></strong>Continuing with our ecommerce example, in Black Friday 2021, the <em>Payments</em> topic <em>Inventory</em> service consumer lag was caused by relatively slow consumer handlers, but also because of problematic choice of Kafka event key by the payments service. The key was configured to be the vertical app id which means small distribution such that many events go to the same partition instead of utilizing all the partitions of the topic.</p><p><strong>Quicker lag resolution<br></strong>Involving the developers of payments service to change the key and deploy a new version took a long time and caused the issue to remain unresolved for a few hours. So as a lesson, Wix streaming infra dev team decided to develop a feature to redistribute the events that cause the single partition lag among all partitions.</p><p><strong>Out-of-order processing<br></strong>While redistribution of the events can cause out-of-order processing, for critical situations where the lag must be removed quickly, or in cases where order doesn’t matter to this particular consumer, this type of remediation can be quite useful.</p><p>In December 2022 we’re still prototyping the solution in production. I will update this article with our full robust battle tested solution once it becomes available.</p><h3>Summary</h3><p>Investing in good infrastructure for troubleshooting event streaming Apache Kafka related production issues is critical for being able to scale an event-driven architecture for your distributed environment of microservices.</p><p>Make sure to have the following monitoring capabilities:</p><ol><li><strong>Trace events flow<br></strong>Ascertain which services successfully processed events related to a user request and which haven’t by using OpenTelemetry protocol for example</li><li><strong>Easily lookup a specific event payload<br></strong>Make sure event payload is not corrupted or the root cause of some unforeseen issue</li><li><strong>Investigate “Slow” Consumers root cause<br></strong>Have relevant metrics such as longest running handler, and lag-per-partition view in place</li></ol><p>Monitoring features have to be accompanied by remediation tools such as:</p><ol><li><strong>Easy events skip/replay<br></strong>Have the ability to skip events to remove consumer lag, or replay events to fix database issues</li><li><strong>Redistribution of single partition lags<br></strong>Have the ability to redistribute single partition lags in order to resolve slow consumption due to badly distributed kafka event key</li></ol><p>These capabilities: <em>Trace, Lookup, Longest-Running, Skip, Redistribute</em>, form the Acronym <strong>TLLSR</strong></p><p>Having infrastructure for microservices event-streaming communication (like Wix has <a href="https://github.com/wix/greyhound">Greyhound</a> and a custom Control Plane) can get you closer to your goals of higher dev velocity and reduced costs for maintaining a scalable and resilient event-streaming architecture.</p><p>There are several open source (<a href="https://github.com/provectus/kafka-ui">UI for Apache Kafka</a>) and commercially available tools (such as <a href="https://www.confluent.io/product/confluent-platform/gui-driven-management-and-monitoring/">Confluent Control Center</a> and <a href="https://towardsdatascience.com/overview-of-ui-tools-for-monitoring-and-management-of-apache-kafka-clusters-8c383f897e80">Conduktor</a>) that can help you get there faster.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on <a href="https://twitter.com/NSilnitsky">Twitter</a>, <a href="https://www.linkedin.com/in/natansilnitsky/">LinkedIn</a>, and Medium.</p><p>You can also visit <a href="https://www.natansil.com/">my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><p>Further reading:</p><ul><li><a href="https://medium.com/wix-engineering/how-wix-manages-schemas-for-kafka-and-grpc-used-by-2000-microservices-2117416ea17b">How Wix manages Schemas for Kafka (and gRPC) used by 2000 microservices</a></li><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a></li><li><a href="https://medium.com/wix-engineering/6-event-driven-architecture-patterns-part-1-93758b253f47">6 Event-Driven Architecture Patterns</a></li><li><a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f">4 Microservices Caching Patterns at Wix</a></li><li><a href="https://medium.com/wix-engineering/leader-election-and-sharding-practices-at-wix-microservices-6e6b853e4852?source=your_stories_page----------------------------------------">Leader election and sharding practices at Wix Microservices</a></li><li><a href="https://www.wix.engineering/post/wix-engineering-tech-interviews-gwen-shapira-and-natan-silnitsky">Gwen Shapira on Event Driven Architecture and Cloud Native Kafka</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=986ee382fd1e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/troubleshooting-kafka-for-2000-microservices-at-wix-986ee382fd1e">Troubleshooting Kafka for 2000 Microservices at Wix</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Event Driven Architecture — 5 Pitfalls to Avoid]]></title>
            <link>https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/b3ebf885bdb1</guid>
            <category><![CDATA[event-sourcing]]></category>
            <category><![CDATA[kafka]]></category>
            <category><![CDATA[pulsar]]></category>
            <category><![CDATA[event-driven-architecture]]></category>
            <category><![CDATA[cdc]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sun, 14 Aug 2022 07:28:19 GMT</pubDate>
            <atom:updated>2023-06-30T09:13:00.229Z</atom:updated>
            <content:encoded><![CDATA[<h3>Event Driven Architecture — 5 Pitfalls to Avoid</h3><p>Event driven architecture is very powerful and well suited for a distributed microservices environment. By introducing a broker intermediary, event driven architecture offers a <strong>decoupled</strong> architecture, easier <strong>scalability</strong>, and a much higher degree of <strong>resiliency</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*K4FVKBu0iOSCpvh4" /><figcaption>request reply (client-server) vs. event streaming (pub-sub)</figcaption></figure><p>But it’s much harder to set up correctly as opposed to request-reply client-server type architecture.</p><p>At Wix we have been gradually migrating our growing set of microservices (currently at 2300) from the request-reply pattern to event driven architecture over the last few years. Below there are <strong>5 pitfalls</strong> that Wix engineers have encountered during our experimentation with event driven architecture.</p><p>These pitfalls have caused us great pain, in terms of production incidents, required re-writes and steep learning curves. For each pitfall I provide battle-tested proven solutions used at Wix today.</p><h3>1. Write to db and then fire event without atomicity</h3><p>Consider for example a simple ecom flow (we will use this example throughout this article)</p><p>Once the payment processing is done, the product inventory should be updated to reflect that the product is reserved for the customer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*yAKvgOJRat-gF3FW" /><figcaption>Write to DB and produce event is a non atomic action</figcaption></figure><p>Unfortunately, writing the payment-complete status to the database and then producing a “payment completed” event to Kafka (or some other message broker) is not an atomic operation. There could be situations where only one of the actions actually happens.</p><p>For example, cases such as the database being unavailable, or Kafka being unavailable, could lead to data inconsistency between different parts of your distributed system. In the case above <strong>Inventory levels</strong> may become <strong>inconsistent</strong> with actual orders.</p><h4>Atomicity Remedy I — Greyhound resilient producer</h4><p>There are several ways to mitigate this issue. At Wix we utilize two ways. The first one is our own messaging platform called <a href="https://github.com/wix/greyhound#greyhound">Greyhound</a>, that allows us to make sure the event is <em>eventually</em> written to Kafka via a resilient producer. One downside of this mitigation is that you can end up with out-of-order processing of events downstream.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*qw3KJwUY1Asq7CYP" /><figcaption>Greyhound producer fallbacks to S3. A dedicated service recovers the messages to Kafka</figcaption></figure><h4>Atomicity Remedy II — Debezium Kafka source connector</h4><p>The second way to make sure both DB update action and Kafka produce action happen and that data remains consistent is using the <a href="https://debezium.io/documentation/reference/stable/architecture.html">Debezium Kafka connector</a>. Debezium connector allows to automatically capture all the change events (<a href="https://en.wikipedia.org/wiki/Change_data_capture">CDC</a>) that happen in the database (For MySQL via <a href="https://dev.mysql.com/doc/internals/en/binary-log-overview.html">binlog</a>) and produce them as Kafka events. <br><a href="https://docs.confluent.io/platform/current/connect/index.html">Kafka Connect</a> together with <a href="https://debezium.io/documentation/reference/stable/connectors/mysql.html">Debezium DB connectors</a> guarantees that events will eventually be produced to Kafka. In addition there is a guarantee that <a href="https://debezium.io/documentation/faq/#how_are_events_for_a_database_organized">events order will be kept</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6dbF1ZqV7jQZNf7f" /><figcaption>Debezium connector makes sure change events are eventually consistent with DB</figcaption></figure><p>Note that Debezium also works with other event streaming platforms such as <a href="https://pulsar.apache.org/docs/io-cdc-debezium/">Apache Pulsar</a>.</p><h3>2. Using Event sourcing everywhere</h3><p><a href="https://microservices.io/patterns/data/event-sourcing.html">Event sourcing</a> is a pattern where instead of updating an entity’s state upon a business operation, the service saves an event to its database. The service reconstructs an entity’s current state by replaying the events. <br>These events are also published on an event bus such that other services can also create materialized views on other databases that are optimized for queries by replaying the events.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*cWg-ievuCCXiWuqE" /><figcaption>Event Sourcing — persist change events to Event Store. Play events to reach current state</figcaption></figure><p>While there are certain advantages to this pattern (a reliable audit log, performing “time travel” — the ability to get the state of your entity at any point in time, and building multiple views over the same data), it is by far more complex than <a href="https://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> services that update the state of an entity stored in a database.</p><h4>Disadvantages of event sourcing include:</h4><ol><li>Complexity — In order to make sure read performance is not affected by a growing list of events you need to play, <a href="https://domaincentric.net/blog/event-sourcing-snapshotting">entity state snapshots</a> have to be taken from time to time to reduce the performance penalty. <br>This increases the system complexity with a background process that may have its own issues and when it does the data remain stale. On top of this, having 2 copies of the data means they might get out of sync.</li><li>Snowflake nature — Unlike CRUD <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping">ORM</a> solutions, It’s harder to create common libraries and frameworks to ease development that can globally solve snapshotting and read-optimizations that can fit for every single use case.</li><li>Only supports eventual consistency (problematic for read-after-write use-cases)</li></ol><h4>Event Sourcing alternative — CRUD+CDC</h4><p>Utilizing both simple CRUD capabilities and publishing database change events (<a href="https://en.wikipedia.org/wiki/Change_data_capture">CDC</a>) for downstream uses (e.g. creation of query-optimized materialized views) can reduce complexity, increase flexibility and still allow for Command-Query Responsibility Segregation (<a href="https://martinfowler.com/bliki/CQRS.html">CQRS</a>) for specific use cases.</p><p>For most of the use-cases, the service can expose a simple read endpoint that will fetch the entity’s current state from the database. As scale increases and more complex queries are needed, the additional published change events can be used to create custom materialized views specifically tailored for complex queries.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*o_QS5WQRTiLLgXW7" /><figcaption>CRUD — simple read from DB + CDC for external materialized views</figcaption></figure><p>In order to avoid exposing DB changes as a contract to other services, and creating a coupling between them, the service can consume the CDC topic and produce an “official” API of change events similar to the event stream created in event-sourcing pattern.</p><h3>3. No Context Propagation</h3><p>Switching to event driven architecture means developers, devops and SREs potentially have more difficulty to debug production issues and track the processing of end-user requests throughout the system.<br>Unlike with the request-reply model, there is no explicit chain of HTTP/RPC requests to follow. Debugging code is harder as event handling code is spread out across the service code instead of being sequentially traceable by clicking into function definitions usually found in the same object/module.</p><p>Consider for example the ecom flow that I’m using throughout this article. The Orders service has to consume multiple events from 3 different topics all related to the same user action (purchasing items in a webstore).</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*aNC8uq4NkUDuHRIs" /><figcaption>Fully event driven micro-services with hard to follow request flow</figcaption></figure><p>The other services also consume multiple events from one or more topics. Let’s assume that it was discovered that some inventory level is incorrect. Being able to investigate all related order handling events is crucial. Otherwise it will take a long time to go to individual services logs and try to manually connect the different pieces of evidence into one cohesive narrative.</p><h4>Automatic Context Propagation</h4><p>Automatically adding identification of the broader request context for all of the events, makes it really simple to filter for all events related to the end-user request. In our ecom example, 2 event headers were added — requestId and userId. Both of these IDs can greatly help with investigations.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*WTK75w8SFQBLmBIc" /><figcaption>Automatically attach user request context for each event for easier tracing &amp; debugging</figcaption></figure><p>At Wix, <a href="https://github.com/wix/greyhound#greyhound">Greyhound</a> automatically propagates the end-user request context when events are produced and consumed. In addition the request context is found also in logs infrastructure, such that logs can be filtered for specific user requests.</p><h3>4. Publishing Events with Large Payloads</h3><p>When processing large event payloads (payloads bigger than 5MB, e.g. Image Recognition, Video Analytics, etc…) it may be tempting to publish them to Kafka (or Pulsar) but there is a risk of greatly increasing latency, reducing throughput and increasing memory pressure (especially when <a href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-405%3A+Kafka+Tiered+Storage">tiered storage</a> is not used)</p><p>Fortunately, there are a few ways to overcome this issue. Including introducing compression, splitting payloads to chunks, and putting the payload in object store and just passing a reference in the streaming platform.</p><h4>Large Payloads Remedy I — Compression</h4><p>Both <a href="https://kafka.apache.org/documentation/#producerconfigs_compression.type">Kafka</a> and <a href="https://pulsar.apache.org/docs/concepts-messaging/#compression">Pulsar</a> allow compression of payloads. You can try several compression types (lz4, snappy, etc.) to find the one best suited for your payload type. If your payload is a bit large (up to 5MB), compression of 50% can help make sure you maintain good performance of your Message broker clusters.</p><p>Compression on Kafka level is usually better than application level, as payloads can be compressed in batches and thus improve compression ratio.</p><h4>Large Payloads Remedy II — Chunking</h4><p>Another way to reduce the pressure on brokers and override message size limitations is to split the messages into chunks.<br>While chunking is already a built-in <a href="https://pulsar.apache.org/docs/concepts-messaging/#chunking">feature</a> of Pulsar (with some limitations), for Kafka chunking has to happen on the application level.</p><p>Examples of how to implement chunking on application level can be found <a href="https://medium.com/wix-engineering/chunks-producer-consumer-f97a834df00d">here</a> and <a href="https://medium.com/workday-engineering/large-message-handling-with-kafka-chunking-vs-external-store-33b0fc4ccf14">here</a>. The basic premise is for producers to send out the chunks with additional metadata that helps consumers to re-assemble them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*enkC5I1wBjQwd7Uh" /><figcaption>producer splits to chunks, consumer figures out how to assemble</figcaption></figure><p>The two examples approaches are different in how they assemble the chunks back to the original payload. The <a href="https://medium.com/wix-engineering/chunks-producer-consumer-f97a834df00d">first example</a> keeps the chunks in some persistent storage and the consumer fetches them once all chunks have been produced. The <a href="https://medium.com/workday-engineering/large-message-handling-with-kafka-chunking-vs-external-store-33b0fc4ccf14">second example</a> makes the consumer seek backwards in the topic partition to the first chunk, once all chunks have arrived.</p><h4>Large Payloads Remedy III — Reference to Object store</h4><p>The final approach is to simply store the payload in an object store (such as <a href="https://aws.amazon.com/s3/">S3</a>) and pass a reference (a URL usually) to the object in the event payload. These object stores allow to persist any required size without impacting first byte latency.</p><p>It’s important to make sure the payload is fully uploaded to the object storage before the link is produced, or else the consumer will need to keep retrying until it can start downloading it.</p><h3>5. Not handling duplicate events</h3><p>Most message brokers and event streaming platforms guarantee <a href="https://medium.com/@madhur25/meaning-of-at-least-once-at-most-once-and-exactly-once-delivery-10e477fafe16">at least once delivery</a> by default. Meaning that some events are duplicated in the stream or potentially can be processed twice (or more). <br>The term for making sure a side-effect of a duplicate event <strong>only happens once</strong> is <a href="https://en.wikipedia.org/wiki/Idempotence">Idempotency</a>.</p><p>Consider the simple ecom flow that I’ve been using throughout this article. In case of duplicate processing due to some processing error, inventory levels recorded into the Inventory database for purchased items may drop more than they actually should.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*4r3D7so86R4DUn4P" /><figcaption>double consumer processing causes inventory level to become incorrect</figcaption></figure><p>Other side-effects include calling a 3rd party api more than once (In our ecom case, it could mean calling inventory service with reduce-level twice for same event and item)</p><h4>Idempotency Remedy — revisionId (versioning)</h4><p><a href="https://vladmihalcea.com/optimistic-vs-pessimistic-locking/">Optimistic locking</a> technique can serve as inspiration in cases where idempotency of event processing is needed. With this technique, the current revisionId (or version) of the stored entity is first read before any update occurs. If more than one party tries to update the entity (while incrementing the version) at the same time (concurrently), the 2nd attempt will fail as the version will no longer match with what it read before.</p><p>In the case of idempotent handling of duplicate events, the revisionId has to be <strong>unique</strong> and <strong>part of the event itself</strong> in order to make sure that two events don’t share the same id and that 2nd updates on the same revisionId will (silently) fail even if does not happen concurrently.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*0v_Y8_-ofk3M-u74xcQXvA.png" /><figcaption>Attaching transactionId for each event to avoid duplicate processing</figcaption></figure><p>Specifically With Kafka, there is a possibility to configure <a href="https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/">exactly once semantics</a>, but still DB duplicate updates can happen due to some failure. Luckily the txnId in this case can just be the topic-partition-offset which is guaranteed to be unique.</p><p>* For more on Exactly once delivery in Kafka you can watch my <a href="https://www.youtube.com/watch?v=7O_UC_i1XY0&amp;t=25s">talk</a> from DevOpsDays Tel Aviv Conference</p><p>I would like to thank Oded Apel, Dalia Simons and Evgeny Krasik for their great feedback!</p><h3>Summary</h3><p>A migration to event-driven architecture can be gradual in order to reduce risks involved with it including harder debugging and mental complexity. Microservices architecture allows flexibility in the choice of pattern for each of the different services. HTTP/RPC endpoints can be called as part of an event’s processing, and vice versa.</p><p>As a consequence of this gradual migration approach I strongly recommend to adopt the <a href="https://en.wikipedia.org/wiki/Change_data_capture">CDC</a> pattern (Database changes streamed as events) as a way to both ensure data consistency (pitfall #1) and avoid the complexity and risks associated with full blown event-sourcing (pitfall #2). The CDC pattern still allows to have the request-reply pattern in place side by side with the event processing pattern.</p><p>Fixing Pitfall #3 (propagation user request context throughout your event streaming flows) will greatly improve your ability to find root causes of production incidents quickly.</p><p>Remediations for Pitfalls #4 and #5 are for more specific uses cases — <em>very large payloads</em> in case of pitfall #4 and non-idempotent side-effects in case of #5. No need to perform the recommended changes in case there is no need for them. Although compression (#4) and transactionIds (#5) are best-practices that you can add by default.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on <a href="https://twitter.com/NSilnitsky">Twitter</a> and Medium.</p><p>You can also visit <a href="https://www.natansil.com/">my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FxfNzGdrxf5w%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DxfNzGdrxf5w&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FxfNzGdrxf5w%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/2e1a459d8573a1921c3ea8bd37002a1f/href">https://medium.com/media/2e1a459d8573a1921c3ea8bd37002a1f/href</a></iframe><h4>Further reading:</h4><ul><li><a href="https://medium.com/wix-engineering/6-event-driven-architecture-patterns-part-1-93758b253f47">6 Event-Driven Architecture Patterns</a></li><li><a href="https://medium.com/wix-engineering/troubleshooting-kafka-for-2000-microservices-at-wix-986ee382fd1e">Troubleshooting Kafka for 2000 Microservices at Wix</a></li><li><a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f">4 Microservices Caching Patterns at Wix</a></li><li><a href="https://medium.com/wix-engineering/leader-election-and-sharding-practices-at-wix-microservices-6e6b853e4852?source=your_stories_page----------------------------------------">Leader election and sharding practices at Wix Microservices</a></li><li><a href="https://www.wix.engineering/post/wix-engineering-tech-interviews-gwen-shapira-and-natan-silnitsky">Gwen Shapira on Event Driven Architecture and Cloud Native Kafka</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b3ebf885bdb1" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Migrating to a Multi-Cluster Managed Kafka with 0 Downtime]]></title>
            <link>https://medium.com/wix-engineering/migrating-to-a-multi-cluster-managed-kafka-with-0-downtime-b936655f888e?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/b936655f888e</guid>
            <category><![CDATA[tiered-storage]]></category>
            <category><![CDATA[multi-cluster]]></category>
            <category><![CDATA[kafka]]></category>
            <category><![CDATA[apache-kafka]]></category>
            <category><![CDATA[cloud]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sat, 26 Mar 2022 14:54:05 GMT</pubDate>
            <atom:updated>2022-12-17T17:56:58.906Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*BbNHDyd0HkcjjHUt" /><figcaption>Photo by <a href="https://unsplash.com/@cgbriggs19?utm_source=medium&amp;utm_medium=referral">Chris Briggs</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>In 2021, my team worked on migrating Wix’s 2000 microservices from self-hosted Kafka clusters to a multi-cluster Managed cloud platform (Confluent Cloud) in a seamless way that did not need to involve the owners of these services. The migration was done during regular traffic without any downtime.</p><p>This was the most challenging project I have ever led, so in this post I want to share with you key design decisions we took, best practices and tips for this kind of migration.</p><h3>Split Overloaded Clusters</h3><p>During the last couple of years, usage of Kafka by business OLTP services at Wix has increased dramatically, as more and more services incorporated event driven architecture.</p><p>Our self-hosted cluster scale increased from 5K topics with &gt;45K partitions in 2019 to 20K topics with &gt;200K partitions.</p><p>Traffic also increased from ~450M records produced per day to &gt;2.5B produced per day per cluster.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*d7S_eeL0Nj9-7ZO6_yoD9g.png" /><figcaption>Kafka usage at Wix before the migration</figcaption></figure><p>This puts a big strain on the cluster controller startup time, as it has to load all this metadata on partitions, which makes the leader election duration greatly increase. It also has a big effect on startup time of individual brokers if they happen to go down causing more and more incidents of under-replicated partitions.</p><p>In order to avoid this instability in our Kafka clusters in production, we decided to migrate our self hosted Kafka clusters to <a href="https://www.confluent.io/confluent-cloud/">Confluent Cloud</a> and split the single-cluster-per-data-center to multiple clusters.</p><h3>Why Managed Kafka</h3><p>Self-managing a Kafka cluster is no easy feat, especially when performing tasks such as rebalancing partitions among brokers, or upgrading broker versions. These can be quite scary and require careful planning and execution. That is especially true when the clusters become overloaded with metadata as was our case.</p><p>Below are 4 benefits of using a managed Kafka cloud platform and Confluent Cloud in particular:</p><ol><li><strong>Better Cluster performance &amp; flexibility<br></strong>Brokers Partition rebalance is done for you, so brokers don’t become performance bottlenecks. You can also easily scale the cluster capacity up or down in order to achieve cost effectiveness.</li><li><strong>Transparent version upgrade<br></strong>The Kafka code base is being improved all of the time, especially focused on <a href="https://cwiki.apache.org/confluence/display/KAFKA/KIP-500%3A+Replace+ZooKeeper+with+a+Self-Managed+Metadata+Quorum">KIP-500</a>: <em>Replace ZooKeeper with a Self-Managed Metadata Quorum</em>. Which, when completed will dramatically increase the amount of metadata each cluster and broker can hold. By going managed, you get automatic version upgrades which improve performance and fix bugs.</li><li><strong>Easy to add a new Cluster<br></strong>In case you require a new cluster. Setting it up is dead simple.</li><li><strong>Tiered Storage<br></strong>Confluent Platform offers <a href="https://docs.confluent.io/platform/current/kafka/tiered-storage.html">Tiered Storage</a>, which allows to dramatically increase the retention period for Kafka records without paying for expensive disk space, by shifting older records to much cheaper <a href="https://aws.amazon.com/s3/">S3</a> storage, without adding latency to latest-offset record consumption.</li></ol><h3>Switching 2000 Microservice to Multi-Cluster Kafka architecture</h3><p>At Wix we have a standard JVM library and Proxy service for interacting with Kafka called <a href="https://github.com/wix/greyhound">Greyhound</a>. It’s an open source high level SDK for Apache Kafka which offers additional features such as concurrent message processing, batch processing, retries, and more. You can read more about it in <a href="https://www.wix.engineering/post/building-a-high-level-sdk-for-kafka-greyhound-unleashed">this article</a> or you can watch<a href="https://www.youtube.com/watch?v=H8blL1gS30k&amp;t=4s"> this talk</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/550/0*XjdQhMw3opixD2oj" /></figure><p>Greyhound is the event-driven backbone of Wix ~2200 microservices, so introducing the multi-cluster concept only had to be done in a few places (including the library and the proxy service). Only new topics’ producers and consumers have to explicitly specify the cluster, as old ones are automatically mapped.</p><p>All that is needed by developers is to define the logical name of the cluster when constructing the greyhound consumer or producer, as can be seen below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rWl1xy-5X4d1RlMM" /></figure><h3>How to Split</h3><p>We decided to split the Kafka clusters according to various <a href="https://en.wikipedia.org/wiki/Service-level_agreement">SLA</a>s. For example, CI/CD pipelines and data migration use cases have different SLA than production services. Important to note that not all data centers have the same amount of Kafka clusters, as each data center serves a different purpose.</p><p>Greyhound (Wix’s own Kafka SDK) knows how to address this issue and avoid crashing in case a cluster is not available in the data center where the service instance is currently running.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/612/0*u-XbQY3tHs-QcvZh" /></figure><h3>Migrate Traffic Drained Data Center?</h3><p>In order to make it easier to migrate producers and consumers of 2000 microservices to multiple managed Kafka clusters, the initial design relied on first <strong>completely draining each data center (DC) from traffic</strong>.</p><p>This design meant that all that was required was to switch the connection details of producers and consumers to their new Kafka clusters. As Wix microservices used Greyhound layer to connect to Kafka clusters, changing connection was required in only one place — Greyhound production configuration (while making sure only 1 DC is affected).</p><p>As simple as this design was, it was unfortunately not possible to implement and execute.<br>There were several reasons:</p><ol><li>There are services that are only deployed in one of the data centers and it is difficult to move them.</li><li>This design means all-or-nothing and is very risky for the moment traffic returns. In case of edge cases that were not switched, they may suffer data loss.</li><li>Traffic cannot be completely drained from a data center for a long period of time, because that could greatly increase the risk of downtime to some service.</li></ol><p>Instead, a new design was planned involving migration during live traffic.</p><h3>Migrate With Traffic</h3><p>Performing migration during live traffic meant that meticulous planning and execution had to take place.</p><p>The process had to be gradual (only affecting some microservices each time in order to reduce blast radius in case there is an issue) and completely automated, in order to reduce chance of manual errors, including automation of a rollback process.</p><p>Migrating producers first (before consumers) was not an option, as it meant a considerable amount of time was needed to make sure all consumers have finished processing all records found on the self-hosted cluster and can safely switch to the new cluster topic. This would have caused considerable delays in processing which could harm certain OLTP business flows and users. Also, rolling back consumers due to some unexpected issue would have been impossible without data loss.</p><p>Active Kafka consumers had to be switched first, while making sure no message is lost and there is minimal re-processing of records. The only way to do this would be to first replicate the records of all the consumed topics from self host cluster to destination managed cluster.</p><h3>Replication</h3><p>In order to make sure no message processing is lost during migration, we created a dedicated replication service. Once all consumer topics were identified, the replicator service was ordered to create the topics in the appropriate cloud clusters, and start consuming records from the self hosted cluster and produce them to the target cluster.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Tbl9FZd7bai54w8c" /></figure><h3>Consumer Migration</h3><p>In order to facilitate consumer migration, the Replicator also persisted the offset mapping for each partition such that the Greyhound consumer can start processing records in the cloud cluster from the correct offset — which was mapped from the first non committed offset in the self-hosted cluster.</p><p>In addition to the Replicator, there was a Migration Orchestrator that made sure a topic was replicated, all offsets were mapped, and then proceeded to request the Greyhound consumer to unsubscribe from the self-hosted cluster. After verifying this was successful, the Orchestrator requested the consumer to subscribe to the cloud cluster, while first seeking the correct mapped offset.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VyorzmEc4j7b5IG_" /></figure><p>In case of failure, the Orchestrator was able to request the consumer to revert back to the self-hosted cluster.</p><p>All this Orchestrator to consumer communication was itself done via dedicated Kafka migration topics. Greyhound consumers started listening to them when they were started.</p><h3>Producer Migration</h3><p>Once all consumers of a certain topic were migrated, it was possible to migrate its producer.<br>The initial migration design entailed requesting the producer to switch cluster connection while still accepting incoming produce requests. This meant buffering the requests in-memory and was deemed quite risky.</p><p>We later came up with a simpler design which relied on Wix’s gradual Kubernetes deployment process. Each new pod starts to accept incoming requests only once all its health checks are OK, including connection to Kafka. As this process is gradual, there are always “older” pods that are running such that the service as a whole is always available for incoming requests.</p><p>On pod startup, the Greyhound producers simply checked a database to ascertain to which cluster they should connect. Much simpler then dynamic cluster switching and records buffering. This meant the migration was safe, no requests could be lost and the service was kept at high availability.</p><h3>Replication bottleneck</h3><p>Only once a producer was migrated, was it acceptable to stop a topic’s replication. But in order to migrate a producer, first all its topic consumers had to be migrated.</p><p>It turned out that many topics had multiple consumers from different services, which meant the Replicator consumer had more and more traffic to process and replicate.</p><p>This caused an issue when a limit was reached to the amount of topics the consumer could handle due to a technical limitation with our relatively old version of self-hosted Kafka brokers. After several attempts to increase message.max.bytes backfired (see <a href="https://issues.apache.org/jira/browse/KAFKA-9254">KAFKA-9254</a> bug) and caused a serious issue, we decided to simply add more Replicator consumers and shard the topics-to-replicate among them.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/898/1*WWKs75LaoXOqnKLnl1mm8g.png" /><figcaption>Sharded Replicator Consumers</figcaption></figure><h3>Beyond Migration — External Consumer Control</h3><p>This “with traffic” migration design opened many new possibilities to dynamically change Greyhound consumers configuration or state without needing to GA a new version to production.</p><p>As now we have the infrastructure in place for Greyhound consumers to listen to incoming commands to change state or configuration. Such commands can include:</p><ol><li>Switch cluster — unsubscribe from current cluster and subscribe to another one</li><li>Skip records — skip records that can’t be processed</li><li>Change processing rate — dynamically increase or decrease amount of parallel processing or add delay for throttling and back-pressure</li><li>Redistribute records — In case there is a growing lag on a single partition, be able to redistribute records among all partitions (and skip the old ones).</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ph7CyMOHRQvq0GpL" /></figure><p>Currently these are all theoretical, but can be much more easily implemented using the migration infrastructure already in place.</p><h3>Best Practices and Tips</h3><p>Below is a list of best practices and tips for a successful Kafka clusters migration:</p><ol><li><strong>Create a script that checks state by itself and stops if expected state is not reached</strong><br>Making the migration process as automatic as possible is key, so having the script check by itself if it can move to the next phase greatly expedite the process. Un the other hand auto-rollback and self-healing is very difficult to get right, so best to leave that for manual intervention.</li><li><strong>Have a rollback readily available<br></strong>No matter how well you tested your migration code, a production environment is the realm of uncertainty. Having a readily available rollback option for each phase is very important. Make sure to prepare it in advance and to test it as much as possible before you start running the migration.</li><li><strong>Start with test/relay topics and no impact topics<br></strong>Migration can be very dangerous, as records can potentially be lost or recovery can be painful. Make sure to start testing your migration code with test topics. In order to have a realistic examination. Use test topics that actually mimic production topics by replicating real production records to the test topics in a special test app. This way, failure in the consumers migration process won’t have any production affect, but it will provide you with a more realistic production simulation.</li><li><strong>Create custom metrics dashboards that show current and evolving state<br></strong>Even if you create a fully unattended automatic migration process, you still need to be able to monitor what is going on and have tools to investigate in case there is an issue. Make sure to prepare dedicated monitoring dashboards in advance that clearly show the current and historical state of consumers and producers you are migrating.<br>In the graph below we can see how a producer successfully switched from self hosted cluster to managed cluster (throughput goes down as more and more pods are restarted and read the new configuration)</li><li><strong>Make sure to be on latest patch version of your self-hosted Kafka broker<br></strong>As our self-hosted Kafka brokers were not on latest patch version, we ended up with a production incident when trying to increase the value of message.max.bytes several times (see more in <em>Replication bottleneck</em> section of this post). My recommendation is to first increase your self-hosted cluster Kafka brokers versions. If not to latest, then at least to latest patch version.</li></ol><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*ckB3o8_wbapJ-pWB" /><figcaption><strong>custom metrics dashboard for producer migration</strong></figcaption></figure><h3>Summary</h3><p>We used Greyhound &amp; dedicated orchestration services and scripts in order to achieve an automatic, safe, and gradual migration in a seamless manner during live traffic.</p><p>This was not an easy task. In case you can completely drain traffic from your data-centers and/or afford processing down time, switching producers and consumers to their new clusters without replicating the data first is highly recommended. It’s a much simpler design that will take you much less time to get done.</p><p>Otherwise, when migration under traffic, you need to keep careful attention to the order in which you perform the migration (Consumers before/after Producers) and make sure you understand the consequences of this decision (ability to rollback, chance of losing data).</p><p>Below you will find a handy flowchart to make it easy for you to understand the various options.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/561/0*v9XqRfbHobMTx2Qw" /></figure><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on <a href="https://twitter.com/NSilnitsky">Twitter</a> and Medium.</p><p>You can also visit <a href="https://www.natansil.com/">my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FXKbG8a-9NRE%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DXKbG8a-9NRE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FXKbG8a-9NRE%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/b2f42fdae814374fa8c45060d0f6b177/href">https://medium.com/media/b2f42fdae814374fa8c45060d0f6b177/href</a></iframe><p><strong>Further reading:</strong></p><ul><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a></li><li><a href="https://medium.com/wix-engineering/6-event-driven-architecture-patterns-part-1-93758b253f47">6 Event-Driven Architecture Patterns</a></li><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Troubleshooting Kafka for 2000 Microservices at Wix</a></li><li><a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f">4 Microservices Caching Patterns at Wix</a></li><li><a href="https://medium.com/wix-engineering/leader-election-and-sharding-practices-at-wix-microservices-6e6b853e4852?source=your_stories_page----------------------------------------">Leader election and sharding practices at Wix Microservices</a></li><li><a href="https://www.wix.engineering/post/wix-engineering-tech-interviews-gwen-shapira-and-natan-silnitsky">Gwen Shapira on Event Driven Architecture and Cloud Native Kafka</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b936655f888e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/migrating-to-a-multi-cluster-managed-kafka-with-0-downtime-b936655f888e">Migrating to a Multi-Cluster Managed Kafka with 0 Downtime</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to choose the right database for your service]]></title>
            <link>https://medium.com/wix-engineering/how-to-choose-the-right-database-for-your-service-97b1670c5632?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/97b1670c5632</guid>
            <category><![CDATA[search-engines]]></category>
            <category><![CDATA[document]]></category>
            <category><![CDATA[key-value-store]]></category>
            <category><![CDATA[relational-databases]]></category>
            <category><![CDATA[microservices]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sat, 25 Sep 2021 15:07:50 GMT</pubDate>
            <atom:updated>2022-08-27T14:51:00.760Z</atom:updated>
            <content:encoded><![CDATA[<p>Choosing which database to use is one of the most important decisions you can make when working on a new microservice.</p><p>If you realize down the line that you’ve made the wrong choice, migrating to another database is a very costly and risky procedure.</p><p>Each database technology (and type) has advantages and disadvantages.</p><p>While there is a convergence happening in some general-purpose databases (that support various models relational / document / key-value at the same time) like MySQL and PostgreSQL, which claim to make your life easier,</p><p>Cloud providers like Amazon offer a dazzling array of database and storage options (e.g. Amazon has Aurora, RDS, DynamoDB, DocumentDB, Keyspaces, elastiCache, S3, elastic file system, etc…), making it harder to figure out which one is the right one.</p><p>Consider the following criteria for choosing the right database technology for your service:</p><h4>Query Patterns</h4><p><strong><em>How complex are your query patterns? Do you just need retrieval by key, or also by various other parameters? Do you also need fuzzy search on the data?</em></strong></p><p>How you are going to fetch your data is one of the main ways to find the best database for your use case. If you are going to fetch data by key, then all you need is a <strong>key-value store</strong> (e.g. <a href="https://aws.amazon.com/dynamodb/">DynamoDB</a>, <a href="https://redis.io/">Redis</a>, <a href="https://aws.amazon.com/s3/">S3</a>, <a href="https://cloud.google.com/storage">GCS</a>).</p><p>In case you mostly fetch via key, but sometimes you also need to fetch by one or two other fields, then <strong>Wide-Column DBs</strong> (e.g.<a href="https://aws.amazon.com/dynamodb/">DynamoDB</a>, <a href="https://cassandra.apache.org/_/index.html">Cassandra</a>) may be right for you.</p><p>On the other hand if you will require to query by many different fields you can choose either <strong>Relational DB</strong> (e.g.<a href="https://www.mysql.com/">MySQL</a>, <a href="https://www.postgresql.org/">PostgreSQL</a>) or <strong>Document DB</strong> (e.g.<a href="https://www.mongodb.com/">MongoDB</a>, <a href="http://couchdb.apache.org/">CouchDB</a>, <a href="https://www.mysql.com/">MySQL</a>, <a href="https://www.postgresql.org/">PostgreSQ</a>). Note that Document DBs don’t support well queries that require joining data from multiple documents.</p><p>Finally, in case you are looking for fuzzy search query capabilities (free text search), then <strong>search engines</strong> like <a href="https://www.elastic.co/">Elasticsearch</a> and <a href="https://solr.apache.org/">Solr</a> are the best fit.</p><h4>Consistency</h4><p><strong><em>Is strong consistency required (read after write, especially when you switch writes to a different data-center) or eventual consistency is OK?</em></strong></p><p>In case you need to read your data right after your write it (i.e. strong consistency) than a <strong>Relational database</strong> (e.g. <a href="https://www.mysql.com/">MySQL</a>, <a href="https://www.postgresql.org/">PostgreSQL</a>) is usually <em>more</em> suited than a <strong>Document Database</strong> (e.g.<a href="https://www.mongodb.com/">MongoDB</a>, <a href="http://couchdb.apache.org/">CouchDB</a>), especially in case of multi-data-center scenario.</p><h4>Storage Capacity</h4><p><strong><em>How much storage capacity is needed?</em></strong></p><p>Most database systems are limited by the amount of space on disk (e.g. <a href="https://www.mysql.com/">MySQL</a>) or struggle with performance as amount of <em>Nodes</em> and <em>Shards</em> grows into the hundreds (e.g. <a href="https://www.elastic.co/">Elasticsearch</a>).</p><p>When infinite storage is needed this is where cloud solutions shine. <strong>Object Storage Services</strong> like <a href="https://aws.amazon.com/s3/">S3</a> and <a href="https://cloud.google.com/storage">GCS</a> will allow you to store as much data as you like with the handy option is <em>multiple tiers</em>, so you pay less for data that is rarely retrieved.</p><h4>Performance</h4><p><strong><em>What is the needed throughput and latency?</em></strong></p><p>All databases performance degrades as the amount of read/write throughput traffic increases. This is the time when optimizations such as re-indexing and re-sharding of your data come in handy.</p><p>In case you have <em>very</em> <em>high</em> traffic and require <em>very low </em>latency, Cloud providers solutions like Amazon’s <a href="https://aws.amazon.com/dynamodb/">DynamoDB</a> and Google’s <a href="https://cloud.google.com/bigtable">Bigtable</a> could be just what you need. As long as your service is deployed on the same data center as the database, you can enjoy latencies that are under 10ms. The downside is of-course the $ cost.</p><h4>Maturity and Stability</h4><p><strong><em>If you choose self-hosted deployment, How much experience does your DBA team have with this technology, how mature is it?</em></strong></p><p>Choosing the most trendy, powerful, and fully featured database to self-host maybe tempting, but as long as your orgainization doesn’t have experience with this database, you may end up regretting it.</p><p>Setup, configuration and fine tuning of databases is a lengthy and risky ordeal. Sometimes choosing the “old” organization self-hosted work-horse will pay bigger dividends in the long term when it comes to <em>production</em> <em>stability</em>.</p><h4>Cost</h4><p><strong><em>If you choose a managed cloud solution, What are the costs? What are its limitations?</em></strong></p><p>The payment model for managed cloud solutions is usually proportional to the read/write traffic. Make sure to read the finer print for each managed solution and make sure that it is cost-effective for your specific read/write usage patterns.</p><p>Below you will find a handy flowchart to help you choose the right database technology for your needs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/996/1*FVW1O3w7hLxSrVALDHswNw.png" /></figure><p>Recently, I wrote an article about <a href="https://medium.com/wix-engineering/5-database-technologies-used-by-2000-wix-microservices-e4769638b8c3">5 Database technologies used by 2000 Wix microservices</a>, where I discuss the pros and cons of each technology and various specific Wix use cases for each one. The technologies are MySQL, MongoDB, DynamoDB, Elasticsearch and S3.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on<a href="https://twitter.com/NSilnitsky"> Twitter</a> and Medium.</p><p>You can also visit<a href="https://www.natansil.com/"> my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><p><strong>Further reading:</strong></p><ul><li><a href="https://medium.com/wix-engineering/5-database-technologies-used-by-2000-wix-microservices-e4769638b8c3">5 Database technologies used by 2000 Wix microservices</a></li><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a></li><li><a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f">4 Microservices Caching Patterns at Wix</a></li><li><a href="https://medium.com/wix-engineering/6-event-driven-architecture-patterns-part-1-93758b253f47">6 Event-Driven Architecture Patterns</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=97b1670c5632" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/how-to-choose-the-right-database-for-your-service-97b1670c5632">How to choose the right database for your service</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[5 Database technologies used by 2000 Wix microservices]]></title>
            <link>https://medium.com/wix-engineering/5-database-technologies-used-by-2000-wix-microservices-e4769638b8c3?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/e4769638b8c3</guid>
            <category><![CDATA[elasticsearch]]></category>
            <category><![CDATA[mysql]]></category>
            <category><![CDATA[mongodb]]></category>
            <category><![CDATA[dynamodb]]></category>
            <category><![CDATA[database]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sun, 12 Sep 2021 15:29:32 GMT</pubDate>
            <atom:updated>2022-08-27T14:51:55.848Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*-CpJnOG5fJP9Wt-j" /><figcaption>Photo by<a href="https://unsplash.com/@gabons?utm_source=medium&amp;utm_medium=referral"> Gabriel Sollmann</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p>Unlike with UI frameworks, or software industry buzzwords, data storage technologies, i.e. databases are famously slow to change, and new innovation takes longer to be adopted.</p><p>For a large organization, switching to a different<a href="https://en.wikipedia.org/wiki/Online_transaction_processing"> OLTP</a> database as your main workhorse happens very rarely. In recent years, with the advent of microservices, more flexibility is given for each service to choose the way it persists it’s data. Still, the risk of using <em>unproven</em> technology sometimes outweighs the benefits, as losing crucial business related data is unacceptable. While the technology may be proven elsewhere, it may not be proven and battle-tested in your organization yet.</p><p>At Wix, the situation is not different, as MySQL is still the main go-to database, more than 10 years after it was first used. Albeit, new and modern MySQL APIs (e.g. JSON Documents) are being used more and more.</p><p>But with 2000 microservices in production, there are of course several storage technologies other than MySQL that are used by a significant portion of services due to various reasons. The reasons range from different API use-cases (e.g. support CRUD API, allow free-text search) to different tech stacks (JVM vs. Node.js) to more demanding technical requirements (infinitely scaling storage).</p><p>5 technologies are described below, each with its own use cases at Wix, unique characteristics, strengths and weaknesses. The technologies are MySQL, MongoDB, DynamoDB, Elasticsearch and S3.</p><p>Read on to get some insights that may help you choose your next microservice storage technology.</p><h3>1. MySQL</h3><figure><img alt="Relational, (+schemaless since 5.7.8) SQL with JOINS JSON type support (since 5.7.8) Open-Source (with proprietary, closed-source modules)" src="https://cdn-images-1.medium.com/max/800/0*DhgAgm-aT0LS451I" /></figure><p><strong><em>Other DBs in this category<br></em></strong><a href="https://www.postgresql.org/">PostgreSQL</a>,<a href="https://mariadb.org/"> MariaDB</a>,<a href="https://www.microsoft.com/en-us/sql-server/sql-server-2019"> SQL Server</a>,<a href="https://www.oracle.com/database/"> Oracle</a>,<a href="https://www.ibm.com/products/db2-database"> Db2</a>,<a href="https://www.sqlite.org/"> SQLite</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*U3arwcZvKzApcSzW" /><figcaption>Source:<a href="https://dasini.net/blog/2019/04/02/mysql-json-document-store/"> Olivier Dasini, Oracle</a></figcaption></figure><p><strong><em>When to use MySQL</em></strong></p><ul><li>When you already widely use it in your organization</li><li>When you want both relational tables (when you know the schema upfront) and JSON collections (Schemaless)</li><li>Relational /<a href="https://towardsdatascience.com/database-normalization-8bba077d12db"> normalized</a> — when you need to optimize on writes instead of reads, to have strong read consistency</li></ul><p><strong><em>MySQL Advantages</em></strong></p><ul><li>Maturity &amp; Reliability — MySQL is highly used, battle tested and mature</li><li>Fast read performance</li><li>Improved JSON/Document support (MySQL 8)</li><li>Cross-DC write consistency (when<a href="https://proxysql.com/"> ProxySQL</a> is used)</li></ul><p><strong><em>MySQL Disadvantages</em></strong></p><ul><li><a href="https://www.wix.engineering/post/scaling-up-wix-pages-storage">Scalability</a> — Does not scale horizontally. Limited by amount of disk space</li><li><a href="https://severalnines.com/blog/mysql-tutorial-troubleshooting-mysql-replication-part-1">Consistency and Replication Issues</a> (when <em>not</em> using<a href="https://proxysql.com/"> ProxySQL</a>)</li></ul><p><strong><em>Example MySQL use cases at Wix</em></strong></p><p><strong>A. Pre MySQL8 JSON support — relational tables with BLOB<br></strong>Almost all JVM (Scala/Java) services at Wix <em>used to</em> store their data in MySQL relational tables. Data was usually denormalized across multiple tables (SQL joins were rarely used). For added flexibility most of the content was kept in<a href="https://dev.mysql.com/doc/refman/8.0/en/blob.html"> BLOB type</a> in order to avoid frequent schema changes that add a lot of risk for production stability.</p><p><strong>B. JSON support and Simple Data Layer<br></strong>Simple Data Layer (SDL) is an internal infrastructure built at Wix in order to help speed-up the development time and reduce cognitive load when persisting a document data structure.</p><p>This is a very common pattern as persistence exists in CRUD methods as well as business operations. The value spans from having sensible defaults like page size through support for WixQL which is part of our <a href="https://dev.wix.com/api/rest/getting-started/api-query-language">API</a> and up to wider cross cutting concerns like GDPR support, emitting domain-changed events, and more.</p><p>It supports the very common need of microservices for a non relational embedded document data structure (to have more operations done by DB instead of in-memory).</p><p>Its engine is MySQL8 with JSON datatype. MySQL was chosen mainly because of Wix DBAs long time experience with MySQL, a lot of infrastructure already in place for backups, migrations, indexing, and for the strong consistency and availability support provided by <em>ProxySQL</em> (see next paragraph)</p><p><strong>C. Multi DC &amp; replication support with ProxySQL<br></strong><a href="https://proxysql.com/">ProxySQL</a> is used in order to seamlessly route <em>write </em>traffic to the currently active main data center’s MySQL clusters without any data loss. It also manages <em>read </em>distribution among replicas. It provides high availability and high performance out of the box.</p><h3>2. MongoDB</h3><figure><img alt="NoSQL, schemaless Document Store JSON/BSON documents OSS/self-hosted (Managed version — Atlas)" src="https://cdn-images-1.medium.com/max/800/0*_raTddUiVsOIAdKs" /><figcaption><a href="https://www.mongodb.com/json-and-bson">BSON</a> , <a href="https://www.mongodb.com/cloud/atlas">Atlas</a></figcaption></figure><p><strong><em>Other DBs in this category<br></em></strong><a href="http://couchdb.apache.org/">CouchDB</a> (many relational/NoSQL DBs now offer JSON support)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/975/0*0qZ0AEzHybCRqZnW.png" /><figcaption>Source: <a href="https://www.mongodb.com/blog/post/getting-started-with-python-and-mongodb">Robert Walters, MongoDB</a></figcaption></figure><p><strong><em>When to use MongoDB</em></strong></p><ul><li>When data schema is predicted to keep changing and evolving</li><li>When working with dynamic JSON content</li><li>When keeping data denormalized is not a problem. i.e. to have eventual consistency</li></ul><p><strong><em>MongoDB Advantages</em></strong></p><ul><li><strong>Flexibility — </strong>with<strong> </strong>Schemaless documents, the number of fields, content and size of the document can differ from one document to another in the same collection.</li><li>Easy to scale with<a href="https://docs.mongodb.com/manual/sharding/"> sharding</a></li></ul><p><strong><em>MongoDB Disadvantages</em></strong></p><ul><li><a href="https://www.bmc.com/blogs/mongodb-memory-usage-and-management/">High Memory Usage</a> — a lot of denormalized data is kept in memory</li><li><a href="https://docs.mongodb.com/manual/core/document/#document-size-limit">Document size limit</a> — 16MB</li><li>Non optimal<a href="https://docs.mongodb.com/manual/replication"> replication</a> solution (data cannot be re-replicated after recovery from failure). Consistency issues on traffic switch to another data center (No automatic remaster)</li></ul><p><strong><em>Example MongoDB use cases at Wix</em></strong></p><p><strong>A. Wix Data<br></strong><em>Wix Data</em> is a service that allows anyone with a Wix website to own a document database — “Database as a Service”). It uses MongoDB behind the scenes to store the data.</p><p>Mongo was chosen in order to be able to store any schemaless (JSON) doc. When the team compared MongoDB performance to MySql 5.7.6, the former had 2X write and read performance over the latter (albeit, this older version of MySql didn’t support JSON natively yet)</p><p>Recently the Wix Data team published a post on<a href="https://www.wix.engineering/post/how-we-re-able-to-host-1-million-sites-per-mongodb-cluster"> how to host 1 million sites per 1 MongoDB cluster</a></p><p><strong>B. Wix Blog<br></strong><em>Wix Blog</em> is Wix’s blog publishing site-app. The backend Node.js microservices use MongoDB to store several TBs worth of blog posts.</p><p>When the project was young the schema was still evolving, and MongoDB’s schema-less nature helped ease the pain of adding new fields to a fast growing database. Data is mostly kept denormalized as MongoDB joins (<em>$lookup</em>) are not convenient to use.</p><h3>3. Amazon DynamoDB</h3><figure><img alt="NoSQL, schemaless key/value + document store Wide-column / column-family Managed (Cloud) service" src="https://cdn-images-1.medium.com/max/800/0*RrcsKexP7nKsFfi3" /><figcaption><a href="https://en.wikipedia.org/wiki/Wide-column_store">wide-column</a>,<a href="https://en.wikipedia.org/wiki/Standard_column_family"> Column-family</a></figcaption></figure><p><strong><em>Other DBs in this category<br></em></strong><a href="https://cassandra.apache.org/">Cassandra</a>,<a href="https://hbase.apache.org/"> HBase</a>,<a href="https://redis.io/"> Redis</a> (Key-value Store)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*IYf8xh3qaOlfQKnz" /></figure><p><strong><em>When to use DynamoDB</em></strong></p><ul><li>When you need a simple key value store without complex querying patterns</li><li>When you need to store expirable data</li><li>Low-medium throughput apps as<a href="https://aws.amazon.com/dynamodb/pricing/provisioned/"> writes are expensive and consistent reads are twice the cost of eventually consistent reads.</a></li></ul><p><strong><em>DynamoDB Advantages</em></strong></p><ul><li>Fast performance in any scale (as long as enough capacity is provisioned)</li><li>No storage limit</li><li>Schemaless — it’s possible to define a schema for each item, rather than for the whole table</li><li>Multi-master replication (update data in multiple regions)</li><li>Supports TTL per item</li><li>Built-in<a href="https://www.striim.com/change-data-capture-cdc-what-it-is-and-how-it-works/"> CDC</a> events (<a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.html">DynamoDB streams</a>)</li></ul><p><strong><em>DynamoDB Disadvantages</em></strong></p><ul><li>Size limit — item can only reach 400KB in size</li><li>Limited querying options (limited number of indices)</li><li>Throttling on burst throughput (and hot keys<a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-partition-key-design.html"> in certain situations</a>)</li></ul><p><strong><em>Example DynamoDB use cases at Wix</em></strong></p><p><strong>A. KVStore + Cache<br></strong>DynamoDB is the back-bone for Wix KV-store cache abstraction. You can find more details<a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f"> in this article</a> (search for <em>(Dynamo)DB+CDC based Cache</em>)</p><p><strong>B. Wix Chat<br></strong>Wix Chat is a service that lets site owners instantly communicate with visitors.</p><p><a href="https://www.wix.engineering/post/wix-inbox-journey-3-approaches-for-zero-downtime-database-migration">They recently migrated</a> their database from Cassandra to DynamoDB, in order to be able to handle growing scale without needing to increase the DBA &amp; operations teams.</p><p>In DynamoDB the Wix Chat team stores chat messages and chat message indications (sent / seen / failed). In addition, data is stored about online site visitors (page, location, entrance time, etc.) which also takes advantage of DynamoDB TTL feature.</p><p><strong>C. Wix Contacts<br></strong>Wix Contacts is a service that manages all contacts of a Wix site owner (Part of<a href="https://www.wix.com/ascend/home"> Ascend</a> business tools suite)</p><p>DynamoDB is used to help orchestrate event-driven bulk jobs (they ​​save the job current status and current offset/page). Each of the job stages is advanced by sending a Kafka event to the appropriate topic. Then the Relevant data is fetched from DynamoDB.</p><h3>4. Elasticsearch</h3><figure><img alt="NoSQL, schemaless Search engine JSON/Lucene segments OSS/self-hosted (Managed version — Elastic Cloud)" src="https://cdn-images-1.medium.com/max/800/0*ugM2jmuBONvR0onr" /><figcaption><a href="https://lucene.apache.org/core/3_0_3/fileformats.html#Segments">Lucene segments</a>,<a href="https://www.elastic.co/cloud/"> Elastic Cloud</a></figcaption></figure><p><strong><em>Other DBs in this category<br></em></strong>Apache Solr, Splunk, Amazon CloudSearch</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/810/0*Wh678r10aTVLy5M0" /><figcaption>source: <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/token-graphs.html">Elasticsearch Guide</a></figcaption></figure><p><strong><em>When to use Elasticsearch</em></strong></p><ul><li>When you need to perform<a href="https://whatis.techtarget.com/definition/fuzzy-search#:~:text=A%20fuzzy%20search%20is%20a,correspond%20to%20the%20desired%20information.&amp;text=A%20fuzzy%20matching%20program%20can,checker%20and%20spelling%2Derror%20corrector."> fuzzy search</a> or have results with ranking</li><li>When you have another data store as source of truth (populate Elasticsearch as a materialized view)</li></ul><p><strong><em>Elasticsearch Advantages</em></strong></p><ul><li>Easy to horizontally scale with<a href="https://medium.com/hipages-engineering/scaling-elasticsearch-b63fa400ee9e"> index sharding</a></li><li><a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html#search-search-api-query-params">Rich</a> search API</li><li>Query for analytical data using<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html"> aggregations</a></li></ul><p><strong><em>Elasticsearch Disadvantages</em></strong></p><ul><li>Indexes are created with a predefined number of shards. More shards requires migration to a new index. Usually done with<a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html"> ReIndex API</a></li><li>Performance issues when indices hit very large scale (&gt; 1TB with hundreds of nodes and shards)</li></ul><p><strong><em>Example Elasticsearch use cases at Wix</em></strong></p><p><strong>Wix Search<br></strong>Wix search allows searching inside any Wix site (out of the box) by having a generic API for indexing per site and installed apps.</p><p>It also provides custom search services for creating and managing self-owned indices by other Wix teams (basically serves as a proxy to Elasticsearch).</p><h3>5. Amazon Simple Storage Service (S3)</h3><figure><img alt="NoSQL, schemaless Key-value, Object Storage Binary data storage Managed (Cloud) service" src="https://cdn-images-1.medium.com/max/800/0*QlI0zTCA8alQvgh8" /><figcaption><a href="https://en.wikipedia.org/wiki/Object_storage">Object Storage</a></figcaption></figure><p><strong><em>Other DBs in this category<br></em></strong><a href="https://cloud.google.com/storage">Google Cloud Storage</a>,<a href="https://azure.microsoft.com/en-us/services/storage/blobs/"> Azure Blob Storage</a></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/897/1*0Cs5hw--xLsWK8Omg91zUA.png" /><figcaption>S3 Stored file URL</figcaption></figure><p><strong><em>When to use S3</em></strong></p><ul><li>When you need to store large binary objects/files (up to 5TB each)</li><li>When the amount of data you need to store is large (&gt;10TB), continues to grow daily, and may need to be retrieved (can’t be deleted)</li></ul><p><strong><em>S3 Advantages</em></strong></p><ul><li>Supports<a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance.html"> very high</a> throughput</li><li>Infinite scalability — No limit on amount of storage</li></ul><p><strong><em>S3 Disadvantages</em></strong></p><ul><li>No Query support, only key-based retrieval</li><li>Latency is<a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/optimizing-performance.html"> 100–200 ms</a> for small objects. Caching can alleviate this</li></ul><p><strong><em>Example S3 use cases at Wix</em></strong></p><p><strong>A. Wix Media<br></strong>Wix Media manages all the media files that are uploaded by Wix site owners. These files are stored, and then accessed when the user’s site gets a visitor.</p><p>In order to have highest possible availability and lowest possible retrieval latency, the media files are stored and replicated between both <em>Amazon S3</em> and <em>Google GCS and</em> cross-region within the same cloud provider.</p><p>A dedicated process moves files to <em>cheaper</em> storage classes (e.g. from S3 <em>Standard</em> to S3<em> Standard-IA</em>) once it finds out they haven’t been accessed for a long time. for more information you can read — <a href="https://www.wix.engineering/post/storage-lifecycle-how-we-cut-cost-on-55-of-our-storage-without-deleting-a-single-file">Storage Lifecycle: How We Cut Cost on 55% of Our Storage Without Deleting a Single File</a></p><p><strong>B. Wix Editor<br></strong>The Wix Editor backend team is in charge of (among other responsibilities) storage and fast retrieval of all Wix site pages during site editing.</p><p>A site page is actually a JSON file. Every change made to a site page means a new immutable JSON file is inserted to the database.</p><p>A couple of years ago<a href="https://www.wix.engineering/post/scaling-up-wix-pages-storage"> they migrated</a> the site pages from MySQL to S3. The main reason was that S3 guaranteed infinite scale (MySQL was unable to handle a scale &gt;10TB well). The S3 latency they measured for read/write ranged from 30 ms on median case to 400ms on p99. In order to improve this they added a write-through caching layer on top of S3.</p><h3>Summary</h3><p>Each database technology (and type) has advantages and disadvantages.</p><p>While there is a convergence happening in some general-purpose databases (that support various models relational / document / key-value at the same time) like MySQL and PostgreSQL,</p><p>Cloud providers like Amazon offer a dazzling array of database and storage options (e.g. Amazon has Aurora, RDS, DynamoDB, DocumentDB, Keyspaces, elastiCache, S3, elastic file system, etc…)</p><p>When choosing a database technology it is very important to consider various criteria:</p><ol><li>How complex are your query patterns? Do you just need retrieval by key, or also by various other parameters? Do you also need fuzzy search on the data?</li><li>Is strong consistency required (read after write, especially when you switch writes to a different data-center) or eventual consistency is OK?</li><li>How much storage capacity is needed?</li><li>What is the needed throughput and latency?</li><li>If you choose self-hosted deployment, How much experience does your DBA team have with this technology, how mature is it?</li><li>If you choose a managed cloud solution, What are the costs? What are its limitations?</li></ol><p>Below you will find a handy flowchart to help you choose the right database technology for your needs.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/800/0*P6G6I_x6kgI-7wtY" /></figure><p>For more <strong>in-depth look</strong> at the <em>various criteria</em> you can read my follow-up article — <a href="https://natansil.medium.com/how-to-choose-the-right-database-for-your-service-97b1670c5632">How to choose the right database for your service</a></p><p>I would like to thank Giedrius Graževičius, Karolis Astrauka, Donatas Remeika, Ittai Zeidman, Baruch Assif Osoveskiy, David Vaks, Avraham Rosenzweig, Idan Yael, &amp; Eyal Malron for their help in detailing their DBs use-cases and technical insights</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future software engineering blog posts, follow me on<a href="https://twitter.com/NSilnitsky"> Twitter</a> and Medium.</p><p>You can also visit<a href="https://www.natansil.com/"> my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><p><strong>Further reading:</strong></p><ul><li><a href="https://natansil.medium.com/how-to-choose-the-right-database-for-your-service-97b1670c5632">How to choose the right database for your service</a></li><li><a href="https://medium.com/wix-engineering/4-microservices-caching-patterns-at-wix-b4dfee1ae22f">4 Microservices Caching Patterns at Wix</a></li><li><a href="https://medium.com/wix-engineering/event-driven-architecture-5-pitfalls-to-avoid-b3ebf885bdb1">Event Driven Architecture — 5 Pitfalls to Avoid</a></li><li><a href="https://medium.com/wix-engineering/6-event-driven-architecture-patterns-part-1-93758b253f47">6 Event-Driven Architecture Patterns</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e4769638b8c3" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/5-database-technologies-used-by-2000-wix-microservices-e4769638b8c3">5 Database technologies used by 2000 Wix microservices</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to successfully manage a ZIO Fiber’s lifecycle]]></title>
            <link>https://medium.com/wix-engineering/how-to-successfully-manage-a-zio-fibers-lifecycle-96fe9c4ecd06?source=rss-32e883029628------2</link>
            <guid isPermaLink="false">https://medium.com/p/96fe9c4ecd06</guid>
            <category><![CDATA[scala]]></category>
            <category><![CDATA[concurrency]]></category>
            <category><![CDATA[zio]]></category>
            <category><![CDATA[multitasking]]></category>
            <category><![CDATA[how-to]]></category>
            <dc:creator><![CDATA[Natan Silnitsky]]></dc:creator>
            <pubDate>Sun, 23 May 2021 07:47:28 GMT</pubDate>
            <atom:updated>2022-12-17T17:56:11.581Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*rMtYYZaxjo3qkLlb" /><figcaption>Photo by <a href="https://unsplash.com/@hjrc33?utm_source=medium&amp;utm_medium=referral">Héctor J. Rivas</a> on <a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral">Unsplash</a></figcaption></figure><p><a href="https://zio.dev/docs/overview/overview_basic_concurrency#fibers">Fibers</a> are the backbone of the highly performant, asynchronous and concurrent abilities of ZIO. They are lightweight “green threads” implemented by the ZIO runtime system.</p><p><em>Forking</em> any IO[E, A] effect means it will immediately run on a new fiber.</p><p>The ZIO <a href="https://zio.dev/docs/datatypes/fiber/fiber">documentation</a> recommends that non-advanced programmers avoid fibers and instead use concurrent primitives like raceWith, zipPar, foreachPar, and so forth, which is sound advice.</p><p>But very soon in a lot of different applications, there comes a need to <em>fork</em> a new fiber. The best example would be — running some recurring job.</p><p><strong>Fiber management edge cases<br></strong>When managing the application’s fibers there are inevitable edge cases each ZIO user has to be familiar with and be comfortable with.</p><p>Errors propagate much better in the asynchronous ZIO runtime (via tracing) than within the Scala Future mechanism. But there are still cases where an error can cause a fiber to die unexpectedly.</p><p>Fibers can also get stuck on some blocking IO operation, and while it may be interruptible, the fact that the fiber is stuck may not be obvious as no error is thrown.</p><p><strong>Track, debug and avoid<br></strong>This article is about how to track, debug and avoid unexpected behaviour in ZIO fibers, including:</p><ol><li>Making sure that fibers do not die without at least some kind of reporting</li><li>Making sure execution will not get stuck when interrupting a fiber</li><li>Having easily available fiber tracking (fiber dump) in place through ZMX or a custom solution</li></ol><h3>1. Handling unexpected failures that can cause fibers to die</h3><p>The code of the example application shown below, creates a periodic job (using the repeat operator) that is forked to run on its own <em>fiber</em>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/958f4e0f1629c609c9894fe4af147b5b/href">https://medium.com/media/958f4e0f1629c609c9894fe4af147b5b/href</a></iframe><p>In order to make sure the job continues to run periodically even when an error occurs the catchAll operator is used <em>before</em> the repeat operator.</p><p><strong>catchAll doesn’t catch all failures<br></strong>Unfortunately, the catchAll operator only catches <em>expected</em> failures. E.g. throwable error on side-effects imported by ZIO.effect or pure errors produced by ZIO.fail</p><p><em>Unexpected</em> failures (aka <em>defects</em>), such as an exception thrown in pure effect ZIO.succeedare not caught by catchAll and will cause the fiber to die.</p><p>This is demonstrated in the standard output of the application:</p><pre>do other stuff<br>Fiber failed.<br>An unchecked error was produced.<br>java.lang.RuntimeException: unexpected defect<br>…<br>do other stuff<br>do other stuff<br>do other stuff<br>…</pre><p>(Note that tapError &amp; retry operators also don’t catch such failures).</p><p><strong>catchAllCause does catch all failures<br></strong>The E type of ZIO[R, E, A] refers only to expected failures. Cause[E] is a description of a full story of failure. <a href="https://zio.dev/docs/datatypes/core/cause#cause-variations">Cause</a> can be either Fail[+E](value: E) or Die(value: Throwable)</p><p>Changing catchAll to catchAllCause will make sure the fiber continues even in case of unexpected error.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/da2383ee4cf041a9c22db91f0f5d71ec/href">https://medium.com/media/da2383ee4cf041a9c22db91f0f5d71ec/href</a></iframe><p>This is reflected in the output of the altered program:</p><pre>do other stuff<br>job failed with Traced(Die(java.lang.RuntimeException: unexpected defect)…<br>do other stuff<br>job failed with Traced(Die(java.lang.RuntimeException: unexpected defect)…<br>…</pre><p>(Note that you can use cause.squashTrace that squashes a Cause down to a single Throwable)</p><p>Usually it is not recommended to keep the fiber going in such extreme cases, but you may require otherwise in your use-case.</p><p><strong>tapCause to help with debugging<br></strong>tapCause is not able to keep the fiber going, but it will at least allow the unexpected error to be reported to the log with all additional information to help with investigation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/054d5857dbd43bf927083050272a598e/href">https://medium.com/media/054d5857dbd43bf927083050272a598e/href</a></iframe><pre>do other stuff<br>job failed with Traced(Die(java.lang.RuntimeException: unexpected defect)…). extra information…<br>Fiber failed.<br>An unchecked error was produced.<br>…</pre><p><strong>withReportFailure<br></strong>You can also set your Runtime Platform’s .withReportFailure in order to report on any uncaught errors, including <em>defects</em>.</p><pre>runtime.mapPlatform(_.withReportFailure(_ =&gt; [report unexpected failure]))</pre><h3>2. Interrupt a Fiber after a grace period</h3><p>Unlike with Scala Futures, ZIO fibers can almost always be interrupted. Only if uninterruptible is specified explicitly, or inside managed resource acquire effect, will the fiber not be interrupted.</p><p>There are certain situations where interrupting a fiber is required. For example, when releasing a managed resource that forked a fiber when it was acquired.</p><p><strong>Abrupt interruption<br></strong>In the following example, a long running fiber is abruptly interrupted after a while.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/da7b4fd9624ca55cd09bbf5e6fa0c63d/href">https://medium.com/media/da7b4fd9624ca55cd09bbf5e6fa0c63d/href</a></iframe><p>The application output shows how the fiber termination happened, immediately after the interrupt effect was interpreted:</p><pre>19:15:38.445 long running job…<br>19:15:38.501 do stuff<br>19:15:39.696 do stuff<br>19:15:40.701 do stuff<br>19:15:40.862 finalizing job!<br>19:15:40.871 do other stuff<br>19:15:41.873 do other stuff</pre><p>The ensuring operator allows to run any finalization effect that is required at the end of fiber execution (in this case it helps with report of time of interruption)</p><p><strong>Graceful interruption<br></strong>In case it is beneficial to allow the fiber a grace period before interruption, the code can be changed as follows (see line 7):</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d94310cfe171591ea1389869871e81f5/href">https://medium.com/media/d94310cfe171591ea1389869871e81f5/href</a></iframe><ol><li>fiber.join — in order to set a timeout, the fiber has to be joined</li><li>.resurrect.ignore — resurrect converts unexpected failures (defects) to regular errors in order to make sure <strong>all</strong> types of errors are ignored. Otherwise any <em>unexpected</em> failure in the forked fiber will cause the <strong>main</strong> fiber to <em>die</em> as well when the former is joined.</li><li>The timeout is specified together with disconnect in order to make sure that timeout will not be blocked by an uninterruptible effect (e.g. due to releasing a managed resource for instance). Setting the job as interruptible also makes sure the timeout will not be blocked</li></ol><p>Line 8:</p><ol><li>timeout.isEmpty — If the timeout elapses then None is returned.</li><li>In the case of a timeout the fiber is still not interrupted, so an explicit interrupt is needed. Here interruptFork is used in case the forked fiber was marked as uninterruptible in order to avoid waiting <strong>forever</strong> for an uninterruptible to get interrupted.</li></ol><p>Now, the output is as follows:</p><pre>19:23:01.422 long running job…<br>19:23:01.492 do stuff<br>19:23:02.689 do stuff<br>19:23:03.693 do stuff<br>19:23:08.960 finalizing job!<br>19:23:08.963 do other stuff<br>19:23:09.964 do other stuff</pre><p>As the output shows, the fiber was only interrupted <strong>after 5 seconds</strong> (the timeout period)</p><p><em>Important note</em>: marking an <em>effect</em> to be forked as interruptible will not have meaning in case the effect itself is uninterruptible. interruptible is only helpful inside some part of a <em>bigger </em>uninterruptible effect.</p><h3>3. Monitoring Fibers state</h3><p>Leaking fibers can cause instability in any ZIO application. For example, performing too many fork operations on the zio <a href="https://degoes.net/articles/zio-threads">Blocking thread pool</a> (which has dynamic size) e.g. effectBlocking([some blocking effect]).forkDaemon can cause memory overloading due to too many open threads.</p><p>Fibers can also die suddenly (as we saw in the first part of this article on <em>defects</em>) or become stuck.</p><p><strong>ZMX fiber dump<br></strong>Performing a fiber dump is sometimes essential to debug the current (troubled) state of your application through the state of its fibers.</p><p>Fortunately, there is ongoing work to introduce such an ability to ZIO through the <a href="https://zio.github.io/zio-zmx/">ZIO-ZMX</a> project.</p><p>On the application (<strong>server</strong>) side, the requirement is to setup a diagnostics <a href="https://zio.dev/docs/datatypes/contextual/zlayer">layer</a></p><pre>val diagnosticsLayer: ZLayer[ZEnv, Throwable, Diagnostics] = Diagnostics.live(“localhost”, 1111)</pre><p>And to supply the runtime Platform with a ZMXSuprvisor:</p><pre>val runtime: Runtime[ZEnv] = Runtime.default.mapPlatform(_.withSupervisor(ZMXSupervisor))</pre><p><a href="https://zio.dev/docs/datatypes/misc/supervisor">Supervisors</a> allow the current state of fibers to be tracked.</p><p>On the <strong>client</strong> side, the interactions is through TPC directly</p><pre>echo -ne ‘*1\r\n$4\r\ndump\r\n’ | nc localhost 1111</pre><p>Or through a Scala ZMXClient.</p><p>For more information, visit the <a href="https://zio.github.io/zio-zmx/docs/overview/overview_diagnostics#client">Diagnostics</a> documentation page of ZMX</p><p><strong>Roll your own fiber dump<br></strong>ZMX is not yet officially released (as of May 2021), and regardless you may wish to create your own custom way of accessing a fiber dump.</p><p>In order to implement your own fiber dump mechanism, follow these steps:</p><ol><li>Create a FiberTracking Service that will access the supervisor’s fibers</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/9ce4802b83ca9722b9a80844a762e992/href">https://medium.com/media/9ce4802b83ca9722b9a80844a762e992/href</a></iframe><p>2. Create a Runtime extension method that creates a <em>supervisor</em> with fiber tracking enabled (Supervisor.track(weak = false)), maps the runtime Platform to include this supervisor, and includes the FiberTracking service in the <em>runtime</em> <em>environment</em>.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5a3a49af4b5c5bfc5dc477fbe2a32a23/href">https://medium.com/media/5a3a49af4b5c5bfc5dc477fbe2a32a23/href</a></iframe><p>3. Create a runtime for your application’s code that sets fiber tracking on using the extension method from the previous phase.</p><p>4. Upon demand, retrieve a snapshot of the currently running fibers from the FiberTracking service and secure a fiber dump string to do with as you wish.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/b43121266099439e7d798c9effe6181b/href">https://medium.com/media/b43121266099439e7d798c9effe6181b/href</a></iframe><p>Note: This example includes a simple console application, but the exact same code can be used for a web server as well.</p><h3>Summary</h3><p>This article described ZIO fiber related edge cases such as a fiber dying due to unexpected failure, or the requirement to interrupt a fiber, either abruptly or gracefully in a successful manner.</p><p>It recommended to use such ZIO operators as ensuring, tapCause, catchAllCause, withReportFailure, resurrect, and disconnect in or to make sure unexpected errors are caught (or at least reported), resources are then released and also that fibers are interrupted safely.</p><p>It also offered a detailed description of how to set up fiber tracking and executing a fiberDump for increased debuggability of your ZIO application.</p><p>I would like to thank Noam Berman, Dmitry Karlinsky and Asaf Jaffi for their help in making this article.</p><p>Thank you for reading!</p><p>If you’d like to get updates on my future ZIO related blog posts, follow me on <a href="https://twitter.com/NSilnitsky">Twitter</a> and Medium.</p><p>You can also visit <a href="https://www.natansil.com/">my website</a>, where you will find my previous blog posts, talks I gave in conferences and open-source projects I’m involved with.</p><p>If anything is unclear or you want to point out something, please comment down below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FzUPtEbPsOqE%3Ffeature%3Doembed&amp;display_name=YouTube&amp;url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DzUPtEbPsOqE&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FzUPtEbPsOqE%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/551a8c4e00a0caf9a92648e7ce822fb8/href">https://medium.com/media/551a8c4e00a0caf9a92648e7ce822fb8/href</a></iframe><p>Further reading:</p><ul><li><a href="https://medium.com/wix-engineering/5-pitfalls-to-avoid-when-starting-to-work-with-zio-adefdc7d2d5c">5 pitfalls to avoid when starting to work with ZIO</a></li><li><a href="https://medium.com/wix-engineering/5-more-pitfalls-to-avoid-when-starting-to-work-with-zio-d0cdd44fa439">5 (more) pitfalls to avoid when starting to work with ZIO</a></li><li><a href="https://medium.com/wix-engineering/5-lessons-learned-from-my-continuing-awesome-journey-with-zio-66319d12ed7c">5 lessons learned from my continuing awesome journey with ZIO</a></li><li><a href="https://medium.com/wix-engineering/easily-create-new-sync-types-with-zio-stm-9a4feeb2c427">Easily Create New Sync Types with ZIO STM</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=96fe9c4ecd06" width="1" height="1" alt=""><hr><p><a href="https://medium.com/wix-engineering/how-to-successfully-manage-a-zio-fibers-lifecycle-96fe9c4ecd06">How to successfully manage a ZIO Fiber’s lifecycle</a> was originally published in <a href="https://medium.com/wix-engineering">Wix Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>