Pięć lat temu próbowałem pracować z Tarantool, ale wtedy mi się nie spodobał. Niedawno prowadziłem webinar, w którym opowiadałem o Hadoop i o tym, jak działa MapReduce. Zostało mi zadane pytanie — „Dlaczego nie użyć do tego zadania Tarantool?”.
Z ciekawości postanowiłem wrócić do niego, przetestować najnowszą wersję — i tym razem projekt bardzo mi się spodobał. Teraz pokażę, jak napisać w Tarantool proste aplikacje, obciążyć je i sprawdzić wydajność, a zobaczycie, jak to wszystko jest łatwe i świetne.

Co to jest Tarantool
Tarantool pozycjonuje się jako superszybka baza danych. Można do niego wprowadzać dowolne dane, jakie tylko zechcesz. Dodatkowo, można je replikować, shardować — czyli dzielić ogromne ilości danych na kilka serwerów i łączyć wyniki — tworzyć odporne na awarie zestawy typu „master-master”.
Po drugie, to serwer aplikacji. Możesz na nim pisać swoje aplikacje, pracować z danymi, na przykład w tle usuwać stare rekordy według określonych reguł. Można napisać bezpośrednio w Tarantool serwer Http, który będzie pracować z danymi: wydawać ich ilość, zapisywać nowe dane i redukować to wszystko na maestra.
Czytałem artykuł, jak goście zrobili kolejkę wiadomości na 300 linijek, która po prostu rozwija i zrywa — mają minimalną wydajność od 20 000 wiadomości na sekundę. Tutaj można naprawdę się rozwinąć i napisać bardzo dużą aplikację, która nie będzie takimi archiwami jak w PostgreS.
Taki serwer, tylko prosty, postaram się opisać w tym artykule.
Instalacja
Na potrzeby testu założyłem trzy standardowe maszyny wirtualne – dysk twardy o pojemności 20 gigabajtów, Ubuntu 18.04, 2 wirtualne CPU i 4 gigabajty pamięci.
Instalujemy Tarantool — uruchamiamy skrypt bashowy lub dodajemy repozytorium i wykonujemy apt get install Tarantool. Link do skryptu — (curl -L | VER=2.4 sudo -E bash). Pojawiają się takie komendy, jak:
tarantoolctl — główna komenda do zarządzania instancjami Tarantoola.
/etc/tarantool — tutaj znajduje się cała konfiguracja.
var/log/tarantool — tutaj znajdują się logi.
var/lib/tarantool — tutaj znajdują się dane, które dalej są podzielone według instancji.
Są foldery instance-available i instance-enable — w tym ostatnim znajduje się to, co będzie uruchamiane — plik konfiguracyjny instancji z kodem lua, w którym opisano, na jakich portach nasłuchuje, jaka pamięć jest mu dostępna, ustawienia silnika Vinyl, kod, który uruchamia się przy starcie serwera, shardowanie, kolejki, usuwanie przestarzałych danych i tak dalej.
Instancje działają podobnie jak w PostgreS. Na przykład, chcesz uruchomić kilka kopii bazy danych, które działają na różnych portach. Oznacza to, że na jednym serwerze uruchamiane są różne instancje baz danych, które działają na różnych portach. Mogą mieć zupełnie różne ustawienia — jedna instancja realizuje jedną logikę, druga — inną.
Zarządzanie instancjami
Mamy komendę tarantoolctl, która pozwala zarządzać instancjami Tarantula. Na przykład, tarantoolctl check example sprawdzi plik konfiguracyjny i powie — plik jest w porządku, jeśli nie ma w nim błędów składniowych.
Możesz sprawdzić status instancji — tarantoolctl status example. W ten sam sposób można wykonywać start, stop, restart.
Kiedy instancja jest uruchomiona, można się do niej podłączyć na dwa sposoby.
1. Konsola administracyjna
Domyślnie Tarantool otwiera gniazdo, w którym przesyłany jest zwykły tekst ASCII do zarządzania Tarantulem. Podłączenie do konsoli odbywa się zawsze jako użytkownik admin, nie ma tam uwierzytelnienia, dlatego nie ma potrzeby wystawiania portu konsoli na zewnątrz do zarządzania Tarantulem.
Aby połączyć się w ten sposób, należy wpisać Tarantoolctl enter instance name. Komenda uruchomi konsolę i połączy się jako użytkownik admin. Nigdy nie wystawiaj portu konsoli na zewnątrz — lepiej zostawić go jako gniazdo jednostkowe. Wtedy możliwość podłączenia się do Tarantula będzie miała tylko ta osoba, która ma dostęp do zapisu w gniazdo.
Ten sposób jest potrzebny do rzeczy administracyjnych. Do pracy z danymi użyj drugiego sposobu — protokołu binarnego.
2. Użycie protokołu binarnego do połączenia z określonym portem
W konfiguracji jest dyrektywa listen, która otwiera port dla zewnętrznych komunikacji. Ten port jest używany z protokołem binarnym i tam włączona jest autoryzacja.
Do tego połączenia używa się tarantoolctl connect to port number. Używając tej komendy, można podłączać się do zdalnych serwerów, używać autoryzacji i nadawać różne prawa dostępu.
Zapis danych i moduł Box
Ponieważ Tarantool jest zarówno bazą danych, jak i serwerem aplikacji, zawiera różne moduły. Interesuje nas moduł box — realizuje on pracę z danymi. Kiedy zapisujesz coś w box, Tarantool zapisuje dane na dysku, przechowuje w pamięci lub wykonuje z nimi inne operacje.
Zapisz
Na przykład wchodzimy do modułu box i wywołujemy funkcję box.once. Zmusza ona Tarantoola do uruchomienia naszego kodu podczas inicjalizacji serwera. Tworzymy space, w którym będą przechowywane nasze dane.
local function bootstrap()
local space = box.schema.create_space('example')
space:create_index('primary')
box.schema.user.grant('guest', 'read,write,execute', 'universe')
-- Zabezpieczamy domyślnie
-- box.schema.user.create('example', { password = 'secret' })
-- box.schema.user.grant('example', 'replication')
-- box.schema.user.grant('example', 'read,write,execute', 'space', 'example')
endNastępnie tworzymy indeks podstawowy – primary, według którego będzie można wyszukiwać dane. Domyślnie, jeśli nie podamy żadnych parametrów, zostanie użyte pierwsze pole w każdym rekordzie do indeksu podstawowego.
Następnie nadajemy uprawnienia użytkownikowi guest, z którym łączymy się za pomocą protokołu binarnego. Pozwalamy na odczyt, zapis i wykonanie w całym instancie.
W porównaniu do zwykłych baz danych, wszystko jest tutaj dość proste. Mamy space – obszar, w którym po prostu przechowujemy nasze dane. Każdy rekord nazywa się krotką. Jest pakowany w MessagePack. To bardzo ciekawy format — jest binarny i zajmuje mniej miejsca – 18 bajtów w porównaniu do 27.

