#负载均衡 #并行 #文本 # #命令行界面

bin+lib slb

分片负载均衡文本流式Unix工具

9 个版本

0.3.1 2021年7月18日
0.3.0 2021年7月17日
0.2.4 2021年7月17日
0.2.3 2021年6月29日
0.1.1 2021年6月20日

#632并发

每月 22 次下载

Apache-2.0

19KB
310

slb: 分片负载均衡器

类似于 parallel --pipe --roundrobin,但是负载均衡是基于输入行哈希进行的。在子进程中执行键聚合时,这是至关重要的,因为只有其中一个分片包含给定的键。以下是一个在 16 个物理 CPU 机器上的单词计数示例

curl -o enwik9.bz2 https://cs.fit.edu/~mmahoney/compression/enwik9.bz2
bunzip2 enwik9.bz2
examples/clean.sh < enwik9 > enwik9.clean ; rm enwik9

/usr/bin/time -f "%e sec" awk -f examples/wc.awk enwik9.clean > wikawk.txt
# 203.97 sec

/usr/bin/time -f "%e sec" slb \
  --mapper 'tr " " "\n" | rg -v "^$"' \
  --folder "awk '{a[\$0]++}END{for(k in a)print k,a[k]}'" \
  --infile enwik9.clean \
  --outprefix wikslb.
# 6.20 sec

diff <(sort wikawk.txt) <(cat wikslb.* | sort) ; echo $?
# 0

这展示了在典型的 "map-reduce" 模式上的 "flatmap-fold" 模式。

每一行

a    b c d -> flatmapper 1
f g   a b -> flatmapper 2

被交给一个独立的平坦映射器 tr " " "\n" | rg -v "^$",它在每一行上放一个单词

flatmapper 1 ->
a
b
c
d

flatmapper 2 ->
f
g
a
b

输出结果将逐行检查。每行的第一个单词会被哈希(在这种情况下,整行)。假设 hash(a) == hash(b) == 1hash(c) == hash(d) == hash(g) == hash(f) == 0,我们将从每个平坦映射器中输入相应的密钥到一个或两个 awk '{a[$0]++}END{for(k in a)print k,a[k]}' 文件夹中。然后,输出将被写入输出文件。

a b a b -> awk 1 -> {a: 2, b: 2} -> outprefix1
f g c d -> awk 0 -> {f: 1, g: 1, c: 1, d: 1} -> outprefix0

特征频率计算

以下是一个计算大数据集稀疏 SVMlight 格式特征频率的示例,在大 KDD12 数据集上进行基准测试(假设已安装 ripgrepGNU Parallel)。

echo 'will cite' | parallel --citation 1>/dev/null 2>/dev/null
curl -o kdd12.tr.bz2 "https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/kdd12.tr.bz2"
bunzip2 kdd12.tr.bz2
du -hs kdd12.tr 
# 17G     kdd12.tr
parallel --pipepart -a kdd12.tr wc -l | awk '{a+=$0}END{print a}'
# num rows: 119705032
parallel --pipepart -a kdd12.tr wc -w | awk '{a+=$0}END{print a}'
# num nnz: 1436460384 - 119705032 = 1316755352

/usr/bin/time -f "%e sec %M KB" awk -f examples/svm-featurecount.awk kdd12.tr > results-awk.txt
# 1032.18 sec 13721032 KB

/usr/bin/time -f "%e sec %M KB" slb \
  --mapper 'sed -E "s/^[^ ]+ //" | sed -E "s/:[^ ]+//g" | tr " " "\n" | rg -v "^$"' \
  --folder "awk '{a[\$0]++}END{for(k in a)print k,a[k]}'" \
  --infile kdd12.tr \
  --outprefix results-slb.
# 122.50 sec 881436 KB
# note above doesn't count child memory
# eyeballing htop, max memory use is ~12.3GB

# check we're correct
cat results-slb.* > results-slb && rm results-slb.*
sort --parallel=$(($(nproc) / 2)) -k2nr -k1n -o results-slb results-slb & \
sort --parallel=$(($(nproc) / 2)) -k2nr -k1n -o results-awk.txt results-awk.txt & \
wait

diff results-slb results-awk.txt >/dev/null ; echo $?
# 0

计算不同特征值

作为另一个类似的例子,我们可以计算每个特征的不同值的数量。特别是,对于每个特征,我们希望得到其不同值的总数与100的最小值(因为我们可能会倾向于将具有超过99个值的任何事物视为连续的)。

curl -o kdda.bz2 "https://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/binary/kdda.bz2"
bunzip2 kdda.bz2
du -hs kdda
# 2.5G    kdda

/usr/bin/time -f "%e sec %M KB" awk -f examples/svm-countdistinct.awk kdda > cdawk.txt
# 388.72 sec 23895104 KB

/usr/bin/time -f "%e sec %M KB" slb \
  --mapper 'sed -E "s/^[^ ]+ //" | tr " " "\n" | tr ":" " " | rg -v "^$"' \
  --folder "awk '{if(!(\$1 in a)||length(a[\$1])<100)a[\$1][\$2]=1}END{for(k in a)print k,length(a[k])}'" \
  --infile kdda \
  --outprefix cdslb.
# 26.79 sec 1499992 KB

diff \
  <(sort --parallel=$(($(nproc) / 2)) -k2nr -k1n cdawk.txt) \
  <(cat cdslb.* | sort --parallel=$(($(nproc) / 2)) -k2nr -k1n) \
  > /dev/null ; echo $?
# 0

安装

注意上述示例展示了工具的便利性

  • 对于大数据集,并行化是必要的。
  • 与等效的map-reduce相比,我们使用更少的内存、更少的时间和更少的代码。

最后一点成立,因为 slb 确保每个并行调用都接收一个 唯一的分区 的键空间。因此,我们使用更少的内存,因为每个文件夹只跟踪其自己的键空间的聚合,并且使用更少的代码,因为我们不需要编写合并两个映射的合并器。

要从 crates.io 本地安装,请运行

cargo install slb

开发相关

使用 ./test.sh 进行基本测试。

使用 cd slb && cargo publish 发布到 crates.io

依赖关系

~3.5MB
~62K SLoC