Jak stworzyć niezawodny system informatyczny?


System informatyczny to zbiór powiązanych ze sobą elementów, w którym następuje przepływ lub przetwarzanie danych w sposób zautomatyzowany, najczęściej przy użyciu techniki komputerowej. Na systemy informatyczne składają się przede wszystkim takie elementy, jak sprzęt i zainstalowane na nim oprogramowanie.

Jaki powinien być udany system informatyczny? Jedną z kluczowych pożądanych cech jest niezawodność. System powinien działać zawsze i, co więcej, powinien działać zawsze prawidłowo. Czy jednak jest to w ogóle możliwe?

Systemy tworzone są przez ludzi, którzy są przecież omylni, a zatem zawodni. Słynne przysłowie mówi, że tylko ten nie popełnia błędów, kto nic nie robi. Różnego typu błędy mogą być popełniane na każdym etapie tworzenia i zarządzania systemem, wpływając niekorzystnie na jego działanie.

Niezawodność systemu zależy również od wykorzystywanej infrastruktury obejmującej między innymi serwery aplikacji, a także wszystkie urządzenia sieciowe oraz kanały transmisji zapewniające komunikację między tymi serwerami a użytkownikami końcowymi. Każdy z elementów infrastruktury może ulec awarii wskutek rozmaitych czynników wewnętrznych i zewnętrznych.

Ustaliliśmy zatem, że wszystkie systemy informatyczne budowane są z zawodnych elementów przez omylnych ludzi. Czy zatem da się stworzyć niezawodny system? Mógłbym odpowiedzieć, że nie i w tym miejscu zakończyć niniejszy artykuł. Temat jest jednak nieco bardziej złożony i jego głębsza analiza może doprowadzić nas do nieco innych, ciekawych wniosków.

Nie da się stworzyć systemu niezawodnego w 100 procentach, ale jest możliwe stworzenie systemu wystarczająco niezawodnego w zależności od przyjętej tolerancji, na przykład niezawodnego na 99,9 procent. Odpowiednie modele matematyczne mogą pozwolić nam na wyliczenie, w jaki sposób i jakimi zasobami tworzyć system, aby spełniał określone kryteria niezawodności. Osiągnięcia technologiczne ostatnich lat pozwalają z kolei minimalizować koszty budowania systemów o coraz większej niezawodności. Jak zatem winniśmy budować system?

Kluczowym słowem jest ‘redundancja’, czyli zastosowanie nadmiarowej ilości zasobów. Przykładowo, jeśli istnieje 50 procent ryzyka, że dany element się zepsuje, zdublujmy go, tak aby co najmniej jeden z dwóch równolegle działających elementów wystarczył do podtrzymania prawidłowego działania systemu. Wówczas ryzyko awarii spada z 50 do 25 procent. Jeśli dodamy jeszcze trzeci równolegle pracujący element, ryzyko ponownie spadnie dwukrotnie – do 12,5 procent. I tak dalej… W ten sposób teoretycznie moglibyśmy ryzyko danego typu awarii zmniejszyć do zera i tym samym zapewnić 100 procent niezawodności danej części systemu, zastosowawszy nieskończoną ilość dublujących się elementów. To oczywiście nie jest wykonalne, ale możemy zbliżyć się do owego ideału tak bardzo, jak tylko chcemy –  pod warunkiem jednak, że nasze chęci są wsparte odpowiednio wysokim budżetem na zakup potrzebnych elementów, zapewnienie dla nich odpowiedniej przestrzeni czy chociażby zasilanie ich energią elektryczną.

Sprzęt

Na niezawodność systemu mocno wpływa niezawodność tworzących go serwerów. Zdecydowanie najczęściej psującym się komponentem serwera są jego dyski twarde. Z tego powodu standardem jest stosowanie macierzy RAID funkcjonujących na zasadzie zapisywania każdej porcji danych równocześnie na kilku dyskach. Dzięki temu awaria pojedynczego dysku lub nawet paru dysków nie powoduje zakłóceń w działaniu całego systemu. Co więcej, zastosowanie RAID może dodatkowo przyspieszyć zapis i odczyt danych, natomiast wymiana zepsutego dysku może odbywać się przy działającym systemie, bez wyłączania serwera.

Kolejnym podatnym na awarię elementem serwera jest moduł zasilania. W związku z tym warto wyposażyć serwer w co najmniej dwa takie moduły. Przy okazji daje to możliwość podłączenia serwera do dwóch niezależnych źródeł zasilania, dzięki czemu nasz serwer nie wyłączy się, gdy w jednym ze źródeł zabraknie prądu.

Skąd wziąć dwa niezależne źródła zasilania? Zazwyczaj zewnętrzne źródło zasilania jest jedno, ale możemy i powinniśmy posiadać dla niego alternatywę w postaci urządzenia UPS, które za pomocą swoich akumulatorów i odpowiedniej elektroniki podtrzyma bez żadnych istotnych zakłóceń zasilanie naszych urządzeń w przypadku zakłóceń w dostawie prądu.

Im więcej akumulatorów zainstalujemy w naszym urządzeniu UPS, na tym więcej czasu wystarczy prądu. Jednocześnie jednak urządzenie będzie nas więcej kosztować i zajmie więcej przestrzeni. Dodatkowy problem może stanowić ciężar akumulatorów, wymagający takiego ich rozmieszczenia, aby nie przekroczyć dopuszczalnej nośności podłogi i tym samym nie dopuścić do ryzyka katastrofy budowlanej.

UPS jest kluczowym urządzeniem w kontekście podtrzymania zasilania urządzeń, ale w celu zabezpieczenia na wypadek wielogodzinnych  przerw w zasilaniu możemy potrzebować dodatkowego rozwiązania, czyli generatora prądu wykorzystującego silnik Diesla podobny do tych spotykanych w samochodach. Zasilane takim generatorem komputery będą działać tak długo, na jak długo wystarczy nam paliwa, które można przecież na bieżąco dolewać.

Nawet najlepiej przemyślany konstrukcyjnie i zabezpieczony serwer może ulec awarii, więc powinniśmy posiadać co najmniej dwa serwery.

Aby nasze wydzielające dużo ciepła komputery się nie przegrzały i działały dobrze odpowiednio długo, konieczne jest utrzymywanie optymalnej temperatury otoczenia. Wzrost temperatury o drobne 5 stopni Celsjusza może dwukrotnie zmniejszyć żywotność niektórych elementów serwerów oraz baterii UPSa i tym samym bardzo zwiększyć ryzyko awarii. Potrzebna jest odpowiednia instalacja klimatyzacji dostarczająca suche zimne powietrze z przodu serwerów i odprowadzająca ciepłe powietrze wydzielane przez wentylatory znajdujące się z tyłu. Układ klimatyzacji może ulec awarii, doprowadzając w konsekwencji do dużego wzrostu temperatury, skutkującego przegrzaniem i wyłączeniem się serwerów. Dlatego potrzebne są co najmniej dwa niezależne układy chłodzenia.

Aby nasz system działał niezawodnie, użytkownicy powinni mieć stabilne połączenie z naszymi serwerami. Do tego potrzebujemy odpowiednich łączy telekomunikacyjnych. Ponieważ żadne łącze nie zapewni nam 100 procent niezawodności, takie łącza powinny być co najmniej dwa, w pełni niezależne od siebie. Oznacza to, że nie powinny mieć one żadnego elementu wspólnego, tak aby awaria jednego elementu nie odłączyła naszej serwerowni od świata. Tym elementem wspólnym nie może być również eter, dlatego nie mogą być to dwa łącza bezprzewodowe oparte o radiolinie, ponieważ anomalie pogodowe typu burze, ulewy mogłyby równocześnie mocno zakłócić działanie wszystkich takich łączy.

Bardziej stabilne są łącza kablowe, w szczególności światłowodowe, ale wiązki kabli nie powinny przebiegać tuż obok siebie, aby pewnego dnia jakiś nieświadomy operator koparki dosłownie nie odciął naszego systemu od świata,  przecinając nieumyślnie biegnącą w ziemi delikatną wiązkę światłowodową i tym samym powodując kilkugodzinną awarię łącza. Tego typu incydenty zdarzają się zaskakująco często.

Wygląda więc na to, że odpowiednie zabezpieczenie naszego serwera może kosztować nas wielokrotnie więcej niż sam nawet bardzo dobrej jakości serwer, a dodatkowo musielibyśmy uzyskać od operatorów telekomunikacyjnych informacje (na temat budowy łączy, lokalizacji wiązek kablowych), którymi zazwyczaj nie chcą się oni dzielić ze swoimi klientami.

