This article is a continuation of a series of articles about the Erlang / Erlang programming language and its use in our
Risovaska project. First of all, I want to answer the questions asked in the comments to the
first article , and there were a lot of questions asked. So let's continue:
Installing Erlang under Windows
Installing Erlang is easy. First, download the distribution from the
official site . We need the latest version of R12B-5, the Windows binary column (incl. Documentation). After installing “Start” - “All Programs” into me, the item Erlang OTP R12B will appear and in it the sub-item “Erlang”. If you select it, then start the nameless node together with the shell (shell) in which you can already execute Erlang code, including from my examples. I will stick to the name “node”, since the official name in Russian has not yet been settled, although the word “node” is translated as “node”.
Here are links about installing Erlang on
Mac OS X and
Linux (in English).
To complete the installation, you need to set the following variables in the Windows environment variables:
1. The path to the directory where Erlang was installed:
ERL_TOP = C: \ Program Files \ erl5.6.5
the same way, but with the addition of
\ bin , i.e.
C: \ Program Files \ erl5.6.5 \ bin must also be entered into the PATH variable if it is not already there
')
2. The variable HOME, if you have not yet registered it, for example:
HOME = C: \ Documents and Settings \ tolik
3. I recommend to immediately register the path to the Erlang third-party libraries:
ERL_LIBS = C: \ Work \ erl_libs
In the future, all third-party libraries that are not included in the delivery of Erlang / OTP, put in this directory. This will make it easy to install the new version of Erlang / OTP, removing the old one, without rearranging the third-party libraries. By the way, new versions of Erlang / OTP come out with regularity twice a year.
Finally, in the HOME directory, create the file ".erlang.cookie". This is a plain text file in which a text cookie is stored in one line, for example: “AMMVFJKDTENSFHDJDGDERSW”. This cookie will be used when the nodes interact with each other. The fact is that two nodes can interact with each other only if they have the same cookie's. If you are not interested in the interaction of several nodes with each other, then skip this step.
In the same HOME directory, it is convenient to create an ".erlang" file in which you can write Erlang code that will be automatically executed when any node on the computer starts. Usually, this file is written with the code adding the path to the executable files of your application to the search list:
code:add_pathz(" ebin ").
Now you can run the node directly from the command line just by typing: “erl”. You can run the node and without a shell or as a demon. If you run a node without a shell, then you can connect to it by running the second node (you can also on another computer) by running:
erl -name test@192.168.0.11 -remsh main@192.168.0.11
where
main@192.168.0.11 is the name of the node to which we are connecting, and
test@192.168.0.11 is the name of the new node. After connecting, you can execute all commands as if you are on the first node.
The launch parameters are described in more detail in the
erl module.
Emacs as development environment
Until recently, almost the only convenient option to write and debug programs on the Erlang was
Emacs (mistaken for a regular text editor) in conjunction with
Distel . Enough good instructions on how to configure and work with both packages in Russian can be found
here . In our work, we still use them, although they look like ancient dinosaurs, compared to modern development environments.
New development environment: erlIDE
To replace Emacs, a new erlIDE development environment is being developed. The current version 0.4.3 is already quite stable and does not fall, as earlier versions. It contains almost all the usual tools for modern IDE: debugger, contextual help, simple code navigation, syntax highlighting, etc.
The installation instructions are written in sufficient detail and usually do not cause questions. erlIDE works as a plugin for
Eclipse , so you need to first install Java on your computer (preferably at least version 6), and then
Eclipse . Eclipse IDE for Java Developers (85 MB) will suffice to work. Under Windows, I would recommend immediately starting with erlIDE, so as not to get used to Emacs.
And now we will return directly to the language.
Creating the first application
To get started, create a folder where you will have a project. Inside it you need to create the following subfolders:
- ebin - compiled code (.beam) will be put here
- src - application source (.erl)
- include - header files (.hrl)
- doc - documentation
- priv - everything else that the application needs in work, but not included in other folders
This is a standard application structure recommended by OTP principles. In the root folder of the application, create an emakefile file with the following contents:
{"src/*", [debug_info, {i, "include"}, {outdir, "ebin"}]}.
and then in the shell of the node, being in the root folder of the application, you can simply execute the command: make: all () to recompile all the application modules.
In the “ebin” subfolder you need to create the file your_application.app with something like this:
{application, your_application.app,
[{description, "Test application"},
{vsn, "1"},
{modules, [you_application, you_application_sup]},
{registered, []},
{applications, [kernel, stdlib, sasl]},
{mod, {your_application,[]}}
]}.
And finally, in the “src” folder you need to create the main project file: you_application.erl with minimal content:
-module(you_application).
-behaviour(application).
-export([start/2, stop/1]).
start(_Type, _Args) ->
your_application_sup:start_link().
stop(_State) ->
ok.
Thus, we have created a minimal application on the Erlang, which so far does nothing. Also, the main application supervisor has not been implemented yet (I will write about it later). For more information on creating an application,
see the OTP documentation.Hot swap code
A very useful feature of Erlang / OTP is a hot-swappable code without stopping the system. How does it work on the example of one module? For example, you changed the code in one of the application modules and want to change it on the fly in a running system. In this situation in Erlang it is not necessary to stop the entire application. Enough in the shell node to type:
l(your_module).
and after executing this command, the new code will already work. In more detail, the Erlang virtual machine stores in memory two copies of each module: the current and the previous one. Why do you need to keep the previous version? So that in the case of incorrect operation of the new code, quickly roll back to the previous version as well without stopping the application.
Of course, you can replace on the fly not only a single module, but the entire application as a whole. For this:
- create an application update file (Application Upgrade File), in which we write the rules for replacing the old version with a new version, as well as dependencies between modules during the version replacement
- create an upgrade update file
- we install the new version of the application over the old
To reduce the size of the article, for more information, I send in the
documentation , where these steps are described in more detail.
But what to do when you have an entire distributed system consisting of several servers and you need to replace all of them at the same time with the code without stopping the entire system. Unfortunately, Erlang / OTP does not offer a ready-made convenient solution. However, the OTP includes the
erl_boot_server module, which allows you to load application code, including configuration files from another node, when starting the node. Then the overload of the entire system can be implemented as follows: first, the code on the main server is hot-swapped, the code from which the rest of the nodes loaded at its start using the erl_boot_server module. And then a message is sent to all nodes to overload the node. When such a message is received on the node, the init: restart / 0 command is executed, which overloads the node without stopping it completely. After the overload, all nodes take the already updated code from the main server. Approximately this approach is described in two articles,
Setting up Erlang on Amazon EC2 (second part of the article) and
Upgrading your Erlang cluster on Amazon EC2 .
Behaviours
Another interesting feature of the language are the behaviors, which are analogs of interfaces in traditional languages, and more precisely abstract classes. If at the beginning of the module, for example, it says
-behaviour(application).
- this means two things: a part of the logic is already implemented in OTP and the second, a certain set of callback functions must be implemented in the module, without which the module will not be compiled. In our case, we must implement the start and stop functions. For more detailed information I send to
documentation on behaviors .
Let the process die
As I noted in my
first article, the high reliability of systems built on Erlang is not based on there, that all the code is written so that it does not fall, but so that if there is any error in the workflow, then there is always an observer a process that corrects the situation and restores system performance. Indeed, most often the workflow usually does not know exactly what to do in the event of an error, so it’s more correct to just die and let the monitoring process figure it out. This is done like this:
- First, the observing process performs the famous command in Erlang:
process_flag(trap_exit, true).
This means that this process catches messages about the fall of related processes. After executing this command, if the workflow falls, then a message of the form comes to the observing process: {'EXIT', From, Reason}
processes until the process that executed process_flag (trap_exit, true) is encountered on the way. - secondly, the monitoring process creates an associated workflow:
spawn_link(?MODULE, worked_function, [Arguments]).
- and, thirdly, the monitoring process begins to listen to the messages:
receive
{'EXIT', From, Reason} ->
supervising_function() % (. )
end
In sum, the minimum code of the monitoring process will look like this:
supervising_function() ->
process_flag(trap_exit, true).
spawn_link(?MODULE, worked_function, [Arguments]).
receive
{'EXIT', From, Reason} ->
supervising_function()
end
end.
Building bricks Erlang / OTP
But it is not at all necessary to write the observing processes, the processes of access to shared resources, etc. from scratch. In less than twenty years of language development, Erlang / OTP has developed a robust and well-established set of basic components on which the application written in Erlang is usually built. Here they are:
- gen_server is a basic server implementation that supports client-server interaction in the system. I note that here the concept of "server" does not coincide with the generally accepted concept, and means a specific server Erlang / OTP. Usually in the system he is responsible for access to the general resources of the system.
- gen_fsm - the basic module that implements the end state machine
- gen_event - the basic module that implements the event handling functionality
- and, of course, supervisor - the module is designed to start, stop and monitor its child processes. In order not to write a lot of theory, I will give a simple example of the initialization function of the supervisor:
init() ->
RestartStrategy = one_for_one
MaxRestarts = 10,
MaxTimeBetRestarts = 3600,
SupFlags = {RestartStrategy, MaxRestarts, MaxTimeBetRestarts},
ChildSpecs = [{Some_Module, {Some_Module, Function, []}, permanent, TimeOut,
worker, %
[Some_Module]}],
{ok, {SupFlags, ChildSpecs}}.
This code will launch one child process, the maximum number of child process restarts = 10 with a frequency of no more than 3600 ms.
I note that in all the basic components described above (except for the supervisor) there is a function code_change, which is automatically executed when the application is hot restarted. In this function, you can write code that provides a smooth transition from one version of the application to another.
Unfortunately, a detailed description of each module and the links between them will take several articles, and they are also well described in the
Design Principles . And you don’t need to go far for examples of usage, take any well-known application or library written on Erlang and see. Almost all of them are written using these basic components.
At the end of the article I want to give a link to a
good article in Wikipedia about Erlang and two good (
1 ,
2 ) collections of resources on Erlag, which was collected by Dima Smolin. For those who are interested in the Erlang language, these links are enough to dive deep into the language.
To be continued...
As in the first article, the list of topics for consideration remains the same: using Mnesia distributed base (which is part of Erlang / OTP), using Amazon S3 and Amazon EC2 with examples of using these technologies on
Risovaska servers.