Росен Генчев

Статии15 май 2023 г.13 мин четене

Erlang: любопитно силният език, който всеки програмист трябва да научи

Erlang: любопитно силният език, който всеки програмист трябва да научи

Въведение

Представете си, ако щете, че стоите на оживените улици на Лондон, изправени пред безброй възможности за транспорт, за да се придвижите из града. Има го Docker, двуетажният автобус: здрав и многофункционален, но понякога малко тромав. Kubernetes е подобен на черно такси: мощен, гъвкав, но често твърде сложен за непосветените. След това е метрото, представител на разпределени опашки като Kafka или RabbitMQ: бързо, надеждно, но не и без своите сложности и случайни закъснения.

Сега си представете алтернатива: пъргаво малко колело, елегантно и просто, което с лекота се справя с трафика и предлага глътка свеж въздух. Това, драги читателю, е Erlang. Език, който прорязва шума и сложността на разработката на разпределени системи с елегантната простота на колоездач, провиращ се през задръстването. Erlang идва напълно оборудван с паралелизъм, отказоустойчивост и разпределеност, вградени от самото начало. Няма нужда от флотилия от технологии, няма нужда от сложна карта на преплитащи се услуги. Само вие, Erlang и отвореният път на системната разработка.

В тази публикация ще направим една спокойна разходка из града от възможности на Erlang, педалирайки покрай историческите му забележителности, минавайки през парковете на функционалното програмиране и наслаждавайки се на живописните гледки на неговите разпределени среди. Ще видим оживените пазари на OTP, ETS и DETS, ще спрем за миг, за да оценим философията „Let it Crash“, и ще завършим с великолепната гледка към залеза на горещите актуализации на кода.

Така че освободете умовете си, сложете си каските и се присъединете към нас в това изследване на Erlang – езикът, който доказва, че понякога най-простият начин е най-добрият. Нека пътешествието започне!

Малко история и интересни факти

Докато се впускаме в нашето приключение с Erlang, нека отделим малко време, за да оценим средата, от която е произлязъл. Представете си края на 80-те години в Швеция – време на подплънки на раменете, синтезатори и, не толкова известно, раждането на език, който завинаги ще промени пейзажа на програмирането на разпределени системи.

Erlang е създаден от Ericsson, шведската телекомуникационна компания, за да решава проблеми, присъщи на телефонните приложения: масивен паралелизъм, отказоустойчивост и изисквания в реално време. Кръстен не на някоя неизвестна шведска поп група от онова време, а на математика Агнер Краруп Ерланг, той е проектиран да се справя с телефонни централи, където времето на престой е толкова желано, колкото внезапна градушка по време на летни празненства.

Първоначално вътрешен проект, Erlang е пуснат като отворен код през 1998 г., което позволява да бъде използван и оценен от разработчици по целия свят. Използван е в разнообразни приложения, от платформи за електронна търговия до компютърна телефония.

Един интересен факт, над който да размишлявате над следващата си чаша чай: синтаксисът на Erlang е вдъхновен от Prolog, но не позволявайте това да ви откаже. Въпреки нестандартния си синтаксис (или може би заради него), Erlang предлага уникален подход за решаване на сложни проблеми със степен на елегантност, която е освежаваща като хладен бриз от Северно море.

Ето, това беше кратка екскурзия в историята на Erlang. Това е език, роден от необходимост, оформен от предизвикателствата на телефонията и узрял под натиска на съвременните разпределени системи. А ние едва сме се докоснали до повърхността! Така че, нека продължим нашето пътешествие из света на Erlang, език, завладяващ колкото и историята, от която произлиза.

Известни проекти, написани на Erlang

Erlang, недооцененият маестро в света на програмирането, е движещата сила зад няколко известни проекта. Ето само няколко от тях:

  • WhatsApp: Глобалният гигант за съобщения избра Erlang, за да управлява милиони съобщения в секунда. Това е все едно да сте домакин на чаено парти за милиард гости и да се грижите чашата на всеки да бъде напълнена своевременно, без да разлеете и капка.
  • RabbitMQ: Този брокер на съобщения с отворен код е надеждният пощальон на разпределените съобщения. Надежден, ефективен и винаги навреме. Без Erlang, RabbitMQ би бил като пощенска станция без писма.
  • Amazon SimpleDB: Amazon взе сложността на управлението на бази данни и я превърна в разходка в парка, всичко това благодарение на Erlang. SimpleDB предлага бързо и надеждно съхранение и извличане на данни, правейки управлението на данни лесно като да си поръчаш сладкиш в любимото кафене.

