惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
About on SuperTechFans
博客园 - 聂微东
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
B
Blog RSS Feed
U
Unit 42
Stack Overflow Blog
Stack Overflow Blog
Recent Announcements
Recent Announcements
雷峰网
雷峰网
罗磊的独立博客
Microsoft Security Blog
Microsoft Security Blog
Hugging Face - Blog
Hugging Face - Blog
L
LangChain Blog
人人都是产品经理
人人都是产品经理
The GitHub Blog
The GitHub Blog
F
Fortinet All Blogs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
H
Help Net Security
P
Proofpoint News Feed
The Cloudflare Blog
D
Docker
大猫的无限游戏
大猫的无限游戏

Comments for Cocoa

Rust Learning from Zero (23) —— The OwO software distribution system! Rust Learning from Zero (22) —— SSL certificates management and distribution with Rust 最近 | Cocoa 留言☆〜(ゝ。∂) | Cocoa 在 CentOS 7 中编译安装 Aria2 我们可以有无任何监管或审核的自由 App Store / Market 吗? iPad 与 Raspberry Pi 4 通过 Type-C 直连 —— SSH 篇 Brainfuck Interpreter in C++17——A Modern Approach to Kill Your Brain
在 Raspberry Pi 4 上编译 64-bit 的 MongoDB Server
Ryza · 2019-11-12 · via Comments for Cocoa

上次编译了 MongoDB 的 Embedded 版本,不过官方表示那个还只是一个实验中的程序,同时上次编译的还是 32-bit 的 Embedded 版本,因此这次就来编译一个真正可用的 64-bit 的 MongoDB 好了_(:3」∠)_

总的来说倒也没有想象中那么复杂,但是确实有几个可能踩到的的坑

首先我做的就是先让树莓派到 64-bit 环境中,可以参考我的这篇博客,让 Raspberry Pi 4 完全运行在 64-bit 模式下

确认 schroot 到 64-bit 环境中之后,同样的,通过 apt 安装必要的依赖

sudo apt install -y scons libssl-dev libffi-dev libcurl4-openssl-dev wget gcc g++ vim cmake python3 python3-pip

包括稍后会用到的 Python 的依赖

cat << EOF >~/build-requirements.txt
Cheetah3 # src/mongo/base/generate_error_codes.py
psutil
pymongo >= 3.0, != 3.6.0  # See PYTHON-1434, SERVER-34820
PyYAML >= 3.0.0
regex
requests >= 2.0.0
typing >= 3.6.4
EOF

sudo pip3 install -r ~/build-requirements.txt

在国内的话,可以指定使用清华大学 TUNA 镜像源

sudo pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple -r ~/build-requirements.txt

接着是编译 snappy ~

snappy 的源代码在其 GitHub Release 页面下载,https://github.com/google/snappy/releases,在写本文的时候,snappy 最新的 release 是在 17 年 8 月 25 号发布的 1.1.7,于是下载地址就是 https://github.com/google/snappy/archive/1.1.7.tar.gz

export SNAPPY_VER=1.1.7
wget https://github.com/google/snappy/archive/\${SNAPPY_VER}.tar.gz -O snappy-\${SNAPPY_VER}.tar.gz
tar xzf snappy-\${SNAPPY_VER}.tar.gz
cd snappy-\${SNAPPY_VER}
mkdir build && cd build
cmake -DBUILD_SHARED_LIBS=ON .. && make -j`nproc` && sudo make install

