W Tarantool możesz połączyć superszybką bazę danych i aplikację do pracy z nimi. Oto jak łatwo to zrobić

Pięć lat temu próbowałem pracować z Tarantoolem, ale wtedy mi to nie wychodziło. Ale ostatnio prowadziłem webinar, na którym mówiłem o Hadoopie, o tym, jak działa MapReduce. Tam zadano mi pytanie - „Dlaczego nie użyć Tarantoola do tego zadania?”.

Z ciekawości postanowiłem do niego wrócić, przetestować najnowszą wersję – i tym razem projekt bardzo mi się spodobał. Teraz pokażę, jak napisać prostą aplikację w Tarantoolu, załadować ją i sprawdzić wydajność, a zobaczysz, jakie wszystko jest tam łatwe i fajne.

W Tarantool możesz połączyć superszybką bazę danych i aplikację do pracy z nimi. Oto jak łatwo to zrobić

Co to jest Tarantool

Tarantool pozycjonuje się jako ultraszybka baza danych. Możesz tam umieścić dowolne dane. Ponadto replikuj je, shard — to znaczy podziel ogromną ilość danych na kilka serwerów i połącz wyniki z nich — stwórz odporne na błędy łącza master-master.

Po drugie, jest to serwer aplikacji. Można na nim pisać swoje aplikacje, pracować z danymi, np. kasować stare wpisy w tle według określonych zasad. Możesz napisać serwer Http bezpośrednio w Tarantuli, który będzie działał z danymi: podaj ich numer, napisz tam nowe dane i zredukuj to wszystko do wzorca.

Czytałem artykuł o tym, jak chłopaki stworzyli 300-liniową kolejkę wiadomości, która po prostu rwie i miota - mają minimalną wydajność 20 000 wiadomości na sekundę. Tutaj naprawdę możesz się odwrócić i napisać bardzo dużą aplikację, a te nie będą przechowywane, jak w PostgreS.

W przybliżeniu taki serwer, tylko prosty, postaram się opisać w tym artykule.

Instalacja

Do testu uruchomiłem trzy standardowe maszyny wirtualne - 20-gigabajtowy dysk twardy, Ubuntu 18.04. 2 wirtualne procesory i 4 gigabajty pamięci.

