LevelDB性能测试|Golang调用LevelDB

大兔子大兔子 提交于 2019-12-02 14:53:25

LevelDB性能测试|Golang调用LevelDB

不同方式使用压力测试

  1. 用ssdb,TCP连接方式调用,底层存储levelDB
  2. 直接调用Cgo的levelDB (必须保证串行)
  3. 直接调用Golang的LevelDB (必须保证串行)

开始:

go test  -v -test.run="DB.*" -test.bench="DB.*" -test.count=1 -test.benchtime=3s
go test  -v -test.run="Raws.*" -test.bench="Raws.*" -test.count=1 -test.benchtime=3s
go test  -v -test.run="Normal.*" -test.bench="Normal.*" -test.count=1 -test.benchtime=3s

性能对比:

1.调用SSDB:随机读写,和顺序读写差异不大,网络延迟是主要问题。

goos: linux
goarch: amd64
pkg: common/ssdb
Benchmark_DBSXSSDBSET          30000        127546 ns/op
Benchmark_DBSXSSDBGET          50000        118855 ns/op
Benchmark_DBRandomSSDBSET      30000        128268 ns/op
Benchmark_DBRandomSSDBGET      50000        119668 ns/op
PASS
ok      common/ssdb 24.545s

2.直接调用LevelDB,每次都打开文件,导致特别慢:

goos: linux
goarch: amd64
pkg: common/ssdb
Benchmark_RawsSXSET              100      38748277 ns/op
Benchmark_RawsSXGET              200      27432834 ns/op
Benchmark_RawsRandomSET          100      39496210 ns/op
Benchmark_RawsRandomGET          200      27987023 ns/op
PASS
ok      common/ssdb 24.637s

改为只打开一次文件:

goos: linux
goarch: amd64
pkg: common/ssdb
Benchmark_RawsSXSET          1000000          3142 ns/op
Benchmark_RawsSXGET          3000000          1856 ns/op
Benchmark_RawsRandomSET      1000000          3892 ns/op
Benchmark_RawsRandomGET      3000000          1467 ns/op
PASS
ok      common/ssdb 24.073s
  1. 调用Golang LevelDB
goos: linux
goarch: amd64
pkg: common/ssdb
Benchmark_NormalSXSET            500       8888019 ns/op
Benchmark_NormalSXGET         500000          6632 ns/op
Benchmark_NormalRandomSET        500       9006333 ns/op
Benchmark_NormalRandomGET     500000          6449 ns/op
PASS
ok      common/ssdb 17.501s

Golang调用Cgo LevelDB

levelDB Golang实现的库性能有问题?那么Golang调用C++ levelDB库:

环境准备:

需要先升级cmake,要求版本3.9以上

wget https://cmake.org/files/v3.9/cmake-3.9.2.tar.gz
tar xvf cmake-3.9.2.tar.gz
cd cmake-3.9.2
./bootstrap --prefix=/usr
make
sudo make install
cmake --version

下载并编译levelDB C库:

git clone https://github.com/google/leveldb
cd leveldb
git checkout v1.20
make

动态库在:

ls out-shared/libleveldb.so.1.20

静态库在:

ls out-static/libleveldb.a

安装:

# cp leveldb header file
sudo cp -r include/ /usr/include/

# cp lib to /usr/lib/
sudo cp out-shared/libleveldb.so.1.20 /usr/lib/

# create link
sudo ln -s /usr/lib/libleveldb.so.1.20 /usr/lib/libleveldb.so.1
sudo ln -s /usr/lib/libleveldb.so.1.20 /usr/lib/libleveldb.so

# update lib cache
sudo ldconfig

ls /usr/lib/libleveldb.so*

# 显示下面 3 个文件即安装成功
/usr/lib/libleveldb.so.1.20
/usr/lib/libleveldb.so.1
/usr/lib/libleveldb.so

我们先用C++来写一个程序先/root/test.cc

#include <iostream>
#include <cassert>
#include <cstdlib>
#include <string>
// 包含必要的头文件
#include <leveldb/db.h>

using namespace std;

int main(void)
{
    leveldb::DB *db = nullptr;
    leveldb::Options options;

    // 如果数据库不存在就创建
    options.create_if_missing = true;

    // 创建的数据库在 /tmp/testdb
    leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
    assert(status.ok());

    std::string key = "A";
    std::string value = "a";
    std::string get_value;

    // 写入 key1 -> value1
    leveldb::Status s = db->Put(leveldb::WriteOptions(), key, value);

    // 写入成功,就读取 key:people 对应的 value
    if (s.ok())
        s = db->Get(leveldb::ReadOptions(), "A", &get_value);

    // 读取成功就输出
    if (s.ok())
        cout << get_value << endl;
    else
        cout << s.ToString() << endl;

    delete db;

    return 0;
}

静态编译:

cp out-static/libleveldb.a /root/
g++ test.cc -o test ./libleveldb.a -lpthread

动态:

g++ test.cc -o test -lpthread -lleveldb

接下来参考:https://github.com/jmhodges/levigo/blob/master/examples/comparator_example.go

下载后使用即可:

CGO_CFLAGS="-I/usr/include" CGO_LDFLAGS="-L/usr/lib" go get github.com/jmhodges/levigo

Golang调用ssdb

使用ssdb,用tcp方式请求,底层存储为levelDB.

wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip
unzip master.zip
cd ssdb-master
apt install autoconf
make
# 将安装在 /usr/local/ssdb 目录下
sudo make install

mkdir /root/ssdb
cp ssdb-server /root/ssdb
cp ssdb.conf /root/ssdb
cd /root/ssdb
mkdir var

编辑ssdb.conf

# ssdb-server config
# MUST indent by TAB!

# absolute path, or relative to path of this file, directory must exists
work_dir = ./var
pidfile = ./var/ssdb.pid

server:
        ip: 0.0.0.0
        port: 8888
        # bind to public ip
        #ip: 0.0.0.0
        # format: allow|deny: all|ip_prefix
        # multiple allows or denys is supported
        #deny: all
        #allow: 127.0.0.1
        #allow: 192.168
        # auth password must be at least 32 characters
        #auth: very-strong-password
        #readonly: yes
        # in ms, to log slowlog with WARN level
        #slowlog_timeout: 5

replication:
        binlog: yes
        # Limit sync speed to *MB/s, -1: no limit
        sync_speed: -1
        slaveof:
                # to identify a master even if it moved(ip, port changed)
                # if set to empty or not defined, ip:port will be used.
                #id: svc_2
                # sync|mirror, default is sync
                #type: sync
                #host: localhost
                #port: 8889

logger:
        level: debug
        output: /root/ssdb/log.txt
        rotate:
                size: 1000000000

leveldb:
        # in MB
        cache_size: 500
        # in MB
        write_buffer_size: 64
        # in MB/s
        compaction_speed: 1000
        # yes|no
        compression: yes

启动:

# 启动主库, 此命令会阻塞住命令行
./ssdb-server ssdb.conf

# 或者启动为后台进程(不阻塞命令行)
./ssdb-server -d ssdb.conf

# 停止 ssdb-server
./ssdb-server ssdb.conf -s stop
# 对于旧版本
kill `cat ./var/ssdb.pid`

# 重启
./ssdb-server ssdb.conf -s restart

下载后使用:

go get -v github.com/seefan/gossdb

代码:

Golang levelDB:

package bench

import (
    "github.com/syndtr/goleveldb/leveldb"
    "github.com/syndtr/goleveldb/leveldb/opt"
    "sync"
)

type LevelDBClient struct {
    db *leveldb.DB
    *sync.Mutex
}

func (x *LevelDBClient) init(dir string) error {
    //os.Mkdir(dir, 777)
    db, err := leveldb.OpenFile(dir, nil)
    if err != nil {
        return err
    }
    x.Mutex = new(sync.Mutex)
    x.db = db
    return nil
}

func (x *LevelDBClient) Set(key, value []byte) error {
    x.Lock()
    defer x.Unlock()
    return x.db.Put(key, value, &opt.WriteOptions{NoWriteMerge: true, Sync: true})
}

func (x *LevelDBClient) Get(key []byte) ([]byte, error) {
    x.Lock()
    defer x.Unlock()
    return x.db.Get(key, &opt.ReadOptions{DontFillCache: true})
}

Cgo levelDB:

package bench

import (
    "github.com/jmhodges/levigo"
    "sync"
)

type RawLevelDBClient struct {
    db *levigo.DB
    ro *levigo.ReadOptions
    wb *levigo.WriteOptions

    *sync.Mutex
}

func (x *RawLevelDBClient) init(dir string) error {
    opts := levigo.NewOptions()
    //opts.SetCache(levigo.NewLRUCache(3 << 30))
    opts.SetCreateIfMissing(true)
    db, err := levigo.Open(dir, opts)

    if err != nil {
        return err
    }

    x.Mutex = new(sync.Mutex)
    x.db = db
    x.ro = levigo.NewReadOptions()
    x.wb = levigo.NewWriteOptions()
    return nil
}

func (x *RawLevelDBClient) Get(key []byte) (data []byte, err error) {
    x.Lock()
    defer x.Unlock()
    data, err = x.db.Get(x.ro, key)

    if err != nil {
        return
    }
    return
}

func (x *RawLevelDBClient) Set(key []byte, value []byte) (err error) {
    x.Lock()
    defer x.Unlock()
    err = x.db.Put(x.wb, key, value)
    return
}

测试文件(三种方式):

package bench

import (
    "testing"
    "github.com/seefan/gossdb"
    "github.com/seefan/gossdb/conf"
    "fmt"
    "math/rand"
)

func Benchmark_DBSXSSDBSET(b *testing.B) {
    pool, err := gossdb.NewPool(&conf.Config{
        Host:             "192.168.153.15",
        Port:             8888,
        MinPoolSize:      5,
        MaxPoolSize:      50,
        AcquireIncrement: 5,
        RetryEnabled:     true,
    })
    if err != nil {
        fmt.Println("xxx")
        return
    }
    defer pool.Close()

    for i := 0; i < b.N; i++ {
        c, err := pool.NewClient()
        if err != nil {
            if c != nil {
                c.Close()
            }
            fmt.Println(err.Error())
            return
        }
        err = c.Set(fmt.Sprintf("%d", i), fmt.Sprintf("%d", i))
        if err != nil {
            fmt.Println(err.Error())
        }
        if c != nil {
            c.Close()
        }
    }
}

func Benchmark_DBSXSSDBGET(b *testing.B) {
    pool, err := gossdb.NewPool(&conf.Config{
        Host:             "192.168.153.15",
        Port:             8888,
        MinPoolSize:      5,
        MaxPoolSize:      50,
        AcquireIncrement: 5,
        RetryEnabled:     true,
    })
    if err != nil {
        fmt.Println("xxx")
        return
    }
    defer pool.Close()

    for i := 0; i < b.N; i++ {
        c, err := pool.NewClient()
        if err != nil {
            if c != nil {
                c.Close()
            }
            fmt.Println(err.Error())
            return
        }
        _, err = c.Get(fmt.Sprintf("%d", i))
        if err != nil {
            fmt.Println(err.Error())
        }
        if c != nil {
            c.Close()
        }
    }
}

func Benchmark_DBRandomSSDBSET(b *testing.B) {
    pool, err := gossdb.NewPool(&conf.Config{
        Host:             "192.168.153.15",
        Port:             8888,
        MinPoolSize:      5,
        MaxPoolSize:      50,
        AcquireIncrement: 5,
        RetryEnabled:     true,
    })
    if err != nil {
        fmt.Println("xxx")
        return
    }
    defer pool.Close()
    for i := 0; i < b.N; i++ {
        c, err := pool.NewClient()
        if err != nil {
            if c != nil {
                c.Close()
            }
            fmt.Println(err.Error())
            return
        }
        dudu := uint(rand.Intn(5))
        err = c.Set(fmt.Sprintf("%d", dudu), fmt.Sprintf("%d", dudu))
        if err != nil {
            fmt.Println(err.Error())
        }
        if c != nil {
            c.Close()
        }
    }
}

func Benchmark_DBRandomSSDBGET(b *testing.B) {
    pool, err := gossdb.NewPool(&conf.Config{
        Host:             "192.168.153.15",
        Port:             8888,
        MinPoolSize:      5,
        MaxPoolSize:      50,
        AcquireIncrement: 5,
        RetryEnabled:     true,
    })
    if err != nil {
        fmt.Println("xxx")
        return
    }
    defer pool.Close()
    for i := 0; i < b.N; i++ {
        c, err := pool.NewClient()
        if err != nil {
            if c != nil {
                c.Close()
            }
            fmt.Println(err.Error())
            return
        }
        _, err = c.Get(fmt.Sprintf("%d", uint(rand.Intn(5))))
        if err != nil {
            fmt.Println(err.Error())
        }
        if c != nil {
            c.Close()
        }
    }
}

var ldb = new(RawLevelDBClient)
var db = new(LevelDBClient)

func init() {
    dir := "/data/leveldb"
    err := ldb.init(dir)
    if err != nil {
        panic(err)
    }

    dir = "/data/leveldb1"
    err = db.init(dir)
    if err != nil {
        panic(err)
    }

}

func Benchmark_RawsSXSET(b *testing.B) {
    for i := 0; i < b.N; i++ {
        dudu := fmt.Sprintf("%d", i)
        err := ldb.Set([]byte(dudu), []byte(dudu))
        if err != nil {
            fmt.Println(err.Error())
        }
    }
}
func Benchmark_RawsSXGET(b *testing.B) {

    for i := 0; i < b.N; i++ {
        dudu := fmt.Sprintf("%d", i)
        _, err := ldb.Get([]byte(dudu))
        if err != nil {
            fmt.Println(err.Error())
        } else {
            //fmt.Println(string(v))
        }
    }
}
func Benchmark_RawsRandomSET(b *testing.B) {
    for i := 0; i < b.N; i++ {
        dudu := fmt.Sprintf("%d", uint(rand.Intn(5)))
        err := ldb.Set([]byte(dudu), []byte(dudu))
        if err != nil {
            fmt.Println(err.Error())
        }
    }
}
func Benchmark_RawsRandomGET(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _, err := ldb.Get([]byte(fmt.Sprintf("%d", uint(rand.Intn(5)))))
        if err != nil {
            //fmt.Println(err.Error())
        } else {
            //fmt.Println(string(v))
        }
    }
}

func Benchmark_NormalSXSET(b *testing.B) {
    for i := 0; i < b.N; i++ {
        dudu := fmt.Sprintf("%d", i)
        err := db.Set([]byte(dudu), []byte(dudu))
        if err != nil {
            //fmt.Println(err.Error())
        } else {

        }
    }
}
func Benchmark_NormalSXGET(b *testing.B) {

    for i := 0; i < b.N; i++ {
        dudu := fmt.Sprintf("%d", i)
        _, err := db.Get([]byte(dudu))
        if err != nil {
            //fmt.Println(err.Error())
        } else {
            //fmt.Println(string(v))
        }
    }
}
func Benchmark_NormalRandomSET(b *testing.B) {
    for i := 0; i < b.N; i++ {
        dudu := fmt.Sprintf("%d", uint(rand.Intn(5)))
        err := db.Set([]byte(dudu), []byte(dudu))
        if err != nil {
            //fmt.Println(err.Error())
        }
    }
}
func Benchmark_NormalRandomGET(b *testing.B) {
    for i := 0; i < b.N; i++ {
        _, err := db.Get([]byte(fmt.Sprintf("%d", uint(rand.Intn(5)))))
        if err != nil {
            //fmt.Println(err.Error())
        } else {
            //fmt.Println(string(v))
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!