Зачитался я последнее время про Tarantool, интересно стало. Идея хорошая — код рядом с базой данных, хранимка в такой быстрой Redis-подобной среде.
И что-то задумался — мы вот сейчас используем активно на работе Golang, собственно, мысль пришла что на Go написано много всего, в т.ч. и встраиваемых баз. А что если сравнить, например, Go+LevelDB (собственно, можно было бы и любую другую) против Tarantool. Тестировал еще Go+RocksDB, но там оказалось все немного сложнее, а результат примерно тот же на небольших данных.
Забегая вперед — в моем ненаучном тесте выиграл Golang за счет использования всех ядер процессора. Скорее всего, если запустить несколько Тарантулов и балансировщик — выигрыш может какой-то и будет, но не сказать чтобы значительный… Но, правда, тут уже надо будет репликацию делать или что-то подобное.
Итак результат (кратко) wrk -t 4 -c 10
(4 потока, 10 соединений):
Golang:
Latency Distribution 50% 269.00us 99% 1.64ms Requests/sec: 25637.26
Tarantool:
Latency Distribution 50% 694.00us 99% 1.43ms Requests/sec: 10377.78
Но, Тарантул занял примерно только половину ядер, так что, вероятно, скорость у них — примерно одинаковая.
Под бОльшей нагрузкой (wrk -t 10 -c 100
) Тарантул остался на месте по RPS (а вот latency просела значительно заметнее чем у Golang, особенно верхняя часть), а Golang даже приободрился (но latency тоже просела, разумеется).
Go:
Latency Distribution 50% 2.85ms 99% 8.12ms Requests/sec: 33226.52
Tarantool:
Latency Distribution 50% 8.69ms 99% 73.09ms Requests/sec: 10763.55
У Tarantool есть свои примущества: secondary index, репликация…
У Go же есть огромная экосистема библиотек (около 100 тыс по моим подсчетам, среди них и реализаций встроенных (и не очень) баз данных — море), и, как пример, тот же bleve дает полнотекстовый поиск (чего, насколько я понял, например, нет в Tarantool).
По ощущениям экосистема Тарантула беднее. По крайней мере все, что предлагается — msgpack, http server, client, json, LRU cache,… в Go реализовано в бессчетных вариантах..
Т.е., в общем-то, безумного выигрыша скорости нет.
Пока что мой личный выбор остается в сторону Go, потому что нет ощущения что экосистема Tarantool выстрелит настолько сильно в ближайшее время, а Go — уже давно активнейше развивается.
Код на Tarantool, конечно, короче, но в основном, за счет того что ошибки обрабатываются языком. В Go можно тоже вырезать все err
и останется примерно столько же.
Может у кого-то есть другие мнения?
И если подробнее про тест.
Тестировал простую задачу — HTTP сервер, при запросе — записать ключик в базу, достать его же по имени (без всяких проверок на race), отправить назад простенький JSON из этого value.
Golang:
➜ ~ wrk -t 4 -c 10 -d 5 --latency http://127.0.0.1:8081/ Running 5s test @ http://127.0.0.1:8081/ 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 346.71us 600.80us 26.94ms 97.89% Req/Sec 6.54k 0.88k 13.87k 73.13% Latency Distribution 50% 269.00us 75% 368.00us 90% 493.00us 99% 1.64ms 130717 requests in 5.10s, 15.08MB read Requests/sec: 25637.26 Transfer/sec: 2.96MB
Tarantool:
➜ ~ wrk -t 4 -c 10 -d 5 --latency http://127.0.0.1:8080/ Running 5s test @ http://127.0.0.1:8080/ 4 threads and 10 connections Thread Stats Avg Stdev Max +/- Stdev Latency 767.53us 209.64us 4.04ms 87.26% Req/Sec 2.61k 437.12 3.15k 45.59% Latency Distribution 50% 694.00us 75% 0.90ms 90% 1.02ms 99% 1.43ms 52927 requests in 5.10s, 8.58MB read Requests/sec: 10377.78 Transfer/sec: 1.68MB
Под большей нагрузкой:
Go:
➜ ~ wrk -t 10 -c 100 -d 5 --latency http://127.0.0.1:8081/ Running 5s test @ http://127.0.0.1:8081/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 3.04ms 1.48ms 25.53ms 80.21% Req/Sec 3.34k 621.43 12.52k 86.20% Latency Distribution 50% 2.85ms 75% 3.58ms 90% 4.57ms 99% 8.12ms 166514 requests in 5.01s, 19.21MB read Requests/sec: 33226.52 Transfer/sec: 3.83MB
Tarantool:
➜ ~ wrk -t 10 -c 100 -d 5 --latency http://127.0.0.1:8080/ Running 5s test @ http://127.0.0.1:8080/ 10 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 10.65ms 14.24ms 269.85ms 98.43% Req/Sec 1.09k 128.17 1.73k 94.56% Latency Distribution 50% 8.69ms 75% 10.50ms 90% 11.36ms 99% 73.09ms 53943 requests in 5.01s, 8.75MB read Requests/sec: 10763.55 Transfer/sec: 1.75MB
Исходники тестов:
Go:
package main import ( "encoding/json" "fmt" "io" "net/http" "github.com/syndtr/goleveldb/leveldb" "github.com/tecbot/gorocksdb" ) var db *leveldb.DB func hello(w http.ResponseWriter, r *http.Request) { err := db.Put([]byte("foo"), []byte("bar"), nil) if err != nil { w.WriteHeader(500) io.WriteString(w, err.Error()) return } res, err := db.Get([]byte("foo"), nil) if err != nil { w.WriteHeader(500) io.WriteString(w, err.Error()) return } result, err := json.Marshal(string(res)) if err != nil { w.WriteHeader(500) io.WriteString(w, err.Error()) return } w.Write(result) } func main() { var err error opts := gorocksdb.NewDefaultOptions() opts.SetCreateIfMissing(true) db, err = leveldb.OpenFile("level.db", nil) if err != nil { panic(err) } http.HandleFunc("/", hello) fmt.Println("http://127.0.0.1:8081/") http.ListenAndServe("127.0.0.1:8081", nil) }
Tarantool:
#!/usr/bin/env tarantool box.cfg{logger = 'tarantool.log'} space = box.space.data if not space then space = box.schema.create_space('data') space:create_index('primary', { parts = {1, 'STR'} }) end local function handler(req) space:put({'foo','bar'}) local val = space:get('foo') return req:render({ json = val[2] }) end print "http://127.0.0.1:8080/" require('http.server').new('127.0.0.1', 8080) :route({ path = '/' }, handler) :start()
ссылка на оригинал статьи https://habrahabr.ru/post/282299/
Добавить комментарий