Instalujemy Tarantool - uruchamiamy skrypt bash lub dodajemy repozytorium i robimy apt get install Tarantool. Link do skryptu - (curl -L https://tarantool.io/installer.sh | VER=2.4 sudo -E bash). Mamy komendy typu:

tarantolctl to główne polecenie do zarządzania instancjami Tarantula.
/etc/tarantool - tutaj leży cała konfiguracja.
var/log/tarantool - oto logi.
var/lib/tarantool - tu leżą dane, a następnie są one dzielone na instancje.

Istnieją foldery instance-available i instance-enable - zawiera to, co zostanie uruchomione - plik konfiguracyjny instancji z kodem lua, który opisuje, na jakich portach nasłuchuje, jaka pamięć jest dla niej dostępna, ustawienia silnika Vinyl, kod działający podczas uruchamiania serwerów, shardingu, kolejek, usuwania przestarzałych danych i tak dalej.

Instancje działają jak w PostgreS. Na przykład chcesz uruchomić wiele kopii bazy danych, która zawiesza się na różnych portach. Okazuje się, że na jednym serwerze uruchamianych jest kilka instancji bazy danych, które zawieszają się na różnych portach. Mogą mieć zupełnie inne ustawienia – jedna instancja realizuje jedną logikę, druga – inną.

Zarządzanie instancjami

Mamy polecenie tarantoolctl, które pozwala nam zarządzać instancjami Tarantuli. Na przykład przykład sprawdzania tarantoolctl sprawdzi plik konfiguracyjny i powie, że plik jest w porządku, jeśli nie ma błędów składniowych.

Możesz zobaczyć status instancji - przykład statusu tarantoolctl. W ten sam sposób możesz uruchomić, zatrzymać, ponownie uruchomić.

Gdy instancja jest już uruchomiona, można się z nią połączyć na dwa sposoby.

1. Konsola administracyjna

Domyślnie Tarantool otwiera gniazdo i wysyła zwykły tekst ASCII, aby kontrolować Tarantulę. Połączenie z konsolą zawsze odbywa się z poziomu administratora, nie ma uwierzytelniania, więc nie trzeba wyjmować portu konsoli, aby sterować Tarantulą na zewnątrz.

Aby połączyć się w ten sposób, musisz wejść w Tarantoolctl wprowadź nazwę instancji. Polecenie uruchomi konsolę i połączy się jako administrator. Nigdy nie wystawiaj portu konsoli na zewnątrz - lepiej zostawić go jako gniazdo jednostki. Wtedy tylko ci, którzy mają dostęp do zapisu w gnieździe, będą mogli połączyć się z Tarantulą.

Ta metoda jest potrzebna do spraw administracyjnych. Do pracy z danymi użyj drugiej metody - protokołu binarnego.

2. Używanie protokołu binarnego do łączenia się z określonym portem

W konfiguracji znajduje się dyrektywa nasłuchiwania, która otwiera port dla komunikacji zewnętrznej. Ten port jest używany z protokołem binarnym i włączone jest tam uwierzytelnianie.

Do tego połączenia używane jest połączenie tarantoolctl z numerem portu. Za jego pomocą możesz łączyć się ze zdalnymi serwerami, korzystać z uwierzytelniania i nadawać różne prawa dostępu.

Moduł rejestracji danych i skrzynki

Ponieważ Tarantool jest zarówno bazą danych, jak i serwerem aplikacji, ma różne moduły. Nas interesuje moduł pudełkowy - realizuje pracę z danymi. Kiedy piszesz coś do pudełka, Tarantool zapisuje dane na dysku, przechowuje je w pamięci lub robi z nimi coś innego.

Rekord

Na przykład wchodzimy do modułu box i wywołujemy funkcję box.once. Zmusi Tarantool do uruchomienia naszego kodu podczas inicjalizacji serwera. Tworzymy przestrzeń, w której 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')

    -- Keep things safe by default
    --  box.schema.user.create('example', { password = 'secret' })
    --  box.schema.user.grant('example', 'replication')
    --  box.schema.user.grant('example', 'read,write,execute', 'space', 'example')
end

Następnie tworzymy indeks podstawowy - primary - po którym możemy wyszukiwać dane. Domyślnie, jeśli nie określono żadnych parametrów, zostanie użyte pierwsze pole w każdym wpisie dla indeksu startera.

Następnie dokonujemy grantu dla gościa, w ramach którego łączymy się protokołem binarnym. Zezwalamy na odczyt, zapis i wykonywanie w całej instancji.

W porównaniu do konwencjonalnych baz danych tutaj wszystko jest dość proste. Mamy przestrzeń – obszar, w którym po prostu przechowywane są nasze dane. Każdy wpis jest nazywany krotką. Jest spakowany w MessagePack. To bardzo fajny format - jest binarny i zajmuje mniej miejsca - 18 bajtów w porównaniu do 27.

W Tarantool możesz połączyć superszybką bazę danych i aplikację do pracy z nimi. Oto jak łatwo to zrobić

Praca z nim jest dość wygodna. Prawie każda linia, każdy wpis danych może mieć zupełnie inne kolumny.

Możemy wyświetlić wszystkie przestrzenie za pomocą polecenia Box.space. Aby wybrać konkretną instancję, piszemy przykład box.space i uzyskujemy o nim pełną informację.

Istnieją dwa typy silników wbudowanych w Tarantool: Memory i Vinyl. Pamięć przechowuje wszystkie dane w pamięci. Dlatego wszystko działa prosto i szybko. Dane są zrzucane na dysk, istnieje również mechanizm dziennika zapisu z wyprzedzeniem, dzięki czemu nic nie stracimy w przypadku awarii serwera.

Vinyl przechowuje dane na dysku w bardziej znanej formie – czyli można przechować więcej danych niż mamy pamięci, a Tarantula odczyta je z dysku.

Teraz użyjemy pamięci.

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:

Dla dowolnej przestrzeni należy utworzyć indeks podstawowy, ponieważ bez niego nic nie będzie działać. Jak w każdej bazie danych tworzymy pierwsze pole - identyfikator rekordu.

Części:

W tym miejscu określamy, z czego składa się nasz indeks. Składa się z jednej części - pierwszego pola, którego użyjemy, typu unsigned - dodatniej liczby całkowitej. O ile pamiętam z dokumentacji, maksymalna liczba, jaka może być, to 18 kwintylionów. Wiele niesamowitych.

Następnie możemy wstawić 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. Nie ogranicza nas liczba kolumn, więc możemy wstawić tam tyle danych, ile nam się podoba. Są one określone w formacie MessagePack, który opisałem powyżej.

Wyjście danych

Następnie możemy wyświetlić dane za pomocą polecenia select.

Box.example.select za pomocą klawisza {1} wyświetli żądany wpis. Jeśli pominiemy klucz, zobaczymy wszystkie posiadane przez nas rekordy. Wszystkie różnią się liczbą kolumn, ale tutaj w zasadzie nie ma pojęcia kolumn - są numery pól.

Danych może być absolutnie tyle, ile chcesz. I na przykład musimy ich szukać w drugim polu. W tym celu tworzymy nowy indeks pomocniczy.


box.space.example:create_index( ‘secondary’, { type = ‘TREE’, unique = false, parts = {{field = 2, type =’string’} }}) 

Używamy polecenia Create_index.
Nazywamy to drugorzędnym.

Następnie musisz określić parametry. Typ indeksu to DRZEWO. Może nie być unikalny, więc wpisujemy Unique = false.

Następnie wskazujemy z jakich części składa się nasz indeks. Pole to numer pola, z którym wiążemy indeks i określa typ ciągu. I tak powstał.

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 tak możemy to nazwać:

unix/:/var/run/tarantool/example.control> box.space.example.index.secondary:select('test1')
---
- - [1, 'test1', 'test2']
...

Zachowanie

Jeśli ponownie uruchomimy instancję i spróbujemy ponownie wywołać dane, zobaczymy, że ich tam nie ma - wszystko jest puste. Dzieje się tak, ponieważ Tarantool robi punkty kontrolne i zapisuje dane na dysku, ale jeśli przestaniemy działać przed kolejnym zapisem, stracimy wszystkie operacje – bo odzyskamy stan z ostatniego punktu kontrolnego, który był np. dwie godziny temu.

Zapisywanie każdej sekundy też się nie sprawdzi – bo ciągłe zrzucanie 20 GB na dysk to taki sobie pomysł.

W tym celu wymyślono i wdrożono koncepcję dziennika zapisu z wyprzedzeniem. Z jego pomocą dla każdej zmiany danych tworzony jest zapis w małym pliku dziennika zapisu z wyprzedzeniem.

Każdy wpis do punktu kontrolnego jest w nich przechowywany. Dla tych plików ustalamy rozmiar - na przykład 64 mb. Gdy się zapełni, nagrywanie rozpocznie się w drugim pliku. A po ponownym uruchomieniu Tarantool odzyskuje z ostatniego punktu kontrolnego, a następnie przewija wszystkie późniejsze transakcje, aż się zatrzyma.

W Tarantool możesz połączyć superszybką bazę danych i aplikację do pracy z nimi. Oto jak łatwo to zrobić

Aby wykonać taki zapis należy określić opcję w ustawieniach box.cfg (w pliku example.lua):

wal_mode = “write”;

użycie danych

Dzięki temu, co napisaliśmy teraz, możesz używać Tarantuli do przechowywania danych i będzie działać bardzo szybko jako baza danych. A teraz wisienka na torcie – co można z tym wszystkim zrobić.

Pisanie aplikacji

Na przykład napiszmy taką aplikację dla Tarantuli

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; -- one hour
    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

-- for first run create a space and add set up grants
box.once('replica', bootstrap)

-- enabling console access
console = require('console')
console.listen('127.0.0.1:3302')

-- http config
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",
                              "API Tokens Count")

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()

