"too many" 线程上的任何特定问题 运行 (linux) BCP?

Any specific problems running (linux) BCP on "too many" threads?

运行在多线程上使用 Microsoft 的 BCP 实用程序(在 CentOS 7 上,https://docs.microsoft.com/en-us/sql/linux/sql-server-linux-migrate-bcp?view=sql-server-2017)是否存在任何特定问题?谷歌搜索找不到太多,但我正在寻找一个似乎与此相关的问题。

使用以下形式的代码将一组大型 TSV 文件从 HDFS 复制到远程 MSSQL 服务器

bcpexport() {
    filename=
    TO_SERVER_ODBCDSN=
    DB= 
    TABLE= 
    USER=
    PASSWORD=
    RECOMMEDED_IMPORT_MODE= 
    DELIMITER= 

    echo -e "\nRemoving header from TSV file $filename"
    echo -e "Current head:\n"
    echo $(head -n 1 $filename)
    echo "$(tail -n +2 $filename)" > $filename
    echo "First line of file is now..."    
    echo $(head -n 1 $filename)

    # temp. workaround safeguard for NFS latency
    #sleep 5 #FIXME: appears to sometimes cause script to hang, workaround implemented below, throws error if timeout reached 
    timeout 30 sleep 5

    echo -e "\nReplacing null literal values with empty chars"
    NULL_WITH_TAB="null\t" # WARN: assumes the first field is prime-key so never null
    TAB="\t"
    sed -i -e "s/$NULL_WITH_TAB/$TAB/g" $filename
    echo -e "Lines containing null (expect zero): $(grep -c "\tnull\t" $filename)"
    
    # temp. workaround safeguard for NFS latency
    #sleep 5 #FIXME: appears to sometimes cause script to hang, workaround implemented below 
    timeout 30 sleep 5

    /opt/mssql-tools/bin/bcp "$TABLE" in "$filename" \
        $TO_SERVER_ODBCDSN \
        -U $USER -P $PASSWORD \
        -d $DB \
        $RECOMMEDED_IMPORT_MODE \
        -t "\t" \
        -e ${filename}.bcperror.log
}

export -f bcpexport
parallel -q -j 7 bcpexport {} "$TO_SERVER_ODBCDSN" $DB $TABLE $USER $PASSWORD $RECOMMEDED_IMPORT_MODE $DELIMITER \
    ::: $DATAFILES/$TARGET_GLOB 

其中 $DATAFILES/$TARGET_GLOB 构造一个列出目录中一组文件的 glob。

当运行将此代码用于一组 TSV 文件时,发现有时 一些(但不是全部) 并行 BCP 线程会失败,即。一些文件成功复制到 MSSQL Server

Starting copy...

5397376 rows copied.

Network packet size (bytes): 4096

Clock Time (ms.) Total : 154902 Average : (34843.8 rows per sec.)

而其他人输出错误信息

Starting copy...

BCP copy in failed

通常,看到这种模式:前几个线程中的一些成功的 BCP 复制操作 returned,然后是一堆失败的线程 return 它们的输出直到 运行文件不足(GNU Parallel returns 输出仅当整个线程完成时看起来与顺序相同)。

请注意,代码中有 -e 选项可为每个 BCP 拷入操作生成错误文件(请参阅 https://docs.microsoft.com/en-us/sql/tools/bcp-utility?view=sql-server-2017#e)。观察这些失败行为后检查文件时,所有内容都是空白,没有错误消息。

只在线程数 >= 10 的情况下看到过(并且仅针对某些数据集(假设与文件总数有关的是文件大小,但是......)),没有错误到目前为止在使用 ~7 个线程时看到,这进一步让我怀疑这与多线程有关。

监控系统资源(通过 free -mh)显示通常约 13GB 或 RAM 始终可用。

注意 bcp 正在尝试复制的数据可能有 ~500000-1000000 条记录长,每条记录的上限为 ~100 列。

有人知道这里会发生什么吗?请注意,我对使用 BCP 以及 GNU 并行和多线程还很陌生。

不,在多线程中 运行 没有特定于 BCP 程序的问题。您似乎正在跟踪我所说的问题,即系统资源。您是否在增加线程数的同时监控系统资源?如果有的话,当 memory/cpu/network 资源不足时,BCP 可能会正常执行。关于“-e”选项,它的意思是输出数据错误。登录错误,错误的 table 名称...许多其他错误不会在使用 -e 选项创建的文件中报告。当您使用“-e”选项获得输出时,您会看到像 "value truncated" 这样的信息...会给您行号和有问题的样本数据。

TLDR:同时向 运行 添加更多线程以使 bcp 复制数据文件似乎具有 [=63= 的影响]用写入指令淹没端点 MSSQL Server,导致 bcp 线程失败(可能超时?)。当线程数变得太多时,似乎取决于 bcp 复制的文件大小(即文件中的记录数以及每条记录的宽度(即. 列数)).

长版(我理论的更多原因):

1. 当 运行使用更多 bcp 线程并查看机器上启动的进程时 (https://clustershell.readthedocs.io/en/latest/tools/clush.html)

ps -aux | grep bcp

看到一堆休眠进程(注意 S,参见 https://askubuntu.com/a/360253/760862),如下所示(添加换行符以提高可读性)

me 135296 14.5 0.0 77596 6940 ? S 00:32 0:01

/opt/mssql-tools/bin/bcp TABLENAME in /path/to/tsv/1_16_0.tsv -D -S MyMSSQLServer -U myusername -P -d myDB -c -t \t -e /path/to/logfile

这些线程似乎休眠了很长时间。进一步调试这些线程休眠的原因表明它们 可能 实际上正在执行它们的预期工作(这将进一步暗示问题可能来自 BCP 本身(参见 )). From https://unix.stackexchange.com/a/47259/260742 and https://unix.stackexchange.com/a/36200/260742 )

A process in S state is usually in a blocking system call, such as reading or writing to a file or the network, or waiting for another called program to finish.

(例如,写入 ODBCDSN 中给定 bcp 的 MSSQL Server 端点目标)

Your process will be in S state when it is doing reads and possibly writes that are blocking. Can also happen while waiting on semaphores or other synchronization primitives... This is all normal and expected, and not usually a problem... you don't want it to waste CPU while it's waiting for user input.

2. 当 运行 设置每个文件记录量不同的不同文件集时(例如范围 500000 - 1000000 rows/file ) 和每个文件的记录宽度 (~10 - 100 columns/row),发现 在数据宽度或数量非常大的情况下,运行 宁一组固定的 bcp 个线程会失败

例如。对于一组约 33 个 TSV,每行约 500000 行,每行约 100 列宽,一组 30 个线程将写入前几个 OK,但随后所有其余的将开始返回失败消息。结合@jamie 的回答,返回的失败消息是 "BCP copy in failed" 错误这一事实并不一定意味着它与相关数据的内容有关。 @jamie 的 post 在我的过程中没有将实际内容写入 -e 错误日志文件,这样说

Regarding the "-e" option, it is meant to output data errors. login errors, bad table names... many other errros are not reported in the file created with the -e option. When you get output using the "-e" option, you'll see info like "value truncated" and such... will give you line numbers and sample data that was at issue.

与此同时,一组约 33 个 TSV,每行约 500000 行,每行约 100 行宽,并且仍然使用 30 bcp 线程将快速且无错误地完成(在减少线程数或文件集数)。 此处唯一的区别是bcp复制到 MSSQL Server 的数据的总体大小。

一直以来

free -mh 

仍然显示机器 运行 在每种情况下线程仍然有大约 15GB 的可用内存剩余(这又是为什么 我怀疑问题与远程有关MSSQL Server 端点而不是代码或本地机器 本身)。

3. 当 运行ning 一些来自 (2) 的测试时,发现手动杀死 parallel 进程(通过 CTL+C) 然后尝试远程 t运行cate 测试 table 在本地机器上用 /opt/mssql-tools/bin/sqlcmd -Q "truncate table mytable" 写入将花费很长时间(与手动登录到 MSSQL 服务器相反并在数据库中执行 truncate mytable)。这再次让我认为这与 MSSQL Server 连接过多 并且不堪重负有关。

** 任何有任何 MSSQL Mgmt Studio 阅读本文经验的人(我基本上 none),如果您在这里看到任何让您认为我的理论不正确的内容,请告诉我您的想法。