Dodatkowo przydałaby się odpowiednia instalacja przeciwpożarowa, która skutecznie stłumi w zarodku wszelkie źródła ognia, nie uszkadzając znajdujących się na serwerach danych. W związku z tym nie nadaje się do tego klasyczna instalacja z gaszeniem wodnym. Standardem jest instalacja argonowa, której działanie polega na wypełnieniu odpowiednio uszczelnionego pomieszczenia niepalnym gazem, tak aby ogień zgasł z powodu braku tlenu. Oprócz samego kosztownego zestawu urządzeń gaszenia argonem potrzebne jest wówczas również zapewnienie pełnej szczelnej izolacji pomieszczeń serwerowych od reszty budynku.

Nawet jeśli udałoby nam się spełnić wszystkie powyższe warunki, to i tak nie możemy założyć pełnej niezawodności systemu, gdyż nie możemy wykluczyć katastrofy, która zniszczy naszą serwerownię mimo wszelkich zabezpieczeń (trzęsienie ziemi, atak terrorystyczny, powódź i inne kataklizmy). Co zatem zrobić, żeby zabezpieczyć się przed tego typu zagrożeniami? Ponownie możemy zastosować redundancję, ale tym razem na poziomie całych serwerowni, czyli zbudować co najmniej dwie oddalone od siebie o wiele kilometrów serwerownie, z których każda będzie spełniać wszystkie opisane powyżej warunki. Wówczas koszty wzrosną nam co najmniej dwukrotnie, ale teoretycznie żadna pojedyncza katastrofa nie będzie w stanie unieruchomić naszego systemu…

Wirtualizacja

Zabezpieczanie systemu poprzez jego rozpraszanie na różne fizyczne serwery i różne lokalizacje przynosi dodatkowe wyzwania. W jaki sposób sprawić, by taki rozporoszony na różnych komputerach system działał w spójny sposób? W jaki sposób sprawić, aby poszczególne serwery synchronizowały się, czyli żeby użytkownik widział to samo niezależnie od tego, która część infrastruktury jest w danym momencie sprawna i dostępna, a która nie? To temat na oddzielną serię artykułów… Tym niemniej maksymalnie streszczając go, można stwierdzić, iż z pomocą przychodzi tu przede wszystkim coraz bardziej zaawansowana wirtualizacja. Do niedawna najbardziej rewolucyjnym rozwiązaniem było stosowanie wirtualizacji całych serwerów, co pozwalało na posiadanie wielu serwerów wirtualnych na jednym fizycznym serwerze i przenoszenie ich między nimi. Tego typu operacje nie były jednak zazwyczaj ani proste, ani szybkie. Kolejną rewolucją okazał się Docker, czyli pakowanie aplikacji w kontenery, które w porównaniu z serwerami wirtualnymi są znacznie mniejsze, lżejsze, o wiele lepiej zoptymalizowane pod kątem pełnionych funkcji. Kontenery można szybko tworzyć, zamykać, przenosić w zależności od dostępności hostów i w zależności od bieżącego obciążenia systemu. Te wszystkie działania mogą być w pełni zautomatyzowane za pomocą sterującego tymi kontenerami tak zwanego orkiestratora, takiego jak np. Kubernetes lub Docker Swarm.

Chmura

Po zapoznaniu się z wszystkimi opisanymi wyżej wytycznymi może nasunąć się jedno ważne pytanie:  czy budowa systemu w opisany wcześniej sposób, z wykorzystaniem sieci niezależnych, doskonale wyposażonych i zabezpieczonych centrów danych może się w ogóle się opłacać? Przeważnie nie. Niewiele systemów na świecie przynosi wystarczające przychody lub ma wystarczająco duże znaczenie, aby uzasadniać wszystkie wyżej wspomniane koszty.

Istnieje jednak sposób, by znacznie obniżyć koszty przy utrzymaniu najwyższych standardów. To rozwiązanie polega na tym, że duże firmy, które posiadają już odpowiednią infrastrukturę, udostępniają miejsce na swoich serwerach innym klientom i ich systemom. W rezultacie ogromne koszty po podziale na wielu klientów stają się znacznie bardziej akceptowalne.

