1

私はツイストに基づいて Web ベンチマーク ツールを作成しようとしています。Twisted は、Web アプリケーション用の非常に優れた非同期フレームワークです。このフレームワークを使い始めて 2 週間しか経っていないので、問題に直面しました。このベンチマーク ツールを ApacheBench と比較してテストすると、同じ同時実行数でも結果が大きく異なります。これが私のツールの結果です:

python pyab.py 50000 50 http://xx.com/a.txt

speed:1063(q/s), worker:50, interval:7, req_made:7493, req_done:7443, req_error:0

Apache Bench の結果は次のとおりです。

ab -c 50 -n 50000 http://xx.com/a.txt

Server Software:        nginx/1.4.1
Server Hostname:        203.90.245.26
Server Port:            8080

Document Path:          /a.txt
Document Length:        6 bytes

Concurrency Level:      50
Time taken for tests:   6.89937 seconds
Complete requests:      50000
Failed requests:        0
Write errors:           0
Total transferred:      12501750 bytes
HTML transferred:       300042 bytes
Requests per second:    8210.27 [#/sec] (mean)
Time per request:       6.090 [ms] (mean)
Time per request:       0.122 [ms] (mean, across all concurrent requests)
Transfer rate:          2004.62 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.8      0       4
Processing:     1    5   3.4      5     110
Waiting:        0    2   3.6      2     109
Total:          1    5   3.5      5     110

Percentage of the requests served within a certain time (ms)
  50%      5
  66%      6
  75%      6
  80%      6
  90%      7
  95%      7
  98%      8
  99%      8
 100%    110 (longest request)

同じ URL と同時実行数で、ApacheBench は最大 8000 リクエスト/秒に達することができますが、pyab は 1000 リクエスト/秒しかありません。

ここに私のコード(pyab.py)があります:

from twisted.internet import reactor,threads
from twisted.internet.protocol import Protocol
from twisted.internet.defer import Deferred
from twisted.web.client import Agent
from twisted.web.client import HTTPConnectionPool
from twisted.web.http_headers import Headers
from twisted.python import log
import time, os, stat, logging, sys
from collections import Counter

logging.basicConfig(
    #filename= "/%s/log/%s.%s" % (RUN_DIR,RUN_MODULE,RUN_TIME),
    format="%(asctime)s [%(levelname)s] %(message)s",
    level=logging.WARNING,
    #level=logging.DEBUG,
    stream=sys.stdout
)

#log.startLogging(sys.stdout)
observer = log.PythonLoggingObserver()
observer.start()


class IgnoreBody(Protocol):
    def __init__(self, deferred, tl):
        self.deferred = deferred
        self.tl = tl

    def dataReceived(self, bytes):
        pass

    def connectionLost(self, reason):
        self.deferred.callback(None)


class Pyab:

    def __init__( self, n = 50000, concurrency = 100, url='http://203.90.245.26:8080/a.txt'):
        self.n = n
        self.url = url
        self.pool = HTTPConnectionPool(reactor, persistent=True)
        self.pool.maxPersistentPerHost = concurrency
        self.agent = Agent(reactor, connectTimeout = 5, pool = self.pool)
        #self.agent = Agent(reactor, connectTimeout = 5)

        self.time_start = time.time()
        self.max_worker = concurrency

        self.cnt = Counter({
            'worker' : 0 ,
            'req_made' : 0,
            'req_done' : 0,
            'req_error' : 0,
            })


    def monitor( self ):
        interval = int(time.time() - self.time_start)
        speed = 0
        if interval != 0:
            speed = int( self.cnt['req_done'] / interval )

        log.msg("speed:%d(q/s), worker:%d, interval:%d, req_made:%d, req_done:%d, req_error:%d" 
                % (speed, self.cnt['worker'], interval, self.cnt['req_made'], self.cnt['req_done'], self.cnt['req_error']), logLevel=logging.WARNING)


        reactor.callLater(1, lambda : self.monitor())

    def start( self ):
        self.keeprunning = True
        self.monitor()
        self.readMore()

    def stop( self ):
        self.keeprunning = False

    def readMore( self ):

        while self.cnt['worker'] < self.max_worker and self.cnt['req_done'] < self.n :
            self.make_request()

        if self.keeprunning and self.cnt['req_done'] < self.n:
            reactor.callLater( 0.0001, lambda: self.readMore() )
        else:
            reactor.stop()


    def make_request( self ):
        d = self.agent.request(
            'GET',
            #'http://examplexx.com/',
            #'http://example.com/',
            #'http://xa.xingcloud.com/v4/qvo/WDCXWD7500AADS-00M2B0_WD-WCAV5E38536685366?update0=ref0%2Ccor&update1=nation%2Ccn&action0=visit&_ts=1376397973636',
            #'http://203.90.245.26:8080/a.txt',
            self.url,
            Headers({'User-Agent': ['Twisted Web Client Example']}),
            None)

        self.cnt['worker'] += 1
        self.cnt['req_made'] += 1

        def cbResponse(resp):
            self.cnt['worker'] -= 1
            self.cnt['req_done'] += 1
            log.msg('response received')

            finished = Deferred()
            resp.deliverBody(IgnoreBody(finished, self))
            return finished

        def cbError(error):
            self.cnt['worker'] -= 1
            self.cnt['req_error'] += 1
            log.msg(error, logLevel=logging.ERROR)


        d.addCallback(cbResponse)
        d.addErrback(cbError)


if __name__ == '__main__' :
    if len(sys.argv) < 4:
        print "Usage: %s <n> <concurrency> <url>" % (sys.argv[0])
        sys.exit()

    ab = Pyab(n=int(sys.argv[1]), concurrency=int(sys.argv[2]), url=sys.argv[3])
    ab.start()
    reactor.run()

私のコードに問題はありますか? ありがとう!

4

1 に答える 1

0

私が最後に使用したとき、ab何十もの重大なバグがあることがわかっていました。場合によっては、非常に誇張された結果が報告されることがあります。場合によっては、否定的な結果が報告されることもあります。時々それはクラッシュするでしょう。のような別のツールをhttperfサニティ チェックとして試してみます。

ただし、サーバーが実際に高速である場合は、別の問題が発生する可能性があります。

修正されたとしても、abここでは C プログラムと CPython で実行されている Python プログラムについて話しているのです。spawnProcessPython で C よりも 8 倍遅いことは実際にはそれほど悪いことではないので、マルチコアの同時実行性を利用していないことを除けば、プログラムに実際に問題があるとは思いません。

まず、PyPy でより良い結果が得られるかどうかを確認してください。

于 2013-08-15T22:18:05.580 に答える