mongo - cxx driver

安装

1
2
# brew
brew insall mongo-cxx-deriver

其他参考这里

示例

官方示例参考这里

连接数据库

1
2
3
mongocxx::instance instance{};
mongocxx::uri uri("mongodb://192.168.4.13:27017");
mongocxx::client client(uri);

读取数组

1
2
3
4
5
6
7
8
auto arr_element = doc["contribs"];
if (arr_element && arr_element.type() == bsoncxx::type::k_array) {
bsoncxx::array::view arr(arr_element.get_array().value);
std::cout << arr.length() << std::endl; // 67; not count of elements
for (auto e: arr) {
std::cout << "E " << e.get_utf8().value.to_string() << std::endl;
}
}

grafana

安装

可以从 清华源 下载。

1
2
3
# centos
wget https://mirrors.tuna.tsinghua.edu.cn/grafana/yum/rpm/grafana-7.5.3-1.x86_64.rpm
sudo npm install grafana-7.5.3-1.x86_64.rpm

插件

Grafana Image Renderer

image

1
2
# 需要安装的依赖
yum install -y libXcomposite libXdamage libXtst cups libXScrnSaver pango atk adwaita-cursor-theme adwaita-icon-theme at at-spi2-atk at-spi2-core cairo-gobject colord-libs dconf desktop-file-utils ed emacs-filesystem gdk-pixbuf2 glib-networking gnutls gsettings-desktop-schemas gtk-update-icon-cache gtk3 hicolor-icon-theme jasper-libs json-glib libappindicator-gtk3 libdbusmenu libdbusmenu-gtk3 libepoxy liberation-fonts liberation-narrow-fonts liberation-sans-fonts liberation-serif-fonts libgusb libindicator-gtk3 libmodman libproxy libsoup libwayland-cursor libwayland-egl libxkbcommon m4 mailx nettle patch psmisc redhat-lsb-core redhat-lsb-submod-security rest spax time trousers xdg-utils xkeyboard-config alsa-lib

安装

1
grafana-cli plugins install grafana-image-renderer

seastar with docker

创建容器

1
docker run ... --sysctl net.core.somaxconn=10240 ...

设置

1
2
3
4
5
6
7
8
9
10
11
12
13
# 临时修改 aio-max-nr
# 注意 image-name 是镜像的名称,不是 container 的名称
docker run --privileged <image-name> sh -c 'echo 1048576 > /proc/sys/fs/aio-max-nr'

# 或者
docker run --privileged -it zhenkai.sun/external-with-openssh bash
sysctl -w fs.aio-max-nr=1048576

# 验证
cat /proc/sys/fs/aio-max-nr
cat /proc/sys/net/core/somaxconn

docker run --privileged --sysctl net.core.somaxconn=10240 zhenkai.sun/external-with-openssh bash

gcc

Install

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 下载 
## 从这里 https://mirrors.aliyun.com/gnu/gcc/ 选一个版本,或使用其他源。
VERSION=7.3.0
wget https://mirrors.aliyun.com/gnu/gcc/gcc-${VERSION}/gcc-${VERSION}.tar.gz
# 解压
tar xzf gcc-${VERSION}.tar.gz
cd gcc-${VERSION}

# 下载依赖
./contrib/download_prerequisites

# 配置
./configure --prefix=/opt/gcc/${VERSION} --enable-languages=c,c++ --disable-multilib
# 编译
make -j$(nproc)
make install

# 如果不想污染源文件
mkdir gcc-build
cd gcc-build
../configure --prefix=/opt/gcc/${VERSION} --enable-languages=c,c++ --disable-multilib
## 另一个配置
../configure --enable-bootstrap --enable-languages=c,c++,objc,obj-c++,fortran,go,lto --enable-shared --enable-threads=posix --enable-checking=release --enable-multilib --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-gcc-major-version-only --with-linker-hash-style=gnu --enable-plugin --enable-initfini-array --with-isl --enable-libmpx --enable-libsanitizer --enable-gnu-indirect-function --enable-libcilkrts --enable-libatomic --enable-libquadmath --enable-libitm --with-tune=generic --with-arch_32=x86-64

错误处理

7.3.0

1
2
3
4
5
6
7
8
9
10
# 错误
../../.././libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc:157:10: fatal error: sys/ustat.h: No such file or directory
#include <sys/ustat.h>

# 解决方案
## 1. 不编译 sanitizer, configure 时添加参数 --disable-libsanitizer
vim libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
## 2. 注释第 157、250 行
// #include <sys/ustat.h>
// unsigned struct_ustat_sz = sizeof(struct ustat);

编译

1
2
3
4
5
6
7
gcc sample.cpp # 默认生成 a.out