Всеки от тези проекти демонстрира способността на Erlang да се справя с мащабни системи с голямо натоварване с грацията на добре обучен иконом. Той е програмният еквивалент на пълна английска закуска – засищаща, надеждна и гарантирано подготвяща ви за деня.

Актьорният модел и неговото превъзходство над традиционните механизми за заключване на нишки

В забързания свят на софтуера управлението на паралелни задачи често се усеща като регулиране на движението на особено хаотично кръгово кръстовище. Традиционните механизми за заключване на нишки са светофарите, които диктуват потока, предотвратяват сблъсъци, но често водят до разочароващи изчаквания и взаимни блокировки (deadlocks). Те осигуряват структура и ред, но за сметка на пропускателната способност и производителността.

И тук се появява Erlang, яхнал отново своето колело, този път доставяйки актьорния модел – различен подход към паралелизма. Представете си град, в който трафикът е заменен от рой колоездачи, всеки от които носи съобщение до определена дестинация. Те се движат независимо, без да се влияят от това, което правят останалите, доставят съобщенията си и отговарят на тези, които получават. Ако един колоездач претърпи инцидент, това не спира целия град. Вместо това, нов колоездач поема работата, съобщението се доставя и животът продължава.

Това е същността на актьорния модел. В Erlang всеки актьор (паралелен процес) е като колоездач. Те са леки, могат да наброяват милиони и комуникират чрез обмен на съобщения. Важното е, че те не споделят нищо, което елиминира нуждата от заключвания и гарантира, че ако един актьор се провали, останалите могат да продължат необезпокоявани.

% Spawning a new actor

Pid = spawn(fun() ->

receive

{From, Message} ->

From ! {self(), Message}

end

end).

% Sending a message to the actor

Pid ! {self(), hello}.

% Receiving a message from the actor

receive

{Pid, Message} ->

io:format("Received ~p~n", [Message])

end.

С този подход Erlang елегантно заобикаля проблемите на традиционния паралелизъм. Това е подобно на замяната на задръстена пътна мрежа с ефикасна куриерска служба с велосипеди. Актьорният модел тогава не е просто глътка свеж въздух, а порив на вятъра, който ни тласка напред в сферата на паралелизма с лекота и стил.

Erlang в разпределена среда

Представете си величествен симфоничен оркестър, в който всеки музикант изпълнява своята партия, перфектно синхронизиран, за да създаде очарователна хармония. В сферата на разпределените системи Erlang е маестрото, дирижиращ множество независими процеси, за да работят в унисон и да създадат безпроблемно потребителско изживяване.

Подходът на Erlang към разпределените системи е освежаващо директен като сандвич с краставица по време на следобеден чай. Езикът е проектиран с ясното разбиране, че в разпределена среда отказът не е изключение, а очакване. Като такъв, той третира процесите като изолирани единици, комуникиращи чрез предаване на съобщения. Този подход, подобен на учтивото подаване на млякото по време на чай, избягва нуждата от заключвания или споделено състояние, които често могат да доведат до объркания еквивалент в паралелните изчисления на разлят чай и разстроени гости.

Нека разгледаме един пример. Да предположим, че имаме два Erlang възела, Alice и Bob, и те искат да споделят приятна информация, да речем, последните резултати от крикет.

%% On Alice's node

BobNode = 'bob@otherhost'.

net_kernel:connect_node(BobNode).

{BobNode, !, "The score is 100 for 2"}.

%% On Bob's node

receive

Message -> io:format("~p~n", [Message])

end.

И воала! Alice предава съобщението на Bob по безпроблемен и прост начин. Системата за предаване на съобщения на Erlang е асинхронна, което означава, че Alice не трябва да чака Bob да получи съобщението. Тя може да продължи с другите си задачи, като например да пече сладкиши или да следи други мачове по крикет.

Друга уникална характеристика на Erlang в разпределена среда е концепцията му за агенти и управление на състоянието. Агентът по същество е процес, който поддържа състояние и извършва операции, когато му бъде наредено чрез съобщения. Той е като предан иконом, винаги готов и очакващ да откликне на нуждите ви.

%% A simple agent storing a number and supporting increment and get operations

start() -> spawn(fun loop/1).

loop(N) ->

receive

{increment, From} ->

From ! {result, N + 1},

loop(N + 1);

{get, From} ->

From ! {result, N},

loop(N)

end.

С тези функции Erlang предлага възхитителна алтернатива на често прекалено усложнените решения за създаване на разпределени системи. Това е като да изберете спокойна разходка из английската провинция пред трескаво препускане през оживен град. Освежаващо, нали?

Инструментите на Erlang: OTP, ETS и DETS

