<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Maximilian Michels</title>
    <description>Insights into software engineering, open-source software, and data-intensive applications.</description>
    <link>https://maximilianmichels.com/</link>
    <atom:link href="https://maximilianmichels.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 12 Feb 2023 19:13:08 +0100</pubDate>
    <lastBuildDate>Sun, 12 Feb 2023 19:13:08 +0100</lastBuildDate>
    <generator>Jekyll v3.9.0</generator>
    
    
      <item>
        <title>Why Stream Processing?</title>
        <description>&lt;p&gt;Over the last decades we have seen an explosion in the data volume generated at companies, governments, and even private households. Data is so readily available that analyzing it becomes a real challenge. The data volume is often too large for ordinary machines to process it in a timely fashion, and although supercomputers could do it, it is simply too costly to use them. To address this, new methods have emerged for cost-effectively processing large amounts of data using arrays of interconnected, commodity hardware machines. This idea was first demonstrated by the &lt;a href=&quot;https://research.google/pubs/pub62/&quot;&gt;MapReduce model&lt;/a&gt; developed by Google in the early 2000s. Only a couple year later (2006), Yahoo replicated the MapReduce paradigm and released it to the open-source world as Apache Hadoop. In the 2010s, next generation systems like Apache Spark and Apache Flink evolved the programming model and the capabilities of the execution engines.&lt;/p&gt;

&lt;h2 id=&quot;the-path-from-batch-processing-to-stream-processing&quot;&gt;The Path from Batch Processing to Stream Processing&lt;/h2&gt;

&lt;p&gt;The first step in the evolution of processing large amounts of data using commodity hardware was found in batch processing which is considered to be the starting point of the “big data” trend.&lt;/p&gt;

&lt;h3 id=&quot;batch-processing&quot;&gt;Batch processing&lt;/h3&gt;

&lt;p&gt;Batch processing originates from the early computer age when a terminal could only be used by one person at a time. In order to allow multiple users to share the underlying computing resources, users could submit &lt;em&gt;jobs&lt;/em&gt;. Jobs would be stored in a &lt;em&gt;job queue&lt;/em&gt;. The batch processing occurs by running multiple of these jobs in a batch, typically sequential but later systems could also run multiple jobs at once. A large part of this process was later done by operating systems which allowed multiple programs to share the overall computing resources.&lt;/p&gt;

&lt;p&gt;Despite the evolution towards large-scale data processing, some of the most basic assumptions remained the same. The input to a processing job is finite (bounded) data, e.g. we use a file or a database query as the input. Due to the bounded input, the processing eventually finishes (if, for once, we disregard Alan Turing’s halting problem). Conceptually, this is still similar to the early batch processing systems because we run a set of pre-programmed code (jobs) and then return the output to the user.&lt;/p&gt;

&lt;h4 id=&quot;distributed-batch-processing&quot;&gt;Distributed Batch Processing&lt;/h4&gt;

&lt;p&gt;The distributed batch processing evolution is largely in the execution layer. Instead of running the processing on a single machine, we partition the input such that in can be processed in parallel by multiple machines. This approach to speeding up the processing is also referred to as horizontal scaling, as opposed to vertical scaling where one would increase the processing power of the individual machines. Horizontal scaling can be an effective, fault-tolerant, and cost-efficient way to process data.&lt;/p&gt;

&lt;h3 id=&quot;the-case-for-stream-processing&quot;&gt;The Case for Stream Processing&lt;/h3&gt;

&lt;p&gt;While distributed batch processing is a leap forward, it is still a static one-off process. Data needs to be already produced for the processing to start. If new data arrives during processing, it can’t be considered because a fundamental assumption is that all the input is available when the processing starts. This is due to parts of the processing like sorting which only work correctly when the entire input is available.&lt;/p&gt;

&lt;p&gt;You might say, why not run this process more frequently? Of course, there is still the option to schedule the processing more often, e.g. every day, every hour, every 30 minutes. But what if the processing itself is so involved that it takes several hours? Is it worth recomputing the entire result every time?&lt;/p&gt;

&lt;p&gt;Imagine you wanted to maintain a live counter of the number of people who visited particular pages on your website. We could process the web server logs to compute these counters. To calculate an up-to-date hourly counter for the day, a batch processing job would need to read through all the logs of the current day. That process would be repeated as often as you wanted to get an up-to-date counter on a given day. One way to solve this problem would be to cache the already computed results for that day, even if that slightly complicates the process. But there might be an even better solution.&lt;/p&gt;

&lt;p&gt;Stream processing lends itself naturally to this problem because we could store the counters for each page in memory and update them as new visitors arrive. As we update the live counter, we don’t need to reprocess any prior events from the past as we have to do with batch processing. It is important to note that other issues can arise with stream processing, in particular how to handle late or out of order events. We will cover these issues later. For now let’s figure out when stream processing would be a good fit.&lt;/p&gt;

&lt;p&gt;Here are some general criteria when evaluating whether to use stream processing:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The application needs to provide real-time results or decision making.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The application logic requires fresh data and long-lived state.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Incoming data needs to be pre-aggregated or reduced before it is stored.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The data consists of events which may arrive out of order.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;enter-stream-processing&quot;&gt;Enter Stream Processing&lt;/h2&gt;

&lt;p&gt;Stream processing is designed to continuously process data and provide low-latency results. Unlike batch processing, it is always-on, allowing new results to be emitted at any desired time or in predefined intervals.&lt;/p&gt;

&lt;h3 id=&quot;stateful-stream-processing&quot;&gt;Stateful Stream Processing&lt;/h3&gt;

&lt;p&gt;The most challenging aspect of stream processing is its state which needs to be persisted across failures or application updates. If we don’t persist the state, we would need to re-process all data up until the point of failure. To prevent this, stateful streaming applications hold and persist state, similarly to a database. But conversely to a database, read and write operations are fast because the state resides in the process memory (with the option to offload to disk to prevent running out of memory).&lt;/p&gt;

&lt;p&gt;State is checkpointed at regular intervals which means we won’t have to re-process any data up until the checkpoint is complete. Checkpointing involves writing the application state to an external storage. In the event of a failure, the state will be recovered from this storage and the processing can resume from when the last checkpoint was made.&lt;/p&gt;

&lt;!-- What about exactly once? --&gt;

&lt;h2 id=&quot;is-batch-processing-a-subset-of-stream-processing&quot;&gt;Is Batch Processing a subset of Stream Processing?&lt;/h2&gt;

&lt;p&gt;Some argue that batch processing is just a special case of stream processing, but in practice, batch processing implemented in terms of the more broad stream processing paradigm usually lacks the batch-specific optimizations, such as operating in larger batches for more throughput, efficient sorting algorithms which can spill to disk, or intelligent recovery using intermediate results. Further, the application logic tends to be different because streaming use cases are defined in terms of groups of events in time and can’t do certain batch processing operations like scanning through the entire data. Streams are by nature unbounded and continous which enforces a different programming model.&lt;/p&gt;

&lt;p&gt;Batch and stream processing are two different approaches to data processing. Neither one is better or superior in terms of processing semantics, it merely depends on how time-critical your data processing needs are.&lt;/p&gt;

&lt;h2 id=&quot;use-cases&quot;&gt;Use cases&lt;/h2&gt;

&lt;p&gt;Many services are based on historic data and do not factor in recent data. With stream processing, we can provide real-time insights based on recent events generated by the user or the environment. The following examples illustrate that:&lt;/p&gt;

&lt;h3 id=&quot;monitoring--observability&quot;&gt;Monitoring &amp;amp; Observability&lt;/h3&gt;

&lt;p&gt;Nowadays almost every machine generates data about its condition, e.g. maintenance cycles, production speed, temperature, etc. If such data can be aggregated in real time, a broken or malfunctioning machine can be shut off or replaced before any damage occurs.&lt;/p&gt;

&lt;p&gt;The same applies to any kind of (software) deployments. Stream processing can generate real-time alerts in case the application metrics are not within their desired bounds.&lt;/p&gt;

&lt;h3 id=&quot;fraud-detection&quot;&gt;Fraud detection&lt;/h3&gt;

&lt;p&gt;For every bank user, we want to instantly decide whether a login attempt, credit card use, or a wire transfer is legitimate or not. This can be done by analyzing the stream of events for a particular user. By looking at recent events and summarized past events, we can decide whether a login attempt is legitimate or not.&lt;/p&gt;

&lt;h3 id=&quot;taxi-ride-pricing&quot;&gt;Taxi ride pricing&lt;/h3&gt;

&lt;p&gt;Taxi rides for ride services like Lyft or Uber are often calculated dynamically. We can more accurately predict the price of taxi rides using traffic information, available drivers, and how many users request the service. Ideally, we want to do this as close to real time as possible.&lt;/p&gt;

&lt;h3 id=&quot;recommendation-systems&quot;&gt;Recommendation systems&lt;/h3&gt;

&lt;p&gt;We can provide better recommendation based one real-time data. For example, recommending new songs based on the last played songs. Users would like their recommendations to change based on the recently played or liked songs.&lt;/p&gt;

&lt;h2 id=&quot;stream-processing-programming-model&quot;&gt;Stream processing programming model&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://research.google/pubs/pub43864/&quot;&gt;Dataflow paper&lt;/a&gt; pointed out that stream processing can be viewed as merely a concern of the execution engine. The programming model for the user can be designed independently of its execution. However, that is somewhat of a simplification. Many stream processors like Apache Spark or Apache Flink have different programming interfaces for batch and streaming. While it is possible to have a unified API like Dataflow’s, there are going to be streaming concepts in batch execution mode that aren’t going to be useful, even if they do not break the batch processing semantics. It is worth listing some of the streaming-specific concepts below.&lt;/p&gt;

&lt;h3 id=&quot;windows&quot;&gt;Windows&lt;/h3&gt;

&lt;p&gt;In batch, we can scan and crunch through all available data. This allows us to be very flexible with respect to the type aggregation of the data. In streaming, this is different because we are never guaranteed to see all available data. This is where windows come into play.&lt;/p&gt;

&lt;p&gt;A window has a start and an end timestamp and marks a time span. In streaming, data elements (events) have a timestamp associated and can be associated with a window based on the timestamp. For example, a 5 minute window could be [2:00pm, 2:05pm). Note that the square bracket means inclusive while the rounded parenthesis means not inclusive.&lt;/p&gt;

&lt;p&gt;Windows can be tumbling or sliding&lt;/p&gt;

&lt;h4 id=&quot;tumbling-window&quot;&gt;Tumbling window&lt;/h4&gt;

&lt;p&gt;Tumbling means that the next windows begins directly after the end of the old one. For example, 5 minute tumbling windows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;... [2:00pm, 2:05pm) [2:05pm, 2:10pm) [2:10pm, 2:15pm) ...
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&quot;sliding-window&quot;&gt;Sliding window&lt;/h4&gt;

&lt;p&gt;Sliding means that in addition to beginning every X interval, it also slides every Y interval. For example, 5 minutes windows sliding every 1 minute:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;... [2:00pm, 2:05pm) [2:01pm, 2:06pm) [2:02, 2:07pm) ...
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;time&quot;&gt;Time&lt;/h3&gt;

&lt;p&gt;In stream processing, time does not strictly advance linearly like we would assume from a regular clock. There are two fundamentally different time schemes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Processing time&lt;/strong&gt;: The regular time we would use on a computer or a regular clock.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Event time&lt;/strong&gt;: A time associated with and derived from the processed events.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;watermarks&quot;&gt;Watermarks&lt;/h3&gt;

&lt;p&gt;Watermarks are used in conjunction with event time. Low watermarks are special time stamps which indicate the current &lt;em&gt;minimum&lt;/em&gt; event time. Similarly, high watermark indicate the maximum event time seen. Watermarks are generated by a function which receives the event timestamps of the inflowing events as input. Watermarks functions can be as simple as taking the latest observed timestamp. However, time must advance monotonously, i.e. we must not go back in time. Watermark functions may use custom logic to decide when it is safe to observe time. For example, it could use a fixed offset from the high watermark as the low watermark. This tolerates some out of orderness of the arriving event timestamps. Let’s see why this is important below.&lt;/p&gt;

&lt;h3 id=&quot;late-or-out-of-order-events&quot;&gt;Late or out of order events&lt;/h3&gt;

&lt;p&gt;Events are considered “late” when their timestamp is before the current event time as determined by the latest emitted low watermark. Out of orderness is often a reason for late data because events do not arrive in their expected order which leads to prematurely advancing the event time via emitting a watermark which is past the event time of the incoming data.&lt;/p&gt;

&lt;h3 id=&quot;fault-tolerance--state&quot;&gt;Fault-tolerance &amp;amp; State&lt;/h3&gt;

&lt;p&gt;State is one of the most interesting and hard parts about stream processing. Most applications have state of some sort, e.g. remembering when a user last logged on requires state, storing any pending records within a system requires state, storing a position in a file or log which we are reading from. Whenever state is present, this has implications on the fault-tolerance of the system. In case of stateless applications, we can simply restart the job. However, if we do have state, we need to take care to re-initialize the state after a failure in a way that the process semantics stay the same.&lt;/p&gt;

&lt;p&gt;When do failures occur? Failures can happen due to hardware failures, network failures, external systems failing, applications errors, malformed data, etc.&lt;/p&gt;

&lt;p&gt;Stream processors must periodically externalize their state to be able to recover it in case of failures. This is done by writing their state to an external data store. It is not a trivial problem to do this in a way that the processing semantics remain unchanged when restoring the persisted state. Typically there are three semantics we distinguish between (from least to most strict):&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;at most once&lt;/p&gt;

    &lt;p&gt;If systems can guarantee at most once, they essentially guarantee that all events are processed once or not at all. This is the weakest guarantee because there can be data loss in the case when an event is not processed.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;at least once&lt;/p&gt;

    &lt;p&gt;If systems guarantee at least once, they guarantee that a record is processed one or more times. This requires some form of acking or checkpointing to persist the stream state. There may be duplicate processing of data after restoring from a checkpoint because the same data will be read that was already processed before the failure which led to restoring the state from the checkpoint.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;exactly once&lt;/p&gt;

    &lt;p&gt;Exactly once is the strongest but also most difficult semantic to guarantee. This is especially difficult when writing to external systems which might not support exactly once semantics. We need some form of support for transactional processing for external systems to ensure that we only yield a result once.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;stream-processors&quot;&gt;Stream processors&lt;/h3&gt;

&lt;p&gt;After describing the most important concepts in stream processing, it may be worth introducing some of the common stream processing engines. Here is a selection of open-source stream processing engines:&lt;/p&gt;

&lt;h4 id=&quot;apache-flink&quot;&gt;Apache Flink&lt;/h4&gt;

&lt;p&gt;Apache Flink is the de facto standard when it comes to stream processing in the open source world. It fully supports stream processing as described in this article. It is suitable for large-scale stream processing with hundreds of processing nodes. Flink can be described as the Swiss army knife or stream processors. It comes with a wide range of connectors. It bundles memory backends for storing stateful stream processing applications with memory demands exceeding main memory which requires spilling to disc. It also has its own scheduler which integrates with Kubernetes and a number of other cluster management solutions.&lt;/p&gt;

&lt;h4 id=&quot;kafka-streams&quot;&gt;Kafka Streams&lt;/h4&gt;

&lt;p&gt;Apache Kafka is often used together with Flink as a message queue and storage layer for events. Kafka also comes with a stream processing library called Kafka Streams. Kafka Streams allows to write stream processing applications which do not require a dedicated runtime like Flink. Kafka Streams leverages the Kafka storage layer to shuffle and persist data. This doesn’t always make it the most performent solution to run stream processing pipelines. However, this operational simplicity is also a huge advantage if the user already has a Kafka cluster. It is to note that the Kafka cluster might become a bottleneck which might also be operationally challenging.&lt;/p&gt;

&lt;h4 id=&quot;apache-spark&quot;&gt;Apache Spark&lt;/h4&gt;

&lt;p&gt;Apache Spark builds its stream processing around their core abstraction: RDDs (Resilient Distributed Datasets). RDD are sets of data which can be processed in a fault-tolerant way. There is some overhead which occurs with this process which is why the data is split into large enough chunks. For stream processing the amount of data is further reduced to achieve lower latencies (micro batching). However, this means throughput is not as good as in systems like Flink which stream data and use a less granular method to ensure fault tolerance (checkpointing).&lt;/p&gt;

&lt;h4 id=&quot;apache-storm&quot;&gt;Apache Storm&lt;/h4&gt;

&lt;p&gt;Apache Storm is a legacy engine originally developed by Nathan Marz. It was one of the first open source stream processing solutions. It does per event acknowledgments for fault-tolerance which comes with a big performance-penalty. Due to its clunky API and slow execution engine, it’s not typically used anymore today.&lt;/p&gt;

&lt;h4 id=&quot;apache-beam--google-cloud-dataflow&quot;&gt;Apache Beam / Google Cloud Dataflow&lt;/h4&gt;

&lt;p&gt;Google has its own stream processing product called Google Cloud Dataflow. Apache Beam is the programming library for Dataflow. The programming model is very similar to Flink’s. However, its underlying execution engine is quite different from Flink’s. The most important differences are its externally persisted state which makes it much more elastic than Flink. For example, in Dataflow it is possible to add or remove workers during runtime which would require an application restart in Flink.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;We have outlined why stream processing is important and when stream processing is a good fit. We have learned about the core concepts and problems in stream processing. Finally, we have introduced some of the stream processing engines available.&lt;/p&gt;

&lt;p&gt;There are many more things to learn about stream processing. I would encourage you to read more about stream processing in one of the following books:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;Stream Processing with Apache Flink&lt;/em&gt; by Fabian Hueske and Vasiliki Kalavri&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Streaming Systems&lt;/em&gt; by Tyler Akidau,  Slava Chernyak, and Reuven Lax&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Designing Data-Intensive Applications&lt;/em&gt; by Martin Kleppmann&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This might only be the beginning of your stream processing journey.&lt;/p&gt;

&lt;!---
### Batch processing

#### History

Historically speaking, batch processing originates from the time where a terminal could only be used by one person at a time. In order to allow multiple users to share the underlying computing resources, users could submit *jobs*. Jobs would be stored in a *job queue*. The batch processing occurs by running multiple of these jobs in a batch, typically sequential but later systems could also run multiple jobs at once. A large part of this process was later done by operating systems which allowed multiple programs to share the overall computing resources.

#### Distributed Batch Processing

A generalization of this paradigm is distributed batch processing where multiple machines provide computing resources which are usually centrally managed by a scheduler.

Batch processing is still a one-off process which assumes finite input. At any time, any part of the complete input can be read, sorted, and processed. These parts are also referred to as batches, hence the name of the paradigm. If the input is not sorted, usually the entire input is read. If the input is pre-sorted, only a fraction of the input may be read, e.g. if the input is grouped by hours and we are only interested in a particular hour's input. A batch program terminates once all input has been read and processed.


### Stream processing

Stream processing is a concept that lives on multiple layers but its principle stays the same.

#### Hardware stream processing

Early processors followed the *Single Instruction Single Data* (SISD) paradigm. A single operation would be performed on data at a time. For example, summing two vectors would take two arrays which hold the vector and sum each component individually.

Later processors would allow *Single Instruction Multiple Data* (SIMD). This allowed for a range of data to be processed with a single instruction. For example, summing two vectors can be done with a single instruction where the input are two vector arrays.

A further generalization of this paradigm is *Multiple Instruction Multiple Data* (MIMD). Here, we can perform arbitrary instructions on arbitrary data. For example, a series of operations on vectors could be performed at a time. The parallelism is limited by the number of processing units.

