Pharos

Monitoring uptime, publiczna strona statusu i obsługa incydentów w jednym binarium (Go + wbudowany SQLite), stawianym jednym poleceniem. Dwie rzeczy, które go wyróżniają: operacje incydentowe żyjące w Discordzie i uptime, który nie zaokrągla na swoją korzyść. Otwarty kod, self-hosting.

Pharos
TL;DR

Pharos to monitoring uptime, publiczna strona statusu i obsługa incydentów spięte w jednym binarium na Go z wbudowanym SQLite. Stawiasz go jedną komendą, hostujesz u siebie, a uptime nie zaokrągla się na własną korzyść: czas bez obserwacji to nie "dostępny", tylko "nieznany". Incydenty prowadzisz z Discorda, kod jest otwarty, a liczba na stronie statusu znaczy dokładnie to, co mówi.

Wprowadzenie

Strony statusu mają jedną brzydką właściwość: prawie wszystkie kłamią na swoją korzyść. Kiedy sonda przestaje odpytywać usługę, bo padł sam monitoring albo skończył się okres retencji, większość narzędzi po prostu nie wlicza tej dziury do statystyki. Efekt jest taki, że wykres pokazuje 100 procent dostępności przez czas, w którym nikt niczego nie mierzył. Do tego dochodzą okna serwisowe, które magicznie nie psują słupka, i nagle masz panel, który wygląda świetnie i nie znaczy nic.

Pharos zbudowaliśmy w drugą stronę. To narzędzie, które stawiasz jednym poleceniem, trzymasz na własnym serwerze i któremu można wierzyć, bo kiedy nie wie, to mówi, że nie wie. Nie jest to kolejny chmurowy dashboard z abonamentem i cudzą retencją, tylko jeden plik, który kopiujesz obok reszty usług i uruchamiasz. Cała reszta tego case study to opowieść o tym, jak jedna decyzja w formule liczenia dostępności zmienia charakter całego produktu.

Cisza to nie dostępność

Klasyczny monitoring zna dwa stany: usługa działa albo nie działa. To wygodne, dopóki nie zapytasz, co się dzieje, gdy monitoring w ogóle nie patrzy. Bo wtedy narzędzie musi coś z tym czasem zrobić, a domyślny wybór prawie zawsze wpada w tę samą pułapkę: ciszę traktuje jak sukces i dolicza ją po cichu do słupka "up". Tak powstają te niedorzeczne 100 procent za miesiąc, w którym realnie połowa danych nie istnieje.

U nas każdy okres życia usługi ma trzy stany, nie dwa. Dostępny, awaria i bez obserwacji. Ten trzeci jest całą pointą: to czas, w którym nie zbieraliśmy danych, więc nie mamy prawa twierdzić, że było dobrze. Zamiast doliczać go do góry, pokazujemy go wprost jako osobny kawałek okresu. Okna serwisowe są oznaczane, ale nie kasują awarii z historii, tylko oddzielają to, co planowane, od tego, co niespodziewane.

i
Informacja

Większość statusów liczy dostępność jako czas "up" podzielony przez czas "up plus down". Pharos liczy ją jako czas "up" podzielony przez czas realnie obserwowany, a okres bez sond kładzie osobno jako "nieznany". To jedna linijka różnicy w formule i cała różnica w zaufaniu do liczby.

Jak liczymy uczciwy uptime

Podział na trzy stany brzmi drobnie, dopóki nie zobaczysz go na konkretnym oknie. Weź dobę, w której usługa była dostępna przez większą część czasu, przez chwilę leżała, a przez kawałek nikt jej nie sondował, bo restartowała się sama maszyna monitorująca. Naiwny licznik zsumuje dostępne z nieobserwowanym i wyrzuci efektowne, wysokie procenty. Uczciwy licznik pokaże mniej i doda, że przez jakiś czas nic nie wiedział.

Z czego naprawdę składa się okno

Dostępny · 96%
Awaria · 1%
Bez obserwacji · 3%

Ta sama doba, dwa liczniki

Ta sama doba, przepuszczona przez dwie różne formuły, daje dwie zupełnie inne liczby. I to nie jest kosmetyka: to różnica między raportem, któremu klient może zaufać, a raportem, który tylko dobrze wygląda na spotkaniu. Wybraliśmy ten mniej efektowny, bo tylko on coś znaczy.

Ta sama doba, dwa liczniki (procent dostępności)

Naiwny licznik
98.9
Uczciwy licznik
96

Jeden plik, który stawiasz komendą

Największym praktycznym problemem narzędzi do statusu jest to, ile trzeba wokół nich postawić, zanim cokolwiek zaczną pokazywać. Osobna baza, kolejka, worker, panel, reverse proxy. Pharos idzie w przeciwną stronę: cały monitoring, historia, strona statusu i obsługa incydentów siedzą w jednym statycznym pliku wykonywalnym na Go, a dane trzyma wbudowany SQLite. Nie ma osobnej bazy do postawienia i pilnowania, nie ma runtime do zainstalowania. Kopiujesz binarium, uruchamiasz, działasz.

Ta prostota nie jest oszczędzaniem na funkcjach, tylko świadomym cięciem powierzchni utrzymania. Im mniej ruchomych części, tym mniej rzeczy, które mogą się zepsuć o trzeciej w nocy. Jedno wdrożenie, jeden port, jeden log do przejrzenia, kiedy coś pójdzie nie tak.