Zamiast posiadać swoją własną bardzo kosztowną infrastrukturę, możemy wydzierżawić część cudzej infrastruktury ufając, że zarządzająca nią firma odpowiednio dba o stabilność platformy, na której będzie działał nasz system. To rozwiązanie potocznie nazywamy chmurą i myślę, że powyższe argumenty dobrze tłumaczą jej dużą popularność. Chmura stała się już standardem i jest wykorzystywana prawie wszędzie. Trzymanie danych w chmurze stało się standardem nawet w przypadku bardzo wrażliwych aplikacji, takich jak osobiste menedżery haseł. Ma to sens w przypadku odpowiednio silnych mechanizmów szyfrowania po stronie klienta. Chodzi o to, by ewentualny niepożądany dostęp do danych składowanych na serwerach w chmurze nie mógł spowodować ujawnienia owych haseł.

Dostawcy rozwiązań chmurowych, zwłaszcza ci wiodący (Amazon Web Services, Microsoft Azure, Google Cloud i inni) przechodzą regularne audyty i posiadają odpowiednie certyfikaty potwierdzające jakość, niezawodność zastosowanych rozwiązań i bezpieczeństwo powierzanych im danych. Wybierając dostawcę chmury, warto zwrócić uwagę na posiadane przez niego certyfikaty, by w dużej mierze na ich podstawie budować poziom zaufania.

Oprogramowanie

System informatyczny to nie tylko infrastruktura sprzętowa, ale także działające na niej oprogramowanie będące efektem pracy zespołu ludzi. Istotnym czynnikiem wpływającym na poziom niezawodności mogą być różnego błędy popełnione przy projektowaniu lub wytwarzaniu tego oprogramowania. Podobnie jak nie da się uniknąć awarii sprzętowych, nie można w pełni wyeliminować błędów, ale tu również możemy wykorzystać cały arsenał narzędzi, pozwalających kontrolować i minimalizować ryzyko wystąpienia błędu.

Ważne jest projektowanie i utrzymywanie systemu w odpowiedni, przemyślany sposób, z wykorzystaniem dostępnych dobrych praktyk. Opisują je standardy takie jak ITIL, stworzone dzięki wieloletniemu bagażowi doświadczeń, z którego możemy czerpać, aby uniknąć kosztownych błędów.

Sam proces tworzenia kodu również wymaga kompleksowego, przemyślanego podejścia, ustalenia odpowiednich reguł tworzenia oprogramowania, sprzyjających produktywności w połączeniu z minimalizacją ilości błędów.

Błędy mogą powstawać na każdym etapie. Jednym z pierwszych etapów jest ustalenie wytycznych odnośnie funkcjonalności budowanego systemu. Zwłaszcza w przypadku systemów modelujących złożone procesy biznesowe zrozumienie wymagań klienta i zaplanowanie odpowiedniej logiki biznesowej może okazać się dużym wyzwaniem, a błędy na tym etapie mogą skutkować trudnym do rozwiązania ciągiem problemów na dalszych etapach. Tu z pomocą przychodzi Domain Driven Design i w szczególności Event Storming, czyli techniki usprawniające pozyskanie wiedzy od tak zwanych ekspertów domenowych, a następnie zaprojektowanie systemu tak, aby wiernie opierał się na opisanym modelu procesów biznesowych. Kluczem do sukcesu jest dobra komunikacja na linii klient – analityk – programista. Wszystko po to, aby oczekiwania klienta zostały wiernie odzwierciedlone w stworzonym kodzie systemu. Wspomniane wyżej techniki mogą w tym bardzo pomóc.

Podobnie jak w przypadku infrastruktury, także w procesie programowania pomocne jest  zastosowanie swego rodzaju redundancji. Ryzyko powstania błędów jest mniejsze, gdy każdy kawałek kodu jest tworzony i weryfikowany przez więcej niż jedną osobę.  W praktyce sprowadza się to do obowiązkowego Code Review przed wdrożeniem każdej, najdrobniejszej nawet zmiany w oprogramowaniu. Każda taka zmiana musi być zweryfikowana przez drugiego programistę i wdrożenie następuje dopiero wtedy, gdy co najmniej dwie osoby mają przekonanie, że wdrażany kod jest optymalny i pozbawiony błędów.

Takie przekonanie jednak nie wystarcza, zwłaszcza w przypadku dużych systemów, z wieloma, często nieoczywistymi zależnościami. Ważne są również testy.

