In Tarantool können Sie eine super schnelle Datenbank mit einer Anwendung zur Bearbeitung kombinieren. So einfach wird es gemacht.

Vor fünf Jahren habe ich versucht, mit Tarantool zu arbeiten, aber damals hat er mir nicht gefallen. Kürzlich habe ich ein Webinar gehalten, in dem ich über Hadoop und die Funktionsweise von MapReduce gesprochen habe. Dort wurde mir die Frage gestellt: "Warum nicht Tarantool für diese Aufgabe nutzen?".

Aus Neugier habe ich beschlossen, zu ihm zurückzukehren, die neueste Version zu testen – und dieses Mal mochte ich das Projekt sehr. Jetzt zeige ich Ihnen, wie man eine einfache Anwendung in Tarantool schreibt, sie belastet und die Leistung überprüft, und Sie werden sehen, wie einfach und großartig es ist.

In Tarantool können Sie eine super schnelle Datenbank mit einer Anwendung zur Bearbeitung kombinieren. So einfach wird es gemacht.

Was ist Tarantool

Tarantool positioniert sich als superschnelle Datenbank. Dort können Sie alle Arten von Daten einfügen, die Sie möchten. Zudem können Sie sie replizieren, sharden – das heißt, eine riesige Menge an Daten auf mehrere Server aufteilen und die Ergebnisse zusammenfassen – und ausfallsichere Verbindungen wie "Master-Master" erstellen.

Zweitens ist es ein Anwendungsserver. Sie können Ihre eigenen Anwendungen darauf schreiben, mit Daten arbeiten, zum Beispiel im Hintergrund alte Einträge nach bestimmten Regeln löschen. Sie können direkt in Tarantool einen Http-Server schreiben, der mit den Daten arbeitet: die Anzahl ausgeben, neue Daten hinzufügen und alles auf den Master zurückführen.

Ich habe einen Artikel gelesen, in dem erzählt wurde, wie die Jungs eine Nachrichtenwarteschlange mit 300 Zeilen erstellt haben, die einfach durchstartet – sie haben eine minimale Leistung von 20.000 Nachrichten pro Sekunde. Hier kann man wirklich aufblühen und eine sehr große Anwendung schreiben, und es werden keine gespeicherten Prozeduren wie in PostgreS verwendet.

Etwa so einen Server, nur einfacher, werde ich in diesem Artikel versuchen zu beschreiben.

Installation

Für den Test habe ich drei Standard-VMs eingerichtet – eine Festplatte mit 20 Gigabyte, Ubuntu 18.04, 2 virtuelle CPUs und 4 Gigabyte RAM.

Wir installieren Tarantool – entweder durch Ausführen eines Bash-Skripts oder indem wir das Repository hinzufügen und mit apt get install Tarantool installieren. Der Link zum Skript ist – (curl -L https://tarantool.io/installer.sh | VER=2.4 sudo -E bash). Wir erhalten dann solche Befehle wie:

tarantoolctl – der Hauptbefehl zur Verwaltung von Tarantool-Instanzen.
/etc/tarantool – hier liegt die gesamte Konfiguration.
var/log/tarantool – hier befinden sich die Protokolle.
var/lib/tarantool – hier liegen die Daten, und sie sind dann nach Instanzen aufgeteilt.

Es gibt die Ordner instance-available und instance-enable – in ihnen befindet sich, was gestartet wird – die Konfigurationsdatei des Instanz mit Lua-Code, in der beschrieben wird, an welchen Ports sie lauscht, welcher Speicher ihr zur Verfügung steht, Einstellungen der Vinyl-Engine, der Code, der beim Start des Servers ausgeführt wird, Sharding, Warteschlangen, das Löschen veralteter Daten und so weiter.

Instanzen arbeiten ähnlich wie in PostgreS. Zum Beispiel möchten Sie mehrere Kopien einer Datenbank starten, die an verschiedenen Ports läuft. Das bedeutet, dass auf einem Server mehrere Datenbankinstanzen starten, die an verschiedenen Ports laufen. Sie können absolut unterschiedliche Einstellungen haben – eine Instanz implementiert eine Logik, die andere eine andere.

Verwaltung der Instanzen

Wir haben das Kommando tarantoolctl, das es ermöglicht, die Tarantool-Instanzen zu verwalten. Zum Beispiel wird tarantoolctl check example die Konfigurationsdatei überprüfen und sagen – die Datei ist ok, sofern es keine Syntaxfehler gibt.

Der Status der Instanz kann mit tarantoolctl status example überprüft werden. Auf die gleiche Weise können Sie start, stop, restart durchführen.

Wenn die Instanz gestartet ist, kann man sich auf zwei Arten verbinden.

1. Administratives Konsolentool

Standardmäßig öffnet Tarantool einen Socket, über den normaler ASCII-Text zur Steuerung von Tarantool übertragen wird. Der Zugang zur Konsole erfolgt immer unter dem Benutzer admin, es gibt keine Authentifizierung, daher sollte der Konsolenport nicht nach außen ausgegeben werden.

Um sich auf diese Weise zu verbinden, geben Sie Tarantoolctl enter instance name ein. Der Befehl startet die Konsole und verbindet sich unter dem Benutzer admin. Stellen Sie den Konsolenport niemals nach außen – es ist besser, ihn als unit socket zu lassen. Auf diese Weise kann nur auf Tarantool zugegriffen werden, wer Zugang zum Schreiben in den Socket hat.

Diese Methode ist für administrative Zwecke gedacht. Für die Arbeit mit Daten verwenden Sie die zweite Methode – das binäre Protokoll.

2. Verwendung des binären Protokolls zur Verbindung mit einem bestimmten Port

In der Konfiguration gibt es die Direktive listen, die einen Port für externe Kommunikation öffnet. Dieser Port wird mit dem binären Protokoll verwendet und unterstützt die Authentifizierung.

Für diese Verbindung wird tarantoolctl connect to port number verwendet. Mit ihr kann man sich mit entfernten Servern verbinden, die Authentifizierung nutzen und verschiedene Zugriffsrechte gewähren.

Datenaufzeichnung und Modul Box

Da Tarantool sowohl eine Datenbank als auch ein Anwendungserver ist, enthält es verschiedene Module. Wir interessieren uns für das Modul box – es implementiert die Arbeit mit Daten. Wenn Sie etwas in die Box schreiben, schreibt Tarantool die Daten auf die Festplatte, speichert sie im Speicher oder macht etwas anderes damit.

Aufzeichnung

Zum Beispiel gehen wir in das Modul box und rufen die Funktion box.once auf. Sie zwingt Tarantool dazu, unseren Code bei der Initialisierung des Servers auszuführen. Wir erstellen einen Space, in dem unsere Daten gespeichert werden.

local function bootstrap()
    local space = box.schema.create_space('example')
    space:create_index('primary')
    box.schema.user.grant('guest', 'read,write,execute', 'universe')

    -- Dinge standardmäßig sicher halten
    --  box.schema.user.create('example', { password = 'secret' })
    --  box.schema.user.grant('example', 'replication')
    --  box.schema.user.grant('example', 'read,write,execute', 'space', 'example')
end

Nachdem wir das gemacht haben, erstellen wir den primären Index – primary – mit dem nach dem die Daten durchsucht werden können. Standardmäßig, ohne weitere Parameter anzugeben, wird das erste Feld in jedem Datensatz für den Primärindex verwendet.

Dann gewähren wir dem Benutzer guest, mit dem wir uns über das Binärprotokoll verbinden, die Rechte. Wir erlauben Lesen, Schreiben und Ausführen im gesamten Instance.

Im Vergleich zu regulären Datenbanken ist hier alles recht einfach. Wir haben einen Space – einen Bereich, in dem unsere Daten gespeichert werden. Jeder Datensatz wird als Tupel bezeichnet. Er wird in MessagePack verpackt. Dies ist ein sehr praktisches Format – es ist binär und nimmt weniger Platz ein – 18 Bytes im Vergleich zu 27.

In Tarantool können Sie eine super schnelle Datenbank mit einer Anwendung zur Bearbeitung kombinieren. So einfach wird es gemacht.

Es ist relativ einfach damit zu arbeiten. Jede Zeile, jeder Datensatz kann völlig unterschiedliche Spalten haben.

Alle Spaces können wir mit dem Befehl Box.space anzeigen. Um eine bestimmte Instanz zu sehen – geben wir box.space example ein und erhalten alle Informationen dazu.

Tarantool verfügt über zwei integrierte Engine-Typen: Memory und Vinyl. Memory speichert alle Daten im Speicher. Daher funktioniert alles einfach und schnell. Die Daten werden auf die Festplatte geschrieben, und es gibt außerdem einen Mechanismus für das Write Ahead Log, sodass wir bei einem Serverausfall nichts verlieren.

Vinyl speichert Daten auf der Festplatte in einer uns vertrauteren Form – das heißt, man kann mehr Daten speichern, als wir im Speicher haben, und Tarantool wird sie von der Festplatte lesen.

Jetzt werden wir Memory verwenden.

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>

Index:

Ein primärer Index muss für jeden Space erstellt werden, da ohne ihn nichts funktioniert. Wie in jeder Datenbank erstellen wir das erste Feld – die ID des Eintrags.

Parts:

Hier geben wir an, aus welchen Teilen unser Index besteht. Er besteht aus einem Teil – dem ersten Feld, das wir verwenden wollen, vom Typ unsigned – eine positive ganze Zahl. Soweit ich mich an die Dokumentation erinnere, beträgt die maximale Zahl, die möglich ist – 18 Quintrillionen. Unglaublich viel.

Dann können wir Daten mit dem Befehl insert einfügen.

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>

Das erste Feld wird als Primärschlüssel verwendet, daher muss es einzigartig sein. Mit der Anzahl der Spalten sind wir nicht limitiert, deshalb können wir so viele Daten einfügen, wie wir wollen. Diese werden im MessagePack-Format angegeben, das ich oben beschrieben habe.

Datenanzeige

Anschließend können wir Daten mit dem Befehl select ausgeben.

Box.example.select mit dem Schlüssel {1} gibt den gewünschten Eintrag aus. Wenn wir den Schlüssel weglassen, sehen wir alle Einträge, die wir haben. Sie unterscheiden sich in der Anzahl der Spalten, aber hier gibt es im Grunde kein Konzept von Spalten – es gibt Feldnummern.

Es können absolut viele Daten vorhanden sein. Und zum Beispiel müssen wir diese nach dem zweiten Feld suchen. Dafür erstellen wir einen neuen sekundären Index.


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

Wir verwenden den Befehl Create_index.
Wir nennen ihn Secondary.

Danach müssen wir die Parameter angeben. Der Index-Typ ist TREE. Er kann nicht einzigartig sein, also geben wir Unique = false ein.

Dann geben wir an, aus welchen Teilen unser Index besteht. Field – das ist die Nummer des Feldes, an das wir den Index binden, und wir geben den Typ string an. Und so wurde er erstellt.

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>

Jetzt können wir es auf diese Weise aufrufen:

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

Speichern

Wenn wir die Instanz neu starten und die Daten erneut abrufen, sehen wir, dass sie nicht vorhanden sind – alles ist leer. Das passiert, weil Tarantool Checkpoints durchführt und Daten auf der Festplatte speichert, aber wenn wir das System vor dem nächsten Speichern stoppen, verlieren wir alle Operationen – denn wir stellen den letzten Checkpoint wieder her, der beispielsweise vor zwei Stunden war.

Jede Sekunde zu speichern, ist auch keine Lösung – denn ständig 20 GB auf die Festplatte zu dumpen, ist eine eher unangenehme Angelegenheit.

Dafür wurde das Konzept des Write-Ahead-Logs entwickelt und implementiert. Damit wird für jede Änderung der Daten ein Eintrag in einer kleinen Write-Ahead-Log-Datei erstellt.

Jeder Eintrag wird bis zum Checkpoint gespeichert. Für diese Dateien setzen wir eine Größe fest – beispielsweise 64 MB. Wenn sie voll sind, wird der Eintrag in die zweite Datei fortgesetzt. Nach dem Neustart stellt sich Tarantool aus dem letzten Checkpoint wieder her und wendet anschließend alle späteren Transaktionen bis zum Zeitpunkt des Stopps an.

In Tarantool können Sie eine super schnelle Datenbank mit einer Anwendung zur Bearbeitung kombinieren. So einfach wird es gemacht.

Um eine solche Aufzeichnung durchzuführen, muss eine Option in den Einstellungen von box.cfg (in der Datei example.lua) angegeben werden:

wal_mode = "write";

Daten verwenden

Mit dem, was wir jetzt geschrieben haben, können Sie Tarantool zur Datenlagerung verwenden, und es wird sehr schnell als DB arbeiten. Und jetzt das i-Tüpfelchen – was man alles damit machen kann.

Wir schreiben eine Anwendung

Zum Beispiel schreiben wir eine solche Anwendung für Tarantool

Die Anwendung sehen Sie im Spoiler

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; -- eine Stunde
    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

-- beim ersten Ausführen einen Space erstellen und Berechtigungen einrichten
box.once('replica', bootstrap)

-- Aktivierung des Konsolenzugriffs
console = require('console')
console.listen('127.0.0.1:3302')

-- http Konfiguration
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 Anzahl")

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

Wir deklarieren eine Tabelle in Lua, die die Zeichen definiert. Diese Tabelle wird benötigt, um eine zufällige Zeichenfolge zu generieren.

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

Danach deklarieren wir die Funktion – randomString und übergeben darin den Wert der Länge.

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

Anschließend integrieren wir den HTTP-Router und den HTTP-Server in unseren Tarantool-Server, sowie JSON, die wir an den Client zurückgeben werden.

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

Nach diesem starten wir auf dem Port 8080 auf allen Schnittstellen einen HTTP-Server, der alle Anforderungen und Fehler protokolliert.

local httpd = http_server.new('0.0.0.0', 8080, {
    log_requests = true,
    log_errors = true
})

Als nächstes deklarieren wir die Route, dass wenn eine Anfrage mit der Methode GET auf Port 8080 /count kommt, wir eine Funktion aufrufen, die einen Status zurückgibt – 200, 404, 403 oder einen anderen, den wir angeben.

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

Im Körper geben wir json.encode zurück, in der wir count und get_count angeben, die aufgerufen wird und die Anzahl der Einträge in unserer Datenbank anzeigt.

Zweite Methode

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)

Wo in der Zeile router:route({method = ‘GET’, path = ‘\/token’}, function() rufen wir die Funktion auf und generieren ein Token.

Zeichenkette local token = randomString(32) – das ist eine zufällige Zeichenkette aus 32 Zeichen.
In der Zeile local last = box.space.example:len() holen wir das letzte Element.
Und in der Zeile box.space.example:insert{ last + 1, token } schreiben wir die Daten in unsere Datenbank, das heißt, wir erhöhen die ID einfach um 1. Übrigens kann das auch nicht nur auf diese klobige Weise gemacht werden. In Tarantool gibt es dafür Sequenzen.

Wir speichern das Token dort.

So haben wir in einer Datei eine Anwendung geschrieben. Es kann sofort mit Daten gearbeitet werden, und das Modul box erledigt die ganze schwierige Arbeit für Sie.

Es hört auf HTTP und arbeitet mit Daten, alles befindet sich in einer einzigen Instanz – sowohl die Anwendung als auch die Daten. Daher geschieht alles ziemlich schnell.

Für den Start installieren wir das HTTP-Modul:

Wie wir das machen, sehen Sie im Spoiler

root@test2: /# tarantoolctl rocks installieren http
Installiere http://rocks.tarantool.org/http-scm-1.src.rock
Fehlende Abhängigkeiten für http scm-1:
   checks >= 3.0.1 (nicht installiert)

http scm-1 hängt von checks >= 3.0.1 (nicht installiert) ab.
Installiere http://rocks.tarantool.org/checks-3.0.1-1.rockspec

Klonen in 'checks'...
remote: Objekte auflisten: 28, erledigt.
remote: Objekte zählen: 100% (28/28), erledigt.
remote: Objekte komprimieren: 100% (19/19), erledigt.
remote: Insgesamt 28 (Delta 1), wiederverwendet 16 (Delta 1), pack-wiederverwendet 0
Erhalte Objekte: 100% (28/28), 12.69 KiB | 12.69 MiB/s, erledigt.
Deltas auflösen: 100% (1/1), erledigt.
Hinweis: Wechsle zu '580388773ef11085015b5a06fe52d61acf16b201'.

Du bist im Zustand 'detached HEAD'. Du kannst herumsehen, experimentelle
Änderungen vornehmen und sie committen, und du kannst alle Commits,
die du in diesem Zustand machst, verwerfen, ohne Auswirkungen auf 
einige Zweige zu haben, indem du einen weiteren Checkout durchführst.

Wenn du einen neuen Zweig erstellen möchtest, um die Commits zu
behalten, die du erstellst, kannst du dies (jetzt oder später)
mit -b erneut für den Checkout-Befehl tun. Beispiel:

  git checkout -b 

Kein vorhandenes Manifest. Versuche, neu zu erstellen...
checks 3.0.1-1 ist jetzt in /.rocks installiert (Lizenz: BSD)

-- Die C-Compiler-Identifikation ist GNU 7.5.0
-- Überprüfung auf funktionierenden C-Compiler: /usr/bin/cc
-- Überprüfung auf funktionierenden C-Compiler: /usr/bin/cc -- funktioniert
-- Erkennung von C-Compiler ABI-Informationen
-- Erkennung von C-Compiler ABI-Informationen - erledigt
-- Erkennung von C-Compiler Funktionen
-- Erkennung von C-Compiler Funktionen - erledigt
-- TARANTOOL gefunden: /usr/include (Version "2.4.2-80-g18f2bc82d" gefunden)
-- Tarantool LUADIR ist /.rocks/share/tarantool/rocks/http/scm-1/lua
-- Tarantool LIBDIR ist /.rocks/share/tarantool/rocks/http/scm-1/lib
-- Konfiguration abgeschlossen
-- Generierung abgeschlossen
CMake-Warnung:
  Manuell angegebene Variablen wurden von dem Projekt nicht verwendet:

    version


-- Build-Dateien wurden geschrieben nach: /tmp/luarocks_http-scm-1-V4P9SM/http/build.luarocks
Scannen der Abhängigkeiten des Ziels httpd
[ 50%] Baue C-Objekt http/CMakeFiles/httpd.dir/lib.c.o
In der Datei enthalten von /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:32:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c: In Funktion 'tpl_term':
/usr/include/tarantool/lauxlib.h:144:15: Warnung: diese Anweisung kann durchfallen [-Wimplicit-fallthrough=]
    (*(B)->p++ = (char)(c)))
    ~~~~~~~~~~~^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:62:7: Hinweis: in Erweiterung des Makros 'luaL_addchar'
       luaL_addchar(b, '\');
       ^~~~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:63:6: Hinweis: hier
      default:
      ^~~~~~~
In der Datei enthalten von /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:39:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h: In Funktion 'tpe_parse':
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:147:9: Warnung: diese Anweisung kann durchfallen [-Wimplicit-fallthrough=]
    type = TPE_TEXT;
    ~~~~~^~~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/tpleval.h:149:3: Hinweis: hier
   case TPE_LINECODE:
   ^~~~
In der Datei enthalten von /tmp/luarocks_http-scm-1-V4P9SM/http/http/lib.c:40:0:
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h: In Funktion 'httpfast_parse':
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:372:22: Warnung: diese Anweisung kann durchfallen [-Wimplicit-fallthrough=]
                 code = 0;
                 ~~~~~^~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:374:13: Hinweis: hier
             case status:
             ^~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:393:23: Warnung: diese Anweisung kann durchfallen [-Wimplicit-fallthrough=]
                 state = message;
                 ~~~~~~^~~~~~~~~
/tmp/luarocks_http-scm-1-V4P9SM/http/http/httpfast.h:395:13: Hinweis: hier
             case message:
             ^~~~
[100%] Verlinkung der C Shared Library lib.so
[100%] Ziel httpd erstellt
[100%] Ziel httpd erstellt
Installiere das Projekt...
-- Installationskonfiguration: "Debug"
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/VERSION.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lib/http/lib.so
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/init.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/server/tsgi_adapter.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/nginx_server/init.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/init.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/fs.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/matching.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/middleware.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/request.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/router/response.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/tsgi.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/utils.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/mime_types.lua
-- Installiere: /.rocks/share/tarantool/rocks/http/scm-1/lua/http/codes.lua
http scm-1 ist jetzt in /.rocks installiert (Lizenz: BSD)

root@test2: /#

Für den Start benötigen wir außerdem prometheus:

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

Klone in 'prometheus'...
remote: Objekte werden aufgezählt: 19, erledigt.
remote: Objekte werden gezählt: 100% (19/19), erledigt.
remote: Objekte werden komprimiert: 100% (19/19), erledigt.
remote: Insgesamt 19 (delta 2), 5 (delta 0) wurden wiederverwendet, pack-reused 0
Empfange Objekte: 100% (19/19), 10.73 KiB | 10.73 MiB/s, erledigt.
Auflösen der Deltas: 100% (2/2), erledigt.
prometheus scm-1 ist jetzt in /.rocks installiert (Lizenz: BSD)

root@test2:/#

Wir starten und können auf die Module zugreifen.

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 выдает токен и делает запись этого токена в базу.

Wir testen die Geschwindigkeit.

Lassen Sie uns einen Benchmark mit 50.000 Anfragen starten. Es wird 500 konkurrierende Anfragen geben.

root@test2:/# ab -c 500 -n 50000 http://127.0.0.1:8080/token
Dies ist ApacheBench, Version 2.3 
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Lizenziert an die Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (bitte Geduld haben)
5000 Anfragen abgeschlossen
10000 Anfragen abgeschlossen
15000 Anfragen abgeschlossen
20000 Anfragen abgeschlossen
25000 Anfragen abgeschlossen
30000 Anfragen abgeschlossen
35000 Anfragen abgeschlossen
40000 Anfragen abgeschlossen
45000 Anfragen abgeschlossen
50000 Anfragen abgeschlossen
50000 Anfragen beendet


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

Dokumentenpfad:        /token
Dokumentenlänge:        44 Bytes

Anzahl der gleichzeitigen Verbindungen:      500
Zeit für Tests:   14.578 Sekunden
Komplette Anfragen:      50000
Fehlgeschlagene Anfragen:        0
Insgesamt übertragene Daten:      7950000 Bytes
Übertragene HTML-Daten:       2200000 Bytes
Anfragen pro Sekunde:    3429.87 [#/sec] (Mittel)
Zeit pro Anfrage:       145.778 [ms] (Mittel)
Zeit pro Anfrage:       0.292 [ms] (Mittel, über alle parallelen Anfragen)
Übertragungsrate:          532.57 [Kbytes/sec] empfangen

Verbindungszeiten (ms)
              min  mean[+/-sd] median   max
Verbinden:        0   10 103.2      0    3048
Verarbeitung:    12   69 685.1     15   13538
Warten:       12   69 685.1     15   13538
Insgesamt:         12   78 768.2     15   14573

Prozentsatz der Anfragen, die innerhalb einer bestimmten Zeit (ms) erfüllt wurden
  50%     15
  66%     15
  75%     16
  80%     16
  90%     16
  95%     16
  98%     21
  99%     42
 100%  14573 (längste Anfrage)
root@test2:/#

Die Tokens werden ausgegeben. Und wir schreiben dauerhaft Daten. 99 % der Anfragen wurden in 42 Millisekunden bearbeitet. Dementsprechend haben wir etwa 3500 Anfragen pro Sekunde auf einem kleinen Rechner mit 2 Kernen und 4 Gigabyte RAM.

Außerdem können Sie einen zufälligen 50.000-Token auswählen und dessen Wert überprüfen.

Es ist nicht nur möglich, http zu verwenden, sondern auch Hintergrundfunktionen zu starten, die Ihre Daten verarbeiten. Zudem gibt es verschiedene Trigger. Zum Beispiel können Sie Funktionen bei Updates aufrufen, um etwas zu überprüfen – Konflikte zu beheben.

Man kann Skript-Anwendungen direkt auf dem Datenbankserver schreiben und ist dabei nicht eingeschränkt, kann beliebige Module einbinden und jede Logik umsetzen.

Der Anwendungsserver kann auf externe Server zugreifen, Daten abrufen und in seiner Datenbank speichern. Diese Daten werden von anderen Anwendungen verwendet.

Das wird Tarantool selbst erledigen, und es ist nicht notwendig, eine separate Anwendung zu schreiben.

Abschließend

Das ist nur der erste Teil einer großen Arbeit. Der zweite Teil wird ganz bald im Blog der Mail.ru Group veröffentlicht, und wir werden unbedingt einen Link dazu in dieses Material einfügen.

Wenn Sie daran interessiert sind, an Veranstaltungen teilzunehmen, bei denen wir solche Dinge online erstellen, und Fragen in Echtzeit zu stellen, schließen Sie sich dem Kanal DevOps von REBRAIN.

Wenn Sie einen Umzug in die Cloud benötigen oder Fragen zu Ihrer Infrastruktur haben, lassen Sie gerne eine Anfrage da.

P.S. Wir haben zwei kostenlose Audits pro Monat, möglicherweise ist genau Ihr Projekt eines davon.

Quelle: habr.com

60GB SSD 8Gb DDR4