Stream processing goes one step further. Here the processing treats the input as a continuous stream which is processed by a kernel function. There is no upper bound parallelism here because the input can be partitioned that arbitrary number of parallel instances can run on the data. Of course, this requires data to be partionable such that it can be processed in parallel. This is why this paradigm does not work well with interconnected data items which do not allow for splitting.

#### Distributed Stream Processing

Hardware stream processing is often too complicated to do efficiently because the hardware needs to be highly specialized or programmable (FPGA) to run efficient stream processing. Distributed processing acknowledges these limitations at the individual machine level and tries to leverage multiple machines for computing. Stream processing is done at higher software layers.

### Event Processing

Event processing is stream processing where the each processed record represents an event. An action can be performed on every event, e.g. send the event downstream, reduce the event size, buffer the event, aggregate multiple events.
--&gt;
</description>
        <pubDate>Sat, 26 Nov 2022 12:40:05 +0100</pubDate>
        <link>https://maximilianmichels.com/2022/stream-processing/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2022/stream-processing/</guid>
        
        
      </item>
    
    
    
      <item>
        <title>A Brief History of Open Source</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;Open-source software (OSS) rules the world. Virtually any product, service, or platform is powered by or built with OSS. We carry OSS around in our pockets as Android or iPhones devices. Whenever we feel like it, we download OSS off the Internet to solve our every day tasks like writing documents, listening to music, or accessing our email. It is fair to say that OSS conquered the world, but does that mean it always has?
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;h3 id=&quot;source-vs-binary&quot;&gt;Source vs binary&lt;/h3&gt;

&lt;p&gt;The term “open-source” refers to code for software being
published in the open, as opposed to only having a “binary” which contains the compiled source code and may have an explicit owner (“proprietary”). Binaries contain opaque information which only computers understand. Source code, on the other hand, is the human-understandable format of the logic contained in computer programs. Computers run binaries, humans can only really reason about binaries by reading their source code.&lt;/p&gt;

&lt;p&gt;Clearly, there is more to open-source than just the code being open. It is a mindset and a way to collaborate in the open. But where does the term open-source come from? Surprisingly, “open-source” was and to some degree still is a controversial term.&lt;/p&gt;

&lt;h2 id=&quot;open-source-history&quot;&gt;Open-Source History&lt;/h2&gt;

&lt;h3 id=&quot;50s&quot;&gt;50s&lt;/h3&gt;

&lt;p&gt;Starting out in the 50s, software was only developed at universities and corporate research centers. Software was not ubiquitous like in today’s world. Only top-notch experts knew how to develop and use software.&lt;/p&gt;

&lt;p&gt;It may come as a surprise that in those days the source code was often the only artifact distributed. Nowadays software comes pre-compiled for the most popular computer architectures, but back then there was no standard computer architecture. If you wanted to use a program, you had to compile it first (i.e. build the source code), or even adjust the source code to be able to run it on your computer or mainframe.&lt;/p&gt;

&lt;p&gt;During those times, companies like IBM even asked their users to send in source code suggestions.&lt;/p&gt;

&lt;h3 id=&quot;60s&quot;&gt;60s&lt;/h3&gt;

&lt;p&gt;In the 60s, most software came bundled together with hardware - a trend that we are seeing again today (hello Apple), though for different reasons.&lt;/p&gt;

&lt;p&gt;Software was entirely supported through a one-time payment for the hardware. There was also no Internet, so any updates (“patches”) had to be distributed via hole punch cards early on, later via floppy discs.&lt;/p&gt;

&lt;p&gt;At the end of the 60s, with the invention of operating systems, databases, and high-level programming languages, software became increasingly more complex. The development costs for software increased so much, it became hard to justify giving software away for free with the hardware. Eventually, companies started charging money for their software.&lt;/p&gt;

&lt;h3 id=&quot;70s&quot;&gt;70s&lt;/h3&gt;

