1000,000개의 서로 다른 요청이 있습니다(요청이 다르다는 것은 쿼리 매개변수가 다르다는 의미입니다. 페이로드가 없는 GET 요청일 뿐입니다. 요청 및 응답 크기는 KB 단위로만 표시됩니다. 이미지나 복잡한 항목은 없습니다). cURL 뒤에 실제 URL이 옵니다. 실제로,각 줄은 http URL이 될 수 있으며 응답을 jq로 파이프할 수 있으며 조건이 충족되면 로그 파일에 기록합니다.(이것이 내가 달성하고 싶은 것입니다).
1000부터 시작해서 5000에 도달할 계획입니다.요청 10,000개/초. 우리는 대략 지속되는 것을 선호합니다. 몇 시간 동안(예: 48~72시간) 초당 10,000개의 요청입니다.
어떤 방법이 가장 좋나요?
- 텍스트 파일에 Gnu 병렬 처리를 사용하면 각 텍스트 파일에 준비된 http URL이 10000개 있게 됩니다. (여기서 텍스트 파일의 http보다 컬이 더 좋나요?)
- 위 작업을 수행할 때 각 컬 요청이 자체 쉘에서 실행됩니까? 요청을 보내고 초당 10000개의 요청에 대한 응답을 받을 수 있는 단일 셸로 이를 어떻게 변경합니까?
xargs와 gnu 병렬 사이에 2.5일을 보냈습니다. 그러나 스택 오버플로에서는 gnu 병렬성에 대한 일부 답변이 xargs에 적용되고 그 반대의 경우도 마찬가지입니다. 또한 초당 10000개의 요청을 보내고 기준을 충족하는 모든 응답에 대해 로그 파일에 쓸 수 있는 더 나은 도구(예: Python 도구 또는 ab 도구)가 있습니까? 도와주세요. 감사해요.
추신: golang이 gnu 병렬보다 이 작업을 더 잘 병렬화하는 데 도움이 될 수 있습니까?
답변1
너무 길어요.
Gb/s 속도를 목표로 하고 있지만 쉘을 시작하는 것은 말할 것도 없고 프로세스를 충분히 빠르게 생성할 수도 없습니다. 따라서 쉘 스크립트는 귀하의 솔루션이 아닙니다. libcurl
액세스 허용을 사용하세요 libcurl-multi
.
완전한 답변
어떤 방법이 가장 좋나요?
- 텍스트 파일에 gnu 병렬을 사용하면 각 텍스트 파일에 준비된 http URL이 10000개 있게 됩니다. (여기서 텍스트 파일의 경우 컬이 http보다 낫습니까?)
- 위 작업을 수행할 때 각 컬 요청이 자체 쉘에서 실행됩니까? 요청을 보내고 초당 10000개의 요청에 대한 응답을 받을 수 있는 단일 셸로 이를 어떻게 변경합니까?
초당 "KB 단위"(복수) 10,000개의 요청을 수행하려고 하므로 이는 단순한 1Gb/s 이더넷 케이블이 아닙니다. 건축학적 의미를 이해했는지 확인하세요!
첫째, 전송 매체(일부 이더넷?)는 직렬입니다. 가장 깊은 기술 수준에서는 여러 패킷을 병렬로 보내는 것이 불가능합니다. 가능한 접근 방식은 여러 코어에서 전송될 패킷 대기열을 채운 다음 들어오는 응답을 병렬로 처리하는 것입니다.
curl
그런 다음 하나의 요청을 실행하기 위해 전체 프로세스를 생성하는 것은훌륭한효율성이 낮습니다. 하지만 전체 쉘을 생성하는 것은(bash를 생각하고 계시나요?) 훨씬 더 나쁩니다! (프로세스 생성이란 새 프로세스를 생성/포킹하고, 실행 파일의 이미지로 바꾸고, 실행 파일이 의존하는 모든 라이브러리를 로드하고, 구성/시작 스크립트를 구문 분석한 다음 실제 작업을 수행하는 것을 의미합니다. 귀하의 경우 실제 일은더 쉽게(C의 빠른 테스트 루프는 약 3500× 이상을 수행할 수 없다는 것을 보여줍니다. vfork()
그런 다음 PID를 확인한 다음 exec
8 스레드 3.6GHz CPU에서 매초마다 빈 프로그램을 실행합니다. 매우 무거운 작업을 실행하고 싶습니다. 내 컴퓨터가 생성할 수 있는 초당 프로세스의 3배를 생성하고 생성된 프로세스 내에서 여전히 네트워킹 및 처리를 수행하지만 대부분의 경우 이러한 일은 발생하지 않습니다.)
jq
모든 요청에 대해 프로세스를 생성하는 것은 완전히 재앙입니다. jq
두 가지 작업을 수행해야 합니다.
- 매개변수로 전달한 쿼리를 구문 분석하고,
- 이 쿼리를 기반으로 JSON을 구문 분석합니다.
이제 JSON은 매번 다르지만 쿼리를 알고 나면(그리고 쿼리가 너무 복잡하지 않음) 구문 분석하기가 상대적으로 간단하지만 쿼리 자체를 구문 분석하는 것은 기본적으로 컴파일러입니다. 동일한 컴파일을 여러 번 수행하면 실제로 쿼리는 동일하게 유지됩니다.
따라서 이와 같은 고성능 테스트의 경우 parallel
셸을 통해 수행하면 xargs
작동하지 않습니다. 시스템의 비효율성으로 인해 필요한 속도로 작업할 수 없습니다.
그래서 프로그램을 작성해 보세요. 프로그래밍 언어는 적절한 멀티스레딩을 허용하고(PHP, Delphi 및 Visual Basic 6.0은 피할 수 있음) 비교적 빠른 JSON 파서에 액세스할 수 있는 한 문제가 되지 않습니다. Python은 작동하지만 Python은 유명하지 않습니다.좋아요멀티스레딩. 하지만 여전히 작동할 수도 있습니다. 개인적으로 저는 C++로 간단히 작성하고 싶습니다.
추천하다:
epoll
세부 사항을 다루는 것을 피하고 싶을 만큼 JSON 파서에 대해 충분히 알고 있다고 생각한다면 libcurl
이를 수행하기 위한 멋진 API가 있습니다.libcurl 많은다중 인터페이스. CPU 코어당 이러한 작업 중 하나를 수행하면 서버 연결이 포화 상태가 될 수 있습니다.
복잡성을 희생하면서 전체적으로 CPU 사용률을 최대화하는 애플리케이션을 작성하려면 요청을 보내는 것이 수신된 데이터를 처리하는 것보다 훨씬 쉽기 때문에 별도의 송신 및 수신 작업자 스레드가 있어야 합니다. 이와 관련하여 먼저
- 다중 스레드 안전 로깅 시스템을 초기화합니다(나는 spdlog를 좋아하지만 초당 10000개의 잠재적 로그를 보고 사람이 읽을 수 있는 텍스트 파일보다 바이너리 데이터를 집계하고 쓰는 것이 더 적절할 수 있습니다).
- 파서를 설정하고,
- (어설픈 추측: CPU 스레드 수/3 - 1) 전송 작업자 스레드(TX)를 생성합니다.
- 여러 개의(어설픈 추측: CPU 스레드 · 2/3 - 1) 수신 작업자 스레드(RX)를 생성합니다.
- 데이터를 읽을 준비가 된 TCP 소켓에 대한 운영 체제 알림 토큰을 보유하는 스레드를 생성합니다. Linux에서 이 메커니즘은
epoll
Python에서select
모듈을 통해select.epoll
. - 요청을 준비하고 TCP 연결을 설정한 다음 작업자의 수신 대기열에 할당하는 스레드를 생성합니다.
각 TX 작업자에서는
- 준비된 요청을 합니다. (이것은 아마도 단지
curl_
함수 호출일 것입니다. libcurl은 실제로 명령줄 도구가 아니라 좋은 라이브러리입니다.)
각 RX 작업자 스레드에서
- 방금 얻은 데이터를 가져와 구문 분석하고, 결과를 계산하고, 적절한 경우 로깅 시스템에 이를 기록하도록 지시합니다.
epoll 스레드에서는
- 이벤트는 데이터를 가져와 RX 작업자에게 공정하게 전달하는 방식으로 처리됩니다(예: 라운드 로빈 방식).
epoll
libcurl을 사용하는 예제를 원한다면 curl
다음이 있습니다.예(실제로는 사용 사례에 매우 가깝습니다!)
C++에서 멀티스레딩, 컬, 네트워킹을 처리하는 방법에 대해 논의하고 싶다면,이것Stack Overflow의 답변이 도움이 될 수 있습니다.
답변2
@MarcusMiller는 단일 시스템에서 초당 10000개의 요청을 수행할 수 있을 것으로 기대하면 안되는 이유를 훌륭하게 요약합니다. 하지만 어쩌면 당신은 그것을 묻지 않았을 수도 있습니다. 어쩌면 이 작업을 수행하는 데 사용할 수 있는 컴퓨터가 100대일 수도 있습니다. 그러면 가능해졌습니다.
100개의 머신 각각에서 다음을 실행합니다.
ulimit -n 1000000
shuf huge-file-with-urls |
parallel -j1000 --pipe --roundrobin 'wget -i - -O - | jq .'
URL을 여러 번 실행해야 하는 경우에는 more를 추가하세요 shuf huge-file-with-urls
.
forever shuf huge-file-with-urls | [...]
(https://gitlab.com/ole.tange/tangetools/-/tree/master/forever)
GNU Parallel은 1,000개 이상의 작업을 병렬로 실행할 수 있지만 컴퓨터가 그렇게 많은 작업을 처리할 수는 없습니다. 1000000초 전에 시작되었지만 sleep
(참조:https://unix.stackexchange.com/a/150686/366317) 내 64코어 컴퓨터를 한계까지 밀어붙였습니다. 실제로 1,000,000개의 동시 프로세스를 시작합니다.했다특정 상황으로 인해 서버가 완전히 중지될 수 있습니다.
프로세스는 한 코어에서 다른 코어로 마이그레이션되므로 어떤 코어가 무엇을 실행하고 있는지 알 수 없습니다. 프로세스가 실행되어야 하는 코어를 제한하는 데 사용할 수 있지만 taskset
이는 매우 특정한 시나리오에서만 의미가 있습니다. 작업을 유휴 CPU 코어로 오프로드하려는 경우가 종종 있는데, 코어는 이를 매우 잘 수행합니다.
답변3
@MarcusMiller는 단일 시스템에서 초당 10000개의 요청을 수행할 수 있을 것으로 기대하면 안되는 이유를 훌륭하게 요약합니다.
수정해야 할 것 같아요.
방금 64개 코어 컴퓨터에 설치 varnish
하고 ab
실행했습니다 .
$ seq 64 | parallel -N0 ab -c 100 -n 100000 http://lo:6081/
Server Software: Apache/2.4.41 (really Varnish)
Server Hostname: lo
Server Port: 6081
Document Path: /
Document Length: 10918 bytes
Concurrency Level: 100
Time taken for tests: 132.916 seconds
Complete requests: 100000
Failed requests: 0
Total transferred: 1127168742 bytes
HTML transferred: 1091800000 bytes
Requests per second: 752.35 [#/sec] (mean)
Time per request: 132.916 [ms] (mean)
Time per request: 1.329 [ms] (mean, across all concurrent requests)
Transfer rate: 8281.53 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 94 484.9 1 15453
Processing: 0 38 68.9 28 4672
Waiting: 0 37 68.9 27 4672
Total: 1 132 498.4 29 15683
초당 64*720개 요청 = 약 45,000개 요청 및 응답을 받습니다.
응답당 10KB = 4.5Gbit/s
CPU의 약 50%는 입니다 varnish
.ab
난 당신을 생각할 수 있는16코어 시스템에서 1Gbps로 초당 10,000개의 요청을 수행했습니다. 하지만 결과로는 아무 것도 할 수 없으며 ab
다른 요청을 사용 하라고 지시할 방법도 찾지 못했습니다 .
당신이 사용하는 경우https://github.com/philipgloyne/apachebench-for-multi-url다른 URL을 사용할 수도 있습니다.
parallel --pipepart --block -1 --fifo -a urls ./ab -L {} -c 100 -n 100000