Bardzo wygodnie się z nim pracuje. Prawie każdy wiersz, każdy zapis danych może mieć zupełnie różne kolumny.
Wszystkie spacje możemy zobaczyć za pomocą polecenia Box.space. Aby wyróżnić konkretny instans – piszemy box.space example i otrzymujemy pełne informacje o nim.
W Tarantool wbudowane są dwa typy silników: Memory i Vinyl. Memory przechowuje wszystkie dane w pamięci. Dlatego wszystko działa prosto i szybko. Dane są dumpowane na dysk, a także istnieje mechanizm write ahead log, więc nic nie stracimy w przypadku awarii serwera.
Vinyl przechowuje dane na dysku w bardziej znanym nam formacie — co oznacza, że można przechowywać więcej danych, niż mamy pamięci, a Tarantool będzie je odczytywał z dysku.
Teraz będziemy używać Memory.
unix/:/var/run/tarantool/example.control> box.space.example
---
- engine: memtx
before_replace: 'function: 0x41eb02c8'
on_replace: 'function: 0x41eb0568'
ck_constraint: []
field_count: 0
temporary: false
index:
0: &0
unique: true
parts:
- type: unsigned
is_nullable: false
fieldno: 1
id: 0
space_id: 512
type: TREE
name: primary
primary: *0
is_local: false
enabled: true
name: example
id: 512
...
unix/:/var/run/tarantool/example.control>Indeks:
Indeks podstawowy musi być tworzony dla każdej przestrzeni, ponieważ bez niego nic nie będzie działać. Tak jak w każdej bazie, tworzymy pierwsze pole – ID wpisu.
Części:
Tutaj wskazujemy, z czego składa się nasz indeks. Składa się z jednej części – pierwszego pola, które będziemy używać, typu unsigned — liczba całkowita dodatnia. Z tego, co pamiętam z dokumentacji, maksymalna liczba, jaka może być – 18 kwintylionów. Naprawdę dużo.
Następnie możemy wstawiać dane za pomocą polecenia insert.
unix/:/var/run/tarantool/example.control> box.space.example:insert{1, 'test1', 'test2'}
---
- [1, 'test1', 'test2']
...
unix/:/var/run/tarantool/example.control> box.space.example:insert{2, 'test2', 'test3', 'test4'}
---
- [2, 'test2', 'test3', 'test4']
...
unix/:/var/run/tarantool/example.control> box.space.example:insert{3, 'test3'}
---
- [3, 'test3']
...
unix/:/var/run/tarantool/example.control> box.space.example:insert{4, 'test4'}
---
- [4, 'test4']
...
unix/:/var/run/tarantool/example.control>Pierwsze pole jest używane jako klucz podstawowy, więc musi być unikalne. Liczbą kolumn nie jesteśmy ograniczeni, więc możemy wstawiać dowolną ilość danych. Wskazują one w formacie MessagePack, który opisałem powyżej.
Wyświetlanie danych
Następnie możemy wyświetlać dane za pomocą polecenia select.
Box.example.select z kluczem {1} wyświetli żądany wpis. Jeśli pominemy klucz, zobaczymy wszystkie wpisy, jakie mamy. Różnią się one liczba kolumn, ale zasadniczo nie ma tu pojęcia kolumn – są tylko numery pól.
Może być ich absolutnie nieograniczona ilość. Na przykład, musimy je wyszukiwać według drugiego pola. W tym celu tworzymy nowy indeks wtórny.
box.space.example:create_index( ‘secondary’, { type = ‘TREE’, unique = false, parts = {{field = 2, type =’string’} }}) Używamy polecenia Create_index.
Nazywamy go Secondary.
Następnie należy wskazać parametry. Typ indeksu — TREE. Może być nieunikalny, dlatego wprowadzamy Unique = false.
Następnie wskazujemy, z jakich części składa się nasz indeks. Field — to numer pola, do którego przypinamy indeks, i wskazujemy typ string. I tak został utworzony.
unix/:/var/run/tarantool/example.control> box.space.example:create_index('secondary', { type = 'TREE', unique = false, parts = {{field = 2, type = 'string'}}})
---
- unique: false
parts:
- type: string
is_nullable: false
fieldno: 2
id: 1
space_id: 512
type: TREE
name: secondary
...
unix/:/var/run/tarantool/example.control>Teraz możemy go wywołać w ten sposób:
unix/:/var/run/tarantool/example.control> box.space.example.index.secondary:select('test1')
---
- - [1, 'test1', 'test2']
...
Zapis
Jeśli zrestartujemy instancję i ponownie spróbujemy wywołać dane — zobaczymy, że ich nie ma — wszystko puste. Tak się dzieje, ponieważ Tarantool wykonuje punkty kontrolne i zapisuje dane na dysku, ale jeśli zatrzymamy pracę przed najbliższym zapisaniem, stracimy wszystkie operacje — ponieważ przywrócimy się do ostatniego punktu kontrolnego, który był, na przykład, dwie godziny temu.
Zapis każdą sekundę też nie jest możliwy — ponieważ ciągłe zrzucanie 20 GB na dysk to niezbyt dobry pomysł.
W tym celu opracowano i wdrożono koncepcję logu zapisu wstecznego. Dzięki temu każda zmiana w danych tworzy wpis w małym pliku logu zapisu wstecznego.
Każdy wpis przed punktem kontrolnym jest w nim zapisywany. Dla tych plików ustalamy rozmiar — na przykład 64 MB. Gdy się zapełni, zapis zaczyna trafiać do drugiego pliku. Po restarcie Tarantool przywraca się z ostatniego punktu kontrolnego, a następnie nawiązuje wszystkie późniejsze transakcje do momento zatrzymania.

