The single best reason to use airflow is that you have some data source with a time-based axis that you want to transfer or process. For example, you might want to ingest daily web logs into a database. Or maybe you want weekly statistics generated on your database, etc.
The next best reason to use airflow is that you have a recurring job that you want not only to happen, but to track it's successes and failures. For example, maybe you want to garbage-collect some files on a remote server with spotty connectivity, and you want to be emailed if it fails for more than two days in a row.
Beyond those two, Airflow might be very useful, but you'll be shoehorning your use case into Airflow's capabilities.
Airflow is basically a distributed cron daemon with support for reruns and SLAs. If you're using Python for your tasks, it also includes a large collection of data abstraction layers such that Airflow can manage the named connections to the different sources, and you only have to code the transfer or transform rules.
Worst of all, if you accept Bisquick, then you open the door to an explosion of Bisquick options. Its a combinatorial explosion of pre-mixed ingredients. In a dystopian future, perhaps people stop buying flour or salt, and the ONLY way you can make food is to buy the right kind of Bisquick. Might make a kind of mash up of a baking show and Black Mirror.
Anyway, yeah, Airflow (and so many other tools) feel like Bisquick. It has all the strengths, but also all the weaknesses, of that model.
Higher-order abstractions can be a productivity boon but have costs when you fight their paradigm or need to regularly interact with lower layers (in ways the designs didn't presume).
Airflow and similar tools are doing four things:
A) Centralized cron for distributed systems. If you don't have a unified runtime for your system, the old ways of using Unix cron, or a "job system" become complex because you don't have centralized management or clarity for when developers should use one given scheduling tool vs another.
B) Job state management. Job can fail and may need to be retried, people alerted, etc ... Most scheduling system has some way to do deal with failure too, but these tools are now treating this as stored state
C) DAGs, complex batch jobs are often composed of many stages with dependencies. And you need the state to track and retry stages independently (especially if they are costly)
D) What many of these tools also try to do, is tie the computation performing a given job to the scheduling tool. This now seems to be an antipattern. They also try to have "premade" job stages or "operators" for common tasks. These are a mix of wrappers to talk to different compute systems and actual compute mechanisms themselves.
If you have the kind of system that is either sufficiently distributed, or heterogeneous enough that you can't use existing schedulers, you need something with #A, but if you also need complex job management, you need #A, #B and #C, and having rebuilt my own my times, using a standard system is better when coordinating between many engineers. What seems necessary in general is #D.
Ed: I should say, I really like this metaphor, and I expect it will crop up in my thinking in the future.
- Airflow the ETL framework is quite bad. Just use Airflow the scheduler/orchestrator: delegate the actual data transformation to external services (serverless, kubernetes etc.).
- Don't use it for tasks that don't require idempotency (eg. a job that uses a bookmark).
- Don't use it for latency-sensitive jobs (this one should be obvious).
- Don't use sensors or cross-DAG dependencies.
So yeah unfortunately it's not a good fit for all the use cases, but it has the right set of features for some of the most common batch workloads.
Also python as the DAG configuration language was a very successful idea, maybe the most important contributor to Airflow success.
You can totally design your tasks to be idempotent - but its up to you to make them that way. The scheduler or executor doesn't have any context into your job.
This is why I encourage people to use a unified base operator and then pass their own docker containers to it. Aka like how https://medium.com/bluecore-engineering/were-all-using-airfl... outlines it.
> - Don't use it for latency-sensitive jobs (this one should be obvious).
IIRC this is being addressed in Airflow 2.0
> - Don't use sensors or cross-DAG dependencies.
This is a little extreme. I've never ran into issues with cross dag dependencies or sensors. They make managing my DAGs way easier because wee can separate computation dags from loading dags.
context: I built/manage my company's Airflow platform. Everything is managed on k8s.
re: idempotency - yes, make your workflow tasks idempotent.
re: latency - this is being worked on very actively. Ash (PMC member) has committed to working on task latency almost exclusively until it's resolved
re: sensors, there is some great work from Airbnb to improve: https://cwiki.apache.org/confluence/display/AIRFLOW/AIP-17+A...
For this specific use case, I use healthchecks.io - trivial to deploy in almost any context which can ping a public URL. Generous free tier limits so I've got that going for me which is nice.
BTW, here's https://github.com/pditommaso/awesome-pipeline a list of almost 200 pipeline toolkits.
* Source control for workflows/DAGs (using git-sync)
* Tracking/retries with SLAs
* Jobs run in Kubernetes
* Web UI for management
* Fully open source
I also use Argo Workflows, because I like its native handling of Kubernetes objects (e.g. the ability to manage and update a deployment as one of the steps), but it just doesn't have the orchestration/tracking side of things very well managed yetIs this "curated"? It seems like an exhaustive "dump" of toolkits.
https://softwareengineeringdaily.com/2020/04/29/prefect-data...
Papermill is another example.
Airflow may not be necessary for a ten person team but it could be if that team has complicated data orchestration needs and doesn't want to incrementally replace their infrastructure every couple years.
We fell in love with Airflow's capability to allow us to write one small python program that generated hundreds of tailored dags by iterating over the configuration of each of our customers. This dynamism is very powerful for similar use cases.
I miss features, sure. The whole execution timing might be confusing the first time, sure. But I can't figure out why i see so many comments regarding deployment difficulties.
Since a lot of you use Airflow, I am curious about your experience with it:
1. Are you hosting Airflow yourselves or using a managed service?
1. a. If managed, which one? (Google Cloud Composer, Astronomer.io, something else?)
1. b. If self-hosted, how difficult was the setup? It seems daunting to get a stable setup (external database, rabbit or redis, etc.).
2. Do you use one operator (DockerOperator looks like the right choice) or do you allow yourself freedom in operators? Do you build your own?
3. How do you pass data from one task to the next? Do the tasks themselves have to be aware of external storage conventions or do you use the built-in xcom mechanism? It seems like xcom stores messages in the database, so you run the risk of blowing through storage capacity this way?
One downside with Composer, though, is that it must be run in its own GKE cluster, and it deploys the Airflow UI to App Engine. These two things can make it a bit of a pain to use alongside infrastructure deployed into another GKE cluster if you need the two to interact.
I would probably still recommend Composer over deploying your own Airflow into GKE, as having it managed is nice.
2. Freedom. For some tasks we run containers in GKE, for other we use things like the PythonOperator or PostgresOperator.
A note here: Using containers with Airflow is not trivial. In addition to needing some CI process to manage image building/deployment, having the ability to develop and test DAGs locally takes some extra work. I would only recommend it if you are already invested in containers and are willing to devote the time to ops to get it all working.
3. X-com is useful for small amounts of data, like if one task needs to pass a file path, IDs, or other parameters to a downstream task. For everything else have a task write its output to something like S3 or a database that another task will read from.
All in all, I would say use Airflow if you need the visibility and dependency management. Don't use it if you could get away with something like cron and some scripts or a simple pool of celery workers.
Also, don't use it if your workflows are highly dynamic. For example, if you have a situation where you need to run a task to get a list of things, then span x downstream tasks based on the contents of the list. Airflow wants the shape of the DAG to be defined before it is run.
Hope that helps.
2. Freedom. We generally use PythonOperators but it is not uncommon to run containers as well. I agree with pyrophane, setting up containerized operators really is a non-trivial and far from straightforward to test locally. Still, it seems worth doing, particularly if you do not want various execution to affect one another.
3. Again, echoing what pyrophane said, a custom solution is needed for anything that's more than a couple hundred bytes in size. There even exists (now mostly abandoned) plugin that allows you to streamline the whole process: https://github.com/industrydive/fileflow Writing directly to something like S3 is almost always sufficient in combination with passing the path for the file from one task to another.
Having said that, I would encourage you to try it out, even if the setup may sound daunting at first. If you can model your tasks as DAGs whose graphs are known in advance, I would argue it almost always makes sense because you get many things "for free" that were not mentioned before: logging, backfill, standard handling of connections/secrets and a ton of metrics in a nice UI that helps a lot with the visibility part.
1b. Pip install airflow[all|what you need] The airflow itself is easy to install. I’d say that installing the external tools is also easy. I believe installing pg, redis, or celery should be categorized in easy. It’s not the kafka or k8s level of installation.
2. Freedom.
3. Custom scripts
1) it's not cloud native in the sense that running this on e.g. AWS is an easy and well trodden path. Cloud is left as an exercise to the reader of the documentation and at best vaguely hinted at as a possibility. This is weird because that kind of is the whole point of this product. Sure, it has lots of things that are highly useful in the cloud (like an ECS operator or EMR operator); but the documentation is aimed at python hackers running this on their laptop; all the defaults are aimed at this as well. This is a problem because essentially all of that is wrong for a proper cloud native type environment. We've looked at quite a few third party repos for terraform, kubernetes, cloudformation, etc that try to fix this. Ultimately we ended up spending non trivial amounts of time on devops. Basically, this involved lots of problem solving for things that a combination of wrong, poorly documented, or misguided by default. Also, we're not done by a long shot.
2) The UX/UI is terrible and I don't use this word lightly. Think hudson/jenkins, 15 years ago (and technically that's unfair to good old Hudson because it never was this bad). It's a fair comparison because Jenkins kind of is a drop in replacement or at least a significant overlap in feature set. And it arguably has a better ecosystem for things like plugins. Absolutely everything in Airflow requires multiple clicks. Also you'll be doing CMD+R a lot as there is no concept of autorefresh. Lots of fiddly icons. And then there's this obsession with graphs and this being the most important thing ever. There are two separate graph views, only one of which has useful ways of getting to the logs (which never requires less than 4-5 mouse clicks). And of course the other view is the default under most links so you have to learn to click the tiny graph icon to get to the good stuff.
3) A lot of the defaults are wrong/misguided/annoying. Like catch up defaulting to true. There's this weird notion of tasks (dags in airflow speak) running on a cron pattern and requiring a start date in the past. Using a dynamic date is not recommended (i.e. now would be a sane default). So typically you just pick whatever fixed time in the past. When you turn a dag on it tries to 'backfill' from that date unless you set catchup to false. I don't know in what universe that's a sane default. Sure, I want to run this task 1000 times just because I unpaused it (everything is paused by default). There is no way to unschedule that. Did I mention the default parallism is 32. That in combination with the docker operator is a great way to instantly run out of memory (yep that happened to us).
4) The UI lacks ways to group tasks like by tag or folders, etc. This gets annoying quickly.
5) Dag configs as code in a weakly typed language without a good test harness leads to obvious problems. We've sort of gobbled together our own tests to somewhat mitigate repeated deploy screw ups.
6) implementing a worker architecture in a language that is still burdened with the global interpreter lock and that has no good support for either threading or light weight threads (aka co-routines) or doing things asynchronously, leads to a lot of complexity. The celery worker is a PITA to debug.
7) IMHO the python operator is a bad idea because it gives data scientists the wrong idea about, oh just install this library on every airflow host please so I can run my thingy. We use the Docker operator a lot and are switching to the ECS operator as soon as we can figure out how to run airflow in ECS (we currently have a snow flaky AMI running on ec2).
8) the logging UI is terrible compared to what I would normally use for logging. Looking at logs of task runs is kind of the core business the UI has to do.
9) Airflow has a DB where it keeps track of state. Any change to dags basically means this state gets stale pretty quickly. There's no sane way to get rid of this stale data other than a lot of command-line fiddling or just running some sql scripts directly against this db. I've manually deleted hundreds of jobs in the last month. Also there's no notion of having a sane default for number of execution runs to preserve. Likewise the there is built in way to clean up logs. Again, Jenkins/Hudson had that always. I have jobs that run every 10 minutes and absolutely no need to keep months of history on that.
There are more things I could list. Also, there are quite a few competing products; this is a very crowded space. I've given serious thought to using Spring Batch or even just firing up a Jenkins. Frankly the only reason we chose airflow is that it's easier for data scientists who are mostly only comfortable with python. So far, I've been disappointed with how complex and flaky this setup is.
If you go down the path of using it, think hard about which operators you are going to use and why. IMHO dockerizing tasks means that most of what Airflow does is just ensuring your dockerized tasks run. Limiting what it does is a good thing. Just because you can doesn't mean you should in airflow. IMHO most of the operators naturally lead to your airflow installs being snow flakes.
Not dockerizing means you are mixing code and orchestration. Just like installing dependencies on CI servers is not a great idea is also the reason why doing the same on an airflow system is a bad idea.
2) Yes the UI is outdated, and not responsive. We're going to kick off a process to build a new modern UI in Q3 (a full-featured Swagger API is being built now, which the new UI will rely upon.)
3) I personally think catchup true is a fine default, but whatever. Generally when I launch a new DAG I want to generate some historical data using the DAG.
4) Airflow has tags now since 1.10.8 https://airflow.readthedocs.io/en/latest/howto/add-dag-tags.... - we decided not to do folders.
5) That's true, but it also provides a low bar to entry. There are some guides written on unit testing DAGs, but I agree we should be a test-first community. On my roadmap.
6) Celery w/ KEDA is pretty nice - check out https://www.astronomer.io/blog/the-keda-autoscaler/
7) I personally love the PythonOperator for simple DAGs. Agree that DockerOperator (KubernetesPodOperator if you're running Airflow in K8s)
8) Yes, logging UI will be improved in the UI rewrite. What's your favorite UI for this?
9) That feature is in the queue https://github.com/apache/airflow/issues/7911
- Simplicity is key. Data Teams should focus on creating solutions, not fighting infrastructure and limitations. - Workflows shouldn't change how code is written. Your code should run the same locally as on our platform, with no extra packages or proprietary setup files required. - Templates are a first-class object. The modern data pipeline should be built with repeatability in mind. - Data solutions should be usable and visible beyond the walls of technical teams.
We're in a private beta and rapidly trying to improve the product. I would love to chat more if you're interested. Details in profile.
For your specific problems:
1) We're cloud-native and handle hosting/scaling on our side. You don't have to worry about setup. Just log in and launch your code.
2) Our UI is pretty slick (built in AntD) and built to reduce the overwhelming options when setting jobs up.
3) If you want to run a job on-demand, just press "Run now". If you schedule a job, then change the schedule or status, we'll automatically add/update/remove the schedules. Other technical defaults aren't options right now because we're trying to abstract those choices away so Data Teams can just focus on building solutions that work.
4) We let you group your scripts into "Projects" (essentially folders) with a high level overview of the quantity of jobs, as well as how many recently failed or succeeded.
5) Workflows get made directly in the UI. This makes it easier for any less technical users to set up jobs on their own. We still have a lot of improvement to go in this area though.
6) Our product is written in Go (the language of the cloud). We don't force the worker to be in a language and managed by a process in that language. We manage at the process level.
7) Every job creates a new container on the fly, installing package dependencies that the user specifies. You can connect your scripts together without worrying about conflicting packages, conflicting language versions, or without needing to know how to make and manage Docker containers.
8) Not sure how we compare on the logging front. However, we separate out logs for each time a script runs so you're not having to search for a needle in a haystack. You can filter and search for specific logs in the UI.
It seems a big gap in the market. I can't rely on cron as its a single point of failure. I have my own hardware so dont want to use AWS Batch or GCP Cloud Scheduler, any other ideas?
This all seems contradictory.
Personnaly, using Python, I go for Celery (www.celeryproject.org): it's a persistant daemon that can run tasks, provide queues and shedule work like cron .
A lot of people prefer Python-RQ, as it seems simpler, but the truth is you can start using celery with just the file system for storing tasks and result:
https://www.distributedpython.com/2018/07/03/simple-celery-s...
If your needs grow, you can plug it to redis, rabbit MQ and/or a database later.
It can expose an API so that other languages can talk to it and trigger tasks or retrieve results (but not write tasks, they must be in python).
If I may ask, what questions do you find most difficult to solve in the context of real-world ETL setups?
- https://github.com/getpopper/popper
- https://github.com/lyft/flyte
- https://aws.amazon.com/step-functions/
- https://github.com/spotify/luigi
- https://github.com/dagster-io/dagster
Another question is, I strongly feel like the definition of pipelines should not be in code, but in the database. I keep coming back to that design pattern every time I start coding my own simple scheduling solution. Is there merit to this thought?
As for the pipeline definition. One goal is to have a notion of pipelines that is both comprehensive and declarative.
As for a database, what would you store there? Container image to run? Past execution data (e.g. output path, time, errors)?
The software world has many pipeline-y things, such as CI definitions and these definitions usually live in configuration files.
What is difficult at time is the tracking of done tasks. Is the output a file or a new row in some database or many files or many rows or anything else?
I believe that says a lot about open source projects released in recent years.
Airflow, Prefect, Dagster, Kedro,... it appears there are now a lot of tools that I never heard of and never needed, despite me doing exactly what all of them try to solve with Hadoop and MapReduce.
The ability to rerun a failed DAG from a given task was ideal for the situation we found ourselves in at the time with a dependency on a Hadoop cluster that was starting to fail.
We're working on making the scheduler HA and more performant, reach out to me if you'd like to collaborate on your use case (ry at astronomer dot io)
I also see a lot of people saying it's a solution for big companies and the like, I heavily disagree it's useful for any size company that wants to have better organization of their pipelines and provide an easy way for non technical users to check on their health.
1. Does airflow have native (read high speed) connectors to destination databases (oracle, mysql, mssql) ?
2. How the typical ETL in Airflow compares to one in Informatica/SSIS in terms of speed of development, performance (throughput and latency), memory consumptipon? Is it the same speed, or slower due to using Python interpreter?
3. Is it easy or hard to use parallel transformations with processes/threads/async ? For example, ingest data from your source in 20 threads at once, as opposed to serial processing
What I found is that if data is high quality - then ELT is totally fine, often times it ends up being just EL without much T. But if the data is crap, and you have a lot of wide columns, then even loading it takes time, before we even get to processing stage. In this scenario ETL works much faster.
Apologies if this is pedantic, but the orchestration of jobs transcends ETL workflows. There's countless usecases of scheduling dependent jobs that aren't ETL workloads.
- Encapsulate your business logic in microservices and expose ETL actions with APIs.
- Call your microservices using Airflow.
That way my Airflow jobs are very lightweight (they only call https APIs) and only contain logic of when doing things, not how. All the core business logic for a specific domain lives in a single container that can be tested and deployed independently.
Doing ETL using Airflow jobs exclusively or Lambda would spread business logic and make it a nightmare to test and reason about.
You can use something like Kedro (https://github.com/quantumblacklabs/kedro) to get started building pipelines with pure Python functions. Kedro has its own pipeline visualiser and also has an Airflow plugin that can automatically help you generate airflow pipelines from Kedro pipelines.
Not knocking Airflow, it is great. Luigi too.
It's only useful if you have workloads that are very strictly time-bounded (Every day, do X for all the data from yesterday). It's virtually impossible to manage an event-driven or for-each-file-do-Y style workflow with Airflow.
https://github.com/voxmedia/maestro/
With the SQL-centric approach you do not need to specify a DAG because it can be inferred automatically, all you do is maintain your SQL and Maestro takes care of executing it in correct order.
You'll probably use up a lot of resources indeed, depending on how big your tasks are you will have quite some overhead to run each and every one in a seperate pod, compared to running them in a Celery Multiprocessing "thread" on an already running worker container.