Go-Rocksdb开发环境搭建
因为需要使用golang开发rocksdb,其中有不少繁琐的环境依赖,所以记录一下mac上的开发环境搭建,并提供dockerfile以便在window或者liunx环境下使用。
注意,当前环境:(不是这个环境可能不适用)
yaml 代码解读复制代码go: 1.21
rocksdb: 7.10.2
lunxGnu/grocksdb: 1.7.16
< macOs: 13 >
环境介绍
-
rocksdb是facebook开源的一个kv数据库,经常作为存储中心的前置引擎。由C++编写,支持通过 C 绑定嵌入到使用 C、C++、Rust、Go 和 Java 等多种语言编写的应用程序中。
-
rocksdb运行时依赖于多个软件包,需要在对应系统安装。
dart代码解读复制代码You can link RocksDB with following compression libraries: zlib - a library for data compression. bzip2 - a library for data compression. lz4 - a library for extremely fast data compression. snappy - a library for fast data compression. zstandard - Fast real-time compression algorithm. All our tools depend on: gflags - a library that handles command line flags processing. You can compile rocksdb library even if you don't have gflags installed.
-
rocksdb的编译有多种选择,可以是编译静态库,也可以编译动态库,基于开发架构选择使用。
go代码解读复制代码make clean 静态库编译,得到librocksdb.a文件 make static_lib or 动态库编译,得到librocksdb.dylib(mac)或者librocksdb.so(linux)文件 make shared_lib or cmake 编译 mkdir ./build && cd ./build cmake .. make 安装 make install shared PREFIX="路径"
-
CGO环境,使用golang开发rocksdb,通过cgo与rocksdb通讯,需要配置对应的环境。go env的CGO_ENABLED='1'
golang代码解读复制代码指定rocksdb的include,可以使用源代码项目中的,也可以install export CGO_CFLAGS="-I/Users/apple/workspace/rocksdb_env/include" 指定链接库,rocksdb可以是动态库或者静态库,其他的是对应的依赖 export CGO_LDFLAGS="-L/Users/apple/workspace/rocksdb_env -lrocksdb -lstdc++ -lm -lz -lsnappy -llz4 -lzstd"
-
指定动态库路径查找路径,程序会到usr/lib,/usr/local/lib等路径中查找,可以通过参数控制。
bash代码解读复制代码liunx中 export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH mac中 export DYLD_LIBRARY_PATH="/usr/local/lib:$DYLD_LIBRARY_PATH"
-
lunxGnu/grocksdb 包装了rocksdb的接口,方便golang开发者使用
mac安装
-
通过brew安装rocksdb的依赖(注意版本,经过测试,macOs 14安装的版本并不适用,需要手动通过源码编译)
sql代码解读复制代码brew install zlib bzip2 lz4 snappy zstd ---- 注意版本: librocksdb.dylib: @rpath/librocksdb.7.dylib (compatibility version 7.0.0, current version 7.10.2) /opt/homebrew/opt/gflags/lib/libgflags.2.2.dylib (compatibility version 2.2.0, current version 2.2.2) /opt/homebrew/opt/zstd/lib/libzstd.1.dylib (compatibility version 1.0.0, current version 1.5.5) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1300.36.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
-
下载rocksdb源码: git clone github.com/facebook/ro… && git checkout tags/v7.10.2
-
make编译
-
这里需要注意gcc的版本,有可能执行make失败,自行解决 :)。
-
make执行不了就通过cmake编译,cmake编译需要注意一个坑:
scala代码解读复制代码如果开发对应的rocksdb中使用了zstd压缩,指定了zstd的压缩算法,那么需要将zstd的依赖编译进rocksdb的动态链接库librocksdb.dylib中。若没有将zstd编译进来,编译go_rocksdb程序能够成功。但是会在运行go程序的时候报错: `Invalid argument: Compression type ZSTD is not linked with the binary`。 坑点: 在rocksdb7.10.2的分支中,cmake对应的CMakeLists.txt文件却默认把zstd依赖关掉了,导致了cmake编译出来的动态库是不包含zstd依赖的。 解决: 把CMakeLists.txt中,option(WITH_ZSTD "build with zstd" OFF) 的OFF改成ON,就可以将zstd编译到动态库中,golang调用cgo的时候可以找到zstd。
-
-
静态库与动态库的选择,两者二选一,只要设定好CGO_LDFLAGS路径即可。不过使用动态库的话,需要关注LD_LIBRARY_PATH(linux)参数。
-
make intall 安装
-
检查,如果使用动态库的话,确保动态库依赖都装上了。
sql代码解读复制代码otool -L librocksdb.dylib librocksdb.dylib: @rpath/librocksdb.7.dylib (compatibility version 7.0.0, current version 7.10.2) /opt/homebrew/opt/gflags/lib/libgflags.2.2.dylib (compatibility version 2.2.0, current version 2.2.2) /opt/homebrew/opt/zstd/lib/libzstd.1.dylib (compatibility version 1.0.0, current version 1.5.5) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1300.36.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
-
编译与运行
Docker 开箱即用
如果不是在mac上,可以使用docker打包环境,在docker容器中开发。最好选择liunx docker环境。
- 提供dockerfile,基于alpine liunx编译rocksdb与对应依赖,然后拷贝到golang1.21的alpine环境中使用,确保开箱即用。
- 官方golang1.21-alpine基于alpine3.20, 版本相对较高,需要做对应的修改。
- alpine3.20的国内软件源需要使用对应的版本。
- 将开发目录挂载进入docker中,使用vscode远程连接进入docker中开发。(确保与主机桥接网络,避免内部依赖拉取不了)
Dockerfile
bash 代码解读复制代码FROM alpine:3.20 AS builder
ARG ROCKSDB_VERSION=v7.10.2
ARG LIB_DIR=/usr/local/rocksdb_env
RUN echo -e http://mirrors.ustc.edu.cn/alpine/v3.20/main/ > /etc/apk/repositories
RUN apk update && \
apk add --no-cache --update \
build-base \
autoconf \
automake \
libtool \
pkgconfig \
git \
bash \
linux-headers \
perl
RUN apk add --no-cache --update \
zlib-dev \
snappy-dev \
bzip2-dev \
lz4-dev \
zstd-dev \
zstd \
libcurl \
curl-dev \
libsodium-dev
RUN apk add --no-cache --update cmake
RUN cd /tmp && \
git clone https://github.com/gflags/gflags.git && \
cd gflags && \
mkdir build && \
cd build && \
cmake -DBUILD_SHARED_LIBS=1 -DGFLAGS_INSTALL_SHARED_LIBS=1 .. && \
make install && \
cd /tmp && \
rm -R /tmp/gflags/
RUN mkdir /usr/src && \
cd /usr/src && \
git clone --depth 1 --branch ${ROCKSDB_VERSION} https://github.com/facebook/rocksdb.git && \
cd /usr/src/rocksdb
RUN gcc --version && \
echo "rocksdb_version= ${ROCKSDB_VERSION}"
# - 编译rocksdb动态库,因为alpine liunx安装的软件都是默认动态库,所以依赖也都是动态库.
# - 因为alpine liunx 3.20中,gcc版本与rocksdb v7.10.2不同,
# 所以需要手动添加 cstdint 头文件,否则编译失败.
# - 因为alpine基于busybox,musl与gnu有的命令有区别,所以需要修改makfile中的install的选项。
RUN cd /usr/src/rocksdb && \
sed -i '1i #include ' table/block_based/data_block_hash_index.h && \
sed -i '1i #include ' util/string_util.h && \
sed -i 's/install -C/install -c/g' Makefile
RUN cd /usr/src/rocksdb && \
make clean && \
# make shared_lib && \
echo "rocksdb_lib= ${LIB_DIR}" && \
make install-shared PREFIX=${LIB_DIR} && \
cd ${LIB_DIR}/lib && \
# rm -R /usr/src/rocksdb/ && \
ls -al && \
ldd ./librocksdb.so
# ----------------------------------------------------------
FROM golang:1.21-alpine
ARG ROCKSDB_VERSION=v7.10.2
ARG LIB_DIR=/usr/local/rocksdb_env
RUN mkdir -p ${LIB_DIR} &&\
mkdir -p /app && \
echo -e http://mirrors.ustc.edu.cn/alpine/v3.20/main/ > /etc/apk/repositories
# 复制编译好的 RocksDB 到最终镜像
COPY --from=builder /usr/local/lib /usr/local/lib
COPY --from=builder /usr/lib /usr/lib
COPY --from=builder ${LIB_DIR} ${LIB_DIR}
# COPY --from=builder /usr/local/include/rocksdb /usr/local/include/rocksdb
# 设置CGO环境变量
ENV CGO_CFLAGS="-I${LIB_DIR}/include" \
CGO_LDFLAGS="-L${LIB_DIR}/lib -lrocksdb -lstdc++ -lm -lz -lsnappy -llz4 -lzstd" \
LD_LIBRARY_PATH="/usr/local/lib:${LIB_DIR}/lib:$LD_LIBRARY_PATH" \
GOPROXY=https://goproxy.io,direct \
CGO_ENABLED='1'
RUN apk add --no-cache --update \
build-base \
zlib \
zlib-dev
# 设置工作目录
WORKDIR /app
EXPOSE 7379
使用
可以将对应的开发rocksdb目录挂载进入docker中,使用vscode远程连接进入docker中开发(桥接主机网络)。
bash代码解读复制代码构建镜像 docker build -t grdb:st -f ./Dockerfile . 运行 docker run --name grdb-st -v /tmp/app:/app grdb:st /bin/sh 远程连接并开发
验证环境
验证环境是否安装完成,可以使用rocksdb项目中的make验证,但是,使用golang开发的情况,还需要验证golang的CGO是否能够成功调用。
-
首先进入容器,创建一个golang项目。
-
安装grocksdb ,版本确定为1.7.16
go get github.com/linxGnu/[email protected]
-
使用以下代码:
go代码解读复制代码package main import ( "log" "github.com/linxGnu/grocksdb" ) func main() { opts := grocksdb.NewDefaultOptions() opts.SetCreateIfMissing(true) db, err := grocksdb.OpenDb(opts, "./path/to/db") if err != nil { log.Fatalf("Error opening db: %v", err) } defer db.Close() // 进行数据库操作... // 写入数据 writeOpts := grocksdb.NewDefaultWriteOptions() defer writeOpts.Destroy() err = db.Put(writeOpts, []byte("key1"), []byte("value1")) if err != nil { log.Fatalf("Error putting data: %v", err) } // 读取数据 readOpts := grocksdb.NewDefaultReadOptions() defer readOpts.Destroy() value, err := db.Get(readOpts, []byte("key1")) if err != nil { log.Fatalf("Error getting data: %v", err) } defer value.Free() log.Printf("Value: %s", value.Data()) // // 批量写入 // batch := grocksdb.NewWriteBatch() // defer batch.Destroy() // batch.Put([]byte("key1"), []byte("value1")) // batch.Put([]byte("key2"), []byte("value2")) // err = db.Write(writeOpts, batch) // if err != nil { // log.Fatalf("Error writing batch: %v", err) // } // // 迭代器使用 // it := db.NewIterator(readOpts) // defer it.Close() // for it.SeekToFirst(); it.Valid(); it.Next() { // key := it.Key() // value := it.Value() // log.Printf("Key: %s, Value: %s\n", string(key.Data()), string(value.Data())) // } }
- 执行mod tidy
- 因为环境变量参数都已经设置好了,可以直接编译 go builid ./main
- 因为环境已经在docker中设置好,可以直接运行 ./main
- 如果正确输出,则环境正常
报错备忘记录
+
bash 代码解读复制代码/go/pkg/mod/github.com/linx!gnu/[email protected]/cache.go:25:12: could not determine kind of name for C.rocksdb_cache_create_hyper_clock
/go/pkg/mod/github.com/linx!gnu/[email protected]/cache.go:31:12: could not determine kind of name for C.rocksdb_cache_create_hyper_clock_opts
go程序编译报错,grocksdb版本太高,对应的rocksdb7.10.2没有,需要将grocksdb将为1.7.16.
+
yaml 代码解读复制代码$DEBUG_LEVEL is 0
make: -c: No such file or directory
make: -c: No such file or directory
make: -c: No such file or directory
make: -c: No such file or directory
make: -c: No such file or directory
make: -c: No such file or directory
make: -c: No such file or directory
Makefile:245: make_config.mk: No such file or directory
make: *** No rule to make target 'make_config.mk'. Stop.
rocksdb项目中执行make报错,未知原因,额外安装一个bash可以解决。
+
perl 代码解读复制代码Reason: tried: '/System/Volumes/Preboot/Cryptexes/OS@rpath/librocksdb.7.dylib' (no such file), '/usr/local/lib/librocksdb.7.dylib' (no such file), '/usr/lib/librocksdb.7.dylib' (no such file, not in dyld cache)
编译rocksdb报错,使用了动态库,但是没有配置动态库路径参数。
mac: DYLD_LIBRARY_PATH
liunx: LD_LIBRARY_PATH
+
xxx no found.
由于alpine镜像使用的是musl libc而不是gnu libc,/lib64/ 是不存在的。但他们是兼容的.
mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
+
-
make编译到一半,报错:note: 'uint8_t' is defined in header ''; did you forget to '#include '
是gcc的版本对应不上,可以通过手动添加:sed -i '1i #include ' table/block_based/data_block_hash_index.h && sed -i '1i #include ' util/string_util.h 修改。
-
make的install失败,因为alpine中-C命令需要改为-c。
sed -i 's/install -C/install -c/g' Makefile (Fix 'install -c' flag)
+
运行编译好的go程序时报错:
Invalid argument: Compression type ZSTD is not linked with the binary
这个是因为编译的时候丢了zstd依赖,可能是cmake编译的,通过otool(mac上)或者ldd(liunx上)工具查看对应动态库的依赖。
评论记录:
回复评论: