Назад | Перейти на главную страницу

Распараллеливание запросов curl

Это мой сценарий оболочки:

for i in `seq 1 $1`; do
    filename=randomfile$(uuidgen).txt
    head -c $2 </dev/urandom > $filename
    checksum256=$(sha256sum $filename | awk '{ print $1 }')
    attrs=$(jq -n --arg cf "$checksum256" '{ "confidential":"N", "transactionId": "sdf", "codiDirCorp": "CorpCode", "expiration": "10/10/2025", "description": "desc", "locked": "N", "title": "titol", "docHash": $cf }')

    curl -X POST \
        'http://localhost:8083/documents?application=RDOCUI&user=nif' \
        -F docFile=@$filename \
        -F 'docAttributes='"${attrs}"''
done

Как видите, я генерирую несколько файлов со случайным содержанием.

После этого я просто выполняю curl-запрос, чтобы загрузить их.

Чтобы выполнить эту команду, я просто набираю:

$ ./stress.sh 1000 200K

Здесь я генерирую 1000 файлов и 1000 запросов на их загрузку.

Я хотел бы ускорить выполнение этих запросов параллельно.

Любые идеи?

Xargs может делать это на переднем плане и дает вам контроль над параллелизмом и пакетной обработкой.

-P 42 определяет, сколько curlбежать за раз.
-n 23 определяет, сколько запросов каждый curl вызов будет обрабатывать. -n 1 отключает пакетирование.

С Bash

#! /bin/bash

URL='http://localhost:8083/documents?application=RDOCUI&user=nif'

for i in `seq $1`
do
    filename=randomfile$(uuidgen).txt
    head -c $2 </dev/urandom > $filename
    export checksum256=$(sha256sum $filename | awk '{ print $1 }')
    attrs=$(jq -n '{ "foo": "bar", "docHash": env.checksum256 }')

    printf -- '--next %q -F docFile=@%q -F docAttributes=%q\0' "$URL" "$filename" "$attrs"
done |
    xargs -0 -n 23 -P 42 bash -c 'eval "$0" "$@"' curl

В for цикл пишет \0-разделенные пробелами группы аргументов в канал для чтения Xargs. Эти аргументы нужно передать в Curl. Xargs, в свою очередь, передает их Bash, поэтому они назначаются "$1", "$2", ... (a.k.a. "$@"). Теперь мы используем eval разгруппировать аргументы. Все специальные символы были правильно экранированы с помощью printf %q, поэтому Bash не будет удалять ненужные кавычки или разбивать слова. "$0" "$@" расширится до curl --next http://l... --next ...

Curl попытается выполнить только одно рукопожатие TCP и повторно использовать это постоянное соединение для отправки всех запросов, перечисленных в его аргументах. В зависимости от размера запроса, это может дать заметное ускорение.

С тире

Dash не поддерживает printf %q, но если вашим форматированием JSON можно пожертвовать (через jq -c) вы можете избежать этого с помощью printf '%s'. Нам также придется полагаться на предположение, что ни JSON, ни другие аргументы не содержат '.

#! /bin/sh

# ...

    attrs=$(jq -n -c '{ "foo": "bar", "docHash": env.checksum256 }')

    printf -- "--next %s -F 'docFile=@%s' -F 'docAttributes=%s'\0" "$URL" "$filename" "$attrs"
done |
    xargs -0 -n 23 -P 42 sh -c 'eval "$0" "$@"' curl

Без for

Вы спросили конкретно о параллельном запуске части запроса. Но если вы хотите запустить весь скрипт параллельно, вы можете ввести команду следующим образом

$ seq 1000 | xargs -n 1 -P 42 ./stress.sh 1 200K

Вы всегда можете взглянуть на нету

for i in `seq 1 $1`; do
    filename=randomfile$(uuidgen).txt
    head -c $2 </dev/urandom > $filename
    checksum256=$(sha256sum $filename | awk '{ print $1 }')
    attrs=$(jq -n --arg cf "$checksum256" '{ "confidential":"N", "transactionId": "sdf", "codiDirCorp": "CorpCode", "expiration": "10/10/2025", "description": "desc", "locked": "N", "title": "titol", "docHash": $cf }')

    nohup curl -X POST \
        'http://localhost:8083/documents?application=RDOCUI&user=nif' \
        -F docFile=@$filename \
        -F 'docAttributes='"${attrs}"''
done

nohup указывает оболочке запускать процесс в фоновом режиме без ввода данных пользователем, игнорируя сигналы зависания. Таким образом, у вас должно быть одновременно запущено несколько CURL