# 指定输出文件
gcc -o sample.exe sample.cpp

# 指定 c++ std 版本
gcc -std=c++17 -o sample.exe sample.cpp

参数

1
2
3
-c	仅编译
-Dname=value 定义 name 值
-o file-name 输出

Flags

1
2
3
4
5
6
7
8
9
10
11
# warning
-Wall 开启警告(all: 应该开启的最小警告集合)
-Wextra 开启扩展警告
-Werror 所有警告视为错误
-Wno-error=... 关闭某项警告视为错误
-Wno-<warning-name> 关闭某项警告
-Wextra
-w 忽略所有警告

# 常用警告
-Werror=return-type 函数没有 return 视为错误

示例

1
2
3
4
5
6
export CFLAGS='-g -O3'
export CXXFLAGS='-ggdb3 -O0 -Wno-narrowing'
export CPPFLAGS='-DX=1 -DY=2 -Wno-narrowing'
export CCFLAGS='--asdf -Wno-narrowing'

make CXXFLAGS='-ggdb3 -O0 -Wno-narrowing' CPPFLAGS='-DX=1 -DY=2 -Wno-narrowing' CCFLAGS='--asdf -Wno-narrowing' all -j

注意

  • -w-Werror... 同时用会有冲突,-w 会短路 -Werror-w -Werror=...-Werror=... -w 都不行。

编译库

1
// common.h

查看查找链接库路径

1
2
gcc -Xlinker -v
g++ -Xlinker -v

链接

  • libraries 允许未定义的符号(undefined symbols)
  • executable 不允许有未定义的符号
  • 在代码中定义的符号(如函数名)还未使用到之前,链接器并不会把它加入到连接表中

修改系统默认库查找路径

1
export LIBRARY_PATH={path}:{path}

AUR 低版本 GCC

1
2
3
4
configure:4314: $? = 0
configure:4303: gcc -V >&5
gcc: error: unrecognized command-line option '-V'
gcc: fatal error: no input files

上面的报错可以忽略,只是尝试探测 gcc 版本,详见 这里

redis usage

登录

1
$ redis-cli -h <host> -p <port>

查询

集群信息

1
2
3
4
5
6
# 集群信息
> cluster info
# 节点信息
> cluster nodes
# 内存信息
> info memory

导出数据

redis-cli

redis-shake

1
2
./redis-shake.linux -type=dump -conf=redis-shake.conf

redis-shake.conf 配置参考这里

搭建集群

1
2
3
4
5
6
nohup redis-server --cluster-enabled yes --port 6379 --cluster-config-file nodes1.conf &
nohup redis-server --cluster-enabled yes --port 6378 --cluster-config-file nodes2.conf &
nohup redis-server --cluster-enabled yes --port 6377 --cluster-config-file nodes3.conf &

sleep 3 # 等服务节点起来
redis-cli --cluster create 127.0.0.1:6379 127.0.0.1:6378 127.0.0.1:6377

nodes1.conf、nodes1.conf、nodes1.conf 可以不存在,运行后 redis 自动创建。不同的 redis 实例,需要绑定不同的配置文件,默认为 node.conf。

c++ 最佳实践

工程

工具

网络

服务治理

配置中心

定义全局变量

1
2
3
4
5
6
7
8
9
// global.h
namespace {
extern int i;
}

// global.cpp
namespace {
int i = 1024;
}

随机数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// random_util.h
#include "random"
#include "climits"
namespace utils {
extern std::random_device gRandomDev;
extern std::mt19937 gRandomGenerator;
extern std::uniform_int_distribution<std::mt19937::result_type> gRandomDist; // (0, INT_MAX)

uint32_t RandomInt(const int &min = 0, const int &max = 0);
}

// random_util.cpp
#include "random_util.h"
namespace ranker::utils {
std::random_device gRandomDev;
std::mt19937 gRandomGenerator(gRandomDev());
std::uniform_int_distribution<std::mt19937::result_type> gRandomDist(0, INT_MAX);

uint32_t RandomInt(const int &min, const int &max) {
if (min == max && min == 0) {
return (uint32_t) gRandomDist(gRandomGenerator);
} else {
std::uniform_int_distribution<std::mt19937::result_type> dist(min, max);
return (uint32_t) dist(gRandomGenerator);
}
}
}

/*
满足泊松分布的随机数
std::poisson_distribution<> d{/*mean=*/4};
d(gRandomGenerator);
*/

c++ - holes

容易 Core Dump 的情形

容器重新分配内存导致的非法内存访问

1
2
3
4
5
6
7
// 定义结构
struct Biz {...};
// 定义容器
std::vector<Biz> bizes;
bizes.emplace_back(); // 添加一个元素
auto p_biz = &bizes.back(); // 保存指针
bizes.emplace_back(); // 添加一个元素. 该操作可能会使指针 p_biz 失效, 因为内存重新分配

