Наследен код е навсякъде. И тъй като скоростта на разпространение на кода продължава да се увеличава експоненциално, все повече и повече от този код се прехвърля в наследствен статус. В много големи организации поддръжката на наследени системи отнема повече от 90% от ресурсите на информационните системи.
Необходимостта от модернизиране на наследения код и системи, за да отговорят на настоящите изисквания за производителност и обработка, е широко разпространена. Тази публикация предоставя казус на използването на Ерланг език за програмиране и базиран на Erlang CloudI Архитектура, ориентирана към услуги (SOA), за адаптиране на наследения код - по-специално на колекция от изходен код на C от десетилетия - към 21 век.
В много големи организации поддръжката на наследени системи отнема повече от 90% от ресурсите на информационните системи.Преди години бях голям фен на текстови мултиплейър онлайн игри, известни като Подземията за много потребители ( Кал ). Но те винаги бяха осеяни с проблеми с производителността. Реших да се потопя отново в купчина изходен код на десетилетия и да видя как можем да модернизираме този наследствен код и да изтласкаме тези ранни онлайн игри до техните граници. На високо ниво този проект беше чудесен пример за използвайки Erlang за адаптиране на наследения софтуер към изискванията на 21-ви век.
Кратко резюме:
Всички масови мултиплейър онлайн ролеви игри ( MMORPG ) - като World of Warcraft и EverQuest - са разработили функции, чийто ранен произход може да бъде проследен до по-стари текстови мултиплейър онлайн игри, известни като Подземията за много потребители ( Кал ).
Първата кал беше Essex MUD на Рой Трубшоу (или Кал1 ), който първоначално е разработен през 1978 г., използвайки езика на асемблера MARO-10 на DEC PDP-10, но е преобразуван в BCPL, предшественик на езика за програмиране C (и работи до 1987 г.). (Както можете да видите, тези неща са по-стари от повечето програмисти.)
MUD постепенно придобиват популярност в края на 80-те и началото на 90-те години с различни MUD кодови бази, написани на C. Кодовата база DikuMUD например е известна като корен на една от най-големите дървета на изведен MUD изходен код, с най-малко 51 уникални варианта, всички базирани на един и същ изходен код DikuMUD. (През този период, между другото, MUDs станаха алтернативно известни като „Унищожител на няколко студенти“ поради броя на студентите, които не успяха да се обучат поради обсебеността си от тях.)
Историческият C MUD изходен код (включително DikuMUD и неговите варианти) е пълен с проблеми с производителността поради съществуващи ограничения по време на създаването му.
Тогава нямаше лесно достъпна библиотека за резби. Освен това нишките биха затруднили поддръжката и модификацията на изходния код. В резултат на това всички MUD бяха еднонишкови.
Всяка част от кода забавя обработката на една отметка. И ако някое изчисление принуди обработката да обхване повече време отколкото само едно отметка, MUD изостава, засягайки всеки свързан играч.По време на единичен „тик“ (нарастване на вътрешния часовник, който проследява прогресията на всички игрови събития), изходният код на MUD трябва да се обработи всеки игра събитие за всеки свързан контакт. С други думи: всяка част от кода забавя обработката на една отметка. И ако някое изчисление принуди обработката да обхване по-дълго от единичен отметка, MUD изостава, засягайки всеки свързан играч.
С това изоставане играта веднага става по-малко ангажираща. Играчите гледат безпомощно, докато героите им умират, като собствените им команди остават необработени.
За целите на този експеримент за модернизиране на наследено приложение избрах SillyMUD , историческо производно на DikuMUD, което е повлияло на съвременните MMORPG и проблемите с производителността, които те споделят. През 90-те години играех кал, която беше получена от кодовата база SillyMUD, така че знаех, че изходният код ще бъде интересна и донякъде позната отправна точка.
Изходният код SillyMUD е подобен на този на други исторически C MUD, тъй като е ограничен до около 50 едновременни играчи (64, за да бъдем точни, въз основа на изходния код).
Забелязах обаче, че изходният код е модифициран поради съображения за производителност (т.е., за да се натисне едновременното ограничение на плейъра). По-конкретно:
CloudI беше обсъдени по-рано като решение за разработване на полиглот поради отказоустойчивостта и мащабируемостта, които осигурява.
CloudI предоставя абстракция на услуги (за предоставяне на ориентирана към услуга архитектура ( SOA )) в Erlang, C / C ++, Java, Python и Ruby, като същевременно запазва софтуерните грешки изолирани в рамките на CloudI. Толерантността към грешки се осигурява чрез внедряването на Erlang на CloudI, като се разчита на характеристиките на Erlang, устойчиви на грешки и неговото изпълнение на Актьорски модел . Тази устойчивост на грешки е ключова характеристика на внедряването на Erlang на CloudI, както целият софтуер съдържа грешки .
CloudI също така предоставя сървър за приложения, за да контролира продължителността на изпълнението на услугата и създаването на сервизни процеси (или като процеси на операционната система за езици за програмиране, които не са Erlang, или като процеси на Erlang за услуги, внедрени в Erlang), така че изпълнението на услугата да се извършва без външно състояние надеждност. За повече вижте моя предишен пост .
Историческият изходен код на C MUD предоставя интересна възможност за интегриране на CloudI предвид проблемите му с надеждността:
С интегрирането на CloudI грешките в стабилността на сървъра все още могат да бъдат коригирани нормално, но въздействието им е ограничено, така че работата на сървъра на играта не винаги се влияе, когато неоткрита преди това грешка причинява отказ на вътрешна игрална система. Това предоставя чудесен пример за използването на Erlang за налагане на устойчивост на грешки в наследена кодова база.
Оригиналната кодова база е написана да бъде еднопоточна и силно зависима от глобалните променливи. Целта ми беше да запазя старата функционалност на изходния код, като същевременно я модернизирам за днешна употреба.
С CloudI успях да запазя изходния код с една нишка, като същевременно осигурявах мащабируемост на връзката на сокета.
Целта ми беше да запазя наследената функционалност на изходния код, като същевременно я адаптирам за съвременна употреба.Нека прегледаме необходимите промени:
Буферирането на изхода на конзолата SillyMUD (терминален дисплей, често свързан с Telnet ) вече беше на мястото си, но някои преки дескриптори на файлове изискваха буфериране (за да може изходът на конзолата да се превърне в отговор на заявка за услуга на CloudI).
Обработката на сокета в оригиналния изходен код разчита на select()
извикване на функция за откриване на вход, грешки и шанс за изход, както и за пауза за отметка от 250 милисекунди преди обработка на чакащите игрови събития.
Интеграцията на CloudI SillyMUD разчита на входящи заявки за услуги за въвеждане, докато прави пауза с C CloudI API's cloudi_poll
функция (за 250 милисекунди преди обработка на същите чакащи събития в играта). Изходният код SillyMUD лесно се изпълнява в CloudI като услуга CloudI, след като е интегриран с C CloudI API (въпреки че CloudI предоставя API на C и C ++ , използвайки C API по-лесно улеснена интеграция с изходния код на SillyMUD’s C).
Интеграцията на CloudI се абонира за три основни модела на имена на услуги за обработка на събития за свързване, прекъсване на връзката и геймплей. Тези модели на имена идват от извикването на C CloudI API Абонирай се в изходния код на интеграцията. Съответно, или WebSocket връзките, или Telnet връзките имат дестинации за имена на услуги за изпращане на заявки за услуги, когато се установят връзки.
Поддръжката на WebSocket и Telnet в CloudI се осигурява от вътрешни услуги на CloudI (cloudi_service_http_cowboy
за поддръжка на WebSocket и cloudi_service_tcp
за поддръжка на Telnet). Тъй като вътрешните CloudI услуги са написани на Erlang, те могат да се възползват от изключителната мащабируемост на Erlang, като същевременно използват CloudI абстракция на услугата който предоставя функциите на API на CloudI.
Като се избягва обработката на сокета, възникват по-малко обработки при грешки в сокета или ситуации като връзка смърт (при което потребителите са изключени от сървъра). По този начин премахването на обработката на сокета на ниско ниво се справи с основния проблем с мащабируемостта.
Премахването на обработка на сокета на ниско ниво е адресирано до основния проблем с мащабируемостта.Но проблемите с мащабируемостта остават. Например MUD използва файловата система като локална база данни както за статични, така и за динамични елементи на играта (т.е. играчите и техния напредък, заедно със световните зони, обекти и чудовища). Рефакторирането на наследения код на MUD, вместо да разчита на услуга CloudI за база данни, ще осигури допълнителна толерантност към грешки. Ако използвахме база данни, а не файлова система, множество процеси на услуга SillyMUD CloudI могат да се използват едновременно като отделни сървъри за игри, като държат потребителите изолирани от грешките по време на изпълнение и намаляват престоя.
Има три основни области на подобрение:
Така че, с простата интеграция на CloudI, броят на връзките се мащабира с три порядъка, като същевременно осигурява толерантност към грешки и увеличава ефективността на същия стария геймплей.
Erlang е осигурил 99,9999999% ъптайм (по-малко от 31,536 милисекунди престой на година) за производствените системи. С CloudI ние носим същата надеждност и за други програмни езици и системи.
Освен доказването на жизнеспособността на този подход за подобряване на застоялия изходен код на наследения сървър за игра (SillyMUD е последно модифициран преди повече от 20 години през 1993 г.!), Този проект демонстрира на по-широко ниво как Erlang и CloudI могат да бъдат използвани за модернизиране на наследени приложения и да предоставят грешки -толерантност, подобрена производителност и висока наличност като цяло. Тези резултати притежават обещаващ потенциал за адаптиране на наследения код към 21-ви век, без да е необходим основен софтуерен ремонт.