Ако Erlang е елегантният велосипед в света на програмирането, то OTP (Open Telecom Platform) е комплектът скорости, които превръщат изкачването на стръмнини в детска игра. OTP е колекция от междинен софтуер, библиотеки и инструменти, предназначени да подпомогнат изграждането на мащабируеми и лесни за поддръжка приложения. Той предоставя удобството на добре обмислени структури, които могат да се използват за организиране на кода, обработка на грешки и управление на системното поведение.

Представете си, ако щете, OTP като комплект инструменти за велосипед, включващ уред за проверка на веригата, комплект шестограми и лепенки за гуми. Той има всичко необходимо за гладко пътуване. Например, GenServer на OTP се държи като надежден двигател, предоставяйки клиент-сървър архитектура, която ви помага да управлявате състояние, да обработвате синхронни и асинхронни повиквания и да се справяте със системни грешки.

%% API

-export([start_link/0]).

%% gen_server callbacks

-export([init/1, handle_call/3, handle_cast/2, handle_info/2,

terminate/2, code_change/3]).

start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) -> {ok, 0}.

handle_call(_Request, _From, State) -> {reply, ok, State}.

Междувременно, в света на съхранението на данни в Erlang, Erlang Term Storage (ETS) и Disk Erlang Term Storage (DETS) са като просторната кошница за багаж и здравия заден багажник на вашия велосипед. ETS осигурява съхранение в паметта, място, където бързо да приберете данните си, докато сте в движение. DETS, от друга страна, е вашето надеждно хранилище за по-големи количества данни, които трябва да бъдат запазени след рестартиране.

1> Tab = ets:new(test_table, []).

2> ets:insert(Tab, {key, value}).

3> ets:lookup(Tab, key).

[{key,value}]

С OTP, ETS и DETS на ваше разположение, вие сте готови да се впуснете дори в най-предизвикателните програмни пътешествия. Така че, запазете спокойствие, продължавайте да въртите педалите и оставете инструментите на Erlang да се погрижат за неравностите по пътя.

Elixir: модерният наследник на Erlang

Нека сега обърнем внимание на Elixir, по-малкият брат на Erlang, преливащ от модерен чар и освежаващ младежки плам. Elixir е като онзи модерен нов магазин за велосипеди в Шордич, който прави традиционния Erlang велосипед още по-привлекателен с елегантен дизайн и лъскави нови функции.

Elixir се възползва от същата здрава основа като Erlang, наследявайки неговия паралелизъм, отказоустойчивост и възможности за разпределени системи. Въпреки това, той добавя слой синтактична захар, която го прави по-достъпен за разработчици, идващи от други езици. Това е все едно да смените стария звънец на колелото си с клаксон с разнообразни мелодии.

Една от най-интересните характеристики на Elixir е метапрограмирането. То позволява на разработчиците да пишат код, който генерира код. Представете си, че колелото ви може да сглоби друго колело, докато го карате. Нещо такова е, но с по-малко хвърчащи гайки и болтове.

Elixir също така предоставя красиви абстракции за създаване на SQL заявки, HTML шаблони и езици, специфични за дадена област (DSLs). Например, Ecto е обвивка за бази данни и генератор на заявки в Elixir:

import Ecto.Query

query = from u in "users", where: u.age > 30, select: u.name

В заключение, Elixir предлага модерен и достъпен поглед върху здравите възможности на Erlang. Той е доказателство за факта, че можеш да имаш хем вълкът сит, хем агнето цяло, или в нашия случай – хем да караш колело, хем да сглобяваш такова. Така че, защо не пробвате Elixir? Може да се окаже, че е точно вашата скорост.

„Let it Crash“ и надзорните дървета

Нека сега обърнем внимание на философията „Let it Crash“, ръководен принцип в Erlang, който е толкова нетрадиционен, колкото да сервираш пълна английска закуска за вечеря, но също толкова удовлетворяващ.

В повечето езици modus operandi по отношение на грешките е да се предотврати тяхната поява на всяка цена. Но Erlang, като един истински особняк, възприема различен подход. Той насърчава разработчиците да пишат код, който върши работата си при нормални условия, и да не се тревожат прекалено за всеки възможен начин, по който нещата могат да се объркат. Вместо това, нека се срине, и да има система, която може да се справи с тези сривове елегантно.

Тук се появяват надзорните дървета (Supervision Trees), отговорът на Erlang на Кралската гвардия, винаги готови да се намесят, когато нещо се обърка. Надзорниците (supervisors) са специални процеси, които наблюдават други процеси, известни като работници (workers). Ако един работен процес се срине, надзорникът може да го рестартира, поддържайки стабилността на системата.

init([]) ->

RestartStrategy = {one_for_one, 5, 10},

