<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Data Pipeline &#8211; Noise</title>
	<atom:link href="https://noise.getoto.net/tag/data-pipeline/feed/" rel="self" type="application/rss+xml" />
	<link>https://noise.getoto.net</link>
	<description>The collective thoughts of the interwebz</description>
	<lastBuildDate>Thu, 20 Mar 2025 00:00:10 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>
	<item>
		<title>Improving Hugo stability and addressing oncall challenges through automation</title>
		<link>https://noise.getoto.net/2025/03/20/improving-hugo-stability-and-addressing-oncall-challenges-through-automation/</link>
		
		<dc:creator><![CDATA[Grab Tech]]></dc:creator>
		<pubDate>Thu, 20 Mar 2025 00:00:10 +0000</pubDate>
				<category><![CDATA[Data Analytics]]></category>
		<category><![CDATA[Data observability]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[Data reliability]]></category>
		<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Platform]]></category>
		<category><![CDATA[System Architecture]]></category>
		<guid isPermaLink="false">https://engineering.grab.com/improving-hugo-stability</guid>

					<description><![CDATA[Introduction

Hugo plays a pivotal role in enabling data ingestion for Grab’s data lake, managing over 4,000 pipelines onboarded by users. The stability of Hugo pipelines is contingent upon the health of both the data sources and various Hugo component...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Incremental Processing using Netflix Maestro and Apache Iceberg</title>
		<link>https://noise.getoto.net/2023/11/21/incremental-processing-using-netflix-maestro-and-apache-iceberg/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Tue, 21 Nov 2023 05:49:38 +0000</pubDate>
				<category><![CDATA[Apache Iceberg]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[data-accuracy]]></category>
		<category><![CDATA[workflow]]></category>
		<guid isPermaLink="false">https://medium.com/p/b8ba072ddeeb</guid>

					<description><![CDATA[by Jun He, Yingyi Zhang, and Pawan DixitIncremental processing is an approach to process new or changed data in workflows. The key advantage is that it only incrementally processes data that are newly added or updated to a dataset, instead of re-proces...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>3. Psyberg: Automated end to end catch up</title>
		<link>https://noise.getoto.net/2023/11/15/3-psyberg-automated-end-to-end-catch-up/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Wed, 15 Nov 2023 03:25:23 +0000</pubDate>
				<category><![CDATA[automated-catchup]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[data-integrity]]></category>
		<category><![CDATA[icebergs]]></category>
		<guid isPermaLink="false">https://medium.com/p/260fbe366fe2</guid>

					<description><![CDATA[By Abhinaya Shetty, Bharath MummadisettyThis blog post will cover how Psyberg helps automate the end-to-end catchup of different pipelines, including dimension tables.In the previous installments of this series, we introduced Psyberg and delved into it...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>2. Diving Deeper into Psyberg: Stateless vs Stateful Data Processing</title>
		<link>https://noise.getoto.net/2023/11/15/2-diving-deeper-into-psyberg-stateless-vs-stateful-data-processing/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Wed, 15 Nov 2023 03:25:13 +0000</pubDate>
				<category><![CDATA[data]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[data-integrity]]></category>
		<category><![CDATA[icebergs]]></category>
		<guid isPermaLink="false">https://medium.com/p/1d273b3aaefb</guid>

					<description><![CDATA[By Abhinaya Shetty, Bharath MummadisettyIn the inaugural blog post of this series, we introduced you to the state of our pipelines before Psyberg and the challenges with incremental processing that led us to create the Psyberg framework within Netflix’...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>1. Streamlining Membership Data Engineering at Netflix with Psyberg</title>
		<link>https://noise.getoto.net/2023/11/15/1-streamlining-membership-data-engineering-at-netflix-with-psyberg/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Wed, 15 Nov 2023 03:24:49 +0000</pubDate>
				<category><![CDATA[data]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[data-integrity]]></category>
		<category><![CDATA[icebergs]]></category>
		<guid isPermaLink="false">https://medium.com/p/f68830617dd1</guid>

					<description><![CDATA[<p>By <a href="https://www.linkedin.com/in/abhinaya-shetty-ab871418/"><em>Abhinaya Shetty</em></a>, <a href="https://www.linkedin.com/in/bharath-chandra-mummadisetty-27591a88/"><em>Bharath Mummadisetty</em></a></p><p>At Netflix, our <strong>Membership and Finance Data Engineering team</strong> harnesses diverse data related to plans, pricing, membership life cycle, and revenue to fuel analytics, power various dashboards, and make data-informed decisions. Many metrics in<strong> </strong><a href="https://s2.bl-1.com/h/i/dtZJ85P6/tWbBNBk"><strong>Netflix’s financial reports</strong></a> are powered and reconciled with efforts from our team! Given our role on this critical path, <strong>accuracy</strong> is paramount. In this context, managing the data, especially when it arrives late, can present a substantial challenge!</p><p>In this three-part blog post series, we introduce you to <strong><em>Psyberg</em>, our incremental data processing framework</strong> designed to tackle such challenges! We’ll discuss batch data processing, the limitations we faced, and how Psyberg emerged as a solution. Furthermore, we’ll delve into the inner workings of Psyberg, its unique features, and how it integrates into our data pipelining workflows. By the end of this series, we hope you will gain an understanding of how Psyberg transformed our data processing, making our pipelines more efficient, accurate, and timely. Let’s dive in!</p><h3>The Challenge: Incremental Data Processing with Late Arriving Data</h3><p>Our teams’ data processing model mainly comprises <strong>batch pipelines</strong>, which run at different intervals ranging from hourly to multiple times a day (also known as intraday) and even daily. We expect <strong>complete and accurate data </strong>at the end of each run. To meet such expectations, we generally run our pipelines with a lag of a few hours to leave room for late-arriving data.</p><h3>What is late-arriving data?</h3><p>Late-arriving data is essentially delayed data due to system retries, network delays, batch processing schedules, system outages, delayed upstream workflows, or reconciliation in source systems.</p><h3>How does late-arriving data impact us?</h3><p>You could think of our data as a puzzle. With each new piece of data, we must fit it into the larger picture and ensure it’s accurate and complete. Thus, we must reprocess the missed data to ensure data completeness and accuracy.</p><h3>Types of late-arriving data</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*Xw5VD9l6P04jy6vM"></figure><p>Based on the structure of our upstream systems, we’ve classified late-arriving data into two categories, each named after the timestamps of the updated partition:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rJmOFmCoW47SCjvHeX0CXQ.png"></figure><h3>Ways to process such data</h3><p>Our team previously employed some strategies to manage these scenarios, which often led to unnecessarily reprocessing unchanged data. Some techniques we used were:</p><p>1. Using<strong> fixed lookback </strong>windows to always reprocess data, assuming that most late-arriving events will occur within that window. However, this approach usually leads to redundant data reprocessing, thereby increasing <a href="https://en.wikipedia.org/wiki/Extract,_transform,_load">ETL</a> processing time and compute costs. It also becomes inefficient as the data scale increases. Imagine reprocessing the past 6 hours of data every hour!</p><p>2. <strong>Add alerts</strong> to flag when late arriving data appears, block the pipelines, and perform a manual intervention where we triggered backfill pipelines to handle the missed events. This approach was a simple solution with minimal extra processing for the most part and, hence, was our preferred solution. However, when the late events occurred, the pain of reprocessing data and catching up on all the dependent pipelines was not worth it! We will talk about this shortly.</p><p>At a high level, both these approaches were inefficient for intraday pipelines and impacted cost, performance, accuracy, and time. We developed <strong>Psyberg</strong>, an incremental processing framework using <a href="https://iceberg.apache.org/">Iceberg</a> to handle these challenges more effectively.</p><h3>The state of our pipelines before Psyberg</h3><p>Before diving into the world of Psyberg, it’s crucial to take a step back and reflect on the state of the data pipelines in our team before its implementation. The complexities involved in these processes and the difficulties they posed led to the development of Psyberg.</p><p>At Netflix, our backend microservices continuously generate real-time event data that gets streamed into Kafka. These raw events are the source of various data processing workflows within our team. We ingest this diverse event data and transform it into standardized fact tables. The fact tables then feed downstream intraday pipelines that process the data hourly. The sequential load ETL shown in the diagram below depicts one such pipeline that calculates an account's state every hour.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*6-ZIOA5PMNz_DPW-"><figcaption>Raw data for hours 3 and 6 arrive. Hour 6 data flows through the various workflows, while hour 3 triggers a late data audit alert.</figcaption></figure><p>Let’s walk through an example to understand the complexity of this pre-Psyberg world.</p><p>Consider a simplified version of our pipelines where we process three events: signups, plan changes, and cancels. Now imagine that some signup events from hour 3 were delayed and sent in at hour 6 instead. Our audits would detect this and alert the on-call data engineer (DE). The on-call DE would then face the daunting task of making things right!</p><p><strong>Step 1</strong>: Dive into the audit logs to identify the late-arriving data and the impacted workflows. In this case, they would discover that the late-arriving data for hour 3 must be included in the signup facts.</p><p><strong>Step 2</strong>: Stop all impacted workflows and downstream jobs (such as the sequential load ETL) and patch the missed data in the fact tables. Now, the data in the signup fact is patched.</p><p><strong>Step 3</strong>: Identify the number of partitions to be rerun for the sequential stateful load jobs to account for the delayed data and rerun them from the impacted date-hour. The DE would note that the data for hours 3–6 needs to be reprocessed and will retrigger four instances to be run sequentially. This step is crucial because missing signup events from hour 3 would result in us missing subsequent events for those affected accounts (e.g., a cancel event for a missed signup would have had no effect). As we capture the state of an account based on the sequence of different types of events, rerunning the sequential load ETL from hours 3 to 6 ensures the accurate representation of account states.</p><p><strong>Step 4</strong>: Now that we’ve spent significant time triaging and resolving the alert, the sequential ETL workflow likely experienced a delay. As a result, we need to catch up to schedule. To compensate for the lost time, the DE must trigger a few additional instances until the latest hour that would have run if the data hadn’t arrived late.</p><p>This entire process was challenging and required significant manual intervention from the on-call DE perspective. Note that these are hourly jobs, so the alert could be triggered at any time of the day (or night!). Yes, they were infrequent, but a big pain point when they occurred! Also, the on-call DE was usually not the SME for these pipelines, as the late data could have arrived in any of our upstream pipelines. To solve these problems, we came up with Psyberg!</p><h3>Psyberg: The Game Changer!</h3><p>Psyberg automates our data loads, making it suitable for various data processing needs, including intraday pipeline use cases. It leverages Iceberg metadata to facilitate processing incremental and batch-based data pipelines.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*i3Q9OtyFGyxh0Zon"></figure><p>One of the critical features of Psyberg is its ability to detect and manage late-arriving data, no matter the partition it lands in. This feature allows data pipelines to handle late-arriving data effectively without manual intervention, ensuring higher data accuracy in our systems. <a href="https://iceberg.apache.org/spec/">Iceberg metadata</a> and Psyberg’s own metadata form the backbone of its efficient data processing capabilities.</p><h3>ETL Process High Watermark</h3><p>This is the last recorded update timestamp for any data pipeline process. This is mainly used to identify new changes since the last update.</p><h3>Iceberg Metadata</h3><p>Psyberg primarily harnesses two key iceberg metadata tables — <em>snapshots and partitions</em> — to manage the workload. All Iceberg tables have associated metadata that provide insight into changes or updates within the data tables.</p><p>The snapshots metadata table records essential metadata such as:</p><ul><li>The creation time of a snapshot</li><li>The type of operation performed (append, overwrite, etc.)</li><li>A summary of partitions created/updated during the generation of the Iceberg snapshot</li></ul><p>These details enable Psyberg to track different operations and identify changes made to a source table since the previous high watermark. For example:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MgEYVLbQnpEnm4aDt3OFMQ.png"></figure><p>The partitions metadata table is particularly interesting as it stores:</p><ul><li>Information about partition keys used in the data table</li><li>Column names and the range of values for each column within a specific partition</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n5c4kslLyEDLKA1aL2bIgw.png"></figure><p>One unique aspect of Netflix’s internal implementation is that it provides the range of values for each column within a partition in a deserialized format. This information helps Psyberg comprehend the timestamp ranges for both types of late-arriving data (event and processing time) without querying the actual data.</p><h3>Psyberg Metadata</h3><p>In addition to Iceberg metadata, Psyberg maintains its own metadata tables — the session table and the high watermark table. Both these tables are partitioned by the pipeline process name to maintain information related to each data pipeline independently.</p><p>The session table captures metadata specific to each pipeline run, including:</p><ul><li>Process name partition to track all the runs associated with the data pipeline process</li><li>Session ID to track unique runs within the process</li><li>Processing URIs to identify the input partitions involved in the load</li><li>“from date”, “from hour”, “to date” and “to hour” for both event and processing times</li></ul><p>The high watermark table stores relevant values from the session table at the end of each pipeline run:</p><ul><li>Latest and previous high water mark timestamp</li><li>Metadata related to the latest run</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*odWvTipThkfPS-r9B_MoKQ.png"></figure><p>This information is vital for each pipeline run instance as it helps determine the data to be loaded, updates the high water mark after processing, and finally generates output signals to inform downstream workflows about the date-hour up to which data is complete and available. It also serves as an essential resource for debugging and creating audits on the pipeline jobs.</p><h3>Conclusion</h3><p>In this post, we described our data architecture at a high level, along with the pain points that led to the development of Psyberg. We also went into details related to the metadata that powers Psyberg. If you understand the challenges faced by the on-call DE and would like to learn more about our solution, please check out the <a href="https://netflixtechblog.medium.com/1d273b3aaefb">next iteration</a> of this three-part series, where we delve deeper into different modes of Psyberg.</p><img src="https://medium.com/_/stat?event=post.clientViewed&#38;referrerSource=full_rss&#38;postId=f68830617dd1" width="1" height="1" alt=""><hr><p><a href="https://netflixtechblog.com/1-streamlining-membership-data-engineering-at-netflix-with-psyberg-f68830617dd1">1. Streamlining Membership Data Engineering at Netflix with Psyberg</a> was originally published in <a href="https://netflixtechblog.com/">Netflix TechBlog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Data ingestion pipeline with Operation Management</title>
		<link>https://noise.getoto.net/2023/03/07/data-ingestion-pipeline-with-operation-management/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Tue, 07 Mar 2023 20:39:08 +0000</pubDate>
				<category><![CDATA[annotations]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[distributed-transaction]]></category>
		<category><![CDATA[machine learning]]></category>
		<category><![CDATA[marken]]></category>
		<guid isPermaLink="false">https://medium.com/p/3c5c638740a8</guid>

					<description><![CDATA[by Varun Sekhri, Meenakshi Jindal, Burak BaciogluIntroductionAt Netflix, to promote and recommend the content to users in the best possible way there are many Media Algorithm teams which work hand in hand with content creators and editors. Several of t...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Ready-to-go sample data pipelines with Dataflow</title>
		<link>https://noise.getoto.net/2022/12/04/ready-to-go-sample-data-pipelines-with-dataflow/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Sun, 04 Dec 2022 00:10:21 +0000</pubDate>
				<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[data-engineering]]></category>
		<category><![CDATA[dataflow]]></category>
		<category><![CDATA[etl]]></category>
		<category><![CDATA[standardization]]></category>
		<guid isPermaLink="false">https://medium.com/p/17440a9e141d</guid>

					<description><![CDATA[<p>by <a href="https://www.linkedin.com/in/ywnfm5/">Jasmine Omeke</a>, <a href="https://www.linkedin.com/in/onwoke/">Obi-Ike Nwoke</a>, <a href="https://www.linkedin.com/in/agorajek/">Olek Gorajek</a></p><h3>Intro</h3><p>This post is for all data practitioners, who are interested in learning about bootstrapping, standardization and automation of batch data pipelines at Netflix.</p><p>You may remember Dataflow from the post we wrote last year titled <a href="https://netflixtechblog.com/data-pipeline-asset-management-with-dataflow-86525b3e21ca">Data pipeline asset management with Dataflow</a>. That article was a deep dive into one of the more technical aspects of Dataflow and didn’t properly introduce this tool in the first place. This time we’ll try to give justice to the intro and then we will focus on one of the very first features Dataflow came with. That feature is called <strong>sample workflows</strong>, but before we start in let’s have a quick look at Dataflow in general.</p><figure><img alt="Dataflow" src="https://cdn-images-1.medium.com/max/1024/1*4IalrwbpzJovyfmA8lMtyA.png"></figure><h4>Dataflow</h4><p>Dataflow is a command line utility built to improve experience and to streamline the data pipeline development at Netflix. Check out this high level Dataflow help command output below:</p><pre>$ dataflow --help<br>Usage: dataflow [OPTIONS] COMMAND [ARGS]...<br><br>Options:<br>  --docker-image TEXT  Url of the docker image to run in.<br>  --run-in-docker      Run dataflow in a docker container.<br>  -v, --verbose        Enables verbose mode.<br>  --version            Show the version and exit.<br>  --help               Show this message and exit.<br><br>Commands:<br>  migration  Manage schema migration.<br>  mock       Generate or validate mock datasets.<br>  project    Manage a Dataflow project.<br>  sample     Generate fully functional sample workflows.</pre><p>As you can see Dataflow CLI is divided into four main subject areas (or commands). The most commonly used one is <strong>dataflow project</strong>, which helps folks in managing their data pipeline repositories through creation, testing, deployment and few other activities.</p><p>The <strong>dataflow migration</strong> command is a special feature, developed single handedly by <a href="https://www.linkedin.com/in/stephenhuenneke/">Stephen Huenneke</a>, to fully automate the communication and tracking of a data warehouse table changes. Thanks to the Netflix internal lineage system (built by <a href="https://www.linkedin.com/in/girish-lingappa-309aa24/">Girish Lingappa</a>) Dataflow migration can then help you identify downstream usage of the table in question. And finally it can help you craft a message to all the owners of these dependencies. After your migration has started Dataflow will also keep track of its progress and help you communicate with the downstream users.</p><p><strong>Dataflow mock</strong> command is another standalone feature. It lets you create YAML formatted mock data files based on selected tables, columns and a few rows of data from the Netflix data warehouse. Its main purpose is to enable easy unit testing of your data pipelines, but it can technically be used in any other situations as a readable data format for small data sets.</p><p>All the above commands are very likely to be described in separate future blog posts, but right now let’s focus on the <strong>dataflow sample </strong>command.</p><h3>Sample workflows</h3><p>Dataflow <strong>sample workflows </strong>is a set of templates anyone can use to bootstrap their data pipeline project. And by “sample” we mean “an example”, like food samples in your local grocery store. One of the main reasons this feature exists is just like with food samples, to give you “a taste” of the production quality ETL code that you could encounter inside the Netflix data ecosystem.</p><p>All the code you get with the Dataflow sample workflows is fully functional, adjusted to your environment and isolated from other sample workflows that others generated. This pipeline is safe to run the moment it shows up in your directory. It will, not only, build a nice example aggregate table and fill it up with real data, but it will also present you with a complete set of recommended components:</p><ul><li>clean DDL code,</li><li>proper table metadata settings,</li><li>transformation job (in a language of choice) wrapped in an optional WAP (Write, Audit, Publish) pattern,</li><li>sample set of data audits for the generated data,</li><li>and a fully functional unit test for your transformation logic.</li></ul><p>And last, but not least, these sample workflows are being tested continuously as part of the Dataflow code change protocol, so you can be sure that what you get is working. This is one way to build trust with our internal user base.</p><p>Next, let’s have a look at the actual business logic of these sample workflows.</p><h4>Business Logic</h4><p>There are several variants of the sample workflow you can get from Dataflow, but all of them share the same business logic. This was a conscious decision in order to clearly illustrate the difference between various languages in which your ETL could be written in. Obviously not all tools are made with the same use case in mind, so we are planning to add more code samples for other (than classical batch ETL) data processing purposes, e.g. Machine Learning model building and scoring.</p><p>The example business logic we use in our template computes the top hundred movies/shows in every country where Netflix operates on a daily basis. This is not an actual production pipeline running at Netflix, because it is a highly simplified code but it serves well the purpose of illustrating a batch ETL job with various transformation stages. Let’s review the transformation steps below.</p><p><strong>Step 1:</strong> on a daily basis, incrementally, sum up all viewing time of all movies and shows in every country</p><pre>WITH STEP_1 AS (<br>   SELECT<br>       title_id<br>       , country_code<br>       , SUM(view_hours) AS view_hours<br>   FROM some_db.source_table<br>   WHERE playback_date = CURRENT_DATE<br>   GROUP BY<br>       title_id<br>       , country_code<br>)</pre><p><strong>Step 2</strong>: rank all titles from most watched to least in every county</p><pre>WITH STEP_2 AS (<br>   SELECT<br>       title_id<br>       , country_code<br>       , view_hours<br>       , RANK() OVER (<br>          PARTITION BY country_code <br>          ORDER BY view_hours DESC<br>       ) AS title_rank<br>   FROM STEP_1<br>)</pre><p><strong>Step 3:</strong> filter all titles to the top 100</p><pre>WITH STEP_3 AS (<br>   SELECT<br>       title_id<br>       , country_code<br>       , view_hours<br>       , title_rank<br>   FROM STEP_2<br>   WHERE title_rank &#60;= 100<br>)</pre><p>Now, using the above simple 3-step transformation we will produce data that can be written to the following Iceberg table:</p><pre>CREATE TABLE IF NOT EXISTS ${TARGET_DB}.dataflow_sample_results (<br>  title_id INT COMMENT "Title ID of the movie or show."<br>  , country_code STRING COMMENT "Country code of the playback session."<br>  , title_rank INT COMMENT "Rank of a given title in a given country."<br>  , view_hours DOUBLE COMMENT "Total viewing hours of a given title in a given country."<br>)<br>COMMENT<br>  "Example dataset brought to you by Dataflow. For more information on this<br>   and other examples please visit the Dataflow documentation page."<br>PARTITIONED BY (<br>  date DATE COMMENT "Playback date."<br>)<br>STORED AS ICEBERG;</pre><p>As you can infer from the above table structure we are going to load about <a href="https://help.netflix.com/en/node/14164">19,000</a> rows into this table on a daily basis. And they will look something like this:</p><pre> sql&#62; SELECT * FROM foo.dataflow_sample_results <br>      WHERE date = 20220101 and country_code = 'US' <br>      ORDER BY title_rank LIMIT 5;<br><br> title_id &#124; country_code &#124; title_rank &#124; view_hours &#124; date<br>----------+--------------+------------+------------+----------<br> 11111111 &#124; US           &#124;          1 &#124;   123      &#124; 20220101<br> 44444444 &#124; US           &#124;          2 &#124;   111      &#124; 20220101<br> 33333333 &#124; US           &#124;          3 &#124;   98       &#124; 20220101<br> 55555555 &#124; US           &#124;          4 &#124;   55       &#124; 20220101<br> 22222222 &#124; US           &#124;          5 &#124;   11       &#124; 20220101<br>(5 rows)</pre><p>With the business logic out of the way, we can now start talking about the components, or the boiler-plate, of our sample workflows.</p><h4>Components</h4><p>Let’s have a look at the most common workflow components that we use at Netflix. These components may not fit into every ETL use case, but are used often enough to be included in every template (or sample workflow). The workflow author, after all, has the final word on whether they want to use all of these patterns or keep only some. Either way they are here to start with, ready to go, if needed.</p><p><strong>Workflow Definitions</strong></p><p>Below you can see a typical file structure of a sample workflow package written in SparkSQL.</p><pre>.<br>├── <strong>backfill.sch.yaml</strong><br>├── <strong>daily.sch.yaml</strong><br>├── <strong>main.sch.yaml</strong><br>├── ddl<br>│   └── dataflow_sparksql_sample.sql<br>└── src<br>    ├── mocks<br>    │   ├── dataflow_pyspark_sample.yaml<br>    │   └── some_db.source_table.yaml<br>    ├── sparksql_write.sql<br>    └── test_sparksql_write.py</pre><p>Above bolded files define a series of steps (a.k.a. jobs) their cadence, dependencies, and the sequence in which they should be executed.</p><p>This is one way we can tie components together into a cohesive workflow. In every sample workflow package there are three workflow definition files that work together to provide flexible functionality. The sample workflow code assumes a daily execution pattern, but it is very easy to adjust them to run at different cadence. For the workflow orchestration we use Netflix homegrown <a href="https://netflixtechblog.com/orchestrating-data-ml-workflows-at-scale-with-netflix-maestro-aaa2b41b800c">Maestro</a> scheduler.</p><p>The <strong><em>main</em></strong> workflow definition file holds the logic of a single run, in this case one day-worth of data. This logic consists of the following parts: <a href="https://docs.google.com/document/d/1iaJPpEGRqiS3Cdxjxhzteup_h5mX5Sk_zEhFDtIxjOE/edit#heading=h.fvqhw2dhwp00">DDL</a> code, table <a href="https://docs.google.com/document/d/1iaJPpEGRqiS3Cdxjxhzteup_h5mX5Sk_zEhFDtIxjOE/edit#heading=h.wugc38fpk98s">metadata</a> information, data <a href="https://docs.google.com/document/d/1iaJPpEGRqiS3Cdxjxhzteup_h5mX5Sk_zEhFDtIxjOE/edit#heading=h.xvk461x30z3o">transformation</a> and a few <a href="https://docs.google.com/document/d/1iaJPpEGRqiS3Cdxjxhzteup_h5mX5Sk_zEhFDtIxjOE/edit#heading=h.1tum3rt1qfhc">audit</a> steps. It’s designed to run for a single date, and meant to be called from the <em>daily</em> or <em>backfill</em> workflows. This <em>main</em> workflow can also be called manually during development with arbitrary run-time parameters to get a feel for the workflow in action.</p><p>The <strong><em>daily</em></strong> workflow executes the <em>main</em> one on a daily basis for the predefined number of previous days. This is sometimes necessary for the purpose of catching up on some late arriving data. This is where we define a trigger schedule, notifications schemes, and update the <a href="https://docs.google.com/document/d/1iaJPpEGRqiS3Cdxjxhzteup_h5mX5Sk_zEhFDtIxjOE/edit#heading=h.lmy247srr96y">“high water mark” timestamps</a> on our target table.</p><p>The <strong><em>backfill</em></strong> workflow executes the <em>main</em> for a specified range of days. This is useful for restating data, most often because of a transformation logic change, but sometimes as a response to upstream data updates.</p><p><strong>DDL</strong></p><p>Often, the first step in a data pipeline is to define the target table structure and column metadata via a DDL statement. We understand that some folks choose to have their output schema be an implicit result of the transform code itself, but the explicit statement of the output schema is not only useful for adding table (and column) level comments, but also serves as one way to validate the transform logic.</p><pre>.<br>├── backfill.sch.yaml<br>├── daily.sch.yaml<br>├── main.sch.yaml<br>├── ddl<br>│   └── <strong>dataflow_sparksql_sample.sql</strong><br>└── src<br>    ├── mocks<br>    │   ├── dataflow_pyspark_sample.yaml<br>    │   └── some_db.source_table.yaml<br>    ├── sparksql_write.sql<br>    └── test_sparksql_write.py</pre><p>Generally, we prefer to execute DDL commands as part of the workflow itself, instead of running outside of the schedule, because it simplifies the development process. See below example of hooking the table creation SQL file into the <em>main</em> workflow definition.</p><pre>      - job:<br>          id: ddl<br>          type: Spark<br>          spark:<br>              script: $S3{./ddl/dataflow_sparksql_sample.sql}<br>              parameters:<br>                  TARGET_DB: ${TARGET_DB}</pre><p><strong>Metadata</strong></p><p>The metadata step provides context on the output table itself as well as the data contained within. Attributes are set via <a href="https://netflixtechblog.com/metacat-making-big-data-discoverable-and-meaningful-at-netflix-56fb36a53520">Metacat</a>, which is a Netflix internal metadata management platform. Below is an example of plugging that metadata step in the <em>main</em> workflow definition</p><pre>     - job:<br>          id: metadata<br>          type: Metadata<br>          metacat:<br>              tables:<br>                - ${CATALOG}/${TARGET_DB}/${TARGET_TABLE}<br>              owner: ${username}<br>              tags:<br>                - dataflow<br>                - sample<br>              lifetime: 123<br>              column_types:<br>                date: pk<br>                country_code: pk<br>                rank: pk</pre><p><strong>Transformation</strong></p><p>The transformation step (or steps) can be executed in the developer’s language of choice. The example below is using SparkSQL.</p><pre>.<br>├── backfill.sch.yaml<br>├── daily.sch.yaml<br>├── main.sch.yaml<br>├── ddl<br>│   └── dataflow_sparksql_sample.sql<br>└── src<br>    ├── mocks<br>    │   ├── dataflow_pyspark_sample.yaml<br>    │   └── some_db.source_table.yaml<br>    ├── <strong>sparksql_write.sql</strong><br>    └── test_sparksql_write.py</pre><p>Optionally, this step can use the Write-Audit-Publish <a href="https://www.dremio.com/subsurface/write-audit-publish-pattern-via-apache-iceberg/">pattern</a> to ensure that data is correct before it is made available to the rest of the company. See example below:</p><pre>      - template:<br>          id: wap<br>          type: wap<br>          tables:<br>              - ${CATALOG}/${DATABASE}/${TABLE}<br>          write_jobs:<br>            - job:<br>                id: write<br>                type: Spark<br>                spark:<br>                    script: $S3{./src/sparksql_write.sql}</pre><p><strong>Audits</strong></p><p>Audit steps can be defined to verify data quality. If a “blocking” audit fails, the job will halt and the write step is not committed, so invalid data will not be exposed to users. This step is optional and configurable, see a partial example of an audit from the <em>main</em> workflow below.</p><pre>         data_auditor:<br>            audits:<br>              - function: columns_should_not_have_nulls<br>                blocking: true<br>                params:<br>                    table: ${TARGET_TABLE}<br>                    columns:<br>                      - title_id<br>                      …</pre><p><strong>High-Water-Mark Timestamp</strong></p><p>A successful write will typically be followed by a metadata call to set the valid time (or high-water mark) of a dataset. This allows other processes, consuming our table, to be notified and start their processing. See an example high water mark job from the <em>main</em> workflow definition.</p><pre>      - job:<br>         id: hwm<br>         type: HWM<br>         metacat:<br>           table: ${CATALOG}/${TARGET_DB}/${TARGET_TABLE}<br>           hwm_datetime: ${EXECUTION_DATE}<br>           hwm_timezone: ${EXECUTION_TIMEZONE}</pre><p><strong>Unit Tests</strong></p><p>Unit test artifacts are also generated as part of the sample workflow structure. They consist of data mocks, the actual test code, and a simple execution harness depending on the workflow language. See the bolded file below.</p><pre>.<br>├── backfill.sch.yaml<br>├── daily.sch.yaml<br>├── main.sch.yaml<br>├── ddl<br>│   └── dataflow_sparksql_sample.sql<br>└── src<br>    ├── mocks<br>    │   ├── <strong>dataflow_pyspark_sample.yaml</strong><br>    │   └── <strong>some_db.source_table.yaml</strong><br>    ├── sparksql_write.sql<br>    └── <strong>test_sparksql_write.py</strong></pre><p>These unit tests are intended to test one “unit” of data transform in isolation. They can be run during development to quickly capture code typos and syntax issues, or during automated testing/deployment phase, to make sure that code changes have not broken any tests.</p><p>We want unit tests to run quickly so that we can have continuous feedback and fast iterations during the development cycle. Running code against a production database can be slow, especially with the overhead required for distributed data processing systems like Apache Spark. Mocks allow you to run tests locally against a small sample of “real” data to validate your transformation code functionality.</p><h4>Languages</h4><p>Over time, the extraction of data from Netflix’s source systems has grown to encompass a wider range of end-users, such as engineers, data scientists, analysts, marketers, and other stakeholders. Focusing on convenience, Dataflow allows for these differing personas to go about their work seamlessly. A large number of our data users employ SparkSQL, pyspark, and Scala. A small but growing contingency of data scientists and analytics engineers use R, backed by the Sparklyr interface or other data processing tools, like <a href="https://docs.metaflow.org/introduction/what-is-metaflow">Metaflow</a>.</p><p>With an understanding that the data landscape and the technologies employed by end-users are not homogenous, Dataflow creates a malleable path toward. It solidifies different recipes or repeatable templates for data extraction. Within this section, we’ll preview a few methods, starting with sparkSQL and python’s manner of creating data pipelines with dataflow. Then we’ll segue into the Scala and R use cases.</p><p>To begin, after installing Dataflow, a user can run the following command to understand how to get started.</p><pre>$ dataflow sample workflow --help                                                         <br>Dataflow (0.6.16)<br><br>Usage: dataflow sample workflow [OPTIONS] RECIPE [TARGET_PATH]<br><br>Create a sample workflow based on selected RECIPE and land it in the <br>specified TARGET_PATH.<br><br>Currently supported workflow RECIPEs are: spark-sql, pyspark, <br>scala and sparklyr.<br><br>  If TARGET_PATH:<br>  - if not specified, current directory is assumed<br>  - points to a directory, it will be used as the target location<br><br>Options:<br>  --source-path TEXT         Source path of the sample workflows.<br>  --workflow-shortname TEXT  Workflow short name.<br>  --workflow-id TEXT         Workflow ID.<br>  --skip-info                Skip the info about the workflow sample.<br>  --help                     Show this message and exit.</pre><p>Once again, let’s assume we have a directory called <em>stranger-data</em> in which the user creates workflow templates in all four languages that Dataflow offers. To better illustrate how to generate the sample workflows using Dataflow, let’s look at the full command one would use to create one of these workflows, e.g:</p><pre>$ cd stranger-data<br>$ dataflow sample workflow spark-sql ./sparksql-workflow</pre><p>By repeating the above command for each type of transformation language we can arrive at the following directory structure</p><pre>.<br>├── <strong>pyspark-workflow</strong><br>│   ├── main.sch.yaml<br>│   ├── daily.sch.yaml<br>│   ├── backfill.sch.yaml<br>│   ├── ddl<br>│   │   └── ...<br>│   ├── src<br>│   │   └── ...<br>│   └── tox.ini<br>├── <strong>scala-workflow</strong><br>│   ├── build.gradle<br>│   └── ...<br>├── <strong>sparklyR-workflow</strong><br>│   └── ...<br>└── <strong>sparksql-workflow</strong><br>    └── ...</pre><p>Earlier we talked about the business logic of these sample workflows and we showed the Spark SQL version of that example data transformation. Now let’s discuss different approaches to writing the data in other languages.</p><p><strong>PySpark</strong></p><p>This partial <strong>pySpark </strong>code below will have the same functionality as the SparkSQL example above, but it utilizes Spark dataframes Python interface.</p><pre>def main(args, spark):<br>   <br>    source_table_df = spark.table(f"{some_db}.{source_table})<br><br>    viewing_by_title_country = (<br>        source_table_df.select("title_id", "country_code",      <br>        "view_hours")<br>        .filter(col("date") == date)<br>        .filter("title_id IS NOT NULL AND view_hours &#62; 0")<br>        .groupBy("title_id", "country_code")<br>        .agg(F.sum("view_hours").alias("view_hours"))<br>    )<br><br>    window = Window.partitionBy(<br>        "country_code"<br>    ).orderBy(col("view_hours").desc())<br><br>    ranked_viewing_by_title_country = viewing_by_title_country.withColumn(<br>        "title_rank", rank().over(window)<br>    )<br><br>    ranked_viewing_by_title_country.filter(<br>        col("title_rank") &#60;= 100<br>    ).withColumn(<br>        "date", lit(int(date))<br>    ).select(<br>        "title_id",<br>        "country_code",<br>        "title_rank",<br>        "view_hours",<br>        "date",<br>    ).repartition(1).write.byName().insertInto(<br>        target_table, overwrite=True<br>    )</pre><p><strong>Scala</strong></p><p>Scala is another Dataflow supported recipe that offers the same business logic in a sample workflow out of the box.</p><pre>package com.netflix.spark<br><br>object ExampleApp {<br>  import spark.implicits._<br><br>  def readSourceTable(sourceDb: String, dataDate: String): DataFrame =<br>    spark<br>      .table(s"$someDb.source_table")<br>      .filter($"playback_start_date" === dataDate)<br><br>  def viewingByTitleCountry(sourceTableDF: DataFrame): DataFrame = {<br>    sourceTableDF<br>      .select($"title_id", $"country_code", $"view_hours")<br>      .filter($"title_id".isNotNull)<br>      .filter($"view_hours" &#62; 0)<br>      .groupBy($"title_id", $"country_code")<br>      .agg(F.sum($"view_hours").as("view_hours"))<br>  }<br><br>  def addTitleRank(viewingDF: DataFrame): DataFrame = {<br>    viewingDF.withColumn(<br>      "title_rank", F.rank().over(<br>        Window.partitionBy($"country_code").orderBy($"view_hours".desc)<br>      )<br>    )<br>  }<br><br>  def writeViewing(viewingDF: DataFrame, targetTable: String, dataDate: String): Unit = {<br>    viewingDF<br>      .select($"title_id", $"country_code", $"title_rank", $"view_hours")<br>      .filter($"title_rank" &#60;= 100)<br>      .repartition(1)<br>      .withColumn("date", F.lit(dataDate.toInt))<br>      .writeTo(targetTable)<br>      .overwritePartitions()<br>  }<br><br>def main():<br>    sourceTableDF = readSourceTable("some_db", "source_table", 20200101)<br>    viewingDf = viewingByTitleCountry(sourceTableDF)<br>    titleRankedDf = addTitleRank(viewingDF)<br>    writeViewing(titleRankedDf)</pre><p>R / sparklyR</p><p>As Netflix has a growing cohort of R users, R is the latest recipe available in Dataflow.</p><pre>suppressPackageStartupMessages({<br>  library(sparklyr)<br>  library(dplyr)<br>})<br><br>...<br><br>main &#60;- function(args, spark) {<br>  title_df &#60;- tbl(spark, g("{some_db}.{source_table}"))<br><br>  title_activity_by_country &#60;- title_df &#124;&#62;<br>    filter(title_date == date) &#124;&#62;<br>    filter(!is.null(title_id) &#38; event_count &#62; 0) &#124;&#62;<br>    select(title_id, country_code, event_type) &#124;&#62;<br>    group_by(title_id, country_code) &#124;&#62;<br>    summarize(event_count = sum(event_type, na.rm = TRUE))<br><br>  ranked_title_activity_by_country &#60;- title_activity_by_country  &#124;&#62;<br>    group_by(country_code) &#124;&#62;<br>    mutate(title_rank = rank(desc(event_count)))<br><br>  top_25_title_by_country &#60;- ranked_title_activity_by_country &#124;&#62;<br>    ungroup() &#124;&#62;<br>    filter(title_rank &#60;= 25) &#124;&#62;<br>    mutate(date = as.integer(date)) &#124;&#62;<br>    select(<br>      title_id,<br>      country_code,<br>      title_rank,<br>      event_count,<br>      date<br>    )<br><br>    top_25_title_by_country &#124;&#62;<br>      sdf_repartition(partitions = 1) &#124;&#62;<br>      spark_insert_table(target_table, mode = "overwrite")<br>}<br>  main(args = args, spark = spark)<br>}</pre><h3>Conclusions</h3><p>As you can see we try to make Netflix data engineering life easier by offering paved paths and suggestions on how to structure their code, while trying to keep the variety of options wide enough so they can pick and choose what works best for them in any particular case.</p><p>Having a well-defined set of defaults for data pipeline creation across Netflix makes onboarding easier, provides standardization and centralization best practices. Let’s review them below.</p><h4>Onboarding</h4><p>Ramping up on a new team or a business vertical always takes some effort, especially in a “highly aligned, loosely coupled” <a href="https://jobs.netflix.com/culture">culture</a>. Having a well-documented starting point removes some of the struggle that comes with starting from scratch and considerably speeds up the first iteration of the development cycle.</p><h4>Standardization</h4><p>Standardization makes life easier for new team members as well as those already familiar with the domain and tech stack.</p><p>Some transfer of work between people or teams is inevitable. Having standardized layout and patterns removes friction from this exchange. Also, code reviews and suggestions are easier to manage when working from a similar baseline.</p><p>Standardization also makes project layout more intuitive and minimizes risk of human error as the codebase evolves.</p><h4>Centralized Best Practices</h4><p>Data infrastructure evolves continually. Having easy access to a centralized set of good defaults is critical to ensure that best practices evolve along with the technology, and that users are aware of what’s the latest on the tech-stack menu.</p><p>Even better, Dataflow offers <strong>executable</strong> best practices, which present these concepts in the context of an actual use case. Instead of reading documentation, you can initialize a “real” project, change it as needed, and iterate from there.</p><h3>Credits</h3><p>Special thanks to <a href="https://www.linkedin.com/in/danielbwatson/">Daniel Watson</a>, <a href="https://www.linkedin.com/in/jim-hester/">Jim Hester</a>, <a href="https://www.linkedin.com/in/stephenhuenneke/">Stephen Huenneke</a>, <a href="https://www.linkedin.com/in/girish-lingappa-309aa24/">Girish Lingappa</a> for their contributions to Dataflow sample workflows and to <a href="https://www.linkedin.com/in/andreahairston/">Andrea Hairston</a> for the Dataflow logo design.</p><h3>Next Episode</h3><p>Hopefully you won’t need to wait another year to read about other features of Dataflow. Here are a few topics that we could write about next. Please have a look at the subjects below and, if you feel strongly about any of them, let us know in the comments section:</p><ul><li><strong>Branch driven deployment</strong> — to explain how Dataflow lets anyone customize their CI/CD jobs based on the git branch for easy testing in isolated environments.</li><li><strong>Local SparkSQL unit testing</strong>— to clarify how Dataflow helps in making robust unit tests for Spark SQL transform code, with ease.</li><li><strong>Data migrations made easy</strong> — to show how Dataflow can be used to plan a table migration, support the communication with downstream users and help in monitoring it to completion.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&#38;referrerSource=full_rss&#38;postId=17440a9e141d" width="1" height="1" alt=""><hr><p><a href="https://netflixtechblog.com/ready-to-go-sample-data-pipelines-with-dataflow-17440a9e141d">Ready-to-go sample data pipelines with Dataflow</a> was originally published in <a href="https://netflixtechblog.com/">Netflix TechBlog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Orchestrating Data/ML Workflows at Scale With Netflix Maestro</title>
		<link>https://noise.getoto.net/2022/10/18/orchestrating-data-ml-workflows-at-scale-with-netflix-maestro/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Tue, 18 Oct 2022 20:43:36 +0000</pubDate>
				<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[distributed-systems]]></category>
		<category><![CDATA[machine learning]]></category>
		<category><![CDATA[Orchestration]]></category>
		<category><![CDATA[workflow]]></category>
		<guid isPermaLink="false">https://medium.com/p/aaa2b41b800c</guid>

					<description><![CDATA[<p>by <a href="https://www.linkedin.com/in/jheua/">Jun He</a>, <a href="https://www.linkedin.com/in/akash-dwivedi-b9779317">Akash Dwivedi</a>, <a href="https://www.linkedin.com/in/natalliadzenisenka/">Natallia Dzenisenka</a>, <a href="https://www.linkedin.com/in/snehalchennuru">Snehal Chennuru</a>, <a href="https://www.linkedin.com/in/praneethy91">Praneeth Yenugutala</a>, <a href="https://www.linkedin.com/in/pawan-dixit-b4307b2/">Pawan Dixit</a></p><p>At Netflix, Data and Machine Learning (ML) pipelines are widely used and have become central for the business, representing diverse use cases that go beyond recommendations, predictions and data transformations. A large number of batch workflows run daily to serve various business needs. These include ETL pipelines, ML model training workflows, batch jobs, etc. As Big data and ML became more prevalent and impactful, the scalability, reliability, and usability of the orchestrating ecosystem have increasingly become more important for our data scientists and the company.</p><p>In this blog post, we introduce and share learnings on Maestro, a workflow orchestrator that can schedule and manage workflows at a massive scale.</p><h3>Motivation</h3><p>Scalability and usability are essential to enable large-scale workflows and support a wide range of use cases. Our existing orchestrator (Meson) has worked well for several years. It schedules around 70 thousands of workflows and half a million jobs per day. Due to its popularity, the number of workflows managed by the system has grown exponentially. We started seeing signs of scale issues, like:</p><ul><li>Slowness during peak traffic moments like 12 AM UTC, leading to increased operational burden. The scheduler on-call has to closely monitor the system during non-business hours.</li><li>Meson was based on a single leader architecture with high availability. As the usage increased, we had to vertically scale the system to keep up and were approaching AWS instance type limits.</li></ul><p>With the high growth of workflows in the past few years — increasing at &#62; 100% a year, the need for a scalable data workflow orchestrator has become paramount for Netflix’s business needs. After perusing the current landscape of workflow orchestrators, we decided to develop a next generation system that can scale horizontally to spread the jobs across the cluster consisting of 100’s of nodes. It addresses the key challenges we face with Meson and achieves operational excellence.</p><h3>Challenges in Workflow Orchestration</h3><h4>Scalability</h4><p>The orchestrator has to schedule hundreds of thousands of workflows, millions of jobs every day and operate with a strict SLO of less than 1 minute of scheduler introduced delay even when there are spikes in the traffic. At Netflix, the peak traffic load can be a few orders of magnitude higher than the average load. For example, a lot of our workflows are run around midnight UTC. Hence, the system has to withstand bursts in traffic while still maintaining the SLO requirements. Additionally, we would like to have a single scheduler cluster to manage most of user workflows for operational and usability reasons.</p><p>Another dimension of scalability to consider is the size of the workflow. In the data domain, it is common to have a super large number of jobs within a single workflow. For example, a workflow to backfill hourly data for the past five years can lead to 43800 jobs (24 * 365 * 5), each of which processes data for an hour. Similarly, ML model training workflows usually consist of tens of thousands of training jobs within a single workflow. Those large-scale workflows might create hotspots and overwhelm the orchestrator and downstream systems. Therefore, the orchestrator has to manage a workflow consisting of hundreds of thousands of jobs in a performant way, which is also quite challenging.</p><h4>Usability</h4><p>Netflix is a data-driven company, where key decisions are driven by data insights, from the pixel color used on the landing page to the renewal of a TV-series. Data scientists, engineers, non-engineers, and even content producers all run their data pipelines to get the necessary insights. Given the diverse backgrounds, usability is a cornerstone of a successful orchestrator at Netflix.</p><p>We would like our users to focus on their business logic and let the orchestrator solve cross-cutting concerns like scheduling, processing, error handling, security etc. It needs to provide different grains of abstractions for solving similar problems, high-level to cater to non-engineers and low-level for engineers to solve their specific problems. It should also provide all the knobs for configuring their workflows to suit their needs. In addition, it is critical for the system to be debuggable and surface all the errors for users to troubleshoot, as they improve the UX and reduce the operational burden.</p><p>Providing abstractions for the users is also needed to save valuable time on creating workflows and jobs. We want users to rely on shared templates and reuse their workflow definitions across their team, saving time and effort on creating the same functionality. Using job templates across the company also helps with upgrades and fixes: when the change is made in a template it’s automatically updated for all workflows that use it.</p><p>However, usability is challenging as it is often opinionated. Different users have different preferences and might ask for different features. Sometimes, the users might ask for the opposite features or ask for some niche cases, which might not necessarily be useful for a broader audience.</p><h3>Introducing Maestro</h3><p>Maestro is the next generation Data Workflow Orchestration platform to meet the current and future needs of Netflix. It is a general-purpose workflow orchestrator that provides a fully managed workflow-as-a-service (WAAS) to the data platform at Netflix. It serves thousands of users, including data scientists, data engineers, machine learning engineers, software engineers, content producers, and business analysts, for various use cases.</p><p>Maestro is highly scalable and extensible to support existing and new use cases and offers enhanced usability to end users. Figure 1 shows the high-level architecture.</p><figure><img alt="Figure 1. Maestro high level architecture" src="https://cdn-images-1.medium.com/max/1024/0*SDt718rSvgh2Nclv"><figcaption>Figure 1. Maestro high level architecture</figcaption></figure><p>In Maestro, a workflow is a <a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph">DAG (Directed acyclic graph)</a> of individual units of job definition called Steps. Steps can have dependencies, triggers, workflow parameters, metadata, step parameters, configurations, and branches (conditional or unconditional). In this blog, we use step and job interchangeably. A workflow instance is an execution of a workflow, similarly, an execution of a step is called a step instance. Instance data include the evaluated parameters and other information collected at runtime to provide different kinds of execution insights. The system consists of 3 main micro services which we will expand upon in the following sections.</p><p>Maestro ensures the business logic is run in isolation. Maestro launches a unit of work (a.k.a. Steps) in a container and ensures the container is launched with the users/applications identity. Launching with identity ensures the work is launched on-behalf-of the user/application, the identity is later used by the downstream systems to validate if an operation is allowed or not, for an example user/application identity is checked by the data warehouse to validate if a table read/write is allowed or not.</p><h4>Workflow Engine</h4><p>Workflow engine is the core component, which manages workflow definitions, the lifecycle of workflow instances, and step instances. It provides rich features to support:</p><ul><li>Any valid DAG patterns</li><li>Popular data flow constructs like sub workflow, <a href="https://netflixtechblog.com/#7d0f">foreach</a>, conditional branching etc.</li><li>Multiple failure modes to handle step failures with different error retry policies</li><li>Flexible concurrency control to throttle the number of executions at workflow/step level</li><li>Step templates for common job patterns like running a Spark query or moving data to Google sheets</li><li>Support parameter code injection using customized expression language</li><li>Workflow definition and ownership management.<br>Timeline including all state changes and related debug info.</li></ul><p>We use <a href="https://conductor.netflix.com/">Netflix open source project Conductor</a> as a library to manage the workflow state machine in Maestro. It ensures to enqueue and dequeue each step defined in a workflow with at least once guarantee.</p><h4>Time-Based Scheduling Service</h4><p>Time-based scheduling service starts new workflow instances at the scheduled time specified in workflow definitions. Users can define the schedule using cron expression or using periodic schedule templates like hourly, weekly etc;. This service is lightweight and provides an at-least-once scheduling guarantee. Maestro engine service will deduplicate the triggering requests to achieve an exact-once guarantee when scheduling workflows.</p><p>Time-based triggering is popular due to its simplicity and ease of management. But sometimes, it is not efficient. For example, the daily workflow should process the data when the data partition is ready, not always at midnight. Therefore, on top of manual and time-based triggering, we also provide event-driven triggering.</p><h4>Signal Service</h4><p>Maestro supports event-driven triggering over signals, which are pieces of messages carrying information such as parameter values. Signal triggering is efficient and accurate because we don’t waste resources checking if the workflow is ready to run, instead we only execute the workflow when a condition is met.</p><p>Signals are used in two ways:</p><ul><li>A trigger to start new workflow instances</li><li>A gating function to conditionally start a step (e.g., data partition readiness)</li></ul><p>Signal service goals are to</p><ul><li>Collect and index signals</li><li>Register and handle workflow trigger subscriptions</li><li>Register and handle the step gating functions</li><li>Captures the lineage of workflows triggers and steps unblocked by a signal</li></ul><figure><img alt="Figure 2. Signal service high level architecture" src="https://cdn-images-1.medium.com/max/764/0*St52rlh8ERrI9aEm"><figcaption>Figure 2. Signal service high level architecture</figcaption></figure><p>The maestro signal service consumes all the signals from different sources, e.g. all the warehouse table updates, S3 events, a workflow releasing a signal, and then generates the corresponding triggers by correlating a signal with its subscribed workflows. In addition to the transformation between external signals and workflow triggers, this service is also responsible for step dependencies by looking up the received signals in the history. Like the scheduling service, the signal service together with Maestro engine achieves exactly-once triggering guarantees.</p><p>Signal service also provides the signal lineage, which is useful in many cases. For example, a table updated by a workflow could lead to a chain of downstream workflow executions. Most of the time the workflows are owned by different teams, the signal lineage helps the upstream and downstream workflow owners to see who depends on whom.</p><h3>Orchestration at Scale</h3><p>All services in the Maestro system are stateless and can be horizontally scaled out. All the requests are processed via distributed queues for message passing. By having a shared nothing architecture, Maestro can horizontally scale to manage the states of millions of workflow and step instances at the same time.</p><p><a href="https://github.com/cockroachdb/cockroach">CockroachDB</a> is used for persisting workflow definitions and instance state. We chose CockroachDB as it is an open-source distributed SQL database that provides strong consistency guarantees that can be scaled horizontally without much operational overhead.</p><p>It is hard to support super large workflows in general. For example, a workflow definition can explicitly define a DAG consisting of millions of nodes. With that number of nodes in a DAG, UI cannot render it well. We have to enforce some constraints and support valid use cases consisting of hundreds of thousands (or even millions) of step instances in a workflow instance.</p><p>Based on our findings and user feedback, we found that in practice</p><ul><li>Users don’t want to manually write the definitions for thousands of steps in a single workflow definition, which is hard to manage and navigate over UI. When such a use case exists, it is always feasible to decompose the workflow into smaller sub workflows.</li><li>Users expect to repeatedly run a certain part of DAG hundreds of thousands (or even millions) times with different parameter settings in a given workflow instance. So at runtime, a workflow instance might include millions of step instances.</li></ul><p>Therefore, we enforce a workflow DAG size limit (e.g. 1K) and we provide a foreach pattern that allows users to define a sub DAG within a foreach block and iterate the sub DAG with a larger limit (e.g. 100K). Note that foreach can be nested by another foreach. So users can run millions or billions of steps in a single workflow instance.</p><p>In Maestro, foreach itself is a step in the original workflow definition. Foreach is internally treated as another workflow which scales similarly as any other Maestro workflow based on the number of step executions in the foreach loop. The execution of sub DAG within foreach will be delegated to a separate workflow instance. Foreach step will then monitor and collect status of those foreach workflow instances, each of which manages the execution of one iteration.</p><figure><img alt="Figure 3. Maestro’s scalable foreach design to support super large iterations" src="https://cdn-images-1.medium.com/max/1024/0*siaMnSYtCPVLWjYm"><figcaption>Figure 3. Maestro’s scalable foreach design to support super large iterations</figcaption></figure><p>With this design, foreach pattern supports sequential loop and nested loop with high scalability. It is easy to manage and troubleshoot as users can see the overall loop status at the foreach step or view each iteration separately.</p><h3>Workflow Platform for Everyone</h3><p>We aim to make Maestro user friendly and easy to learn for users with different backgrounds. We made some assumptions about user proficiency in programming languages and they can bring their business logic in multiple ways, including but not limited to, a bash script, a <a href="https://jupyter.org/">Jupyter notebook</a>, a Java jar, a docker image, a SQL statement, or a few clicks in the UI using <a href="https://netflixtechblog.com/#360e">parameterized workflow templates</a>.</p><h4>User Interfaces</h4><p>Maestro provides multiple domain specific languages (DSLs) including YAML, Python, and Java, for end users to define their workflows, which are decoupled from their business logic. Users can also directly talk to Maestro API to create workflows using the JSON data model. We found that human readable DSL is popular and plays an important role to support different use cases. YAML DSL is the most popular one due to its simplicity and readability.</p><p>Here is an example workflow defined by different DSLs.</p><figure><img alt="Figure 4. An example workflow defined by YAML, Python, and Java DSLs" src="https://cdn-images-1.medium.com/max/896/1*EekMn84UsAehrMjg3JPAxA.png"><figcaption>Figure 4. An example workflow defined by YAML, Python, and Java DSLs</figcaption></figure><p>Additionally, users can also generate certain types of workflows on UI or use other libraries, e.g.</p><ul><li>In Notebook UI, users can directly schedule to run the chosen notebook periodically.</li><li>In Maestro UI, users can directly schedule to move data from one source (e.g. a data table or a spreadsheet) to another periodically.</li><li>Users can use <a href="https://github.com/Netflix/metaflow">Metaflow</a> library to create workflows in Maestro to execute DAGs consisting of arbitrary Python code.</li></ul><h4>Parameterized Workflows</h4><p>Lots of times, users want to define a dynamic workflow to adapt to different scenarios. Based on our experiences, a completely dynamic workflow is less favorable and hard to maintain and troubleshooting. Instead, Maestro provides three features to assist users to define a parameterized workflow</p><ul><li>Conditional branching</li><li>Sub-workflow</li><li>Output parameters</li></ul><p>Instead of dynamically changing the workflow DAG at runtime, users can define those changes as sub workflows and then invoke the appropriate sub workflow at runtime because the sub workflow id is a parameter, which is evaluated at runtime. Additionally, using the output parameter, users can produce different results from the upstream job step and then iterate through those within the foreach, pass it to the sub workflow, or use it in the downstream steps.</p><p>Here is an example (using YAML DSL) of backfill workflow with 2 steps. In step1, the step computes the backfill ranges and returns the dates back. Next, foreach step uses the dates from step1 to create foreach iterations. Finally, each of the backfill jobs gets the date from the foreach and backfills the data based on the date.</p><pre>Workflow:<br>  id: demo.pipeline<br>  jobs:<br>    - job:<br>        id: step1<br>        type: NoOp<br>        '!dates': return new int[]{20220101,20220102,20220103}; #<a href="https://netflixtechblog.com/#0518">SEL</a><br>    - foreach:<br>        id: step2<br>        params:<br>          date: ${dates@step1}  #reference a upstream step parameter<br>        jobs:<br>          - job: <br>              id: backfill<br>              type: Notebook<br>              notebook:<br>                input_path: s3://path/to/notebook.ipynb<br>              arg1: $date  #pass the foreach parameter into notebook</pre><figure><img alt="Figure 4. An example of using parameterized workflow for backfill data" src="https://cdn-images-1.medium.com/max/1024/0*Qa0WTl3s-POfEh8R"><figcaption>Figure 5. An example of using parameterized workflow for backfill data</figcaption></figure><p>The parameter system in Maestro is completely dynamic with code injection support. Users can write the code in Java syntax as the parameter definition. We developed our own secured expression language (SEL) to ensure security. It only exposes limited functionality and includes additional checks (e.g. the number of iteration in the loop statement, etc.) in the language parser.</p><h4>Execution Abstractions</h4><p>Maestro provides multiple levels of execution abstractions. Users can choose to use the provided step type and set its parameters. This helps to encapsulate the business logic of commonly used operations, making it very easy for users to create jobs. For example, for spark step type, all users have to do is just specify needed parameters like spark sql query, memory requirements, etc, and Maestro will do all behind-the-scenes to create the step. If we have to make a change in the business logic of a certain step, we can do so seamlessly for users of that step type.</p><p>If provided step types are not enough, users can also develop their own business logic in a Jupyter notebook and then pass it to Maestro. Advanced users can develop their own well-tuned docker image and let Maestro handle the scheduling and execution.</p><p>Additionally, we abstract the common functions or reusable patterns from various use cases and add them to the Maestro in a loosely coupled way by introducing job templates, which are parameterized notebooks. This is different from step types, as templates provide a combination of various steps. Advanced users also leverage this feature to ship common patterns for their own teams. While creating a new template, users can define the list of required/optional parameters with the types and register the template with Maestro. Maestro validates the parameters and types at the push and run time. In the future, we plan to extend this functionality to make it very easy for users to define templates for their teams and for all employees. In some cases, sub-workflows are also used to define common sub DAGs to achieve multi-step functions.</p><h3>Moving Forward</h3><p>We are taking Big Data Orchestration to the next level and constantly solving new problems and challenges, please stay tuned. If you are motivated to solve large scale orchestration problems, please <a href="https://jobs.netflix.com/search?team=Data%20Platform">join us</a> as we are hiring.</p><img src="https://medium.com/_/stat?event=post.clientViewed&#38;referrerSource=full_rss&#38;postId=aaa2b41b800c" width="1" height="1" alt=""><hr><p><a href="https://netflixtechblog.com/orchestrating-data-ml-workflows-at-scale-with-netflix-maestro-aaa2b41b800c">Orchestrating Data/ML Workflows at Scale With Netflix Maestro</a> was originally published in <a href="https://netflixtechblog.com/">Netflix TechBlog</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Data Movement in Netflix Studio via Data Mesh</title>
		<link>https://noise.getoto.net/2021/07/26/data-movement-in-netflix-studio-via-data-mesh/</link>
		
		<dc:creator><![CDATA[Netflix Technology Blog]]></dc:creator>
		<pubDate>Mon, 26 Jul 2021 18:00:56 +0000</pubDate>
				<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[data streaming]]></category>
		<category><![CDATA[data-mesh]]></category>
		<category><![CDATA[data-movement]]></category>
		<category><![CDATA[stream-processing]]></category>
		<guid isPermaLink="false">https://medium.com/p/3fddcceb1059</guid>

					<description><![CDATA[By Andrew Nguonly, Armando Magalhães, Obi-Ike Nwoke, Shervin Afshar, Sreyashi Das, Tongliang Liu, Wei Liu, Yucheng ZengBackgroundOver the next few years, most content on Netflix will come from Netflix’s own Studio. From the moment a Netflix film or ser...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Use Macie to discover sensitive data as part of automated data pipelines</title>
		<link>https://noise.getoto.net/2020/12/09/use-macie-to-discover-sensitive-data-as-part-of-automated-data-pipelines/</link>
		
		<dc:creator><![CDATA[Brandon Wu]]></dc:creator>
		<pubDate>Wed, 09 Dec 2020 21:26:31 +0000</pubDate>
				<category><![CDATA[Advanced (300)]]></category>
		<category><![CDATA[Amazon Macie]]></category>
		<category><![CDATA[Amazon S3]]></category>
		<category><![CDATA[Amazon SES]]></category>
		<category><![CDATA[api gateway]]></category>
		<category><![CDATA[AWS Lambda]]></category>
		<category><![CDATA[cloud security]]></category>
		<category><![CDATA[cybersecurity]]></category>
		<category><![CDATA[data discovery]]></category>
		<category><![CDATA[Data Lake]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[Data protection]]></category>
		<category><![CDATA[data security]]></category>
		<category><![CDATA[DevSecOps]]></category>
		<category><![CDATA[PII]]></category>
		<category><![CDATA[Security Blog]]></category>
		<category><![CDATA[Security, Identity & Compliance]]></category>
		<category><![CDATA[serverless]]></category>
		<category><![CDATA[Step Functions]]></category>
		<guid isPermaLink="false">http://noise.getoto.net/?guid=e270a2b4fc0eba8dc45cf2753674c009</guid>

					<description><![CDATA[Data is a crucial part of every business and is used for strategic decision making at all levels of an organization. To extract value from their data more quickly, Amazon Web Services (AWS) customers are building automated data pipelines&#8212;from data ingestion to transformation and analytics. As part of this process, my customers often ask how [&#8230;]]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
		<item>
		<title>Securing and managing multi-cloud Presto Clusters with Grab’s DataGateway</title>
		<link>https://noise.getoto.net/2020/08/24/securing-and-managing-multi-cloud-presto-clusters-with-grabs-datagateway/</link>
		
		<dc:creator><![CDATA[Grab Tech]]></dc:creator>
		<pubDate>Mon, 24 Aug 2020 08:12:56 +0000</pubDate>
				<category><![CDATA[Access Control]]></category>
		<category><![CDATA[cluster]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Data Pipeline]]></category>
		<category><![CDATA[Data Science]]></category>
		<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Presto]]></category>
		<category><![CDATA[Workload Distribution]]></category>
		<guid isPermaLink="false">https://engineering.grab.com/data-gateway</guid>

					<description><![CDATA[Introduction

Data is the lifeblood of Grab and the insights we gain from it drive all the most critical business decisions made by Grabbers and our leaders every day.

Grab’s Data Engineering (DE) team is responsible for maintaining the data platform,...]]></description>
		
		
		<enclosure url="" length="0" type="" />

			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/

Object Caching 46/242 objects using Memcached
Page Caching using Disk: Enhanced 
Lazy Loading (feed)
Database Caching using Memcached

Served from: noise.getoto.net @ 2025-12-11 09:14:11 by W3 Total Cache
-->