
Jeżeli używasz bazy danych szeregów czasowych (timeseries db, ) jako głównego magazynu dla strony ze statystykami, to zamiast rozwiązania problemu możesz natknąć się na wiele bólu głowy. Pracuję nad projektem, w którym wykorzystuje się taką bazę, a czasami InfluxDB, o której za chwilę mowa, zaskakuje zupełnie nieoczekiwanymi niespodziankami.
Zrzeczenie się odpowiedzialności: przedstawione problemy dotyczą wersji InfluxDB 1.7.4.
Dlaczego szereg czasowy?
Projekt polega na śledzeniu transakcji w różnych blockchainach i wyświetlaniu statystyk. Konkretnie - przyglądamy się emisji i spalaniu stablecoinów (). Na podstawie tych transakcji należy budować wykresy i przedstawiać tabele podsumowujące.
Podczas analizy transakcji pojawił się pomysł: użyć bazy danych szeregów czasowych InfluxDB jako głównego magazynu. Transakcje są punktami w czasie i dobrze wpasowują się w model szeregów czasowych.
Dodatkowo funkcje agregacji wyglądały bardzo wygodnie - doskonale nadają się do przetwarzania wykresów z dużym okresem. Użytkownik potrzebuje wykresu za rok, a w bazie znajduje się zbiór danych z interwałem pięciu minut. Wysyłanie wszystkich stu tysięcy punktów jest bez sensu - oprócz długiego przetwarzania, nie zmieszczą się też na ekranie. Można napisać własną implementację zwiększenia interwału lub skorzystać z wbudowanych w Influx funkcji agregacji. Dzięki nim można pogrupować dane według dni i wysłać potrzebne 365 punktów.
Nieco niepokoiło to, że zazwyczaj takie bazy używa się w celu zbierania metryk. Monitorowanie serwerów, urządzenia IoT, wszystko, z czego „spływają” miliony punktów w postaci: [<czas> - <wartość metryki>]. Ale jeśli baza dobrze działa z dużym przepływem danych, to dlaczego mały wolumen miałby stwarzać problemy? Z tym przemyśleniem wzięliśmy InfluxDB do pracy.
Co jeszcze jest wygodne w InfluxDB
Oprócz wspomnianych funkcji agregacji istnieje jeszcze jedna wspaniała rzecz - zapytania ciągłe (). To wbudowany w bazie planer, który może przetwarzać dane według harmonogramu. Na przykład, można co 24 godziny grupować wszystkie rekordy za dzień, obliczać średnią i zapisywać jeden nowy punkt w innej tabeli bez pisania własnych rozwiązań.
Jest także polityki retencji () — ustawienie usuwania danych po pewnym okresie. Przydatne, gdy na przykład trzeba przechować obciążenie CPU za tydzień z pomiarami co sekundę, a na odległości kilku miesięcy taka precyzja nie jest konieczna. W takiej sytuacji można zrobić tak:
- utworzyć zapytanie ciągłe do agregacji danych w innej tabeli;
- dla pierwszej tabeli określić politykę usuwania metryk, które są starsze niż ten tydzień.
I Influx samodzielnie będzie zmniejszać rozmiar danych i usuwać zbędne.
O przechowywanych danych
Danych nie ma wiele: około 70 tysięcy transakcji oraz kolejny milion punktów z informacjami rynkowymi. Dodawanie nowych rekordów — nie więcej niż 3000 punktów dziennie. Są też metryki dotyczące strony, ale tam danych jest mało i według polityki retencji przechowują się one nie dłużej niż miesiąc.
Problemy
Podczas rozwoju i późniejszych testów usługi pojawiały się coraz bardziej krytyczne problemy przy eksploatacji InfluxDB.
1. Usuwanie danych
Jest seria danych z transakcjami:
SELECT time, amount, block, symbol FROM transactions WHERE symbol='USDT'Wynik:

Wysyłam komendę do usunięcia danych:
DELETE FROM transactions WHERE symbol='USDT'Następnie wykonuję zapytanie o już usunięte dane. I Influx zamiast pustej odpowiedzi zwraca część danych, które powinny być usunięte.
Próbuję usunąć tabelę całkowicie:
DROP MEASUREMENT transactionsSprawdzam usunięcie tabeli:
SHOW MEASUREMENTSNie widzę tabeli na liście, ale nowe zapytanie danych nadal zwraca ten sam zestaw transakcji.
Problem pojawił się u mnie tylko raz, ponieważ przypadek usunięcia — to jednostkowy przypadek. Ale takie zachowanie bazy ewidentnie nie wpisuje się w ramy “poprawnej” pracy. Później na githubie znalazłem otwarty prawie roczny na ten temat.
W rezultacie, pomogło usunięcie i późniejsze przywrócenie całej bazy.
2. Liczby zmiennoprzecinkowe
Obliczenia matematyczne przy użyciu wbudowanych funkcji InfluxDB dają błędy dokładności. Nie jest to nic niezwykłego, ale jest nieprzyjemne.
W moim przypadku dane mają aspekt finansowy i chciałbym je przetwarzać z wysoką dokładnością. Z powodu tego planuję zrezygnować z zapytań ciągłych.
3. Zapytania ciągłe nie mogą być dostosowywane do różnych stref czasowych
Na serwisie znajduje się tabela dziennej statystyki transakcji. Dla każdego dnia należy pogrupować wszystkie transakcje z tych 24 godzin. Jednak dzień dla każdego użytkownika zaczyna się o różnym czasie, co oznacza, że zestaw transakcji również będzie inny. Według UTC jest przesunięcia, dla których należy agregować dane.
W InfluxDB podczas grupowania według czasu można dodatkowo wskazać przesunięcie, na przykład dla czasu moskiewskiego (UTC+3):
SELECT MEAN("supply") FROM transactions GROUP BY symbol, time(1d, 3h) fill(previous)Jednak wynik zapytania będzie niepoprawny. Z jakiegoś powodu dane pogrupowane według dni będą zaczynały się aż w 1677 roku (InfluxDB oficjalnie wspiera przedział czasowy od tego roku):

Aby obejść ten problem, tymczasowo przestawiliśmy serwis na UTC+0.
4. Wydajność
W internecie jest wiele benchmarków porównujących InfluxDB i inne bazy danych. Podczas pierwszej lektury wyglądały one na materiały marketingowe, ale teraz uważam, że jest w nich trochę prawdy.
Podzielę się swoim przypadkiem.
Serwis udostępnia metodę API, która zwraca statystyki za ostatnie 24 godziny. Przy obliczeniach metoda wykonuje trzy zapytania do bazy danych:
SELECT * FROM coins_info WHERE time <= NOW() GROUP BY symbol ORDER BY time DESC LIMIT 1SELECT * FROM dominance_info ORDER BY time DESC LIMIT 1SELECT * FROM transactions WHERE time >= NOW() - 24h ORDER BY time DESCWyjaśnienie:
- W pierwszym zapytaniu otrzymujemy ostatnie punkty dla każdej monety z danymi rynkowymi. W moim przypadku osiem punktów dla ośmiu monet.
- Drugie zapytanie pobiera jeden najnowszy punkt.
- Trzecie zapytanie żąda listy transakcji za ostatnie 24 godziny, może ich być kilka setek.
Uzupełnię, że w InfluxDB indeks automatycznie buduje się według tagów i czasu, co przyspiesza zapytania. W pierwszym zapytaniu symbol — to tag.
Przeprowadziłem test obciążeniowy tego metody API. Przy 25 RPS serwer wykazywał pełne obciążenie sześciu CPU:

Przy czym proces NodeJS wcale nie obciążał serwera.
Prędkość wykonania zaczęła spadać już przy 7-10 RPS: jeśli jeden klient mógł otrzymać odpowiedź w 200 ms, to 10 klientów musiało czekać po sekundzie. 25 RPS — to granica, przy której stabilność zaczynała cierpieć, klienci otrzymywali błędy 500.
Przy takiej wydajności użycie Influx w naszym projekcie jest niemożliwe. Co więcej: w projekcie, gdzie monitoring musi być pokazany wielu klientom — mogą wystąpić podobne problemy i serwer metryk będzie przeciążony.
Wnioski
Najważniejszym wnioskiem z uzyskanego doświadczenia jest to, że nie można wprowadzać do projektu nieznanej technologii bez odpowiedniej analizy. Proste przeszukanie otwartych zgłoszeń na GitHubie mogło dostarczyć informacji, które pomogłyby zrezygnować z InfluxDB jako głównego magazynu danych.
InfluxDB wydawała się dobrze pasować do zadań mojego projektu, ale jak pokazała praktyka, ta baza danych nie spełnia wymagań i wiele rzeczy nie działa poprawnie.
W repozytorium projektu można już znaleźć wersję 2.0.0-beta, pozostaje mieć nadzieję, że w drugiej wersji pojawią się istotne ulepszenia. A ja tymczasem zajmę się dokumentacją TimescaleDB.
Źródło: habr.com
