Obsługa dużej bazy użytkowników niezawodnymi, spójnymi danymi o niskim opóźnieniu jest bardzo trudnym wyzwaniem dla każdego zespołu backendowego. W Ledger dokonaliśmy strategicznego wyboru, aby hostować nasze własne podstawowe usługi danych blockchain. Nie polegając na osobach trzecich, możemy sami zarządzać danymi naszych klientów, zapewniając, że podstawowe procesy są zgodne z naszymi wytycznymi dotyczącymi bezpieczeństwa i celami poziomu usług zorientowanymi na wydajność (SLO).
Ale ta strategia niesie ze sobą także własny zestaw wyzwań.
Naszym pierwszym wyzwaniem jest migracja tych podstawowych usług dostarczania danych z fajnych i błyszczących narzędzi noSQL. W tym artykule omówię, dlaczego podjęliśmy tę trudną decyzję, jakie zawiłości napotkaliśmy i jakie korzyści odnieśliśmy.
Celem tego artykułu jest pokazanie aspektów technicznych, które skłoniły nas do wyboru PostgreSQL jako naszej nowej podstawowej warstwy przechowywania danych blockchain.
Głęboko zanurz się w danych Blockchain
Dane Blockchain mają kilka kluczowych cech.
Po pierwsze, stale rośnie i nic z niego nigdy nie jest usuwane. Jednak w praktyce, chociaż większość łańcucha bloków jest niezmienna, najmłodsza część łańcucha bloków może ulec zmianie z powodu konfliktów, które należy rozwiązać. Rzeczywiście, ponieważ łańcuch jest siecią typu peer to peer, kilka legalnych bloków może tymczasowo współistnieć. Zwykle starsze są usuwane, co powoduje tak zwaną reorganizację. Krótko mówiąc, dane są podzielone pomiędzy niezmienny zimny ogon i rzadko zmieniający się stan głowy.
Problem, który próbujemy rozwiązać, polega na tym, że chociaż łańcuchy bloków świetnie nadają się do przechowywania danych odpornych na błędy bizantyjskie, są mniej skuteczne w krojeniu ich na wiele osi. Mianowicie uzyskanie listy operacji, które miały wpływ na konto, jest bardzo trudne. Nawet uzyskanie salda konta na blockchainie takim jak Bitcoin jest wyzwaniem, jeśli nie masz jeszcze listy transakcji.
Aby przezwyciężyć te wyzwania, usługi Ledger Explorer Services indeksują cały łańcuch bloków. Jest to duża, krytyczna i wrażliwa na wydajność usługa w całości napisana w języku Scala przy użyciu efekt kota czas działania o wysokiej wydajności. Mamy ponad 10 tys. obr./s na bitcoinie, utrzymując opóźnienie ogona p95 poniżej 100 ms. Prowadzimy również rekrutację 😊.
Trochę historii
Na początku naszej historii, na długo zanim dołączyłem do firmy, warstwa usług danych Ledger była obsługiwana przez wbudowaną bazę danych Neo4j. Każde pudełko do serwowania indeksowało własne dane i udostępniało je lokalnie, co powodowało wiele problemów.
Nie gwarantowano spójności danych pomiędzy instancjami, a sam rozmiar stanu, który wymagał indeksowania, w połączeniu z wykorzystaniem dysku i pamięci RAM neo4j, nie był skalowalny. Problem ten pogłębił się wraz z rozwojem firmy, przez co tworzenie nowych instancji było coraz trudniejsze.
Cassandra została następnie wybrana jako główny czynnik napędzający tę nową konfigurację: jest to klastrowa, skalowalna poziomo baza danych, która znajduje się po stronie AP twierdzenia CAP. Rozwiązuje problemy związane z udostępnianiem danych i pozwala na wyraźne oddzielenie komponentu indeksującego, obsługującego blockchain i bezgłowych serwerów API.
Ale jaki jest sens udostępniania całego stanu historycznego, jeśli tak naprawdę nigdy nie będziemy z niego czytać?
Jeśli chodzi o nasz przypadek użycia, surowe dane historyczne są rzadko potrzebne, ponieważ można na ich podstawie zagregować stan naszego konta użytkownika. To skłoniło nas do zakwestionowania istniejącego rozwiązania do przechowywania danych opartego na rozproszonej bazie danych Cassandra.
Ilość danych, które musimy przechowywać w każdym łańcuchu bloków, choć rzędu terabajtów, nie jest tym, co można nazwać „dużymi danymi”. Co więcej, część if, która będzie używana do odpowiedzi na większość zapytań (czyli gorąca ścieżka), jest jeszcze mniejsza. Obecnie można łatwo znaleźć standardowe serwery sprzętowe z pamięcią masową SSD NVMe o pojemności ponad 16 TB. Skalowanie pionowe to bardzo potężne narzędzie, podobnie jak relacyjna baza danych.
Wreszcie, głównym problemem, jaki mieliśmy w obecnej konfiguracji Cassandry, nie był ani marnotrawny model przechowywania, ani źle dopasowany przypadek wykorzystania danych, ale brak przyjazności dla programistów. Opracowanie nowej funkcji opartej na danych w Cassandrze okazało się niepotrzebnie czasochłonne. Dążyliśmy do wdrożenia każdej nowej osi, na której musimy podać dane.
Biorąc pod uwagę wiedzę naszego zespołu w zakresie umiejętności modelowania danych i biegłość w języku SQL, PostgreSQL był idealnym kandydatem. To rozwiązanie zostało przetestowane w boju, solidne i łatwe w rozbudowie, co czyni je idealnym wyborem.
Dlaczego wybraliśmy SQL zamiast NoSQL:
- Odczytuje/zapisuje salda: przypadek użycia danych blockchain został mocno przesunięty w stosunku do odczytów, a nie zapisów (blockchain zapisuje bardzo niewiele danych z bardzo rozsądną szybkością, nawet w przypadku blockchainu takiego jak Polygon). Cassandra ma zdolność pochłaniania bardzo dużej ilości zapisów – w rzeczywistości jest to ścieżka odczytu dłużej niż ścieżka zapisu.
- Wsparcie indeksowania: Indeksy są kluczowym elementem systemu DBMS, umożliwiającym odpowiadanie na zapytania i nowe uzasadnienia biznesowe lub możliwości. Cassandra ma ograniczoną obsługę indeksowania. Indeksy są skuteczne tylko wtedy, gdy zapytanie określa już sposób ograniczenia partycji, na której będzie uruchamiane zapytanie. Płacimy tutaj koszty posiadania dowolnie dystrybuowane Baza danych. Obsługa indeksów w PostgreSQL jest wydajna, rozszerzalna i na najwyższym poziomie.
- Wsparcie agregacji: Ten sam przypadek agregacji; ponieważ Cassandra nie pozwala na agregację wielu partycji i nie toleruje żadnej klauzuli GROUP BY w swoim języku zapytań, brakuje jej wsparcia. PostgreSQL oferuje rozbudowaną obsługę agregacji, nawet w przypadku egzotycznych typów danych, takich jak zakresy i obiekty blob jsonb.
- Modelowanie danych: Cassandra ma bardzo, bardzo ograniczone możliwości modelowania danych. Dla prawie każdego żądania, na które chcesz odpowiedzieć, należy utworzyć tabelę, a dane należy zdenormalizować do dużych wierszy (w pełni wykorzystując sklep z szeroką kolumną aspekt C*, a także fakt, że autorzy są jak barszcz tani). PostgreSQL pozwala nam wykorzystać relacyjny aspekt blockchain (wywołania, transakcje, bloki) i oszczędzić miejsce na dysku, zachęcając do ponownego wykorzystania danych.
- Zapytania i audyty doraźne: Możliwość korzystania z pełnego standardu SQL i wykonywania dowolnych zapytań oznacza, że możemy eksplorować i wyszukiwać potencjalną przyczynę błędu lub dysponować danymi eksploracyjnymi do przyszłych zastosowań. Naprawdę możemy używać bazy danych jako interaktywnego i inteligentnego narzędzia, a nie głupiego magazynu. Robimy to na Cassandrze bez rozbudowanego i kosztownego klastra obliczeniowego do analizy, takiego jak Presto, Spark itp. (a ponieważ działamy na serwerach typu bare metal, nie mamy dostępu do łatwo dostępnych narzędzi do rozproszonej analizy danych, takich jak EMR).
- Wykorzystanie bagażu: Cassandra zakłada, że pamięć masowa jest bardzo tania i że klaster można łatwo rozszerzyć o nowe maszyny. Oznacza to, że wszelkie ograniczenia dotyczące zarówno indeksów, jak i agregacji muszą być opłacone w ramach przechowywania. Brak globalnie wydajnych indeksów i obsługa złączeń oznaczają, że musimy denormalizować i przechowywać kopię całej tabeli dla każdej osi, do której chcemy wysłać zapytanie. PostgreSQL oszczędza nam terabajty pamięci.
- Konsystencja: Ponieważ Cassandra jest rozproszoną bazą danych zorientowaną na AP (komunikacja odbywa się poprzez plotkowanie między węzłami), spójność jest ostateczna tylko w zakresie zapisów. Możesz dostroić politykę spójności każdej instrukcji zarówno dla odczytu, jak i zapisu, ale celem tej bazy danych nigdy nie było zapewnienie silnej spójności. PostgreSQL ma długą historię wykorzystywania w krytycznych misjach i jest bardzo odporny. Scentralizowanie oznacza również, że w ścieżce zapisu nie ma żadnej sieci.
- Transakcje i MVCC:
- Transakcje: Cassandra obsługuje tylko lekkie transakcje w zapytaniach DML. Można zastosować pewne dozowanie (doc), ale istnieje wiele zastrzeżeń, a mianowicie, że wiersze muszą znajdować się na tym samym serwerze (= partycja), aby nie zapewniały straszliwej wydajności.
- MVCC: Cassandra obsługuje znaczniki czasu wierszy, ale nie gwarantuje się pełnego MVCC. Kompaktowanie może usunąć nieaktualne dane i nie ma sposobu, aby powiedzieć C*, że nie powinno (jak np. w przypadku transakcji w PG).
- PostgreSQL obsługuje silny model MVCC, który zapewnia naszym użytkownikom spójną ścieżkę odczytu.
- Obróbka: PostgreSQL ma o wiele więcej narzędzi powszechnie używanych do łatwej obsługi bazy danych. Co więcej, narzędzie takie jak przelot zapewnia utrzymanie solidnej wersji schematu bazy danych. Zintegrowaliśmy go już z naszą bazą kodu. Na Cassandrze nie ma odpowiednika o takim poziomie dojrzałości.
- Skalowalność pozioma: To jest kluczowy punkt sprzedaży Cassandry. Po prostu dodawaj więcej maszyn w miarę powiększania się danych. Nie ma odpowiednika dla PostgreSQL, ponieważ sharding i partycjonowanie muszą być wykonywane ręcznie.
Jak planujemy skalować
Jak widzieliśmy, jedyną wadą korzystania z konfiguracji Postgres jest skalowanie zarówno podczas odczytów, jak i przechowywania. Co możemy zrobić, aby pokonać to ograniczenie?
Pierwszym skutecznym narzędziem, jakie mamy, jest segregacja każdego obsługiwanego przez nas protokołu lub łańcucha bloków w oddzielną bazę danych, ponieważ w ten sposób można go odpowiednio skalować, biorąc pod uwagę wielkość i ruch. Segmentacja według domeny biznesowej zapewnia pierwszą warstwę skalowania.
Kontynuując tę koncepcję, możemy również podzielić zimne dane historyczne na podział czasowy. Najnowsze wersje Postgresa znacznie poprawiły użyteczność partycjonowanych tabel, co może umożliwić płynne przenoszenie danych pomiędzy klastrem maszyn. Na przykład moglibyśmy używać tańszych maszyn o mniejszej mocy obliczeniowej do hostowania większości danych historycznych, utrzymując jednocześnie potężne, obsługujące użytkowników behemoty ze stosami pamięci RAM, umożliwiające hostowanie zagregowanych tabel i najnowszych operacji użytkownika.
To podejście sprawdza się bardzo dobrze w naszym przypadku użycia, ponieważ w pamięci historycznej nie ma kluczy obcych pochodzących z różnych partycji (wszystko jest ostatecznie dołączone do bloku). Z perspektywy głównego serwera dostęp do danych historycznych można uzyskać nawet za pomocą partycjonowania i rozszerzenia postgres_fdw.
Aby pomóc to wszystko wdrożyć, przyjrzeliśmy się również rozszerzeniu TimescaleDB. To rozszerzenie dodaje wiele funkcjonalności do podstawowego postgresu, a większość z nich idealnie pasuje do naszych przypadków użycia:
- Automatyczne partycjonowanie tabel w oparciu o kolumnę typu czasowego (w naszym przypadku dostosowujemy to, przyjmując jako punkt odniesienia wysokość łańcucha bloków).
- Automatyczna, uwzględniająca typ danych i oparta na kolumnach kompresja starszych fragmentów. Zapewnia to niemal idealny współczynnik kompresji dzięki zastosowaniu najnowocześniejszych algorytmów na bardzo podobnych danych.
- Wydajna agregacja oparta na przedziałach czasu w celu łatwego obliczania sald historycznych i wykresów danych rynkowych.
Jesteśmy dopiero na początku eksperymentów dotyczących przechowywania, a to otwiera wiele przypadków użycia. Weryfikacja koncepcji przy użyciu niewielkiej ilości danych (~10 tys. bloków w sieci głównej Ethereum, czyli około 2 dni danych) pokazał redukcję miejsca na dysku aż o 40%.
Jak widzieliśmy, ilość danych, pod warunkiem, że zastosujemy odpowiednią strategię, nie stanowi problemu. Ale jak skalować w zależności od wielkości naszej bazy użytkowników?
Mamy tu już niezłą przewagę: indeksujemy całe dane blockchain. Zatem potrzebna pamięć nie będzie rosła wraz z liczbą użytkowników, ale z całkowitym rozmiarem łańcucha bloków. Optymalizacje przechowywania i odczytu są całkowicie ortogonalne pod względem rozdzielczości.
Taka konfiguracja, w połączeniu z bardzo niskim zapotrzebowaniem na zapis w stosunku do wolumenu odczytu, jaki należy obsłużyć, jest wymarzoną konfiguracją dla klasowego wzorca repliki lider-podążający. Aby jeszcze bardziej zwiększyć wydajność i przepustowość, możemy również umieścić repliki odczytu Postgres na tych samych maszynach, co serwery API i skorzystać z gniazd domen UNIX, aby pominąć podróże w obie strony sieci.
Oto przykład strategii replikacji danych, której możemy użyć do skalowania naszych odczytów. Jasnoszare pola reprezentują pojedyncze serwery. Widzimy tutaj, że moduły API są bezpośrednio zlokalizowane w pobliżu replik najgorętszych danych, aby zapewnić minimalny czas przesyłania między pamięcią masową a użytkownikami. Opisane powyżej instancje archiwalne nie są reprezentowane, aby nie komplikować zbytnio schematu.
Uwagi końcowe
Jako wieloletni użytkownik Cassandry chcę podkreślić, że jest to świetna baza danych w swojej konstrukcji, która pasuje do szerokiej gamy zastosowań. Niestety, decyzja o wykorzystaniu tej metody w firmie Ledger została podjęta w związku z przypadkiem użycia danych, który nigdy się nie zmaterializował.
Miało to wpływ na produktywność naszego zespołu i nie mogąc się doczekać wyzwań, które musimy rozwiązać, postanowiliśmy nie dać się zwieść mitowi zatopionych kosztów.
W wielu przypadkach Twoje dane nie są dużymi zbiorami danych. Zarządzanie dystrybucją danych w większości przypadków nie jest trudnym zadaniem i naprawdę należy dokładnie rozważyć kompromisy wynikające z posiadania w pełni rozwiniętej rozproszonej bazy danych. Kluczową kwestią jest doświadczenie programisty, ponieważ pozwala ono zaoszczędzić cenny czas na zbudowanie czegokolwiek innego. To jest prawdziwy przypadek użycia, w który musimy mocno zainwestować.
- Dystrybucja treści i PR oparta na SEO. Uzyskaj wzmocnienie już dziś.
- PlatoAiStream. Analiza danych Web3. Wiedza wzmocniona. Dostęp tutaj.
- Wybijanie przyszłości w Adryenn Ashley. Dostęp tutaj.
- Kupuj i sprzedawaj akcje spółek PRE-IPO z PREIPO®. Dostęp tutaj.
- Źródło: https://www.ledger.com/blog/serving-web3-at-web2-scale
- :ma
- :Jest
- :nie
- $W GÓRĘ
- 10
- 10 tysięcy
- 20
- a
- zdolność
- Zdolny
- dostęp
- dostęp
- Konto
- w poprzek
- faktycznie
- przystosować
- Dodaj
- Dodaje
- przylegać
- Korzyść
- zbiór
- Algorytmy
- Wszystkie kategorie
- dopuszczać
- pozwala
- już
- również
- Chociaż
- ilość
- an
- analiza
- analityka
- i
- odpowiedź
- każdy
- wszystko
- api
- aplikacje
- stosowany
- podejście
- odpowiednio
- Archiwum
- SĄ
- na około
- Sztuka
- artykuł
- AS
- aspekt
- aspekty
- założenie
- At
- dostępny
- świadomy
- z dala
- OSIE
- Oś
- Backend
- Bilans
- salda
- baza
- na podstawie
- Baseline
- BE
- bo
- być
- zanim
- Początek
- Behemoty
- jest
- Korzyści
- pomiędzy
- Duży
- Big Data
- Bit
- Bitcoin
- Blokować
- blockchain
- dane blockchain
- blockchains
- Bloki
- obie
- Pudełko
- Skrzynki
- Przynosi
- Bug
- budować
- biznes
- ale
- by
- wezwanie
- Połączenia
- CAN
- kandydat
- czapka z daszkiem
- ostrożnie
- walizka
- Etui
- Spowodować
- powodowany
- scentralizowane
- łańcuch
- wyzwanie
- wyzwania
- wyzwanie
- zmiana
- wymiana pieniędzy
- tani
- tańsze
- tańsze maszyny
- wybór
- Dodaj
- wybrał
- wybrany
- jasny
- Grupa
- kod
- podstawa kodu
- zimno
- Kolumna
- połączony
- towar
- Komunikacja
- sukcesy firma
- złożoności
- składnik
- obliczać
- pojęcie
- Koncepcje
- wynagrodzenie
- za
- zgodny
- Chłodny
- rdzeń
- Koszty:
- mógłby
- stworzony
- krytyczny
- Aktualny
- dane
- analiza danych
- udostępnianie danych
- przechowywanie danych
- Baza danych
- Dni
- decyzja
- opisane
- Wnętrze
- Deweloper
- rozwijanie
- trudny
- bezpośrednio
- brud
- dystrybuowane
- 分配
- podzielony
- do
- robi
- robi
- domena
- nie
- minusem
- marzenie
- kierowca
- z powodu
- e
- każdy
- z łatwością
- łatwo
- krawędź
- Efektywne
- wydajny
- więcej
- osadzone
- podkreślać
- umożliwiać
- zachęcający
- wzmacniać
- zapewnić
- zapewnia
- zapewnienie
- Równoważny
- itp
- ethereum
- SIEĆ GŁÓWNA ETHEREUM
- Parzyste
- Ewentualny
- EVER
- Każdy
- wszystko
- przykład
- Przede wszystkim system został opracowany
- Egzotyczny
- rozszerza się
- doświadczenie
- ekspertyza
- odkryj
- badacz
- rozciągać się
- rozbudowa
- rozległy
- fakt
- Spadać
- Cecha
- Korzyści
- kilka
- Znajdź
- i terminów, a
- dopasować
- W razie zamówieenia projektu
- obcy
- Naprzód
- życzliwość
- od
- pełny
- pełnoprawny
- w pełni
- funkcjonalności
- dalej
- przyszłość
- miejsce
- dany
- Globalnie
- cel
- będzie
- wykresy
- szary
- wspaniały
- Zarządzanie
- Rosnąć
- Rozwój
- gwarantowane
- wytyczne
- miał
- Ciężko
- sprzęt komputerowy
- Have
- mający
- głowa
- ciężko
- wysokość
- pomoc
- tutaj
- Wysoki
- wysoko
- historyczny
- gospodarz
- HOT
- Najgorętsze
- W jaki sposób
- How To
- Jednak
- HTML
- HTTPS
- i
- idealny
- if
- niezmienny
- wpływ
- wykonawczych
- ulepszony
- in
- coraz bardziej
- wskaźnik
- Indeksy
- przykład
- zintegrowany
- interaktywne
- najnowszych
- Inwestuj
- zaangażowany
- problem
- problemy
- IT
- JEGO
- przystąpić
- Dołączył
- jpg
- właśnie
- konserwacja
- Klawisz
- Klawisze
- Uprzejmy
- Brak
- język
- duży
- Utajenie
- firmy
- warstwa
- Doprowadziło
- Księga główna
- prawowity
- mniej
- poziom
- Dźwignia
- lekki
- lekki
- lubić
- ograniczenie
- Ograniczenia
- Ograniczony
- Lista
- mało
- lokalnie
- długo
- wyglądał
- poszukuje
- Partia
- niski
- maszyny
- zrobiony
- Główny
- mainnet
- utrzymać
- Większość
- Dokonywanie
- zarządzanie
- zarządzający
- ręcznie
- wiele
- rynek
- Dane rynkowe
- dojrzałość
- Maksymalna szerokość
- Może..
- znaczy
- metal
- migrować
- minimalny
- misje
- model
- modelowanie
- jeszcze
- Ponadto
- większość
- ruch
- dużo
- musi
- mianowicie
- prawie
- Potrzebować
- potrzebne
- wymagania
- Ani
- sieć
- nigdy
- Nowości
- miło
- Nie
- węzły
- nic
- numer
- liczny
- Cele
- of
- on
- ONE
- tylko
- działać
- operacje
- Szanse
- or
- zamówienie
- ludzkiej,
- sobie
- koniec
- Przezwyciężać
- własny
- płatny
- część
- strony
- ścieżka
- Wzór
- Zapłacić
- par
- peer to peer
- doskonały
- jest gwarancją najlepszej jakości, które mogą dostarczyć Ci Twoje monitory,
- perspektywa
- Miejsce
- krok po kroku
- plato
- Analiza danych Platona
- PlatoDane
- pods
- punkt
- polityka
- Wielokąt
- możliwy
- postgresql
- potencjał
- power
- mocny
- praktyka
- Problem
- procesów
- wydajność
- dowód
- odsetek
- proponuje
- protokół
- Sprawdzony
- zapewniać
- pod warunkiem,
- położyć
- zapytania
- RAM
- zasięg
- Kurs
- raczej
- stosunek
- Surowy
- Czytaj
- real
- naprawdę
- rozsądny
- redukcja
- w sprawie
- związane z
- rzetelny
- reorganizacja
- odpowiedzieć
- replikacja
- reprezentować
- reprezentowane
- zażądać
- sprężysty
- Rozkład
- zdecydowany
- wynikły
- ponownie
- prawo
- krzepki
- korzeń
- okrągły
- RZĄD
- run
- bieganie
- taki sam
- Scala
- skalowalny
- Skala
- skalowaniem
- płynnie
- Szukaj
- bezpieczeństwo
- widzieć
- widziany
- segment
- segmentacja
- Sprzedawanie
- punkt sprzedaży
- usługa
- Usługi
- służąc
- zestaw
- ustawienie
- kilka
- sharding
- dzielenie
- Short
- pokazać
- bok
- podobny
- ponieważ
- pojedynczy
- Rozmiar
- umiejętności
- mały
- mniejszy
- mądry
- So
- rozwiązanie
- ROZWIĄZANIA
- Rozwiązuje
- kilka
- Typ przestrzeni
- Iskra
- Ikra
- SQL
- standard
- Stan
- Zestawienie sprzedaży
- przechowywanie
- sklep
- Historia
- Strategiczny
- Strategia
- silny
- strongly
- Z powodzeniem
- wsparcie
- podpory
- stół
- Brać
- biorąc
- Zadanie
- zespół
- Techniczny
- powiedzieć
- REGULAMIN
- niż
- że
- Połączenia
- Blok
- Państwo
- ich
- następnie
- Tam.
- Te
- one
- Trzeci
- osoby trzecie
- to
- wydajność
- czas
- do
- także
- narzędzie
- narzędzia
- Kwota produktów:
- CAŁKOWICIE
- ruch drogowy
- transakcja
- transakcje
- przenieść
- transparentnie
- rodzaj
- typy
- Ostatecznie
- dla
- zasadniczy
- Niestety
- UNIX
- odblokowuje
- niepotrzebnie
- us
- użyteczność
- Stosowanie
- posługiwać się
- przypadek użycia
- używany
- Użytkownik
- Użytkownicy
- za pomocą
- zazwyczaj
- Cenny
- różnorodność
- pionowy
- początku.
- Tom
- chcieć
- była
- Droga..
- we
- Web2
- Web3
- DOBRZE
- Co
- Co to jest
- jeśli chodzi o komunikację i motywację
- który
- Podczas
- Podczas
- cały
- dlaczego
- szeroki
- szeroko
- będzie
- w
- bez
- działa
- napisać
- napisany
- ty
- Najmłodszy
- Twój
- zefirnet