模板

类似需要在编译期展开的代码实现,不能放在 cpp 文件中,而应该放在 header 中

静态变量初始化

1
2
3
4
5
6
7
8
// s.h
#ifndef S_H
#define S_H
class S {
static int v;
};
int S::v = 0;
#endif

上面的代码在链接时会报错。声明保护(gragma once 或使用 ifndef 判断)可以解决单个编译单元(单个源文件)的重复声明错误,但不能避免多个编译单元在链接时的重复定义错误。要解决这个问题,需要把静态变量的声明和初始化放在不同的文件里面。

1
2
3
4
5
6
7
8
9
10
// s.h
#ifndef S_H
#define S_H
class S {
static int v;
};
#endif

// s.cpp
int S::v = 0;

undefined reference to

  • 未连接库

  • 编译库的编译器版本不一致,ABI 不兼容

    • 尤其注意,多个库之间使用的 gcc/++ 不一致
  • find_package 的顺序,在某些情况下也有可能会导致这个问题

    • 被依赖先调用 find_package

编译 C 库使用 C++ 语法

1
gcc -lstdc++ code.c

ABI 兼容性问题

1
"CXXFLAGS": "-D_GLIBCXX_USE_CXX11_ABI=0 -Wno-stringop-truncation"

链接的库没有使用统一的 _GLIBCXX_USE_CXX11_ABI 参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"version": 2,
"configurePresets": [
{
"name": "build",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
},
"environment": {
"CXXFLAGS": "-D_GLIBCXX_USE_CXX11_ABI=0 -Wno-stringop-truncation"
}
}
]
}

c++ - perf

工具

gprof、perf、gperftools、valgrind。

Perf

perf 工具默认生成记录文件 perf.data,读写路径是 pwd。

安装

1
2
3
4
5
# ubuntu
sudo apt install linux-tools-common linux-tools-generic linux-tools-`uname -r` -y

# centos
sudo yum install perf -y
1
2
3
4
5
6
7
# source code
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.134.tar.gz
tar -xf linux-5.10.134.tar.gz
cd linux-5.10.134/tools/perf

make # 如果编译出错,可以尝试修改 Makefile.config 里面的 FLAGS, 移除 -Werror
cp perf /usr/bin/

工具

bpftrace

1
bpftrace -e 'profile:hz:99 /pid == 1/ { @[ustack] = count(); }'

google-perftools + brpc

1
apt install google-gperftools
1
2
pprof-symbolize --text 0.0.0.0:9500 --seconds=5
pprof-symbolize 0.0.0.0:9500 --seconds=5

brpc/tools/pporf

./brpc/tools/pprof 是一个 prel 脚本文件,不需要编译

1
./brpc/tools/pprof --text localhost:9500/pprof/profile

top

系统性能分析工具。

参数

1
2
-e 指定 event,多个 event 用 , 分隔
-s 指定分类聚合列, 默认是函数,还有 comm(命令)、pid 等

使用

1
2
3
4
# 所有进程
$ perf top
# 指定进程
$ perf top -p <pid>

stat

运行命令 / 指定 pid,并收集性能统计数据。

record

运行命令 / 指定 pid,并收集分析数据至 perf.data。

1
2
3
4
5
# 指定 pid
$ pid=$(pgrep <program-name>)

# 查看报告
$ perf report --show-total-period

report

读取 perf.data,展示分析结果。

1
2
3
4
5
$ perf report 

# 参数
--show-total-period 展示总耗时列
-a 统计系统范围内数据

diff

对比两个 perf.data 内容的区别,使用场景比如对比改动前后的变化。

archive

用来打包 perf.data 中使用到的环境数据,用于离线分析。

1
2
3
4
5
# 打包
$ perf archieve

# 分析
$ tar xvf perf.data.tar.bz2 -C ~/.debug

使用

1
2
3
4
5
6
7
8
9
10
11
12
# 查看系统全部耗时
$ perf top

# pid
$ pid=$(pgrep <program-name>)

# 记录数据
$ perf record -e cpu-clock -F 99 -p $pid -g -- sleep 60 # 记录 60 秒数据

# 展示记录数据的分析结果
$ perf report --show-total-period
$ perf report --show-total-period$ -i <perf.data> # 指定记录文件

火焰图

使用 这里 生成火焰图。

1
2
3
4
5
# 下载工具
$ git clone https://github.com/brendangregg/FlameGraph

# 生成火焰图
$ sudo perf script | FlameGraph/stackcollapse-perf.pl | FlameGraph/flamegraph.pl > flamegraph.svg

参考

问题

1