&lt;p&gt;In 1974, software became copyrightable (&lt;a href=&quot;https://digitalcommons.law.ggu.edu/cgi/viewcontent.cgi?article=1344&amp;amp;context=ggulrev&quot;&gt;source&lt;/a&gt;), but that didn’t have a big impact because many companies had already stopped to distribute source code to prevent copying their software.&lt;/p&gt;

&lt;p&gt;Companies like Microsoft and Apple were founded in the 70s. Clearly, those were for-profit companies which saw open or free software as a threat. Bill Gates famously wrote an &lt;a href=&quot;https://en.wikipedia.org/wiki/Open_Letter_to_Hobbyists&quot;&gt;“Open Letter to Hobbyists”&lt;/a&gt;, asking them to stop copying his company’s software.&lt;/p&gt;

&lt;p&gt;It was only much later companies would realize the potential of OSS.&lt;/p&gt;

&lt;h3 id=&quot;80s&quot;&gt;80s&lt;/h3&gt;

&lt;p&gt;The 80s saw OSS on the rise.&lt;/p&gt;

&lt;p&gt;In 1983, Richard Stallman created the GNU project, because he was frustrated with the proprietary nature of computer systems he worked on (particularly Unix). The GNU project contained open-source rewrites of closed-source software Stallman used.&lt;/p&gt;

&lt;p&gt;In 1985 Stallman founded the Free Software Foundation (FSF), a foundation to support the free software movement. Despite the problematic statements Stallman has made from time to time, he is a true visionary and pioneer of open-source software. The FSF takes a radical stance as it demands total control over software and its code.&lt;/p&gt;

&lt;h3 id=&quot;90s&quot;&gt;90s&lt;/h3&gt;

&lt;p&gt;The term “open source” was first coined at the Foresight Institute (&lt;a href=&quot;https://opensource.com/article/18/2/coining-term-open-source-software&quot;&gt;source&lt;/a&gt;). Computer security researchers wanted to promote the idea of “free software” but they were worried about people thinking it was merely software for free. In an act to promote free software to improve security they looked for term that would reflect the collaborative nature of OSS.&lt;/p&gt;

&lt;p&gt;The term open-source was readily adopted at the end of the 90s by the Linux, Perl, and Python community, but also by companies like, Netscape and Red Hat.&lt;/p&gt;

&lt;p&gt;The FSF does not like the term open-source because they think it undermines the freedom associated with open software: “Open source is a development methodology; free software is a social movement.” (&lt;a href=&quot;https://www.gnu.org/philosophy/free-software-for-freedom.en.html&quot;&gt;source&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;The Internet and the increasing presence of software in the world led to more developers sharing their code openly. Although the movement started from a non-commercial, idealistic movement, very soon companies adopted open source as a new way to promote their products or subscriptions, and to cut development costs by using existing open-source software.&lt;/p&gt;

&lt;p&gt;In 1998, the non-profit Open Source Initiative was founded, inspired by Netscape which had just open-sourced their web browser Netscape Communicator (which later became Firefox).&lt;/p&gt;

&lt;p&gt;In 1999, a group of developers of the Apache web server realized their methodology could be applied to other open-source projects as well. They proceeded to found the non-profit Apache Software Foundation.&lt;/p&gt;

&lt;p&gt;In 1999, Sourceforge.com was launched which allowed developers to easily share and develop source code.&lt;/p&gt;

&lt;h3 id=&quot;2000s&quot;&gt;2000s&lt;/h3&gt;

&lt;p&gt;In 2000, the Linux Foundation was founded. It became on of the biggest and most influential open-source software foundations with a $100 million in revenue (2018, &lt;a href=&quot;https://projects.propublica.org/nonprofits/organizations/460503801&quot;&gt;source&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In 2001, the Python Software Foundation was founded. To this date, the foundation remains committed to developing Python in the open.&lt;/p&gt;

&lt;p&gt;In 2005, Linus Torvalds created the initial version of Git, an open-source version control system to speed up the distributed development of the Linux kernel.&lt;/p&gt;

&lt;p&gt;In 2008, GitHub.com was launched - a central platform for source code development based on Git.&lt;/p&gt;

&lt;p&gt;Also in 2008, Google released the first version of Android, today’s most used mobile operating system.&lt;/p&gt;

&lt;h3 id=&quot;2010s&quot;&gt;2010s&lt;/h3&gt;

&lt;p&gt;Over the years, more and more companies started to embrace open-source development as they realized the benefits of developing in the open. Expertise in open-source has become a competitive advantage.&lt;/p&gt;

&lt;p&gt;Since 2017, Microsoft is one of the biggest open-source contributors in the world (&lt;a href=&quot;https://en.wikipedia.org/wiki/Microsoft_and_open_source&quot;&gt;source&lt;/a&gt;). In 2018, Microsoft acquired GitHub, the largest open-source development platform to this date.&lt;/p&gt;

&lt;p&gt;We’ve really come a long way.&lt;/p&gt;

&lt;h2 id=&quot;the-future-of-open-source&quot;&gt;The Future of Open-Source&lt;/h2&gt;

&lt;p&gt;Open-source software has seen tremendous change:&lt;/p&gt;

&lt;p&gt;In its early days it was a scientific practice to share code among other researchers. Source code used to be given away for free with computer hardware, but when companies realized they could make more money with software than hardware, they began to license their source code. The Free Software Foundation (FSF), the Apache Software Foundation (ASF), and the Linux Foundation became the largest foundations for open-source software. Even companies which fought open-source for decades started embracing open-source.&lt;/p&gt;

&lt;p&gt;Open-Source Software clearly has conquered the world. Yet, there remain challenges around creating and maintaining open-source software, for example:&lt;/p&gt;

&lt;h4 id=&quot;legal-issues&quot;&gt;Legal issues&lt;/h4&gt;

&lt;p&gt;Open-source projects continue to see legal threats from companies who claim their intellectual property violated. Without strong legal support, open-source can be a costly endeavour. Fortunately, open-source foundations can provide a legal umbrella against these threats.&lt;/p&gt;

&lt;h4 id=&quot;licensing&quot;&gt;Licensing&lt;/h4&gt;

&lt;p&gt;Licenses for OSS are fragmented.&lt;/p&gt;

&lt;p&gt;On the one hand, there are
Copyleft licenses which are more restrictive when it comes to using OSS commercially. For example, by requiring to contribute back changes which are distributed elsewhere. Yet, in the age of Software as a Service (SaaS) this can often be circumvented.&lt;/p&gt;

&lt;p&gt;On the other hand, Liberal licenses (e.g. Apache license) which do not have aforementioned restrictions, do not always promote the best behavior when it comes to contributing back to OSS.&lt;/p&gt;

&lt;h4 id=&quot;trademarks-branding&quot;&gt;Trademarks (branding)&lt;/h4&gt;

&lt;p&gt;Often open-source projects uses trademarked brands. This puts the project under the risk of losing their name if the company or person owning the trademark does not want the project to use their brand anymore.&lt;/p&gt;

&lt;h4 id=&quot;funding&quot;&gt;Funding&lt;/h4&gt;

&lt;p&gt;Writing good software takes time and money. Many open-source projects continue to be underfunded.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h4 id=&quot;additional-sources&quot;&gt;Additional sources&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Open-source_software#History&quot;&gt;https://en.wikipedia.org/wiki/Open-source_software#History&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/History_of_free_and_open-source_software&quot;&gt;https://en.wikipedia.org/wiki/History_of_free_and_open-source_software
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Timeline_of_free_and_open-source_software&quot;&gt;https://en.wikipedia.org/wiki/Timeline_of_free_and_open-source_software&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 31 May 2021 15:17:41 +0200</pubDate>
        <link>https://maximilianmichels.com/2021/history-of-open-source/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2021/history-of-open-source/</guid>
        
        
        <category>open</category>
        
        <category>source</category>
        
        <category>software</category>
        
        <category>history</category>
        
      </item>
    
    
    
      <item>
        <title>Kubernetes in a Nutshell: 10 Things You Need to Know</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;Kubernetes changed everything about how we deploy applications. Yet many people
struggle to understand the essence of Kubernetes. I’ve assembled the 10 most
important things I believe everyone should know about Kubernetes.
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;h2 id=&quot;1-kubernetes-vs-k8s&quot;&gt;1. Kubernetes vs. k8s&lt;/h2&gt;

&lt;p&gt;The cool kids abbreviate Kubernetes with “&lt;strong&gt;k8s&lt;/strong&gt;” which stands for, you might have
guessed it, Kubernetes. Simply drop the eight (8) letters between the first
letter “K” and the last letter “s”, et voila.&lt;/p&gt;

&lt;h2 id=&quot;2-google-kubernetes-and-the-cloud-native-foundation&quot;&gt;2. Google, Kubernetes, and the Cloud Native Foundation&lt;/h2&gt;

&lt;p&gt;Google open-sourced Kubernetes in 2015 and partnered with the Linux Foundation to
create the &lt;strong&gt;Cloud Native Computing Foundation&lt;/strong&gt;. Kubernetes
was the first project at the Cloud Native Foundation. Kubernetes is licensed
under the permissive Apache 2.0 license.&lt;/p&gt;

&lt;p&gt;Kubernetes was not made out of thin air. Its design is based on a container
orchestration technology called Borg, to this date being developed and used
internally at Google.&lt;/p&gt;

&lt;h2 id=&quot;3-kubernetes-killed-yarn-mesos-and-docker-swarm&quot;&gt;3. Kubernetes killed YARN, Mesos, and Docker Swarm&lt;/h2&gt;

&lt;p&gt;Kubernetes was not the first of its kind. Before Kubernetes came out, there were
other cluster management systems in the open-source:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Apache Hadoop YARN (Yet Another Resource Negotiator)&lt;/li&gt;
  &lt;li&gt;Apache Mesos (incl. Marathon)&lt;/li&gt;
  &lt;li&gt;Docker Swarm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is fair to say that Kubernetes superseded all of these systems. The reasons
are manifold but to summarize: Mesos tried to be platform for
solving all kinds of problems including fine-grained resource allocation and
non-containerized applications. YARN was too tightly integrated into the Hadoop
ecosystem. On other hand, Docker Swam was much like Kubernetes in the sense that
it focused on container deployments but it lacked too many features that Kubernetes
came with out-of-the-box.&lt;/p&gt;

&lt;h2 id=&quot;4-kubernetes-manages-containers&quot;&gt;4. Kubernetes manages containers&lt;/h2&gt;

&lt;p&gt;Kubernetes focuses on managing container deployments in a computer
cluster, including their communication with each other. Think of a container as
a portable and reproducible instance of a software environment including its
dependencies.&lt;/p&gt;

&lt;p&gt;Typically, the container format used is the &lt;strong&gt;Docker&lt;/strong&gt; container format. More
formats like &lt;strong&gt;containerd&lt;/strong&gt; are supported and new ones can be plugged in as
needed using Kubernetes’ Container Runtime Interface (CRI).&lt;/p&gt;

&lt;p&gt;Kubernetes smallest operational unit is a &lt;strong&gt;Pod&lt;/strong&gt;. Pods hold one or more
containers. Usually Pods are not created by hand but by so called &lt;strong&gt;Deployments&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;5-kubernetes-is-declarative&quot;&gt;5. Kubernetes is declarative&lt;/h2&gt;

&lt;p&gt;Kubernetes takes a different approach than many other systems when it comes to
creating the desired deployments.&lt;/p&gt;

&lt;p&gt;Instead of specifying &lt;strong&gt;how&lt;/strong&gt; the application should be deployed, users specify
&lt;strong&gt;what&lt;/strong&gt; should be deployed. Kubernetes then ensures that the declared requirements
are met. Some examples of what can be declared:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A container image and its startup arguments&lt;/li&gt;
  &lt;li&gt;Minimum / maximum resources such as CPU, memory&lt;/li&gt;
  &lt;li&gt;Number of instances to create&lt;/li&gt;
  &lt;li&gt;Volumes to be mounted&lt;/li&gt;
  &lt;li&gt;Environment variables or configuration&lt;/li&gt;
  &lt;li&gt;Ports to communicate with other services&lt;/li&gt;
  &lt;li&gt;Credentials or secrets to be loaded&lt;/li&gt;
  &lt;li&gt;etc.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All this is specified via YAML. There is no code involved. Previously, one had
to write code to achieve this (infrastructure as code), but with Kubernetes
infrastructure is data. We have shifted from “how” to “what” and leave the rest
to Kubernetes.&lt;/p&gt;

&lt;h2 id=&quot;6-kubernetes-is-fault-tolerant-and-self-healing&quot;&gt;6. Kubernetes is fault-tolerant and self-healing&lt;/h2&gt;

&lt;p&gt;Over time, failures are inevitably in computer clusters. Failures can occur due
to hardware issues but also due to software bugs or upgrades.&lt;/p&gt;

&lt;p&gt;Kubernetes is designed to continue to work in the presence of failures. From
Kubernetes’ point of view, a failure is just a deviation of the declared
specification. Kubernetes will simply strive to restore the desired state.&lt;/p&gt;

&lt;p&gt;To be able to do that, Kubernetes replicates its own state. By doing that, it
can tolerate failures of its own nodes. It implements &lt;strong&gt;health checks&lt;/strong&gt; on nodes and containers
to be able to tell apart a healthy from an unhealthy entity. If a
container is detected to be unhealthy, it will be removed and a new version of
the container will be started.&lt;/p&gt;

&lt;h2 id=&quot;7-kubernetes-is-ubiquitous&quot;&gt;7. Kubernetes is ubiquitous&lt;/h2&gt;

&lt;p&gt;A major reason for the success of Kubernetes is its availability in the modern cloud.
All the major cloud providers (Amazon AWS, Microsoft Azure, Google Cloud) have
managed Kubernetes offerings. Kubernetes can easily be integrated with the
storage and networking implementations of any cloud provider.&lt;/p&gt;

&lt;p&gt;Since Kubernetes is available in many cloud offerings, there is little to &lt;strong&gt;no vendor
lock-in&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;8-kubernetes-comes-with-batteries-included&quot;&gt;8. Kubernetes comes with batteries included&lt;/h2&gt;

&lt;p&gt;Kubernetes comes with powerful abstractions but it’s not only a tool for
experts. It has been built with decades of practical experience in
cluster deployments in mind. It includes proven, easy-to-use recipes for working
with containers, storage, configuration, secrets, service discovery, networking,
etc.&lt;/p&gt;

&lt;h2 id=&quot;9-kubernetes-is-extensible&quot;&gt;9. Kubernetes is extensible&lt;/h2&gt;

&lt;p&gt;Besides the included resource types, Kubernetes allows to create &lt;strong&gt;custom resource&lt;/strong&gt;
types and &lt;strong&gt;custom operators&lt;/strong&gt; which help to realize the resource specifications.&lt;/p&gt;

&lt;p&gt;For example, if you were to run an application on Kubernetes that required
custom state management which cannot be expressed by Kubernetes deployments,
you could define your own resource type alongside with an operator which creates
this custom resource. Oftentimes, the operator can compose this new
resource in terms of the included Kubernetes resource types, which allows to
write an operator with relatively little code.&lt;/p&gt;

&lt;h2 id=&quot;10-kubernetes-is-efficient&quot;&gt;10. Kubernetes is efficient&lt;/h2&gt;

&lt;p&gt;Kubernetes is great at ensuring efficient resource usage. It has built-in &lt;strong&gt;load
balancing&lt;/strong&gt; which is able to balance load across all containers associated with a
deployment.&lt;/p&gt;

&lt;p&gt;Kubernetes packs its computing nodes with containers such that the containers
and their computing needs &lt;strong&gt;maximize the utilization&lt;/strong&gt; of each node. It regularly
performs de-fragmentation by migrating containers to other nodes in order to
achieve maximum utilization.&lt;/p&gt;

&lt;p&gt;Kubernetes provides &lt;strong&gt;resource isolation&lt;/strong&gt; and &lt;strong&gt;resource usage limitation&lt;/strong&gt; by
leveraging the container options for resource limits for CPU or memory (via Linux’s cgroups).&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h1 id=&quot;final-thoughts&quot;&gt;Final Thoughts&lt;/h1&gt;

&lt;p&gt;Thank you for reading this post. I hope I could shed some light on Kubernetes.
If you found the article helpful, please send it to a friend or feel free to
share it on social media.&lt;/p&gt;

&lt;p&gt;If you want to learn more about Kubernetes, the official Kubernetes docs are a
great place to start: &lt;a href=&quot;https://kubernetes.io/docs/&quot;&gt;https://kubernetes.io/docs/&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 15 Mar 2021 14:26:44 +0100</pubDate>
        <link>https://maximilianmichels.com/2021/kubernetes-what-you-need-to-know/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2021/kubernetes-what-you-need-to-know/</guid>
        
        
        <category>kubernetes</category>
        
        <category>deployment</category>
        
        <category>introduction</category>
        
      </item>
    
    
    
      <item>
        <title>The Significance of &quot;Upstream First&quot;</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;In open-source software, the term “upstream” refers to the main place of
development. Many people talk about doing “upstream first” for open-source
contributions, but what does that really mean?
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;h2 id=&quot;upstream&quot;&gt;Upstream&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Upstream&lt;/em&gt; is the place where open-source software lives. It is where it is
continuously improved, it is where it is maintained, it is where people come to
ask questions or report bugs.&lt;/p&gt;

&lt;p&gt;If you download the source code of an open-source project, then you have a copy
of the upstream code, either a released version or a development (unreleased)
version.&lt;/p&gt;

&lt;h2 id=&quot;forks&quot;&gt;Forks&lt;/h2&gt;

&lt;p&gt;If you modify the source code, you have &lt;em&gt;diverged&lt;/em&gt; from upstream. Only when you
&lt;em&gt;contribute back&lt;/em&gt; to upstream, you have resolved that discrepancy.&lt;/p&gt;

&lt;p&gt;There are many reasons why you would modify the source code: adaptations for
your system, infrastructure, internal processes. A copy of upstream with
modifications is called a &lt;em&gt;fork&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Most forks &lt;em&gt;track&lt;/em&gt; upstream by regularly merging in the upstream
changes and applying their small adaptations on top of the upstream code.&lt;/p&gt;

&lt;p&gt;The more changes you make in your fork, the more expensive it can become to
maintain. You will find that the changes you are making are not exclusive to your
company or infrastructure because the problems you solve with your changes are
just as much of a problem to other people than they are to you.&lt;/p&gt;

&lt;h2 id=&quot;contributing-back&quot;&gt;Contributing Back&lt;/h2&gt;

&lt;p&gt;It can be frustrating that every time you merge in changes, it becomes more and more
difficult to make them work with your adaptations. It would be so much easier,
if the upstream project knew about your problem and needs. Then you begin to realize that
open-source software is only available and free
of charge to you because other people took the time to publish their ideas and
code in the open. You know that you could do the same and avoid the upstream changes
working against you. You realize it would be smart to &lt;em&gt;contribute back&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;upstream-first&quot;&gt;Upstream First&lt;/h2&gt;

&lt;p&gt;Upstream First means that whenever you solve a problem in your copy of the
upstream code which others could benefit from, you contribute these
changes back upstream, i.e. you send a patch or open a pull request to the
upstream repository.&lt;/p&gt;

&lt;p&gt;In the course of contributing back, you may have to discuss with the community
members of the upstream project. You may find there is already a solution you
were not aware of. You may find your solution can be improved. Most importantly,
when the upstream project releases a new version, you can delete your
modifications from your fork and stop worrying about the adaptation work you
would have to do if you hadn’t contributed back.&lt;/p&gt;

&lt;h2 id=&quot;does-upstream-first-just-mean-being-kind&quot;&gt;Does Upstream First just mean being kind?&lt;/h2&gt;

&lt;p&gt;Upstream First is more than just “being kind”. It means you have a say in the
project. It means predictability. It means you are in control. It means you act
rather than react. It means you understand open-source.&lt;/p&gt;
</description>
        <pubDate>Fri, 22 Jan 2021 10:59:14 +0100</pubDate>
        <link>https://maximilianmichels.com/2021/upstream-first/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2021/upstream-first/</guid>
        
        
        <category>upstream</category>
        
        <category>first</category>
        
        <category>open</category>
        
        <category>source</category>
        
      </item>
    
    
    
      <item>
        <title>The 4 Pillars of Successful Open-Source Communities</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;The community is the backbone of an open-source project. It
establishes a framework for collaboration, innovation, growth, and
sustainability. In order to for an open-source project to be a successful, it needs to
develop a community.
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;p&gt;Let’s have a look at what makes a good community, how communities are structured, and how to build them. I’ll also try to point out common pitfalls when developing communities.&lt;/p&gt;

&lt;h2 id=&quot;asking-the-right-questions&quot;&gt;Asking the Right Questions&lt;/h2&gt;

&lt;p&gt;There are pros and cons to building a community. Let’s have a look at why you should or shouldn’t invest in building a community:&lt;/p&gt;

&lt;h3 id=&quot;why-should-you-build-a-community&quot;&gt;Why should you build a community?&lt;/h3&gt;

&lt;p&gt;The following are good reasons to build an open-source community:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Attract attention to your personal self or your company&lt;/p&gt;

    &lt;p&gt;Believe it or not, but selfish motives are a common theme in open-source. Open-source can enable you to be recognized and be seen as an industry leader. Open-source provides attention across organizations and corporate environments.&lt;/p&gt;

    &lt;p&gt;If you run your own company, you could build a community to attract attention, then offer services around the open-source product, e.g. selling subscriptions, consulting, or proprietary products related to the open-source project.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Innovation and ideas&lt;/p&gt;

    &lt;p&gt;Lively open-source communities allow for a rapid exchange of ideas. This drives innovation in open-source software.
Releases can be made often and interaction with users is possible at any point in time. This can yield a very effective feedback loop which accelerates innovation.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Recruitment&lt;/p&gt;

    &lt;p&gt;Companies or organizations which have a good reputation in open-source are popular amongst many developers. This can be a factor for driving people to your project. Many communities are built on top of existing communities, or relate to existing open-source communities because they share code with each other. This allows bootstrapping a community more easily by collaborating with existing communities.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Saving costs&lt;/p&gt;

    &lt;p&gt;By building a community, you can share the costs for maintenance, testing, and innovation. In a perfect community you get all this from the community and you just have to invest a small part in it. Initially, building a community will be work but can very rewarding.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Forking&lt;/p&gt;

    &lt;p&gt;You may have forked a project whose community is dying or controlled by an actor which does not play fair. There are many cases where that’s not a good idea but it can make sense. A good example where forking worked is the CI server Hudson which was backed by Sun. After Sun was acquired by Oracle, the community forked the project and it became Jenkins. This was a success and allowed the project to grow independently of Oracle’s interests.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Open-source is fun.&lt;/p&gt;

    &lt;p&gt;Exchanging ideas, making new connections, working together towards a goal, sharing resources - all that is great fun. Being open is a modern mindset that makes solving many problems easier.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;why-shouldnt-you-build-a-community&quot;&gt;Why shouldn’t you build a community?&lt;/h3&gt;

&lt;p&gt;There a legitimate reasons why building a community might not be a good idea. Let’s have a look at some of the counter-arguments:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;You think the community is going to build itself&lt;/p&gt;

    &lt;p&gt;Nope. Building a community will be a lot of work.
How much precisely depends on the momentum of your project (demand) and how you effectively generate it (marketing). The more people you have initially and how well they are connected to the industry or other open-source projects will make a big impact.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The technology is not innovative or useful to people&lt;/p&gt;

    &lt;p&gt;It is going to be hard to build a community around software which people do not really want to use. You may ask yourself, “Who cares about my project?” If you can’t think of a handful of people who would find your software immensely useful, chances are that nobody does.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You want to offload the maintenance and development.&lt;/p&gt;

    &lt;p&gt;Things will likely not turn out the way you intended. If you do not want to participate in leadership of a project, it will likely not go anywhere, or you’ll lose influence over it.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;(Hostile) Forking&lt;/p&gt;

    &lt;p&gt;People will not like forks unless there is a good reason for it. Consider Open Office, which was open-sourced by Sun. When Sun was acquired by Oracle, Oracle decided to not invest into Open Office anymore. This led to a fork which was called Libre Office. The fork couldn’t use the name Open Office because Oracle owns the brand Open Office. Even though Libre Office can be considered a successful fork, to this day it suffers from the popularity of the Open Office brand. Yet, there are many examples of (hostile) forks which never went anywhere.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You think open-source itself is a business model&lt;/p&gt;

    &lt;p&gt;Through OSS, one can find great way to build a business, but do not expect open-source to generate money if you haven’t developed a good business idea. Nowadays, many people talk about big players like Amazon offering open-source products as a service and not contributing back to them. Although one may criticize that, please take this possibility into account when you develop your business idea.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You are afraid of having IP stolen.&lt;/p&gt;

    &lt;p&gt;Generally speaking, you should be comfortable with sharing IP. Not sharing it usually leads to licensing problems, which can hinder adoption. Open-source is not a one-way street, you get something in return for your ideas, but you may have to start sharing first.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;You are a control freak.&lt;/p&gt;

    &lt;p&gt;Just don’t.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;what-about-existing-communities&quot;&gt;What about existing communities?&lt;/h3&gt;

&lt;p&gt;Do you really need to start a new community? Maybe there is already a community that would fit your needs. Think about joining one. Building a community from scratch can be much harder than joining an existing one. You can start making an impact in the project and focus on the things that matter most to you.&lt;/p&gt;

&lt;h2 id=&quot;the-4-pillars-of-a-successful-open-source-community&quot;&gt;The 4 Pillars of a Successful Open-Source Community&lt;/h2&gt;

&lt;p&gt;For a strong open-source community you need the following ingredients:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/communities/4-pillars-of-open-source.png&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;1-code&quot;&gt;1. Code&lt;/h3&gt;

&lt;p&gt;Why code? A community can only evolve about a meaningful piece of software. If you don’t provide value to people, nobody is going to care about your project.
          So think about the existing open-source software and how you will
          provide value to motivate others to join and participate.&lt;/p&gt;

&lt;p&gt;Code also attracts a certain type of community. Innovativeness, ease of use, complexity, and the programming language play an important part in what kind of community evolves around a project.
          For example, compare a Lisp project with a Javascript project. Compare
          system software like a database to a web framework or a JS
          library. The type of code has a huge impact on the type of community
          that grows around a project.&lt;/p&gt;

&lt;p&gt;You should ask yourself:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;“Do I know the type of people that could contribute?“&lt;/li&gt;
  &lt;li&gt;“Is there a demand for a community around your code?”&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;2-people&quot;&gt;2. People!&lt;/h3&gt;

&lt;p&gt;Code aside, of course a community is all about the people. If you look up who is part of an open-source community, you usually find this definition:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Users&lt;/li&gt;
  &lt;li&gt;Developers&lt;/li&gt;
  &lt;li&gt;Contributors (most of the time these are both Users and Developers)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In reality, things are much more complicated:&lt;/p&gt;

&lt;p&gt;Take software developers as an example. They are part of the community but they are rarely employed by the project — the open-source funding dilemma. Instead, they work at companies whose corporate goals vary. As a project you need to acknowledge this.&lt;/p&gt;

&lt;p&gt;Don’t expect that everyone can spend the same amount of time in the community, but still give everyone a chance to participate.&lt;/p&gt;

&lt;p&gt;Do not rely on a single person to maintain a project, build in some redundancy by having a second maintainer or at least document things well. Otherwise you have a single point of failure for your project.
Maintainer burnout is a very real thing, so acknowledge the work of developers
and find a way to balance the work the developers have to do.&lt;/p&gt;

&lt;p&gt;Recognize that your community can span outside the code domain. This makes your community more diverse and can significantly grow it. Consider the following roles:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Decision makers&lt;/p&gt;

    &lt;p&gt;Every project has people behind the scenes which vouch for open-source projects. Knowing who that is finding a way to eventually recognize their contributions can be very valuable.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;What about writers / bloggers / organizers / evangelists / influencers / enthusiasts?&lt;/p&gt;

    &lt;p&gt;Make it easy for non-developers to reach out. It is the stories that lead people to using your software or joining your community.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Think about all the roles that you need in your community and whether all of them currently exist:&lt;/p&gt;

    &lt;p&gt;What could be those roles? For example: Coders, architects, reviewers, leaders, organizers, supporters, helpers, questioners, explainers, moderators. Having a diverse set of roles is crucial for a functioning community.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-critical-mass&quot;&gt;The Critical Mass&lt;/h4&gt;

&lt;p&gt;Every community needs a group of people which takes responsibility for a project. I call that the critical mass. What does the critical mass do? They are the project managers of the project. They are self-motivated with a long-term interest. They build structures and delegate responsibility. They promote the project in the industry, they are active in the day-to-day business of the project. They help to organize offline meetings, such as meetups and conferences to foster the relationships.&lt;/p&gt;

&lt;p&gt;What would be a good example of a things done by the critical mass?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Starting off the project
    &lt;ul&gt;
      &lt;li&gt;Donating the code / licensing it appropriately&lt;/li&gt;
      &lt;li&gt;Creating bylaws / code of conduct / contributions guidelines&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Day to day business
    &lt;ul&gt;
      &lt;li&gt;Foster open discussions (e.g. mailing list)&lt;/li&gt;
      &lt;li&gt;Ensuring the project stays relevant (technology)&lt;/li&gt;
      &lt;li&gt;Getting rid of technical debt&lt;/li&gt;
      &lt;li&gt;Ensure project’s infrastructure works correctly&lt;/li&gt;
      &lt;li&gt;Meditating conflicts&lt;/li&gt;
      &lt;li&gt;Recognize contributions and recruit new community members (!)&lt;/li&gt;
      &lt;li&gt;Highlight achievements e.g. reaching milestones 1000 PRs, new committers, anniversaries&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Outreach
    &lt;ul&gt;
      &lt;li&gt;Organize meetups and conferences&lt;/li&gt;
      &lt;li&gt;Write books or articles&lt;/li&gt;
      &lt;li&gt;Promote on social media&lt;/li&gt;
      &lt;li&gt;Being excited&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you find a critical mass? To give you an idea, here’s a great quote by Jan Lenhardt:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I tried to be involved with every thread on the mailing list, showing exemplary behaviour, being nice to people, taking their issues seriously and trying to be helpful overall. After a while, people stuck around not to only ask questions, but to help with answering as well, and to my complete delight, they mimicked my style.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;small&gt;Quote taken from &lt;a href=&quot;https://writing.jan.io/2015/11/20/sustainable-open-source.html&quot;&gt;https://writing.jan.io/2015/11/20/sustainable-open-source.html&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;The critical mass is the role model of the community. It all starts with a few people but it grows over time.&lt;/p&gt;

&lt;h3 id=&quot;3-processes&quot;&gt;3. Processes&lt;/h3&gt;

&lt;p&gt;Every community needs clearly defined processes for:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Workflows
    &lt;ul&gt;
      &lt;li&gt;How do you contribute to the project?&lt;/li&gt;
      &lt;li&gt;How are changes reviewed?&lt;/li&gt;
      &lt;li&gt;How do we document changes?&lt;/li&gt;
      &lt;li&gt;How do we test changes?&lt;/li&gt;
      &lt;li&gt;How do we release software? How often?&lt;/li&gt;
      &lt;li&gt;What tools do we rely on?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Communication
    &lt;ul&gt;
      &lt;li&gt;How do we communicate with each other? (Tools, code of conduct, work flows)&lt;/li&gt;
      &lt;li&gt;How do you earn merit?&lt;/li&gt;
      &lt;li&gt;Who takes care of recognizing contributions?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Decision-making
    &lt;ul&gt;
      &lt;li&gt;How do we decide?&lt;/li&gt;
      &lt;li&gt;Consensus, majority-based?&lt;/li&gt;
      &lt;li&gt;Who has the final say?&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Legal
    &lt;ul&gt;
      &lt;li&gt;What do we have to watch out for?
        &lt;ul&gt;
          &lt;li&gt;licensing,&lt;/li&gt;
          &lt;li&gt;use of libraries, logos&lt;/li&gt;
          &lt;li&gt;compliance&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these processes should be formalized and documented as much as possible. This not only helps the existing community but also allows others to understand how the community works and whether it is safe to rely on the produced software.&lt;/p&gt;

&lt;h2 id=&quot;4-ownership&quot;&gt;4. Ownership&lt;/h2&gt;

&lt;p&gt;Ownership is often associated with the license of the code, so let’s review some common open-source licenses:&lt;/p&gt;

&lt;h3 id=&quot;open-source-licenses&quot;&gt;Open-Source licenses&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Public domain&lt;/p&gt;

    &lt;p&gt;Not actually a license but a statement which permits free use. This can be problematic in some countries because of the jurisdictional consequences if the license does not state that the software comes without warranties.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Permissive: Apache, BSD, MIT, etc.&lt;/p&gt;

    &lt;p&gt;This is still pretty much “do whatever you want” but with a legal framework for warranty, branding, distribution and attribution.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Copyleft: GPL, Eclipse Public, etc.&lt;/p&gt;

    &lt;p&gt;These require you to contribute back your changes if you ever were to distribute the Copyleft licensed code.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Propriertary-ish: Open core and other custom licenses.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Licenses are important for communities because they set the legal framework for
contributions. They also influence the type of communities which built around
them because they allow for different use of the software.&lt;/p&gt;

&lt;p&gt;For example, the Apache license doesn’t require you to contribute back if you
make changes and distribute/sell them. That may seem bad for the community but
it is also a great way to grow the adoption of the code and help the community.&lt;/p&gt;

&lt;p&gt;For a community to grow, contributing back upstream and engaging with the
community is necessary. There should be an incentive for individuals or
companies to stay relevant in the project and participate in it. If you make it easy
for people or companies to do that, the license may be secondary.&lt;/p&gt;

&lt;h3 id=&quot;beyond-the-license&quot;&gt;Beyond the license&lt;/h3&gt;

&lt;p&gt;Ownership is not only limited to the license. It also applies to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Infrastructure (repository, mailing list, chat, servers)&lt;/li&gt;
  &lt;li&gt;Name (Trademark)&lt;/li&gt;
  &lt;li&gt;Decision-making / governance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The two most prominent models are:&lt;/p&gt;

&lt;h4 id=&quot;owned-by-a-single-person--company&quot;&gt;Owned by a single person / company&lt;/h4&gt;

&lt;p&gt;Often these projects are owned and led by a “Benevolent dictator”. Prominent examples are Guido van Rossum (Python) and Linus Torvalds (Linux).&lt;/p&gt;

&lt;p&gt;There are pros and cons to this model. For one, it’s easy to stay in control and keep the project focused. On the other hand, the dictator can become the bottleneck of the project which will slow down its growth. This happened to Linux in the early 2000s when Linus Torvalds was still reviewing and approving all incoming changes.&lt;/p&gt;

&lt;h4 id=&quot;foundation-owned&quot;&gt;Foundation owned&lt;/h4&gt;

&lt;p&gt;Famous foundations for open-source are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Apache Software Foundation&lt;/li&gt;
  &lt;li&gt;Python Software Foundation&lt;/li&gt;
  &lt;li&gt;Linux Foundation&lt;/li&gt;
  &lt;li&gt;Eclipse Foundation / Mozilla Foundation&lt;/li&gt;
  &lt;li&gt;Free Software Foundation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my eyes, the ASF and the FSF are the most open although they are quite
different in terms of defining freedom in code. They both accept monetary donations, but the only way to influence projects is by gaining merit in them.&lt;/p&gt;

&lt;p&gt;What does that mean? It means that you based on your contributions to the
project you will be granted responsibility (comittership) which gives you power
in the project. At the ASF, there is an incubation process which teaches and probes new projects on good behavior inside Apache.&lt;/p&gt;

&lt;p&gt;At the Linux and Python software foundation there is also a merit-based model,
but contrary to the ASF or FSF, you can also donate money to have a saying in the project’s decisions.&lt;/p&gt;

&lt;p&gt;In the end, it doesn’t matter what model you choose but it does look like the open governance model in software foundations has the most potential to grow a large community.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;There is not easy recipe for open-source communities. This probably shouldn’t
come as a big surprise. Building a community is a not something that happens
overnight. Rather it takes a continuous effort to nourish a community. The level
of effort may decline once the community is more mature, but there are
inevitable going to be challenges which the community will face. To succeed with
building a community you need to invest long-term.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A good community is one which develops a good standpoint in all four domains: Code, People, Processes, and Ownership (COPP).&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-mindset-for-success&quot;&gt;The mindset for success&lt;/h3&gt;

&lt;p&gt;We have learned about the 4 pillars for a successful open-source community (COPP). In addition, here are 5 important principles which you should watch out for in the course of building a successful community:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Communicate openly&lt;/li&gt;
  &lt;li&gt;Document well&lt;/li&gt;
  &lt;li&gt;Innovate frequently&lt;/li&gt;
  &lt;li&gt;Recruit always&lt;/li&gt;
  &lt;li&gt;Foster relationships, e.g. via Meetups/Conferences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a critical mass, you can build the foundation for your community. Your critical mass might be small to begin with, so keep an eye open for potential new members. Remember, relationships are the core of every strong community.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;
This post is based on talks given at Fossbackstage 2020 and Berlin Buzzwords
2020.
&lt;/small&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 31 Dec 2020 12:38:14 +0100</pubDate>
        <link>https://maximilianmichels.com/2020/the-4-pillars-of-successful-open-source-communities/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2020/the-4-pillars-of-successful-open-source-communities/</guid>
        
        
        <category>open-source</category>
        
        <category>project</category>
        
        <category>communities</category>
        
        <category>principles</category>
        
      </item>
    
    
    
      <item>
        <title>The Art of Debugging Distributed Systems</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;Debugging is the process of identifying the root cause of an unexpected behavior of a software program. In software development, bugs are inevitable — No matter how good programmers are. Distributed systems are no exception in this regard, but they are often more difficult to debug.
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;p&gt;Let’s take a look at why this is the case.&lt;/p&gt;

&lt;h2 id=&quot;the-hierarchy-of-complexity-for-debugging&quot;&gt;The Hierarchy of Complexity for Debugging&lt;/h2&gt;

&lt;p&gt;There is a hierarchy of complexity when it comes to debugging software:&lt;/p&gt;

&lt;h3 id=&quot;level-1-nonconcurrency&quot;&gt;Level 1: Nonconcurrency&lt;/h3&gt;

&lt;p&gt;The program to debug is strictly nonconcurrent, meaning there is a single program path which is executed.&lt;/p&gt;

&lt;p&gt;These are single-threaded programs, i.e. programs running on a single machine, using only a single CPU core.&lt;/p&gt;

&lt;h3 id=&quot;level-2-concurrency&quot;&gt;Level 2: Concurrency&lt;/h3&gt;

&lt;p&gt;The program utilizes concurrency in its execution paths. At any point in time there are multiple paths in the program which are executed without a guaranteed order.&lt;/p&gt;

&lt;p&gt;Typical these programs use one of the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Multithreading_(computer_architecture)&quot;&gt;multithreading&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Coroutine&quot;&gt;coroutines&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that concurrency does not mean that multiple programs paths execute at the same time. Rather, it means that the order in which the program paths execute cannot be guaranteed. If the execution paths have a dependency on each other, e.g. one thread needs to hand over a partial result to another thread, correct execution can only be ensured if the two execution paths can execute serially. Serial execution is defined to yield the same result, no matter of the order in which the execution paths run.&lt;/p&gt;

&lt;h3 id=&quot;level-3-distribution&quot;&gt;Level 3: Distribution&lt;/h3&gt;

&lt;p&gt;The program runs in a distributed fashion, meaning it’s composed of multiple independent but interconnected computing nodes. The nodes exchange messages to coordinate the distributed computing. Regardless of whether the individual nodes use concurrency, the overall distributed application is automatically concurrent because each node has its own execution path.&lt;/p&gt;

&lt;h2 id=&quot;why-debugging-distributed-systems-is-hard&quot;&gt;Why debugging distributed systems is hard&lt;/h2&gt;

&lt;p&gt;Debugging distributed systems is hard because we operate on Level 3 which includes both the concurrency as well as the distributed execution as a source of errors. While it may be trivial to read the code to figure out a bug on Level 1, it can become challenging to figure out what different threads on Level 2 are doing. On Level 3 we have another dimension for bugs arising from the message exchange of nodes. It’s often non-trivial to capture the state in a distributed system, as we can’t attach a debugger to all nodes at the same time. Likewise, integration tests are harder to write because they require a test scenario as close to running the actual distributed system as possible.&lt;/p&gt;

&lt;p&gt;To understand this better, let’s look at common debugging techniques and how they relate to debugging distributed systems:&lt;/p&gt;

&lt;h2 id=&quot;common-debugging-techniques&quot;&gt;Common Debugging Techniques&lt;/h2&gt;

&lt;p&gt;Let’s look at some of the common debugging techniques which can be applied at Level 1 and Level 2.&lt;/p&gt;

&lt;h3 id=&quot;understanding-error-messages&quot;&gt;Understanding error messages&lt;/h3&gt;

&lt;p&gt;As basic as it sounds, understanding the error message or related messages is often enough to fix the cause of a bug. Usually, that requires good knowledge of the internals of the software which reports the error. However, the error message may not be related to the actual cause of the error and thereby distract from the real problem. In any case, the error message is usually the starting point of the investigation.&lt;/p&gt;

&lt;p&gt;In a distributed system, obtaining an error message is not always trivial because the actual cause of the error might occur and get logged on a different machine. Errors messages are not guaranteed to be propagated back to the client which initiated the request. Understanding the message flow between the nodes of a distributed systems, as well as having an infrastructure to obtain metrics and logs from all nodes is crucial here.&lt;/p&gt;

&lt;h3 id=&quot;reading-the-code&quot;&gt;Reading the code&lt;/h3&gt;

&lt;p&gt;It may seem counter-intuitive, but going back to the code and verifying its desired behavior can be the most effective way to identify and fix bugs.&lt;/p&gt;

&lt;p&gt;In a distributed system, the code paths are often spread across multiple modules which execute across many machines. The message exchange may not always be defined clearly and this makes debugging hard. Also, the error could depend on a non-obvious interleaving of messages.&lt;/p&gt;

&lt;p&gt;If a bug cannot be properly identified by just reading the code, more information needs to be gathered by using one or more of the following methods.&lt;/p&gt;

&lt;h3 id=&quot;using-code-checkers&quot;&gt;Using code checkers&lt;/h3&gt;

&lt;p&gt;Code checkers such as valgrind (C, C++), Findbugs / Spotbugs (Java) use a set of rules to detect programming mistakes which can lead to bugs. These can run statically at runtime (e.g. Findbugs / Spotbugs) or dynamically at runtime (e.g. valgrind). It makes sense to inspect the errors or warnings on a regular basis.&lt;/p&gt;

&lt;p&gt;While code checkers are good to find edge cases or memory leaks, they do not cover the whole spectrum of possible bugs. Also, they often just give a hint about an error and more debugging has to be performed afterwards.&lt;/p&gt;

&lt;h3 id=&quot;adding-tests&quot;&gt;Adding tests&lt;/h3&gt;

&lt;p&gt;By adding tests for the broken functionality, we can ensure that our assumptions gathered from reading the code hold true. Tests also allow us to check for edge cases in the program execution which are easily missed if checked by hand. Tests come in various forms:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;unit tests&lt;/li&gt;
  &lt;li&gt;integration tests&lt;/li&gt;
  &lt;li&gt;end-to-end tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The downside of using testing for debugging is that the test creation is usually biased. Programmers tend to only test for the cases they can imagine. Non-trivial bugs are often hard to find using this method. However, tests are a great way to ensure regressions do not occur once a bug has been identified and fixed.&lt;/p&gt;

&lt;p&gt;In distributed systems, testing the actual distributed setup including simulation of real-world failure scenarios, such as machine failures or network partitions, is hard to do. Also developing the proper testing utilities to built a distributed test environment locally, can be challenging.&lt;/p&gt;

&lt;h4 id=&quot;bisecting&quot;&gt;Bisecting&lt;/h4&gt;

&lt;p&gt;In debugging, bisecting is the process of running a &lt;a href=&quot;https://en.wikipedia.org/wiki/Binary_search_algorithm&quot;&gt;binary search&lt;/a&gt; on the commit log of the version control system such as Git. For every version found in the commit log, a new version of the software is built. Then, a test is run which determines whether this version is healthy or not. One starts by declaring the latest &lt;em&gt;healthy&lt;/em&gt; (correctly working, also called &lt;em&gt;good&lt;/em&gt;) version and a known &lt;em&gt;unhealthy&lt;/em&gt; (buggy, also called &lt;em&gt;bad&lt;/em&gt;) version. Using binary search, we then search between the healthy and the unhealthy version. A test is run to determine whether a version is healthy. Eventually, this will find the first commit which was unhealthy. The change set can then reveal information about what introduced the bug.&lt;/p&gt;

&lt;p&gt;On a single node, this process is usually efficient if the test runs fast. In a distributed system, this process can become very time-intense due to the need to deploy a new version every time. Also, this only works efficiently if all tasks can be automated.&lt;/p&gt;

&lt;h3 id=&quot;logging&quot;&gt;Logging&lt;/h3&gt;

&lt;h4 id=&quot;logs&quot;&gt;logs&lt;/h4&gt;

&lt;p&gt;If logs are available, they can give an idea of what happened before the bug occurred. Logs are usually easily accessible on the same machine.&lt;/p&gt;

&lt;p&gt;In a distributed system, logs are spread across multiple machines. Getting access to the right machine and searching the logs becomes much more involved.&lt;/p&gt;

&lt;p&gt;If not enough output is available, we may have to generate some output:&lt;/p&gt;

&lt;h4 id=&quot;printf-debugging&quot;&gt;printf debugging&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;printf&lt;/code&gt; is a function from the C standard library. In Printf debugging we are outputting information about the state of the program to a console, file or any other output method. This allows us to understand the behavior of the program better.&lt;/p&gt;

&lt;p&gt;The drawback of this method is that it requires us to alter the program itself. In concurrent programs this can lead to a bug not showing up anymore, which does not make it applicable in all scenarios.&lt;/p&gt;

&lt;p&gt;In distributed system, we face the difficulty of deployment costs and time. Deploying a new version of the software might take a considerate amount of time.&lt;/p&gt;

&lt;h4 id=&quot;tracing&quot;&gt;Tracing&lt;/h4&gt;

&lt;p&gt;Tracing tools allow us to understand the instruction flow of the program execution. This can involve the state changes in the program or system calls to the underlying operating systems (e.g. &lt;code&gt;strace&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In a distributed system, the tracing needs to be aware of the multiple instances of the software. Otherwise, the trace on a single node may not reveal the necessary information for debugging the problem.&lt;/p&gt;

&lt;h3 id=&quot;using-a-debugger&quot;&gt;Using a debugger&lt;/h3&gt;

&lt;p&gt;A debugger is a separate program which attaches to the program we want to debug. Debuggers can gather information about the state of the program at any point in time. They also allow to set breakpoints at specific instructions or, if the source code is available, at lines of the source code.&lt;/p&gt;

&lt;p&gt;Debuggers are very powerful. In the case of concurrent programs (Level 2) using multiple threads, we can halt the execution of all threads and inspect their state.&lt;/p&gt;

&lt;p&gt;In distributed systems, there is the hurdle of using the debugger on the correct node. Halting the execution of the program may cause timeouts on other nodes and provoke a unwanted failure scenario in the distributed system.&lt;/p&gt;

&lt;h3 id=&quot;profiling&quot;&gt;Profiling&lt;/h3&gt;

&lt;p&gt;In profiling, we can sample CPU, memory, or disk usage. For statically compiled languages such as C/C++, we usually need to recompile to enable profiling information. For dynamically compiled languages with a runtime environment such as Java with its JVM, we can use a profiler such as JProfiler which gathers the information from the running program without having to recompile.&lt;/p&gt;

&lt;p&gt;A profiler can be useful to detect memory leaks or performance-related bugs. Like the debugger, profiling will be performed per-node. This information has to be inspected individually, or we can collect and merge this information to be able to get an overview of all the nodes in a distributed system.&lt;/p&gt;

&lt;h2 id=&quot;debugging-techniques-for-distributed-systems&quot;&gt;Debugging Techniques for Distributed Systems&lt;/h2&gt;

&lt;p&gt;We have already learned that the overall complexity in debugging distributed systems is higher. Here are a few techniques which, additionally to the already described debugging techniques, can help with debugging distributed systems:&lt;/p&gt;

&lt;h3 id=&quot;contracts-and-documentation&quot;&gt;Contracts and documentation&lt;/h3&gt;

&lt;p&gt;Without an understanding of the communication between nodes in a distributed system, it is often impossible to debug. Specifying the message protocol between nodes in a distributed systems, provides a reference for debugging illegal message exchange. Modern distributed system architecture like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Actor_model&quot;&gt;Actor model&lt;/a&gt; have made documenting message exchange easier, yet it is still up to developers to enforce and document contracts.&lt;/p&gt;

&lt;h3 id=&quot;defensive-programming&quot;&gt;Defensive programming&lt;/h3&gt;

&lt;p&gt;Whenever contracts or assumptions the code makes are violated, we should print out a warning or fail with an appropriate error message. This provides feedback to the developers and users early on in the software cycle and allows to fix bugs before they are shipped to the customer, and before they become hard to fix.&lt;/p&gt;

&lt;h3 id=&quot;better-tests&quot;&gt;Better tests&lt;/h3&gt;

&lt;h4 id=&quot;instrumentation-for-integration-tests&quot;&gt;Instrumentation for integration tests&lt;/h4&gt;

&lt;p&gt;Code should be easy to test. If test utilities allow for an easy setup of local versions of the distributed systems, more tests will be written. This can be achieved by parameterizing components to allow them to run locally instead of fully distributed.&lt;/p&gt;

&lt;h4 id=&quot;end-to-end-tests&quot;&gt;End-to-end tests&lt;/h4&gt;

&lt;p&gt;End-to-end tests are a great way to see if the common code paths work correctly across all nodes. Compared to unit or integration tests, these are more expensive in terms of setup and computing resources but they also provide the most realistic test scenario. The downside is that end-to-end tests are not good at testing edge cases which can be more easily tested using unit or integration tests.&lt;/p&gt;

&lt;h3 id=&quot;remote-debugging&quot;&gt;Remote Debugging&lt;/h3&gt;

&lt;p&gt;In remote debugging, we connect a locally running debugger to a remote node of the distributed system. This allows us to use the same features as if we were debugging a locally running program. Key problem here is to identify which node to connect to and to avoid network timeouts while debugging parts of the distributed system.&lt;/p&gt;

&lt;h3 id=&quot;distributed-logging&quot;&gt;Distributed logging&lt;/h3&gt;

&lt;h4 id=&quot;log-collection-and-visualization&quot;&gt;Log collection and visualization&lt;/h4&gt;

&lt;p&gt;Log collection tools (e.g. Prometheus or Logstash) collect and transform log files, then insert them into a data store (e.g. Prometheus or Elasticsearch). Visualization tools (e.g. Prometheus or Kibana) allow you to query and visualize the data across all nodes of a distributed system or selectively for certain nodes. This can be very helpful when looking for errors messages or certain outputs.&lt;/p&gt;

&lt;h4 id=&quot;metrics&quot;&gt;Metrics&lt;/h4&gt;

&lt;p&gt;In addition to logs, distributed systems usually emit metrics which can be an indicator for what is happening during execution. Apart from application specific metrics, standard metrics like CPU usage, memory usage, and network saturation are typically available.&lt;/p&gt;

&lt;h4 id=&quot;distributed-tracing&quot;&gt;Distributed tracing&lt;/h4&gt;

&lt;p&gt;In distributed tracing, we extend the tracing for a single node to a distributed system. For example, we could store all messages exchanged such that we can replay the messages to reproduce the bug. Note, that this way of replaying may not always work because the state changes within the nodes might also be important for reproducing the bug. This is where deterministic replay becomes interesting.&lt;/p&gt;

&lt;h3 id=&quot;distributed-deterministic-simulation-and-replay&quot;&gt;Distributed deterministic simulation and replay&lt;/h3&gt;

&lt;p&gt;It’s a typical scenario that we see a bug occur, even during testing, but we can’t reproduce the bug by running the test again. If only there was a way to deterministically replay the test run? Turns out, this is possible by creating a simulation layer which abstracts the underlying hardware and the network interfaces to allow for an exact replay of all the state changes and messages exchanged between the nodes. To my best knowledge, this was pioneered by &lt;a href=&quot;https://apple.github.io/foundationdb/testing.html&quot;&gt;FoundationDB&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;model-checking&quot;&gt;Model checking&lt;/h3&gt;

&lt;p&gt;By building a model of the concurrent and distributed aspects of the systems, we can formally specify important aspects of it. Further, we can then run model checks to see if the system is guaranteed to run correctly, according to our model. One language which is used by Amazon and Microsoft is &lt;a href=&quot;https://en.wikipedia.org/wiki/TLA%2B&quot;&gt;TLA+&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Debugging distributed systems is hard, but not impossible. With the right tools and practices it is a reasonable endeavour. Did I miss something here? Let me know via email or feel free to comment on the &lt;a href=&quot;https://twitter.com/stadtlegende/status/1313859680805031937&quot;&gt;Twitter thread&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Wed, 07 Oct 2020 11:05:33 +0200</pubDate>
        <link>https://maximilianmichels.com/2020/debugging-distributed-systems/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2020/debugging-distributed-systems/</guid>
        
        
        <category>distributed</category>
        
        <category>system</category>
        
        <category>debugging</category>
        
      </item>
    
    
    
      <item>
        <title>5 Steps to Get Started with Data Processing in Python Using Apache Beam</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;Over two years ago, &lt;a href=&quot;https://beam.apache.org&quot;&gt;Apache Beam&lt;/a&gt; introduced the portability framework which allowed pipelines to be written in other languages than Java, e.g. Python and Go. Here’s how to get started writing Python pipelines in Beam.
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;h2 id=&quot;1-creating-a-virtual-environment&quot;&gt;1. Creating a virtual environment&lt;/h2&gt;

&lt;p&gt;Let’s first create a virtual environment for our pipelines. Note that we want to use Python 3 because Python 2 is now obsolete and won’t be supported in future Beam releases.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;gt; virtualenv --python&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;python3 venv
&amp;gt; &lt;span class=&quot;nb&quot;&gt;source &lt;/span&gt;venv/bin/activate&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now let’s install the latest version of Apache Beam:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;gt; pip install apache_beam&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;2-writing-a-beam-python-pipeline&quot;&gt;2. Writing a Beam Python pipeline&lt;/h2&gt;

&lt;p&gt;Next, let’s create a file called &lt;code&gt;wordcount.py&lt;/code&gt; and write a simple Beam Python pipeline. I recommend using PyCharm or IntelliJ with the PyCharm plugin, but for now a simple text editor will also do the job:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;beam&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam.transforms.window&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;window&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam.options.pipeline_options&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PipelineOptions&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run_pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Load pipeline options from the script&amp;#39;s arguments&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PipelineOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# Create a pipeline and run it after leaving the &amp;#39;with&amp;#39; block&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Wrap in paranthesis to avoid Python indention issues&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# Load some dummy data, this can be replaced with a proper source later on&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Create words&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;to be or not to be&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# Split the words into one element per word&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Split words&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FlatMap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# We are assigning a count of 1 to every word (very relevant if we had more data)&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Pair with 1&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# We are interested in 10 second periods of words&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Window of 10 seconds&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WindowInto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FixedWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# Group all the values (counts) of each unique word&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Group by key&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GroupByKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# Sum the counts for each word and return the result&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Sum word counts&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
     &lt;span class=&quot;c&quot;&gt;# Just print to the console for testing&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Print to console&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wordcount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wordcount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;run_pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Please see the inline comments for an explanation of what the code does.&lt;/p&gt;

&lt;p&gt;We can now run the pipeline:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;gt; python wordcount.py
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;to&amp;#39;&lt;/span&gt;, 2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;be&amp;#39;&lt;/span&gt;, 2&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;or&amp;#39;&lt;/span&gt;, 1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;not&amp;#39;&lt;/span&gt;, 1&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Arguably, that’s a very simple pipeline but you get the gist. Later on, we will change the data source to read from Kafka.&lt;/p&gt;

&lt;h2 id=&quot;3-choosing-a-runner&quot;&gt;3. Choosing a Runner&lt;/h2&gt;

&lt;p&gt;By default, the so called DirectRunner runs your pipeline. The DirectRunner is only intended for local development purposes. It’s very slow and does not support distributed execution.&lt;/p&gt;

&lt;p&gt;Let’s run the same pipeline with the Flink Runner which will runs the pipeline (you guessed it) on top of Apache Flink:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;gt; python wordcount.py --runner&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;FlinkRunner&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;What happens when you run your script with the &lt;code&gt;--runner&lt;/code&gt; argument? Beam will look up the Runner (FlinkRunner) and attempt to run the pipeline. By default, this will download the Flink Runner JAR which contains the Beam JobService. The JobService will receive the pipeline and submit the pipeline to a Flink cluster. If you do not specify a cluster address via &lt;code&gt;--flink_master&lt;/code&gt;, a local Flink cluster will be started.&lt;/p&gt;

&lt;p&gt;Fore more information visit the &lt;a href=&quot;https://beam.apache.org/documentation/runners/flink/&quot;&gt;Flink Runner page&lt;/a&gt;. The page also contains information on other Runners, such as Google Cloud Dataflow or Apache Spark.&lt;/p&gt;

&lt;h2 id=&quot;4-configuring-the-environment&quot;&gt;4. Configuring the environment&lt;/h2&gt;

&lt;p&gt;By default, the Python code will run in a so called &lt;code&gt;LOOPBACK&lt;/code&gt; environment. That’s an environment intended for development and testing purposes. It’s called &lt;code&gt;LOOPBACK&lt;/code&gt; because a local Python process is started which runs the Python code. However, if you submit to a cluster, the environment will default to &lt;code&gt;DOCKER&lt;/code&gt; which will bring up Docker containers on each of the hosts.&lt;/p&gt;

&lt;p&gt;If you want to test the Docker-based execution locally, you can specify the following:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&amp;gt; python wordcount.py --runner&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;FlinkRunner --environment_type&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;DOCKER&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The Beam community publishes Docker images for all releases which are used by default. You can &lt;a href=&quot;https://beam.apache.org/documentation/runtime/environments/&quot;&gt;build / specify a custom image&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See the &lt;a href=&quot;https://beam.apache.org/documentation/runtime/sdk-harness-config/&quot;&gt;environment documentation page&lt;/a&gt; for more information on environment configuration.&lt;/p&gt;

&lt;h2 id=&quot;5-cross-language-pipelines&quot;&gt;5. Cross-language pipelines&lt;/h2&gt;

&lt;p&gt;As a next step, let’s read some data using Beam’s KafkaIO. Oh no! Turns out, there is no native Kafka connector in the Python API. No problem, we can use KafkaIO in from the Java SDK:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;beam&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam.transforms.window&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;window&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam.options.pipeline_options&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PipelineOptions&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;apache_beam.io.external.kafka&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ReadFromKafka&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WriteToKafka&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;run_pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PipelineOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Read from Kafka&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ReadFromKafka&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;bootstrap.servers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kafka_bootstrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                                           &lt;span class=&quot;s&quot;&gt;&amp;#39;auto.offset.reset&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;latest&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                                          &lt;span class=&quot;n&quot;&gt;topics&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;demo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Par with 1&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Window of 10 seconds&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;WindowInto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;FixedWindows&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Group by key&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GroupByKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Sum word counts&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;beam&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])))&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;Write to Kafka&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;WriteToKafka&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;producer_config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;bootstrap.servers&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kafka_bootstrap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
                                        &lt;span class=&quot;n&quot;&gt;topic&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;demo-output&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__name__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;run_pipeline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The essential pipeline logic hasn’t changed, but we have swapped out the simple &lt;code&gt;Create&lt;/code&gt; / &lt;code&gt;Print&lt;/code&gt; transforms for reading / writing to / from Kafka. Note that these transforms are not native Python transforms but so called &lt;strong&gt;external&lt;/strong&gt; transforms. External transforms are placeholders which get replaced by the actual transform when the pipeline is built.&lt;/p&gt;

&lt;p&gt;To understand what will happen when we run this pipeline, have a look at this image:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/portability/portability.png&quot; alt=&quot;Beam portability overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When we run the Python script, the pipeline is constructed. During this, a lookup to the &lt;code&gt;ExpansionService&lt;/code&gt; is performed to resolve &lt;code&gt;ReadFromKafka&lt;/code&gt; / &lt;code&gt;WriteToKafka&lt;/code&gt;. Once the pipeline has been assembled, it is submitted to the &lt;code&gt;JobService&lt;/code&gt; which also receives any required artifacts (e.g. Python libraries). The Runner then submits the pipeline against a Flink cluster.&lt;/p&gt;

&lt;p&gt;Native transforms like GroupByKey can be processed directly by Flink. Any language-specific code runs in a separate environment for the language. The environment contains the SDK Harness which is responsible for running the language-specific code.&lt;/p&gt;

&lt;p&gt;The good news is that you normally do not have to worry about this process. &lt;code&gt;FlinkRunner&lt;/code&gt;, as part of the Python SDK, abstracts away a lot of the complexity.&lt;/p&gt;

&lt;h2 id=&quot;6-reach-out-to-the-beam-community&quot;&gt;6. Reach out to the Beam community&lt;/h2&gt;

&lt;p&gt;That’s it! For more information, check out the &lt;a href=&quot;https://beam.apache.org/documentation/&quot;&gt;Beam documentation&lt;/a&gt;. Still stuck? Feel free to &lt;a href=&quot;https://beam.apache.org/community/contact-us/&quot;&gt;reach out to the Beam community&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Fri, 18 Sep 2020 16:05:33 +0200</pubDate>
        <link>https://maximilianmichels.com/2020/getting-started-with-beam-python/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2020/getting-started-with-beam-python/</guid>
        
        
        <category>apache</category>
        
        <category>beam</category>
        
        <category>python</category>
        
        <category>stream</category>
        
        <category>processing</category>
        
      </item>
    
    
    
      <item>
        <title>Apache Arrow: The Hidden Champion of Data Analytics</title>
        <description>&lt;!--excerpt.begin--&gt;

&lt;p&gt;In today’s open-source software stack you can find many indispensable dependencies in the form of software libraries. They are logging frameworks, testing frameworks, HTTP libraries, or code style checkers. But it doesn’t happen often that a new library emerges which changes the way we think about computing.
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;p&gt;One of such libraries in the data processing and data science space is &lt;a href=&quot;https://arrow.apache.org&quot;&gt;Apache Arrow&lt;/a&gt;. Arrow is used by open-source projects like Apache Parquet, Apache Spark, pandas, and many commercial or closed-source services. It provides the following functionality:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;In-memory computing&lt;/li&gt;
  &lt;li&gt;A standardized columnar storage format&lt;/li&gt;
  &lt;li&gt;An IPC and RPC framework for data exchange between processes and nodes respectively&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why is this such a big deal?&lt;/p&gt;

&lt;h2 id=&quot;in-memory-computing&quot;&gt;In-Memory Computing&lt;/h2&gt;

&lt;p&gt;Let’s look at how things worked before Arrow existed:&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/images/arrow/without_arrow.png&quot; alt=&quot;Data exchange without Arrow&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;We can see that in order for Spark to read data from a Parquet file, we needed to read and deserialize the data in the Parquet format. This requires us to make a full copy of the data by loading it into memory. First, we read the data into a memory buffer, then we use Parquet’s conversion methods to turn the data, e.g. a String or a number, into the representation of our programming language. This is necessary because Parquet represents a number differently from how the Python programming language represents it.&lt;/p&gt;

&lt;p&gt;This is a pretty big deal for performance for a number of reasons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We are copying the data and running conversion steps on it. The data is in a different format, we need to read all of it and convert it before doing any computation with the data.&lt;/li&gt;
  &lt;li&gt;The data we are loading has to fit into memory. Do you only have 8GB of RAM and your data is 10GB? You are out of luck!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now let’s look at how Apache Arrow improves this:&lt;/p&gt;
&lt;center&gt;
&lt;img src=&quot;/assets/images/arrow/with_arrow.png&quot; alt=&quot;Data exchange with Arrow&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;Instead of copying and converting the data, Arrow understands how to read and operate on the data directly. For this to work, the Arrow community defined a new file format alongside with operations which works directly on the serialized data. This data format can be read directly from disk without the need to load it into memory and convert / deserialize the data. Of course, parts of the data is still going to be loaded into RAM but your data does not have to fit into memory. Arrow uses memory-mapping of its files to load only as much data into memory as necessary and possible.&lt;/p&gt;

&lt;h2 id=&quot;standardized-column-storage-format&quot;&gt;Standardized Column Storage Format&lt;/h2&gt;

&lt;p&gt;The heart of Apache Arrow is its columnar data format. What does columnar data mean? In traditional file formats or databases, data is stored row-wise. For example, if we had a record with the fields &lt;code&gt;product&lt;/code&gt;, &lt;code&gt;quantity&lt;/code&gt;, and &lt;code&gt;price&lt;/code&gt;:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
  &lt;th&gt;Product&lt;/th&gt;
  &lt;th&gt;Quantity&lt;/th&gt;
  &lt;th&gt;Price&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;td&gt;Banana&lt;/td&gt;
  &lt;td&gt;3&lt;/td&gt;
  &lt;td&gt;1.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;td&gt;Apple&lt;/td&gt;
  &lt;td&gt;5&lt;/td&gt;
  &lt;td&gt;2.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;In row-wise storage the data would be stored on disk row by row. That makes a lot of sense. However, if you quickly want to sum up the total price of all the items, you would have to read all the records and extract the price column from them. Wouldn’t it be better if the data already came in a format that allowed to read the columns efficiently?&lt;/p&gt;

&lt;h3 id=&quot;enter-columnar-storage&quot;&gt;Enter columnar storage.&lt;/h3&gt;

&lt;p&gt;For columnar storage we arrange the data in columnar format. In our example this would look like this:&lt;/p&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
  &lt;th scope=&quot;row&quot;&gt;Product&lt;/th&gt;
  &lt;td&gt;Banana&lt;/td&gt;
  &lt;td&gt;Apple&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;th scope=&quot;row&quot;&gt;Quantity&lt;/th&gt;
  &lt;td&gt;3&lt;/td&gt;
  &lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
  &lt;th scope=&quot;row&quot;&gt;Price&lt;/th&gt;
  &lt;td&gt;1.8&lt;/td&gt;
  &lt;td&gt;2.5&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;If we store the data like this, we have all the column data in one place and can iterate over it efficiently. Not only is this more efficient in terms of extracting values but we can also take advantage of modern CPU architecture which applies the same operation (e.g. summation) on a continuous data segment in memory. This is also referred to as Single Instruction Multiple Data (SIMD). It is very efficient due to caching and pipelining at the processor level.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/arrow/simd.png&quot; alt=&quot;Taking advantage of Single Instruction Multiple Data&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;How much faster is this? The simpler answer: a lot faster! Here are some performance numbers from &lt;a href=&quot;https://www.dremio.com/apache-arrow-explained/&quot;&gt;Dremio&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;Parquet and C++: Reading data into Parquet from C++ at up to 4GB/s&lt;/li&gt;
    &lt;li&gt;Pandas: Reading into pandas up to 10GB/s&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;Clearly, the speedup depends on the application but there is no doubt that, besides its functional advantages, Arrow can provide a tremendous performance boost, to the point that it enables new applications which were not feasible before.&lt;/p&gt;

&lt;h2 id=&quot;supported-languages&quot;&gt;Supported languages&lt;/h2&gt;

&lt;p&gt;The following languages are supported by Apache Arrow:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;C++&lt;/li&gt;
  &lt;li&gt;C#&lt;/li&gt;
  &lt;li&gt;Go&lt;/li&gt;
  &lt;li&gt;Java&lt;/li&gt;
  &lt;li&gt;JavaScript&lt;/li&gt;
  &lt;li&gt;Rust&lt;/li&gt;
  &lt;li&gt;Python (through the C++ library)&lt;/li&gt;
  &lt;li&gt;Ruby (through the C++ library)&lt;/li&gt;
  &lt;li&gt;R (through the C++ library)&lt;/li&gt;
  &lt;li&gt;MATLAB (through the C++ library).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;not-just-a-more-efficient-file-format&quot;&gt;Not just a more efficient file format&lt;/h2&gt;

&lt;h3 id=&quot;ipc-inter-process-communication&quot;&gt;IPC (inter-process communication)&lt;/h3&gt;

&lt;p&gt;It is important to understand that Apache Arrow is not merely an efficient file format. The Arrow library also provides interfaces for communicating across processes or nodes. That means that processes, e.g. a Python and a Java process, can efficiently exchange data without copying it locally. Nodes in a computer network also benefit from this, while the data has to be transferred over the network, we only need to transfer the relevant columns from the data. In both cases, we don’t have to deserialize data because Arrow understands how to operate directly on the data.&lt;/p&gt;

&lt;p&gt;According to &lt;a href=&quot;https://www.dremio.com/apache-arrow-explained/&quot;&gt;Dremio&lt;/a&gt;, the following speedup was achieved in PySpark:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;IBM measured a 53x speedup in data processing by Python and Spark after adding support for Arrow in PySpark&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;rpc-remote-procedure-call&quot;&gt;RPC (remote procedure call)&lt;/h3&gt;

&lt;p&gt;Within arrow there is a project called &lt;a href=&quot;https://arrow.apache.org/blog/2019/10/13/introducing-arrow-flight/&quot;&gt;Flight&lt;/a&gt; which allows to easily build arrow-based data endpoints and interchange data between them. Flight is optimized in terms of parallel data access. It is possible to receive data from multiple endpoints in parallel and request data from a new endpoint while still reading from an endpoint. This highly parallel way of interacting with the services can provide a performance boost for network transfers.&lt;/p&gt;

&lt;p&gt;It was observed by Dremio in their &lt;a href=&quot;https://www.dremio.com/is-time-to-replace-odbc-jdbc/&quot;&gt;Arrow Flight connector&lt;/a&gt; that you could achieve a 20-50x better performance than ODBC over a TCP connection.&lt;/p&gt;

&lt;h2 id=&quot;whats-next-building-a-query-engine-on-top-of-arrow&quot;&gt;What’s next? Building a query engine on top of Arrow&lt;/h2&gt;

&lt;p&gt;As of now, to use Arrow you need to know how Arrow works and how the data is stored. Many projects such as &lt;a href=&quot;https://pandas.pydata.org/&quot;&gt;pandas&lt;/a&gt; have taken advantage of that. However, the missing piece is a query engine on top of Arrow capabilities which would allow users to easily query and process data stored in the Arrow format. The Arrow community is working on that.&lt;/p&gt;

&lt;h3 id=&quot;post-mortem&quot;&gt;Post Mortem&lt;/h3&gt;

&lt;p&gt;There is/was a &lt;a href=&quot;https://twitter.com/stadtlegende/status/1306253802153168896&quot;&gt;lively discussion on Twitter&lt;/a&gt; which brought up &lt;a href=&quot;https://github.com/cwida/duckdb&quot;&gt;DuckDB&lt;/a&gt; and &lt;a href=&quot;https://github.com/vaexio/vaex&quot;&gt;vaex&lt;/a&gt; as query engines built on top of Arrow. Also, it was mentioned that &lt;a href=&quot;https://github.com/apache/arrow/tree/master/rust/datafusion&quot;&gt;DataFusion&lt;/a&gt;, a Rust-based query engine, has been donated to Arrow.&lt;/p&gt;

&lt;p&gt;&lt;br /&gt;
&lt;small&gt;Images taken from the &lt;a href=&quot;https://arrow.apache.org/overview/&quot;&gt;Apache Arrow site&lt;/a&gt;.&lt;/small&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 15 Sep 2020 19:05:33 +0200</pubDate>
        <link>https://maximilianmichels.com/2020/apache-arrow-the-hidden-champion/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2020/apache-arrow-the-hidden-champion/</guid>
        
        
        <category>apache</category>
        
        <category>arrow</category>
        
        <category>python</category>
        
        <category>data</category>
        
        <category>frames</category>
        
        <category>in-memory</category>
        
        <category>spark</category>
        
      </item>
    
    
    
      <item>
        <title>10 Reasons for Choosing Apache Pulsar over Apache Kafka</title>
        <description>&lt;!--excerpt.begin--&gt;
&lt;p&gt;I’ve been taking a closer look at &lt;a href=&quot;https://pulsar.apache.org&quot;&gt;Apache Pulsar&lt;/a&gt; and how it relates to &lt;a href=&quot;https://kafka.apache.org&quot;&gt;Apache Kafka&lt;/a&gt;. In case you are curious, here are ten of my findings:
&lt;!--excerpt.end--&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar’s brokers are stateless. The state is kept in a separate storage layer (&lt;a href=&quot;https://bookkeeper.apache.org&quot;&gt;Apache BookKeeper&lt;/a&gt;). This means you can leverage a new broker without the need to re-partition existing data, which is required by Kafka.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar’s storage layer is organized into segments which are spread across all storage nodes. Segments can be written to the main storage or off-loaded to a different type of storage. This allows Pulsar to offer tiered storage which Kafka does not support yet.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;For replication, Pulsar uses a quorum-based algorithm, as opposed to a leader/follower-based approach in Kafka. The guarantees are the same, but the quorum approach tends to yield lower and more consistent latencies.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar includes support for multi-tenancy which allows multiple user groups to share the same cluster, either via access control, or in entirely different namespaces. In Kafka, this is still under discussion.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar offers full end-to-end encryption from the client to the storage nodes. Kafka currently does not have end-to-end encryption.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar speaks other protocols such as RabbitMQ, AMQP, or even Kafka (!) which makes it easy to integrate Pulsar with existing applications. Further, there is support for &lt;a href=&quot;https://prestodb.io/&quot;&gt;Presto&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar Functions is a way to do lightweight stream processing on top of Pulsar, conceptually similar to Kafka Streams. What I found interesting is that Pulsar’s functions are directly deployed on the broker nodes, whereas Kafka’s streams run as separate applications.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The Pulsar community has been very open about the limitations of Pulsar Functions, e.g. state management and DAG flows. In case Pulsar Functions doesn’t do it for you, there is an actively maintained &lt;a href=&quot;https://github.com/streamnative/pulsar-flink&quot;&gt;Pulsar &amp;lt;&amp;gt; ApacheFlink connector&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;It’s not all sunshine and rainbows: Pulsar requires two systems: Apache BookKeeper and Apache Zookeeper. Kafka just requires Zookeeper. More systems could increase the operational complexity. On the other hand, it’s also the reason why Pulsar provides additional flexibility.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Pulsar is not new. It was originally developed and used at Yahoo, later donated to the &lt;a href=&quot;https://apache.org&quot;&gt;Apache Software Foundation&lt;/a&gt; in 2016. It’s used by Tencent, Splunk, and many others at large scale.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Obviously, this is not a full comparison of Apache Pulsar and Apache Kafka, but rather a compilation of the things I was surprised to find out about Pulsar, coming from the Kafka landscape.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/stadtlegende/status/1300461546578087936&quot;&gt;Join the conversation on Twitter&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Mon, 31 Aug 2020 09:05:33 +0200</pubDate>
        <link>https://maximilianmichels.com/2020/apache-pulsar-vs-apache-kafka/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2020/apache-pulsar-vs-apache-kafka/</guid>
        
        
        <category>apache</category>
        
        <category>pulsar</category>
        
        <category>kafka</category>
        
        <category>flink</category>
        
      </item>
    
    
    
      <item>
        <title>How &lt;br&gt;Apache Beam&lt;br&gt; Runs on Top of &lt;br&gt;Apache Flink</title>
        <description>&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;/h3&gt;

&lt;!--excerpt.begin--&gt;

&lt;p&gt;&lt;a href=&quot;https://flink.apache.org/&quot;&gt;Apache Flink&lt;/a&gt; and &lt;a href=&quot;https://beam.apache.org/&quot;&gt;Apache Beam&lt;/a&gt; are open-source frameworks for parallel, distributed data processing at scale. Unlike Flink, Beam does not come with a full-blown execution engine of its own but plugs into other execution engines, such as Apache Flink, Apache Spark, or Google Cloud Dataflow. In this blog post we discuss the reasons to use Flink together with Beam for your batch and stream processing needs. We also take a closer look at how Beam works with Flink to provide an idea of the technical aspects of running Beam pipelines with Flink. We hope you find some useful information on how and why the two frameworks can be utilized in combination. For more information, you can refer to the corresponding &lt;a href=&quot;https://beam.apache.org/documentation/runners/flink/&quot;&gt;documentation&lt;/a&gt; on the Beam website or contact the community through the &lt;a href=&quot;https://beam.apache.org/community/contact-us/&quot;&gt;Beam mailing list&lt;/a&gt;.&lt;/p&gt;

&lt;!--excerpt.end--&gt;

&lt;h1 id=&quot;what-is-apache-beam&quot;&gt;What is Apache Beam&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://beam.apache.org/&quot;&gt;Apache Beam&lt;/a&gt; is an open-source, unified model for defining batch and streaming data-parallel processing pipelines. It is unified in the sense that you use a single API, in contrast to using a separate API for batch and streaming like it is the case in Flink. Beam was originally developed by Google which released it in 2014 as the Cloud Dataflow SDK. In 2016, it was donated to &lt;a href=&quot;https://www.apache.org/&quot;&gt;the Apache Software Foundation&lt;/a&gt; with the name of Beam. It has been developed by the open-source community ever since. With Apache Beam, developers can write data processing jobs, also known as pipelines, in multiple languages, e.g. Java, Python, Go, SQL. A pipeline is then executed by one of Beam’s Runners. A Runner is responsible for translating Beam pipelines such that they can run on an execution engine. Every supported execution engine has a Runner. The following Runners are available: Apache Flink, Apache Spark, Apache Samza, Hazelcast Jet, Google Cloud Dataflow, and others.&lt;/p&gt;

&lt;p&gt;The execution model, as well as the API of Apache Beam, are similar to Flink’s. Both frameworks are inspired by the &lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//archive/mapreduce-osdi04.pdf&quot;&gt;MapReduce&lt;/a&gt;, &lt;a href=&quot;https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/41378.pdf&quot;&gt;MillWheel&lt;/a&gt;, and &lt;a href=&quot;https://research.google/pubs/pub43864/&quot;&gt;Dataflow&lt;/a&gt; papers. Like Flink, Beam is designed for parallel, distributed data processing. Both have similar transformations, support for windowing, event/processing time, watermarks, timers, triggers, and much more. However, Beam not being a full runtime focuses on providing the framework for building portable, multi-language batch and stream processing pipelines such that they can be run across several execution engines. The idea is that you write your pipeline once and feed it with either batch or streaming data. When you run it, you just pick one of the supported backends to execute. A large integration test suite in Beam called “ValidatesRunner” ensures that the results will be the same, regardless of which backend you choose for the execution.&lt;/p&gt;

&lt;p&gt;One of the most exciting developments in the Beam technology is the framework’s support for multiple programming languages including Java, Python, Go, Scala and SQL. Essentially, developers can write their applications in a programming language of their choice. Beam, with the help of the Runners, translates the program to one of the execution engines, as shown in the diagram below.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/beam-on-flink/flink-runner-beam-beam-vision.png&quot; width=&quot;600px&quot; alt=&quot;The vision of Apache Beam&quot; /&gt;
&lt;/center&gt;

&lt;h1 id=&quot;reasons-to-use-beam-with-flink&quot;&gt;Reasons to use Beam with Flink&lt;/h1&gt;

&lt;p&gt;Why would you want to use Beam with Flink instead of directly using Flink? Ultimately, Beam and Flink complement each other and provide additional value to the user. The main reasons for using Beam with Flink are the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Beam provides a unified API for both batch and streaming scenarios.&lt;/li&gt;
  &lt;li&gt;Beam comes with native support for different programming languages, like Python or Go with all their libraries like Numpy, Pandas, Tensorflow, or TFX.&lt;/li&gt;
  &lt;li&gt;You get the power of Apache Flink like its exactly-once semantics, strong memory management and robustness.&lt;/li&gt;
  &lt;li&gt;Beam programs run on your existing Flink infrastructure or infrastructure for other supported Runners, like Spark or Google Cloud Dataflow.&lt;/li&gt;
  &lt;li&gt;You get additional features like side inputs and cross-language pipelines that are not supported natively in Flink but only supported when using Beam with Flink.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;the-flink-runner-in-beam&quot;&gt;The Flink Runner in Beam&lt;/h1&gt;

&lt;p&gt;The Flink Runner in Beam translates Beam pipelines into Flink jobs. The translation can be parameterized using Beam’s pipeline options which are parameters for settings like configuring the job name, parallelism, checkpointing, or metrics reporting.&lt;/p&gt;

&lt;p&gt;If you are familiar with a DataSet or a DataStream, you will have no problems understanding what a PCollection is. PCollection stands for parallel collection in Beam and is exactly what DataSet/DataStream would be in Flink. Due to Beam’s unified API we only have one type of results of transformation: PCollection.&lt;/p&gt;

&lt;p&gt;Beam pipelines are composed of transforms. Transforms are like operators in Flink and come in two flavors: primitive and composite transforms. The beauty of all this is that Beam only comes with a small set of primitive transforms which are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;Source&lt;/code&gt; (for loading data)&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;ParDo&lt;/code&gt; (think of a flat map operator on steroids)&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;GroupByKey&lt;/code&gt; (think of keyBy() in Flink)&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;AssignWindows&lt;/code&gt; (windows can be assigned at any point in time in Beam)&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;Flatten&lt;/code&gt; (like a union() operation in Flink)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Composite transforms are built by combining the above primitive transforms. For example, &lt;code&gt;Combine = GroupByKey + ParDo&lt;/code&gt;.&lt;/p&gt;

&lt;h1 id=&quot;flink-runner-internals&quot;&gt;Flink Runner Internals&lt;/h1&gt;

&lt;p&gt;Although using the Flink Runner in Beam has no prerequisite to understanding its internals, we provide more details of how the Flink runner works in Beam to share knowledge of how the two frameworks can integrate and work together to provide state-of-the-art streaming data pipelines.&lt;/p&gt;

&lt;p&gt;The Flink Runner has two translation paths. Depending on whether we execute in batch or streaming mode, the Runner either translates into Flink’s DataSet or into Flink’s DataStream API. Since multi-language support has been added to Beam, another two translation paths have been added. To summarize the four modes:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;The Classic Flink Runner for batch jobs:&lt;/strong&gt; Executes batch Java pipelines&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The Classic Flink Runner for streaming jobs:&lt;/strong&gt; Executes streaming Java pipelines&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The Portable Flink Runner for batch jobs:&lt;/strong&gt; Executes Java as well as Python, Go and other supported SDK pipelines for batch scenarios&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;The Portable Flink Runner for streaming jobs:&lt;/strong&gt; Executes Java as well as Python, Go and other supported SDK pipelines for streaming scenarios&lt;/li&gt;
&lt;/ol&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/beam-on-flink/flink-runner-beam-runner-translation-paths.png&quot; width=&quot;300px&quot; alt=&quot;The 4 translation paths in the Beam's Flink Runner&quot; /&gt;
&lt;/center&gt;

&lt;h2 id=&quot;the-classic-flink-runner-in-beam&quot;&gt;The “Classic” Flink Runner in Beam&lt;/h2&gt;

&lt;p&gt;The classic Flink Runner was the initial version of the Runner, hence the “classic” name. Beam pipelines are represented as a graph in Java which is composed of the aforementioned composite and primitive transforms. Beam provides translators which traverse the graph in topological order. Topological order means that we start from all the sources first as we iterate through the graph. Presented with a transform from the graph, the Flink Runner generates the API calls as you would normally when writing a Flink job.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/beam-on-flink/classic-flink-runner-beam.png&quot; width=&quot;600px&quot; alt=&quot;The Classic Flink Runner in Beam&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;While Beam and Flink share very similar concepts, there are enough differences between the two frameworks that make Beam pipelines impossible to be translated 1:1 into a Flink program. In the following sections, we will present the key differences:&lt;/p&gt;

&lt;h3 id=&quot;serializers-vs-coders&quot;&gt;Serializers vs Coders&lt;/h3&gt;

&lt;p&gt;When data is transferred over the wire in Flink, it has to be turned into bytes. This is done with the help of serializers. Flink has a type system to instantiate the correct coder for a given type, e.g. &lt;code&gt;StringTypeSerializer&lt;/code&gt; for a String. Apache Beam also has its own type system which is similar to Flink’s but uses slightly different interfaces. Serializers are called Coders in Beam. In order to make a Beam Coder run in Flink, we have to make the two serializer types compatible. This is done by creating a special Flink type information that looks like the one in Flink but calls the appropriate Beam coder. That way, we can use Beam’s coders although we are executing the Beam job with Flink. Flink operators expect a TypeInformation, e.g. &lt;code&gt;StringTypeInformation&lt;/code&gt;, for which we use a &lt;code&gt;CoderTypeInformation&lt;/code&gt; in Beam. The type information returns the serializer for which we return a &lt;code&gt;CoderTypeSerializer&lt;/code&gt;, which calls the underlying Beam Coder.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/beam-on-flink/flink-runner-beam-serializers-coders.png&quot; width=&quot;300px&quot; alt=&quot;Serializers vs Coders&quot; /&gt;
&lt;/center&gt;

&lt;h3 id=&quot;read&quot;&gt;Read&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;Read&lt;/code&gt; transform provides a way to read data into your pipeline in Beam. The Read transform is supported by two wrappers in Beam, the &lt;code&gt;SourceInputFormat&lt;/code&gt; for batch processing and the &lt;code&gt;UnboundedSourceWrapper&lt;/code&gt; for stream processing.&lt;/p&gt;

&lt;h3 id=&quot;pardo&quot;&gt;ParDo&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;ParDo&lt;/code&gt; is the swiss army knife of Beam and can be compared to a &lt;code&gt;RichFlatMapFunction&lt;/code&gt; in Flink with additional features such as &lt;code&gt;SideInputs&lt;/code&gt;, &lt;code&gt;SideOutputs&lt;/code&gt;, State and Timers. &lt;code&gt;ParDo&lt;/code&gt; is essentially translated by the Flink runner using the &lt;code&gt;FlinkDoFnFunction&lt;/code&gt; for batch processing or the &lt;code&gt;FlinkStatefulDoFnFunction&lt;/code&gt;, while for streaming scenarios the translation is executed with the &lt;code&gt;DoFnOperator&lt;/code&gt; that takes care of checkpointing and buffering of data during checkpoints, watermark emissions and maintenance of state and timers. This is all executed by Beam’s interface, called the &lt;code&gt;DoFnRunner&lt;/code&gt;, that encapsulates Beam-specific execution logic, like retrieving state, executing state and timers, or reporting metrics.&lt;/p&gt;

&lt;h3 id=&quot;side-inputs&quot;&gt;Side Inputs&lt;/h3&gt;

&lt;p&gt;In addition to the main input, ParDo transforms can have a number of side inputs. A side input can be a static set of data that you want to have available at all parallel instances. However, it is more flexible than that. You can have keyed and even windowed side input which updates based on the window size. This is a very powerful concept which does not exist in Flink but is added on top of Flink using Beam.&lt;/p&gt;

&lt;h3 id=&quot;assignwindows&quot;&gt;AssignWindows&lt;/h3&gt;

&lt;p&gt;In Flink, windows are assigned by the &lt;code&gt;WindowOperator&lt;/code&gt; when you use the &lt;code&gt;window()&lt;/code&gt; in the API. In Beam, windows can be assigned at any point in time. Any element is implicitly part of a window. If no window is assigned explicitly, the element is part of the &lt;code&gt;GlobalWindow&lt;/code&gt;. Window information is stored for each element in a wrapper called &lt;code&gt;WindowedValue&lt;/code&gt;. The window information is only used once we issue a &lt;code&gt;GroupByKey&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;groupbykey&quot;&gt;GroupByKey&lt;/h3&gt;

&lt;p&gt;Most of the time it is useful to partition the data by a key. In Flink, this is done via the &lt;code&gt;keyBy()&lt;/code&gt; API call. In Beam the &lt;code&gt;GroupByKey&lt;/code&gt; transform can only be applied if the input is of the form &lt;code&gt;KV&amp;lt;Key, Value&amp;gt;&lt;/code&gt;. Unlike Flink where the key can even be nested inside the data, Beam enforces the key to always be explicit. The &lt;code&gt;GroupByKey&lt;/code&gt; transform then groups the data by key and by window which is similar to what &lt;code&gt;keyBy(..).window(..)&lt;/code&gt; would give us in Flink. Beam has its own set of libraries to do that because Beam has its own set of window functions and triggers. Essentially, GroupByKey is very similar to what the WindowOperator does in Flink.&lt;/p&gt;

&lt;h3 id=&quot;flatten&quot;&gt;Flatten&lt;/h3&gt;

&lt;p&gt;The Flatten operator takes multiple DataSet/DataStreams, called P[arallel]Collections in Beam, and combines them into one collection. This is equivalent to Flink’s &lt;code&gt;union()&lt;/code&gt; operation.&lt;/p&gt;

&lt;h2 id=&quot;the-portable-flink-runner-in-beam&quot;&gt;The “Portable” Flink Runner in Beam&lt;/h2&gt;

&lt;p&gt;The portable Flink Runner in Beam is the evolution of the classic Runner. Classic Runners are tied to the JVM ecosystem, but the Beam community wanted to move past this and also execute Python, Go and other languages. This adds another dimension to Beam in terms of portability because, like previously mentioned, Beam already had portability across execution engines. It was necessary to change the translation logic of the Runner to be able to support language portability.&lt;/p&gt;

&lt;p&gt;There are two important building blocks for portable Runners:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A common pipeline format across all the languages: The Runner API&lt;/li&gt;
  &lt;li&gt;A common interface during execution for the communication between the Runner and the code written in any language: The Fn API&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Runner API provides a universal representation of the pipeline as Protobuf which contains the transforms, types, and user code. Protobuf was chosen as the format because every language has libraries available for it. Similarly, for the execution part, Beam introduced the Fn API interface to handle the communication between the Runner/execution engine and the user code that may be written in a different language and executes in a different process. Fn API is pronounced “fun API”, you may guess why.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/beam-on-flink/flink-runner-beam-language-portability.png&quot; width=&quot;600px&quot; alt=&quot;Language Portability in Apache Beam&quot; /&gt;
&lt;/center&gt;

&lt;h2 id=&quot;how-are-beam-programs-translated-in-language-portability&quot;&gt;How Are Beam Programs Translated In Language Portability?&lt;/h2&gt;

&lt;p&gt;Users write their Beam pipelines in one language, but they may get executed in an environment based on a completely different language. How does that work? To explain that, let’s follow the lifecycle of a pipeline. Let’s suppose we use the Python SDK to write the pipeline. Before submitting the pipeline via the Job API to Beam’s JobServer, Beam would convert it to the Runner API, the language-agnostic format we described before. The JobServer is also a Beam component that handles the staging of the required dependencies during execution. The JobServer will then kick-off the translation which is similar to the classic Runner. However, an important change is the so-called &lt;code&gt;ExecutableStage&lt;/code&gt; transform. It is essentially a ParDo transform that we already know but designed for holding language-dependent code. Beam tries to combine as many of these transforms into one “executable stage”. The result again is a Flink program which is then sent to the Flink cluster and executed there. The major difference compared to the classic Runner is that during execution we will start &lt;em&gt;environments&lt;/em&gt; to execute the aforementioned &lt;em&gt;ExecutableStages&lt;/em&gt;. The following environments are available:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Docker-based (the default)&lt;/li&gt;
  &lt;li&gt;Process-based (a simple process is started)&lt;/li&gt;
  &lt;li&gt;Externally-provided (K8s or other schedulers)&lt;/li&gt;
  &lt;li&gt;Embedded (intended for testing and only works with Java)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Environments hold the &lt;em&gt;SDK Harness&lt;/em&gt; which is the code that handles the execution and the communication with the Runner over the Fn API. For example, when Flink executes Python code, it sends the data to the Python environment containing the Python SDK Harness. Sending data to an external process involves a minor overhead which we have measured to be 5-10% slower than the classic Java pipelines. However, Beam uses a fusion of transforms to execute as many transforms as possible in the same environment which share the same input or output. That’s why in real-world scenarios the overhead could be much lower.&lt;/p&gt;

&lt;center&gt;
&lt;img src=&quot;/assets/images/beam-on-flink/flink-runner-beam-language-portability-architecture.png&quot; width=&quot;600px&quot; alt=&quot;Language Portability Architecture in beam&quot; /&gt;
&lt;/center&gt;

&lt;p&gt;Environments can be present for many languages. This opens up an entirely new type of pipelines: cross-language pipelines. In cross-language pipelines we can combine transforms of two or more languages, e.g. a machine learning pipeline with the feature generation written in Java and the learning written in Python. All this can be run on top of Flink.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Using Apache Beam with Apache Flink combines  (a.) the power of Flink with (b.) the flexibility of Beam. All it takes to run Beam is a Flink cluster, which you may already have. Apache Beam’s fully-fledged Python API is probably the most compelling argument for using Beam with Flink, but the unified API which allows to “write-once” and “execute-anywhere” is also very appealing to Beam users. On top of this, features like side inputs and a rich connector ecosystem are also reasons why people like Beam.&lt;/p&gt;

&lt;p&gt;With the introduction of schemas, a new format for handling type information, Beam is heading in a similar direction as Flink with its type system which is essential for the Table API or SQL. Speaking of, the next Flink release will include a Python version of the Table API which is based on the language portability of Beam. Looking ahead, the Beam community plans to extend the support for interactive programs like notebooks. TFX, which is built with Beam, is a very powerful way to solve many problems around training and validating machine learning models.&lt;/p&gt;

&lt;p&gt;For many years, Beam and Flink have inspired and learned from each other. With the Python support being based on Beam in Flink, they only seem to come closer to each other. That’s all the better for the community, and also users have more options and functionality to choose from.&lt;/p&gt;

&lt;h4 id=&quot;this-blog-post-is-co-authored-by-markos-sfikas-from-ververica-its-a-summary-of-the-talk-beam-on-flink-how-does-it-actually-work-which-i-gave-at-flinkforward-berlin-2019-it-has-also-been-featured-on-the-flink-blog&quot;&gt;This blog post is co-authored by Markos Sfikas from Ververica. It’s a summary of the talk &lt;a href=&quot;https://www.youtube.com/watch?v=hxHGLrshnCY&quot;&gt;“Beam on Flink: How Does It Actually Work?”&lt;/a&gt; which I gave at FlinkForward Berlin 2019. It has also been featured on the &lt;a href=&quot;https://flink.apache.org/ecosystem/2020/02/22/apache-beam-how-beam-runs-on-top-of-flink.html&quot;&gt;Flink blog&lt;/a&gt;.&lt;/h4&gt;
</description>
        <pubDate>Sat, 22 Feb 2020 08:05:33 +0100</pubDate>
        <link>https://maximilianmichels.com/2020/how-apache-beam-runs-on-top-of-apache-flink/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2020/how-apache-beam-runs-on-top-of-apache-flink/</guid>
        
        
        <category>apache</category>
        
        <category>beam</category>
        
        <category>flink</category>
        
      </item>
    
    
    
      <item>
        <title>The CAP Theorem's Common Misconception</title>
        <description>&lt;p&gt;A couple of days ago &lt;a href=&quot;https://twitter.com/stadtlegende/status/1019971194018287616&quot;&gt;I tweeted about the CAP theorem&lt;/a&gt; which sparked some interest and a small conversation on Twitter. Since tweets tend to disappear in the void pretty quickly, I thought I also put this here:&lt;/p&gt;

&lt;h2 id=&quot;the-misconception-around-the-cap-theorem&quot;&gt;The Misconception around the CAP Theorem&lt;/h2&gt;

&lt;p&gt;The CAP theorem in distributed systems states that you cannot satisfy more than two of these three properties:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Consistency&lt;/li&gt;
  &lt;li&gt;Availability&lt;/li&gt;
  &lt;li&gt;Partition Tolerance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here’s what’s commonly misunderstood about the CAP theorem:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Being Partition Tolerant or not is not really a choice. In distributed systems, partitions may occur at any time. It’s more of a choice what to give up during a network partition: Consistency or Availability.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Giving up Availability implies a part of your system will become unresponsive or return an error during a network partition.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Giving up Consistency implies your system might return stale data (=dirty reads) because data was written to some nodes but not yet to all due to a network partition.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Consistency according to CAP is Linearizability – not what the ‘C’ in ACID means. Linearizability enforces a linear order to operations, e.g. read(key) should return the latest written value of key.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Consistency in A[C]ID is ensured through Serializability which is a mechanism to ensure concurrent transactions in databases can be split up into multiple serial executions. No strict order is required.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Whether a system is actually CP or CA is often very hard to tell. It depends on the configuration of the system, e.g. number of replicas, consensus algorithms, quorum sizes, bugs, etc.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The CAP theorem is a starting point for characterizing systems, but to properly understand guarantees of distributed systems, you have to dive deeper. Here’s an excellent article on this by &lt;a href=&quot;https://twitter.com/martinkl&quot;&gt;@martinkl&lt;/a&gt;: &lt;a href=&quot;https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html&quot;&gt;martin.kleppmann.com/2015/05/11/ple…&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;hr /&gt;

&lt;p&gt;Hope you found this useful. Let me know on Twitter if you have any remarks.&lt;/p&gt;
</description>
        <pubDate>Thu, 19 Jul 2018 15:10:12 +0200</pubDate>
        <link>https://maximilianmichels.com/2018/cap-theorem-common-misconception/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2018/cap-theorem-common-misconception/</guid>
        
        
        <category>cap</category>
        
        <category>theorem</category>
        
        <category>twitter</category>
        
      </item>
    
    
    
      <item>
        <title>Who Is Behind Maven Central?</title>
        <description>&lt;p&gt;Ever wondered who or what is behind the central repository which is used to download the dependencies in your Maven / Gradle / SBT builds? Did you specify the repository URL in your build file? You didn’t?&lt;/p&gt;

&lt;p&gt;The actual URL of the repository is
&lt;a href=&quot;http://repo1.maven.org/maven2&quot;&gt;http://repo1.maven.org/maven2&lt;/a&gt;.
You can browse all the artifacts by package name if you click the link.&lt;/p&gt;

&lt;p&gt;This URL is hardcoded inside Maven and is used to lookup and retrieve build artifacts.&lt;/p&gt;

&lt;p&gt;In fact, when you build Maven
itself, this URL is used to retrieve Maven’s dependencies from Maven Central (crazy,
no?). Why? Because Maven is built with…Maven :)&lt;/p&gt;

&lt;p&gt;Here is a snippet from
Maven’s bootstrap code for constructing the initial Maven version
which is then used to build Maven itself:&lt;/p&gt;

&lt;p&gt;Hardcoded URL from &lt;a href=&quot;https://github.com/apache/maven/blob/c7761703c8f2d57df5de26d6619fd4974964fbaf/maven-mboot2/src/main/java/download/ArtifactDownloader.java#L35&quot;&gt;ArtifactDownloader&lt;/a&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REPO_URL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;http://repo1.maven.org/maven2&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Note that this bootstrap process is pretty common in the compiler domain where you want to write the compiler itself in the language for which you build the compiler. Likewise, the authors of Maven wanted to use Maven to build…Maven.&lt;/p&gt;

&lt;p&gt;The author already had some doubts whether hardcoding the URL would be a good idea and, thus, commented in the same file:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// TODO: use super POM?&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Repository&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;repository&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;REPO_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;LAYOUT_DEFAULT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;In fact, the Maven super POM sets the Maven Central URL.
If you haven’t worked with Maven, the &lt;code&gt;pom.xml&lt;/code&gt; (POM) is the build file
where you define the dependencies and properties of your project.
When you define your &lt;code&gt;pom.xml&lt;/code&gt;, by default, you inherit from the
&lt;a href=&quot;https://github.com/apache/maven/blob/13adc1bc2b6d9fc3a62ec2389996726c2edce4d8/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml#L30&quot;&gt;super pom&lt;/a&gt; which
defines the central repository in the &lt;code&gt;&amp;lt;repositories&amp;gt;&lt;/code&gt; section:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-xml&quot; data-lang=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;repositories&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;repository&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;central&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;name&amp;gt;&lt;/span&gt;Central Repository&lt;span class=&quot;nt&quot;&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;url&amp;gt;&lt;/span&gt;https://repo.maven.apache.org/maven2&lt;span class=&quot;nt&quot;&gt;&amp;lt;/url&amp;gt;&lt;/span&gt;
      ...
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/repository&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/repositories&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, it looks like it is not possible to go without the Maven Central repository because Maven contains code which checks if Maven Central is defined as a repository and, if not, re-adds it:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;definedRepositories&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RepositorySystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DEFAULT_REMOTE_REPO_ID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addRemoteRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;repositorySystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;createDefaultRemoteRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MavenExecutionRequestPopulationException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&amp;quot;Cannot create default remote repository.&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Taken from &lt;a href=&quot;https://github.com/apache/maven/blob/eb6b212b567c287734a2dbbef3c113fe650f1def/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulator.java#L121&quot;&gt;DefaultMavenExecutionRequestPopulator.java&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And indeed, the above method &lt;a href=&quot;https://github.com/apache/maven/blob/eb6b212b567c287734a2dbbef3c113fe650f1def/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java#L575&quot;&gt;&lt;code&gt;createDefaultRemoteRepository&lt;/code&gt;&lt;/a&gt; uses the default central repository URL:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArtifactRepository&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createDefaultRemoteRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MavenExecutionRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;throws&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Exception&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;createRepository&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RepositorySystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DEFAULT_REMOTE_REPO_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;RepositorySystem&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DEFAULT_REMOTE_REPO_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArtifactRepositoryPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;UPDATE_POLICY_DAILY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArtifactRepositoryPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;UPDATE_POLICY_DAILY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ArtifactRepositoryPolicy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;CHECKSUM_POLICY_WARN&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;&lt;code&gt;DEFAULT_REMOTE_REPO_URL&lt;/code&gt; is stored in the
&lt;a href=&quot;https://github.com/apache/maven/blob/eb6b212b567c287734a2dbbef3c113fe650f1def/maven-core/src/main/java/org/apache/maven/repository/RepositorySystem.java#L55&quot;&gt;RepositorySystem&lt;/a&gt; class:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-java&quot; data-lang=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DEFAULT_REMOTE_REPO_URL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;https://repo.maven.apache.org/maven2&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;So you can add your own repositories through the &lt;code&gt;&amp;lt;repository&amp;gt;&lt;/code&gt; XML tag but
you can’t get rid of the default. That’s interesting.&lt;/p&gt;

&lt;p&gt;Wait, now the URL
is &lt;code&gt;https://repo.maven.apache.org/maven2/&lt;/code&gt;?!&lt;/p&gt;

&lt;p&gt;What is going on here?&lt;/p&gt;

&lt;p&gt;Well, the truth is that Maven Central is
a &lt;a href=&quot;https://en.wikipedia.org/wiki/Content_delivery_network&quot;&gt;CDN&lt;/a&gt;. A CDN is
basically a set of servers which distribute data (e.g. web pages, videos, Maven
artifacts, etc.) in such a way that the data is reliably and quickly accessible
throughout the internet.&lt;/p&gt;

&lt;p&gt;Who operates the CDN? Surprisingly, this is a service of a
company called &lt;a href=&quot;http://www.sonatype.com&quot;&gt;Sonatype Inc&lt;/a&gt;. Sonatype offers commercial
services for open-source software with products related to repositories,
continuous integration, and security. Their non-commercial branch
is &lt;a href=&quot;http://sonatype.org&quot;&gt;sonatype.org&lt;/a&gt; which gives back some of their services
to open-source projects. One of these services is Maven Central.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;http://central.sonatype.org/pages/producers.html&quot;&gt;Maven Central website&lt;/a&gt; lists “Producers” who publish artifacts to Maven Central. The following organizations are currently “Producers”:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Apache&lt;/li&gt;
  &lt;li&gt;Atlassian&lt;/li&gt;
  &lt;li&gt;eXo Platform&lt;/li&gt;
  &lt;li&gt;JBoss/RedHat&lt;/li&gt;
  &lt;li&gt;Liferay&lt;/li&gt;
  &lt;li&gt;Oracle / java.net&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we discovered, the default Maven Central URL has been changed from &lt;code&gt;http://repo1.maven.org/maven2&lt;/code&gt; to &lt;code&gt;https://repo.maven.apache.org/maven2/&lt;/code&gt;.
Keep in mind that &lt;code&gt;maven.org&lt;/code&gt; is a domain owned by Sonatype, as opposed to &lt;code&gt;apache.org&lt;/code&gt; which is owned by the Apache Software Foundation.&lt;/p&gt;

&lt;p&gt;Maven Central is a crucial component for Apache projects. As we have learned, Apache projects publish their artifacts on Maven Central and almost all of their dependencies are hosted on Maven Central as well.&lt;/p&gt;

&lt;p&gt;Some &lt;a href=&quot;https://search.maven.org/#stats&quot;&gt;stats&lt;/a&gt; of the central repository:&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Total number of artifacts indexed (GAV):&lt;/td&gt;
      &lt;td&gt;2,426,748&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Total number of unique artifacts indexed (GA):&lt;/td&gt;
      &lt;td&gt;215,031&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;That’s a lot of artifacts. If one day, the central repository breaks for
whatever reason, developers would be in for a treat :)&lt;/p&gt;

&lt;p&gt;Luckily, thanks to the repository URL now defaulting to
&lt;code&gt;repo.maven.apache.org&lt;/code&gt;, we have the Apache Software Foundation to completely takeover any traffic in case the Sonatype CDN shut down. And I’m assuming they also have a copy of the artifacts.&lt;/p&gt;

&lt;p&gt;Phew. So we are good after all.&lt;/p&gt;

&lt;video width=&quot;320&quot; height=&quot;240&quot; autoplay=&quot;&quot; loop=&quot;&quot;&gt;
  &lt;source src=&quot;/assets/gifs/phew.mp4&quot; type=&quot;video/mp4&quot; /&gt;
Your browser does not support the video tag.
&lt;/video&gt;

&lt;p&gt;How do other build systems serve their build dependencies? Is the situation any different there? Not really. Python build tools, for instance, use &lt;a href=&quot;http://pypi.org&quot;&gt;PyPi&lt;/a&gt; which is also backed by a central repository.
Ruby Gemfiles use &lt;a href=&quot;http://RubyGems.org&quot;&gt;RubyGems&lt;/a&gt;.
C/C++ build tools typically assume the dependencies have already been installed, e.g. via the package manager of the operating system. Of course the package manager also accesses central repositories. I have yet to find out who runs all these repositories :)&lt;/p&gt;

&lt;p&gt;Thanks for reading this post. It was fun to learn about the central repository that we mostly take for granted. Thank you Sonatype for your service!&lt;/p&gt;

&lt;p&gt;If you don’t know Maven, it’s a a great build system which powers a lot of open-source projects. Check it out on &lt;a href=&quot;https://github.com/apache/maven/&quot;&gt;GitHub&lt;/a&gt;.
Or check out the
&lt;a href=&quot;https://maven.apache.org/guides/getting-started/maven-in-five-minutes.html&quot;&gt;The 5 Minute Guide to Maven&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;em&gt;EDIT&lt;/em&gt;: &lt;a href=&quot;https://twitter.com/rfscholte/status/948877167542394881&quot;&gt;As pointed out by Robert Scholte&lt;/a&gt;,
there are two Maven Central mirrors listed on the &lt;a href=&quot;http://maven.apache.org/repository/index.html&quot;&gt;maven.org Central Repository page&lt;/a&gt;.
One at &lt;a href=&quot;http://maven.ibiblio.org/maven2/&quot;&gt;ibiblio.org&lt;/a&gt;, the other hosted by &lt;a href=&quot;https://maven-central.storage.googleapis.com&quot;&gt;Google&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So we are really good after all :)&lt;/p&gt;
</description>
        <pubDate>Fri, 29 Dec 2017 11:15:14 +0100</pubDate>
        <link>https://maximilianmichels.com/2017/who-is-behind-maven-central/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2017/who-is-behind-maven-central/</guid>
        
        
        <category>apache</category>
        
      </item>
    
    
    
      <item>
        <title>An Introduction to Apache Software — What you need to know</title>
        <description>&lt;h4 id=&quot;a-revised-version-of-this-post-has-been-published-on-the-blog-of-the-apache-software-foundation&quot;&gt;&lt;a href=&quot;https://blogs.apache.org/foundation/entry/success-at-apache-what-you&quot;&gt;A revised version of this post has been published on the blog of the Apache Software Foundation&lt;/a&gt;.&lt;/h4&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;!--excerpt.begin--&gt;

&lt;p&gt;If you’re reading this post, you have already been using Apache software. The Apache web server is used by about every second web page on the WWW, including this website. You could say, Apache software runs the WWW. But it doesn’t stop there. Apache is more than a web server. Apache software also runs on mobile devices. Apache software is part of enterprise and banking software. Apache software is literally everywhere in today’s software world.&lt;/p&gt;

&lt;!--excerpt.end--&gt;

&lt;p&gt;Apache has become a powerful brand and a philosophy of software development which remains unmatched in the world of open-source. Although the Apache© trademark is a known term even among the less tech-savvy people, many people struggle to define what Apache software really is about, and what role it plays for today’s software development and businesses.&lt;/p&gt;

&lt;p&gt;In the last years I’ve learned a lot about Apache through my work on &lt;a href=&quot;http://flink.apache.org&quot;&gt;Apache Flink&lt;/a&gt; and &lt;a href=&quot;http://beam.apache.org&quot;&gt;Apache Beam&lt;/a&gt; with &lt;a href=&quot;http://data-artisans.com&quot;&gt;Data Artisans&lt;/a&gt;. In this post I present some of the things I learned by giving an overview of the Apache Software Foundation and its history. Moreover, I want to show how the “Apache way” of software development shaped the open-source software development as it is today.&lt;/p&gt;

&lt;h2 id=&quot;the-history-of-the-foundation&quot;&gt;The History of the Foundation&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/feather_old.svg&quot; style=&quot;width:175px;margin-right:15px;float:left;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The Apache Software Foundation (ASF) was founded in 1999 by a group of open-source enthusiasts and some corporate entities which were eager to sponsor the foundation’s work. Among the first projects was the famous web server called Apache HTTP, which is also simply referred to as “Apache web server”. At that time, the Apache web server was already quite mature. In fact, not only did the Apache web server give the foundation its name but it became the role model for the “Apache way” of open and collaborative software development. To see how that took place, we have to go back a bit further in time.&lt;/p&gt;

&lt;h3 id=&quot;a-web-server-goes-a-long-way&quot;&gt;A Web Server goes a long way&lt;/h3&gt;

&lt;p&gt;As early as 1994, Rob McCool at the National Center for Supercomputing Applications (NCSA) in Illinois created a simple web server which served pages using one of the early versions of today’s HTTP protocol. Web servers were not ubiquitous like they are today. In these days, the Web was still in its early days and there was only one web browser developed at CERN where the WWW was invented only shortly before. Rob’s web server was adopted quite fruitfully throughout the web due to its extensible nature. When its source code spread, web page administrators around the world developed extensions for the web server and helped to fix errors. When Rob left the NCSA in late 1994, he left a void because nobody maintained the web server along with its extensions. Quickly it became apparent that the group of existing users and developers needed to join forces to be able to maintain NCSA HTTP.&lt;/p&gt;

&lt;p&gt;At the beginning of 1995, the Apache Group was formed to coordinate the development of the NCSA HTTP web server. This led to the first release of the Apache web server in April 1995. During the same time, development at NCSA started picking off again and the two teams were in vivid exchange about future ideas to improve the web server. However, the Apache Group was able to develop its version of the web server much faster because of their structure which encouraged worldwide collaboration. At the end of the year, the Apache server had its architecture redone to be modular and execute much faster.&lt;/p&gt;

&lt;p&gt;One year later, at the beginning of 1996, the Apache web server already succeeded the popularity of the NCSA HTTP which had been the most popular web server on the Internet until then. Apache 1.0 finally was released on Dec 1, 1995. The web server continued to thrive and is still the most widely used web browser as of this writing.&lt;/p&gt;

&lt;h3 id=&quot;the-rise-of-the-foundation&quot;&gt;The Rise of the Foundation&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/asf_logo.svg&quot; style=&quot;width:200px;margin-right:15px;float:left;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The team effort that led to the development and adoption of the Apache web server was a huge success. The Apache project kept receiving feedback and code changes (also called patches) from people all over the world. Could this be the development model for future software? It became apparent that more and more projects started to organize their groups similarly to the Apache group. Out of this need, the Apache Software Foundation (ASF) was formed as non-profit corporation in June 1999.&lt;/p&gt;

&lt;p&gt;The ASF became a framework for open-source software development which, in its entirety, remains unmatched by other forms of open-source software development. The secret of its success is its unique approach to open-source software development where the foundation does not get in the way of the individual developers. Instead, it focuses on providing developers with the infrastructure and a minimal set of rules to manage their projects. The projects itself remain relatively autonomous.&lt;/p&gt;

&lt;h2 id=&quot;apache-governance---how-does-the-foundation-work&quot;&gt;Apache Governance - How does the foundation work?&lt;/h2&gt;

&lt;p&gt;There are about 200 independent projects running under the Apache umbrella. The question may arise, how does the foundation govern its project? First of all, the ASF is an organization that is run almost entirely by developers. Developers hate to spend too much time with administrative things (who doesn’t?), so the organization is structured in a way that requires little central control but favors autonomy of the projects which run under its umbrella.&lt;/p&gt;

&lt;h3 id=&quot;per-project-entities&quot;&gt;Per-Project Entities&lt;/h3&gt;

&lt;p&gt;For every project (e.g. Apache HTTP, Apache Hadoop, Apache Commons, Apache Flink, Apache Beam, etc.), there is a Project Management Commitee (PMC), Committers, and Users.&lt;/p&gt;

&lt;h4 id=&quot;project-management-committee-pmc&quot;&gt;Project Management Committee (PMC)&lt;/h4&gt;

&lt;p&gt;The Project Management Committee (PMC) manages a project and decides over its development direction. In that sense it has similar function as the original Apache Group which led the development of the Apache web server. When a new project is formed, the proposers constitute the initial PMC. Later on, new PMC members can be elected by the existing PMC. Note, that this goes without the permission of the central instances of the foundation. PMC members are also committers (see below).&lt;/p&gt;

&lt;h4 id=&quot;committers&quot;&gt;Committers&lt;/h4&gt;

&lt;p&gt;Committers can modify the code base of the project but they can’t make major project changing decisions. They are trusted by the PMC to work in the interest of the project. When they contribute changes, they commit (thus, the name) these changes to the project. Committers don’t only change code but they can also update documentation or write blog posts on the project’s website. Committers are selected from the users of the project; more about this process in the Mediocrity section.&lt;/p&gt;

&lt;h4 id=&quot;users&quot;&gt;Users&lt;/h4&gt;

&lt;p&gt;Users are as important as the developers because they try out the project’s software, report bugs, and request new features. The term is a slightly confusing because, in the Apache world, most users are actually developers themselves. They are users in the sense that they are using an Apache project for their own work; they are not actively developing the Apache software they are using. However, they may also provide patches to the Committers. Users who contribute to a project are called Contributors. Contributors may eventually become committers.&lt;/p&gt;

&lt;p&gt;In the following, the per-project entities are represented as circles. They exist for every project. The larger the circles, the more people. The redder the background color, the more decisional power the group has. Note that the user group circle is too large to fit in the image which is an accurate depiction of the user/developer ratio :)&lt;/p&gt;
&lt;div style=&quot;text-align:center; margin-bottom: 15px&quot;&gt;
    &lt;img src=&quot;/assets/images/hierarchy_pmc2.svg&quot; height=&quot;375px&quot; /&gt;
&lt;/div&gt;

&lt;h3 id=&quot;foundation-wide-entities&quot;&gt;Foundation-Wide Entities&lt;/h3&gt;

&lt;p&gt;The ASF does not work without some central instances. Here are the most important entities:&lt;/p&gt;

&lt;h4 id=&quot;apache-members&quot;&gt;Apache Members&lt;/h4&gt;

&lt;p&gt;Apache members are the heart of the foundation. A prerequisite to becoming a members is to be active in at least one project. To become a member, you have to show a deep interest in the foundation and try to promote its values. Existing members can then invite you to become a member. Becoming a members does not only mean honor but it also provides the right to elect the Board.&lt;/p&gt;

&lt;h4 id=&quot;the-board-of-directors-board&quot;&gt;The Board of Directors (Board)&lt;/h4&gt;

&lt;p&gt;The Board of Directors (Board) takes care of the overall government of the foundation. In particular, it is concerned with legal and financial matters like brand/patent issues, fundraising, and financial planning. The board is elected annually and is composed of Apache members. The current board can be viewed &lt;a href=&quot;https://www.apache.org/foundation/board/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Again, we use circles to set the per-project and foundation-wide entities into relation. Note that there is only one central Board for the entire foundation but Board members can be PMC members in different projects.&lt;/p&gt;
&lt;div style=&quot;text-align:center&quot;&gt;
    &lt;img src=&quot;/assets/images/hierarchy.svg&quot; width=&quot;300px&quot; /&gt;
&lt;/div&gt;

&lt;h4 id=&quot;officers-of-the-corporation&quot;&gt;Officers of the corporation&lt;/h4&gt;

&lt;p&gt;Officers of the corporation are the executive part of the administration. They execute the decisions of the board and take care of everyday business.&lt;/p&gt;

&lt;h4 id=&quot;infrastructure-infra&quot;&gt;Infrastructure (INFRA)&lt;/h4&gt;

&lt;p&gt;The support and administration team (INFRA) is the team that runs the Apache infrastructure and provides tools and support for developers. This includes running the &lt;a href=&quot;http://apache.org&quot;&gt;apache.org&lt;/a&gt; web site and the mailing lists which are Apache’s main way of communication. Over time, the need for various tools to assist developers became apparent. The main tools available which are used by almost all projects are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Mailing lists, for discussing the roadmap of the project, exchanging ideas, or reporting bugs (unwanted software behavior). Typically the mailing lists are divided into a developer and a user mailing list.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Bug trackers, which help developers to keep track of new features or bugs.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Version control, which helps developers to keep track of the code changes.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Build servers, which help to integrate/test new code or changes to existing code.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-incubator&quot;&gt;The Incubator&lt;/h4&gt;

&lt;p&gt;The Incubator is a division of the foundation dedicated to forming (bootstrapping) new Apache projects. The process is the following. People (volunteers, enthusiasts, or company employees) make a proposal to the Incubator. The proposal contains the name, the list of initial PMC members, and the motivation and goals for a new project. When the standards of the Apache Software Foundation are fulfilled by the proposal, the project enters the incubation phase. In the incubation phase, projects carry “incubating” with their names which is dropped once they graduate. To graduate, a project has to show that it adheres to the Apache standards and manages to develop a community. Formally, the project needs to prove that to the Incubator Project Management Committee (IPMC) which is comprised of Apache members. All existing work which is donated in the course of entering the incubator and, more importantly, all future work inside the project has to be licensed to the ASF under the Apache License. This ensures that development remains in the open-source according to the Apache philosophy. &lt;a href=&quot;https://incubator.apache.org&quot;&gt;More about incubation on the official website&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;meritocracy---how-are-decisions-made&quot;&gt;Meritocracy - How are decisions made?&lt;/h3&gt;

&lt;p&gt;The Apache Software Foundation uses the term “meritocracy” to describe how it governs itself. Going back to the ancient Greeks, meritocracy was a political system to put those into power which proofed that they had ability and talent within the field of power. The core of this philosophy can be found throughout history from ancient China to medieval Europe and is still present in many of today’s cultures in the sense that effort, increased responsibility, and service to a part of society ought to pay off in terms of power of decision, social status, or money.&lt;/p&gt;

&lt;p&gt;Meritocracy in the Apache Software Foundation denotes that people who either work in the interest of the foundation or a project get promoted. Users who submit patches may be offered committer status. Comitters who are driving the project constructively, may gain PMC status. PMC members active across projects may earn the member status.&lt;/p&gt;

&lt;p&gt;From there on, decision-making within the foundation and projects are typically performed using Lazy Consensus. Lazy consensus implies that even a few people can drive a discussion and make decisions for the entire community as long as nobody objects. The discussions have to be held in public on the mailing list. For instance, if a committer decides to introduce a new feature X, she may do so by proposing the feature on the mailing list. If nobody objects, she can go ahead and develop the feature. If lazy consensus does not work because an argument cannot be settled, a majority based vote can be started.&lt;/p&gt;

&lt;p&gt;Meritocracy and Lazy Consensus are the core principles for governance within the Apache Software Foundation. On the one hand, Meritocracy ensures that new people can join those already in power. On the other hand, Lazy Consensus creates the opportunity to split up decision-making among the group such that it doesn’t always require the action of all members of the community.&lt;/p&gt;

&lt;h3 id=&quot;the-apache-license---a-license-for-the-world-of-open-source&quot;&gt;The Apache License - A license for the world of open-source&lt;/h3&gt;

&lt;p&gt;With the incorporation of the foundation in 1999, a license had to be created to prevent conflicts with the intellectual property contributed by others to the ASF. Originally, the license was meant to be used exclusively by the ASF but it quickly became one of the most widely used software licenses for all kinds of open-source software development.&lt;/p&gt;

&lt;p&gt;The Apache license is very liberal in the sense that source code modifications are not required to be open-sourced (= made publicly available) even when the source code is distributed or sold to other entities. This is in contrast to “Copyleft” licenses like the GNU Public License (GPL) which, upon redistribution, requires public attribution and publication of changes made to the source code.&lt;/p&gt;

&lt;p&gt;The current version of the Apache License is 2.0, released in January 2004. The changes made since the initial release are only minor but they set the prerequisite for its prevalence. In the first place, the license was only available to Apache projects. Due to the success of the Apache model, people also wanted to use the license outside the foundation. This was made possible in version 2.0. Also, the new version made it possible to combine GPL code with Apache licensed code. In this case, the resulting product would have to be licensed under the GPL to be compatible with the GPL license. The last minor change for version 2.0 was to make inclusion of the license easier and require explicit patents for patent-relevant parts.&lt;/p&gt;

&lt;h2 id=&quot;apache-today&quot;&gt;Apache Today&lt;/h2&gt;

&lt;p&gt;The ASF today is not the small circle as it used to be back in 1999. At the time of this writing, the Apache Software Foundation hosts 177 committees (same as PMCs) with close to 300 projects (&lt;a href=&quot;https://projects.apache.org/&quot;&gt;latest statistics&lt;/a&gt;). Note that, a PMC may decide to host multiple projects if necessary. For instance, the Apache Commons PMC has broken up the different parts of the Apache Commons library, e.g. CLI, Email, Daemon, etc. Also, about 25 of the 300 projects have been retired and about 60 are currently in the incubation phase. So realistically, the number of projects is about 200.&lt;/p&gt;

&lt;p&gt;The Apache Software Foundation regularly organizes conferences around the world called &lt;a href=&quot;http://www.apachecon.com/&quot;&gt;ApacheCons&lt;/a&gt;. These conferences are dedicated to the Apache community or certain topics like Big Data or IoT. It is a place to meet the developers and learn about the latest ideas and trends within the global Apache community. Apart from the official conferences, there are conferences on Apache software organized by companies or external organization, e.g. &lt;a href=&quot;http://www.stratahadoopworld.com/&quot;&gt;Strata&lt;/a&gt;, &lt;a href=&quot;http://flink-forward.org/&quot;&gt;FlinkForward&lt;/a&gt;, &lt;a href=&quot;https://kafka-summit.org/&quot;&gt;Kafka Summit&lt;/a&gt;, &lt;a href=&quot;https://spark-summit.org/&quot;&gt;Spark Summit&lt;/a&gt;, &lt;a href=&quot;https://www.elastic.co/elasticon&quot;&gt;Elasticon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a list of some projects that I have run across in the past. I grouped them into categories for a better overview. I realize you might not know a lot of the projects but maybe this list can be the starting point to discover more about these Apache projects :)&lt;/p&gt;

&lt;div style=&quot;float:left; width:225px; height:350px&quot;&gt;
  &lt;h3 id=&quot;big-data&quot;&gt;Big Data&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Hadoop&lt;/li&gt;
    &lt;li&gt;Flink&lt;/li&gt;
    &lt;li&gt;Spark&lt;/li&gt;
    &lt;li&gt;Beam&lt;/li&gt;
    &lt;li&gt;Samza&lt;/li&gt;
    &lt;li&gt;Storm&lt;/li&gt;
    &lt;li&gt;NiFi&lt;/li&gt;
    &lt;li&gt;Kafka&lt;/li&gt;
    &lt;li&gt;Flume&lt;/li&gt;
    &lt;li&gt;Tez&lt;/li&gt;
    &lt;li&gt;Zeppelin&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:350px&quot;&gt;
  &lt;h3 id=&quot;database&quot;&gt;Database&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;CouchDB&lt;/li&gt;
    &lt;li&gt;HBase&lt;/li&gt;
    &lt;li&gt;Zookeeper&lt;/li&gt;
    &lt;li&gt;Derby&lt;/li&gt;
    &lt;li&gt;Cassandra&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:350px&quot;&gt;
  &lt;h3 id=&quot;query-tools--apis&quot;&gt;Query Tools / APIs&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Hive&lt;/li&gt;
    &lt;li&gt;Pig&lt;/li&gt;
    &lt;li&gt;Drill&lt;/li&gt;
    &lt;li&gt;Crunch&lt;/li&gt;
    &lt;li&gt;Ignite&lt;/li&gt;
    &lt;li&gt;Solr&lt;/li&gt;
    &lt;li&gt;Lucene&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;clear:both&quot;&gt;&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:150px&quot;&gt;
  &lt;h3 id=&quot;programming-languages&quot;&gt;Programming Languages&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Groovy&lt;/li&gt;
  &lt;/ul&gt;

&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:150px&quot;&gt;
  &lt;h3 id=&quot;distributions&quot;&gt;Distributions&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Bigtop&lt;/li&gt;
    &lt;li&gt;Ambari&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:150px&quot;&gt;
  &lt;h3 id=&quot;cloud&quot;&gt;Cloud&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Mesos&lt;/li&gt;
    &lt;li&gt;CloudStack&lt;/li&gt;
    &lt;li&gt;Libcloud&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;clear:both&quot;&gt;&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:200px&quot;&gt;
  &lt;h3 id=&quot;machine-learning&quot;&gt;Machine Learning&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Mahout&lt;/li&gt;
    &lt;li&gt;SAMOA&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:200px&quot;&gt;
  &lt;h3 id=&quot;office&quot;&gt;Office&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;OpenOffice&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:200px&quot;&gt;
  &lt;h3 id=&quot;libraries&quot;&gt;Libraries&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Commons&lt;/li&gt;
    &lt;li&gt;Avro&lt;/li&gt;
    &lt;li&gt;Thrift&lt;/li&gt;
    &lt;li&gt;ActiveMQ&lt;/li&gt;
    &lt;li&gt;Parquet&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;clear:both&quot;&gt;&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:200px&quot;&gt;
  &lt;h3 id=&quot;developer-tools&quot;&gt;Developer Tools&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Ant&lt;/li&gt;
    &lt;li&gt;Maven&lt;/li&gt;
    &lt;li&gt;Ivy&lt;/li&gt;
    &lt;li&gt;Subversion&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:200px&quot;&gt;
  &lt;h3 id=&quot;web-servers&quot;&gt;Web Servers&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Http (the one!)&lt;/li&gt;
    &lt;li&gt;Tomcat&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;float:left; width:225px; height:200px&quot;&gt;
  &lt;h3 id=&quot;web-frameworks&quot;&gt;Web Frameworks&lt;/h3&gt;

  &lt;ul&gt;
    &lt;li&gt;Cocoon&lt;/li&gt;
    &lt;li&gt;Struts&lt;/li&gt;
    &lt;li&gt;Sling&lt;/li&gt;
  &lt;/ul&gt;
&lt;/div&gt;

&lt;div style=&quot;clear:both&quot;&gt;&lt;/div&gt;

&lt;h2 id=&quot;apache---a-successful-open-source-development-model&quot;&gt;Apache - A Successful Open-Source Development Model&lt;/h2&gt;

&lt;p&gt;My first attempt to learn more about Apache goes back several years. I was using the Apache License while working on &lt;a href=&quot;http://scalaris.zib.de&quot;&gt;Scalaris&lt;/a&gt; at &lt;a href=&quot;http://zib.de&quot;&gt;Zuse Institute Berlin&lt;/a&gt;. I realized that the license was somehow connected to the Apache Software Foundation but I didn’t really understand the depth of this relationship until I started working on Apache Flink with &lt;a href=&quot;http://data-artisans.com&quot;&gt;Data Artisans&lt;/a&gt;. Besides the official homepage of the foundation, relatively little information was available on the Internet about the foundation and its projects. In hindsight, the best source of information would have been to read the email archives, ask the developers, or become a developer yourself :)&lt;/p&gt;

&lt;p&gt;Still today, I couldn’t find an introductory guide to the ASF. So I wrote this blog post. I hope that I could provide an overview of the ASF and show you how significant the foundation has been for the open-source software development.&lt;/p&gt;

&lt;h2 id=&quot;thank-you&quot;&gt;Thank you&lt;/h2&gt;

&lt;p&gt;Thank you for reading this article. Please drop me a message if I got something wrong or you would like to comment on anything.&lt;/p&gt;

&lt;p&gt;Thank you to the Apache Flink project. Especially to Robert Metzger, Vasia Kalavri, Henry Saputra, Aljoscha Krettek, Matthias Sax, Ufuk Celebi, Till Rohrmann, Fabian Hueske, Stephan Ewen, and Kostas Tzoumas. You taught me a lot about the Apache way. Thanks also to the Apache Beam community which just graduated from the Incubator and has proven to be an excellent member of the Apache family.&lt;/p&gt;

&lt;h2 id=&quot;sources&quot;&gt;Sources&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://w3techs.com/technologies/history_overview/web_server&quot;&gt;Web Server usage&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://apache.org/foundation/&quot;&gt;Apache Foundation&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apache.org/history/&quot;&gt;Apache History&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://httpd.apache.org/ABOUT_APACHE.html&quot;&gt;About Apache&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Robert_McCool&quot;&gt;Robert McCool&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/CERN_httpd&quot;&gt;CERN httpd&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Apache_HTTP_Server&quot;&gt;Apache HTTP&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apache.org/foundation/press/pr_1999_06_30.html&quot;&gt;Initial press release&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Apache_License&quot;&gt;Apache License&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apache.org/licenses/&quot;&gt;Apache License #2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apache.org/foundation/how-it-works.html&quot;&gt;How it works&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.apache.org/dev/&quot;&gt;Apache Dev&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://incubator.apache.org/&quot;&gt;Apache Incubator&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://projects.apache.org/&quot;&gt;Apache projects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 03 Feb 2017 09:05:33 +0100</pubDate>
        <link>https://maximilianmichels.com/2017/an-introduction-to-apache-software/</link>
        <guid isPermaLink="true">https://maximilianmichels.com/2017/an-introduction-to-apache-software/</guid>
        
        
        <category>apache</category>
        
      </item>
    
    
  </channel>
</rss>