Children = [

{worker1, {worker1, start_link, []}, permanent, 5000, worker, [worker1]},

{worker2, {worker2, start_link, []}, permanent, 5000, worker, [worker2]}

],

{ok, {RestartStrategy, Children}}.

В този фрагмент от код дефинираме надзорник, който наблюдава два работни процеса. Ако някой от тези работни процеси се срине, надзорникът ще ги рестартира, осигурявайки устойчивостта на системата.

Така философията „Let it Crash“ на Erlang, съчетана с надзорни дървета, създава система, която е здрава пред лицето на грешките, подобно на здрав дъб, който стои непоклатимо сред буря. Това е глътка свеж въздух в един често прекалено предпазлив свят, доказвайки още веднъж, че Erlang не е просто поредният език, а изцяло нов начин на мислене за надеждността на системите.

Горещи актуализации на кода в Erlang

Представете си, ако щете, сложен, високотехнологичен питстоп във Формула 1. Колата влиза с висока скорост в бокса, спира и в трескава дейност гумите се сменят, горивото се допълва и се извършват дребни ремонти. Всичко това се случва за броени секунди, без дори да се изключва двигателят. Това, драги читатели, е накратко функцията за гореща актуализация на кода в Erlang.

Erlang, с грацията и финеса на опитен екип в бокса, позволява горещи актуализации на кода – възможността да се променя работеща система, без да се спира за чаша чай, камо ли за пълно рестартиране. Тази функция е особено важна за системи, които изискват висока наличност. В индустрия, където времето на престой е толкова желано, колкото внезапна градушка по време на мач по крикет, горещата смяна на код в Erlang е триумф.

Средата за изпълнение на Erlang позволява съвместното съществуване на две версии на един модул: текущата и старата. Когато заредите нова версия на модул, всички процеси, изпълняващи старата версия, завършват текущото си извикване на функция, преди да мигрират към новата. Преходът е плавен като добре смазана топка за крикет, изплъзваща се от ръцете на полеви играч.

За да илюстрираме, нека разгледаме сценарий, в който актуализираме прост ехо сървър, за да добавя поздрав към отговорите си. В света на Erlang такава актуализация би се осъществила безпроблемно. Ехо сървърът ще продължи да функционира по време на актуализацията, блажено невеж за трансформацията, която току-що е претърпял.

1> c(echo_server).

{ok,echo_server}

2> l(echo_server).

{module,echo_server}

Ако сега изпратим съобщение до нашия сървър, ще получим новото поведение:

Както виждате, сървърът дори не се задави по време на актуализацията си. Така че, ето наздравица за Erlang, езикът, който никога няма нужда да си поема дъх. Горещите актуализации на кода са само една от многото функции, които правят Erlang страховит играч в света на високите залози на разпределените системи. А това, драги читателю, заслужава всяка частица от вашето внимание.

Заключение: Предимството на Erlang

Докато спираме плавно в края на нашето пътешествие из Erlang, е време да отделим момент и да оценим пейзажа, който прекосихме. Видяхме обширните панорами на разпределените системи, усетихме свежия въздух на функционалното програмиране и се възхитихме на елегантната архитектура на горещите актуализации на кода.

На фона на оживения метрополис от алтернативни технологии, Erlang се откроява като спокоен парк, предлагащ простота сред сложността. Той е като остров на спокойствието по оживените улици на Лондон, предоставящ оазис на здравия разум сред автобусите Docker, такситата Kubernetes и метрото Kafka.

Erlang не е просто поредният език; той е промяна в гледната точка, нов начин на мислене за системния дизайн, който може да бъде освежаващ като хладен бриз в горещ летен ден. Учейки Erlang (и неговия модерен братовчед, Elixir), вие не просто добавяте още един инструмент към своя арсенал. Вие фундаментално променяте начина, по който подхождате към проблемите, придобивайки ново разбиране за отказоустойчивост, разпределеност и паралелизъм.

Така че, следващия път, когато се почувствате претоварени от трафика в час пик на системната разработка, спомнете си за Erlang. Слезте от автобуса, оставете таксито и вместо това изберете простата елегантност на велосипеда. Пътят може да изглежда различен, но ви обещавам, че пътуването си заслужава.

В заключение, драги читателю, ученето на Erlang и Elixir не е просто акт на придобиване на умения, а стъпка към това да станете по-добър и по-гъвкав разработчик. В крайна сметка, както казват в света на колоезденето, животът е като карането на колело – за да запазиш равновесие, трябва да продължиш да се движиш. Така че, продължавайте напред, продължавайте да учите и винаги, винаги си носете каската. Светът навън е луд и Erlang може да се окаже здравият разум, от който се нуждаете.