Stos

WarstwaWybórDlaczego tak
RdzeńGo, jeden statyczny plik wykonywalnyzero zależności runtime, kopiujesz i uruchamiasz
DaneSQLite wbudowany w binariumbrak osobnej bazy do postawienia i pilnowania
SondyHTTP i TCP w tleproste checki, które pokrywają większość usług
Powiadomieniawebhooki Discordazespół już tam jest, nie trzeba kolejnego narzędzia
Strona statususerwowana z tego samego procesujedno wdrożenie, jeden port, jeden log

Sondy w tle i strumień wyników

Pod uczciwą liczbą musi leżeć uczciwe źródło danych. Pharos odpytuje twoje usługi w stałym interwale po HTTP i TCP, i zapisuje każdy pojedynczy wynik razem z czasem odpowiedzi i znacznikiem czasu. Nie uśredniamy niczego w locie i nie nadpisujemy historii, bo to właśnie z tego surowego strumienia próbek buduje się potem trzy stany. Jeśli próbki dla jakiegoś przedziału nie ma, ten przedział jest bez obserwacji z definicji, a nie z domysłu.

1
Sonduje

odpytuje twoje usługi po HTTP i TCP w stałym interwale i zapisuje każdy wynik z czasem odpowiedzi.

2
Zapisuje surowo

każda próbka leży osobno, z własnym znacznikiem czasu, zamiast być od razu uśredniana.

3
Liczy uczciwie

buduje historię z trzech stanów i nigdy nie traktuje ciszy jako sukcesu.

4
Pokazuje

wystawia publiczną stronę statusu z czytelną historią, taką, którą klient rozumie bez tłumaczenia.

5
Alarmuje

kiedy stan usługi się zmienia, leci powiadomienie na Discorda, od razu tam, gdzie pracuje zespół.

uptime.go · go
type Sample struct {
    At       time.Time
    Observed bool
    Up       bool
}

func availability(samples []Sample) float64 {
    var observed, up time.Duration
    for i := 1; i < len(samples); i++ {
        span := samples[i].At.Sub(samples[i-1].At)
        if !samples[i-1].Observed {
            continue
        }
        observed += span
        if samples[i-1].Up {
            up += span
        }
    }
    if observed == 0 {
        return math.NaN()
    }
    return float64(up) / float64(observed)
}

Zwróć uwagę na dwie rzeczy w tym kawałku. Czas bez obserwacji jest pomijany w mianowniku, a nie doliczany do góry. I kiedy nie było żadnej obserwacji, funkcja zwraca NaN zamiast fałszywego 100 procent, bo brak danych to brak danych, nie sukces.

Incydenty tam, gdzie już jest zespół

Klasyczny scenariusz awarii wygląda tak: coś pada, ktoś to widzi, i zaczyna się skakanie między panelem monitoringu, komunikatorem i stroną statusu. Trzy okna, trzy wersje prawdy, i duża szansa, że publiczny status rozjedzie się z tym, co zespół naprawdę wie. Pharos ścina to do jednego miejsca. Incydent zakładasz i prowadzisz z Discorda, a publiczna strona statusu jest tylko odbiciem tego, co zespół i tak już pisze.

Nie ma drugiego narzędzia do nauczenia i nie ma ryzyka, że status pójdzie w swoją stronę, bo to ta sama rzeczywistość widziana z dwóch stron. Zgłoszenie, aktualizacje i zamknięcie ogarniasz tam, gdzie i tak siedzicie, a strona odświeża się sama.

1 binarium
cały monitoring, status i incydenty
1 komenda
do postawienia od zera
3 stany
zamiast dwóch, z jawnym "nieznany"
0
zewnętrznych zależności runtime

Liczba, której można wierzyć

Uczciwy monitoring nie jest ten, który zawsze pokazuje zielono. To ten, który przyznaje się, że przez chwilę nie patrzył.

Wyszło narzędzie, które możesz postawić na małej maszynie obok reszty usług i o którym nie musisz myśleć. Jeden plik, wbudowana baza, jeden port. Liczba na stronie statusu znaczy dokładnie to, co mówi, a kiedy monitoring czegoś nie wie, to nie udaje, że wie. Dla klienta, który tę stronę ogląda, to różnica między zaufaniem a ścianką reklamową.

!
Ostrzeżenie

Jeśli twoja strona statusu od lat pokazuje równiutkie 99.99 procent, warto sprawdzić, czy naprawdę jest tak dobrze, czy po prostu nikt nie wlicza ciszy. Uczciwy licznik prawie zawsze pokaże mniej niż ten, do którego przywykliśmy, i właśnie dlatego jest coś wart.

Kod jest otwarty, więc całą tę formułę możesz przeczytać samodzielnie, a nie wierzyć nam na słowo. To chyba najuczciwsza rzecz, jaką narzędzie do uczciwego liczenia dostępności może o sobie powiedzieć.

Więcej projektów

Inne realizacje z tej samej kategorii - zobacz, jak podchodzimy do podobnych wyzwań.

Masz podobny projekt?

Napisz do nas - wycena jest bezpłatna i wraca w godzinę.