Wszystkie istotne funkcje systemu powinny być pokryte testami jednostkowymi weryfikującymi działanie nowej porcji kodu oraz jej wpływ na resztę systemu. Takie testy powinny być obowiązkowo uruchamiane przed wdrożeniem poprawki. Można również pójść parę kroków dalej i zastosować tak zwany Test Driven Development. W takim wypadku tworzenie kodu zaczynamy od napisania testów jednostkowych do przetestowania działania zaplanowanej zmiany. Po napisaniu prawidłowego testu programowanie aplikacji sprowadza się do stworzenia kodu, który sprawi, że stworzone wcześniej testy zaczną zwracać pomyślny rezultat. Takie podejście nieco ułatwia samo programowanie aplikacji i pozwala ograniczyć ryzyko błędów, pod warunkiem jednakże, że wcześniej przygotowaliśmy odpowiednio przemyślany i odpowiedniej jakości zestaw testów.

Potrzeba testowania nie ogranicza się do automatycznych testów jednostkowych. Po nich następują kolejne etapy testowania systemu, w coraz szerszym ujęciu: testy manualne, testy integracyjne i w końcu testy akceptacji.

Po testach następuje wdrożenie zmian, które również wymaga odpowiedniego podejścia, minimalizującego ryzyko powstania błędu na tym etapie. Ponieważ mamy tu do czynienia z niekiedy dość złożonymi, ale zazwyczaj powtarzalnymi czynnościami do wykonania, zdecydowanie najlepiej jest je zautomatyzować, korzystając z dostępnych narzędzi CI/CD. W ten sposób można zredukować ryzyko błędów na tym etapie niemal do zera. Zaprojektowanie i skonfigurowanie optymalnie działającego procesu wdrażania zmian wymaga określonej wiedzy i doświadczenia z zakresu DEVOPS.

Jeśli na dowolnym z etapów testowania zostanie wykryty błąd, wymaga on oczywiście naprawy. Jeśli nie jest ona wykonalna w szybkim czasie, konieczne może okazać się cofnięcie konkretnej zmiany, czy też prześledzenie historii zmian w systemie. W związku z tym koniecznością staje się stosowanie kontroli wersji, konkretnie narzędzia GIT, które jest obecnie bezkonkurencyjnym standardem. Jest ono niezbędne również przy samym wytwarzaniu, zwłaszcza w sytuacji  oprogramowania w sytuacji, gdy nad zmianami danego komponentu systemu pracuje równocześnie kilka osób i muszą one działać tak, aby wzajemnie nie zakłócać swojej pracy.

Podsumowanie

Nie jest możliwe stworzenie w pełni niezawodnego systemu. Możemy jednak zbliżyć się do owej idealnej niezawodności na niemal dowolnie bliską odległość, jednak każde kolejne zbliżenie może oznaczać wykładniczo rosnący poziom kosztów. Warto wiedzieć, jak liczyć poziom niezawodności w poszczególnych obszarach środowiska systemu i jakie wytyczne obrać, aby optymalnie połączyć poziom tolerancji z poziomem kosztów. Warto brać pod uwagę rozmaite dostępne rozwiązania (Chmura, Docker, metodyki wytwarzania oprogramowania), dobierać je w zależności od potrzeb i stosować je z głową, mając pełną świadomość ich zalet i ewentualnych stojących za nimi zagrożeń. Okazuje się zatem, że za zapewnieniem odpowiedniej niezawodności musi przede wszystkim stać zespół dobrze współpracujących ze sobą doświadczonych ekspertów z wielu obszarów. Bezpieczeństwo i niezawodność systemu to złożony temat obejmujący  wiele różnych dziedzin. Do każdej z nich należy podejść z należytą uwagą, pamiętając, że cały system jest tak dobry, jak jego najsłabsze ogniwo.


Piotr Zyśk

O Piotr Zyśk

Od 2019 roku jako programista fullstack w Atenie zgłębiam głównie technologie .Net i Angular. Wcześniej przez kilkanaście lat zajmowałem się szeroko pojętym wsparciem administracyjno-programistycznym w dla dużej sieci call-center. W wolnym czasie lubię wykorzystywać swój komputer na różne sposoby, np. jako studio do tworzenia muzyki lub urządzenie do symulacji rajdów i wyścigów samochodowych. Często również można spotkać mnie w podolsztyńskich lasach na rowerze, z aparatem fotograficznym.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *