• LevelDB性能测试|Golang调用LevelDB


    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))
    		}
    	}
    }
    
    
  • 相关阅读:
    分块传输编码在WEB安全中的应用——sql注入用,可以直接复用chunkSplitPostData还原
    漏扫是如何做的?——从xunfeng源码看漏扫原理
    WhatWeb使用——可识别Web技术,包括内容管理系统(CMS),博客平台,统计/分析包,Javascript库,服务器和嵌入式设备
    PyCharm单行执行代码 或 运行选中的代码
    PyCharm 改变黑色主题的颜色方案
    Docker四种网络模式
    Does C# have an equivalent to JavaScript's encodeURIComponent()?
    When are you supposed to use escape instead of encodeURI / encodeURIComponent?
    Difference between escape(), encodeURI(), encodeURIComponent()
    How can I trace the HttpClient request using fiddler or any other tool?
  • 原文地址:https://www.cnblogs.com/nima/p/11751055.html
Copyright © 2020-2023  润新知