Aby zrealizować taki zapis, należy wskazać opcję w ustawieniach box.cfg (w pliku example.lua):
wal_mode = “write”;Użycie danych
Z tym, co właśnie napisaliśmy, możecie używać Tarantoola do przechowywania danych, a będzie on działał bardzo szybko jako baza danych. A teraz wisienka na torcie – co można z tym wszystkim zrobić.
Tworzymy aplikację
Na przykład, napiszemy dla Tarantoola taką aplikację
Zobacz aplikację pod spoilerem
box.cfg {
listen = '0.0.0.0:3301';
io_collect_interval = nil;
readahead = 16320;
memtx_memory = 128 * 1024 * 1024; -- 128Mb
memtx_min_tuple_size = 16;
memtx_max_tuple_size = 128 * 1024 * 1024; -- 128Mb
vinyl_memory = 128 * 1024 * 1024; -- 128Mb
vinyl_cache = 128 * 1024 * 1024; -- 128Mb
vinyl_max_tuple_size = 128 * 1024 * 1024; -- 128Mb
vinyl_write_threads = 2;
wal_mode = "write";
wal_max_size = 256 * 1024 * 1024;
checkpoint_interval = 60 * 60; -- jedna godzina
checkpoint_count = 6;
force_recovery = true;
log_level = 5;
log_nonblock = false;
too_long_threshold = 0.5;
read_only = false
}
local function bootstrap()
local space = box.schema.create_space('example')
space:create_index('primary')
box.schema.user.create('example', { password = 'secret' })
box.schema.user.grant('example', 'read,write,execute', 'space', 'example')
box.schema.user.create('repl', { password = 'replication' })
box.schema.user.grant('repl', 'replication')
end
-- przy pierwszym uruchomieniu twórz przestrzeń i skonfiguruj uprawnienia
box.once('replica', bootstrap)
-- włączanie dostępu do konsoli
console = require('console')
console.listen('127.0.0.1:3302')
-- konfiguracja http
local charset = {} do -- [0-9a-zA-Z]
for c = 48, 57 do table.insert(charset, string.char(c)) end
for c = 65, 90 do table.insert(charset, string.char(c)) end
for c = 97, 122 do table.insert(charset, string.char(c)) end
end
local function randomString(length)
if not length or length <= 0 then return '' end
math.randomseed(os.clock()^5)
return randomString(length - 1) .. charset[math.random(1, #charset)]
end
local http_router = require('http.router')
local http_server = require('http.server')
local json = require('json')
local httpd = http_server.new('0.0.0.0', 8080, {
log_requests = true,
log_errors = true
})
local router = http_router.new()
local function get_count()
local cnt = box.space.example:len()
return cnt
end
router:route({method = 'GET', path = '\/count'}, function()
return {status = 200, body = json.encode({count = get_count()})}
end)
router:route({method = 'GET', path = '\/token'}, function()
local token = randomString(32)
local last = box.space.example:len()
box.space.example:insert{ last + 1, token }
return {status = 200, body = json.encode({token = token})}
end)
prometheus = require('prometheus')
fiber = require('fiber')
tokens_count = prometheus.gauge("tarantool_tokens_count",
"Liczba tokenów API")
function monitor_tokens_count()
while true do
tokens_count:set(get_count())
fiber.sleep(5)
end
end
fiber.create(monitor_tokens_count)
router:route( { method = 'GET', path = '\/metrics' }, prometheus.collect_http)
httpd:set_router(router)
httpd:start()Ogłaszamy pewną tablicę w lua, która definiuje znaki. Ta tablica jest potrzebna do generowania losowego ciągu.
local charset = {} do -- [0-9a-zA-Z]
for c = 48, 57 do table.insert(charset, string.char(c)) end
for c = 65, 90 do table.insert(charset, string.char(c)) end
for c = 97, 122 do table.insert(charset, string.char(c)) end
endNastępnie ogłaszamy funkcję – randomString i w nawiasach przypiszemy wartość długości.
local function randomString(length)
if not length or length <= 0 then return '' end
math.randomseed(os.clock()^5)
return randomString(length - 1) .. charset[math.random(1, #charset)]
endNastępnie do naszego serwera Tarantool podłączamy http-router oraz http-server, JSON, które będziemy zwracać klientowi.
local http_router = require('http.router')
local http_server = require('http.server')
local json = require('json')Następnie uruchamiamy serwer http na porcie 8080 na wszystkich interfejsach, który będzie rejestrował wszystkie żądania i błędy.
local httpd = http_server.new('0.0.0.0', 8080, {
log_requests = true,
log_errors = true
})Następnie ogłaszamy trasę, że jeśli na port 8080 /count przychodzi żądanie metodą GET, to wywołujemy funkcję z jednej linijki. Zwraca ona status — 200, 404, 403 lub inny, który wskażemy.
router:route({method = 'GET', path = ' /count'}, function()
return {status = 200, body = json.encode({count = get_count()})}
end)W ciele zwracamy json.encode, w której wskazujemy count oraz get_count, która jest wywoływana i pokazuje liczbę rekordów w naszej bazie.
Druga metoda
router:route({method = 'GET', path = ' /token'}, function()
local token = randomString(32)
local last = box.space.example:len()
box.space.example:insert{ last + 1, token }
return {status = 200, body = json.encode({token = token})}
end)Gdzie w linijce router:route({method = ‘GET’, path = ‘ /token’}, function() wywołujemy funkcję i generujemy token.
Ciąg local token = randomString(32) – to losowy ciąg składający się z 32 znaków.
W linii local last = box.space.example:len() wyciągamy ostatni element.
A w linijce box.space.example:insert{ last + 1, token } zapisujemy dane do naszej bazy, czyli po prostu zwiększamy ID o 1. Można to zresztą zrobić nie tylko w taki niezgrabny sposób. W Tarantule są sekwencje do tego celu.
Zapisujemy tam token.
W ten sposób, w jednym pliku napisaliśmy aplikację. Może ona od razu obsługiwać dane, a moduł box wykona całą brudną robotę za Ciebie.
Słucha http i pracuje z danymi, wszystko jest w jednym instansie — zarówno aplikacja, jak i dane. Dlatego wszystko przebiega wystarczająco szybko.
Aby uruchomić, instalujemy moduł http:
Jak to robimy, zobacz w spoilerze
root@test2:₩ tarantoolctl rocks install http
Instalowanie http://rocks.tarantool.org/http-scm-1.src.rock
Brakujące zależności dla http scm-1:
checks >= 3.0.1 (niezainstalowane)
http scm-1 wymaga checks >= 3.0.1 (niezainstalowane)
Instalowanie http://rocks.tarantool.org/checks-3.0.1-1.rockspec
Klontowanie do 'checks'...
remote: Enumerating objects: 28, done.
remote: Counting objects: 100% (28/28), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 28 (delta 1), reused 16 (delta 1), pack-reused 0
Receiving objects: 100% (28/28), 12.69 KiB | 12.69 MiB/s, done.
Resolving deltas: 100% (1/1), done.
Uwaga: sprawdzanie '580388773ef11085015b5a06fe52d61acf16b201'.
Jesteś w stanie 'detached HEAD'. Możesz rozglądać się, wprowadzać eksperymentalne
zmiany i je zatwierdzać, a także możesz zignorować wszelkie zatwierdzenia, które wprowadzisz w tym
stanie, nie wpływając na żadne gałęzie, wykonując kolejne checkout.
Jeśli chcesz stworzyć nową gałąź, aby zachować dokonane zatwierdzenia, możesz
to zrobić (teraz lub później) używając -b z poleceniem checkout ponownie. Przykład:
git checkout -b
Brak istniejącego manifestu. Próbuję odbudować...
checks 3.0.1-1 jest teraz zainstalowane w /.rocks (licencja: BSD)
-- Identyfikacja kompilatora C to GNU 7.5.0
-- Sprawdzenie, czy kompilator C działa: /usr/bin/cc
-- Sprawdzenie, czy kompilator C działa: /usr/bin/cc -- działa
-- Wykrywanie informacji ABI kompilatora C
-- Wykrywanie informacji ABI kompilatora C - zakończone
-- Wykrywanie funkcji kompilacji C
-- Wykrywanie funkcji kompilacji C - zakończone
-- Znaleziono TARANTOOL: /usr/include (znaleziono wersję "2.4.2-80-g18f2bc82d")
-- Tarantool LUADIR to /.rocks/share/tarantool/rocks/http/scm-1/lua
-- Tarantool LIBDIR to /.rocks/share/tarantool/rocks/http/scm-1/lib
-- Konfiguracja zakończona
-- Generowanie zakończone
CMake Warning:
Ręcznie określone zmienne nie zostały użyte przez projekt:
version
-- Pliki budowy zostały zapisane do: /tmp/luarocks_http-scm-1-V4P9SM/http/build.luarocks
Skanowanie zależności dla celu httpd
[ 50%] Budowanie obiektu C http/CMakeFiles/httpd.dir/lib.c.o
W pliku zawartym z /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:32:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c: W funkcji ‘tpl_term’:
/usr/include/tarantool/lauxlib.h:144:15: ostrzeżenie: to stwierdzenie może przejść [-Wimplicit-fallthrough=]
(*(B)->p++ = (char)(c)))
~~~~~~~~~~~^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:62:7: uwaga: w rozbudowie makra ‘luaL_addchar’
luaL_addchar(b, '\');
^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:63:6: uwaga: tutaj
domyślnie:
^~~~~~~
W pliku zawartym z /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:39:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h: W funkcji ‘tpe_parse’:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:147:9: ostrzeżenie: to stwierdzenie może przejść [-Wimplicit-fallthrough=]
type = TPE_TEXT;
~~~~~^~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:149:3: uwaga: tutaj
przypadek TPE_LINECODE:
^~~~
W pliku zawartym z /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:40:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h: W funkcji ‘httpfast_parse’:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:372:22: ostrzeżenie: to stwierdzenie może przejść [-Wimplicit-fallthrough=]
code = 0;
~~~~~^~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:374:13: uwaga: tutaj
przypadek status:
^~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:393:23: ostrzeżenie: to stwierdzenie może przejść [-Wimplicit-fallthrough=]
state = message;
~~~~~~^~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:395:13: uwaga: tutaj
przypadek message:
^~~~
[100%] Linkowanie biblioteki współdzielonej C lib.so
[100%] Zbudowany cel httpd
[100%] Zbudowany cel httpd
Zainstaluj projekt...
-- Konfiguracja instalacji: "Debug"
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/VERSION.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lib/http/lib.so
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/init.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/tsgi_adapter.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/nginx_server/init.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/init.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/fs.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/matching.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/middleware.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/request.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/response.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/tsgi.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/utils.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/mime_types.lua
-- Instalowanie: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/codes.lua
http scm-1 jest teraz zainstalowane w /.rocks (licencja: BSD)
root@test2:₩Do uruchomienia potrzebujemy także prometheus:
root@test2:~# tarantoolctl rocks install prometheus
Instalowanie http://rocks.tarantool.org/prometheus-scm-1.rockspec
Klonowanie do 'prometheus'...
remote: Enumerowanie obiektów: 19, gotowe.
remote: Zliczanie obiektów: 100% (19/19), gotowe.
remote: Kompresowanie obiektów: 100% (19/19), gotowe.
remote: Całkowita liczba 19 (delta 2), ponownie użyto 5 (delta 0), pakiet ponownie użyty 0
Odbieranie obiektów: 100% (19/19), 10.73 KiB | 10.73 MiB/s, gotowe.
Rozwiązywanie deltas: 100% (2/2), gotowe.
prometheus scm-1 jest teraz zainstalowany w /.rocks (licencja: BSD)
root@test2:~#
Uruchamiamy i możemy korzystać z modułów
root@test2:~# curl -D - -s http://127.0.0.1:8080/token
HTTP/1.1 200 Ok
Content-length: 44
Server: Tarantool http (tarantool v2.4.2-80-g18f2bc82d)
Connection: keep-alive
{"token":"e2tPq9l5Z3QZrewRf6uuoJUl3lJgSLOI"}
root@test2:~# curl -D - -s http://127.0.0.1:8080/token
HTTP/1.1 200 Ok
Content-length: 44
Server: Tarantool http (tarantool v2.4.2-80-g18f2bc82d)
Connection: keep-alive
{"token":"fR5aCA84gj9eZI3gJcV0LEDl9XZAG2Iu"}
root@test2:~# curl -D - -s http://127.0.0.1:8080/count
HTTP/1.1 200 Ok
Content-length: 11
Server: Tarantool http (tarantool v2.4.2-80-g18f2bc82d)
Connection: keep-alive
{"count":2}root@test2:~# /count отдает нам статус 200.
/token выдает токен и делает запись этого токена в базу.
Testujemy szybkość
Uruchommy benchmark z 50 000 żądaniami. Równoległych żądań będzie 500.
root@test2:~# ab -c 500 -n 50000 http://127.0.0.1:8080/token
To jest ApacheBench, Wersja 2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licencjonowane dla Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (bądź cierpliwy)
Zrealizowano 5000 żądań
Zrealizowano 10000 żądań
Zrealizowano 15000 żądań
Zrealizowano 20000 żądań
Zrealizowano 25000 żądań
Zrealizowano 30000 żądań
Zrealizowano 35000 żądań
Zrealizowano 40000 żądań
Zrealizowano 45000 żądań
Zrealizowano 50000 żądań
Zrealizowano 50000 żądań
Oprogramowanie serwera: Tarantool
Nazwa hosta serwera: 127.0.0.1
Port serwera: 8080
Ścieżka dokumentu: /token
Długość dokumentu: 44 bajty
Poziom konkurencyjności: 500
Czas potrzebny na testy: 14.578 sekundy
Kompletne żądania: 50000
Nieudane żądania: 0
Całkowita ilość przesyłanych danych: 7950000 bajtów
HTML przesyłane: 2200000 bajtów
Żądania na sekundę: 3429.87 [# /sec] (średnio)
Czas na żądanie: 145.778 [ms] (średnio)
Czas na żądanie: 0.292 [ms] (średnio, w całym zestawie równoległych żądań)
Wskaźnik transferu: 532.57 [Kbytes /sec] odebrane
Czasy połączeń (ms)
min średni[+/-sd] mediana max
Połączenie: 0 10 103.2 0 3048
Przetwarzanie: 12 69 685.1 15 13538
Oczekiwanie: 12 69 685.1 15 13538
Całkowity: 12 78 768.2 15 14573
Procent żądań zrealizowanych w określonym czasie (ms)
50% 15
66% 15
75% 16
80% 16
90% 16
95% 16
98% 21
99% 42
100% 14573 (najdłuższe żądanie)
root@test2:~#Tokeny są wydawane. I stale zapisujemy dane. 99% żądań zostało obsłużonych w ciągu 42 milisekund. Oznacza to, że osiągamy około 3500 żądań na sekundę na małej maszynie, która ma 2 rdzenie i 4 gigabajty pamięci.
Można również wybrać jakiś 50000-token i sprawdzić jego wartość.
Można używać nie tylko http, uruchamiać funkcje w tle, które przetwarzają twoje dane. Dodatkowo dostępne są różne wyzwalacze. Na przykład, możesz wywoływać funkcje przy aktualizacjach, coś sprawdzać – naprawiać konflikty.
Można pisać aplikacje-skrypty bezpośrednio na serwerze bazy danych, nie mając żadnych ograniczeń, podłączać dowolne moduły i realizować dowolną logikę.
Serwer aplikacji może łączyć się z zewnętrznymi serwerami, pobierać dane i przechowywać je w swojej bazie. Dane z tej bazy będą używane przez inne aplikacje.
To będzie robił sam Tarantool, więc nie trzeba będzie pisać osobnej aplikacji.
Na zakończenie
To dopiero pierwsza część dużej pracy. Druga zostanie opublikowana już wkrótce na blogu Mail.ru Group, a my na pewno dodamy do niej link w tym materiale.
Jeśli chcesz uczestniczyć w wydarzeniach, gdzie tworzymy takie rzeczy na żywo i zadawać pytania w czasie rzeczywistym, dołącz do.
Jeśli potrzebujesz migracji do chmury lub masz pytania dotyczące swojej infrastruktury, .
P.S. Mamy dwa bezpłatne audyty miesięcznie, być może to właśnie Twój projekt znajdzie się w ich gronie.
Źródło: habr.com