Deklarujemy tabelę w lua, która definiuje symbole. Ta tabela jest potrzebna do wygenerowania losowego ciągu znaków.

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

Następnie deklarujemy funkcję - randomString i podajemy w nawiasach 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)]
end

Następnie łączymy router http i serwer http z naszym serwerem Tarantula, JSON, który przekażemy klientowi.

local http_router = require('http.router')
local http_server = require('http.server')
local json = require('json')

Następnie zaczynamy na porcie 8080 na wszystkich interfejsach serwera http, 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 deklarujemy trasę, że jeśli żądanie z metodą GET dotrze na port 8080 /count, to wywołamy funkcję z jednej linii. Zwraca status - 200, 404, 403 lub cokolwiek, co określimy.

router:route({method = 'GET', path = '/count'}, function()
    return {status = 200, body = json.encode({count = get_count()})}
end)

W body zwracamy json.encode, określamy w nim count i getcount, który jest wywoływany i pokazuje ilość rekordów w naszej bazie danych.

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 kolejce router:route({metoda = 'GET', ścieżka = '/token'}, funkcja() wywołujemy funkcję i generujemy token.

Linia token lokalny = randomString(32) jest losowym ciągiem 32 znaków.
W kolejce lokalny ostatni = box.space.example:len() wyciągamy ostatni element.
I w linii pudełko.przestrzeń.przykład:wstaw{ ostatni + 1, token } zapisujemy dane do naszej bazy, czyli po prostu zwiększamy ID o 1. Notabene da się to zrobić nie tylko w taki niezdarny sposób. Tarantula ma sekwencje dla tego przypadku.

Piszemy tam token.

Napisaliśmy więc aplikację w jednym pliku. Możesz uzyskać dostęp do danych od razu, a moduł skrzynki wykona całą brudną robotę za Ciebie.

Nasłuchuje http i pracuje z danymi, wszystko jest w jednej instancji - zarówno aplikacja, jak i dane. Dlatego wszystko dzieje się dość szybko.

Aby uruchomić, instalujemy moduł http:

Jak to robimy, zobacz pod spoilerem

root@test2:/# tarantoolctl rocks install http
Installing http://rocks.tarantool.org/http-scm-1.src.rock
Missing dependencies for http scm-1:
   checks >= 3.0.1 (not installed)

http scm-1 depends on checks >= 3.0.1 (not installed)
Installing http://rocks.tarantool.org/checks-3.0.1-1.rockspec

Cloning into '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.
Note: checking out '580388773ef11085015b5a06fe52d61acf16b201'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

No existing manifest. Attempting to rebuild...
checks 3.0.1-1 is now installed in /.rocks (license: BSD)

-- The C compiler identification is GNU 7.5.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Found TARANTOOL: /usr/include (found version "2.4.2-80-g18f2bc82d")
-- Tarantool LUADIR is /.rocks/share/tarantool/rocks/http/scm-1/lua
-- Tarantool LIBDIR is /.rocks/share/tarantool/rocks/http/scm-1/lib
-- Configuring done
-- Generating done
CMake Warning:
  Manually-specified variables were not used by the project:

    version


-- Build files have been written to: /tmp/luarocks_http-scm-1-V4P9SM/http/build.luarocks
Scanning dependencies of target httpd
[ 50%] Building C object http/CMakeFiles/httpd.dir/lib.c.o
In file included from /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:32:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c: In function ‘tpl_term’:
/usr/include/tarantool/lauxlib.h:144:15: warning: this statement may fall through [-Wimplicit-fallthrough=]
    (*(B)->p++ = (char)(c)))
    ~~~~~~~~~~~^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:62:7: note: in expansion of macro ‘luaL_addchar’
       luaL_addchar(b, '\');
       ^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:63:6: note: here
      default:
      ^~~~~~~
In file included from /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:39:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h: In function ‘tpe_parse’:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:147:9: warning: this statement may fall through [-Wimplicit-fallthrough=]
    type = TPE_TEXT;
    ~~~~~^~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:149:3: note: here
   case TPE_LINECODE:
   ^~~~
In file included from /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:40:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h: In function ‘httpfast_parse’:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:372:22: warning: this statement may fall through [-Wimplicit-fallthrough=]
                 code = 0;
                 ~~~~~^~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:374:13: note: here
             case status:
             ^~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:393:23: warning: this statement may fall through [-Wimplicit-fallthrough=]
                 state = message;
                 ~~~~~~^~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:395:13: note: here
             case message:
             ^~~~
[100%] Linking C shared library lib.so
[100%] Built target httpd
[100%] Built target httpd
Install the project...
-- Install configuration: "Debug"
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/VERSION.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lib/http/lib.so
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/init.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/tsgi_adapter.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/nginx_server/init.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/init.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/fs.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/matching.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/middleware.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/request.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/response.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/tsgi.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/utils.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/mime_types.lua
-- Installing: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/codes.lua
http scm-1 is now installed in /.rocks (license: BSD)

root@test2:/#

Potrzebujemy również Prometeusza do uruchomienia:

root@test2:/# tarantoolctl rocks install prometheus
Installing http://rocks.tarantool.org/prometheus-scm-1.rockspec

Cloning into 'prometheus'...
remote: Enumerating objects: 19, done.
remote: Counting objects: 100% (19/19), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 19 (delta 2), reused 5 (delta 0), pack-reused 0
Receiving objects: 100% (19/19), 10.73 KiB | 10.73 MiB/s, done.
Resolving deltas: 100% (2/2), done.
prometheus scm-1 is now installed in /.rocks (license: BSD)

root@test2:/#

Uruchamiamy i mamy dostęp do 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 daje nam status 200.
/token wystawia token i zapisuje ten token w bazie danych.

Testowanie prędkości

Przeprowadźmy test porównawczy dla 50 000 zapytań. Żądań konkurencyjnych będzie 500.

root@test2:/# ab -c 500 -n 50000 http://127.0.0.1:8080/token
This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Completed 30000 requests
Completed 35000 requests
Completed 40000 requests
Completed 45000 requests
Completed 50000 requests
Finished 50000 requests


Server Software:        Tarantool
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /token
Document Length:        44 bytes

Concurrency Level:      500
Time taken for tests:   14.578 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      7950000 bytes
HTML transferred:       2200000 bytes
Requests per second:    3429.87 [#/sec] (mean)
Time per request:       145.778 [ms] (mean)
Time per request:       0.292 [ms] (mean, across all concurrent requests)
Transfer rate:          532.57 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   10 103.2      0    3048
Processing:    12   69 685.1     15   13538
Waiting:       12   69 685.1     15   13538
Total:         12   78 768.2     15   14573

Percentage of the requests served within a certain time (ms)
  50%     15
  66%     15
  75%     16
  80%     16
  90%     16
  95%     16
  98%     21
  99%     42
 100%  14573 (longest request)
root@test2:/#

Tokeny są wydawane. I stale rejestrujemy dane. 99% żądań zostało zrealizowanych w ciągu 42 milisekund. W związku z tym mamy około 3500 żądań na sekundę na małej maszynie, gdzie są 2 rdzenie i 4 gigabajty pamięci.

Możesz także wybrać token o wartości 50000 i zobaczyć jego wartość.

Możesz używać nie tylko http, uruchamiać funkcje w tle, które przetwarzają Twoje dane. Poza tym są różne wyzwalacze. Na przykład możesz wywoływać funkcje przy aktualizacjach, sprawdzać coś - naprawiać konflikty.

Możesz pisać aplikacje skryptowe bezpośrednio w samym serwerze bazy danych i nie być niczym ograniczonym, łączyć dowolne moduły i implementować dowolną logikę.

Serwer aplikacji może uzyskiwać dostęp do zewnętrznych serwerów, gromadzić dane i dodawać je do swojej bazy danych. Dane z tej bazy danych będą używane przez inne aplikacje.

Zrobi to sama Tarantula i nie ma potrzeby pisania osobnej aplikacji.

Na zakończenie

To tylko pierwsza część dużej pracy. Drugi zostanie wkrótce opublikowany na blogu Mail.ru Group i na pewno dodamy do niego link w tym materiale.

Jeśli chcesz uczestniczyć w wydarzeniach, podczas których tworzymy te rzeczy online i zadawać pytania w czasie rzeczywistym, połącz się z DevOps przez kanał REBRAIN.

Jeśli musisz przenieść się do chmury lub masz pytania dotyczące swojej infrastruktury, Zachęcamy do złożenia wniosku.

PS Mamy 2 bezpłatne audyty miesięcznie, być może Twój projekt będzie jednym z nich.

Źródło: www.habr.com

Dodaj komentarz