且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

SSDB —— 开源NoSQL数据库 Redis之外的选择

更新时间:2022-04-25 14:11:33

SSDB是一个快速的用来存储十亿级别列表数据的开源 NoSQL 数据库。


特性

  • 替代 Redis 数据库, Redis 的 100 倍容量
  • LevelDB 网络支持, 使用 C/C++ 开发
  • Redis API 兼容, 支持 Redis 客户端
  • 适合存储集合数据, 如 list, hash, zset...
  • 客户端 API 支持的语言包括: C++、PHP、Python、Cpy、Java、NodeJS、Ruby、Go。
  • 持久化的队列服务
  • 主从复制, 负载均衡


性能

1000请求:

writeseq  :    0.546 ms/op      178.7 MB/s

writerand :    0.519 ms/op      188.1 MB/s

readseq   :    0.304 ms/op      321.6 MB/s

readrand  :    0.310 ms/op      315.0 MB/s

并发:

========== set ==========

qps: 44251, time: 0.226 s

========== get ==========

qps: 55541, time: 0.180 s

========== del ==========

qps: 46080, time: 0.217 s

========== hset ==========

qps: 42338, time: 0.236 s

========== hget ==========

qps: 55601, time: 0.180 s

========== hdel ==========

qps: 46529, time: 0.215 s

========== zset ==========

qps: 37381, time: 0.268 s

========== zget ==========

qps: 41455, time: 0.241 s

========== zdel ==========

qps: 38792, time: 0.258 s

在MacBook Pro 13 (Retina屏幕)上运行。

与redis的比较:

性能数据使用 ssdb-bench(SSDB) 和 redis-benchmark(Redis) 来获取。

SSDB —— 开源NoSQL数据库 Redis之外的选择

架构

SSDB —— 开源NoSQL数据库 Redis之外的选择


安装

下载压缩包,解压缩

wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip

unzip master

cd ssdb-master

编译

make

安装(可选)

sudo make install

运行

./ssdb-server ssdb.conf

或者以后台的方式运行

./ssdb-server -d ssdb.conf

ssdb命令行

./tools/ssdb-cli -p 8888

停止ssdb-server

kill `cat ./var/ssdb.pid`

使用

PHP

<?php

include_once('SSDB.php');

try{

    $ssdb = new SimpleSSDB('127.0.0.1', 8888);

}catch(Exception $e){

    die(__LINE__ . ' ' . $e->getMessage());

}

$ret = $ssdb->set('key', 'value');

if($ret === false){

    // error!

}

echo $ssdb->get('key');

Python

使用pyssdb

>>> import pyssdb

>>> c = pyssdb.Client()

>>> c.set('key', 'value')

1

>>> c.get('key')

'value'

>>> c.hset('hash', 'item', 'value')

1

>>> c.hget('hash', 'item')

'value'

>>> c.hget('hash', 'not exist') is None

True

>>> c.incr('counter')

1

>>> c.incr('counter')

2

>>> c.incr('counter')

3

>>> c.keys('a', 'z', 1)

['counter']

>>> c.keys('a', 'z', 10)

['counter', 'key']

Ruby

使用ssdb-rb

require "ssdb"

ssdb = SSDB.new url: "ssdb://1.2.3.4:8889"

ssdb.set("mykey", "hello world")

# => true

ssdb.get("mykey")

# => "hello world"

ssdb.batch do

  ssdb.set "foo", "5"

  ssdb.get "foo"

  ssdb.incr "foo"

end

# => [true, "5", 6]

Go

package main

import (

        "fmt"

        "os"

        "./ssdb"

       )

func main(){

    ip := "127.0.0.1";

    port := 8888;

    db, err := ssdb.Connect(ip, port);

    if(err != nil){

        os.Exit(1);

    }

    var val interface{};

    db.Set("a", "xxx");

    val, err = db.Get("a");

    fmt.Printf("%s\n", val);

    db.Del("a");

    val, err = db.Get("a");

    fmt.Printf("%s\n", val);

    db.Do("zset", "z", "a", 3);

    db.Do("multi_zset", "z", "b", -2, "c", 5, "d", 3);

    resp, err := db.Do("zrange", "z", 0, 10);

    if err != nil{

        os.Exit(1);

    }

    if len(resp) % 2 != 1{

        fmt.Printf("bad response");

        os.Exit(1);

    }

    fmt.Printf("Status: %s\n", resp[0]);

    for i:=1; i<len(resp); i+=2{

        fmt.Printf("  %s : %3s\n", resp[i], resp[i+1]);

    }

    return;

ngx_lua

使用lua-resty-ssdb

lua_package_path "/path/to/lua-resty-ssdb/lib/?.lua;;";

server {

    location /test {

        content_by_lua '

            local ssdb = require "resty.ssdb"

            local db = ssdb:new()

            db:set_timeout(1000) -- 1 sec

            local ok, err = db:connect("127.0.0.1", 8888)

            if not ok then

                ngx.say("failed to connect: ", err)

               return

            end

            ok, err = db:set("dog", "an animal")

            if not ok then

                ngx.say("failed to set dog: ", err)

               return

            end

            ngx.say("set result: ", ok)

            local res, err = db:get("dog")

            if not res then

                ngx.say("failed to get dog: ", err)

               return

            end

            if res == ngx.null then

                ngx.say("dog not found.")

               return

            end

            ngx.say("dog: ", res)

            db:init_pipeline()

            db:set("cat", "Marry")

            db:set("horse", "Bob")

            db:get("cat")

            db:get("horse")

            local results, err = db:commit_pipeline()

            if not results then

                ngx.say("failed to commit the pipelined requests: ", err)

               return

            end

            for i, res in ipairs(results) do

                if type(res) == "table" then

                    if not res[1] then

                        ngx.say("failed to run command ", i, ": ", res[2])

                    else

                        -- process the table value

                    end

                else

                    -- process the scalar value

                end

            end

            -- put it into the connection pool of size 100,

            -- with 0 idle timeout

            local ok, err = db:set_keepalive(0, 100)

            if not ok then

                ngx.say("failed to set keepalive: ", err)

               return

            end

            -- or just close the connection right away:

            -- local ok, err = db:close()

            -- if not ok then

            --     ngx.say("failed to close: ", err)

            --     return

            -- end

        ';

    }

}

C++

#include <stdio.h>

#include <stdlib.h>

#include <string>

#include <vector>

#include "SSDB.h"

int main(int argc, char **argv){

    const char *ip = (argc >= 2)? argv[1] : "127.0.0.1";

    int port = (argc >= 3)? atoi(argv[2]) : 8888;

    ssdb::Client *client = ssdb::Client::connect(ip, port);

    if(client == NULL){

        printf("fail to connect to server!\n");

        return 0;

    }

    ssdb::Status s;

    s = client->set("k", "hello ssdb!");

    if(s.ok()){

        printf("k = hello ssdb!\n");

    }else{

        printf("error!\n");

    }

    delete client;

    return 0;