下一个则是 Mongo C Driver ♪(´ε` ) Mongo C Driver 的源代码也是在它的 GitHub Release 页面上,https://github.com/mongodb/mongo-c-driver/releases,在写这篇 post 的时候最新版本是 19 年 11 月 7 号发布的 1.15.2,下载链接则是 https://github.com/mongodb/mongo-c-driver/releases/download/1.15.2/mongo-c-driver-1.15.2.tar.gz

export MONGO_C_VER=1.15.2
wget https://github.com/mongodb/mongo-c-driver/releases/download/\${MONGO_C_VER}/mongo-c-driver-\${MONGO_C_VER}.tar.gz -O mongo-c-driver-\${MONGO_C_VER}.tar.gz
tar xzf mongo-c-driver-\${MONGO_C_VER}.tar.gz
cd mongo-c-driver-\${MONGO_C_VER}
mkdir release && cd release
cmake .. && make -j`nproc` && sudo make install

现在就是到了重头戏的地方了~编译 MongoDB~

MongoDB 的源代码则是在它的官网上下载,https://www.mongodb.com/download-center/community。在页面右侧会有一个 Download Source (tgz),下载到 Raspberry Pi 上即可~

截止这篇 post 写作的时候,MongoDB 在其官网上最新的版本是 4.2.1~于是

export MONGODB_VER=4.2.1
wget https://fastdl.mongodb.org/src/mongodb-src-r\${MONGODB_VER}.tar.gz -O mongodb-src-r${MONGODB_VER}.tar.gz
tar xzf mongodb-src-r\${MONGODB_VER}.tar.gz
cd mongodb-src-r\${MONGODB_VER}

在先前那篇编译 MongoDB 的 Embedded 版本中,我误以为 MongoDB 有一处 type-casting 的问题,其实因为当时是 32-bit 的环境,所以会出现问题。

但我们这里编译的命令确实需要做出一定的调整,不然编译到后面会出现这样的报错

虽然不是很清楚为什么 scons 找不到 core 这个编译依赖,但是我们编译 MongoDB Server 可以不用它

我们的编译命令需要改为如下

CCFLAGS="-mabi=lp64 -march=armv8-a+crc+simd" \
    python3 buildscripts/scons.py mongod \
    --disable-warnings-as-errors \
    --release=RELEASE \
    --dbg=off

但是!!!只是改了这里还不行,为什么呢?

因为这里的坑是 crc,我其实一开始第一行写的是 CCFLAGS="-mabi=lp64 -march=native",但是编译到 wiredtigercrc32-arm64 部分时,编译器突然报错说

Compiling build/opt/third_party/wiredtiger/src/checksum/arm64/crc32-arm64.o
/tmp/ccHQNUYS.s: Assembler messages:
/tmp/ccHQNUYS.s:40: Error: selected processor does not support `crc32cb w2,w2,w3'
/tmp/ccHQNUYS.s:70: Error: selected processor does not support `crc32cb w2,w2,x4'
/tmp/ccHQNUYS.s:95: Error: selected processor does not support `crc32cb w2,w2,w0'
scons: *** [build/opt/third_party/wiredtiger/src/checksum/arm64/crc32-arm64.o] Error 1
scons: building terminated because of errors.

然而我记得 Raspberry Pi 4 的 CPU 肯定是支持硬件 CRC 的,于是总之先找了一段使用硬件 crc32 的代码测试,代码来自 linux kernel arch/arm64/crypto/crc32-arm64.c

#include <stdlib.h>
#include <stdint.h>

#define CRC32X(crc, value) __asm__("crc32x %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32W(crc, value) __asm__("crc32w %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32H(crc, value) __asm__("crc32h %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32B(crc, value) __asm__("crc32b %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32CX(crc, value) __asm__("crc32cx %w[c], %w[c], %x[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32CW(crc, value) __asm__("crc32cw %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32CH(crc, value) __asm__("crc32ch %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))
#define CRC32CB(crc, value) __asm__("crc32cb %w[c], %w[c], %w[v]":[c]"+r"(crc):[v]"r"(value))

uint32_t crc32_arm64_le_hw(uint32_t crc, const uint8_t *p, unsigned int len)
{
    int64_t length = len;
    while ((length -= sizeof(uint64_t)) >= 0) {
        CRC32X(crc, *((uint64_t *)p));
        p += sizeof(uint64_t);
    }
    if (length & sizeof(uint32_t)) {
        CRC32W(crc, *((uint32_t *)p));
        p += sizeof(uint32_t);
    }
    if (length & sizeof(uint16_t)) {
        CRC32H(crc, *((uint16_t *)p));
        p += sizeof(uint16_t);
    }
    if (length & sizeof(uint8_t))
        CRC32B(crc, *p);
    return crc;
}

uint32_t crc32c_arm64_le_hw(uint32_t crc, const uint8_t *p, unsigned int len)
{
    int64_t length = len;
    while ((length -= sizeof(uint64_t)) >= 0) {
        CRC32CX(crc, *((uint64_t *)p));
        p += sizeof(uint64_t);
    }
    if (length & sizeof(uint32_t)) {
        CRC32CW(crc, *((uint32_t *)p));
        p += sizeof(uint32_t);
    }
    if (length & sizeof(uint16_t)) {
        CRC32CH(crc, *((uint16_t *)p));
        p += sizeof(uint16_t);
    }
    if (length & sizeof(uint8_t))
        CRC32CB(crc, *p);
    return crc;
}

然后用如下命令在 Raspberry Pi 4 上编译~

gcc -mabi=lp64 -march=armv8-a+crc+simd -c crc32-arm64.c -o crc32-arm64.o

发现确实是没问题的,Raspberry Pi 4 的 CPU 支持硬件 CRC,也就是说,我们需要更改的是 wiredtiger 的相关文件~

这里因为我们是用 scons 编译的整个项目,因此我们要改的文件就是 wiredtiger 下面 scons 的配置~

wiredtiger 的源代码在 src/third_party/wiredtiger/ 下,其实那下面有两个 scons 的配置文件,一个是 SConscript,另一个是 SconstructSconstruct 是给 Windows 平台用的,所以我们忽略它就好

打开 Sconscript,之后,我们需要在对应编译环境判断语句后增加 -march=armv8-a+crc+simd 这个参数~

那么阅读这个编译脚本之后,我们添加的位置如下~(对应 r4.2.1 所附带的 wiredtiger 的配置文件在 76 行

# ...
elif env.TargetOSIs('linux'):
    if env.TargetOSIs('android'):
        env.Append(CPPPATH=["build_android"])
        env.Append(CPPDEFINES=["_GNU_SOURCE"])
    else:
        env.Append(CPPPATH=["build_linux"])
        env.Append(CPPDEFINES=["_GNU_SOURCE"])
        env.Append(CFLAGS=["-march=armv8-a+crc+simd"])
else:
# ...

其实另一个方法就是不用硬件 CRC,但是那样可能会损失一定的性能,再说反正就只增加一行代码就可以用硬件 CRC 的话,并不算麻烦2333333

在修改好这个文件之后,回到 mongodb-src-r4.2.1 目录,在正式开始前还有最后一个坑,就是 MongoDB 编译的时候需要的内存还比较大,哪怕我买的已经是 4GB 的 Raspberry Pi,还是出现过 Out-of-Memory 的情况

因此可以接个读写速度相对较快的 U 盘到 Raspberry Pi 上,确保 U 盘上有足够的空间,大约需要 8G 以上的剩余空间(如果你的是 1GB 的树莓派的话,可以酌情考虑使用 12G 的 swap 文件,把下文里命令对应的 8G 改成 12G 即可),我们会将那个 U 盘拿来做 swap

给 Raspberry Pi 增加 swap 的方法也很简单~

首先,在没有接 U 盘之前执行

ls /dev/sd*

因为 Raspberry Pi 会给外接的储存依次分配 /dev/sda/dev/sdb 等这样的路径,记录下上面的输出~

下一步则是接上 U 盘,然后同样执行 ls /dev/sd*,观察多出来的部分

比如我这里多出来的是 /dev/sda/dev/sda1/dev/sda2,因为我的 U 盘上分了 2 个区,所以会有 /dev/sda1/dev/sda2

我这里 U 盘上第二个分区是 Extfs 4 的格式,所以我就用它来放 swap 文件了~

mkdir -p /tmp/sd
sudo mount /dev/sda2 /tmp/sd
sudo fallocate -l 8G /tmp/sd/swapfile
sudo chmod 400 /tmp/sd/swapfile
sudo mkswap /tmp/sd/swapfile
sudo swapon /tmp/sd/swapfile

这样子就添加好了 8G 的 swap 空间~

现在一切准备好之后,就可以使用前面提到的命令开始编译了~

CCFLAGS="-mabi=lp64 -march=armv8-a+crc+simd" \
    python3 buildscripts/scons.py mongod \
    --disable-warnings-as-errors \
    --release=RELEASE \
    --dbg=off

整个过程大约 5-7 个小时,我忘了给它计时2333333

这个时候一来因为我们修改好了 wiredtiger,所以在编译 crc32-arm64.c 的时候不会再报错了

我编译完成的时候已经是晚上了,但是总算是编译完了♪(´ε` ) 而且理论上所有功能都可以正常使用~

编译好的 mongodbuild/opt/mongo/mongod

要测试一下的话,可以使用如下命令~

cd build/opt/mongo/
rm -rf ~/mongodb
mkdir -p ~/mongodb
./mongod --dbpath=${HOME}/mongodb --bind_ip=0.0.0.0

然后就能看到 MongoDB Server 正常运行了~顺便我还从 Mac 上连过去了一下,也是没问题的~

Raspberry Pi 4 那边 MongoDB Server 收到连接的 log 如下~