In this article, we will take a look at the Erlang ecosystem, focusing on the underlying architecture of Elixir and Erlang, two functional programming languages, and see how they utilize a shared runtime system known as BEAM for code execution
To grasp the full potential and innovation behind Erlang and Elixir, it's crucial to delve into their origins and the principles that guide their development.
The development of Erlang began in the mid-1980s in Ericsson's laboratory. At that time, Erlang was designed to provide a better way to "build telephone applications"[1]. It was developed for writing concurrent programs that can run without interruption.
What makes Erlang exceptionally concurrent and scalable, as well as fault-tolerant, is its process-based approach. These processes do not share memory and can communicate with each other using asynchronous messages. Processes can also restart each other, which allows for easy system recovery in case of errors. These processes belong to the programming language rather than the operating system. In addition to sending and receiving messages and commands among themselves, they can also send them outside the kernel, allowing the system to scale by adding more processing units. Erlang also has a mechanism for changing code within the program without stopping its execution called hot code swapping.
Elixir is a dynamic functional language created for building scalable and maintainable applications, with prominent applications in communication networks, real-time systems, and web application development[2]. It was created by José Valim in 2011 to offer a solution to common concurrency issues in programming that he faced during the time he worked as a Ruby/Rails developer[3]. At the same time, the intention was to achieve the competitive robustness of Erlang. Therefore, Elixir was developed based on the Erlang Virtual Machine (BEAM), inheriting Erlang's capabilities for creating resilient, distributed applications. The interoperability of Elixir and Erlang is further facilitated since both languages compile into a common bytecode format, allowing seamless integration and use of libraries from both languages.
The Erlang Runtime System (ERTS) compiles the original Erlang program code into bytecode, which is then executed on BEAM, Erlang's virtual machine. BEAM runs as a single process of the operating system (OS), and unless specified otherwise, the number of threads that this process executes corresponds to the number of OS cores[4]. BEAM does not have any information about system information or OS processes but serves only to execute commands that are written in special registers. All processes implemented within Elixir or Erlang are fully executed by BEAM, on just one OS process. These processes are small and lightweight compared to threads and processes of the operating system, which allows for the creation of many such processes where each performs its task, isolated from the rest of the program. BEAM efficiently allocates and manages these lightweight processes through its scheduler threads. Scheduler threads in BEAM are designed to dynamically distribute tasks (processes) across available cores, thus optimizing program execution without unnecessary load on a single core.
To wrap up, understanding the architecture that underpins Elixir and Erlang offers fascinating insights into how these languages manage to achieve remarkable levels of concurrency, scalability, and fault tolerance. From Erlang's original design to revolutionize the development of telephone applications to Elixir's creation for enhanced maintainability and scalability in modern applications, both languages demonstrate the power of functional programming in managing complex, distributed systems with ease.